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
45tstart:
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
190slave_cpu:
191	; A slave waits for cpu_now_booting to be equal to CPU ID.
192	move.d	cpu_now_booting, $r1
193slave_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
205master_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
2461:	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]
2681:	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
294move_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
3581:
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
3682:
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
3861:
387	move.b  [$r11+], $r12
388	move.b  $r12, [$r10+]
389	subq	1, $r13
390	bne	1b
391	nop
392
393no_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
4081:	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
430etrax_irv:
431	.dword 0
432romfs_start:
433	.dword 0
434romfs_length:
435	.dword 0
436romfs_in_flash:
437	.dword 0
438crisv32_nand_boot:
439	.dword 0
440crisv32_nand_cramfs_offset:
441	.dword 0
442
443swapper_pg_dir = 0xc0002000
444
445	.section ".init.data", "aw"
446
447#include "../lib/hw_settings.S"
448