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