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