]>
Commit | Line | Data |
---|---|---|
c021880a WD |
1 | /* |
2 | * Startup Code for MIPS32 CPU-core | |
3 | * | |
4 | * Copyright (c) 2003 Wolfgang Denk <wd@denx.de> | |
5 | * | |
1a459660 | 6 | * SPDX-License-Identifier: GPL-2.0+ |
c021880a WD |
7 | */ |
8 | ||
25ddd1fb | 9 | #include <asm-offsets.h> |
c021880a | 10 | #include <config.h> |
a39b1cb7 | 11 | #include <asm/asm.h> |
c021880a WD |
12 | #include <asm/regdef.h> |
13 | #include <asm/mipsregs.h> | |
14 | ||
ab2a98b1 DS |
15 | #ifndef CONFIG_SYS_MIPS_CACHE_MODE |
16 | #define CONFIG_SYS_MIPS_CACHE_MODE CONF_CM_CACHABLE_NONCOHERENT | |
17 | #endif | |
18 | ||
dd82128e DS |
19 | #ifndef CONFIG_SYS_INIT_SP_ADDR |
20 | #define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + \ | |
21 | CONFIG_SYS_INIT_SP_OFFSET) | |
22 | #endif | |
23 | ||
ab0d0026 PB |
24 | #ifdef CONFIG_32BIT |
25 | # define MIPS_RELOC 3 | |
f1c64a08 | 26 | # define STATUS_SET 0 |
ab0d0026 PB |
27 | #endif |
28 | ||
29 | #ifdef CONFIG_64BIT | |
30 | # ifdef CONFIG_SYS_LITTLE_ENDIAN | |
31 | # define MIPS64_R_INFO(ssym, r_type3, r_type2, r_type) \ | |
32 | (((r_type) << 24) | ((r_type2) << 16) | ((r_type3) << 8) | (ssym)) | |
33 | # else | |
34 | # define MIPS64_R_INFO(ssym, r_type3, r_type2, r_type) \ | |
35 | ((r_type) | ((r_type2) << 8) | ((r_type3) << 16) | (ssym) << 24) | |
36 | # endif | |
37 | # define MIPS_RELOC MIPS64_R_INFO(0x00, 0x00, 0x12, 0x03) | |
f1c64a08 | 38 | # define STATUS_SET ST0_KX |
ab0d0026 PB |
39 | #endif |
40 | ||
decaba6f SK |
41 | /* |
42 | * For the moment disable interrupts, mark the kernel mode and | |
43 | * set ST0_KX so that the CPU does not spit fire when using | |
44 | * 64-bit addresses. | |
45 | */ | |
46 | .macro setup_c0_status set clr | |
47 | .set push | |
48 | mfc0 t0, CP0_STATUS | |
49 | or t0, ST0_CU0 | \set | 0x1f | \clr | |
50 | xor t0, 0x1f | \clr | |
51 | mtc0 t0, CP0_STATUS | |
52 | .set noreorder | |
53 | sll zero, 3 # ehb | |
54 | .set pop | |
55 | .endm | |
56 | ||
c021880a WD |
57 | .set noreorder |
58 | ||
59 | .globl _start | |
60 | .text | |
61 | _start: | |
8b1c7345 DS |
62 | /* U-boot entry point */ |
63 | b reset | |
64 | nop | |
65 | ||
66 | .org 0x10 | |
843a76b6 | 67 | #if defined(CONFIG_SYS_XWAY_EBU_BOOTCFG) |
7185adb4 DS |
68 | /* |
69 | * Almost all Lantiq XWAY SoC devices have an external bus unit (EBU) to | |
70 | * access external NOR flashes. If the board boots from NOR flash the | |
71 | * internal BootROM does a blind read at address 0xB0000010 to read the | |
72 | * initial configuration for that EBU in order to access the flash | |
73 | * device with correct parameters. This config option is board-specific. | |
74 | */ | |
75 | .word CONFIG_SYS_XWAY_EBU_BOOTCFG | |
8b1c7345 | 76 | .word 0x0 |
7a9d109b | 77 | #elif defined(CONFIG_MALTA) |
843a76b6 GJ |
78 | /* |
79 | * Linux expects the Board ID here. | |
80 | */ | |
81 | .word 0x00000420 # 0x420 (Malta Board with CoreLV) | |
82 | .word 0x00000000 | |
c021880a | 83 | #endif |
8bde7f77 | 84 | |
8b1c7345 DS |
85 | .org 0x200 |
86 | /* TLB refill, 32 bit task */ | |
87 | 1: b 1b | |
88 | nop | |
89 | ||
90 | .org 0x280 | |
91 | /* XTLB refill, 64 bit task */ | |
92 | 1: b 1b | |
93 | nop | |
94 | ||
95 | .org 0x300 | |
96 | /* Cache error exception */ | |
97 | 1: b 1b | |
98 | nop | |
99 | ||
100 | .org 0x380 | |
101 | /* General exception */ | |
102 | 1: b 1b | |
103 | nop | |
104 | ||
105 | .org 0x400 | |
106 | /* Catch interrupt exceptions */ | |
107 | 1: b 1b | |
108 | nop | |
109 | ||
110 | .org 0x480 | |
111 | /* EJTAG debug exception */ | |
112 | 1: b 1b | |
113 | nop | |
114 | ||
c021880a WD |
115 | .align 4 |
116 | reset: | |
117 | ||
7aa1f198 | 118 | /* Clear watch registers */ |
a39b1cb7 PB |
119 | MTC0 zero, CP0_WATCHLO |
120 | MTC0 zero, CP0_WATCHHI | |
c021880a | 121 | |
7aa1f198 | 122 | /* WP(Watch Pending), SW0/1 should be cleared */ |
d43d43ef SK |
123 | mtc0 zero, CP0_CAUSE |
124 | ||
f1c64a08 | 125 | setup_c0_status STATUS_SET 0 |
c021880a | 126 | |
c021880a WD |
127 | /* Init Timer */ |
128 | mtc0 zero, CP0_COUNT | |
129 | mtc0 zero, CP0_COMPARE | |
130 | ||
7aa1f198 | 131 | #ifndef CONFIG_SKIP_LOWLEVEL_INIT |
c021880a WD |
132 | /* CONFIG0 register */ |
133 | li t0, CONF_CM_UNCACHED | |
134 | mtc0 t0, CP0_CONFIG | |
7aa1f198 | 135 | #endif |
c021880a | 136 | |
a39b1cb7 PB |
137 | /* |
138 | * Initialize $gp, force pointer sized alignment of bal instruction to | |
139 | * forbid the compiler to put nop's between bal and _gp. This is | |
140 | * required to keep _gp and ra aligned to 8 byte. | |
141 | */ | |
142 | .align PTRLOG | |
03c031d5 | 143 | bal 1f |
7aa1f198 | 144 | nop |
a39b1cb7 | 145 | PTR _gp |
03c031d5 | 146 | 1: |
a39b1cb7 | 147 | PTR_L gp, 0(ra) |
c75eba3b | 148 | |
7aa1f198 SK |
149 | #ifndef CONFIG_SKIP_LOWLEVEL_INIT |
150 | /* Initialize any external memory */ | |
a39b1cb7 | 151 | PTR_LA t9, lowlevel_init |
03c031d5 | 152 | jalr t9 |
7aa1f198 | 153 | nop |
c021880a | 154 | |
7aa1f198 | 155 | /* Initialize caches... */ |
a39b1cb7 | 156 | PTR_LA t9, mips_cache_reset |
03c031d5 | 157 | jalr t9 |
7aa1f198 | 158 | nop |
c021880a | 159 | |
7aa1f198 | 160 | /* ... and enable them */ |
ab2a98b1 | 161 | li t0, CONFIG_SYS_MIPS_CACHE_MODE |
c021880a | 162 | mtc0 t0, CP0_CONFIG |
7aa1f198 | 163 | #endif |
c021880a | 164 | |
7aa1f198 | 165 | /* Set up temporary stack */ |
a39b1cb7 PB |
166 | PTR_LI t0, -16 |
167 | PTR_LI t1, CONFIG_SYS_INIT_SP_ADDR | |
e5200238 | 168 | and sp, t1, t0 # force 16 byte alignment |
a39b1cb7 | 169 | PTR_SUB sp, sp, GD_SIZE # reserve space for gd |
e5200238 DS |
170 | and sp, sp, t0 # force 16 byte alignment |
171 | move k0, sp # save gd pointer | |
172 | #ifdef CONFIG_SYS_MALLOC_F_LEN | |
a39b1cb7 PB |
173 | PTR_LI t2, CONFIG_SYS_MALLOC_F_LEN |
174 | PTR_SUB sp, sp, t2 # reserve space for early malloc | |
e5200238 DS |
175 | and sp, sp, t0 # force 16 byte alignment |
176 | #endif | |
6d08e22a | 177 | move fp, sp |
c021880a | 178 | |
e5200238 DS |
179 | /* Clear gd */ |
180 | move t0, k0 | |
181 | 1: | |
182 | sw zero, 0(t0) | |
183 | blt t0, t1, 1b | |
a39b1cb7 | 184 | PTR_ADDI t0, 4 |
e5200238 DS |
185 | |
186 | #ifdef CONFIG_SYS_MALLOC_F_LEN | |
a39b1cb7 | 187 | PTR_ADDU t0, k0, GD_MALLOC_BASE # gd->malloc_base offset |
e5200238 DS |
188 | sw sp, 0(t0) |
189 | #endif | |
190 | ||
a39b1cb7 | 191 | PTR_LA t9, board_init_f |
43c50925 | 192 | jr t9 |
6d08e22a | 193 | move ra, zero |
c021880a | 194 | |
c021880a WD |
195 | /* |
196 | * void relocate_code (addr_sp, gd, addr_moni) | |
197 | * | |
198 | * This "function" does not return, instead it continues in RAM | |
199 | * after relocating the monitor code. | |
200 | * | |
201 | * a0 = addr_sp | |
202 | * a1 = gd | |
203 | * a2 = destination address | |
204 | */ | |
205 | .globl relocate_code | |
206 | .ent relocate_code | |
207 | relocate_code: | |
7aa1f198 | 208 | move sp, a0 # set new stack pointer |
6d08e22a | 209 | move fp, sp |
c021880a | 210 | |
b2fe86f8 GJ |
211 | move s0, a1 # save gd in s0 |
212 | move s2, a2 # save destination address in s2 | |
213 | ||
a39b1cb7 PB |
214 | PTR_LI t0, CONFIG_SYS_MONITOR_BASE |
215 | PTR_SUB s1, s2, t0 # s1 <-- relocation offset | |
248fe03f | 216 | |
a39b1cb7 PB |
217 | PTR_LA t3, in_ram |
218 | PTR_L t2, -(3 * PTRSIZE)(t3) # t2 <-- __image_copy_end | |
27b207fd WD |
219 | move t1, a2 |
220 | ||
a39b1cb7 | 221 | PTR_ADD gp, s1 # adjust gp |
8bde7f77 | 222 | |
c021880a WD |
223 | /* |
224 | * t0 = source address | |
225 | * t1 = target address | |
226 | * t2 = source end address | |
227 | */ | |
228 | 1: | |
229 | lw t3, 0(t0) | |
230 | sw t3, 0(t1) | |
a39b1cb7 | 231 | PTR_ADDU t0, 4 |
5b7dd816 | 232 | blt t0, t2, 1b |
a39b1cb7 | 233 | PTR_ADDU t1, 4 |
c021880a | 234 | |
7aa1f198 | 235 | /* If caches were enabled, we would have to flush them here. */ |
a39b1cb7 PB |
236 | PTR_SUB a1, t1, s2 # a1 <-- size |
237 | PTR_LA t9, flush_cache | |
71fa0714 | 238 | jalr t9 |
67d80c9f | 239 | move a0, s2 # a0 <-- destination address |
71fa0714 | 240 | |
7aa1f198 | 241 | /* Jump to where we've relocated ourselves */ |
a39b1cb7 | 242 | PTR_ADDI t0, s2, in_ram - _start |
43c50925 | 243 | jr t0 |
7aa1f198 | 244 | nop |
c021880a | 245 | |
a39b1cb7 PB |
246 | PTR __rel_dyn_end |
247 | PTR __rel_dyn_start | |
248 | PTR __image_copy_end | |
249 | PTR _GLOBAL_OFFSET_TABLE_ | |
250 | PTR num_got_entries | |
c021880a WD |
251 | |
252 | in_ram: | |
22069215 SK |
253 | /* |
254 | * Now we want to update GOT. | |
255 | * | |
256 | * GOT[0] is reserved. GOT[1] is also reserved for the dynamic object | |
257 | * generated by GNU ld. Skip these reserved entries from relocation. | |
c021880a | 258 | */ |
a39b1cb7 PB |
259 | PTR_L t3, -(1 * PTRSIZE)(t0) # t3 <-- num_got_entries |
260 | PTR_L t8, -(2 * PTRSIZE)(t0) # t8 <-- _GLOBAL_OFFSET_TABLE_ | |
261 | PTR_ADD t8, s1 # t8 now holds relocated _G_O_T_ | |
262 | PTR_ADDI t8, t8, 2 * PTRSIZE # skipping first two entries | |
263 | PTR_LI t2, 2 | |
c021880a | 264 | 1: |
a39b1cb7 | 265 | PTR_L t1, 0(t8) |
c021880a | 266 | beqz t1, 2f |
a39b1cb7 PB |
267 | PTR_ADD t1, s1 |
268 | PTR_S t1, 0(t8) | |
c021880a | 269 | 2: |
a39b1cb7 | 270 | PTR_ADDI t2, 1 |
c021880a | 271 | blt t2, t3, 1b |
a39b1cb7 | 272 | PTR_ADDI t8, PTRSIZE |
c021880a | 273 | |
04380c65 | 274 | /* Update dynamic relocations */ |
a39b1cb7 PB |
275 | PTR_L t1, -(4 * PTRSIZE)(t0) # t1 <-- __rel_dyn_start |
276 | PTR_L t2, -(5 * PTRSIZE)(t0) # t2 <-- __rel_dyn_end | |
04380c65 GJ |
277 | |
278 | b 2f # skip first reserved entry | |
a39b1cb7 | 279 | PTR_ADDI t1, 2 * PTRSIZE |
04380c65 GJ |
280 | |
281 | 1: | |
691995f9 | 282 | lw t8, -4(t1) # t8 <-- relocation info |
04380c65 | 283 | |
ab0d0026 PB |
284 | PTR_LI t3, MIPS_RELOC |
285 | bne t8, t3, 2f # skip non-MIPS_RELOC entries | |
04380c65 GJ |
286 | nop |
287 | ||
a39b1cb7 | 288 | PTR_L t3, -(2 * PTRSIZE)(t1) # t3 <-- location to fix up in FLASH |
04380c65 | 289 | |
a39b1cb7 PB |
290 | PTR_L t8, 0(t3) # t8 <-- original pointer |
291 | PTR_ADD t8, s1 # t8 <-- adjusted pointer | |
04380c65 | 292 | |
a39b1cb7 PB |
293 | PTR_ADD t3, s1 # t3 <-- location to fix up in RAM |
294 | PTR_S t8, 0(t3) | |
04380c65 GJ |
295 | |
296 | 2: | |
297 | blt t1, t2, 1b | |
a39b1cb7 | 298 | PTR_ADDI t1, 2 * PTRSIZE # each rel.dyn entry is 2*PTRSIZE bytes |
04380c65 | 299 | |
696a3b2a DS |
300 | /* |
301 | * Clear BSS | |
302 | * | |
303 | * GOT is now relocated. Thus __bss_start and __bss_end can be | |
304 | * accessed directly via $gp. | |
305 | */ | |
a39b1cb7 PB |
306 | PTR_LA t1, __bss_start # t1 <-- __bss_start |
307 | PTR_LA t2, __bss_end # t2 <-- __bss_end | |
c021880a | 308 | |
03c031d5 | 309 | 1: |
a39b1cb7 | 310 | PTR_S zero, 0(t1) |
696a3b2a | 311 | blt t1, t2, 1b |
a39b1cb7 | 312 | PTR_ADDI t1, PTRSIZE |
8bde7f77 | 313 | |
7aa1f198 | 314 | move a0, s0 # a0 <-- gd |
6d08e22a | 315 | move a1, s2 |
a39b1cb7 | 316 | PTR_LA t9, board_init_r |
43c50925 | 317 | jr t9 |
6d08e22a | 318 | move ra, zero |
c021880a WD |
319 | |
320 | .end relocate_code |