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