1/* SPDX-License-Identifier: GPL-2.0+ */
2/*
3 *  Startup Code for MIPS32 CPU-core
4 *
5 *  Copyright (c) 2003	Wolfgang Denk <wd@denx.de>
6 */
7
8#include <asm-offsets.h>
9#include <config.h>
10#include <asm/asm.h>
11#include <asm/regdef.h>
12#include <asm/mipsregs.h>
13
14#ifndef CONFIG_SYS_INIT_SP_ADDR
15#define CONFIG_SYS_INIT_SP_ADDR	(CONFIG_SYS_SDRAM_BASE + \
16				CONFIG_SYS_INIT_SP_OFFSET)
17#endif
18
19#ifdef CONFIG_32BIT
20# define STATUS_SET	0
21#endif
22
23#ifdef CONFIG_64BIT
24# define STATUS_SET	ST0_KX
25#endif
26
27	.set noreorder
28
29	.macro init_wr sel
30	MTC0	zero, CP0_WATCHLO,\sel
31	mtc0	t1, CP0_WATCHHI,\sel
32	mfc0	t0, CP0_WATCHHI,\sel
33	bgez	t0, wr_done
34	 nop
35	.endm
36
37	.macro uhi_mips_exception
38	move	k0, t9		# preserve t9 in k0
39	move	k1, a0		# preserve a0 in k1
40	li	t9, 15		# UHI exception operation
41	li	a0, 0		# Use hard register context
42	sdbbp	1		# Invoke UHI operation
43	.endm
44
45	.macro setup_stack_gd
46	li	t0, -16
47	PTR_LI	t1, CONFIG_SYS_INIT_SP_ADDR
48	and	sp, t1, t0		# force 16 byte alignment
49	PTR_SUBU \
50		sp, sp, GD_SIZE		# reserve space for gd
51	and	sp, sp, t0		# force 16 byte alignment
52	move	k0, sp			# save gd pointer
53#if CONFIG_VAL(SYS_MALLOC_F_LEN) && \
54    !CONFIG_IS_ENABLED(INIT_STACK_WITHOUT_MALLOC_F)
55	li	t2, CONFIG_VAL(SYS_MALLOC_F_LEN)
56	PTR_SUBU \
57		sp, sp, t2		# reserve space for early malloc
58	and	sp, sp, t0		# force 16 byte alignment
59#endif
60	move	fp, sp
61
62	/* Clear gd */
63	move	t0, k0
641:
65	PTR_S	zero, 0(t0)
66	PTR_ADDIU t0, PTRSIZE
67	blt	t0, t1, 1b
68	 nop
69
70#if CONFIG_VAL(SYS_MALLOC_F_LEN) && \
71    !CONFIG_IS_ENABLED(INIT_STACK_WITHOUT_MALLOC_F)
72	PTR_S	sp, GD_MALLOC_BASE(k0)	# gd->malloc_base offset
73#endif
74	.endm
75
76ENTRY(_start)
77	/*
78	 * U-Boot entry point.
79	 * Do not add instructions to the branch delay slot! Some SoC's
80	 * like Octeon might patch the final U-Boot binary at this location
81	 * with additional boot headers.
82	 */
83	b	reset
84	 nop
85
86#if defined(CONFIG_MIPS_INSERT_BOOT_CONFIG)
87	/*
88	 * Store some board-specific boot configuration. This is used by some
89	 * MIPS systems like Malta.
90	 */
91	.org 0x10
92	.word CONFIG_MIPS_BOOT_CONFIG_WORD0
93	.word CONFIG_MIPS_BOOT_CONFIG_WORD1
94#endif
95
96#if defined(CONFIG_ROM_EXCEPTION_VECTORS)
97	/*
98	 * Exception vector entry points. When running from ROM, an exception
99	 * cannot be handled. Halt execution and transfer control to debugger,
100	 * if one is attached.
101	 */
102	.org 0x200
103	/* TLB refill, 32 bit task */
104	uhi_mips_exception
105
106	.org 0x280
107	/* XTLB refill, 64 bit task */
108	uhi_mips_exception
109
110	.org 0x300
111	/* Cache error exception */
112	uhi_mips_exception
113
114	.org 0x380
115	/* General exception */
116	uhi_mips_exception
117
118	.org 0x400
119	/* Catch interrupt exceptions */
120	uhi_mips_exception
121
122	.org 0x480
123	/* EJTAG debug exception */
1241:	b	1b
125	 nop
126
127	.org 0x500
128#endif
129
130reset:
131	mtc0	zero, CP0_COUNT	# clear cp0 count for most accurate boot timing
132#if __mips_isa_rev >= 6
133	mfc0	t0, CP0_CONFIG, 5
134	and	t0, t0, MIPS_CONF5_VP
135	beqz	t0, 1f
136	 nop
137
138	b	2f
139	 mfc0	t0, CP0_GLOBALNUMBER
140#endif
141
142#ifdef CONFIG_ARCH_BMIPS
1431:	mfc0	t0, CP0_DIAGNOSTIC, 3
144	and	t0, t0, (1 << 31)
145#else
1461:	mfc0	t0, CP0_EBASE
147	and	t0, t0, MIPS_EBASE_CPUNUM
148#endif
149
150	/* Hang if this isn't the first CPU in the system */
1512:	beqz	t0, 4f
152	 nop
1533:	wait
154	b	3b
155	 nop
156
157	/* Init CP0 Status */
1584:	mfc0	t0, CP0_STATUS
159	and	t0, ST0_IMPL
160	or	t0, ST0_BEV | ST0_ERL | STATUS_SET
161	mtc0	t0, CP0_STATUS
162
163	/*
164	 * Check whether CP0 Config1 is implemented. If not continue
165	 * with legacy Watch register initialization.
166	 */
167	mfc0	t0, CP0_CONFIG
168	bgez	t0, wr_legacy
169	 nop
170
171	/*
172	 * Check WR bit in CP0 Config1 to determine if Watch registers
173	 * are implemented.
174	 */
175	mfc0	t0, CP0_CONFIG, 1
176	andi	t0, (1 << 3)
177	beqz	t0, wr_done
178	 nop
179
180	/* Clear Watch Status bits and disable watch exceptions */
181	li	t1, 0x7		# Clear I, R and W conditions
182	init_wr	0
183	init_wr	1
184	init_wr	2
185	init_wr	3
186	init_wr	4
187	init_wr	5
188	init_wr	6
189	init_wr	7
190	b	wr_done
191	 nop
192
193wr_legacy:
194	MTC0	zero, CP0_WATCHLO
195	mtc0	zero, CP0_WATCHHI
196
197wr_done:
198	/* Clear WP, IV and SW interrupts */
199	mtc0	zero, CP0_CAUSE
200
201	/* Clear timer interrupt (CP0_COUNT cleared on branch to 'reset') */
202	mtc0	zero, CP0_COMPARE
203
204#ifdef CONFIG_MIPS_CACHE_DISABLE
205	/* Disable caches */
206	PTR_LA	t9, mips_cache_disable
207	jalr	t9
208	 nop
209#endif
210
211#ifdef CONFIG_MIPS_CM
212	PTR_LA	t9, mips_cm_map
213	jalr	t9
214	 nop
215#endif
216
217#ifdef CONFIG_MIPS_INIT_STACK_IN_SRAM
218#ifdef CONFIG_MIPS_SRAM_INIT
219	/* Initialize the SRAM first */
220	PTR_LA	t9, mips_sram_init
221	jalr	t9
222	 nop
223#endif
224
225	/* Set up initial stack and global data */
226	setup_stack_gd
227
228# ifdef CONFIG_DEBUG_UART
229	/* Earliest point to set up debug uart */
230	PTR_LA	t9, debug_uart_init
231	jalr	t9
232	 nop
233# endif
234#endif
235
236#ifndef CONFIG_SKIP_LOWLEVEL_INIT
237# ifdef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD
238	/* Initialize any external memory */
239	PTR_LA	t9, lowlevel_init
240	jalr	t9
241	 nop
242# endif
243#endif
244
245#ifdef CONFIG_MIPS_MACH_EARLY_INIT
246	bal	mips_mach_early_init
247	 nop
248#endif
249
250#ifdef CONFIG_MIPS_CACHE_SETUP
251	/* Initialize caches... */
252	PTR_LA	t9, mips_cache_reset
253	jalr	t9
254	 nop
255#endif
256
257#ifndef CONFIG_SKIP_LOWLEVEL_INIT
258# ifndef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD
259	/* Initialize any external memory */
260	PTR_LA	t9, lowlevel_init
261	jalr	t9
262	 nop
263# endif
264#endif
265
266#ifndef CONFIG_MIPS_INIT_STACK_IN_SRAM
267	/* Set up initial stack and global data */
268	setup_stack_gd
269
270# ifdef CONFIG_DEBUG_UART
271	/* Earliest point to set up debug uart */
272	PTR_LA	t9, debug_uart_init
273	jalr	t9
274	 nop
275# endif
276#endif
277
278	move	a0, zero		# a0 <-- boot_flags = 0
279	PTR_LA	t9, board_init_f
280
281	jr	t9
282	 move	ra, zero
283
284	END(_start)
285