xref: /openbmc/u-boot/arch/microblaze/cpu/start.S (revision 25ddd1fb)
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 * See file CREDITS for list of people who contributed to this
9 * project.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24 * MA 02111-1307 USA
25 */
26
27#include <asm-offsets.h>
28#include <config.h>
29
30	.text
31	.global _start
32_start:
33	mts	rmsr, r0	/* disable cache */
34	addi	r1, r0, CONFIG_SYS_INIT_SP_OFFSET
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	swi	r6, r0, 0
48	lbui	r10, r0, 0
49	swi	r6, r0, 0x40
50	swi	r10, r0, 0x50
51
52	/* add opcode instruction for 32bit jump - 2 instruction imm & brai*/
53	addi	r6, r0, 0xb0000000	/* hex b000 opcode imm */
54	swi	r6, r0, 0x0	/* reset address */
55	swi	r6, r0, 0x8	/* user vector exception */
56	swi	r6, r0, 0x10	/* interrupt */
57	swi	r6, r0, 0x20	/* hardware exception */
58
59	addi	r6, r0, 0xb8080000	/* hew b808 opcode brai*/
60	swi	r6, r0, 0x4	/* reset address */
61	swi	r6, r0, 0xC	/* user vector exception */
62	swi	r6, r0, 0x14	/* interrupt */
63	swi	r6, r0, 0x24	/* hardware exception */
64
65#ifdef CONFIG_SYS_RESET_ADDRESS
66	/* reset address */
67	addik	r6, r0, CONFIG_SYS_RESET_ADDRESS
68	sw	r6, r1, r0
69	lhu	r7, r1, r0
70	shi	r7, r0, 0x2
71	shi	r6, r0, 0x6
72/*
73 * Copy U-Boot code to CONFIG_SYS_TEXT_BASE
74 * solve problem with sbrk_base
75 */
76#if (CONFIG_SYS_RESET_ADDRESS != CONFIG_SYS_TEXT_BASE)
77	addi	r4, r0, __end
78	addi	r5, r0, __text_start
79	rsub	r4, r5, r4	/* size = __end - __text_start */
80	addi	r6, r0, CONFIG_SYS_RESET_ADDRESS	/* source address */
81	addi	r7, r0, 0	/* counter */
824:
83	lw	r8, r6, r7
84	sw	r8, r5, r7
85	addi	r7, r7, 0x4
86	cmp	r8, r4, r7
87	blti	r8, 4b
88#endif
89#endif
90
91#ifdef CONFIG_SYS_USR_EXCEP
92	/* user_vector_exception */
93	addik	r6, r0, _exception_handler
94	sw	r6, r1, r0
95	/*
96	 * BIG ENDIAN memory map for user exception
97	 * 0x8: 0xB000XXXX
98	 * 0xC: 0xB808XXXX
99	 *
100	 * then it is necessary to count address for storing the most significant
101	 * 16bits from _exception_handler address and copy it to
102	 * 0xa address. Big endian use offset in r10=0 that's why is it just
103	 * 0xa address. The same is done for the least significant 16 bits
104	 * for 0xe address.
105	 *
106	 * LITTLE ENDIAN memory map for user exception
107	 * 0x8: 0xXXXX00B0
108	 * 0xC: 0xXXXX08B8
109	 *
110	 * Offset is for little endian setup to 0x2. rsubi instruction decrease
111	 * address value to ensure that points to proper place which is
112	 * 0x8 for the most significant 16 bits and
113	 * 0xC for the least significant 16 bits
114	 */
115	lhu	r7, r1, r10
116	rsubi	r8, r10, 0xa
117	sh	r7, r0, r8
118	rsubi	r8, r10, 0xe
119	sh	r6, r0, r8
120#endif
121
122#ifdef CONFIG_SYS_INTC_0
123	/* interrupt_handler */
124	addik	r6, r0, _interrupt_handler
125	sw	r6, r1, r0
126	lhu	r7, r1, r10
127	rsubi	r8, r10, 0x12
128	sh	r7, r0, r8
129	rsubi	r8, r10, 0x16
130	sh	r6, r0, r8
131#endif
132
133	/* hardware exception */
134	addik	r6, r0, _hw_exception_handler
135	sw	r6, r1, r0
136	lhu	r7, r1, r10
137	rsubi	r8, r10, 0x22
138	sh	r7, r0, r8
139	rsubi	r8, r10, 0x26
140	sh	r6, r0, r8
141
142	/* enable instruction and data cache */
143	mfs	r12, rmsr
144	ori	r12, r12, 0xa0
145	mts	rmsr, r12
146
147clear_bss:
148	/* clear BSS segments */
149	addi	r5, r0, __bss_start
150	addi	r4, r0, __bss_end
151	cmp	r6, r5, r4
152	beqi	r6, 3f
1532:
154	swi     r0, r5, 0 /* write zero to loc */
155	addi    r5, r5, 4 /* increment to next loc */
156	cmp     r6, r5, r4 /* check if we have reach the end */
157	bnei    r6, 2b
1583:	/* jumping to board_init */
159	brai	board_init
1601:	bri	1b
161
162/*
163 * Read 16bit little endian
164 */
165	.text
166	.global	in16
167	.ent	in16
168	.align	2
169in16:	lhu	r3, r0, r5
170	bslli	r4, r3, 8
171	bsrli	r3, r3, 8
172	andi	r4, r4, 0xffff
173	or	r3, r3, r4
174	rtsd	r15, 8
175	sext16	r3, r3
176	.end	in16
177
178/*
179 * Write 16bit little endian
180 * first parameter(r5) - address, second(r6) - short value
181 */
182	.text
183	.global	out16
184	.ent	out16
185	.align	2
186out16:	bslli	r3, r6, 8
187	bsrli	r6, r6, 8
188	andi	r3, r3, 0xffff
189	or	r3, r3, r6
190	sh	r3, r0, r5
191	rtsd	r15, 8
192	or	r0, r0, r0
193	.end	out16
194