]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/microblaze/cpu/start.S
microblaze: Save and restore first unused vector
[karo-tx-uboot.git] / arch / microblaze / cpu / start.S
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         /*
34          * reserve registers:
35          * r10: Stores little/big endian offset for vectors
36          * r2: Stores imm opcode
37          * r3: Stores brai opcode
38          */
39
40         mts     rmsr, r0        /* disable cache */
41         addi    r1, r0, CONFIG_SYS_INIT_SP_OFFSET
42         addi    r1, r1, -4      /* Decrement SP to top of memory */
43
44         /* Find-out if u-boot is running on BIG/LITTLE endian platform
45          * There are some steps which is necessary to keep in mind:
46          * 1. Setup offset value to r6
47          * 2. Store word offset value to address 0x0
48          * 3. Load just byte from address 0x0
49          * 4a) LITTLE endian - r10 contains 0x2 because it is the smallest
50          *     value that's why is on address 0x0
51          * 4b) BIG endian - r10 contains 0x0 because 0x2 offset is on addr 0x3
52          */
53         addik   r6, r0, 0x2 /* BIG/LITTLE endian offset */
54         lwi     r7, r0, 0x28
55         swi     r6, r0, 0x28 /* used first unused MB vector */
56         lbui    r10, r0, 0x28 /* used first unused MB vector */
57         swi     r7, r0, 0x28
58
59         /* add opcode instruction for 32bit jump - 2 instruction imm & brai */
60         addi    r2, r0, 0xb0000000      /* hex b000 opcode imm */
61         addi    r3, r0, 0xb8080000      /* hew b808 opcode brai */
62
63 #ifdef CONFIG_SYS_RESET_ADDRESS
64         /* reset address */
65         swi     r2, r0, 0x0     /* reset address - imm opcode */
66         swi     r3, r0, 0x4     /* reset address - brai opcode */
67
68         addik   r6, r0, CONFIG_SYS_RESET_ADDRESS
69         sw      r6, r1, r0
70         lhu     r7, r1, r0
71         shi     r7, r0, 0x2
72         shi     r6, r0, 0x6
73 /*
74  * Copy U-Boot code to CONFIG_SYS_TEXT_BASE
75  * solve problem with sbrk_base
76  */
77 #if (CONFIG_SYS_RESET_ADDRESS != CONFIG_SYS_TEXT_BASE)
78         addi    r4, r0, __end
79         addi    r5, r0, __text_start
80         rsub    r4, r5, r4      /* size = __end - __text_start */
81         addi    r6, r0, CONFIG_SYS_RESET_ADDRESS        /* source address */
82         addi    r7, r0, 0       /* counter */
83 4:
84         lw      r8, r6, r7
85         sw      r8, r5, r7
86         addi    r7, r7, 0x4
87         cmp     r8, r4, r7
88         blti    r8, 4b
89 #endif
90 #endif
91
92 #ifdef CONFIG_SYS_USR_EXCEP
93         /* user_vector_exception */
94         swi     r2, r0, 0x8     /* user vector exception - imm opcode */
95         swi     r3, r0, 0xC     /* user vector exception - brai opcode */
96
97         addik   r6, r0, _exception_handler
98         sw      r6, r1, r0
99         /*
100          * BIG ENDIAN memory map for user exception
101          * 0x8: 0xB000XXXX
102          * 0xC: 0xB808XXXX
103          *
104          * then it is necessary to count address for storing the most significant
105          * 16bits from _exception_handler address and copy it to
106          * 0xa address. Big endian use offset in r10=0 that's why is it just
107          * 0xa address. The same is done for the least significant 16 bits
108          * for 0xe address.
109          *
110          * LITTLE ENDIAN memory map for user exception
111          * 0x8: 0xXXXX00B0
112          * 0xC: 0xXXXX08B8
113          *
114          * Offset is for little endian setup to 0x2. rsubi instruction decrease
115          * address value to ensure that points to proper place which is
116          * 0x8 for the most significant 16 bits and
117          * 0xC for the least significant 16 bits
118          */
119         lhu     r7, r1, r10
120         rsubi   r8, r10, 0xa
121         sh      r7, r0, r8
122         rsubi   r8, r10, 0xe
123         sh      r6, r0, r8
124 #endif
125
126 #ifdef CONFIG_SYS_INTC_0
127         /* interrupt_handler */
128         swi     r2, r0, 0x10    /* interrupt - imm opcode */
129         swi     r3, r0, 0x14    /* interrupt - brai opcode */
130
131         addik   r6, r0, _interrupt_handler
132         sw      r6, r1, r0
133         lhu     r7, r1, r10
134         rsubi   r8, r10, 0x12
135         sh      r7, r0, r8
136         rsubi   r8, r10, 0x16
137         sh      r6, r0, r8
138 #endif
139
140         /* hardware exception */
141         swi     r2, r0, 0x20    /* hardware exception - imm opcode */
142         swi     r3, r0, 0x24    /* hardware exception - brai opcode */
143
144         addik   r6, r0, _hw_exception_handler
145         sw      r6, r1, r0
146         lhu     r7, r1, r10
147         rsubi   r8, r10, 0x22
148         sh      r7, r0, r8
149         rsubi   r8, r10, 0x26
150         sh      r6, r0, r8
151
152         /* enable instruction and data cache */
153         mfs     r12, rmsr
154         ori     r12, r12, 0xa0
155         mts     rmsr, r12
156
157 clear_bss:
158         /* clear BSS segments */
159         addi    r5, r0, __bss_start
160         addi    r4, r0, __bss_end
161         cmp     r6, r5, r4
162         beqi    r6, 3f
163 2:
164         swi     r0, r5, 0 /* write zero to loc */
165         addi    r5, r5, 4 /* increment to next loc */
166         cmp     r6, r5, r4 /* check if we have reach the end */
167         bnei    r6, 2b
168 3:      /* jumping to board_init */
169         brai    board_init
170 1:      bri     1b
171
172 /*
173  * Read 16bit little endian
174  */
175         .text
176         .global in16
177         .ent    in16
178         .align  2
179 in16:   lhu     r3, r0, r5
180         bslli   r4, r3, 8
181         bsrli   r3, r3, 8
182         andi    r4, r4, 0xffff
183         or      r3, r3, r4
184         rtsd    r15, 8
185         sext16  r3, r3
186         .end    in16
187
188 /*
189  * Write 16bit little endian
190  * first parameter(r5) - address, second(r6) - short value
191  */
192         .text
193         .global out16
194         .ent    out16
195         .align  2
196 out16:  bslli   r3, r6, 8
197         bsrli   r6, r6, 8
198         andi    r3, r3, 0xffff
199         or      r3, r3, r6
200         sh      r3, r0, r5
201         rtsd    r15, 8
202         or      r0, r0, r0
203         .end    out16