blob: 471bc1eb663b52a335732732d396e75c6e1ddfc0 [file] [log] [blame]
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +02001/*
2 * Startup Code for MIPS64 CPU-core
3 *
4 * Copyright (c) 2003 Wolfgang Denk <wd@denx.de>
5 *
Tom Rini7d2d26b2013-07-24 09:50:52 -04006 * SPDX-License-Identifier: GPL-2.0+
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +02007 */
8
9#include <asm-offsets.h>
10#include <config.h>
11#include <asm/regdef.h>
12#include <asm/mipsregs.h>
13
14#ifndef CONFIG_SYS_MIPS_CACHE_MODE
15#define CONFIG_SYS_MIPS_CACHE_MODE CONF_CM_CACHABLE_NONCOHERENT
16#endif
17
Daniel Schwierzeck28144592015-01-18 22:18:38 +010018#ifndef CONFIG_SYS_INIT_SP_ADDR
19#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + \
20 CONFIG_SYS_INIT_SP_OFFSET)
21#endif
22
Gabor Juhos84937ab2013-02-12 22:22:13 +010023#ifdef CONFIG_SYS_LITTLE_ENDIAN
24#define MIPS64_R_INFO(ssym, r_type3, r_type2, r_type) \
25 (((r_type) << 24) | ((r_type2) << 16) | ((r_type3) << 8) | (ssym))
26#else
27#define MIPS64_R_INFO(ssym, r_type3, r_type2, r_type) \
28 ((r_type) | ((r_type2) << 8) | ((r_type3) << 16) | (ssym) << 24)
29#endif
30
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +020031 /*
32 * For the moment disable interrupts, mark the kernel mode and
33 * set ST0_KX so that the CPU does not spit fire when using
34 * 64-bit addresses.
35 */
36 .macro setup_c0_status set clr
37 .set push
38 mfc0 t0, CP0_STATUS
39 or t0, ST0_CU0 | \set | 0x1f | \clr
40 xor t0, 0x1f | \clr
41 mtc0 t0, CP0_STATUS
42 .set noreorder
43 sll zero, 3 # ehb
44 .set pop
45 .endm
46
47 .set noreorder
48
49 .globl _start
50 .text
51_start:
Daniel Schwierzeckec443162013-02-12 22:22:12 +010052 /* U-boot entry point */
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +020053 b reset
54 nop
Daniel Schwierzeckec443162013-02-12 22:22:12 +010055
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +020056 .org 0x200
Daniel Schwierzeckec443162013-02-12 22:22:12 +010057 /* TLB refill, 32 bit task */
581: b 1b
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +020059 nop
Daniel Schwierzeckec443162013-02-12 22:22:12 +010060
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +020061 .org 0x280
Daniel Schwierzeckec443162013-02-12 22:22:12 +010062 /* XTLB refill, 64 bit task */
631: b 1b
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +020064 nop
Daniel Schwierzeckec443162013-02-12 22:22:12 +010065
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +020066 .org 0x300
Daniel Schwierzeckec443162013-02-12 22:22:12 +010067 /* Cache error exception */
681: b 1b
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +020069 nop
Daniel Schwierzeckec443162013-02-12 22:22:12 +010070
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +020071 .org 0x380
Daniel Schwierzeckec443162013-02-12 22:22:12 +010072 /* General exception */
731: b 1b
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +020074 nop
Daniel Schwierzeckec443162013-02-12 22:22:12 +010075
76 .org 0x400
77 /* Catch interrupt exceptions */
781: b 1b
79 nop
80
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +020081 .org 0x480
Daniel Schwierzeckec443162013-02-12 22:22:12 +010082 /* EJTAG debug exception */
831: b 1b
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +020084 nop
85
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +020086 .align 4
87reset:
88
89 /* Clear watch registers */
90 dmtc0 zero, CP0_WATCHLO
91 dmtc0 zero, CP0_WATCHHI
92
93 /* WP(Watch Pending), SW0/1 should be cleared */
94 mtc0 zero, CP0_CAUSE
95
96 setup_c0_status ST0_KX 0
97
98 /* Init Timer */
99 mtc0 zero, CP0_COUNT
100 mtc0 zero, CP0_COMPARE
101
102#ifndef CONFIG_SKIP_LOWLEVEL_INIT
103 /* CONFIG0 register */
104 dli t0, CONF_CM_UNCACHED
105 mtc0 t0, CP0_CONFIG
106#endif
107
Zhi-zhou Zhang26dd82b2012-11-24 05:07:12 +0000108 /*
109 * Initialize $gp, force 8 byte alignment of bal instruction to forbid
110 * the compiler to put nop's between bal and _gp. This is required to
111 * keep _gp and ra aligned to 8 byte.
112 */
113 .align 3
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +0200114 bal 1f
115 nop
116 .dword _gp
1171:
118 ld gp, 0(ra)
119
120#ifndef CONFIG_SKIP_LOWLEVEL_INIT
121 /* Initialize any external memory */
122 dla t9, lowlevel_init
123 jalr t9
124 nop
125
126 /* Initialize caches... */
127 dla t9, mips_cache_reset
128 jalr t9
129 nop
130
131 /* ... and enable them */
132 dli t0, CONFIG_SYS_MIPS_CACHE_MODE
133 mtc0 t0, CP0_CONFIG
134#endif
135
136 /* Set up temporary stack */
Daniel Schwierzeck01cab272015-01-18 22:18:39 +0100137 dli t0, -16
138 dli t1, CONFIG_SYS_INIT_SP_ADDR
139 and sp, t1, t0 # force 16 byte alignment
140 dsub sp, sp, GD_SIZE # reserve space for gd
141 and sp, sp, t0 # force 16 byte alignment
142 move k0, sp # save gd pointer
143#ifdef CONFIG_SYS_MALLOC_F_LEN
144 dli t2, CONFIG_SYS_MALLOC_F_LEN
145 dsub sp, sp, t2 # reserve space for early malloc
146 and sp, sp, t0 # force 16 byte alignment
147#endif
Daniel Schwierzeckf224c1a2014-11-20 23:55:32 +0100148 move fp, sp
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +0200149
Daniel Schwierzeck01cab272015-01-18 22:18:39 +0100150 /* Clear gd */
151 move t0, k0
1521:
153 sw zero, 0(t0)
154 blt t0, t1, 1b
155 daddi t0, 4
156
157#ifdef CONFIG_SYS_MALLOC_F_LEN
158 daddu t0, k0, GD_MALLOC_BASE # gd->malloc_base offset
159 sw sp, 0(t0)
160#endif
161
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +0200162 dla t9, board_init_f
163 jr t9
Daniel Schwierzeckf224c1a2014-11-20 23:55:32 +0100164 move ra, zero
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +0200165
166/*
167 * void relocate_code (addr_sp, gd, addr_moni)
168 *
169 * This "function" does not return, instead it continues in RAM
170 * after relocating the monitor code.
171 *
172 * a0 = addr_sp
173 * a1 = gd
174 * a2 = destination address
175 */
176 .globl relocate_code
177 .ent relocate_code
178relocate_code:
179 move sp, a0 # set new stack pointer
Daniel Schwierzeckf224c1a2014-11-20 23:55:32 +0100180 move fp, sp
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +0200181
Gabor Juhosf902d462013-01-24 06:27:53 +0000182 move s0, a1 # save gd in s0
183 move s2, a2 # save destination address in s2
184
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +0200185 dli t0, CONFIG_SYS_MONITOR_BASE
Gabor Juhosfac2f652013-01-24 06:27:54 +0000186 dsub s1, s2, t0 # s1 <-- relocation offset
187
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +0200188 dla t3, in_ram
Daniel Schwierzeck7f2d5402013-02-12 22:22:13 +0100189 ld t2, -24(t3) # t2 <-- __image_copy_end
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +0200190 move t1, a2
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +0200191
Gabor Juhosfac2f652013-01-24 06:27:54 +0000192 dadd gp, s1 # adjust gp
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +0200193
194 /*
195 * t0 = source address
196 * t1 = target address
197 * t2 = source end address
198 */
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +02001991:
200 lw t3, 0(t0)
201 sw t3, 0(t1)
202 daddu t0, 4
Gabor Juhos9a081ab2013-01-24 06:27:51 +0000203 blt t0, t2, 1b
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +0200204 daddu t1, 4
205
206 /* If caches were enabled, we would have to flush them here. */
Gabor Juhoseb590242013-01-24 06:27:55 +0000207 dsub a1, t1, s2 # a1 <-- size
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +0200208 dla t9, flush_cache
209 jalr t9
Gabor Juhoseb590242013-01-24 06:27:55 +0000210 move a0, s2 # a0 <-- destination address
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +0200211
212 /* Jump to where we've relocated ourselves */
213 daddi t0, s2, in_ram - _start
214 jr t0
215 nop
216
Gabor Juhos84937ab2013-02-12 22:22:13 +0100217 .dword __rel_dyn_end
218 .dword __rel_dyn_start
Daniel Schwierzeck7f2d5402013-02-12 22:22:13 +0100219 .dword __image_copy_end
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +0200220 .dword _GLOBAL_OFFSET_TABLE_
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +0200221 .dword num_got_entries
222
223in_ram:
224 /*
225 * Now we want to update GOT.
226 *
227 * GOT[0] is reserved. GOT[1] is also reserved for the dynamic object
228 * generated by GNU ld. Skip these reserved entries from relocation.
229 */
230 ld t3, -8(t0) # t3 <-- num_got_entries
Daniel Schwierzeck7f2d5402013-02-12 22:22:13 +0100231 ld t8, -16(t0) # t8 <-- _GLOBAL_OFFSET_TABLE_
Gabor Juhosbc18d0b2013-01-30 04:56:37 +0000232 dadd t8, s1 # t8 now holds relocated _G_O_T_
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +0200233 daddi t8, t8, 16 # skipping first two entries
234 dli t2, 2
2351:
236 ld t1, 0(t8)
237 beqz t1, 2f
238 dadd t1, s1
239 sd t1, 0(t8)
2402:
241 daddi t2, 1
242 blt t2, t3, 1b
243 daddi t8, 8
244
Gabor Juhos84937ab2013-02-12 22:22:13 +0100245 /* Update dynamic relocations */
246 ld t1, -32(t0) # t1 <-- __rel_dyn_start
247 ld t2, -40(t0) # t2 <-- __rel_dyn_end
248
249 b 2f # skip first reserved entry
250 daddi t1, 16
251
2521:
253 lw t8, -4(t1) # t8 <-- relocation info
254
255 dli t3, MIPS64_R_INFO(0x00, 0x00, 0x12, 0x03)
256 bne t8, t3, 2f # skip non R_MIPS_REL32 entries
257 nop
258
259 ld t3, -16(t1) # t3 <-- location to fix up in FLASH
260
261 ld t8, 0(t3) # t8 <-- original pointer
262 dadd t8, s1 # t8 <-- adjusted pointer
263
264 dadd t3, s1 # t3 <-- location to fix up in RAM
265 sd t8, 0(t3)
266
2672:
268 blt t1, t2, 1b
269 daddi t1, 16 # each rel.dyn entry is 16 bytes
270
Daniel Schwierzeck0de9cc52013-02-12 22:22:13 +0100271 /*
272 * Clear BSS
273 *
274 * GOT is now relocated. Thus __bss_start and __bss_end can be
275 * accessed directly via $gp.
276 */
277 dla t1, __bss_start # t1 <-- __bss_start
278 dla t2, __bss_end # t2 <-- __bss_end
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +0200279
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +02002801:
Daniel Schwierzeck0de9cc52013-02-12 22:22:13 +0100281 sd zero, 0(t1)
282 blt t1, t2, 1b
283 daddi t1, 8
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +0200284
285 move a0, s0 # a0 <-- gd
Daniel Schwierzeckf224c1a2014-11-20 23:55:32 +0100286 move a1, s2
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +0200287 dla t9, board_init_r
288 jr t9
Daniel Schwierzeckf224c1a2014-11-20 23:55:32 +0100289 move ra, zero
Zhi-zhou Zhange0d6df52012-10-16 15:02:08 +0200290
291 .end relocate_code