xref: /openbmc/u-boot/arch/microblaze/cpu/start.S (revision 61a4392a)
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 defined(CONFIG_SYS_MALLOC_F_LEN)
35	addi	r1, r0, CONFIG_SYS_INIT_SP_OFFSET - CONFIG_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 /* BUILD_SPL */
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#ifndef CONFIG_SPL_BUILD
159	or	r5, r0, r0	/* flags - empty */
160	addi    r31, r0, _gd
161#if defined(CONFIG_SYS_MALLOC_F_LEN)
162	addi	r6, r0, CONFIG_SYS_INIT_SP_OFFSET
163	swi	r6, r31, GD_MALLOC_BASE
164#endif
165	brai	board_init_f
166#else
167	addi	r31, r0, _gd
168#if defined(CONFIG_SYS_MALLOC_F_LEN)
169	addi	r6, r0, CONFIG_SPL_STACK_ADDR
170	swi	r6, r31, GD_MALLOC_BASE
171#endif
172	brai	board_init_r
173#endif
1741:	bri	1b
175
176 .section .bss
177.align 4
178_gd:
179         .space  GENERATED_GBL_DATA_SIZE
180
181#ifndef CONFIG_SPL_BUILD
182/*
183 * Read 16bit little endian
184 */
185	.text
186	.global	in16
187	.ent	in16
188	.align	2
189in16:	lhu	r3, r0, r5
190	bslli	r4, r3, 8
191	bsrli	r3, r3, 8
192	andi	r4, r4, 0xffff
193	or	r3, r3, r4
194	rtsd	r15, 8
195	sext16	r3, r3
196	.end	in16
197
198/*
199 * Write 16bit little endian
200 * first parameter(r5) - address, second(r6) - short value
201 */
202	.text
203	.global	out16
204	.ent	out16
205	.align	2
206out16:	bslli	r3, r6, 8
207	bsrli	r6, r6, 8
208	andi	r3, r3, 0xffff
209	or	r3, r3, r6
210	sh	r3, r0, r5
211	rtsd	r15, 8
212	or	r0, r0, r0
213	.end	out16
214
215/*
216 * Relocate u-boot
217 */
218	.text
219	.global	relocate_code
220	.ent	relocate_code
221	.align	2
222relocate_code:
223	/*
224	 * r5 - start_addr_sp
225	 * r6 - new_gd
226	 * r7 - reloc_addr
227	 */
228	addi	r1, r5, 0 /* Start to use new SP */
229	addi	r31, r6, 0 /* Start to use new GD */
230
231	add	r23, r0, r7 /* Move reloc addr to r23 */
232	/* Relocate text and data - r12 temp value */
233	addi	r21, r0, _start
234	addi	r22, r0, __end - 4 /* Include BSS too */
235
236	rsub	r6, r21, r22
237	or	r5, r0, r0
2381:	lw	r12, r21, r5 /* Load u-boot data */
239	sw	r12, r23, r5 /* Write zero to loc */
240	cmp	r12, r5, r6 /* Check if we have reach the end */
241	bneid	r12, 1b
242	addi	r5, r5, 4 /* Increment to next loc - relocate code */
243
244       /* R23 points to the base address. */
245	add	r23, r0, r7 /* Move reloc addr to r23 */
246	addi	r24, r0, CONFIG_SYS_TEXT_BASE /* Get reloc offset */
247	rsub	r23, r24, r23 /* keep - this is already here gd->reloc_off */
248
249	addik	r6, r0, 0x2 /* BIG/LITTLE endian offset */
250	lwi	r7, r0, 0x28
251	swi	r6, r0, 0x28 /* used first unused MB vector */
252	lbui	r10, r0, 0x28 /* used first unused MB vector */
253	swi	r7, r0, 0x28
254
255#ifdef CONFIG_SYS_USR_EXCEP
256	addik	r6, r0, _exception_handler
257	addk	r6, r6, r23 /* add offset */
258	sw	r6, r1, r0
259	lhu	r7, r1, r10
260	rsubi	r8, r10, 0xa
261	sh	r7, r0, r8
262	rsubi	r8, r10, 0xe
263	sh	r6, r0, r8
264#endif
265	addik	r6, r0, _hw_exception_handler
266	addk	r6, r6, r23 /* add offset */
267	sw	r6, r1, r0
268	lhu	r7, r1, r10
269	rsubi	r8, r10, 0x22
270	sh	r7, r0, r8
271	rsubi	r8, r10, 0x26
272	sh	r6, r0, r8
273
274	addik	r6, r0, _interrupt_handler
275	addk	r6, r6, r23 /* add offset */
276	sw	r6, r1, r0
277	lhu	r7, r1, r10
278	rsubi	r8, r10, 0x12
279	sh	r7, r0, r8
280	rsubi	r8, r10, 0x16
281	sh	r6, r0, r8
282
283	/* Check if GOT exist */
284	addik	r21, r23, _got_start
285	addik	r22, r23, _got_end
286	cmpu	r12, r21, r22
287	beqi	r12, 2f /* No GOT table - jump over */
288
289	/* Skip last 3 entries plus 1 because of loop boundary below */
290	addik	r22, r22, -0x10
291
292        /* Relocate the GOT. */
2933:	lw	r12, r21, r0 /* Load entry */
294	addk	r12, r12, r23 /* Add reloc offset */
295	sw	r12, r21, r0 /* Save entry back */
296
297	cmpu	r12, r21, r22 /* Check if this cross boundary */
298	bneid	r12, 3b
299	addik	r21. r21, 4
300
301	/* Update pointer to GOT */
302	mfs	r20, rpc
303	addik	r20, r20, _GLOBAL_OFFSET_TABLE_ + 8
304	addk	r20, r20, r23
305
306	/* Flush caches to ensure consistency */
307	addik	r5, r0, 0
308	addik	r6, r0, XILINX_DCACHE_BYTE_SIZE
309	bralid	r15, flush_cache
310	nop
311
3122:	addi	r5, r31, 0 /* gd is initialized in board_r.c */
313	addi	r6, r0, CONFIG_SYS_TEXT_BASE
314	addi	r12, r23, board_init_r
315	bra	r12 /* Jump to relocated code */
316
317	.end	relocate_code
318#endif
319