summaryrefslogtreecommitdiffstats
path: root/arch/cris/kernel/head.S
blob: b436aa84345922d3e4acd4be7b108a42a063ab9f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
	;; $Id: head.S,v 1.11 2001/01/16 16:31:38 bjornw Exp $
	;; 
	;; Head of the kernel - alter with care
	;;
	;; Copyright (C) 2000, 2001 Axis Communications AB
	;;
	;; Authors:	Bjorn Wesen (bjornw@axis.com)
	;; 
	;; $Log: head.S,v $
	;; Revision 1.11  2001/01/16 16:31:38  bjornw
	;; * Changed name and semantics of running_from_flash to romfs_in_flash,
	;;   set by head.S to indicate to setup.c whether there is a cramfs image
	;;   after the kernels BSS or not. Should work for all three boot-cases
	;;   (DRAM with cramfs in DRAM, DRAM with cramfs in flash (compressed boot),
	;;    and flash with cramfs in flash)
	;;
	;; Revision 1.10  2001/01/16 14:12:21  bjornw
	;; * Check for cramfs start passed in r9 from the decompressor, if all other
	;;   cramfs options fail (if we boot from DRAM but don't find a cramfs image
	;;   after the kernel in DRAM, it is probably still in the flash)
	;; * Check magic in cramfs detection when booting from flash directly
	;;
	;; Revision 1.9  2001/01/15 17:17:02  bjornw
	;; * Corrected the code that detects the cramfs lengths
	;; * Added a comment saying that the above does not work due to other
	;;   reasons..
	;;
	;; Revision 1.8  2001/01/15 16:27:51  jonashg
	;; Made boot after flashing work.
	;; * end destination is __vmlinux_end in RAM.
	;; * _romfs_start moved because of virtual memory.
	;;
	;; Revision 1.7  2000/11/21 13:55:29  bjornw
	;; Use CONFIG_CRIS_LOW_MAP for the low VM map instead of explicit CPU type
	;;
	;; Revision 1.6  2000/10/06 12:36:55  bjornw
	;; Forgot swapper_pg_dir when changing memory map..
	;;
	;; Revision 1.5  2000/10/04 16:49:30  bjornw
	;; * Fixed memory mapping in LX
	;; * Check for cramfs instead of romfs
	;;
	;;
	
#include <linux/config.h>
#define ASSEMBLER_MACROS_ONLY
#include <asm/sv_addr_ag.h>

#define CRAMFS_MAGIC 0x28cd3d45
	
	;; exported symbols
		
	.globl	_etrax_irv
	.globl	_romfs_start
	.globl	_romfs_length
	.globl	_romfs_in_flash
	.globl  _swapper_pg_dir
					
	.text

	;; This is the entry point of the kernel. We are in supervisor mode.
	;; 0x00000000 if Flash, 0x40004000 if DRAM
	;; since etrax actually starts at address 2 when booting from flash, we
	;; put a nop (2 bytes) here first so we dont accidentally skip the di
	;;
	;; NOTICE! The register r9 is used as a parameter carrying register from
	;; the decompressor (if the kernel was compressed). It should not be
	;; used in the code below until it is read.
	
	nop	
	di

	;; First setup the kseg_c mapping from where the kernel is linked
	;; to 0x40000000 (where the actual DRAM resides) otherwise
	;; we cannot do very much! See arch/cris/README.mm
	;;
	;; Notice that since we're potentially running at 0x00 or 0x40 right now,
	;; we will get a fault as soon as we enable the MMU if we dont
	;; temporarily map those segments linearily.
	;;
	;; Due to a bug in Etrax-100 LX version 1 we need to map the memory
	;; slightly different. We also let the simulator get this mapping for now.

#ifdef CONFIG_CRIS_LOW_MAP
	move.d	0x0800b000, r0	; kseg mappings
	move.d	r0, [R_MMU_KBASE_HI]

	move.d	0x04040000, r0	; temporary map of 0x40->0x40 and 0x00->0x00 
	move.d	r0, [R_MMU_KBASE_LO]

	move.d	0x80074871, r0	; mmu enable, segs e,b,6,5,4,0 segment mapped
	move.d	r0, [R_MMU_CONFIG]
#else
	move.d	0x0804b000, r0	; kseg mappings
	move.d	r0, [R_MMU_KBASE_HI]

	move.d	0x00040000, r0	; temporary map of 0x40->0x40 and 0x00->0x00 
	move.d	r0, [R_MMU_KBASE_LO]

	move.d	0x8007d811, r0	; mmu enable, segs f,e,c,b,4,0 segment mapped
	move.d	r0, [R_MMU_CONFIG]
#endif

	;; Now we need to sort out the segments and their locations in RAM or
	;; Flash. The image in the Flash (or in DRAM) consists of 3 pieces:
	;; 1) kernel text, 2) kernel data, 3) ROM filesystem image
	;; But the linker has linked the kernel to expect this layout in
	;; DRAM memory:
	;; 1) kernel text, 2) kernel data, 3) kernel BSS
	;; (the location of the ROM filesystem is determined by the krom driver)
	;; If we boot this from Flash, we want to keep the ROM filesystem in
	;; the flash, we want to copy the text and need to copy the data to DRAM.
	;; But if we boot from DRAM, we need to move the ROMFS image
	;; from its position after kernel data, to after kernel BSS, BEFORE the
	;; kernel starts using the BSS area (since its "overlayed" with the ROMFS)
	;;
	;; In both cases, we start in un-cached mode, and need to jump into a
	;; cached PC after we're done fiddling around with the segments.
	;; 
	;; arch/etrax100/etrax100.ld sets some symbols that define the start
	;; and end of each segment.
	
	;; Check if we start from DRAM or FLASH by testing PC
	
	move.d	pc,r0
	and.d	0x7fffffff,r0	; get rid of the non-cache bit
	cmp.d	0x10000,r0	; arbitrary... just something above this code
	bcs	inflash
	nop

	jump	inram		; enter cached ram
	
inflash:

#ifndef CONFIG_SVINTO_SIM	

	;; We need to setup the bus registers before we start using the DRAM

	move.d   DEF_R_WAITSTATES, r0
	move.d   r0, [R_WAITSTATES]

	move.d   DEF_R_BUS_CONFIG, r0
	move.d   r0, [R_BUS_CONFIG]
  
	move.d   DEF_R_DRAM_CONFIG, r0
	move.d   r0, [R_DRAM_CONFIG]

	move.d   DEF_R_DRAM_TIMING, r0
	move.d   r0, [R_DRAM_TIMING]

#endif
	;; Copy text+data to DRAM
	;; This is fragile - the calculation of r4 as the image size depends
	;; on that the labels below actually are the first and last positions
	;; in the linker-script.
	;;
	;; Then the locating of the cramfs image depends on the aforementioned
	;; image being located in the flash at 0. This is most often not true,
	;; thus the following does not work (normally there is a rescue-block
	;; between the physical start of the flash and the flash-image start,
	;; and when run with compression, the kernel is actually unpacked to
	;; DRAM and we never get here in the first place :))
	
	moveq	0, r0			; source
	move.d	_text_start, r1		; destination
	move.d	__vmlinux_end, r2	; end destination
	move.d	r2, r4
	sub.d	r1, r4			; r4=__vmlinux_end in flash, used below
1:	move.w	[r0+], r3
	move.w	r3, [r1+]
	cmp.d	r2, r1
	bcs	1b
	nop

	;; We keep the cramfs in the flash.
	;; There might be none, but that does not matter because
	;; we don't do anything than read some bytes here.

	moveq	0, r0
	move.d	r0, [_romfs_length] ; default if there is no cramfs

	move.d  [r4], r0	; cramfs_super.magic
	cmp.d	CRAMFS_MAGIC, r0
	bne	1f
	nop
	move.d	[r4 + 4], r0	; cramfs_super.size
	move.d	r0, [_romfs_length]
#ifdef CONFIG_CRIS_LOW_MAP
	add.d   0x50000000, r4	; add flash start in virtual memory (cached)
#else
	add.d   0xf0000000, r4	; add flash start in virtual memory (cached)
#endif
	move.d	r4, [_romfs_start]
1:	
	moveq	1, r0
	move.d	r0, [_romfs_in_flash]
		
	jump	start_it	; enter code, cached this time

inram:
	;; Move the ROM fs to after BSS end. This assumes that the cramfs
	;; second longword contains the length of the cramfs
	
	moveq	0, r0
	move.d	r0, [_romfs_length] ; default if there is no cramfs
	
	;; First check if there is a cramfs (magic value)
	;; Notice that we check for cramfs magic value - which is
	;; the "rom fs" we'll possibly use in 2.4 if not JFFS (which does
	;; not need this mechanism anyway)
	
	move.d	__vmlinux_end, r0 ; the image will be after the vmlinux end address
	move.d	[r0], r1	; cramfs assumes same endian on host/target
	cmp.d	CRAMFS_MAGIC, r1; magic value in cramfs superblock
	bne	no_romfs_in_ram
	nop

	;; Ok. What is its size ? 
	
	move.d	[r0 + 4], r2	; cramfs_super.size (again, no need to swapwb)

	;; We want to copy it to the end of the BSS

	move.d	_end, r1

	;; Remember values so cramfs and setup can find this info

	move.d	r1, [_romfs_start]	; new romfs location
	move.d	r2, [_romfs_length]

	;; We need to copy it backwards, since they can be overlapping

	add.d	r2, r0
	add.d	r2, r1
		
	;; Go ahead. Make my loop.

	lsrq	1, r2		; size is in bytes, we copy words

1:	move.w	[r0=r0-2],r3
	move.w	r3,[r1=r1-2]
	subq	1, r2
	bne	1b
	nop
	
	;; Dont worry that the BSS is tainted. It will be cleared later.

	moveq	0, r0
	move.d	r0, [_romfs_in_flash]

	jump	start_it	; better skip the additional cramfs check below
			
no_romfs_in_ram:

	;; We have still one other possibility at this point - the kernel
	;; could have been unpacked to DRAM by the loader, but the cramfs
	;; image was still in the Flash directly after the compressed kernel
	;; image. The loader passes the address of the byte succeeding the
	;; last compressed byte in the flash in the register r9 when starting
	;; the kernel. Check if r9 points to a decent cramfs image!
	;; (Notice that if this is not booted from the loader, r9 will be
	;;  garbage but we do sanity checks on it, the chance that it points
	;;  to a cramfs magic is small.. )
	
	cmp.d	0x0ffffff8, r9
	bcc	1f		; r9 points outside the flash area
	nop
	move.d	[r9], r0	; cramfs_super.magic
	cmp.d	CRAMFS_MAGIC, r0
	bne	1f
	nop
	move.d	[r9+4], r0	; cramfs_super.length
	move.d	r0, [_romfs_length]
#ifdef CONFIG_CRIS_LOW_MAP
	add.d   0x50000000, r9	; add flash start in virtual memory (cached)
#else
	add.d   0xf0000000, r9	; add flash start in virtual memory (cached)
#endif
	move.d	r9, [_romfs_start]

	moveq	1, r0
	move.d	r0, [_romfs_in_flash]
1:	
	
	jump	start_it	; enter code, cached this time
	
start_it:
	;; the kernel stack is overlayed with the task structure for each
	;; task. thus the initial kernel stack is in the same page as the
	;; init_task (but starts in the top of the page, size 8192)
	move.d	_init_task_union + 8192,sp
	move.d	_ibr_start,r0	; this symbol is set by the linker script 
	move	r0,ibr
	move.d	r0,[_etrax_irv]	; set the interrupt base register and pointer

	;; Clear BSS region, from _bss_start to _end

	move.d	__bss_start, r0
	move.d	_end, r1
1:	clear.d	[r0+]
	cmp.d	r1, r0
	bcs	1b
	nop
	
#ifdef CONFIG_BLK_DEV_ETRAXIDE
	;; disable ATA before enabling it in genconfig below
	moveq	0,r0
	move.d	r0,[R_ATA_CTRL_DATA]
	move.d	r0,[R_ATA_TRANSFER_CNT]
	move.d	r0,[R_ATA_CONFIG]
#if 0
	move.d	R_PORT_G_DATA,r1
	move.d	r0,[r1]; assert ATA bus-reset
	nop
	nop
	nop
	nop
	nop
	nop
	move.d	0x08000000,r0
	move.d	r0,[r1]
#endif
#endif

#ifdef CONFIG_JULIETTE
	;; configure external DMA channel 0 before enabling it in genconfig
	
	moveq	0,r0
	move.d	r0,[R_EXT_DMA_0_ADDR]
	move.d	0x860000,r0	; cnt enable, word size, output, stop, size 0
	move.d	r0,[R_EXT_DMA_0_CMD]

	;; reset dma4 and wait for completion
	
	moveq	4,r0
	move.b	r0,[R_DMA_CH4_CMD]
w4u:	move.b	[R_DMA_CH4_CMD],r0
	and.b	7,r0
	cmp.b	4,r0
	beq	w4u
	nop

	;; reset dma5 and wait for completion
	
	moveq	4,r0
	move.b	r0,[R_DMA_CH5_CMD]
w5u:	move.b	[R_DMA_CH5_CMD],r0
	and.b	7,r0
	cmp.b	4,r0
	beq	w5u
	nop
#endif	
			
	;; Etrax product HW genconfig setup

	moveq	0,r0
#if !defined(CONFIG_KGDB) && !defined(CONFIG_DMA_MEMCPY)
	or.d	0x140000,r0	; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA
#endif
#if !defined(CONFIG_KGDB) || !defined(CONFIG_DEBUG_PORT1)
	or.d	0xc00000,r0	; DMA channels 8 and 9 to ser1, kgdb doesnt want DMA
#endif
#ifdef CONFIG_DMA_MEMCPY
	or.d	0x003c0000,r0	; 6/7 memory-memory DMA
#endif
#ifdef CONFIG_ETRAX100_SERIAL_PORT2
	or.d	0x2808,r0	; DMA channels 2 and 3 to serport 2, port 2 enabled
#endif
#ifdef CONFIG_ETRAX100_SERIAL_PORT3
	or.d	0x28100,r0	; DMA channels 4 and 5 to serport 3, port 3 enabled
#endif
#if defined(CONFIG_ETRAX100_PARALLEL_PORT0) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE)
	or.w	0x4,r0	; parport 0 enabled using DMA 2/3
#endif
#if defined(CONFIG_ETRAX100_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE)
	or.w	0x80,r0	; parport 1 enabled using DMA 4/5
#endif
#ifdef CONFIG_BLK_DEV_ETRAXIDE
	or.d	0x3c02,r0	; DMA channels 2 and 3 to ATA, ATA enabled
#endif
#ifdef CONFIG_JULIETTE
	or.d	0x3c000,r0	; DMA channels 4 and 5 to EXTDMA0, for Juliette
#ifndef CONFIG_BLK_DEV_ETRAXIDE
	or.d	0x41,r0		; HACK for now! To make G27 connected for the RTC
#endif
#endif
	move.d	r0,[_genconfig_shadow] ; init a shadow register of R_GEN_CONFIG

#ifndef CONFIG_SVINTO_SIM
	move.d	r0,[R_GEN_CONFIG]

#if 0
	moveq	4,r0
	move.b	r0,[R_DMA_CH6_CMD]	; reset (ser0 dma out)
	move.b	r0,[R_DMA_CH7_CMD]	; reset (ser0 dma in)
w61:	move.b	[R_DMA_CH6_CMD],r0	; wait for reset cycle to finish
	and.b	7,r0
	cmp.b	4,r0
	beq	w61
	nop
w71:	move.b	[R_DMA_CH7_CMD],r0	; wait for reset cycle to finish
	and.b	7,r0
	cmp.b	4,r0
	beq	w71
	nop
#endif
	
	moveq	4,r0
	move.b	r0,[R_DMA_CH8_CMD]	; reset (ser1 dma out)
	move.b	r0,[R_DMA_CH9_CMD]	; reset (ser1 dma in)
w81:	move.b	[R_DMA_CH8_CMD],r0	; wait for reset cycle to finish
	and.b	7,r0
	cmp.b	4,r0
	beq	w81
	nop
w91:	move.b	[R_DMA_CH9_CMD],r0	; wait for reset cycle to finish
	and.b	7,r0
	cmp.b	4,r0
	beq	w91
	nop

	;; setup port PA and PB default initial directions and data
	;; including their shadow registers
		
	move.b	DEF_R_PORT_PA_DIR,r0
	move.b	r0,[_port_pa_dir_shadow]
	move.b	r0,[R_PORT_PA_DIR]
	move.b	DEF_R_PORT_PA_DATA,r0
	move.b	r0,[_port_pa_data_shadow]
	move.b	r0,[R_PORT_PA_DATA]
	
	move.b	DEF_R_PORT_PB_CONFIG,r0
	move.b	r0,[_port_pb_config_shadow]
	move.b	r0,[R_PORT_PB_CONFIG]
	move.b	DEF_R_PORT_PB_DIR,r0
	move.b	r0,[_port_pb_dir_shadow]
	move.b	r0,[R_PORT_PB_DIR]
	move.b	DEF_R_PORT_PB_DATA,r0
	move.b	r0,[_port_pb_data_shadow]
	move.b	r0,[R_PORT_PB_DATA]

	moveq	0,r0
	move.d	r0,[_port_g_data_shadow]
	move.d	r0,[R_PORT_G_DATA]
	
	;; setup the serial port 0 at 115200 baud for debug purposes
	
	moveq	0,r0
	move.d	r0,[R_SERIAL0_XOFF] 

	move.b	0x99,r0
	move.b	r0,[R_SERIAL0_BAUD]	; 115.2kbaud for both transmit and receive

	move.b	0x40,r0			; rec enable
	move.b	r0,[R_SERIAL0_REC_CTRL] 
	
	move.b	0x40,r0			; tr enable
	move.b	r0,[R_SERIAL0_TR_CTRL]

	;; setup the serial port 1 at 115200 baud for debug purposes
	
	moveq	0,r0
	move.d	r0,[R_SERIAL1_XOFF] 

	move.b	0x99,r0
	move.b	r0,[R_SERIAL1_BAUD]	; 115.2kbaud for both transmit and receive

	move.b	0x40,r0			; rec enable
	move.b	r0,[R_SERIAL1_REC_CTRL] 
	
	move.b	0x40,r0			; tr enable
	move.b	r0,[R_SERIAL1_TR_CTRL]

#ifdef CONFIG_ETRAX_90000000_LEDS
	;; clear LED's on Stallone and Olga boards
	moveq	-1,r0
	move.d	r0,[_port_90000000_shadow]
	move.d	r0,[0x90000000]
#endif
	
#ifdef CONFIG_ETRAX100_SERIAL_PORT3	
	;; setup the serial port 3 at 115200 baud for debug purposes
	
	moveq	0,r0
	move.d	r0,[R_SERIAL3_XOFF] 

	move.b	0x99,r0
	move.b	r0,[R_SERIAL3_BAUD]	; 115.2kbaud for both transmit and receive

	move.b	0x40,r0			; rec enable
	move.b	r0,[R_SERIAL3_REC_CTRL] 
	
	move.b	0x40,r0			; tr enable
	move.b	r0,[R_SERIAL3_TR_CTRL]
#endif
	
#endif /* CONFIG_SVINTO_SIM */

	jump	_start_kernel	; jump into the C-function _start_kernel in init/main.c

	
	.data
_etrax_irv:	
	.dword	0
_romfs_start:
	.dword	0
_romfs_length:
	.dword	0
_romfs_in_flash:
	.dword	0

	;; put some special pages at the beginning of the kernel aligned
	;; to page boundaries - the kernel cannot start until after this

#ifdef CONFIG_CRIS_LOW_MAP
_swapper_pg_dir = 0x60002000
#else	
_swapper_pg_dir = 0xc0002000
#endif