1/* SPDX-License-Identifier: GPL-2.0+ */
2/*
3 * (C) Copyright 2004, Psyent Corporation <www.psyent.com>
4 * Scott McNutt <smcnutt@psyent.com>
5 */
6
7#include <asm-offsets.h>
8#include <config.h>
9#include <version.h>
10
11/*
12 * icache and dcache configuration used only for start.S.
13 * the values are chosen so that it will work for all configuration.
14 */
15#define ICACHE_LINE_SIZE	32 /* fixed 32 */
16#define ICACHE_SIZE_MAX		0x10000 /* 64k max */
17#define DCACHE_LINE_SIZE_MIN	4 /* 4, 16, 32 */
18#define DCACHE_SIZE_MAX		0x10000 /* 64k max */
19
20	/* RESTART */
21	.text
22	.global _start, _except_start, _except_end
23
24_start:
25	wrctl	status, r0		/* Disable interrupts */
26	/*
27	 * ICACHE INIT -- only the icache line at the reset address
28	 * is invalidated at reset. So the init must stay within
29	 * the cache line size (8 words). If GERMS is used, we'll
30	 * just be invalidating the cache a second time. If cache
31	 * is not implemented initi behaves as nop.
32	 */
33	ori	r4, r0, %lo(ICACHE_LINE_SIZE)
34	movhi	r5, %hi(ICACHE_SIZE_MAX)
35	ori	r5, r5, %lo(ICACHE_SIZE_MAX)
360:	initi	r5
37	sub	r5, r5, r4
38	bgt	r5, r0, 0b
39	br	_except_end	/* Skip the tramp */
40
41	/*
42	 * EXCEPTION TRAMPOLINE -- the following gets copied
43	 * to the exception address (below), but is otherwise at the
44	 * default exception vector offset (0x0020).
45	 */
46_except_start:
47	movhi	et, %hi(_exception)
48	ori	et, et, %lo(_exception)
49	jmp	et
50_except_end:
51
52	/*
53	 * INTERRUPTS -- for now, all interrupts masked and globally
54	 * disabled.
55	 */
56	wrctl	ienable, r0		/* All disabled	*/
57
58	/*
59	 * DCACHE INIT -- if dcache not implemented, initd behaves as
60	 * nop.
61	 */
62	ori	r4, r0, %lo(DCACHE_LINE_SIZE_MIN)
63	movhi	r5, %hi(DCACHE_SIZE_MAX)
64	ori	r5, r5, %lo(DCACHE_SIZE_MAX)
65	mov	r6, r0
661:	initd	0(r6)
67	add	r6, r6, r4
68	bltu	r6, r5, 1b
69
70	/*
71	 * RELOCATE CODE, DATA & COMMAND TABLE -- the following code
72	 * assumes code, data and the command table are all
73	 * contiguous. This lets us relocate everything as a single
74	 * block. Make sure the linker script matches this ;-)
75	 */
76	nextpc	r4
77_cur:	movhi	r5, %hi(_cur - _start)
78	ori	r5, r5, %lo(_cur - _start)
79	sub	r4, r4, r5		/* r4 <- cur _start */
80	mov	r8, r4
81	movhi	r5, %hi(_start)
82	ori	r5, r5, %lo(_start)	/* r5 <- linked _start */
83	mov	sp, r5		/* initial stack below u-boot code */
84	beq	r4, r5, 3f
85
86	movhi	r6, %hi(CONFIG_SYS_MONITOR_LEN)
87	ori	r6, r6, %lo(CONFIG_SYS_MONITOR_LEN)
88	add	r6, r6, r5
892:	ldwio	r7, 0(r4)
90	addi	r4, r4, 4
91	stwio	r7, 0(r5)
92	addi	r5, r5, 4
93	bne	r5, r6, 2b
943:
95
96	/* JUMP TO RELOC ADDR */
97	movhi	r4, %hi(_reloc)
98	ori	r4, r4, %lo(_reloc)
99	jmp	r4
100_reloc:
101
102	/* STACK INIT -- zero top two words for call back chain. */
103	addi	sp, sp, -8
104	stw	r0, 0(sp)
105	stw	r0, 4(sp)
106	mov	fp, sp
107
108#ifdef CONFIG_DEBUG_UART
109	/* Set up the debug UART */
110	movhi	r2, %hi(debug_uart_init@h)
111	ori	r2, r2, %lo(debug_uart_init@h)
112	callr	r2
113#endif
114
115	/* Allocate and initialize reserved area, update SP */
116	mov	r4, sp
117	movhi	r2, %hi(board_init_f_alloc_reserve@h)
118	ori	r2, r2, %lo(board_init_f_alloc_reserve@h)
119	callr	r2
120	mov	sp, r2
121	mov	r4, sp
122	movhi	r2, %hi(board_init_f_init_reserve@h)
123	ori	r2, r2, %lo(board_init_f_init_reserve@h)
124	callr	r2
125
126	/* Update frame-pointer */
127	mov	fp, sp
128
129	/* Call board_init_f -- never returns */
130	mov	r4, r0
131	movhi	r2, %hi(board_init_f@h)
132	ori	r2, r2, %lo(board_init_f@h)
133	callr	r2
134
135	/*
136	 * NEVER RETURNS -- but branch to the _start just
137	 * in case ;-)
138	 */
139	br	_start
140
141	/*
142	 * relocate_code -- Nios2 handles the relocation above. But
143	 * the generic board code monkeys with the heap, stack, etc.
144	 * (it makes some assumptions that may not be appropriate
145	 * for Nios). Nevertheless, we capitulate here.
146	 *
147	 * We'll call the board_init_r from here since this isn't
148	 * supposed to return.
149	 *
150	 * void relocate_code(ulong sp, gd_t *global_data,
151	 *			ulong reloc_addr)
152	 *			__attribute__ ((noreturn));
153	 */
154	.text
155	.global relocate_code
156
157relocate_code:
158	mov	sp, r4		/* Set the new sp */
159	mov	r4, r5
160
161	/*
162	 * ZERO BSS/SBSS -- bss and sbss are assumed to be adjacent
163	 * and between __bss_start and __bss_end.
164	 */
165	movhi	r5, %hi(__bss_start)
166	ori	r5, r5, %lo(__bss_start)
167	movhi	r6, %hi(__bss_end)
168	ori	r6, r6, %lo(__bss_end)
169	beq	r5, r6, 5f
170
1714:	stw	r0, 0(r5)
172	addi	r5, r5, 4
173	bne	r5, r6, 4b
1745:
175
176	movhi	r8, %hi(board_init_r@h)
177	ori	r8, r8, %lo(board_init_r@h)
178	callr	r8
179	ret
180