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