xref: /OK3568_Linux_fs/u-boot/arch/nds32/cpu/n1213/start.S (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun/*
2*4882a593Smuzhiyun *	Andesboot - Startup Code for Whitiger core
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun *	Copyright (C) 2006	Andes Technology Corporation
5*4882a593Smuzhiyun *	Copyright (C) 2006	Shawn Lin <nobuhiro@andestech.com>
6*4882a593Smuzhiyun *	Copyright (C) 2011	Macpaul Lin <macpaul@andestech.com>
7*4882a593Smuzhiyun *				Greentime Hu <greentime@andestech.com>
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * SPDX-License-Identifier:	GPL-2.0+
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun.pic
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun#include <asm-offsets.h>
15*4882a593Smuzhiyun#include <config.h>
16*4882a593Smuzhiyun#include <common.h>
17*4882a593Smuzhiyun#include <asm/macro.h>
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun/*
20*4882a593Smuzhiyun * Jump vector table for EVIC mode
21*4882a593Smuzhiyun */
22*4882a593Smuzhiyun#define ENA_DCAC		2UL
23*4882a593Smuzhiyun#define DIS_DCAC		~ENA_DCAC
24*4882a593Smuzhiyun#define ICAC_MEM_KBF_ISET	(0x07)	 	! I Cache sets per way
25*4882a593Smuzhiyun#define ICAC_MEM_KBF_IWAY	(0x07<<3)	! I cache ways
26*4882a593Smuzhiyun#define ICAC_MEM_KBF_ISZ	(0x07<<6)	! I cache line size
27*4882a593Smuzhiyun#define DCAC_MEM_KBF_DSET	(0x07)		! D Cache sets per way
28*4882a593Smuzhiyun#define DCAC_MEM_KBF_DWAY	(0x07<<3)	! D cache ways
29*4882a593Smuzhiyun#define DCAC_MEM_KBF_DSZ	(0x07<<6)	! D cache line size
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun#define PSW			$ir0
32*4882a593Smuzhiyun#define EIT_INTR_PSW		$ir1		! interruption $PSW
33*4882a593Smuzhiyun#define EIT_PREV_IPSW		$ir2		! previous $IPSW
34*4882a593Smuzhiyun#define EIT_IVB			$ir3		! intr vector base address
35*4882a593Smuzhiyun#define EIT_EVA			$ir4		! MMU related Exception VA reg
36*4882a593Smuzhiyun#define EIT_PREV_EVA		$ir5		! previous $eva
37*4882a593Smuzhiyun#define EIT_ITYPE		$ir6		! interruption type
38*4882a593Smuzhiyun#define EIT_PREV_ITYPE		$ir7		! prev intr type
39*4882a593Smuzhiyun#define EIT_MACH_ERR		$ir8		! machine error log
40*4882a593Smuzhiyun#define EIT_INTR_PC		$ir9		! Interruption PC
41*4882a593Smuzhiyun#define EIT_PREV_IPC		$ir10		! previous $IPC
42*4882a593Smuzhiyun#define EIT_OVL_INTR_PC		$ir11		! overflow interruption PC
43*4882a593Smuzhiyun#define EIT_PREV_P0		$ir12		! prev $P0
44*4882a593Smuzhiyun#define EIT_PREV_P1		$ir13		! prev $p1
45*4882a593Smuzhiyun#define CR_ICAC_MEM		$cr1		! I-cache/memory config reg
46*4882a593Smuzhiyun#define CR_DCAC_MEM		$cr2		! D-cache/memory config reg
47*4882a593Smuzhiyun#define MR_CAC_CTL		$mr8
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun.globl _start
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun_start:	j	reset
52*4882a593Smuzhiyun	j	tlb_fill
53*4882a593Smuzhiyun	j	tlb_not_present
54*4882a593Smuzhiyun	j	tlb_misc
55*4882a593Smuzhiyun	j	tlb_vlpt_miss
56*4882a593Smuzhiyun	j	machine_error
57*4882a593Smuzhiyun	j	debug
58*4882a593Smuzhiyun	j	general_exception
59*4882a593Smuzhiyun	j	syscall
60*4882a593Smuzhiyun	j	internal_interrupt		! H0I
61*4882a593Smuzhiyun	j	internal_interrupt		! H1I
62*4882a593Smuzhiyun	j	internal_interrupt		! H2I
63*4882a593Smuzhiyun	j	internal_interrupt		! H3I
64*4882a593Smuzhiyun	j	internal_interrupt		! H4I
65*4882a593Smuzhiyun	j	internal_interrupt		! H5I
66*4882a593Smuzhiyun	j	software_interrupt		! S0I
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun	.balign 16
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun/*
71*4882a593Smuzhiyun * Andesboot Startup Code (reset vector)
72*4882a593Smuzhiyun *
73*4882a593Smuzhiyun *	1.	bootstrap
74*4882a593Smuzhiyun *		1.1 reset - start of u-boot
75*4882a593Smuzhiyun *		1.2 to superuser mode - as is when reset
76*4882a593Smuzhiyun *		1.4 Do lowlevel_init
77*4882a593Smuzhiyun *			- (this will jump out to lowlevel_init.S in SoC)
78*4882a593Smuzhiyun *			- (lowlevel_init)
79*4882a593Smuzhiyun *		1.3 Turn off watchdog timer
80*4882a593Smuzhiyun *			- (this will jump out to watchdog.S in SoC)
81*4882a593Smuzhiyun *			- (turnoff_watchdog)
82*4882a593Smuzhiyun *	2.	Do critical init when reboot (not from mem)
83*4882a593Smuzhiyun *	3.	Relocate andesboot to ram
84*4882a593Smuzhiyun *	4.	Setup stack
85*4882a593Smuzhiyun *	5.	Jump to second stage (board_init_r)
86*4882a593Smuzhiyun */
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun/* Note: TEXT_BASE is defined by the (board-dependent) linker script */
89*4882a593Smuzhiyun.globl _TEXT_BASE
90*4882a593Smuzhiyun_TEXT_BASE:
91*4882a593Smuzhiyun	.word	CONFIG_SYS_TEXT_BASE
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun/* IRQ stack memory (calculated at run-time) + 8 bytes */
94*4882a593Smuzhiyun.globl IRQ_STACK_START_IN
95*4882a593SmuzhiyunIRQ_STACK_START_IN:
96*4882a593Smuzhiyun	.word 0x0badc0de
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun/*
99*4882a593Smuzhiyun * The bootstrap code of nds32 core
100*4882a593Smuzhiyun */
101*4882a593Smuzhiyun
102*4882a593Smuzhiyunreset:
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun/*
105*4882a593Smuzhiyun *  gp = ~0            for burn mode
106*4882a593Smuzhiyun *     = ~load_address for load mode
107*4882a593Smuzhiyun */
108*4882a593Smuzhiyunreset_gp:
109*4882a593Smuzhiyun	.relax_hint 0
110*4882a593Smuzhiyun	sethi   $gp, hi20(_GLOBAL_OFFSET_TABLE_-8)
111*4882a593Smuzhiyun	.relax_hint 0
112*4882a593Smuzhiyun	ori     $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_-4)
113*4882a593Smuzhiyun	add5.pc $gp
114*4882a593Smuzhiyun
115*4882a593Smuzhiyunset_ivb:
116*4882a593Smuzhiyun	li	$r0, 0x0
117*4882a593Smuzhiyun	/* turn on BTB */
118*4882a593Smuzhiyun	mtsr	$r0, $misc_ctl
119*4882a593Smuzhiyun	/* set IVIC, vector size: 4 bytes, base: 0x0 */
120*4882a593Smuzhiyun	mtsr	$r0, $ivb
121*4882a593Smuzhiyun/*
122*4882a593Smuzhiyun * MMU_CTL NTC0 Cacheable/Write-Back
123*4882a593Smuzhiyun */
124*4882a593Smuzhiyun	li	$r0, ~0x3
125*4882a593Smuzhiyun	mfsr	$r1, $mr8
126*4882a593Smuzhiyun	and	$r1, $r1, $r0
127*4882a593Smuzhiyun	mtsr	$r1, $mr8
128*4882a593Smuzhiyun#if (!defined(CONFIG_SYS_ICACHE_OFF) || !defined(CONFIG_SYS_DCACHE_OFF))
129*4882a593Smuzhiyun	li	$r0, 0x4
130*4882a593Smuzhiyun	mfsr	$r1, $mr0
131*4882a593Smuzhiyun	or	$r1, $r1, $r0
132*4882a593Smuzhiyun	mtsr	$r1, $mr0
133*4882a593Smuzhiyun#endif
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun#if !defined(CONFIG_SYS_ICACHE_OFF)
136*4882a593Smuzhiyun	li	$r0, 0x1
137*4882a593Smuzhiyun	mfsr	$r1, $mr8
138*4882a593Smuzhiyun	or	$r1, $r1, $r0
139*4882a593Smuzhiyun	mtsr	$r1, $mr8
140*4882a593Smuzhiyun#endif
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun#if !defined(CONFIG_SYS_DCACHE_OFF)
143*4882a593Smuzhiyun	li	$r0, 0x2
144*4882a593Smuzhiyun	mfsr	$r1, $mr8
145*4882a593Smuzhiyun	or	$r1, $r1, $r0
146*4882a593Smuzhiyun	mtsr	$r1, $mr8
147*4882a593Smuzhiyun#endif
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun	jal mem_init
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun#ifndef CONFIG_SKIP_LOWLEVEL_INIT
152*4882a593Smuzhiyun	jal	lowlevel_init
153*4882a593Smuzhiyun/*
154*4882a593Smuzhiyun *  gp = ~VMA          for burn mode
155*4882a593Smuzhiyun *     = ~load_address for load mode
156*4882a593Smuzhiyun */
157*4882a593Smuzhiyunupdate_gp:
158*4882a593Smuzhiyun	.relax_hint 0
159*4882a593Smuzhiyun	sethi   $gp, hi20(_GLOBAL_OFFSET_TABLE_-8)
160*4882a593Smuzhiyun	.relax_hint 0
161*4882a593Smuzhiyun	ori     $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_-4)
162*4882a593Smuzhiyun	add5.pc $gp
163*4882a593Smuzhiyun#endif
164*4882a593Smuzhiyun/*
165*4882a593Smuzhiyun *  do critical initializations first (shall be in short time)
166*4882a593Smuzhiyun *  do self_relocation ASAP.
167*4882a593Smuzhiyun */
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun/*
170*4882a593Smuzhiyun * Set the N1213 (Whitiger) core to superuser mode
171*4882a593Smuzhiyun * According to spec, it is already when reset
172*4882a593Smuzhiyun */
173*4882a593Smuzhiyun#ifndef CONFIG_SKIP_TRUNOFF_WATCHDOG
174*4882a593Smuzhiyun	jal	turnoff_watchdog
175*4882a593Smuzhiyun#endif
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun/*
178*4882a593Smuzhiyun * Do CPU critical regs init only at reboot,
179*4882a593Smuzhiyun * not when booting from ram
180*4882a593Smuzhiyun */
181*4882a593Smuzhiyun#ifdef CONFIG_INIT_CRITICAL
182*4882a593Smuzhiyun	jal	cpu_init_crit		! Do CPU critical regs init
183*4882a593Smuzhiyun#endif
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun/*
186*4882a593Smuzhiyun * Set stackpointer in internal RAM to call board_init_f
187*4882a593Smuzhiyun * $sp must be 8-byte alignment for ABI compliance.
188*4882a593Smuzhiyun */
189*4882a593Smuzhiyuncall_board_init_f:
190*4882a593Smuzhiyun	li		$sp, CONFIG_SYS_INIT_SP_ADDR
191*4882a593Smuzhiyun	move	$r0, $sp
192*4882a593Smuzhiyun	bal	board_init_f_alloc_reserve
193*4882a593Smuzhiyun	move	$sp, $r0
194*4882a593Smuzhiyun	bal	board_init_f_init_reserve
195*4882a593Smuzhiyun#ifdef CONFIG_DEBUG_UART
196*4882a593Smuzhiyun	bal	debug_uart_init
197*4882a593Smuzhiyun#endif
198*4882a593Smuzhiyun	li		$r0, 0x00000000
199*4882a593Smuzhiyun#ifdef __PIC__
200*4882a593Smuzhiyun#ifdef __NDS32_N1213_43U1H__
201*4882a593Smuzhiyun/* __NDS32_N1213_43U1H__ implies NDS32 V0 ISA */
202*4882a593Smuzhiyun	la	$r15, board_init_f	! store function address into $r15
203*4882a593Smuzhiyun#endif
204*4882a593Smuzhiyun#endif
205*4882a593Smuzhiyun	j	board_init_f		! jump to board_init_f() in lib/board.c
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun/*
208*4882a593Smuzhiyun * void relocate_code (addr_sp, gd, addr_moni)
209*4882a593Smuzhiyun *
210*4882a593Smuzhiyun * This "function" does not return, instead it continues in RAM
211*4882a593Smuzhiyun * after relocating the monitor code.
212*4882a593Smuzhiyun *
213*4882a593Smuzhiyun */
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun/*
216*4882a593Smuzhiyun *  gp = ~RAM_SIZE - TEXT_SIZE for burn/load mode
217*4882a593Smuzhiyun */
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun.globl	relocate_code
220*4882a593Smuzhiyunrelocate_code:
221*4882a593Smuzhiyun	move	$r4, $r0		/* save addr_sp */
222*4882a593Smuzhiyun	move	$r5, $r1		/* save addr of gd */
223*4882a593Smuzhiyun	move	$r6, $r2		/* save addr of destination */
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun/* Set up the stack */
226*4882a593Smuzhiyunstack_setup:
227*4882a593Smuzhiyun	move	$sp, $r4
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun	la	$r0, _start@GOTOFF
230*4882a593Smuzhiyun	beq	$r0, $r6, clear_bss	/* skip relocation */
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun	la	 $r1, _end@GOTOFF
233*4882a593Smuzhiyun	move $r2, $r6			/* r2 <- scratch for copy_loop */
234*4882a593Smuzhiyuncopy_loop:
235*4882a593Smuzhiyun	lmw.bim	$r11, [$r0], $r18
236*4882a593Smuzhiyun	smw.bim	$r11, [$r2], $r18
237*4882a593Smuzhiyun	blt	$r0, $r1, copy_loop
238*4882a593Smuzhiyun/*
239*4882a593Smuzhiyun * fix relocations related issues
240*4882a593Smuzhiyun */
241*4882a593Smuzhiyunfix_relocations:
242*4882a593Smuzhiyun	l.w	$r0, _TEXT_BASE@GOTOFF	/* r0 <- Text base */
243*4882a593Smuzhiyun	sub	$r9, $r6, $r0			/* r9 <- relocation offset */
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun	la  $r7, __rel_dyn_start@GOTOFF
246*4882a593Smuzhiyun	add	$r7, $r7, $r9		/* r2 <- rel __got_start in RAM */
247*4882a593Smuzhiyun	la  $r8, __rel_dyn_end@GOTOFF
248*4882a593Smuzhiyun	add	$r8, $r8, $r9		/* r2 <- rel __got_start in RAM */
249*4882a593Smuzhiyun	li  $r3, #0x2a /* R_NDS32_RELATIVE */
250*4882a593Smuzhiyun1:
251*4882a593Smuzhiyun	lmw.bim $r0, [$r7], $r2 /* r0,r1,r2 <- adr,type,addend */
252*4882a593Smuzhiyun	bne $r1, $r3, 2f
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun	add $r0, $r0, $r9
255*4882a593Smuzhiyun	add $r2, $r2, $r9
256*4882a593Smuzhiyun	sw  $r2, [$r0]
257*4882a593Smuzhiyun2:
258*4882a593Smuzhiyun	blt $r7, $r8, 1b
259*4882a593Smuzhiyun
260*4882a593Smuzhiyunclear_bss:
261*4882a593Smuzhiyun	la	$r0, __bss_start@GOTOFF	/* r0 <- rel __bss_start in FLASH */
262*4882a593Smuzhiyun	add	$r0, $r0, $r9		/* r0 <- rel __bss_start in FLASH */
263*4882a593Smuzhiyun	la	$r1, __bss_end@GOTOFF		/* r1 <- rel __bss_end in RAM */
264*4882a593Smuzhiyun	add	$r1, $r1, $r9		/* r0 <- rel __bss_end in RAM */
265*4882a593Smuzhiyun	li	$r2, 0x00000000		/* clear */
266*4882a593Smuzhiyun
267*4882a593Smuzhiyunclbss_l:
268*4882a593Smuzhiyun	sw	$r2, [$r0]		/* clear loop... */
269*4882a593Smuzhiyun	addi	$r0, $r0, #4
270*4882a593Smuzhiyun	bne	$r0, $r1, clbss_l
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun/*
273*4882a593Smuzhiyun * We are done. Do not return, instead branch to second part of board
274*4882a593Smuzhiyun * initialization, now running from RAM.
275*4882a593Smuzhiyun */
276*4882a593Smuzhiyuncall_board_init_r:
277*4882a593Smuzhiyun	bal invalidate_icache_all
278*4882a593Smuzhiyun	bal flush_dcache_all
279*4882a593Smuzhiyun	la	$r0, board_init_r@GOTOFF
280*4882a593Smuzhiyun	move	$lp, $r0		/* offset of board_init_r() */
281*4882a593Smuzhiyun	add	$lp, $lp, $r9		/* real address of board_init_r() */
282*4882a593Smuzhiyun	/* setup parameters for board_init_r */
283*4882a593Smuzhiyun	move	$r0, $r5		/* gd_t */
284*4882a593Smuzhiyun	move	$r1, $r6		/* dest_addr */
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun#ifdef __PIC__
287*4882a593Smuzhiyun#ifdef __NDS32_N1213_43U1H__		/* NDS32 V0 ISA	*/
288*4882a593Smuzhiyun	move	$r15, $lp		/* store function address into $r15 */
289*4882a593Smuzhiyun#endif
290*4882a593Smuzhiyun#endif
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun	/* jump to it ... */
293*4882a593Smuzhiyun	jr	$lp			/* jump to board_init_r() */
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun/*
296*4882a593Smuzhiyun * Initialize CPU critical registers
297*4882a593Smuzhiyun *
298*4882a593Smuzhiyun *	1.	Setup control registers
299*4882a593Smuzhiyun *		1.1 Mask all IRQs
300*4882a593Smuzhiyun *		1.2 Flush cache and TLB
301*4882a593Smuzhiyun *		1.3 Disable MMU and cache
302*4882a593Smuzhiyun *	2.	Setup memory timing
303*4882a593Smuzhiyun */
304*4882a593Smuzhiyun
305*4882a593Smuzhiyuncpu_init_crit:
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun	move	$r0, $lp		/* push	ra */
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun	/* Disable Interrupts by clear GIE in $PSW reg */
310*4882a593Smuzhiyun	setgie.d
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun	/* Flush caches and TLB */
313*4882a593Smuzhiyun	/* Invalidate caches */
314*4882a593Smuzhiyun	jal	invalidate_icac
315*4882a593Smuzhiyun	jal	invalidate_dcac
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun	/* Flush TLB */
318*4882a593Smuzhiyun	mfsr	$p0, $MMU_CFG
319*4882a593Smuzhiyun	andi	$p0, $p0, 0x3			! MMPS
320*4882a593Smuzhiyun	li	$p1, 0x2			! TLB MMU
321*4882a593Smuzhiyun	bne	$p0, $p1, 1f
322*4882a593Smuzhiyun	tlbop	flushall			! Flush TLB
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun1:
325*4882a593Smuzhiyun	! Disable MMU, Dcache
326*4882a593Smuzhiyun	! Whitiger is MMU disabled when reset
327*4882a593Smuzhiyun	! Disable the D$
328*4882a593Smuzhiyun	mfsr	$p0, MR_CAC_CTL			! Get the $CACHE_CTL reg
329*4882a593Smuzhiyun	li	$p1, DIS_DCAC
330*4882a593Smuzhiyun	and	$p0, $p0, $p1			! Set DC_EN bit
331*4882a593Smuzhiyun	mtsr	$p0, MR_CAC_CTL			! write back the $CACHE_CTL reg
332*4882a593Smuzhiyun	isb
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun	move	$lp, $r0
335*4882a593Smuzhiyun2:
336*4882a593Smuzhiyun	ret
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun/*
339*4882a593Smuzhiyun * Invalidate I$
340*4882a593Smuzhiyun */
341*4882a593Smuzhiyuninvalidate_icac:
342*4882a593Smuzhiyun	! read $cr1(I CAC/MEM cfg. reg.) configuration
343*4882a593Smuzhiyun	mfsr	$t0, CR_ICAC_MEM
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun	! Get the ISZ field
346*4882a593Smuzhiyun	andi	$p0, $t0, ICAC_MEM_KBF_ISZ
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun	! if $p0=0, then no I CAC existed
349*4882a593Smuzhiyun	beqz	$p0, end_flush_icache
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun	! get $p0 the index of I$ block
352*4882a593Smuzhiyun	srli	$p0, $p0, 6
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun	! $t1= bit width of I cache line size(ISZ)
355*4882a593Smuzhiyun	addi	$t1, $p0, 2
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun	li	$t4, 1
358*4882a593Smuzhiyun	sll	$t5, $t4, $t1			! get $t5 cache line size
359*4882a593Smuzhiyun	andi	$p1, $t0, ICAC_MEM_KBF_ISET	! get the ISET field
360*4882a593Smuzhiyun	addi	$t2, $p1, 6			! $t2= bit width of ISET
361*4882a593Smuzhiyun	andi	$p1, $t0, ICAC_MEM_KBF_IWAY	! get bitfield of Iway
362*4882a593Smuzhiyun	srli	$p1, $p1, 3
363*4882a593Smuzhiyun	addi	$p1, $p1, 1			! then $p1 is I way number
364*4882a593Smuzhiyun	add	$t3, $t2, $t1			! SHIFT
365*4882a593Smuzhiyun	sll	$p1, $p1, $t3			! GET the total cache size
366*4882a593SmuzhiyunICAC_LOOP:
367*4882a593Smuzhiyun	sub	$p1, $p1, $t5
368*4882a593Smuzhiyun	cctl	$p1, L1I_IX_INVAL
369*4882a593Smuzhiyun	bnez	$p1, ICAC_LOOP
370*4882a593Smuzhiyunend_flush_icache:
371*4882a593Smuzhiyun	ret
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun/*
374*4882a593Smuzhiyun * Invalidate D$
375*4882a593Smuzhiyun */
376*4882a593Smuzhiyuninvalidate_dcac:
377*4882a593Smuzhiyun	! read $cr2(D CAC/MEM cfg. reg.) configuration
378*4882a593Smuzhiyun	mfsr	$t0, CR_DCAC_MEM
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun	! Get the DSZ field
381*4882a593Smuzhiyun	andi	$p0, $t0, DCAC_MEM_KBF_DSZ
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun	! if $p0=0, then no D CAC existed
384*4882a593Smuzhiyun	beqz	$p0, end_flush_dcache
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun	! get $p0 the index of D$ block
387*4882a593Smuzhiyun	srli	$p0, $p0, 6
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun	! $t1= bit width of D cache line size(DSZ)
390*4882a593Smuzhiyun	addi	$t1, $p0, 2
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun	li	$t4, 1
393*4882a593Smuzhiyun	sll	$t5, $t4, $t1			! get $t5 cache line size
394*4882a593Smuzhiyun	andi	$p1, $t0, DCAC_MEM_KBF_DSET	! get the DSET field
395*4882a593Smuzhiyun	addi	$t2, $p1, 6			! $t2= bit width of DSET
396*4882a593Smuzhiyun	andi	$p1, $t0, DCAC_MEM_KBF_DWAY	! get bitfield of D way
397*4882a593Smuzhiyun	srli	$p1, $p1, 3
398*4882a593Smuzhiyun	addi	$p1, $p1, 1			! then $p1 is D way number
399*4882a593Smuzhiyun	add	$t3, $t2, $t1			! SHIFT
400*4882a593Smuzhiyun	sll	$p1, $p1, $t3			! GET the total cache size
401*4882a593SmuzhiyunDCAC_LOOP:
402*4882a593Smuzhiyun	sub	$p1, $p1, $t5
403*4882a593Smuzhiyun	cctl	$p1, L1D_IX_INVAL
404*4882a593Smuzhiyun	bnez	$p1, DCAC_LOOP
405*4882a593Smuzhiyunend_flush_dcache:
406*4882a593Smuzhiyun	ret
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun/*
409*4882a593Smuzhiyun * Interrupt handling
410*4882a593Smuzhiyun */
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun/*
413*4882a593Smuzhiyun * exception handlers
414*4882a593Smuzhiyun */
415*4882a593Smuzhiyun	.align	5
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun.macro	SAVE_ALL
418*4882a593Smuzhiyun	! FIXME: Other way to get PC?
419*4882a593Smuzhiyun	! FIXME: Update according to the newest spec!!
420*4882a593Smuzhiyun1:
421*4882a593Smuzhiyun	li	 $r28, 1
422*4882a593Smuzhiyun	push $r28
423*4882a593Smuzhiyun	mfsr $r28, PSW			! $PSW
424*4882a593Smuzhiyun	push $r28
425*4882a593Smuzhiyun	mfsr $r28, EIT_EVA		! $ir1 $EVA
426*4882a593Smuzhiyun	push $r28
427*4882a593Smuzhiyun	mfsr $r28, EIT_ITYPE		! $ir2 $ITYPE
428*4882a593Smuzhiyun	push $r28
429*4882a593Smuzhiyun	mfsr $r28, EIT_MACH_ERR		! $ir3 Mach Error
430*4882a593Smuzhiyun	push $r28
431*4882a593Smuzhiyun	mfsr $r28, EIT_INTR_PSW		! $ir5 $IPSW
432*4882a593Smuzhiyun	push $r28
433*4882a593Smuzhiyun	mfsr $r28, EIT_PREV_IPSW	! $ir6 prev $IPSW
434*4882a593Smuzhiyun	push $r28
435*4882a593Smuzhiyun	mfsr $r28, EIT_PREV_EVA		! $ir7 prev $EVA
436*4882a593Smuzhiyun	push $r28
437*4882a593Smuzhiyun	mfsr $r28, EIT_PREV_ITYPE	! $ir8 prev $ITYPE
438*4882a593Smuzhiyun	push $r28
439*4882a593Smuzhiyun	mfsr $r28, EIT_INTR_PC		! $ir9 Interruption PC
440*4882a593Smuzhiyun	push $r28
441*4882a593Smuzhiyun	mfsr $r28, EIT_PREV_IPC		! $ir10 prev INTR_PC
442*4882a593Smuzhiyun	push $r28
443*4882a593Smuzhiyun	mfsr $r28, EIT_OVL_INTR_PC	! $ir11 Overflowed INTR_PC
444*4882a593Smuzhiyun	push $r28
445*4882a593Smuzhiyun	mfusr $r28, $d1.lo
446*4882a593Smuzhiyun	push $r28
447*4882a593Smuzhiyun	mfusr $r28, $d1.hi
448*4882a593Smuzhiyun	push $r28
449*4882a593Smuzhiyun	mfusr $r28, $d0.lo
450*4882a593Smuzhiyun	push $r28
451*4882a593Smuzhiyun	mfusr $r28, $d0.hi
452*4882a593Smuzhiyun	push $r28
453*4882a593Smuzhiyun	pushm $r0, $r30		! store $sp-$r31, ra-$r30, $gp-$r29, $r28-$fp
454*4882a593Smuzhiyun	addi	$sp, $sp, -4	! make room for implicit pt_regs parameters
455*4882a593Smuzhiyun.endm
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun	.align	5
458*4882a593Smuzhiyuntlb_fill:
459*4882a593Smuzhiyun	SAVE_ALL
460*4882a593Smuzhiyun	move	$r0, $sp			! To get the kernel stack
461*4882a593Smuzhiyun	li	$r1, 1				! Determine interruption type
462*4882a593Smuzhiyun	bal 	do_interruption
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun	.align	5
465*4882a593Smuzhiyuntlb_not_present:
466*4882a593Smuzhiyun	SAVE_ALL
467*4882a593Smuzhiyun	move	$r0, $sp			! To get the kernel stack
468*4882a593Smuzhiyun	li	$r1, 2				! Determine interruption type
469*4882a593Smuzhiyun	bal 	do_interruption
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun	.align	5
472*4882a593Smuzhiyuntlb_misc:
473*4882a593Smuzhiyun	SAVE_ALL
474*4882a593Smuzhiyun	move	$r0, $sp			! To get the kernel stack
475*4882a593Smuzhiyun	li	$r1, 3				! Determine interruption type
476*4882a593Smuzhiyun	bal 	do_interruption
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun	.align	5
479*4882a593Smuzhiyuntlb_vlpt_miss:
480*4882a593Smuzhiyun	SAVE_ALL
481*4882a593Smuzhiyun	move	$r0, $sp			! To get the kernel stack
482*4882a593Smuzhiyun	li	$r1, 4				! Determine interruption type
483*4882a593Smuzhiyun	bal	do_interruption
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun	.align	5
486*4882a593Smuzhiyunmachine_error:
487*4882a593Smuzhiyun	SAVE_ALL
488*4882a593Smuzhiyun	move	$r0, $sp			! To get the kernel stack
489*4882a593Smuzhiyun	li	$r1, 5				! Determine interruption type
490*4882a593Smuzhiyun	bal	do_interruption
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun	.align	5
493*4882a593Smuzhiyundebug:
494*4882a593Smuzhiyun	SAVE_ALL
495*4882a593Smuzhiyun	move	$r0, $sp			! To get the kernel stack
496*4882a593Smuzhiyun	li	$r1, 6				! Determine interruption type
497*4882a593Smuzhiyun	bal	do_interruption
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun	.align	5
500*4882a593Smuzhiyungeneral_exception:
501*4882a593Smuzhiyun	SAVE_ALL
502*4882a593Smuzhiyun	move	$r0, $sp			! To get the kernel stack
503*4882a593Smuzhiyun	li	$r1, 7				! Determine interruption type
504*4882a593Smuzhiyun	bal	do_interruption
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun	.align	5
507*4882a593Smuzhiyunsyscall:
508*4882a593Smuzhiyun	SAVE_ALL
509*4882a593Smuzhiyun	move	$r0, $sp			! To get the kernel stack
510*4882a593Smuzhiyun	li	$r1, 8				! Determine interruption type
511*4882a593Smuzhiyun	bal	do_interruption
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun	.align	5
514*4882a593Smuzhiyuninternal_interrupt:
515*4882a593Smuzhiyun	SAVE_ALL
516*4882a593Smuzhiyun	move	$r0, $sp			! To get the kernel stack
517*4882a593Smuzhiyun	li	$r1, 9				! Determine interruption type
518*4882a593Smuzhiyun	bal	do_interruption
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun	.align	5
521*4882a593Smuzhiyunsoftware_interrupt:
522*4882a593Smuzhiyun	SAVE_ALL
523*4882a593Smuzhiyun	move	$r0, $sp			! To get the kernel stack
524*4882a593Smuzhiyun	li	$r1, 10				! Determine interruption type
525*4882a593Smuzhiyun	bal	do_interruption
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun	.align	5
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun/*
530*4882a593Smuzhiyun * void reset_cpu(ulong addr);
531*4882a593Smuzhiyun * $r0: input address to jump to
532*4882a593Smuzhiyun */
533*4882a593Smuzhiyun.globl reset_cpu
534*4882a593Smuzhiyunreset_cpu:
535*4882a593Smuzhiyun/* No need to disable MMU because we never enable it */
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun	bal	invalidate_icac
538*4882a593Smuzhiyun	bal	invalidate_dcac
539*4882a593Smuzhiyun	mfsr	$p0, $MMU_CFG
540*4882a593Smuzhiyun	andi	$p0, $p0, 0x3			! MMPS
541*4882a593Smuzhiyun	li	$p1, 0x2			! TLB MMU
542*4882a593Smuzhiyun	bne	$p0, $p1, 1f
543*4882a593Smuzhiyun	tlbop	flushall			! Flush TLB
544*4882a593Smuzhiyun1:
545*4882a593Smuzhiyun	mfsr	$p0, MR_CAC_CTL			! Get the $CACHE_CTL reg
546*4882a593Smuzhiyun	li	$p1, DIS_DCAC
547*4882a593Smuzhiyun	and	$p0, $p0, $p1			! Clear the DC_EN bit
548*4882a593Smuzhiyun	mtsr	$p0, MR_CAC_CTL			! Write back the $CACHE_CTL reg
549*4882a593Smuzhiyun	br	$r0				! Jump to the input address
550