xref: /openbmc/u-boot/arch/microblaze/cpu/start.S (revision 83d290c56fab2d38cd1ab4c4cc7099559c1d5046)
1*83d290c5STom Rini/* SPDX-License-Identifier: GPL-2.0+ */
26260fb04SPeter Tyser/*
36260fb04SPeter Tyser * (C) Copyright 2007 Michal Simek
46260fb04SPeter Tyser * (C) Copyright 2004 Atmark Techno, Inc.
56260fb04SPeter Tyser *
66260fb04SPeter Tyser * Michal  SIMEK <monstr@monstr.eu>
76260fb04SPeter Tyser * Yasushi SHOJI <yashi@atmark-techno.com>
86260fb04SPeter Tyser */
96260fb04SPeter Tyser
1025ddd1fbSWolfgang Denk#include <asm-offsets.h>
116260fb04SPeter Tyser#include <config.h>
126260fb04SPeter Tyser
136260fb04SPeter Tyser	.text
146260fb04SPeter Tyser	.global _start
156260fb04SPeter Tyser_start:
1686c1b2a8SMichal Simek	/*
1786c1b2a8SMichal Simek	 * reserve registers:
1886c1b2a8SMichal Simek	 * r10: Stores little/big endian offset for vectors
1986c1b2a8SMichal Simek	 * r2: Stores imm opcode
2086c1b2a8SMichal Simek	 * r3: Stores brai opcode
2186c1b2a8SMichal Simek	 */
2286c1b2a8SMichal Simek
236260fb04SPeter Tyser	mts	rmsr, r0	/* disable cache */
249d242745SMichal Simek
25da931af1SMichal Simek	addi	r8, r0, __end
26da931af1SMichal Simek	mts	rslr, r8
27ecc30663SAlbert ARIBAUD	/* TODO: Redo this code to call board_init_f_*() */
289d242745SMichal Simek#if defined(CONFIG_SPL_BUILD)
299d242745SMichal Simek	addi	r1, r0, CONFIG_SPL_STACK_ADDR
30da931af1SMichal Simek	mts	rshr, r1
319d242745SMichal Simek	addi	r1, r1, -4	/* Decrement SP to top of memory */
329d242745SMichal Simek#else
339eea5016SAndy Yan#if CONFIG_VAL(SYS_MALLOC_F_LEN)
349eea5016SAndy Yan	addi	r1, r0, CONFIG_SYS_INIT_SP_OFFSET - CONFIG_VAL(SYS_MALLOC_F_LEN)
35405e651dSMichal Simek#else
366260fb04SPeter Tyser	addi	r1, r0, CONFIG_SYS_INIT_SP_OFFSET
37405e651dSMichal Simek#endif
38da931af1SMichal Simek	mts	rshr, r1
396260fb04SPeter Tyser	addi	r1, r1, -4	/* Decrement SP to top of memory */
40b98cba09SMichal Simek
41b98cba09SMichal Simek	/* Find-out if u-boot is running on BIG/LITTLE endian platform
42b98cba09SMichal Simek	 * There are some steps which is necessary to keep in mind:
43b98cba09SMichal Simek	 * 1. Setup offset value to r6
44b98cba09SMichal Simek	 * 2. Store word offset value to address 0x0
45b98cba09SMichal Simek	 * 3. Load just byte from address 0x0
46b98cba09SMichal Simek	 * 4a) LITTLE endian - r10 contains 0x2 because it is the smallest
47b98cba09SMichal Simek	 *     value that's why is on address 0x0
48b98cba09SMichal Simek	 * 4b) BIG endian - r10 contains 0x0 because 0x2 offset is on addr 0x3
49b98cba09SMichal Simek	 */
50b98cba09SMichal Simek	addik	r6, r0, 0x2 /* BIG/LITTLE endian offset */
51f3090fceSMichal Simek	lwi	r7, r0, 0x28
52f3090fceSMichal Simek	swi	r6, r0, 0x28 /* used first unused MB vector */
53f3090fceSMichal Simek	lbui	r10, r0, 0x28 /* used first unused MB vector */
54f3090fceSMichal Simek	swi	r7, r0, 0x28
55b98cba09SMichal Simek
566260fb04SPeter Tyser	/* add opcode instruction for 32bit jump - 2 instruction imm & brai */
5786c1b2a8SMichal Simek	addi	r2, r0, 0xb0000000	/* hex b000 opcode imm */
5886c1b2a8SMichal Simek	addi	r3, r0, 0xb8080000	/* hew b808 opcode brai */
596260fb04SPeter Tyser
606260fb04SPeter Tyser#ifdef CONFIG_SYS_RESET_ADDRESS
616260fb04SPeter Tyser	/* reset address */
6286c1b2a8SMichal Simek	swi	r2, r0, 0x0	/* reset address - imm opcode */
6386c1b2a8SMichal Simek	swi	r3, r0, 0x4	/* reset address - brai opcode */
6486c1b2a8SMichal Simek
656260fb04SPeter Tyser	addik	r6, r0, CONFIG_SYS_RESET_ADDRESS
666260fb04SPeter Tyser	sw	r6, r1, r0
675562bcc2SMichal Simek	lhu	r7, r1, r10
685562bcc2SMichal Simek	rsubi	r8, r10, 0x2
695562bcc2SMichal Simek	sh	r7, r0, r8
705562bcc2SMichal Simek	rsubi	r8, r10, 0x6
715562bcc2SMichal Simek	sh	r6, r0, r8
726260fb04SPeter Tyser#endif
736260fb04SPeter Tyser
746260fb04SPeter Tyser#ifdef CONFIG_SYS_USR_EXCEP
756260fb04SPeter Tyser	/* user_vector_exception */
7686c1b2a8SMichal Simek	swi	r2, r0, 0x8	/* user vector exception - imm opcode */
7786c1b2a8SMichal Simek	swi	r3, r0, 0xC	/* user vector exception - brai opcode */
7886c1b2a8SMichal Simek
796260fb04SPeter Tyser	addik	r6, r0, _exception_handler
806260fb04SPeter Tyser	sw	r6, r1, r0
81b98cba09SMichal Simek	/*
82b98cba09SMichal Simek	 * BIG ENDIAN memory map for user exception
83b98cba09SMichal Simek	 * 0x8: 0xB000XXXX
84b98cba09SMichal Simek	 * 0xC: 0xB808XXXX
85b98cba09SMichal Simek	 *
86b98cba09SMichal Simek	 * then it is necessary to count address for storing the most significant
87b98cba09SMichal Simek	 * 16bits from _exception_handler address and copy it to
88b98cba09SMichal Simek	 * 0xa address. Big endian use offset in r10=0 that's why is it just
89b98cba09SMichal Simek	 * 0xa address. The same is done for the least significant 16 bits
90b98cba09SMichal Simek	 * for 0xe address.
91b98cba09SMichal Simek	 *
92b98cba09SMichal Simek	 * LITTLE ENDIAN memory map for user exception
93b98cba09SMichal Simek	 * 0x8: 0xXXXX00B0
94b98cba09SMichal Simek	 * 0xC: 0xXXXX08B8
95b98cba09SMichal Simek	 *
96b98cba09SMichal Simek	 * Offset is for little endian setup to 0x2. rsubi instruction decrease
97b98cba09SMichal Simek	 * address value to ensure that points to proper place which is
98b98cba09SMichal Simek	 * 0x8 for the most significant 16 bits and
99b98cba09SMichal Simek	 * 0xC for the least significant 16 bits
100b98cba09SMichal Simek	 */
101b98cba09SMichal Simek	lhu	r7, r1, r10
102b98cba09SMichal Simek	rsubi	r8, r10, 0xa
103b98cba09SMichal Simek	sh	r7, r0, r8
104b98cba09SMichal Simek	rsubi	r8, r10, 0xe
105b98cba09SMichal Simek	sh	r6, r0, r8
1066260fb04SPeter Tyser#endif
1076260fb04SPeter Tyser
1086260fb04SPeter Tyser	/* interrupt_handler */
10986c1b2a8SMichal Simek	swi	r2, r0, 0x10	/* interrupt - imm opcode */
11086c1b2a8SMichal Simek	swi	r3, r0, 0x14	/* interrupt - brai opcode */
11186c1b2a8SMichal Simek
1126260fb04SPeter Tyser	addik	r6, r0, _interrupt_handler
1136260fb04SPeter Tyser	sw	r6, r1, r0
114b98cba09SMichal Simek	lhu	r7, r1, r10
115b98cba09SMichal Simek	rsubi	r8, r10, 0x12
116b98cba09SMichal Simek	sh	r7, r0, r8
117b98cba09SMichal Simek	rsubi	r8, r10, 0x16
118b98cba09SMichal Simek	sh	r6, r0, r8
1196260fb04SPeter Tyser
1206260fb04SPeter Tyser	/* hardware exception */
12186c1b2a8SMichal Simek	swi	r2, r0, 0x20	/* hardware exception - imm opcode */
12286c1b2a8SMichal Simek	swi	r3, r0, 0x24	/* hardware exception - brai opcode */
12386c1b2a8SMichal Simek
1246260fb04SPeter Tyser	addik	r6, r0, _hw_exception_handler
1256260fb04SPeter Tyser	sw	r6, r1, r0
126b98cba09SMichal Simek	lhu	r7, r1, r10
127b98cba09SMichal Simek	rsubi	r8, r10, 0x22
128b98cba09SMichal Simek	sh	r7, r0, r8
129b98cba09SMichal Simek	rsubi	r8, r10, 0x26
130b98cba09SMichal Simek	sh	r6, r0, r8
1311d82e2c1SMichal Simek#endif /* CONFIG_SPL_BUILD */
1326260fb04SPeter Tyser
1335811830fSMichal Simek	/* Flush cache before enable cache */
1345811830fSMichal Simek	addik	r5, r0, 0
1355811830fSMichal Simek	addik	r6, r0, XILINX_DCACHE_BYTE_SIZE
136e4a4743eSMichal Simek	bralid r15, flush_cache
1375811830fSMichal Simek	nop
1385811830fSMichal Simek
1396260fb04SPeter Tyser	/* enable instruction and data cache */
1406260fb04SPeter Tyser	mfs	r12, rmsr
141822d43a6SMichal Simek	ori	r12, r12, 0x1a0
1426260fb04SPeter Tyser	mts	rmsr, r12
1436260fb04SPeter Tyser
144ecc30663SAlbert ARIBAUD	/* TODO: Redo this code to call board_init_f_*() */
1456260fb04SPeter Tyserclear_bss:
1466260fb04SPeter Tyser	/* clear BSS segments */
1476260fb04SPeter Tyser	addi	r5, r0, __bss_start
1486260fb04SPeter Tyser	addi	r4, r0, __bss_end
1496260fb04SPeter Tyser	cmp	r6, r5, r4
1506260fb04SPeter Tyser	beqi	r6, 3f
1516260fb04SPeter Tyser2:
1526260fb04SPeter Tyser	swi     r0, r5, 0 /* write zero to loc */
1536260fb04SPeter Tyser	addi    r5, r5, 4 /* increment to next loc */
1546260fb04SPeter Tyser	cmp     r6, r5, r4 /* check if we have reach the end */
1556260fb04SPeter Tyser	bnei    r6, 2b
1566260fb04SPeter Tyser3:	/* jumping to board_init */
15748470b7aSMichal Simek#ifdef CONFIG_DEBUG_UART
15848470b7aSMichal Simek	bralid	r15, debug_uart_init
15948470b7aSMichal Simek	nop
16048470b7aSMichal Simek#endif
1619d242745SMichal Simek#ifndef CONFIG_SPL_BUILD
162e945f6dcSMichal Simek	or	r5, r0, r0	/* flags - empty */
1630510b14bSMichal Simek	addi    r31, r0, _gd
1649eea5016SAndy Yan#if CONFIG_VAL(SYS_MALLOC_F_LEN)
165405e651dSMichal Simek	addi	r6, r0, CONFIG_SYS_INIT_SP_OFFSET
166405e651dSMichal Simek	swi	r6, r31, GD_MALLOC_BASE
167405e651dSMichal Simek#endif
1682380b8f5SMichal Simek	brai	board_init_f
1699d242745SMichal Simek#else
170ca7d2266SMichal Simek	addi	r31, r0, _gd
1719eea5016SAndy Yan#if CONFIG_VAL(SYS_MALLOC_F_LEN)
172ca7d2266SMichal Simek	addi	r6, r0, CONFIG_SPL_STACK_ADDR
173ca7d2266SMichal Simek	swi	r6, r31, GD_MALLOC_BASE
174ca7d2266SMichal Simek#endif
1759d242745SMichal Simek	brai	board_init_r
1769d242745SMichal Simek#endif
1776260fb04SPeter Tyser1:	bri	1b
1786260fb04SPeter Tyser
1790510b14bSMichal Simek .section .bss
1800510b14bSMichal Simek.align 4
1810510b14bSMichal Simek_gd:
1820510b14bSMichal Simek         .space  GENERATED_GBL_DATA_SIZE
1830510b14bSMichal Simek
1849d242745SMichal Simek#ifndef CONFIG_SPL_BUILD
1856260fb04SPeter Tyser/*
1866260fb04SPeter Tyser * Read 16bit little endian
1876260fb04SPeter Tyser */
1886260fb04SPeter Tyser	.text
1896260fb04SPeter Tyser	.global	in16
1906260fb04SPeter Tyser	.ent	in16
1916260fb04SPeter Tyser	.align	2
1926260fb04SPeter Tyserin16:	lhu	r3, r0, r5
1936260fb04SPeter Tyser	bslli	r4, r3, 8
1946260fb04SPeter Tyser	bsrli	r3, r3, 8
1956260fb04SPeter Tyser	andi	r4, r4, 0xffff
1966260fb04SPeter Tyser	or	r3, r3, r4
1976260fb04SPeter Tyser	rtsd	r15, 8
1986260fb04SPeter Tyser	sext16	r3, r3
1996260fb04SPeter Tyser	.end	in16
2006260fb04SPeter Tyser
2016260fb04SPeter Tyser/*
2026260fb04SPeter Tyser * Write 16bit little endian
2036260fb04SPeter Tyser * first parameter(r5) - address, second(r6) - short value
2046260fb04SPeter Tyser */
2056260fb04SPeter Tyser	.text
2066260fb04SPeter Tyser	.global	out16
2076260fb04SPeter Tyser	.ent	out16
2086260fb04SPeter Tyser	.align	2
2096260fb04SPeter Tyserout16:	bslli	r3, r6, 8
2106260fb04SPeter Tyser	bsrli	r6, r6, 8
2116260fb04SPeter Tyser	andi	r3, r3, 0xffff
2126260fb04SPeter Tyser	or	r3, r3, r6
2136260fb04SPeter Tyser	sh	r3, r0, r5
2146260fb04SPeter Tyser	rtsd	r15, 8
2156260fb04SPeter Tyser	or	r0, r0, r0
2166260fb04SPeter Tyser	.end	out16
217e945f6dcSMichal Simek
218e945f6dcSMichal Simek/*
219e945f6dcSMichal Simek * Relocate u-boot
220e945f6dcSMichal Simek */
221e945f6dcSMichal Simek	.text
222e945f6dcSMichal Simek	.global	relocate_code
223e945f6dcSMichal Simek	.ent	relocate_code
224e945f6dcSMichal Simek	.align	2
225e945f6dcSMichal Simekrelocate_code:
226e945f6dcSMichal Simek	/*
227e945f6dcSMichal Simek	 * r5 - start_addr_sp
228e945f6dcSMichal Simek	 * r6 - new_gd
229e945f6dcSMichal Simek	 * r7 - reloc_addr
230e945f6dcSMichal Simek	 */
231e945f6dcSMichal Simek	addi	r1, r5, 0 /* Start to use new SP */
232e945f6dcSMichal Simek	addi	r31, r6, 0 /* Start to use new GD */
233e945f6dcSMichal Simek
234e945f6dcSMichal Simek	add	r23, r0, r7 /* Move reloc addr to r23 */
235e945f6dcSMichal Simek	/* Relocate text and data - r12 temp value */
236e945f6dcSMichal Simek	addi	r21, r0, _start
237e945f6dcSMichal Simek	addi	r22, r0, __end - 4 /* Include BSS too */
2387c4dd542SMichal Simek
2397c4dd542SMichal Simek	rsub	r6, r21, r22
2407c4dd542SMichal Simek	or	r5, r0, r0
2417c4dd542SMichal Simek1:	lw	r12, r21, r5 /* Load u-boot data */
2427c4dd542SMichal Simek	sw	r12, r23, r5 /* Write zero to loc */
2437c4dd542SMichal Simek	cmp	r12, r5, r6 /* Check if we have reach the end */
244e945f6dcSMichal Simek	bneid	r12, 1b
2457c4dd542SMichal Simek	addi	r5, r5, 4 /* Increment to next loc - relocate code */
246e945f6dcSMichal Simek
247e945f6dcSMichal Simek       /* R23 points to the base address. */
248e945f6dcSMichal Simek	add	r23, r0, r7 /* Move reloc addr to r23 */
249e945f6dcSMichal Simek	addi	r24, r0, CONFIG_SYS_TEXT_BASE /* Get reloc offset */
250e945f6dcSMichal Simek	rsub	r23, r24, r23 /* keep - this is already here gd->reloc_off */
251e945f6dcSMichal Simek
252e945f6dcSMichal Simek	addik	r6, r0, 0x2 /* BIG/LITTLE endian offset */
253e945f6dcSMichal Simek	lwi	r7, r0, 0x28
254e945f6dcSMichal Simek	swi	r6, r0, 0x28 /* used first unused MB vector */
255e945f6dcSMichal Simek	lbui	r10, r0, 0x28 /* used first unused MB vector */
256e945f6dcSMichal Simek	swi	r7, r0, 0x28
257e945f6dcSMichal Simek
258e945f6dcSMichal Simek#ifdef CONFIG_SYS_USR_EXCEP
259e945f6dcSMichal Simek	addik	r6, r0, _exception_handler
260e945f6dcSMichal Simek	addk	r6, r6, r23 /* add offset */
261e945f6dcSMichal Simek	sw	r6, r1, r0
262e945f6dcSMichal Simek	lhu	r7, r1, r10
263e945f6dcSMichal Simek	rsubi	r8, r10, 0xa
264e945f6dcSMichal Simek	sh	r7, r0, r8
265e945f6dcSMichal Simek	rsubi	r8, r10, 0xe
266e945f6dcSMichal Simek	sh	r6, r0, r8
267e945f6dcSMichal Simek#endif
268e945f6dcSMichal Simek	addik	r6, r0, _hw_exception_handler
269e945f6dcSMichal Simek	addk	r6, r6, r23 /* add offset */
270e945f6dcSMichal Simek	sw	r6, r1, r0
271e945f6dcSMichal Simek	lhu	r7, r1, r10
272e945f6dcSMichal Simek	rsubi	r8, r10, 0x22
273e945f6dcSMichal Simek	sh	r7, r0, r8
274e945f6dcSMichal Simek	rsubi	r8, r10, 0x26
275e945f6dcSMichal Simek	sh	r6, r0, r8
276e945f6dcSMichal Simek
277e945f6dcSMichal Simek	addik	r6, r0, _interrupt_handler
278e945f6dcSMichal Simek	addk	r6, r6, r23 /* add offset */
279e945f6dcSMichal Simek	sw	r6, r1, r0
280e945f6dcSMichal Simek	lhu	r7, r1, r10
281e945f6dcSMichal Simek	rsubi	r8, r10, 0x12
282e945f6dcSMichal Simek	sh	r7, r0, r8
283e945f6dcSMichal Simek	rsubi	r8, r10, 0x16
284e945f6dcSMichal Simek	sh	r6, r0, r8
285e945f6dcSMichal Simek
286e945f6dcSMichal Simek	/* Check if GOT exist */
287e945f6dcSMichal Simek	addik	r21, r23, _got_start
288e945f6dcSMichal Simek	addik	r22, r23, _got_end
289e945f6dcSMichal Simek	cmpu	r12, r21, r22
290e945f6dcSMichal Simek	beqi	r12, 2f /* No GOT table - jump over */
291e945f6dcSMichal Simek
292e945f6dcSMichal Simek	/* Skip last 3 entries plus 1 because of loop boundary below */
293e945f6dcSMichal Simek	addik	r22, r22, -0x10
294e945f6dcSMichal Simek
295e945f6dcSMichal Simek        /* Relocate the GOT. */
296e945f6dcSMichal Simek3:	lw	r12, r21, r0 /* Load entry */
297e945f6dcSMichal Simek	addk	r12, r12, r23 /* Add reloc offset */
298e945f6dcSMichal Simek	sw	r12, r21, r0 /* Save entry back */
299e945f6dcSMichal Simek
300e945f6dcSMichal Simek	cmpu	r12, r21, r22 /* Check if this cross boundary */
301e945f6dcSMichal Simek	bneid	r12, 3b
302e945f6dcSMichal Simek	addik	r21. r21, 4
303e945f6dcSMichal Simek
304e945f6dcSMichal Simek	/* Update pointer to GOT */
305e945f6dcSMichal Simek	mfs	r20, rpc
306e945f6dcSMichal Simek	addik	r20, r20, _GLOBAL_OFFSET_TABLE_ + 8
307e945f6dcSMichal Simek	addk	r20, r20, r23
308e945f6dcSMichal Simek
309e945f6dcSMichal Simek	/* Flush caches to ensure consistency */
310e945f6dcSMichal Simek	addik	r5, r0, 0
311e945f6dcSMichal Simek	addik	r6, r0, XILINX_DCACHE_BYTE_SIZE
312e945f6dcSMichal Simek	bralid	r15, flush_cache
313e945f6dcSMichal Simek	nop
314e945f6dcSMichal Simek
315e945f6dcSMichal Simek2:	addi	r5, r31, 0 /* gd is initialized in board_r.c */
316e945f6dcSMichal Simek	addi	r6, r0, CONFIG_SYS_TEXT_BASE
317e945f6dcSMichal Simek	addi	r12, r23, board_init_r
318e945f6dcSMichal Simek	bra	r12 /* Jump to relocated code */
319e945f6dcSMichal Simek
320e945f6dcSMichal Simek	.end	relocate_code
3219d242745SMichal Simek#endif
322