xref: /openbmc/u-boot/arch/microblaze/cpu/start.S (revision 3ebd892f)
1/* SPDX-License-Identifier: GPL-2.0+ */
2/*
3 * (C) Copyright 2007 Michal Simek
4 * (C) Copyright 2004 Atmark Techno, Inc.
5 *
6 * Michal  SIMEK <monstr@monstr.eu>
7 * Yasushi SHOJI <yashi@atmark-techno.com>
8 */
9
10#include <asm-offsets.h>
11#include <config.h>
12
13	.text
14	.global _start
15_start:
16	/*
17	 * reserve registers:
18	 * r10: Stores little/big endian offset for vectors
19	 * r2: Stores imm opcode
20	 * r3: Stores brai opcode
21	 */
22
23	mts	rmsr, r0	/* disable cache */
24
25	addi	r8, r0, __end
26	mts	rslr, r8
27	/* TODO: Redo this code to call board_init_f_*() */
28#if defined(CONFIG_SPL_BUILD)
29	addi	r1, r0, CONFIG_SPL_STACK_ADDR
30	mts	rshr, r1
31	addi	r1, r1, -4	/* Decrement SP to top of memory */
32#else
33#if CONFIG_VAL(SYS_MALLOC_F_LEN)
34	addi	r1, r0, CONFIG_SYS_INIT_SP_OFFSET - CONFIG_VAL(SYS_MALLOC_F_LEN)
35#else
36	addi	r1, r0, CONFIG_SYS_INIT_SP_OFFSET
37#endif
38	mts	rshr, r1
39	addi	r1, r1, -4	/* Decrement SP to top of memory */
40
41	/* Find-out if u-boot is running on BIG/LITTLE endian platform
42	 * There are some steps which is necessary to keep in mind:
43	 * 1. Setup offset value to r6
44	 * 2. Store word offset value to address 0x0
45	 * 3. Load just byte from address 0x0
46	 * 4a) LITTLE endian - r10 contains 0x2 because it is the smallest
47	 *     value that's why is on address 0x0
48	 * 4b) BIG endian - r10 contains 0x0 because 0x2 offset is on addr 0x3
49	 */
50	addik	r6, r0, 0x2 /* BIG/LITTLE endian offset */
51	lwi	r7, r0, 0x28
52	swi	r6, r0, 0x28 /* used first unused MB vector */
53	lbui	r10, r0, 0x28 /* used first unused MB vector */
54	swi	r7, r0, 0x28
55
56	/* add opcode instruction for 32bit jump - 2 instruction imm & brai */
57	addi	r2, r0, 0xb0000000	/* hex b000 opcode imm */
58	addi	r3, r0, 0xb8080000	/* hew b808 opcode brai */
59
60#ifdef CONFIG_SYS_RESET_ADDRESS
61	/* reset address */
62	swi	r2, r0, 0x0	/* reset address - imm opcode */
63	swi	r3, r0, 0x4	/* reset address - brai opcode */
64
65	addik	r6, r0, CONFIG_SYS_RESET_ADDRESS
66	sw	r6, r1, r0
67	lhu	r7, r1, r10
68	rsubi	r8, r10, 0x2
69	sh	r7, r0, r8
70	rsubi	r8, r10, 0x6
71	sh	r6, r0, r8
72#endif
73
74#ifdef CONFIG_SYS_USR_EXCEP
75	/* user_vector_exception */
76	swi	r2, r0, 0x8	/* user vector exception - imm opcode */
77	swi	r3, r0, 0xC	/* user vector exception - brai opcode */
78
79	addik	r6, r0, _exception_handler
80	sw	r6, r1, r0
81	/*
82	 * BIG ENDIAN memory map for user exception
83	 * 0x8: 0xB000XXXX
84	 * 0xC: 0xB808XXXX
85	 *
86	 * then it is necessary to count address for storing the most significant
87	 * 16bits from _exception_handler address and copy it to
88	 * 0xa address. Big endian use offset in r10=0 that's why is it just
89	 * 0xa address. The same is done for the least significant 16 bits
90	 * for 0xe address.
91	 *
92	 * LITTLE ENDIAN memory map for user exception
93	 * 0x8: 0xXXXX00B0
94	 * 0xC: 0xXXXX08B8
95	 *
96	 * Offset is for little endian setup to 0x2. rsubi instruction decrease
97	 * address value to ensure that points to proper place which is
98	 * 0x8 for the most significant 16 bits and
99	 * 0xC for the least significant 16 bits
100	 */
101	lhu	r7, r1, r10
102	rsubi	r8, r10, 0xa
103	sh	r7, r0, r8
104	rsubi	r8, r10, 0xe
105	sh	r6, r0, r8
106#endif
107
108	/* interrupt_handler */
109	swi	r2, r0, 0x10	/* interrupt - imm opcode */
110	swi	r3, r0, 0x14	/* interrupt - brai opcode */
111
112	addik	r6, r0, _interrupt_handler
113	sw	r6, r1, r0
114	lhu	r7, r1, r10
115	rsubi	r8, r10, 0x12
116	sh	r7, r0, r8
117	rsubi	r8, r10, 0x16
118	sh	r6, r0, r8
119
120	/* hardware exception */
121	swi	r2, r0, 0x20	/* hardware exception - imm opcode */
122	swi	r3, r0, 0x24	/* hardware exception - brai opcode */
123
124	addik	r6, r0, _hw_exception_handler
125	sw	r6, r1, r0
126	lhu	r7, r1, r10
127	rsubi	r8, r10, 0x22
128	sh	r7, r0, r8
129	rsubi	r8, r10, 0x26
130	sh	r6, r0, r8
131#endif /* CONFIG_SPL_BUILD */
132
133	/* Flush cache before enable cache */
134	addik	r5, r0, 0
135	addik	r6, r0, XILINX_DCACHE_BYTE_SIZE
136	bralid r15, flush_cache
137	nop
138
139	/* enable instruction and data cache */
140	mfs	r12, rmsr
141	ori	r12, r12, 0x1a0
142	mts	rmsr, r12
143
144	/* TODO: Redo this code to call board_init_f_*() */
145clear_bss:
146	/* clear BSS segments */
147	addi	r5, r0, __bss_start
148	addi	r4, r0, __bss_end
149	cmp	r6, r5, r4
150	beqi	r6, 3f
1512:
152	swi     r0, r5, 0 /* write zero to loc */
153	addi    r5, r5, 4 /* increment to next loc */
154	cmp     r6, r5, r4 /* check if we have reach the end */
155	bnei    r6, 2b
1563:	/* jumping to board_init */
157#ifdef CONFIG_DEBUG_UART
158	bralid	r15, debug_uart_init
159	nop
160#endif
161#ifndef CONFIG_SPL_BUILD
162	or	r5, r0, r0	/* flags - empty */
163	addi    r31, r0, _gd
164#if CONFIG_VAL(SYS_MALLOC_F_LEN)
165	addi	r6, r0, CONFIG_SYS_INIT_SP_OFFSET
166	swi	r6, r31, GD_MALLOC_BASE
167#endif
168	brai	board_init_f
169#else
170	addi	r31, r0, _gd
171#if CONFIG_VAL(SYS_MALLOC_F_LEN)
172	addi	r6, r0, CONFIG_SPL_STACK_ADDR
173	swi	r6, r31, GD_MALLOC_BASE
174#endif
175	brai	board_init_r
176#endif
1771:	bri	1b
178
179 .section .bss
180.align 4
181_gd:
182         .space  GENERATED_GBL_DATA_SIZE
183
184#ifndef CONFIG_SPL_BUILD
185/*
186 * Read 16bit little endian
187 */
188	.text
189	.global	in16
190	.ent	in16
191	.align	2
192in16:	lhu	r3, r0, r5
193	bslli	r4, r3, 8
194	bsrli	r3, r3, 8
195	andi	r4, r4, 0xffff
196	or	r3, r3, r4
197	rtsd	r15, 8
198	sext16	r3, r3
199	.end	in16
200
201/*
202 * Write 16bit little endian
203 * first parameter(r5) - address, second(r6) - short value
204 */
205	.text
206	.global	out16
207	.ent	out16
208	.align	2
209out16:	bslli	r3, r6, 8
210	bsrli	r6, r6, 8
211	andi	r3, r3, 0xffff
212	or	r3, r3, r6
213	sh	r3, r0, r5
214	rtsd	r15, 8
215	or	r0, r0, r0
216	.end	out16
217
218/*
219 * Relocate u-boot
220 */
221	.text
222	.global	relocate_code
223	.ent	relocate_code
224	.align	2
225relocate_code:
226	/*
227	 * r5 - start_addr_sp
228	 * r6 - new_gd
229	 * r7 - reloc_addr
230	 */
231	addi	r1, r5, 0 /* Start to use new SP */
232	addi	r31, r6, 0 /* Start to use new GD */
233
234	add	r23, r0, r7 /* Move reloc addr to r23 */
235	/* Relocate text and data - r12 temp value */
236	addi	r21, r0, _start
237	addi	r22, r0, __end - 4 /* Include BSS too */
238
239	rsub	r6, r21, r22
240	or	r5, r0, r0
2411:	lw	r12, r21, r5 /* Load u-boot data */
242	sw	r12, r23, r5 /* Write zero to loc */
243	cmp	r12, r5, r6 /* Check if we have reach the end */
244	bneid	r12, 1b
245	addi	r5, r5, 4 /* Increment to next loc - relocate code */
246
247       /* R23 points to the base address. */
248	add	r23, r0, r7 /* Move reloc addr to r23 */
249	addi	r24, r0, CONFIG_SYS_TEXT_BASE /* Get reloc offset */
250	rsub	r23, r24, r23 /* keep - this is already here gd->reloc_off */
251
252	addik	r6, r0, 0x2 /* BIG/LITTLE endian offset */
253	lwi	r7, r0, 0x28
254	swi	r6, r0, 0x28 /* used first unused MB vector */
255	lbui	r10, r0, 0x28 /* used first unused MB vector */
256	swi	r7, r0, 0x28
257
258#ifdef CONFIG_SYS_USR_EXCEP
259	addik	r6, r0, _exception_handler
260	addk	r6, r6, r23 /* add offset */
261	sw	r6, r1, r0
262	lhu	r7, r1, r10
263	rsubi	r8, r10, 0xa
264	sh	r7, r0, r8
265	rsubi	r8, r10, 0xe
266	sh	r6, r0, r8
267#endif
268	addik	r6, r0, _hw_exception_handler
269	addk	r6, r6, r23 /* add offset */
270	sw	r6, r1, r0
271	lhu	r7, r1, r10
272	rsubi	r8, r10, 0x22
273	sh	r7, r0, r8
274	rsubi	r8, r10, 0x26
275	sh	r6, r0, r8
276
277	addik	r6, r0, _interrupt_handler
278	addk	r6, r6, r23 /* add offset */
279	sw	r6, r1, r0
280	lhu	r7, r1, r10
281	rsubi	r8, r10, 0x12
282	sh	r7, r0, r8
283	rsubi	r8, r10, 0x16
284	sh	r6, r0, r8
285
286	/* Check if GOT exist */
287	addik	r21, r23, _got_start
288	addik	r22, r23, _got_end
289	cmpu	r12, r21, r22
290	beqi	r12, 2f /* No GOT table - jump over */
291
292	/* Skip last 3 entries plus 1 because of loop boundary below */
293	addik	r22, r22, -0x10
294
295        /* Relocate the GOT. */
2963:	lw	r12, r21, r0 /* Load entry */
297	addk	r12, r12, r23 /* Add reloc offset */
298	sw	r12, r21, r0 /* Save entry back */
299
300	cmpu	r12, r21, r22 /* Check if this cross boundary */
301	bneid	r12, 3b
302	addik	r21. r21, 4
303
304	/* Update pointer to GOT */
305	mfs	r20, rpc
306	addik	r20, r20, _GLOBAL_OFFSET_TABLE_ + 8
307	addk	r20, r20, r23
308
309	/* Flush caches to ensure consistency */
310	addik	r5, r0, 0
311	addik	r6, r0, XILINX_DCACHE_BYTE_SIZE
312	bralid	r15, flush_cache
313	nop
314
3152:	addi	r5, r31, 0 /* gd is initialized in board_r.c */
316	addi	r6, r0, CONFIG_SYS_TEXT_BASE
317	addi	r12, r23, board_init_r
318	bra	r12 /* Jump to relocated code */
319
320	.end	relocate_code
321#endif
322