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