xref: /openbmc/u-boot/arch/microblaze/cpu/start.S (revision 53ab4af3)
1/*
2 * (C) Copyright 2007 Michal Simek
3 * (C) Copyright 2004 Atmark Techno, Inc.
4 *
5 * Michal  SIMEK <monstr@monstr.eu>
6 * Yasushi SHOJI <yashi@atmark-techno.com>
7 *
8 * SPDX-License-Identifier:	GPL-2.0+
9 */
10
11#include <asm-offsets.h>
12#include <config.h>
13
14	.text
15	.global _start
16_start:
17	/*
18	 * reserve registers:
19	 * r10: Stores little/big endian offset for vectors
20	 * r2: Stores imm opcode
21	 * r3: Stores brai opcode
22	 */
23
24	mts	rmsr, r0	/* disable cache */
25
26	addi	r8, r0, __end
27	mts	rslr, r8
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 defined(CONFIG_SYS_MALLOC_F_LEN)
34	addi	r1, r0, CONFIG_SYS_INIT_SP_OFFSET - CONFIG_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 /* BUILD_SPL */
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
144clear_bss:
145	/* clear BSS segments */
146	addi	r5, r0, __bss_start
147	addi	r4, r0, __bss_end
148	cmp	r6, r5, r4
149	beqi	r6, 3f
1502:
151	swi     r0, r5, 0 /* write zero to loc */
152	addi    r5, r5, 4 /* increment to next loc */
153	cmp     r6, r5, r4 /* check if we have reach the end */
154	bnei    r6, 2b
1553:	/* jumping to board_init */
156#ifndef CONFIG_SPL_BUILD
157	or	r5, r0, r0	/* flags - empty */
158	addi    r31, r0, _gd
159#if defined(CONFIG_SYS_MALLOC_F_LEN)
160	addi	r6, r0, CONFIG_SYS_INIT_SP_OFFSET
161	swi	r6, r31, GD_MALLOC_BASE
162#endif
163	brai	board_init_f
164#else
165	addi	r31, r0, _gd
166#if defined(CONFIG_SYS_MALLOC_F_LEN)
167	addi	r6, r0, CONFIG_SPL_STACK_ADDR
168	swi	r6, r31, GD_MALLOC_BASE
169#endif
170	brai	board_init_r
171#endif
1721:	bri	1b
173
174 .section .bss
175.align 4
176_gd:
177         .space  GENERATED_GBL_DATA_SIZE
178
179#ifndef CONFIG_SPL_BUILD
180/*
181 * Read 16bit little endian
182 */
183	.text
184	.global	in16
185	.ent	in16
186	.align	2
187in16:	lhu	r3, r0, r5
188	bslli	r4, r3, 8
189	bsrli	r3, r3, 8
190	andi	r4, r4, 0xffff
191	or	r3, r3, r4
192	rtsd	r15, 8
193	sext16	r3, r3
194	.end	in16
195
196/*
197 * Write 16bit little endian
198 * first parameter(r5) - address, second(r6) - short value
199 */
200	.text
201	.global	out16
202	.ent	out16
203	.align	2
204out16:	bslli	r3, r6, 8
205	bsrli	r6, r6, 8
206	andi	r3, r3, 0xffff
207	or	r3, r3, r6
208	sh	r3, r0, r5
209	rtsd	r15, 8
210	or	r0, r0, r0
211	.end	out16
212
213/*
214 * Relocate u-boot
215 */
216	.text
217	.global	relocate_code
218	.ent	relocate_code
219	.align	2
220relocate_code:
221	/*
222	 * r5 - start_addr_sp
223	 * r6 - new_gd
224	 * r7 - reloc_addr
225	 */
226	addi	r1, r5, 0 /* Start to use new SP */
227	addi	r31, r6, 0 /* Start to use new GD */
228
229	add	r23, r0, r7 /* Move reloc addr to r23 */
230	/* Relocate text and data - r12 temp value */
231	addi	r21, r0, _start
232	addi	r22, r0, __end - 4 /* Include BSS too */
233
234	rsub	r6, r21, r22
235	or	r5, r0, r0
2361:	lw	r12, r21, r5 /* Load u-boot data */
237	sw	r12, r23, r5 /* Write zero to loc */
238	cmp	r12, r5, r6 /* Check if we have reach the end */
239	bneid	r12, 1b
240	addi	r5, r5, 4 /* Increment to next loc - relocate code */
241
242       /* R23 points to the base address. */
243	add	r23, r0, r7 /* Move reloc addr to r23 */
244	addi	r24, r0, CONFIG_SYS_TEXT_BASE /* Get reloc offset */
245	rsub	r23, r24, r23 /* keep - this is already here gd->reloc_off */
246
247	addik	r6, r0, 0x2 /* BIG/LITTLE endian offset */
248	lwi	r7, r0, 0x28
249	swi	r6, r0, 0x28 /* used first unused MB vector */
250	lbui	r10, r0, 0x28 /* used first unused MB vector */
251	swi	r7, r0, 0x28
252
253#ifdef CONFIG_SYS_USR_EXCEP
254	addik	r6, r0, _exception_handler
255	addk	r6, r6, r23 /* add offset */
256	sw	r6, r1, r0
257	lhu	r7, r1, r10
258	rsubi	r8, r10, 0xa
259	sh	r7, r0, r8
260	rsubi	r8, r10, 0xe
261	sh	r6, r0, r8
262#endif
263	addik	r6, r0, _hw_exception_handler
264	addk	r6, r6, r23 /* add offset */
265	sw	r6, r1, r0
266	lhu	r7, r1, r10
267	rsubi	r8, r10, 0x22
268	sh	r7, r0, r8
269	rsubi	r8, r10, 0x26
270	sh	r6, r0, r8
271
272	addik	r6, r0, _interrupt_handler
273	addk	r6, r6, r23 /* add offset */
274	sw	r6, r1, r0
275	lhu	r7, r1, r10
276	rsubi	r8, r10, 0x12
277	sh	r7, r0, r8
278	rsubi	r8, r10, 0x16
279	sh	r6, r0, r8
280
281	/* Check if GOT exist */
282	addik	r21, r23, _got_start
283	addik	r22, r23, _got_end
284	cmpu	r12, r21, r22
285	beqi	r12, 2f /* No GOT table - jump over */
286
287	/* Skip last 3 entries plus 1 because of loop boundary below */
288	addik	r22, r22, -0x10
289
290        /* Relocate the GOT. */
2913:	lw	r12, r21, r0 /* Load entry */
292	addk	r12, r12, r23 /* Add reloc offset */
293	sw	r12, r21, r0 /* Save entry back */
294
295	cmpu	r12, r21, r22 /* Check if this cross boundary */
296	bneid	r12, 3b
297	addik	r21. r21, 4
298
299	/* Update pointer to GOT */
300	mfs	r20, rpc
301	addik	r20, r20, _GLOBAL_OFFSET_TABLE_ + 8
302	addk	r20, r20, r23
303
304	/* Flush caches to ensure consistency */
305	addik	r5, r0, 0
306	addik	r6, r0, XILINX_DCACHE_BYTE_SIZE
307	bralid	r15, flush_cache
308	nop
309
3102:	addi	r5, r31, 0 /* gd is initialized in board_r.c */
311	addi	r6, r0, CONFIG_SYS_TEXT_BASE
312	addi	r12, r23, board_init_r
313	bra	r12 /* Jump to relocated code */
314
315	.end	relocate_code
316#endif
317