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