Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
[pandora-kernel.git] / arch / cris / arch-v32 / kernel / head.S
1 /*
2  * CRISv32 kernel startup code.
3  *
4  * Copyright (C) 2003, Axis Communications AB
5  */
6
7 #define ASSEMBLER_MACROS_ONLY
8
9 /*
10  * The macros found in mmu_defs_asm.h uses the ## concatenation operator, so
11  * -traditional must not be used when assembling this file.
12  */
13 #include <arch/memmap.h>
14 #include <hwregs/reg_rdwr.h>
15 #include <hwregs/intr_vect.h>
16 #include <hwregs/asm/mmu_defs_asm.h>
17 #include <hwregs/asm/reg_map_asm.h>
18 #include <mach/startup.inc>
19
20 #define CRAMFS_MAGIC 0x28cd3d45
21 #define JHEAD_MAGIC 0x1FF528A6
22 #define JHEAD_SIZE 8
23 #define RAM_INIT_MAGIC 0x56902387
24 #define COMMAND_LINE_MAGIC 0x87109563
25 #define NAND_BOOT_MAGIC 0x9a9db001
26
27         ;; NOTE: R8 and R9 carry information from the decompressor (if the
28         ;; kernel was compressed). They must not be used in the code below
29         ;; until they are read!
30
31         ;; Exported symbols.
32         .global etrax_irv
33         .global romfs_start
34         .global romfs_length
35         .global romfs_in_flash
36         .global nand_boot
37         .global swapper_pg_dir
38
39         ;; Dummy section to make it bootable with current VCS simulator
40 #ifdef CONFIG_ETRAX_VCS_SIM
41         .section ".boot", "ax"
42         ba tstart
43         nop
44 #endif
45
46         .text
47 tstart:
48         ;; This is the entry point of the kernel. The CPU is currently in
49         ;; supervisor mode.
50         ;;
51         ;; 0x00000000 if flash.
52         ;; 0x40004000 if DRAM.
53         ;;
54         di
55
56         START_CLOCKS
57
58         SETUP_WAIT_STATES
59
60         GIO_INIT
61
62 #ifdef CONFIG_SMP
63 secondary_cpu_entry: /* Entry point for secondary CPUs */
64         di
65 #endif
66
67         ;; Setup and enable the MMU. Use same configuration for both the data
68         ;; and the instruction MMU.
69         ;;
70         ;; Note; 3 cycles is needed for a bank-select to take effect. Further;
71         ;; bank 1 is the instruction MMU, bank 2 is the data MMU.
72
73 #ifdef CONFIG_CRIS_MACH_ARTPEC3
74         move.d  REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8)       \
75                 | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4)     \
76                 | REG_FIELD(mmu, rw_mm_kbase_hi, base_d, 5)     \
77                 | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb), $r0
78 #elif !defined(CONFIG_ETRAX_VCS_SIM)
79         move.d  REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8)       \
80                 | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4)     \
81                 | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb), $r0
82 #else
83         ;; Map the virtual DRAM to the RW eprom area at address 0.
84         ;; Also map 0xa for the hook calls,
85         move.d  REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8)       \
86                 | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4)     \
87                 | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb)   \
88                 | REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0xa), $r0
89 #endif
90
91         ;; Temporary map of 0x40 -> 0x40 and 0x00 -> 0x00.
92         move.d  REG_FIELD(mmu, rw_mm_kbase_lo, base_4, 4)  \
93                 | REG_FIELD(mmu, rw_mm_kbase_lo, base_0, 0), $r1
94
95         ;; Enable certain page protections and setup linear mapping
96         ;; for f,e,c,b,4,0.
97
98         ;; ARTPEC-3:
99         ;; c,d used for linear kernel mapping, up to 512 MB
100         ;; e used for vmalloc
101         ;; f unused, but page mapped to get page faults
102
103         ;; ETRAX FS:
104         ;; c used for linear kernel mapping, up to 256 MB
105         ;; d used for vmalloc
106         ;; e,f used for memory-mapped NOR flash
107
108 #ifdef CONFIG_CRIS_MACH_ARTPEC3
109         move.d  REG_STATE(mmu, rw_mm_cfg, we, on)               \
110                 | REG_STATE(mmu, rw_mm_cfg, acc, on)            \
111                 | REG_STATE(mmu, rw_mm_cfg, ex, on)             \
112                 | REG_STATE(mmu, rw_mm_cfg, inv, on)            \
113                 | REG_STATE(mmu, rw_mm_cfg, seg_f, page)        \
114                 | REG_STATE(mmu, rw_mm_cfg, seg_e, page)        \
115                 | REG_STATE(mmu, rw_mm_cfg, seg_d, linear)      \
116                 | REG_STATE(mmu, rw_mm_cfg, seg_c, linear)      \
117                 | REG_STATE(mmu, rw_mm_cfg, seg_b, linear)      \
118                 | REG_STATE(mmu, rw_mm_cfg, seg_a, page)        \
119                 | REG_STATE(mmu, rw_mm_cfg, seg_9, page)        \
120                 | REG_STATE(mmu, rw_mm_cfg, seg_8, page)        \
121                 | REG_STATE(mmu, rw_mm_cfg, seg_7, page)        \
122                 | REG_STATE(mmu, rw_mm_cfg, seg_6, page)        \
123                 | REG_STATE(mmu, rw_mm_cfg, seg_5, page)        \
124                 | REG_STATE(mmu, rw_mm_cfg, seg_4, linear)      \
125                 | REG_STATE(mmu, rw_mm_cfg, seg_3, page)        \
126                 | REG_STATE(mmu, rw_mm_cfg, seg_2, page)        \
127                 | REG_STATE(mmu, rw_mm_cfg, seg_1, page)        \
128                 | REG_STATE(mmu, rw_mm_cfg, seg_0, linear), $r2
129 #elif !defined(CONFIG_ETRAX_VCS_SIM)
130         move.d  REG_STATE(mmu, rw_mm_cfg, we, on)               \
131                 | REG_STATE(mmu, rw_mm_cfg, acc, on)            \
132                 | REG_STATE(mmu, rw_mm_cfg, ex, on)             \
133                 | REG_STATE(mmu, rw_mm_cfg, inv, on)            \
134                 | REG_STATE(mmu, rw_mm_cfg, seg_f, linear)      \
135                 | REG_STATE(mmu, rw_mm_cfg, seg_e, linear)      \
136                 | REG_STATE(mmu, rw_mm_cfg, seg_d, page)        \
137                 | REG_STATE(mmu, rw_mm_cfg, seg_c, linear)      \
138                 | REG_STATE(mmu, rw_mm_cfg, seg_b, linear)      \
139                 | REG_STATE(mmu, rw_mm_cfg, seg_a, page)        \
140                 | REG_STATE(mmu, rw_mm_cfg, seg_9, page)        \
141                 | REG_STATE(mmu, rw_mm_cfg, seg_8, page)        \
142                 | REG_STATE(mmu, rw_mm_cfg, seg_7, page)        \
143                 | REG_STATE(mmu, rw_mm_cfg, seg_6, page)        \
144                 | REG_STATE(mmu, rw_mm_cfg, seg_5, page)        \
145                 | REG_STATE(mmu, rw_mm_cfg, seg_4, linear)      \
146                 | REG_STATE(mmu, rw_mm_cfg, seg_3, page)        \
147                 | REG_STATE(mmu, rw_mm_cfg, seg_2, page)        \
148                 | REG_STATE(mmu, rw_mm_cfg, seg_1, page)        \
149                 | REG_STATE(mmu, rw_mm_cfg, seg_0, linear), $r2
150 #else
151         move.d  REG_STATE(mmu, rw_mm_cfg, we, on)               \
152                 | REG_STATE(mmu, rw_mm_cfg, acc, on)            \
153                 | REG_STATE(mmu, rw_mm_cfg, ex, on)             \
154                 | REG_STATE(mmu, rw_mm_cfg, inv, on)            \
155                 | REG_STATE(mmu, rw_mm_cfg, seg_f, linear)      \
156                 | REG_STATE(mmu, rw_mm_cfg, seg_e, linear)      \
157                 | REG_STATE(mmu, rw_mm_cfg, seg_d, page)        \
158                 | REG_STATE(mmu, rw_mm_cfg, seg_c, linear)      \
159                 | REG_STATE(mmu, rw_mm_cfg, seg_b, linear)      \
160                 | REG_STATE(mmu, rw_mm_cfg, seg_a, linear)      \
161                 | REG_STATE(mmu, rw_mm_cfg, seg_9, page)        \
162                 | REG_STATE(mmu, rw_mm_cfg, seg_8, page)        \
163                 | REG_STATE(mmu, rw_mm_cfg, seg_7, page)        \
164                 | REG_STATE(mmu, rw_mm_cfg, seg_6, page)        \
165                 | REG_STATE(mmu, rw_mm_cfg, seg_5, page)        \
166                 | REG_STATE(mmu, rw_mm_cfg, seg_4, linear)      \
167                 | REG_STATE(mmu, rw_mm_cfg, seg_3, page)        \
168                 | REG_STATE(mmu, rw_mm_cfg, seg_2, page)        \
169                 | REG_STATE(mmu, rw_mm_cfg, seg_1, page)        \
170                 | REG_STATE(mmu, rw_mm_cfg, seg_0, linear), $r2
171 #endif
172
173         ;; Update instruction MMU.
174         move    1, $srs
175         nop
176         nop
177         nop
178         move    $r0, $s2        ; kbase_hi.
179         move    $r1, $s1        ; kbase_lo.
180         move    $r2, $s0        ; mm_cfg, virtual memory configuration.
181
182         ;; Update data MMU.
183         move    2, $srs
184         nop
185         nop
186         nop
187         move    $r0, $s2        ; kbase_hi.
188         move    $r1, $s1        ; kbase_lo
189         move    $r2, $s0        ; mm_cfg, virtual memory configuration.
190
191         ;; Enable data and instruction MMU.
192         move    0, $srs
193         moveq   0xf, $r0        ;  IMMU, DMMU, DCache, Icache on
194         nop
195         nop
196         nop
197         move    $r0, $s0
198         nop
199         nop
200         nop
201
202 #ifdef CONFIG_SMP
203         ;; Read CPU ID
204         move    0, $srs
205         nop
206         nop
207         nop
208         move    $s12, $r0
209         cmpq    0, $r0
210         beq     master_cpu
211         nop
212 slave_cpu:
213         ; Time to boot-up. Get stack location provided by master CPU.
214         move.d  smp_init_current_idle_thread, $r1
215         move.d  [$r1], $sp
216         add.d   8192, $sp
217         move.d  ebp_start, $r0  ; Defined in linker-script.
218         move    $r0, $ebp
219         jsr     smp_callin
220         nop
221 master_cpu:
222         /* Set up entry point for secondary CPUs. The boot ROM has set up
223          * EBP at start of internal memory. The CPU will get there
224          * later when we issue an IPI to them... */
225         move.d MEM_INTMEM_START + IPI_INTR_VECT * 4, $r0
226         move.d secondary_cpu_entry, $r1
227         move.d $r1, [$r0]
228 #endif
229 #ifndef CONFIG_ETRAX_VCS_SIM
230         ; Check if starting from DRAM (network->RAM boot or unpacked
231         ; compressed kernel), or directly from flash.
232         lapcq   ., $r0
233         and.d   0x7fffffff, $r0 ; Mask off the non-cache bit.
234         cmp.d   0x10000, $r0    ; Arbitrary, something above this code.
235         blo     _inflash0
236         nop
237 #endif
238
239         jump    _inram          ; Jump to cached RAM.
240         nop
241
242         ;; Jumpgate.
243 _inflash0:
244         jump _inflash
245         nop
246
247         ;; Put the following in a section so that storage for it can be
248         ;; reclaimed after init is finished.
249         .section ".init.text", "ax"
250
251 _inflash:
252
253         ;; Initialize DRAM.
254         cmp.d   RAM_INIT_MAGIC, $r8 ; Already initialized?
255         beq     _dram_initialized
256         nop
257
258 #if defined CONFIG_ETRAXFS
259 #include "../mach-fs/dram_init.S"
260 #elif defined CONFIG_CRIS_MACH_ARTPEC3
261 #include "../mach-a3/dram_init.S"
262 #else
263 #error Only ETRAXFS and ARTPEC-3 supported!
264 #endif
265
266
267 _dram_initialized:
268         ;; Copy the text and data section to DRAM. This depends on that the
269         ;; variables used below are correctly set up by the linker script.
270         ;; The calculated value stored in R4 is used below.
271         ;; Leave the cramfs file system (piggybacked after the kernel) in flash.
272         moveq   0, $r0          ; Source.
273         move.d  text_start, $r1 ; Destination.
274         move.d  __vmlinux_end, $r2
275         move.d  $r2, $r4
276         sub.d   $r1, $r4
277 1:      move.w  [$r0+], $r3
278         move.w  $r3, [$r1+]
279         cmp.d   $r2, $r1
280         blo     1b
281         nop
282
283         ;; Check for cramfs.
284         moveq   0, $r0
285         move.d  romfs_length, $r1
286         move.d  $r0, [$r1]
287         move.d  [$r4], $r0      ; cramfs_super.magic
288         cmp.d   CRAMFS_MAGIC, $r0
289         bne 1f
290         nop
291
292         ;; Set length and start of cramfs, set romfs_in_flash flag
293         addoq   +4, $r4, $acr
294         move.d  [$acr], $r0
295         move.d  romfs_length, $r1
296         move.d  $r0, [$r1]
297         add.d   0xf0000000, $r4 ; Add cached flash start in virtual memory.
298         move.d  romfs_start, $r1
299         move.d  $r4, [$r1]
300 1:      moveq   1, $r0
301         move.d  romfs_in_flash, $r1
302         move.d  $r0, [$r1]
303
304         jump    _start_it       ; Jump to cached code.
305         nop
306
307 _inram:
308         ;; Check if booting from NAND flash; if so, set appropriate flags
309         ;; and move on.
310         cmp.d   NAND_BOOT_MAGIC, $r12
311         bne     move_cramfs     ; not nand, jump
312         moveq   1, $r0
313         move.d  nand_boot, $r1  ; tell axisflashmap we're booting from NAND
314         move.d  $r0, [$r1]
315         moveq   0, $r0          ; tell axisflashmap romfs is not in
316         move.d  romfs_in_flash, $r1 ; (directly accessed) flash
317         move.d  $r0, [$r1]
318         jump    _start_it       ; continue with boot
319         nop
320
321 move_cramfs:
322         ;; kernel is in DRAM.
323         ;; Must figure out if there is a piggybacked rootfs image or not.
324         ;; Set romfs_length to 0 => no rootfs image available by default.
325         moveq   0, $r0
326         move.d  romfs_length, $r1
327         move.d  $r0, [$r1]
328
329 #ifndef CONFIG_ETRAX_VCS_SIM
330         ;; The kernel could have been unpacked to DRAM by the loader, but
331         ;; the cramfs image could still be in the flash immediately
332         ;; following the compressed kernel image. The loader passes the address
333         ;; of the byte succeeding the last compressed byte in the flash in
334         ;; register R9 when starting the kernel.
335         cmp.d   0x0ffffff8, $r9
336         bhs     _no_romfs_in_flash ; R9 points outside the flash area.
337         nop
338 #else
339         ba _no_romfs_in_flash
340         nop
341 #endif
342         ;; cramfs rootfs might to be in flash. Check for it.
343         move.d  [$r9], $r0      ; cramfs_super.magic
344         cmp.d   CRAMFS_MAGIC, $r0
345         bne     _no_romfs_in_flash
346         nop
347
348         ;; found cramfs in flash. set address and size, and romfs_in_flash flag.
349         addoq   +4, $r9, $acr
350         move.d  [$acr], $r0
351         move.d  romfs_length, $r1
352         move.d  $r0, [$r1]
353         add.d   0xf0000000, $r9 ; Add cached flash start in virtual memory.
354         move.d  romfs_start, $r1
355         move.d  $r9, [$r1]
356         moveq   1, $r0
357         move.d  romfs_in_flash, $r1
358         move.d  $r0, [$r1]
359
360         jump    _start_it       ; Jump to cached code.
361         nop
362
363 _no_romfs_in_flash:
364         ;; No romfs in flash, so look for cramfs, or jffs2 with jhead,
365         ;; after kernel in RAM, as is the case with network->RAM boot.
366         ;; For cramfs, partition starts with magic and length.
367         ;; For jffs2, a jhead is prepended which contains with magic and length.
368         ;; The jhead is not part of the jffs2 partition however.
369 #ifndef CONFIG_ETRAXFS_SIM
370         move.d  __bss_start, $r0
371 #else
372         move.d  __end, $r0
373 #endif
374         move.d  [$r0], $r1
375         cmp.d   CRAMFS_MAGIC, $r1 ; cramfs magic?
376         beq     2f                ; yes, jump
377         nop
378         cmp.d   JHEAD_MAGIC, $r1 ; jffs2 (jhead) magic?
379         bne     4f              ; no, skip copy
380         nop
381         addq    4, $r0          ; location of jffs2 size
382         move.d  [$r0+], $r2     ; fetch jffs2 size -> r2
383                                 ; r0 now points to start of jffs2
384         ba      3f
385         nop
386 2:
387         addoq   +4, $r0, $acr   ; location of cramfs size
388         move.d  [$acr], $r2     ; fetch cramfs size -> r2
389                                 ; r0 still points to start of cramfs
390 3:
391         ;; Now, move the root fs to after kernel's BSS
392
393         move.d  _end, $r1       ; start of cramfs -> r1
394         move.d  romfs_start, $r3
395         move.d  $r1, [$r3]      ; store at romfs_start (for axisflashmap)
396         move.d  romfs_length, $r3
397         move.d  $r2, [$r3]      ; store size at romfs_length
398
399 #ifndef CONFIG_ETRAX_VCS_SIM
400         add.d   $r2, $r0        ; copy from end and downwards
401         add.d   $r2, $r1
402
403         lsrq    1, $r2          ; Size is in bytes, we copy words.
404         addq    1, $r2
405 1:
406         move.w  [$r0], $r3
407         move.w  $r3, [$r1]
408         subq    2, $r0
409         subq    2, $r1
410         subq    1, $r2
411         bne     1b
412         nop
413 #endif
414
415 4:
416         ;; BSS move done.
417         ;; Clear romfs_in_flash flag, as we now know romfs is in DRAM
418         ;; Also clear nand_boot flag; if we got here, we know we've not
419         ;; booted from NAND flash.
420         moveq   0, $r0
421         move.d  romfs_in_flash, $r1
422         move.d  $r0, [$r1]
423         moveq   0, $r0
424         move.d  nand_boot, $r1
425         move.d  $r0, [$r1]
426
427         jump    _start_it       ; Jump to cached code.
428         nop
429
430 _start_it:
431
432         ;; Check if kernel command line is supplied
433         cmp.d   COMMAND_LINE_MAGIC, $r10
434         bne     no_command_line
435         nop
436
437         move.d  256, $r13
438         move.d  cris_command_line, $r10
439         or.d    0x80000000, $r11 ; Make it virtual
440 1:
441         move.b  [$r11+], $r1
442         move.b  $r1, [$r10+]
443         subq    1, $r13
444         bne     1b
445         nop
446
447 no_command_line:
448
449         ;; The kernel stack contains a task structure for each task. This
450         ;; the initial kernel stack is in the same page as the init_task,
451         ;; but starts at the top of the page, i.e. + 8192 bytes.
452         move.d  init_thread_union + 8192, $sp
453         move.d  ebp_start, $r0  ; Defined in linker-script.
454         move    $r0, $ebp
455         move.d  etrax_irv, $r1  ; Set the exception base register and pointer.
456         move.d  $r0, [$r1]
457
458 #ifndef CONFIG_ETRAX_VCS_SIM
459         ;; Clear the BSS region from _bss_start to _end.
460         move.d  __bss_start, $r0
461         move.d  _end, $r1
462 1:      clear.d [$r0+]
463         cmp.d   $r1, $r0
464         blo 1b
465         nop
466 #endif
467
468 #ifdef CONFIG_ETRAX_VCS_SIM
469         /* Set the watchdog timeout to something big. Will be removed when */
470         /* watchdog can be disabled with command line option */
471         move.d  0x7fffffff, $r10
472         jsr     CPU_WATCHDOG_TIMEOUT
473         nop
474 #endif
475
476         ; Initialize registers to increase determinism
477         move.d __bss_start, $r0
478         movem [$r0], $r13
479
480 #ifdef CONFIG_ETRAX_L2CACHE
481         jsr     l2cache_init
482         nop
483 #endif
484
485         jump    start_kernel    ; Jump to start_kernel() in init/main.c.
486         nop
487
488         .data
489 etrax_irv:
490         .dword 0
491
492 ; Variables for communication with the Axis flash map driver (axisflashmap),
493 ; and for setting up memory in arch/cris/kernel/setup.c .
494
495 ; romfs_start is set to the start of the root file system, if it exists
496 ; in directly accessible memory (i.e. NOR Flash when booting from Flash,
497 ; or RAM when booting directly from a network-downloaded RAM image)
498 romfs_start:
499         .dword 0
500
501 ; romfs_length is set to the size of the root file system image, if it exists
502 ; in directly accessible memory (see romfs_start). Otherwise it is set to 0.
503 romfs_length:
504         .dword 0
505
506 ; romfs_in_flash is set to 1 if the root file system resides in directly
507 ; accessible flash memory (i.e. NOR flash). It is set to 0 for RAM boot
508 ; or NAND flash boot.
509 romfs_in_flash:
510         .dword 0
511
512 ; nand_boot is set to 1 when the kernel has been booted from NAND flash
513 nand_boot:
514         .dword 0
515
516 swapper_pg_dir = 0xc0002000
517
518         .section ".init.data", "aw"
519
520 #if defined CONFIG_ETRAXFS
521 #include "../mach-fs/hw_settings.S"
522 #elif defined CONFIG_CRIS_MACH_ARTPEC3
523 #include "../mach-a3/hw_settings.S"
524 #else
525 #error Only ETRAXFS and ARTPEC-3 supported!
526 #endif