Merge /spare/repo/linux-2.6/
[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 #include <linux/config.h>
8
9 #define ASSEMBLER_MACROS_ONLY
10
11 /*
12  * The macros found in mmu_defs_asm.h uses the ## concatenation operator, so
13  * -traditional must not be used when assembling this file.
14  */
15 #include <asm/arch/hwregs/reg_rdwr.h>
16 #include <asm/arch/hwregs/asm/mmu_defs_asm.h>
17 #include <asm/arch/hwregs/asm/reg_map_asm.h>
18 #include <asm/arch/hwregs/asm/config_defs_asm.h>
19 #include <asm/arch/hwregs/asm/bif_core_defs_asm.h>
20
21 #define CRAMFS_MAGIC 0x28cd3d45
22 #define RAM_INIT_MAGIC 0x56902387
23 #define COMMAND_LINE_MAGIC 0x87109563
24
25         ;; NOTE: R8 and R9 carry information from the decompressor (if the
26         ;; kernel was compressed). They must not be used in the code below
27         ;; until they are read!
28
29         ;; Exported symbols.
30         .global etrax_irv
31         .global romfs_start
32         .global romfs_length
33         .global romfs_in_flash
34         .global swapper_pg_dir
35         .global crisv32_nand_boot
36         .global crisv32_nand_cramfs_offset
37
38         ;; Dummy section to make it bootable with current VCS simulator
39 #ifdef CONFIG_ETRAXFS_SIM
40         .section ".boot", "ax"
41         ba tstart
42         nop
43 #endif
44
45         .text
46 tstart:
47         ;; This is the entry point of the kernel. The CPU is currently in
48         ;; supervisor mode.
49         ;;
50         ;; 0x00000000 if flash.
51         ;; 0x40004000 if DRAM.
52         ;;
53         di
54
55         ;; Start clocks for used blocks.
56         move.d REG_ADDR(config, regi_config, rw_clk_ctrl), $r1
57         move.d [$r1], $r0
58         or.d   REG_STATE(config, rw_clk_ctrl, cpu, yes) | \
59                REG_STATE(config, rw_clk_ctrl, bif, yes) | \
60                REG_STATE(config, rw_clk_ctrl, fix_io, yes), $r0
61         move.d $r0, [$r1]
62
63         ;; Set up waitstates etc
64         move.d   REG_ADDR(bif_core, regi_bif_core, rw_grp1_cfg), $r0
65         move.d   CONFIG_ETRAX_MEM_GRP1_CONFIG, $r1
66         move.d   $r1, [$r0]
67         move.d   REG_ADDR(bif_core, regi_bif_core, rw_grp2_cfg), $r0
68         move.d   CONFIG_ETRAX_MEM_GRP2_CONFIG, $r1
69         move.d   $r1, [$r0]
70         move.d   REG_ADDR(bif_core, regi_bif_core, rw_grp3_cfg), $r0
71         move.d   CONFIG_ETRAX_MEM_GRP3_CONFIG, $r1
72         move.d   $r1, [$r0]
73         move.d   REG_ADDR(bif_core, regi_bif_core, rw_grp4_cfg), $r0
74         move.d   CONFIG_ETRAX_MEM_GRP4_CONFIG, $r1
75         move.d   $r1, [$r0]
76
77 #ifdef CONFIG_ETRAXFS_SIM
78         ;; Set up minimal flash waitstates
79         move.d 0, $r10
80         move.d REG_ADDR(bif_core, regi_bif_core, rw_grp1_cfg), $r11
81         move.d $r10, [$r11]
82 #endif
83
84         ;; Setup and enable the MMU. Use same configuration for both the data
85         ;; and the instruction MMU.
86         ;;
87         ;; Note; 3 cycles is needed for a bank-select to take effect. Further;
88         ;; bank 1 is the instruction MMU, bank 2 is the data MMU.
89 #ifndef CONFIG_ETRAXFS_SIM
90         move.d  REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8)       \
91                 | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4)     \
92                 | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb), $r0
93 #else
94         ;; Map the virtual DRAM to the RW eprom area at address 0.
95         ;; Also map 0xa for the hook calls,
96         move.d  REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8)       \
97                 | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 0)     \
98                 | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb)   \
99                 | REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0xa), $r0
100 #endif
101
102         ;; Temporary map of 0x40 -> 0x40 and 0x00 -> 0x00.
103         move.d  REG_FIELD(mmu, rw_mm_kbase_lo, base_4, 4)  \
104                 | REG_FIELD(mmu, rw_mm_kbase_lo, base_0, 0), $r1
105
106         ;; Enable certain page protections and setup linear mapping
107         ;; for f,e,c,b,4,0.
108 #ifndef CONFIG_ETRAXFS_SIM
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, linear)      \
114                 | REG_STATE(mmu, rw_mm_cfg, seg_e, linear)      \
115                 | REG_STATE(mmu, rw_mm_cfg, seg_d, page)        \
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 #else
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, linear)      \
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 #endif
151
152         ;; Update instruction MMU.
153         move    1, $srs
154         nop
155         nop
156         nop
157         move    $r0, $s2        ; kbase_hi.
158         move    $r1, $s1        ; kbase_lo.
159         move    $r2, $s0        ; mm_cfg, virtual memory configuration.
160
161         ;; Update data MMU.
162         move    2, $srs
163         nop
164         nop
165         nop
166         move    $r0, $s2        ; kbase_hi.
167         move    $r1, $s1        ; kbase_lo
168         move    $r2, $s0        ; mm_cfg, virtual memory configuration.
169
170         ;; Enable data and instruction MMU.
171         move    0, $srs
172         moveq   0xf, $r0        ;  IMMU, DMMU, DCache, Icache on
173         nop
174         nop
175         nop
176         move    $r0, $s0
177         nop
178         nop
179         nop
180
181 #ifdef CONFIG_SMP
182         ;; Read CPU ID
183         move    0, $srs
184         nop
185         nop
186         nop
187         move    $s10, $r0
188         cmpq    0, $r0
189         beq     master_cpu
190         nop
191 slave_cpu:
192         ; A slave waits for cpu_now_booting to be equal to CPU ID.
193         move.d  cpu_now_booting, $r1
194 slave_wait:
195         cmp.d   [$r1], $r0
196         bne     slave_wait
197         nop
198         ; Time to boot-up. Get stack location provided by master CPU.
199         move.d  smp_init_current_idle_thread, $r1
200         move.d  [$r1], $sp
201         add.d   8192, $sp
202         move.d  ebp_start, $r0  ; Defined in linker-script.
203         move    $r0, $ebp
204         jsr     smp_callin
205         nop
206 master_cpu:
207 #endif
208 #ifndef CONFIG_ETRAXFS_SIM
209         ;; Check if starting from DRAM or flash.
210         lapcq   ., $r0
211         and.d   0x7fffffff, $r0 ; Mask off the non-cache bit.
212         cmp.d   0x10000, $r0    ; Arbitrary, something above this code.
213         blo     _inflash0
214         nop
215 #endif
216
217         jump    _inram          ; Jump to cached RAM.
218         nop
219
220         ;; Jumpgate.
221 _inflash0:
222         jump _inflash
223         nop
224
225         ;; Put the following in a section so that storage for it can be
226         ;; reclaimed after init is finished.
227         .section ".init.text", "ax"
228
229 _inflash:
230
231         ;; Initialize DRAM.
232         cmp.d   RAM_INIT_MAGIC, $r8 ; Already initialized?
233         beq     _dram_initialized
234         nop
235
236 #include "../lib/dram_init.S"
237
238 _dram_initialized:
239         ;; Copy the text and data section to DRAM. This depends on that the
240         ;; variables used below are correctly set up by the linker script.
241         ;; The calculated value stored in R4 is used below.
242         moveq   0, $r0          ; Source.
243         move.d  text_start, $r1 ; Destination.
244         move.d  __vmlinux_end, $r2
245         move.d  $r2, $r4
246         sub.d   $r1, $r4
247 1:      move.w  [$r0+], $r3
248         move.w  $r3, [$r1+]
249         cmp.d   $r2, $r1
250         blo     1b
251         nop
252
253         ;; Keep CRAMFS in flash.
254         moveq   0, $r0
255         move.d  romfs_length, $r1
256         move.d  $r0, [$r1]
257         move.d  [$r4], $r0      ; cramfs_super.magic
258         cmp.d   CRAMFS_MAGIC, $r0
259         bne 1f
260         nop
261
262         addoq   +4, $r4, $acr
263         move.d  [$acr], $r0
264         move.d  romfs_length, $r1
265         move.d  $r0, [$r1]
266         add.d   0xf0000000, $r4 ; Add cached flash start in virtual memory.
267         move.d  romfs_start, $r1
268         move.d  $r4, [$r1]
269 1:      moveq   1, $r0
270         move.d  romfs_in_flash, $r1
271         move.d  $r0, [$r1]
272
273         jump    _start_it       ; Jump to cached code.
274         nop
275
276 _inram:
277         ;; Check if booting from NAND flash (in that case we just remember the offset
278         ;; into the flash where cramfs should be).
279         move.d  REG_ADDR(config, regi_config, r_bootsel), $r0
280         move.d  [$r0], $r0
281         and.d   REG_MASK(config, r_bootsel, boot_mode), $r0
282         cmp.d   REG_STATE(config, r_bootsel, boot_mode, nand), $r0
283         bne     move_cramfs
284         moveq   1,$r0
285         move.d  crisv32_nand_boot, $r1
286         move.d  $r0, [$r1]
287         move.d  crisv32_nand_cramfs_offset, $r1
288         move.d  $r9, [$r1]
289         moveq   1, $r0
290         move.d  romfs_in_flash, $r1
291         move.d  $r0, [$r1]
292         jump    _start_it
293         nop
294
295 move_cramfs:
296         ;; Move the cramfs after BSS.
297         moveq   0, $r0
298         move.d  romfs_length, $r1
299         move.d  $r0, [$r1]
300
301 #ifndef CONFIG_ETRAXFS_SIM
302         ;; The kernel could have been unpacked to DRAM by the loader, but
303         ;; the cramfs image could still be inte the flash immediately
304         ;; following the compressed kernel image. The loaded passes the address
305         ;; of the bute succeeding the last compressed byte in the flash in
306         ;; register R9 when starting the kernel.
307         cmp.d   0x0ffffff8, $r9
308         bhs     _no_romfs_in_flash ; R9 points outside the flash area.
309         nop
310 #else
311         ba _no_romfs_in_flash
312         nop
313 #endif
314         move.d  [$r9], $r0      ; cramfs_super.magic
315         cmp.d   CRAMFS_MAGIC, $r0
316         bne     _no_romfs_in_flash
317         nop
318
319         addoq   +4, $r9, $acr
320         move.d  [$acr], $r0
321         move.d  romfs_length, $r1
322         move.d  $r0, [$r1]
323         add.d   0xf0000000, $r9 ; Add cached flash start in virtual memory.
324         move.d  romfs_start, $r1
325         move.d  $r9, [$r1]
326         moveq   1, $r0
327         move.d  romfs_in_flash, $r1
328         move.d  $r0, [$r1]
329
330         jump    _start_it       ; Jump to cached code.
331         nop
332
333 _no_romfs_in_flash:
334         ;; Look for cramfs.
335 #ifndef CONFIG_ETRAXFS_SIM
336         move.d  __vmlinux_end, $r0
337 #else
338         move.d  __end, $r0
339 #endif
340         move.d  [$r0], $r1
341         cmp.d   CRAMFS_MAGIC, $r1
342         bne     2f
343         nop
344
345         addoq   +4, $r0, $acr
346         move.d  [$acr], $r2
347         move.d  _end, $r1
348         move.d  romfs_start, $r3
349         move.d  $r1, [$r3]
350         move.d  romfs_length, $r3
351         move.d  $r2, [$r3]
352
353 #ifndef CONFIG_ETRAXFS_SIM
354         add.d   $r2, $r0
355         add.d   $r2, $r1
356
357         lsrq    1, $r2          ; Size is in bytes, we copy words.
358         addq    1, $r2
359 1:
360         move.w  [$r0], $r3
361         move.w  $r3, [$r1]
362         subq    2, $r0
363         subq    2, $r1
364         subq    1, $r2
365         bne     1b
366         nop
367 #endif
368
369 2:
370         moveq   0, $r0
371         move.d  romfs_in_flash, $r1
372         move.d  $r0, [$r1]
373
374         jump    _start_it       ; Jump to cached code.
375         nop
376
377 _start_it:
378
379         ;; Check if kernel command line is supplied
380         cmp.d   COMMAND_LINE_MAGIC, $r10
381         bne     no_command_line
382         nop
383
384         move.d  256, $r13
385         move.d  cris_command_line, $r10
386         or.d    0x80000000, $r11 ; Make it virtual
387 1:
388         move.b  [$r11+], $r12
389         move.b  $r12, [$r10+]
390         subq    1, $r13
391         bne     1b
392         nop
393
394 no_command_line:
395
396         ;; The kernel stack contains a task structure for each task. This
397         ;; the initial kernel stack is in the same page as the init_task,
398         ;; but starts at the top of the page, i.e. + 8192 bytes.
399         move.d  init_thread_union + 8192, $sp
400         move.d  ebp_start, $r0  ; Defined in linker-script.
401         move    $r0, $ebp
402         move.d  etrax_irv, $r1  ; Set the exception base register and pointer.
403         move.d  $r0, [$r1]
404
405 #ifndef CONFIG_ETRAXFS_SIM
406         ;; Clear the BSS region from _bss_start to _end.
407         move.d  __bss_start, $r0
408         move.d  _end, $r1
409 1:      clear.d [$r0+]
410         cmp.d   $r1, $r0
411         blo 1b
412         nop
413 #endif
414
415 #ifdef CONFIG_ETRAXFS_SIM
416         /* Set the watchdog timeout to something big. Will be removed when */
417         /* watchdog can be disabled with command line option */
418         move.d  0x7fffffff, $r10
419         jsr     CPU_WATCHDOG_TIMEOUT
420         nop
421 #endif
422
423         ; Initialize registers to increase determinism
424         move.d __bss_start, $r0
425         movem [$r0], $r13
426
427         jump    start_kernel    ; Jump to start_kernel() in init/main.c.
428         nop
429
430         .data
431 etrax_irv:
432         .dword 0
433 romfs_start:
434         .dword 0
435 romfs_length:
436         .dword 0
437 romfs_in_flash:
438         .dword 0
439 crisv32_nand_boot:
440         .dword 0
441 crisv32_nand_cramfs_offset:
442         .dword 0
443
444 swapper_pg_dir = 0xc0002000
445
446         .section ".init.data", "aw"
447
448 #include "../lib/hw_settings.S"