summaryrefslogtreecommitdiffstats
path: root/arch/cris/arch-v10/kernel/head.S
blob: b260a8833903b89cb48dc77df0b660a649dd35a6 (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
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Head of the kernel - alter with care
 *
 * Copyright (C) 2000, 2001, 2010 Axis Communications AB
 *
 */

#include <linux/init.h>

#define ASSEMBLER_MACROS_ONLY
/* The IO_* macros use the ## token concatenation operator, so
   -traditional must not be used when assembling this file.  */
#include <arch/sv_addr_ag.h>

#define CRAMFS_MAGIC 0x28cd3d45
#define RAM_INIT_MAGIC 0x56902387
#define COMMAND_LINE_MAGIC 0x87109563

#define START_ETHERNET_CLOCK IO_STATE(R_NETWORK_GEN_CONFIG, enable, on) |\
                             IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk)

	;; exported symbols

	.globl	etrax_irv
	.globl	romfs_start
	.globl	romfs_length
	.globl	romfs_in_flash
	.globl  swapper_pg_dir

	__HEAD

	;; 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 registers r8 and r9 are used as parameters carrying
	;; information from the decompressor (if the kernel was compressed).
	;; They should not be used in the code below until 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.  The bug is that you can't remap bit 31 of
	;; an address.  Though we can check the version register for
	;; whether the bug is present, some constants would then have to
	;; be variables, so we don't.  The drawback is that you can "only" map
	;; 1G per process with CONFIG_CRIS_LOW_MAP.

#ifdef CONFIG_CRIS_LOW_MAP
	; kseg mappings, temporary map of 0xc0->0x40
	move.d	  IO_FIELD (R_MMU_KBASE_HI, base_c, 4)		\
		| IO_FIELD (R_MMU_KBASE_HI, base_b, 0xb)	\
		| IO_FIELD (R_MMU_KBASE_HI, base_9, 9)		\
		| IO_FIELD (R_MMU_KBASE_HI, base_8, 8), $r0
	move.d	$r0, [R_MMU_KBASE_HI]

	; temporary map of 0x40->0x40 and 0x60->0x40
	move.d	  IO_FIELD (R_MMU_KBASE_LO, base_6, 4)		\
		| IO_FIELD (R_MMU_KBASE_LO, base_4, 4), $r0
	move.d	$r0, [R_MMU_KBASE_LO]

	; mmu enable, segs e,c,b,a,6,5,4,0 segment mapped
	move.d	  IO_STATE (R_MMU_CONFIG, mmu_enable, enable)	\
		| IO_STATE (R_MMU_CONFIG, inv_excp, enable)	\
		| IO_STATE (R_MMU_CONFIG, acc_excp, enable)	\
		| IO_STATE (R_MMU_CONFIG, we_excp, enable)	\
		| IO_STATE (R_MMU_CONFIG, seg_f, page)		\
		| IO_STATE (R_MMU_CONFIG, seg_e, seg)		\
		| IO_STATE (R_MMU_CONFIG, seg_d, page)		\
		| IO_STATE (R_MMU_CONFIG, seg_c, seg)		\
		| IO_STATE (R_MMU_CONFIG, seg_b, seg)		\
		| IO_STATE (R_MMU_CONFIG, seg_a, seg)		\
		| IO_STATE (R_MMU_CONFIG, seg_9, page)		\
		| IO_STATE (R_MMU_CONFIG, seg_8, page)		\
		| IO_STATE (R_MMU_CONFIG, seg_7, page)		\
		| IO_STATE (R_MMU_CONFIG, seg_6, seg)		\
		| IO_STATE (R_MMU_CONFIG, seg_5, seg)		\
		| IO_STATE (R_MMU_CONFIG, seg_4, seg)		\
		| IO_STATE (R_MMU_CONFIG, seg_3, page)		\
		| IO_STATE (R_MMU_CONFIG, seg_2, page)		\
		| IO_STATE (R_MMU_CONFIG, seg_1, page)		\
		| IO_STATE (R_MMU_CONFIG, seg_0, seg), $r0
	move.d	$r0, [R_MMU_CONFIG]
#else
	; kseg mappings
	move.d	  IO_FIELD (R_MMU_KBASE_HI, base_e, 8)		\
		| IO_FIELD (R_MMU_KBASE_HI, base_c, 4)		\
		| IO_FIELD (R_MMU_KBASE_HI, base_b, 0xb), $r0
	move.d	$r0, [R_MMU_KBASE_HI]

	; temporary map of 0x40->0x40 and 0x00->0x00
	move.d	  IO_FIELD (R_MMU_KBASE_LO, base_4, 4), $r0
	move.d	$r0, [R_MMU_KBASE_LO]

	; mmu enable, segs f,e,c,b,4,0 segment mapped
	move.d	  IO_STATE (R_MMU_CONFIG, mmu_enable, enable)	\
		| IO_STATE (R_MMU_CONFIG, inv_excp, enable)	\
		| IO_STATE (R_MMU_CONFIG, acc_excp, enable)	\
		| IO_STATE (R_MMU_CONFIG, we_excp, enable)	\
		| IO_STATE (R_MMU_CONFIG, seg_f, seg)		\
		| IO_STATE (R_MMU_CONFIG, seg_e, seg)		\
		| IO_STATE (R_MMU_CONFIG, seg_d, page)		\
		| IO_STATE (R_MMU_CONFIG, seg_c, seg)		\
		| IO_STATE (R_MMU_CONFIG, seg_b, seg)		\
		| IO_STATE (R_MMU_CONFIG, seg_a, page)		\
		| IO_STATE (R_MMU_CONFIG, seg_9, page)		\
		| IO_STATE (R_MMU_CONFIG, seg_8, page)		\
		| IO_STATE (R_MMU_CONFIG, seg_7, page)		\
		| IO_STATE (R_MMU_CONFIG, seg_6, page)		\
		| IO_STATE (R_MMU_CONFIG, seg_5, page)		\
		| IO_STATE (R_MMU_CONFIG, seg_4, seg)		\
		| IO_STATE (R_MMU_CONFIG, seg_3, page)		\
		| IO_STATE (R_MMU_CONFIG, seg_2, page)		\
		| IO_STATE (R_MMU_CONFIG, seg_1, page)		\
		| IO_STATE (R_MMU_CONFIG, seg_0, seg), $r0
	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
	blo	_inflash0
	nop

	jump	_inram		; enter cached ram

	;; Jumpgate for branches.
_inflash0:
	jump	_inflash

	;; Put this in a suitable section where we can reclaim storage
	;; after init.
	__INIT
_inflash:
#ifdef CONFIG_ETRAX_ETHERNET
	;; Start MII clock to make sure it is running when tranceiver is reset
	move.d START_ETHERNET_CLOCK, $r0
	move.d $r0, [R_NETWORK_GEN_CONFIG]
#endif

	;; Set up waitstates etc according to kernel configuration.
	move.d   CONFIG_ETRAX_DEF_R_WAITSTATES, $r0
	move.d   $r0, [R_WAITSTATES]

	move.d   CONFIG_ETRAX_DEF_R_BUS_CONFIG, $r0
	move.d   $r0, [R_BUS_CONFIG]

	;; We need to initialze DRAM registers before we start using the DRAM

	cmp.d	RAM_INIT_MAGIC, $r8	; Already initialized?
	beq	_dram_init_finished
	nop

#include "../lib/dram_init.S"

_dram_init_finished:
	;; 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
	blo	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

	;; The kernel could have been unpacked to DRAM by the loader, but
	;; the cramfs image could still be 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
	bhs	_no_romfs_in_flash	; r9 points outside the flash area
	nop
	move.d	[$r9], $r0	; cramfs_super.magic
	cmp.d	CRAMFS_MAGIC, $r0
	bne	_no_romfs_in_flash
	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]

	jump	_start_it	; enter code, cached this time

_no_romfs_in_flash:

	;; 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	__init_end, $r0; the image will be after the end of init
	move.d	[$r0], $r1	; cramfs assumes same endian on host/target
	cmp.d	CRAMFS_MAGIC, $r1; magic value in cramfs superblock
	bne	2f
	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

2:
	;; 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

_start_it:

	;; Check if kernel command line is supplied
	cmp.d	COMMAND_LINE_MAGIC, $r10
	bne	no_command_line
	nop

	move.d	256, $r13
	move.d  cris_command_line, $r10
	or.d	0x80000000, $r11 ; Make it virtual
1:
	move.b  [$r11+], $r12
	move.b  $r12, [$r10+]
	subq	1, $r13
	bne	1b
	nop

no_command_line:

	;; 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_thread_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
	blo	1b
	nop

	;; Etrax product HW genconfig setup

	moveq	0,$r0

	;; Select or disable serial port 2
#ifdef CONFIG_ETRAX_SERIAL_PORT2
	or.d	  IO_STATE (R_GEN_CONFIG, ser2, select),$r0
#else
	or.d	  IO_STATE (R_GEN_CONFIG, ser2, disable),$r0
#endif

	;; Init interfaces (disable them).
	or.d	  IO_STATE (R_GEN_CONFIG, scsi0, disable) \
		| IO_STATE (R_GEN_CONFIG, ata, disable) \
		| IO_STATE (R_GEN_CONFIG, par0, disable) \
		| IO_STATE (R_GEN_CONFIG, mio, disable) \
		| IO_STATE (R_GEN_CONFIG, scsi1, disable) \
		| IO_STATE (R_GEN_CONFIG, scsi0w, disable) \
		| IO_STATE (R_GEN_CONFIG, par1, disable) \
		| IO_STATE (R_GEN_CONFIG, ser3, disable) \
		| IO_STATE (R_GEN_CONFIG, mio_w, disable) \
		| IO_STATE (R_GEN_CONFIG, usb1, disable) \
		| IO_STATE (R_GEN_CONFIG, usb2, disable) \
		| IO_STATE (R_GEN_CONFIG, par_w, disable),$r0

	;; Init DMA channel muxing (set to unused clients).
	or.d	  IO_STATE (R_GEN_CONFIG, dma2, ata)	\
		| IO_STATE (R_GEN_CONFIG, dma3, ata) \
		| IO_STATE (R_GEN_CONFIG, dma4, scsi1) \
		| IO_STATE (R_GEN_CONFIG, dma5, scsi1) \
		| IO_STATE (R_GEN_CONFIG, dma6, unused) \
		| IO_STATE (R_GEN_CONFIG, dma7, unused) \
		| IO_STATE (R_GEN_CONFIG, dma8, usb) \
		| IO_STATE (R_GEN_CONFIG, dma9, usb),$r0


	move.d	$r0,[genconfig_shadow] ; init a shadow register of R_GEN_CONFIG

	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)
1:	move.b	[R_DMA_CH6_CMD],$r0	; wait for reset cycle to finish
	and.b	7,$r0
	cmp.b	4,$r0
	beq	1b
	nop
1:	move.b	[R_DMA_CH7_CMD],$r0	; wait for reset cycle to finish
	and.b	7,$r0
	cmp.b	4,$r0
	beq	1b
	nop
#endif

	moveq	IO_STATE (R_DMA_CH8_CMD, cmd, reset),$r0
	move.b	$r0,[R_DMA_CH8_CMD]	; reset (ser1 dma out)
	move.b	$r0,[R_DMA_CH9_CMD]	; reset (ser1 dma in)
1:	move.b	[R_DMA_CH8_CMD],$r0	; wait for reset cycle to finish
	andq	IO_MASK (R_DMA_CH8_CMD, cmd),$r0
	cmpq	IO_STATE (R_DMA_CH8_CMD, cmd, reset),$r0
	beq	1b
	nop
1:	move.b	[R_DMA_CH9_CMD],$r0	; wait for reset cycle to finish
	andq	IO_MASK (R_DMA_CH9_CMD, cmd),$r0
	cmpq	IO_STATE (R_DMA_CH9_CMD, cmd, reset),$r0
	beq	1b
	nop

	;; setup port PA and PB default initial directions and data
	;; including their shadow registers

	move.b	CONFIG_ETRAX_DEF_R_PORT_PA_DIR,$r0
	move.b	$r0,[port_pa_dir_shadow]
	move.b	$r0,[R_PORT_PA_DIR]
	move.b	CONFIG_ETRAX_DEF_R_PORT_PA_DATA,$r0
	move.b	$r0,[port_pa_data_shadow]
	move.b	$r0,[R_PORT_PA_DATA]

	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG,$r0
	move.b	$r0,[port_pb_config_shadow]
	move.b	$r0,[R_PORT_PB_CONFIG]
	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_DIR,$r0
	move.b	$r0,[port_pb_dir_shadow]
	move.b	$r0,[R_PORT_PB_DIR]
	move.b	CONFIG_ETRAX_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_pb_i2c_shadow]
	move.d  $r0, [R_PORT_PB_I2C]

	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	  IO_STATE (R_SERIAL0_XOFF, tx_stop, enable)		\
		| IO_STATE (R_SERIAL0_XOFF, auto_xoff, disable)		\
		| IO_FIELD (R_SERIAL0_XOFF, xoff_char, 0),$r0
	move.d	$r0,[R_SERIAL0_XOFF]

	; 115.2kbaud for both transmit and receive
	move.b	  IO_STATE (R_SERIAL0_BAUD, tr_baud, c115k2Hz)		\
		| IO_STATE (R_SERIAL0_BAUD, rec_baud, c115k2Hz),$r0
	move.b	$r0,[R_SERIAL0_BAUD]

	; Set up and enable the serial0 receiver.
	move.b	  IO_STATE (R_SERIAL0_REC_CTRL, dma_err, stop)		\
		| IO_STATE (R_SERIAL0_REC_CTRL, rec_enable, enable)	\
		| IO_STATE (R_SERIAL0_REC_CTRL, rts_, active)		\
		| IO_STATE (R_SERIAL0_REC_CTRL, sampling, middle)	\
		| IO_STATE (R_SERIAL0_REC_CTRL, rec_stick_par, normal)	\
		| IO_STATE (R_SERIAL0_REC_CTRL, rec_par, even)		\
		| IO_STATE (R_SERIAL0_REC_CTRL, rec_par_en, disable)	\
		| IO_STATE (R_SERIAL0_REC_CTRL, rec_bitnr, rec_8bit),$r0
	move.b	$r0,[R_SERIAL0_REC_CTRL]

	; Set up and enable the serial0 transmitter.
	move.b	  IO_FIELD (R_SERIAL0_TR_CTRL, txd, 0)			\
		| IO_STATE (R_SERIAL0_TR_CTRL, tr_enable, enable)	\
		| IO_STATE (R_SERIAL0_TR_CTRL, auto_cts, disabled)	\
		| IO_STATE (R_SERIAL0_TR_CTRL, stop_bits, one_bit)	\
		| IO_STATE (R_SERIAL0_TR_CTRL, tr_stick_par, normal)	\
		| IO_STATE (R_SERIAL0_TR_CTRL, tr_par, even)		\
		| IO_STATE (R_SERIAL0_TR_CTRL, tr_par_en, disable)	\
		| IO_STATE (R_SERIAL0_TR_CTRL, tr_bitnr, tr_8bit),$r0
	move.b	$r0,[R_SERIAL0_TR_CTRL]

	;; setup the serial port 1 at 115200 baud for debug purposes

	moveq	  IO_STATE (R_SERIAL1_XOFF, tx_stop, enable)		\
		| IO_STATE (R_SERIAL1_XOFF, auto_xoff, disable)		\
		| IO_FIELD (R_SERIAL1_XOFF, xoff_char, 0),$r0
	move.d	$r0,[R_SERIAL1_XOFF]

	; 115.2kbaud for both transmit and receive
	move.b	  IO_STATE (R_SERIAL1_BAUD, tr_baud, c115k2Hz)		\
		| IO_STATE (R_SERIAL1_BAUD, rec_baud, c115k2Hz),$r0
	move.b	$r0,[R_SERIAL1_BAUD]

	; Set up and enable the serial1 receiver.
	move.b	  IO_STATE (R_SERIAL1_REC_CTRL, dma_err, stop)		\
		| IO_STATE (R_SERIAL1_REC_CTRL, rec_enable, enable)	\
		| IO_STATE (R_SERIAL1_REC_CTRL, rts_, active)		\
		| IO_STATE (R_SERIAL1_REC_CTRL, sampling, middle)	\
		| IO_STATE (R_SERIAL1_REC_CTRL, rec_stick_par, normal)	\
		| IO_STATE (R_SERIAL1_REC_CTRL, rec_par, even)		\
		| IO_STATE (R_SERIAL1_REC_CTRL, rec_par_en, disable)	\
		| IO_STATE (R_SERIAL1_REC_CTRL, rec_bitnr, rec_8bit),$r0
	move.b	$r0,[R_SERIAL1_REC_CTRL]

	; Set up and enable the serial1 transmitter.
	move.b	  IO_FIELD (R_SERIAL1_TR_CTRL, txd, 0)			\
		| IO_STATE (R_SERIAL1_TR_CTRL, tr_enable, enable)	\
		| IO_STATE (R_SERIAL1_TR_CTRL, auto_cts, disabled)	\
		| IO_STATE (R_SERIAL1_TR_CTRL, stop_bits, one_bit)	\
		| IO_STATE (R_SERIAL1_TR_CTRL, tr_stick_par, normal)	\
		| IO_STATE (R_SERIAL1_TR_CTRL, tr_par, even)		\
		| IO_STATE (R_SERIAL1_TR_CTRL, tr_par_en, disable)	\
		| IO_STATE (R_SERIAL1_TR_CTRL, tr_bitnr, tr_8bit),$r0
	move.b	$r0,[R_SERIAL1_TR_CTRL]

#ifdef CONFIG_ETRAX_SERIAL_PORT2
	;; setup the serial port 2 at 115200 baud for debug purposes

	moveq	  IO_STATE (R_SERIAL2_XOFF, tx_stop, enable)		\
		| IO_STATE (R_SERIAL2_XOFF, auto_xoff, disable)		\
		| IO_FIELD (R_SERIAL2_XOFF, xoff_char, 0),$r0
	move.d	$r0,[R_SERIAL2_XOFF]

	; 115.2kbaud for both transmit and receive
	move.b	  IO_STATE (R_SERIAL2_BAUD, tr_baud, c115k2Hz)		\
		| IO_STATE (R_SERIAL2_BAUD, rec_baud, c115k2Hz),$r0
	move.b	$r0,[R_SERIAL2_BAUD]

	; Set up and enable the serial2 receiver.
	move.b	  IO_STATE (R_SERIAL2_REC_CTRL, dma_err, stop)		\
		| IO_STATE (R_SERIAL2_REC_CTRL, rec_enable, enable)	\
		| IO_STATE (R_SERIAL2_REC_CTRL, rts_, active)		\
		| IO_STATE (R_SERIAL2_REC_CTRL, sampling, middle)	\
		| IO_STATE (R_SERIAL2_REC_CTRL, rec_stick_par, normal)	\
		| IO_STATE (R_SERIAL2_REC_CTRL, rec_par, even)		\
		| IO_STATE (R_SERIAL2_REC_CTRL, rec_par_en, disable)	\
		| IO_STATE (R_SERIAL2_REC_CTRL, rec_bitnr, rec_8bit),$r0
	move.b	$r0,[R_SERIAL2_REC_CTRL]

	; Set up and enable the serial2 transmitter.
	move.b	  IO_FIELD (R_SERIAL2_TR_CTRL, txd, 0)			\
		| IO_STATE (R_SERIAL2_TR_CTRL, tr_enable, enable)	\
		| IO_STATE (R_SERIAL2_TR_CTRL, auto_cts, disabled)	\
		| IO_STATE (R_SERIAL2_TR_CTRL, stop_bits, one_bit)	\
		| IO_STATE (R_SERIAL2_TR_CTRL, tr_stick_par, normal)	\
		| IO_STATE (R_SERIAL2_TR_CTRL, tr_par, even)		\
		| IO_STATE (R_SERIAL2_TR_CTRL, tr_par_en, disable)	\
		| IO_STATE (R_SERIAL2_TR_CTRL, tr_bitnr, tr_8bit),$r0
	move.b	$r0,[R_SERIAL2_TR_CTRL]
#endif

#ifdef CONFIG_ETRAX_SERIAL_PORT3
	;; setup the serial port 3 at 115200 baud for debug purposes

	moveq	  IO_STATE (R_SERIAL3_XOFF, tx_stop, enable)		\
		| IO_STATE (R_SERIAL3_XOFF, auto_xoff, disable)		\
		| IO_FIELD (R_SERIAL3_XOFF, xoff_char, 0),$r0
	move.d	$r0,[R_SERIAL3_XOFF]

	; 115.2kbaud for both transmit and receive
	move.b	  IO_STATE (R_SERIAL3_BAUD, tr_baud, c115k2Hz)		\
		| IO_STATE (R_SERIAL3_BAUD, rec_baud, c115k2Hz),$r0
	move.b	$r0,[R_SERIAL3_BAUD]

	; Set up and enable the serial3 receiver.
	move.b	  IO_STATE (R_SERIAL3_REC_CTRL, dma_err, stop)		\
		| IO_STATE (R_SERIAL3_REC_CTRL, rec_enable, enable)	\
		| IO_STATE (R_SERIAL3_REC_CTRL, rts_, active)		\
		| IO_STATE (R_SERIAL3_REC_CTRL, sampling, middle)	\
		| IO_STATE (R_SERIAL3_REC_CTRL, rec_stick_par, normal)	\
		| IO_STATE (R_SERIAL3_REC_CTRL, rec_par, even)		\
		| IO_STATE (R_SERIAL3_REC_CTRL, rec_par_en, disable)	\
		| IO_STATE (R_SERIAL3_REC_CTRL, rec_bitnr, rec_8bit),$r0
	move.b	$r0,[R_SERIAL3_REC_CTRL]

	; Set up and enable the serial3 transmitter.
	move.b	  IO_FIELD (R_SERIAL3_TR_CTRL, txd, 0)			\
		| IO_STATE (R_SERIAL3_TR_CTRL, tr_enable, enable)	\
		| IO_STATE (R_SERIAL3_TR_CTRL, auto_cts, disabled)	\
		| IO_STATE (R_SERIAL3_TR_CTRL, stop_bits, one_bit)	\
		| IO_STATE (R_SERIAL3_TR_CTRL, tr_stick_par, normal)	\
		| IO_STATE (R_SERIAL3_TR_CTRL, tr_par, even)		\
		| IO_STATE (R_SERIAL3_TR_CTRL, tr_par_en, disable)	\
		| IO_STATE (R_SERIAL3_TR_CTRL, tr_bitnr, tr_8bit),$r0
	move.b	$r0,[R_SERIAL3_TR_CTRL]
#endif

	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

	.section ".init.data", "aw"
#include "../lib/hw_settings.S"