Commit | Line | Data |
---|---|---|
5a0015d6 CZ |
1 | /* |
2 | * arch/xtensa/kernel/head.S | |
3 | * | |
4 | * Xtensa Processor startup code. | |
5 | * | |
6 | * This file is subject to the terms and conditions of the GNU General Public | |
7 | * License. See the file "COPYING" in the main directory of this archive | |
8 | * for more details. | |
9 | * | |
2d1c645c | 10 | * Copyright (C) 2001 - 2008 Tensilica Inc. |
5a0015d6 CZ |
11 | * |
12 | * Chris Zankel <chris@zankel.net> | |
13 | * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca> | |
14 | * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> | |
15 | * Kevin Chea | |
16 | */ | |
17 | ||
5a0015d6 CZ |
18 | #include <asm/processor.h> |
19 | #include <asm/page.h> | |
173d6681 | 20 | #include <asm/cacheasm.h> |
c622b29d | 21 | #include <asm/initialize_mmu.h> |
f615136c | 22 | #include <asm/mxregs.h> |
5a0015d6 | 23 | |
0ebdcb4d | 24 | #include <linux/init.h> |
adba09f0 CZ |
25 | #include <linux/linkage.h> |
26 | ||
5a0015d6 CZ |
27 | /* |
28 | * This module contains the entry code for kernel images. It performs the | |
29 | * minimal setup needed to call the generic C routines. | |
30 | * | |
31 | * Prerequisites: | |
32 | * | |
33 | * - The kernel image has been loaded to the actual address where it was | |
34 | * compiled to. | |
35 | * - a2 contains either 0 or a pointer to a list of boot parameters. | |
36 | * (see setup.c for more details) | |
37 | * | |
38 | */ | |
39 | ||
5a0015d6 CZ |
40 | /* |
41 | * _start | |
42 | * | |
43 | * The bootloader passes a pointer to a list of boot parameters in a2. | |
44 | */ | |
45 | ||
46 | /* The first bytes of the kernel image must be an instruction, so we | |
47 | * manually allocate and define the literal constant we need for a jx | |
48 | * instruction. | |
49 | */ | |
50 | ||
0ebdcb4d | 51 | __HEAD |
e85e335f MF |
52 | .begin no-absolute-literals |
53 | ||
d1538c46 CZ |
54 | ENTRY(_start) |
55 | ||
e85e335f MF |
56 | /* Preserve the pointer to the boot parameter list in EXCSAVE_1 */ |
57 | wsr a2, excsave1 | |
f615136c | 58 | _j _SetupOCD |
e85e335f MF |
59 | |
60 | .align 4 | |
61 | .literal_position | |
f615136c MF |
62 | _SetupOCD: |
63 | /* | |
64 | * Initialize WB, WS, and clear PS.EXCM (to allow loop instructions). | |
65 | * Set Interrupt Level just below XCHAL_DEBUGLEVEL to allow | |
66 | * xt-gdb to single step via DEBUG exceptions received directly | |
67 | * by ocd. | |
68 | */ | |
69 | movi a1, 1 | |
70 | movi a0, 0 | |
71 | wsr a1, windowstart | |
72 | wsr a0, windowbase | |
73 | rsync | |
74 | ||
75 | movi a1, LOCKLEVEL | |
76 | wsr a1, ps | |
77 | rsync | |
78 | ||
e85e335f MF |
79 | .global _SetupMMU |
80 | _SetupMMU: | |
81 | Offset = _SetupMMU - _start | |
82 | ||
83 | #ifdef CONFIG_INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX | |
84 | initialize_mmu | |
c5a771d0 MF |
85 | #if defined(CONFIG_MMU) && XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY |
86 | rsr a2, excsave1 | |
40dc948f MF |
87 | movi a3, XCHAL_KSEG_PADDR |
88 | bltu a2, a3, 1f | |
89 | sub a2, a2, a3 | |
90 | movi a3, XCHAL_KSEG_SIZE | |
c5a771d0 | 91 | bgeu a2, a3, 1f |
40dc948f | 92 | movi a3, XCHAL_KSEG_CACHED_VADDR |
c5a771d0 MF |
93 | add a2, a2, a3 |
94 | wsr a2, excsave1 | |
95 | 1: | |
96 | #endif | |
e85e335f | 97 | #endif |
e85e335f | 98 | |
03760270 | 99 | movi a0, _startup |
5a0015d6 CZ |
100 | jx a0 |
101 | ||
d1538c46 | 102 | ENDPROC(_start) |
03760270 | 103 | .end no-absolute-literals |
d1538c46 | 104 | |
49b424fe | 105 | __REF |
e85e335f | 106 | .literal_position |
d1538c46 CZ |
107 | |
108 | ENTRY(_startup) | |
5a0015d6 | 109 | |
5a0015d6 CZ |
110 | /* Set a0 to 0 for the remaining initialization. */ |
111 | ||
112 | movi a0, 0 | |
113 | ||
53490121 | 114 | #if XCHAL_HAVE_VECBASE |
a9f2fc62 | 115 | movi a2, VECBASE_VADDR |
53490121 MF |
116 | wsr a2, vecbase |
117 | #endif | |
118 | ||
5a0015d6 CZ |
119 | /* Clear debugging registers. */ |
120 | ||
121 | #if XCHAL_HAVE_DEBUG | |
d83ff0bb | 122 | #if XCHAL_NUM_IBREAK > 0 |
bc5378fc | 123 | wsr a0, ibreakenable |
d83ff0bb | 124 | #endif |
bc5378fc | 125 | wsr a0, icount |
5a0015d6 | 126 | movi a1, 15 |
bc5378fc | 127 | wsr a0, icountlevel |
5a0015d6 | 128 | |
173d6681 | 129 | .set _index, 0 |
7de7ac78 | 130 | .rept XCHAL_NUM_DBREAK |
bc5378fc | 131 | wsr a0, SREG_DBREAKC + _index |
173d6681 CZ |
132 | .set _index, _index + 1 |
133 | .endr | |
5a0015d6 CZ |
134 | #endif |
135 | ||
136 | /* Clear CCOUNT (not really necessary, but nice) */ | |
137 | ||
bc5378fc | 138 | wsr a0, ccount # not really necessary, but nice |
5a0015d6 CZ |
139 | |
140 | /* Disable zero-loops. */ | |
141 | ||
142 | #if XCHAL_HAVE_LOOPS | |
bc5378fc | 143 | wsr a0, lcount |
5a0015d6 CZ |
144 | #endif |
145 | ||
146 | /* Disable all timers. */ | |
147 | ||
173d6681 | 148 | .set _index, 0 |
79fcf52b | 149 | .rept XCHAL_NUM_TIMERS |
bc5378fc | 150 | wsr a0, SREG_CCOMPARE + _index |
173d6681 CZ |
151 | .set _index, _index + 1 |
152 | .endr | |
5a0015d6 CZ |
153 | |
154 | /* Interrupt initialization. */ | |
155 | ||
156 | movi a2, XCHAL_INTTYPE_MASK_SOFTWARE | XCHAL_INTTYPE_MASK_EXTERN_EDGE | |
bc5378fc MF |
157 | wsr a0, intenable |
158 | wsr a2, intclear | |
5a0015d6 CZ |
159 | |
160 | /* Disable coprocessors. */ | |
161 | ||
eab5e7a7 | 162 | #if XCHAL_HAVE_CP |
bc5378fc | 163 | wsr a0, cpenable |
5a0015d6 CZ |
164 | #endif |
165 | ||
5a0015d6 | 166 | /* Initialize the caches. |
173d6681 | 167 | * a2, a3 are just working registers (clobbered). |
5a0015d6 CZ |
168 | */ |
169 | ||
173d6681 CZ |
170 | #if XCHAL_DCACHE_LINE_LOCKABLE |
171 | ___unlock_dcache_all a2 a3 | |
172 | #endif | |
173 | ||
174 | #if XCHAL_ICACHE_LINE_LOCKABLE | |
175 | ___unlock_icache_all a2 a3 | |
176 | #endif | |
177 | ||
178 | ___invalidate_dcache_all a2 a3 | |
179 | ___invalidate_icache_all a2 a3 | |
180 | ||
181 | isync | |
5a0015d6 | 182 | |
7bb516ca MF |
183 | initialize_cacheattr |
184 | ||
f615136c MF |
185 | #ifdef CONFIG_HAVE_SMP |
186 | movi a2, CCON # MX External Register to Configure Cache | |
187 | movi a3, 1 | |
188 | wer a3, a2 | |
189 | #endif | |
190 | ||
191 | /* Setup stack and enable window exceptions (keep irqs disabled) */ | |
192 | ||
193 | movi a1, start_info | |
194 | l32i a1, a1, 0 | |
195 | ||
196 | movi a2, (1 << PS_WOE_BIT) | LOCKLEVEL | |
197 | # WOE=1, INTLEVEL=LOCKLEVEL, UM=0 | |
198 | wsr a2, ps # (enable reg-windows; progmode stack) | |
199 | rsync | |
200 | ||
f615136c MF |
201 | #ifdef CONFIG_SMP |
202 | /* | |
203 | * Notice that we assume with SMP that cores have PRID | |
204 | * supported by the cores. | |
205 | */ | |
206 | rsr a2, prid | |
207 | bnez a2, .Lboot_secondary | |
208 | ||
209 | #endif /* CONFIG_SMP */ | |
210 | ||
5a0015d6 CZ |
211 | /* Unpack data sections |
212 | * | |
213 | * The linker script used to build the Linux kernel image | |
214 | * creates a table located at __boot_reloc_table_start | |
215 | * that contans the information what data needs to be unpacked. | |
216 | * | |
217 | * Uses a2-a7. | |
218 | */ | |
219 | ||
220 | movi a2, __boot_reloc_table_start | |
221 | movi a3, __boot_reloc_table_end | |
222 | ||
223 | 1: beq a2, a3, 3f # no more entries? | |
224 | l32i a4, a2, 0 # start destination (in RAM) | |
225 | l32i a5, a2, 4 # end desination (in RAM) | |
226 | l32i a6, a2, 8 # start source (in ROM) | |
227 | addi a2, a2, 12 # next entry | |
228 | beq a4, a5, 1b # skip, empty entry | |
229 | beq a4, a6, 1b # skip, source and dest. are the same | |
230 | ||
231 | 2: l32i a7, a6, 0 # load word | |
232 | addi a6, a6, 4 | |
233 | s32i a7, a4, 0 # store word | |
234 | addi a4, a4, 4 | |
235 | bltu a4, a5, 2b | |
236 | j 1b | |
237 | ||
238 | 3: | |
239 | /* All code and initialized data segments have been copied. | |
240 | * Now clear the BSS segment. | |
241 | */ | |
242 | ||
8b307f9c CZ |
243 | movi a2, __bss_start # start of BSS |
244 | movi a3, __bss_stop # end of BSS | |
5a0015d6 | 245 | |
173d6681 | 246 | __loopt a2, a3, a4, 2 |
5a0015d6 | 247 | s32i a0, a2, 0 |
5029615e | 248 | __endla a2, a3, 4 |
5a0015d6 CZ |
249 | |
250 | #if XCHAL_DCACHE_IS_WRITEBACK | |
251 | ||
252 | /* After unpacking, flush the writeback cache to memory so the | |
253 | * instructions/data are available. | |
254 | */ | |
255 | ||
173d6681 | 256 | ___flush_dcache_all a2 a3 |
5a0015d6 | 257 | #endif |
e85e335f MF |
258 | memw |
259 | isync | |
260 | ___invalidate_icache_all a2 a3 | |
261 | isync | |
5a0015d6 | 262 | |
f615136c | 263 | movi a6, 0 |
bc5378fc | 264 | xsr a6, excsave1 |
5a0015d6 CZ |
265 | |
266 | /* init_arch kick-starts the linux kernel */ | |
267 | ||
2da03d41 MF |
268 | call4 init_arch |
269 | call4 start_kernel | |
5a0015d6 CZ |
270 | |
271 | should_never_return: | |
272 | j should_never_return | |
273 | ||
f615136c MF |
274 | #ifdef CONFIG_SMP |
275 | .Lboot_secondary: | |
276 | ||
277 | movi a2, cpu_start_ccount | |
278 | 1: | |
32a7726c | 279 | memw |
f615136c MF |
280 | l32i a3, a2, 0 |
281 | beqi a3, 0, 1b | |
282 | movi a3, 0 | |
283 | s32i a3, a2, 0 | |
f615136c | 284 | 1: |
32a7726c | 285 | memw |
f615136c MF |
286 | l32i a3, a2, 0 |
287 | beqi a3, 0, 1b | |
288 | wsr a3, ccount | |
289 | movi a3, 0 | |
290 | s32i a3, a2, 0 | |
291 | memw | |
292 | ||
293 | movi a6, 0 | |
294 | wsr a6, excsave1 | |
295 | ||
2da03d41 | 296 | call4 secondary_start_kernel |
f615136c MF |
297 | j should_never_return |
298 | ||
299 | #endif /* CONFIG_SMP */ | |
300 | ||
d1538c46 | 301 | ENDPROC(_startup) |
5a0015d6 | 302 | |
49b424fe MF |
303 | #ifdef CONFIG_HOTPLUG_CPU |
304 | ||
305 | ENTRY(cpu_restart) | |
306 | ||
307 | #if XCHAL_DCACHE_IS_WRITEBACK | |
308 | ___flush_invalidate_dcache_all a2 a3 | |
309 | #else | |
310 | ___invalidate_dcache_all a2 a3 | |
311 | #endif | |
312 | memw | |
313 | movi a2, CCON # MX External Register to Configure Cache | |
314 | movi a3, 0 | |
315 | wer a3, a2 | |
316 | extw | |
317 | ||
318 | rsr a0, prid | |
319 | neg a2, a0 | |
320 | movi a3, cpu_start_id | |
32a7726c | 321 | memw |
49b424fe MF |
322 | s32i a2, a3, 0 |
323 | #if XCHAL_DCACHE_IS_WRITEBACK | |
324 | dhwbi a3, 0 | |
325 | #endif | |
326 | 1: | |
32a7726c | 327 | memw |
49b424fe MF |
328 | l32i a2, a3, 0 |
329 | dhi a3, 0 | |
330 | bne a2, a0, 1b | |
331 | ||
332 | /* | |
333 | * Initialize WB, WS, and clear PS.EXCM (to allow loop instructions). | |
334 | * Set Interrupt Level just below XCHAL_DEBUGLEVEL to allow | |
335 | * xt-gdb to single step via DEBUG exceptions received directly | |
336 | * by ocd. | |
337 | */ | |
338 | movi a1, 1 | |
339 | movi a0, 0 | |
340 | wsr a1, windowstart | |
341 | wsr a0, windowbase | |
342 | rsync | |
343 | ||
344 | movi a1, LOCKLEVEL | |
345 | wsr a1, ps | |
346 | rsync | |
347 | ||
348 | j _startup | |
349 | ||
350 | ENDPROC(cpu_restart) | |
351 | ||
352 | #endif /* CONFIG_HOTPLUG_CPU */ | |
353 | ||
f615136c MF |
354 | /* |
355 | * DATA section | |
356 | */ | |
357 | ||
358 | .section ".data.init.refok" | |
359 | .align 4 | |
360 | ENTRY(start_info) | |
361 | .long init_thread_union + KERNEL_STACK_SIZE | |
362 | ||
adba09f0 CZ |
363 | /* |
364 | * BSS section | |
365 | */ | |
366 | ||
02b7da37 | 367 | __PAGE_ALIGNED_BSS |
e5083a63 | 368 | #ifdef CONFIG_MMU |
adba09f0 CZ |
369 | ENTRY(swapper_pg_dir) |
370 | .fill PAGE_SIZE, 1, 0 | |
d1538c46 | 371 | END(swapper_pg_dir) |
e5083a63 | 372 | #endif |
adba09f0 CZ |
373 | ENTRY(empty_zero_page) |
374 | .fill PAGE_SIZE, 1, 0 | |
d1538c46 | 375 | END(empty_zero_page) |