blob: 92954e1c907bf9dddb64aa433aa6374cd324205a [file] [log] [blame]
Zhi-zhou Zhang32afad72012-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 Rini518d4382013-07-24 09:50:52 -04006 * SPDX-License-Identifier: GPL-2.0+
Zhi-zhou Zhang32afad72012-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
Gabor Juhos04380c62013-02-12 22:22:13 +010018#ifdef CONFIG_SYS_LITTLE_ENDIAN
19#define MIPS64_R_INFO(ssym, r_type3, r_type2, r_type) \
20 (((r_type) << 24) | ((r_type2) << 16) | ((r_type3) << 8) | (ssym))
21#else
22#define MIPS64_R_INFO(ssym, r_type3, r_type2, r_type) \
23 ((r_type) | ((r_type2) << 8) | ((r_type3) << 16) | (ssym) << 24)
24#endif
25
Zhi-zhou Zhang32afad72012-10-16 15:02:08 +020026 /*
27 * For the moment disable interrupts, mark the kernel mode and
28 * set ST0_KX so that the CPU does not spit fire when using
29 * 64-bit addresses.
30 */
31 .macro setup_c0_status set clr
32 .set push
33 mfc0 t0, CP0_STATUS
34 or t0, ST0_CU0 | \set | 0x1f | \clr
35 xor t0, 0x1f | \clr
36 mtc0 t0, CP0_STATUS
37 .set noreorder
38 sll zero, 3 # ehb
39 .set pop
40 .endm
41
42 .set noreorder
43
44 .globl _start
45 .text
46_start:
Daniel Schwierzeck8b1c7342013-02-12 22:22:12 +010047 /* U-boot entry point */
Zhi-zhou Zhang32afad72012-10-16 15:02:08 +020048 b reset
49 nop
Daniel Schwierzeck8b1c7342013-02-12 22:22:12 +010050
Zhi-zhou Zhang32afad72012-10-16 15:02:08 +020051 .org 0x200
Daniel Schwierzeck8b1c7342013-02-12 22:22:12 +010052 /* TLB refill, 32 bit task */
531: b 1b
Zhi-zhou Zhang32afad72012-10-16 15:02:08 +020054 nop
55
Daniel Schwierzeck8b1c7342013-02-12 22:22:12 +010056 .org 0x280
57 /* XTLB refill, 64 bit task */
581: b 1b
59 nop
60
61 .org 0x300
62 /* Cache error exception */
631: b 1b
64 nop
65
66 .org 0x380
67 /* General exception */
681: b 1b
69 nop
70
71 .org 0x400
72 /* Catch interrupt exceptions */
731: b 1b
74 nop
75
76 .org 0x480
77 /* EJTAG debug exception */
781: b 1b
79 nop
80
Zhi-zhou Zhang32afad72012-10-16 15:02:08 +020081 .align 4
82reset:
83
84 /* Clear watch registers */
85 dmtc0 zero, CP0_WATCHLO
86 dmtc0 zero, CP0_WATCHHI
87
88 /* WP(Watch Pending), SW0/1 should be cleared */
89 mtc0 zero, CP0_CAUSE
90
91 setup_c0_status ST0_KX 0
92
93 /* Init Timer */
94 mtc0 zero, CP0_COUNT
95 mtc0 zero, CP0_COMPARE
96
97#ifndef CONFIG_SKIP_LOWLEVEL_INIT
98 /* CONFIG0 register */
99 dli t0, CONF_CM_UNCACHED
100 mtc0 t0, CP0_CONFIG
101#endif
102
Zhi-zhou Zhang0d69d912012-11-24 05:07:12 +0000103 /*
104 * Initialize $gp, force 8 byte alignment of bal instruction to forbid
105 * the compiler to put nop's between bal and _gp. This is required to
106 * keep _gp and ra aligned to 8 byte.
107 */
108 .align 3
Zhi-zhou Zhang32afad72012-10-16 15:02:08 +0200109 bal 1f
110 nop
111 .dword _gp
1121:
113 ld gp, 0(ra)
114
115#ifndef CONFIG_SKIP_LOWLEVEL_INIT
116 /* Initialize any external memory */
117 dla t9, lowlevel_init
118 jalr t9
119 nop
120
121 /* Initialize caches... */
122 dla t9, mips_cache_reset
123 jalr t9
124 nop
125
126 /* ... and enable them */
127 dli t0, CONFIG_SYS_MIPS_CACHE_MODE
128 mtc0 t0, CP0_CONFIG
129#endif
130
131 /* Set up temporary stack */
Gabor Juhosf321b0f2013-01-24 06:27:52 +0000132 dli sp, CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_INIT_SP_OFFSET
Zhi-zhou Zhang32afad72012-10-16 15:02:08 +0200133
134 dla t9, board_init_f
135 jr t9
136 nop
137
138/*
139 * void relocate_code (addr_sp, gd, addr_moni)
140 *
141 * This "function" does not return, instead it continues in RAM
142 * after relocating the monitor code.
143 *
144 * a0 = addr_sp
145 * a1 = gd
146 * a2 = destination address
147 */
148 .globl relocate_code
149 .ent relocate_code
150relocate_code:
151 move sp, a0 # set new stack pointer
152
Gabor Juhosb2fe86f2013-01-24 06:27:53 +0000153 move s0, a1 # save gd in s0
154 move s2, a2 # save destination address in s2
155
Zhi-zhou Zhang32afad72012-10-16 15:02:08 +0200156 dli t0, CONFIG_SYS_MONITOR_BASE
Gabor Juhos248fe032013-01-24 06:27:54 +0000157 dsub s1, s2, t0 # s1 <-- relocation offset
158
Zhi-zhou Zhang32afad72012-10-16 15:02:08 +0200159 dla t3, in_ram
Daniel Schwierzeck28875e22013-02-12 22:22:13 +0100160 ld t2, -24(t3) # t2 <-- __image_copy_end
Zhi-zhou Zhang32afad72012-10-16 15:02:08 +0200161 move t1, a2
Zhi-zhou Zhang32afad72012-10-16 15:02:08 +0200162
Gabor Juhos248fe032013-01-24 06:27:54 +0000163 dadd gp, s1 # adjust gp
Zhi-zhou Zhang32afad72012-10-16 15:02:08 +0200164
165 /*
166 * t0 = source address
167 * t1 = target address
168 * t2 = source end address
169 */
Zhi-zhou Zhang32afad72012-10-16 15:02:08 +02001701:
171 lw t3, 0(t0)
172 sw t3, 0(t1)
173 daddu t0, 4
Gabor Juhos5b7dd812013-01-24 06:27:51 +0000174 blt t0, t2, 1b
Zhi-zhou Zhang32afad72012-10-16 15:02:08 +0200175 daddu t1, 4
176
177 /* If caches were enabled, we would have to flush them here. */
Gabor Juhos67d80c92013-01-24 06:27:55 +0000178 dsub a1, t1, s2 # a1 <-- size
Zhi-zhou Zhang32afad72012-10-16 15:02:08 +0200179 dla t9, flush_cache
180 jalr t9
Gabor Juhos67d80c92013-01-24 06:27:55 +0000181 move a0, s2 # a0 <-- destination address
Zhi-zhou Zhang32afad72012-10-16 15:02:08 +0200182
183 /* Jump to where we've relocated ourselves */
184 daddi t0, s2, in_ram - _start
185 jr t0
186 nop
187
Gabor Juhos04380c62013-02-12 22:22:13 +0100188 .dword __rel_dyn_end
189 .dword __rel_dyn_start
Daniel Schwierzeck28875e22013-02-12 22:22:13 +0100190 .dword __image_copy_end
Zhi-zhou Zhang32afad72012-10-16 15:02:08 +0200191 .dword _GLOBAL_OFFSET_TABLE_
Zhi-zhou Zhang32afad72012-10-16 15:02:08 +0200192 .dword num_got_entries
193
194in_ram:
195 /*
196 * Now we want to update GOT.
197 *
198 * GOT[0] is reserved. GOT[1] is also reserved for the dynamic object
199 * generated by GNU ld. Skip these reserved entries from relocation.
200 */
201 ld t3, -8(t0) # t3 <-- num_got_entries
Daniel Schwierzeck28875e22013-02-12 22:22:13 +0100202 ld t8, -16(t0) # t8 <-- _GLOBAL_OFFSET_TABLE_
Gabor Juhos025f2b32013-01-30 04:56:37 +0000203 dadd t8, s1 # t8 now holds relocated _G_O_T_
Zhi-zhou Zhang32afad72012-10-16 15:02:08 +0200204 daddi t8, t8, 16 # skipping first two entries
205 dli t2, 2
2061:
207 ld t1, 0(t8)
208 beqz t1, 2f
209 dadd t1, s1
210 sd t1, 0(t8)
2112:
212 daddi t2, 1
213 blt t2, t3, 1b
214 daddi t8, 8
215
Gabor Juhos04380c62013-02-12 22:22:13 +0100216 /* Update dynamic relocations */
217 ld t1, -32(t0) # t1 <-- __rel_dyn_start
218 ld t2, -40(t0) # t2 <-- __rel_dyn_end
219
220 b 2f # skip first reserved entry
221 daddi t1, 16
222
2231:
224 lw t8, -4(t1) # t8 <-- relocation info
225
226 dli t3, MIPS64_R_INFO(0x00, 0x00, 0x12, 0x03)
227 bne t8, t3, 2f # skip non R_MIPS_REL32 entries
228 nop
229
230 ld t3, -16(t1) # t3 <-- location to fix up in FLASH
231
232 ld t8, 0(t3) # t8 <-- original pointer
233 dadd t8, s1 # t8 <-- adjusted pointer
234
235 dadd t3, s1 # t3 <-- location to fix up in RAM
236 sd t8, 0(t3)
237
2382:
239 blt t1, t2, 1b
240 daddi t1, 16 # each rel.dyn entry is 16 bytes
241
Daniel Schwierzeck696a3b22013-02-12 22:22:13 +0100242 /*
243 * Clear BSS
244 *
245 * GOT is now relocated. Thus __bss_start and __bss_end can be
246 * accessed directly via $gp.
247 */
248 dla t1, __bss_start # t1 <-- __bss_start
249 dla t2, __bss_end # t2 <-- __bss_end
Zhi-zhou Zhang32afad72012-10-16 15:02:08 +0200250
Zhi-zhou Zhang32afad72012-10-16 15:02:08 +02002511:
Daniel Schwierzeck696a3b22013-02-12 22:22:13 +0100252 sd zero, 0(t1)
253 blt t1, t2, 1b
254 daddi t1, 8
Zhi-zhou Zhang32afad72012-10-16 15:02:08 +0200255
256 move a0, s0 # a0 <-- gd
257 dla t9, board_init_r
258 jr t9
259 move a1, s2
260
261 .end relocate_code