blob: 98b17f9f904b5bdc2569ecf8b6040f64d210178e [file] [log] [blame]
Michal Simek6d5af1a2009-03-27 14:25:20 +01001/*
2 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
3 * Copyright (C) 2007-2009 PetaLogix
4 * Copyright (C) 2006 Atmark Techno, Inc.
5 *
Michal Simek5846cc62009-05-26 16:30:09 +02006 * MMU code derived from arch/ppc/kernel/head_4xx.S:
7 * Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org>
8 * Initial PowerPC version.
9 * Copyright (c) 1996 Cort Dougan <cort@cs.nmt.edu>
10 * Rewritten for PReP
11 * Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
12 * Low-level exception handers, MMU support, and rewrite.
13 * Copyright (c) 1997 Dan Malek <dmalek@jlc.net>
14 * PowerPC 8xx modifications.
15 * Copyright (c) 1998-1999 TiVo, Inc.
16 * PowerPC 403GCX modifications.
17 * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
18 * PowerPC 403GCX/405GP modifications.
19 * Copyright 2000 MontaVista Software Inc.
20 * PPC405 modifications
21 * PowerPC 403GCX/405GP modifications.
22 * Author: MontaVista Software, Inc.
23 * frank_rowand@mvista.com or source@mvista.com
24 * debbie_chu@mvista.com
25 *
Michal Simek6d5af1a2009-03-27 14:25:20 +010026 * This file is subject to the terms and conditions of the GNU General Public
27 * License. See the file "COPYING" in the main directory of this archive
28 * for more details.
29 */
30
Steven J. Magnani7a0248e2010-04-09 22:03:37 -050031#include <linux/init.h>
Michal Simek6d5af1a2009-03-27 14:25:20 +010032#include <linux/linkage.h>
33#include <asm/thread_info.h>
34#include <asm/page.h>
Grant Likelyd8678b52009-10-15 10:57:53 -060035#include <linux/of_fdt.h> /* for OF_DT_HEADER */
Michal Simek6d5af1a2009-03-27 14:25:20 +010036
Michal Simek5846cc62009-05-26 16:30:09 +020037#ifdef CONFIG_MMU
38#include <asm/setup.h> /* COMMAND_LINE_SIZE */
39#include <asm/mmu.h>
40#include <asm/processor.h>
41
Michal Simek495162d2011-01-31 14:57:26 +010042.section .data
Michal Simek5846cc62009-05-26 16:30:09 +020043.global empty_zero_page
44.align 12
45empty_zero_page:
Steven J. Magnaniba9c4f82010-05-13 10:48:27 -050046 .space PAGE_SIZE
Michal Simek5846cc62009-05-26 16:30:09 +020047.global swapper_pg_dir
48swapper_pg_dir:
Steven J. Magnaniba9c4f82010-05-13 10:48:27 -050049 .space PAGE_SIZE
Michal Simek5846cc62009-05-26 16:30:09 +020050
51#endif /* CONFIG_MMU */
52
Michal Simek495162d2011-01-31 14:57:26 +010053.section .rodata
54.align 4
55endian_check:
56 .word 1
57
Steven J. Magnani7a0248e2010-04-09 22:03:37 -050058 __HEAD
Michal Simek6d5af1a2009-03-27 14:25:20 +010059ENTRY(_start)
Michal Simekee68f1742010-03-15 08:48:27 +010060#if CONFIG_KERNEL_BASE_ADDR == 0
61 brai TOPHYS(real_start)
62 .org 0x100
63real_start:
64#endif
65
Michal Simek173701d2011-11-09 15:39:58 +010066 mts rmsr, r0
Michal Simek26224342009-07-30 14:31:23 +020067/*
Michal Simek0eb6aaf2011-02-04 15:24:11 +010068 * According to Xilinx, msrclr instruction behaves like 'mfs rX,rpc'
69 * if the msrclr instruction is not enabled. We use this to detect
70 * if the opcode is available, by issuing msrclr and then testing the result.
71 * r8 == 0 - msr instructions are implemented
72 * r8 != 0 - msr instructions are not implemented
Michal Simek26224342009-07-30 14:31:23 +020073 */
Michal Simek173701d2011-11-09 15:39:58 +010074 mfs r1, rmsr
Michal Simek0eb6aaf2011-02-04 15:24:11 +010075 msrclr r8, 0 /* clear nothing - just read msr for test */
76 cmpu r8, r8, r1 /* r1 must contain msr reg content */
Michal Simek26224342009-07-30 14:31:23 +020077
John Williams909964e2009-06-22 14:02:09 +100078/* r7 may point to an FDT, or there may be one linked in.
79 if it's in r7, we've got to save it away ASAP.
80 We ensure r7 points to a valid FDT, just in case the bootloader
81 is broken or non-existent */
82 beqi r7, no_fdt_arg /* NULL pointer? don't copy */
Michal Simek026a2072011-01-26 13:41:05 +010083/* Does r7 point to a valid FDT? Load HEADER magic number */
84 /* Run time Big/Little endian platform */
85 /* Save 1 as word and load byte - 0 - BIG, 1 - LITTLE */
Michal Simek495162d2011-01-31 14:57:26 +010086 lbui r11, r0, TOPHYS(endian_check)
Michal Simek026a2072011-01-26 13:41:05 +010087 beqid r11, big_endian /* DO NOT break delay stop dependency */
88 lw r11, r0, r7 /* Big endian load in delay slot */
89 lwr r11, r0, r7 /* Little endian load */
90big_endian:
91 rsubi r11, r11, OF_DT_HEADER /* Check FDT header */
Michal Simekea3fd142009-06-22 12:31:55 +020092 beqi r11, _prepare_copy_fdt
93 or r7, r0, r0 /* clear R7 when not valid DTB */
John Williams909964e2009-06-22 14:02:09 +100094 bnei r11, no_fdt_arg /* No - get out of here */
Michal Simekea3fd142009-06-22 12:31:55 +020095_prepare_copy_fdt:
Michal Simek6d5af1a2009-03-27 14:25:20 +010096 or r11, r0, r0 /* incremment */
John Williams909964e2009-06-22 14:02:09 +100097 ori r4, r0, TOPHYS(_fdt_start)
Michal Simek3a1d2672011-07-13 15:26:09 +020098 ori r3, r0, (0x8000 - 4)
Michal Simek6d5af1a2009-03-27 14:25:20 +010099_copy_fdt:
100 lw r12, r7, r11 /* r12 = r7 + r11 */
101 sw r12, r4, r11 /* addr[r4 + r11] = r12 */
102 addik r11, r11, 4 /* increment counting */
103 bgtid r3, _copy_fdt /* loop for all entries */
104 addik r3, r3, -4 /* descrement loop */
105no_fdt_arg:
106
Michal Simek5846cc62009-05-26 16:30:09 +0200107#ifdef CONFIG_MMU
108
109#ifndef CONFIG_CMDLINE_BOOL
110/*
111 * handling command line
112 * copy command line to __init_end. There is space for storing command line.
113 */
114 or r6, r0, r0 /* incremment */
115 ori r4, r0, __init_end /* load address of command line */
116 tophys(r4,r4) /* convert to phys address */
117 ori r3, r0, COMMAND_LINE_SIZE - 1 /* number of loops */
118_copy_command_line:
Michal Simek3f218932010-03-24 11:06:23 +0100119 lbu r2, r5, r6 /* r2=r5+r6 - r5 contain pointer to command line */
120 sb r2, r4, r6 /* addr[r4+r6]= r2*/
Michal Simek5846cc62009-05-26 16:30:09 +0200121 addik r6, r6, 1 /* increment counting */
122 bgtid r3, _copy_command_line /* loop for all entries */
123 addik r3, r3, -1 /* descrement loop */
124 addik r5, r4, 0 /* add new space for command line */
125 tovirt(r5,r5)
126#endif /* CONFIG_CMDLINE_BOOL */
127
128#ifdef NOT_COMPILE
129/* save bram context */
130 or r6, r0, r0 /* incremment */
131 ori r4, r0, TOPHYS(_bram_load_start) /* save bram context */
132 ori r3, r0, (LMB_SIZE - 4)
133_copy_bram:
134 lw r7, r0, r6 /* r7 = r0 + r6 */
135 sw r7, r4, r6 /* addr[r4 + r6] = r7*/
136 addik r6, r6, 4 /* increment counting */
137 bgtid r3, _copy_bram /* loop for all entries */
138 addik r3, r3, -4 /* descrement loop */
139#endif
140 /* We have to turn on the MMU right away. */
141
142 /*
143 * Set up the initial MMU state so we can do the first level of
144 * kernel initialization. This maps the first 16 MBytes of memory 1:1
145 * virtual to physical.
146 */
147 nop
Michal Simek0691c972010-03-24 10:09:17 +0100148 addik r3, r0, MICROBLAZE_TLB_SIZE -1 /* Invalidate all TLB entries */
Michal Simek5846cc62009-05-26 16:30:09 +0200149_invalidate:
150 mts rtlbx, r3
151 mts rtlbhi, r0 /* flush: ensure V is clear */
Michal Simeke02db0a2010-02-08 16:41:38 +0100152 mts rtlblo, r0
Michal Simek5846cc62009-05-26 16:30:09 +0200153 bgtid r3, _invalidate /* loop for all entries */
154 addik r3, r3, -1
155 /* sync */
156
Michal Simek137d0792010-02-04 11:42:24 +0100157 /* Setup the kernel PID */
158 mts rpid,r0 /* Load the kernel PID */
159 nop
160 bri 4
161
Michal Simek5846cc62009-05-26 16:30:09 +0200162 /*
163 * We should still be executing code at physical address area
164 * RAM_BASEADDR at this point. However, kernel code is at
165 * a virtual address. So, set up a TLB mapping to cover this once
166 * translation is enabled.
167 */
168
169 addik r3,r0, CONFIG_KERNEL_START /* Load the kernel virtual address */
170 tophys(r4,r3) /* Load the kernel physical address */
171
Michal Simek95b0f9e2010-02-08 16:41:38 +0100172 /* start to do TLB calculation */
173 addik r12, r0, _end
174 rsub r12, r3, r12
175 addik r12, r12, CONFIG_KERNEL_PAD /* that's the pad */
176
177 or r9, r0, r0 /* TLB0 = 0 */
178 or r10, r0, r0 /* TLB1 = 0 */
179
180 addik r11, r12, -0x1000000
181 bgei r11, GT16 /* size is greater than 16MB */
182 addik r11, r12, -0x0800000
183 bgei r11, GT8 /* size is greater than 8MB */
184 addik r11, r12, -0x0400000
185 bgei r11, GT4 /* size is greater than 4MB */
186 /* size is less than 4MB */
187 addik r11, r12, -0x0200000
188 bgei r11, GT2 /* size is greater than 2MB */
189 addik r9, r0, 0x0100000 /* TLB0 must be 1MB */
190 addik r11, r12, -0x0100000
191 bgei r11, GT1 /* size is greater than 1MB */
192 /* TLB1 is 0 which is setup above */
193 bri tlb_end
194GT4: /* r11 contains the rest - will be either 1 or 4 */
195 ori r9, r0, 0x400000 /* TLB0 is 4MB */
196 bri TLB1
197GT16: /* TLB0 is 16MB */
198 addik r9, r0, 0x1000000 /* means TLB0 is 16MB */
199TLB1:
200 /* must be used r2 because of substract if failed */
201 addik r2, r11, -0x0400000
202 bgei r2, GT20 /* size is greater than 16MB */
203 /* size is >16MB and <20MB */
204 addik r11, r11, -0x0100000
205 bgei r11, GT17 /* size is greater than 17MB */
206 /* kernel is >16MB and < 17MB */
207GT1:
208 addik r10, r0, 0x0100000 /* means TLB1 is 1MB */
209 bri tlb_end
210GT2: /* TLB0 is 0 and TLB1 will be 4MB */
211GT17: /* TLB1 is 4MB - kernel size <20MB */
212 addik r10, r0, 0x0400000 /* means TLB1 is 4MB */
213 bri tlb_end
214GT8: /* TLB0 is still zero that's why I can use only TLB1 */
215GT20: /* TLB1 is 16MB - kernel size >20MB */
216 addik r10, r0, 0x1000000 /* means TLB1 is 16MB */
217tlb_end:
218
Michal Simek5846cc62009-05-26 16:30:09 +0200219 /*
220 * Configure and load two entries into TLB slots 0 and 1.
221 * In case we are pinning TLBs, these are reserved in by the
222 * other TLB functions. If not reserving, then it doesn't
223 * matter where they are loaded.
224 */
225 andi r4,r4,0xfffffc00 /* Mask off the real page number */
226 ori r4,r4,(TLB_WR | TLB_EX) /* Set the write and execute bits */
227
Michal Simeke02db0a2010-02-08 16:41:38 +0100228 /*
229 * TLB0 is always used - check if is not zero (r9 stores TLB0 value)
230 * if is use TLB1 value and clear it (r10 stores TLB1 value)
231 */
232 bnei r9, tlb0_not_zero
233 add r9, r10, r0
234 add r10, r0, r0
235tlb0_not_zero:
Michal Simek95b0f9e2010-02-08 16:41:38 +0100236
237 /* look at the code below */
238 ori r30, r0, 0x200
239 andi r29, r9, 0x100000
240 bneid r29, 1f
241 addik r30, r30, 0x80
242 andi r29, r9, 0x400000
243 bneid r29, 1f
244 addik r30, r30, 0x80
245 andi r29, r9, 0x1000000
246 bneid r29, 1f
247 addik r30, r30, 0x80
2481:
Michal Simek5846cc62009-05-26 16:30:09 +0200249 andi r3,r3,0xfffffc00 /* Mask off the effective page number */
Michal Simek95b0f9e2010-02-08 16:41:38 +0100250 ori r3,r3,(TLB_VALID)
Michal Simeke02db0a2010-02-08 16:41:38 +0100251 or r3, r3, r30
Michal Simek5846cc62009-05-26 16:30:09 +0200252
Michal Simeke02db0a2010-02-08 16:41:38 +0100253 /* Load tlb_skip size value which is index to first unused TLB entry */
254 lwi r11, r0, TOPHYS(tlb_skip)
255 mts rtlbx,r11 /* TLB slow 0 */
Michal Simek5846cc62009-05-26 16:30:09 +0200256
257 mts rtlblo,r4 /* Load the data portion of the entry */
258 mts rtlbhi,r3 /* Load the tag portion of the entry */
259
Michal Simeke02db0a2010-02-08 16:41:38 +0100260 /* Increase tlb_skip size */
261 addik r11, r11, 1
262 swi r11, r0, TOPHYS(tlb_skip)
263
Michal Simek95b0f9e2010-02-08 16:41:38 +0100264 /* TLB1 can be zeroes that's why we not setup it */
265 beqi r10, jump_over2
266
267 /* look at the code below */
268 ori r30, r0, 0x200
269 andi r29, r10, 0x100000
270 bneid r29, 1f
271 addik r30, r30, 0x80
272 andi r29, r10, 0x400000
273 bneid r29, 1f
274 addik r30, r30, 0x80
275 andi r29, r10, 0x1000000
276 bneid r29, 1f
277 addik r30, r30, 0x80
2781:
Michal Simek95b0f9e2010-02-08 16:41:38 +0100279 addk r4, r4, r9 /* previous addr + TLB0 size */
280 addk r3, r3, r9
281
282 andi r3,r3,0xfffffc00 /* Mask off the effective page number */
283 ori r3,r3,(TLB_VALID)
Michal Simeke02db0a2010-02-08 16:41:38 +0100284 or r3, r3, r30
Michal Simek5846cc62009-05-26 16:30:09 +0200285
Michal Simeke02db0a2010-02-08 16:41:38 +0100286 lwi r11, r0, TOPHYS(tlb_skip)
287 mts rtlbx, r11 /* r11 is used from TLB0 */
Michal Simek5846cc62009-05-26 16:30:09 +0200288
289 mts rtlblo,r4 /* Load the data portion of the entry */
290 mts rtlbhi,r3 /* Load the tag portion of the entry */
291
Michal Simeke02db0a2010-02-08 16:41:38 +0100292 /* Increase tlb_skip size */
293 addik r11, r11, 1
294 swi r11, r0, TOPHYS(tlb_skip)
295
Michal Simek95b0f9e2010-02-08 16:41:38 +0100296jump_over2:
Michal Simek5846cc62009-05-26 16:30:09 +0200297 /*
298 * Load a TLB entry for LMB, since we need access to
299 * the exception vectors, using a 4k real==virtual mapping.
300 */
Michal Simeke02db0a2010-02-08 16:41:38 +0100301 /* Use temporary TLB_ID for LMB - clear this temporary mapping later */
302 ori r6, r0, MICROBLAZE_LMB_TLB_ID
Michal Simek5846cc62009-05-26 16:30:09 +0200303 mts rtlbx,r6
304
305 ori r4,r0,(TLB_WR | TLB_EX)
306 ori r3,r0,(TLB_VALID | TLB_PAGESZ(PAGESZ_4K))
307
308 mts rtlblo,r4 /* Load the data portion of the entry */
309 mts rtlbhi,r3 /* Load the tag portion of the entry */
310
311 /*
312 * We now have the lower 16 Meg of RAM mapped into TLB entries, and the
313 * caches ready to work.
314 */
315turn_on_mmu:
316 ori r15,r0,start_here
317 ori r4,r0,MSR_KERNEL_VMS
318 mts rmsr,r4
319 nop
320 rted r15,0 /* enables MMU */
321 nop
322
323start_here:
324#endif /* CONFIG_MMU */
325
Michal Simek6d5af1a2009-03-27 14:25:20 +0100326 /* Initialize small data anchors */
Michal Simekcd341572011-02-01 09:00:57 +0100327 addik r13, r0, _KERNEL_SDA_BASE_
328 addik r2, r0, _KERNEL_SDA2_BASE_
Michal Simek6d5af1a2009-03-27 14:25:20 +0100329
330 /* Initialize stack pointer */
Michal Simekcd341572011-02-01 09:00:57 +0100331 addik r1, r0, init_thread_union + THREAD_SIZE - 4
Michal Simek6d5af1a2009-03-27 14:25:20 +0100332
333 /* Initialize r31 with current task address */
Michal Simekcd341572011-02-01 09:00:57 +0100334 addik r31, r0, init_task
Michal Simek6d5af1a2009-03-27 14:25:20 +0100335
336 /*
337 * Call platform dependent initialize function.
338 * Please see $(ARCH)/mach-$(SUBARCH)/setup.c for
339 * the function.
340 */
Michal Simek95b0f9e2010-02-08 16:41:38 +0100341 addik r11, r0, machine_early_init
342 brald r15, r11
Michal Simek6d5af1a2009-03-27 14:25:20 +0100343 nop
344
Michal Simek5846cc62009-05-26 16:30:09 +0200345#ifndef CONFIG_MMU
Michal Simekcd341572011-02-01 09:00:57 +0100346 addik r15, r0, machine_halt
Michal Simek6d5af1a2009-03-27 14:25:20 +0100347 braid start_kernel
348 nop
Michal Simek5846cc62009-05-26 16:30:09 +0200349#else
350 /*
351 * Initialize the MMU.
352 */
353 bralid r15, mmu_init
354 nop
355
356 /* Go back to running unmapped so we can load up new values
357 * and change to using our exception vectors.
358 * On the MicroBlaze, all we invalidate the used TLB entries to clear
359 * the old 16M byte TLB mappings.
360 */
361 ori r15,r0,TOPHYS(kernel_load_context)
362 ori r4,r0,MSR_KERNEL
363 mts rmsr,r4
364 nop
365 bri 4
366 rted r15,0
367 nop
368
369 /* Load up the kernel context */
370kernel_load_context:
Michal Simeke02db0a2010-02-08 16:41:38 +0100371 ori r5, r0, MICROBLAZE_LMB_TLB_ID
Michal Simek5846cc62009-05-26 16:30:09 +0200372 mts rtlbx,r5
373 nop
374 mts rtlbhi,r0
375 nop
376 addi r15, r0, machine_halt
377 ori r17, r0, start_kernel
378 ori r4, r0, MSR_KERNEL_VMS
379 mts rmsr, r4
380 nop
381 rted r17, 0 /* enable MMU and jump to start_kernel */
382 nop
383#endif /* CONFIG_MMU */