Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/arch/cris/arch-v10/Kconfig b/arch/cris/arch-v10/Kconfig
new file mode 100644
index 0000000..2ca64cc
--- /dev/null
+++ b/arch/cris/arch-v10/Kconfig
@@ -0,0 +1,422 @@
+# ETRAX 100LX v1 has a MMU "feature" requiring a low mapping
+config CRIS_LOW_MAP
+	bool
+	depends on ETRAX_ARCH_V10 && ETRAX100LX
+	default y
+
+config ETRAX_DRAM_VIRTUAL_BASE
+	hex
+	depends on ETRAX_ARCH_V10
+	default "c0000000" if !ETRAX100LX
+	default "60000000" if ETRAX100LX
+
+choice
+	prompt "Product LED port"
+	depends on ETRAX_ARCH_V10
+	default ETRAX_PA_LEDS
+
+config ETRAX_PA_LEDS
+	bool "Port-PA-LEDs"
+	help
+	  The ETRAX network driver is responsible for flashing LED's when
+	  packets arrive and are sent.  It uses macros defined in
+	  <file:include/asm-cris/io.h>, and those macros are defined after what
+	  YOU choose in this option.  The actual bits used are configured
+	  separately.  Select this if the LEDs are on port PA.  Some products
+	  put the leds on PB or a memory-mapped latch (CSP0) instead.
+
+config ETRAX_PB_LEDS
+	bool "Port-PB-LEDs"
+	help
+	  The ETRAX network driver is responsible for flashing LED's when
+	  packets arrive and are sent.  It uses macros defined in
+	  <file:include/asm-cris/io.h>, and those macros are defined after what
+	  YOU choose in this option.  The actual bits used are configured
+	  separately.  Select this if the LEDs are on port PB.  Some products
+	  put the leds on PA or a memory-mapped latch (CSP0) instead.
+
+config ETRAX_CSP0_LEDS
+	bool "Port-CSP0-LEDs"
+	help
+	  The ETRAX network driver is responsible for flashing LED's when
+	  packets arrive and are sent. It uses macros defined in
+	  <file:include/asm-cris/io.h>, and those macros are defined after what
+	  YOU choose in this option.  The actual bits used are configured
+	  separately.  Select this if the LEDs are on a memory-mapped latch
+	  using chip select CSP0, this is mapped at 0x90000000.
+	  Some products put the leds on PA or PB instead.
+
+config ETRAX_NO_LEDS
+	bool "None"
+	help
+	  Select this option if you don't have any LED at all.
+
+endchoice
+
+config ETRAX_LED1G
+	int "First green LED bit"
+	depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS
+	default "2"
+	help
+	  Bit to use for the first green LED.
+	  Most Axis products use bit 2 here.
+
+config ETRAX_LED1R
+	int "First red LED bit"
+	depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS
+	default "3"
+	help
+	  Bit to use for the first red LED.
+	  Most Axis products use bit 3 here.
+	  For products with only one controllable LED,
+	  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+config ETRAX_LED2G
+	int "Second green LED bit"
+	depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS
+	default "4"
+	help
+	  Bit to use for the second green LED. The "Active" LED.
+	  Most Axis products use bit 4 here.
+	  For products with only one controllable LED,
+	  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+config ETRAX_LED2R
+	int "Second red LED bit"
+	depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS
+	default "5"
+	help
+	  Bit to use for the second red LED.
+	  Most Axis products use bit 5 here.
+	  For products with only one controllable LED,
+	  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+config ETRAX_LED3G
+	int "Third green LED bit"
+	depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS
+	default "2"
+	help
+	  Bit to use for the third green LED. The "Drive" LED.
+	  For products with only one or two controllable LEDs,
+	  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+config ETRAX_LED3R
+	int "Third red LED bit"
+	depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS
+	default "2"
+	help
+	  Bit to use for the third red LED.
+	  For products with only one or two controllable LEDs,
+	  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+config ETRAX_LED4R
+	int "Fourth red LED bit"
+	depends on ETRAX_CSP0_LEDS
+	default "2"
+	help
+	  Bit to use for the fourth red LED.
+	  For products with only one or two controllable LEDs,
+	  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+config ETRAX_LED4G
+	int "Fourth green LED bit"
+	depends on ETRAX_CSP0_LEDS
+	default "2"
+	help
+	  Bit to use for the fourth green LED.
+	  For products with only one or two controllable LEDs,
+	  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+config ETRAX_LED5R
+	int "Fifth red LED bit"
+	depends on ETRAX_CSP0_LEDS
+	default "2"
+	help
+	  Bit to use for the fifth red LED.
+	  For products with only one or two controllable LEDs,
+	  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+config ETRAX_LED5G
+	int "Fifth green LED bit"
+	depends on ETRAX_CSP0_LEDS
+	default "2"
+	help
+	  Bit to use for the fifth green LED.
+	  For products with only one or two controllable LEDs,
+	  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+config ETRAX_LED6R
+	int "Sixth red LED bit"
+	depends on ETRAX_CSP0_LEDS
+	default "2"
+	help
+	  Bit to use for the sixth red LED.
+	  For products with only one or two controllable LEDs,
+	  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+config ETRAX_LED6G
+	int "Sixth green LED bit"
+	depends on ETRAX_CSP0_LEDS
+	default "2"
+	help
+	  Bit to use for the sixth green LED. The "Drive" LED.
+	  For products with only one or two controllable LEDs,
+	  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+config ETRAX_LED7R
+	int "Seventh red LED bit"
+	depends on ETRAX_CSP0_LEDS
+	default "2"
+	help
+	  Bit to use for the seventh red LED.
+	  For products with only one or two controllable LEDs,
+	  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+config ETRAX_LED7G
+	int "Seventh green LED bit"
+	depends on ETRAX_CSP0_LEDS
+	default "2"
+	help
+	  Bit to use for the seventh green LED.
+	  For products with only one or two controllable LEDs,
+	  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+config ETRAX_LED8Y
+	int "Eigth yellow LED bit"
+	depends on ETRAX_CSP0_LEDS
+	default "2"
+	help
+	  Bit to use for the eighth yellow LED. The "Drive" LED.
+	  For products with only one or two controllable LEDs,
+	  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+config ETRAX_LED9Y
+	int "Ninth yellow LED bit"
+	depends on ETRAX_CSP0_LEDS
+	default "2"
+	help
+	  Bit to use for the ninth yellow LED.
+	  For products with only one or two controllable LEDs,
+	  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+config ETRAX_LED10Y
+	int "Tenth yellow LED bit"
+	depends on ETRAX_CSP0_LEDS
+	default "2"
+	help
+	  Bit to use for the tenth yellow LED.
+	  For products with only one or two controllable LEDs,
+	  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+config ETRAX_LED11Y
+	int "Eleventh yellow LED bit"
+	depends on ETRAX_CSP0_LEDS
+	default "2"
+	help
+	  Bit to use for the eleventh yellow LED.
+	  For products with only one or two controllable LEDs,
+	  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+config ETRAX_LED12R
+	int "Twelfth red LED bit"
+	depends on ETRAX_CSP0_LEDS
+	default "2"
+	help
+	  Bit to use for the twelfth red LED.
+	  For products with only one or two controllable LEDs,
+	  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+choice
+	prompt "Product debug-port"
+	depends on ETRAX_ARCH_V10
+	default ETRAX_DEBUG_PORT0
+
+config ETRAX_DEBUG_PORT0
+	bool "Serial-0"
+	help
+	  Choose a serial port for the ETRAX debug console.  Default to
+	  port 0.
+
+config ETRAX_DEBUG_PORT1
+	bool "Serial-1"
+	help
+	  Use serial port 1 for the console.
+
+config ETRAX_DEBUG_PORT2
+	bool "Serial-2"
+	help
+	  Use serial port 2 for the console.
+
+config ETRAX_DEBUG_PORT3
+	bool "Serial-3"
+	help
+	  Use serial port 3 for the console.
+
+config ETRAX_DEBUG_PORT_NULL
+	bool "disabled"
+	help
+	  Disable serial-port debugging.
+
+endchoice
+
+choice
+	prompt "Product rescue-port"
+	depends on ETRAX_ARCH_V10
+	default ETRAX_RESCUE_SER0
+
+config ETRAX_RESCUE_SER0
+	bool "Serial-0"
+	help
+	  Select one of the four serial ports as a rescue port.  The default
+	  is port 0.
+
+config ETRAX_RESCUE_SER1
+	bool "Serial-1"
+	help
+	  Use serial port 1 as the rescue port.
+
+config ETRAX_RESCUE_SER2
+	bool "Serial-2"
+	help
+	  Use serial port 2 as the rescue port.
+
+config ETRAX_RESCUE_SER3
+	bool "Serial-3"
+	help
+	  Use serial port 3 as the rescue port.
+
+endchoice
+
+config ETRAX_DEF_R_WAITSTATES
+	hex "R_WAITSTATES"
+	depends on ETRAX_ARCH_V10
+	default "95a6"
+	help
+	  Waitstates for SRAM, Flash and peripherials (not DRAM).  95f8 is a
+	  good choice for most Axis products...
+
+config ETRAX_DEF_R_BUS_CONFIG
+	hex "R_BUS_CONFIG"
+	depends on ETRAX_ARCH_V10
+	default "104"
+	help
+	  Assorted bits controlling write mode, DMA burst length etc.  104 is
+	  a good choice for most Axis products...
+
+config ETRAX_SDRAM
+	bool "SDRAM support"
+	depends on ETRAX_ARCH_V10
+	help
+	  Enable this if you use SDRAM chips and configure
+	  R_SDRAM_CONFIG and R_SDRAM_TIMING as well.
+
+config ETRAX_DEF_R_DRAM_CONFIG
+	hex "R_DRAM_CONFIG"
+	depends on ETRAX_ARCH_V10 && !ETRAX_SDRAM
+	default "1a200040"
+	help
+	  The R_DRAM_CONFIG register specifies everything on how the DRAM
+	  chips in the system are connected to the ETRAX CPU.  This is
+	  different depending on the manufacturer, chip type and number of
+	  chips.  So this value often needs to be different for each Axis
+	  product.
+
+config ETRAX_DEF_R_DRAM_TIMING
+	hex "R_DRAM_TIMING"
+	depends on ETRAX_ARCH_V10 && !ETRAX_SDRAM
+	default "5611"
+	help
+	  Different DRAM chips have different speeds.  Current Axis products
+	  use 50ns DRAM chips which can use the timing: 5611.
+
+config ETRAX_DEF_R_SDRAM_CONFIG
+	hex "R_SDRAM_CONFIG"
+	depends on ETRAX_ARCH_V10 && ETRAX_SDRAM
+	default "d2fa7878"
+	help
+	  The R_SDRAM_CONFIG register specifies everything on how the SDRAM
+	  chips in the system are connected to the ETRAX CPU.  This is
+	  different depending on the manufacturer, chip type and number of
+	  chips.  So this value often needs to be different for each Axis
+	  product.
+
+config ETRAX_DEF_R_SDRAM_TIMING
+	hex "R_SDRAM_TIMING"
+	depends on ETRAX_ARCH_V10 && ETRAX_SDRAM
+	default "80004801"
+	help
+	  Different SDRAM chips have different timing.
+
+config ETRAX_DEF_R_PORT_PA_DIR
+	hex "R_PORT_PA_DIR"
+	depends on ETRAX_ARCH_V10
+	default "1c"
+	help
+	  Configures the direction of general port A bits.  1 is out, 0 is in.
+	  This is often totally different depending on the product used.
+	  There are some guidelines though - if you know that only LED's are
+	  connected to port PA, then they are usually connected to bits 2-4
+	  and you can therefore use 1c.  On other boards which don't have the
+	  LED's at the general ports, these bits are used for all kinds of
+	  stuff.  If you don't know what to use, it is always safe to put all
+	  as inputs, although floating inputs isn't good.
+
+config ETRAX_DEF_R_PORT_PA_DATA
+	hex "R_PORT_PA_DATA"
+	depends on ETRAX_ARCH_V10
+	default "00"
+	help
+	  Configures the initial data for the general port A bits.  Most
+	  products should use 00 here.
+
+config ETRAX_DEF_R_PORT_PB_CONFIG
+	hex "R_PORT_PB_CONFIG"
+	depends on ETRAX_ARCH_V10
+	default "00"
+	help
+	  Configures the type of the general port B bits.  1 is chip select,
+	  0 is port.  Most products should use 00 here.
+
+config ETRAX_DEF_R_PORT_PB_DIR
+	hex "R_PORT_PB_DIR"
+	depends on ETRAX_ARCH_V10
+	default "00"
+	help
+	  Configures the direction of general port B bits. 1 is out, 0 is in.
+	  This is often totally different depending on the product used.  Bits
+	  0 and 1 on port PB are usually used for I2C communication, but the
+	  kernel I2C driver sets the appropriate directions itself so you
+	  don't need to take that into consideration when setting this option.
+	  If you don't know what to use, it is always safe to put all as
+	  inputs.
+
+config ETRAX_DEF_R_PORT_PB_DATA
+	hex "R_PORT_PB_DATA"
+	depends on ETRAX_ARCH_V10
+	default "ff"
+	help
+	  Configures the initial data for the general port A bits.  Most
+	  products should use FF here.
+
+config ETRAX_SOFT_SHUTDOWN
+	bool "Software Shutdown Support"
+	depends on ETRAX_ARCH_V10
+	help
+	  Enable this if ETRAX is used with a power-supply that can be turned
+	  off and on with PS_ON signal. Gives the possibility to detect
+	  powerbutton and then do a power off after unmounting disks.
+
+config ETRAX_SHUTDOWN_BIT
+	int "Shutdown bit on port CSP0"
+	depends on ETRAX_SOFT_SHUTDOWN
+	default "12"
+	help
+	  Configure what pin on CSPO-port that is used for controlling power
+	  supply.
+
+config ETRAX_POWERBUTTON_BIT
+	int "Power button bit on port G"
+	depends on ETRAX_SOFT_SHUTDOWN
+	default "25"
+	help
+	  Configure where power button is connected.
diff --git a/arch/cris/arch-v10/README.mm b/arch/cris/arch-v10/README.mm
new file mode 100644
index 0000000..6f08903
--- /dev/null
+++ b/arch/cris/arch-v10/README.mm
@@ -0,0 +1,244 @@
+Memory management for CRIS/MMU
+------------------------------
+HISTORY:
+
+$Log: README.mm,v $
+Revision 1.1  2001/12/17 13:59:27  bjornw
+Initial revision
+
+Revision 1.1  2000/07/10 16:25:21  bjornw
+Initial revision
+
+Revision 1.4  2000/01/17 02:31:59  bjornw
+Added discussion of paging and VM.
+
+Revision 1.3  1999/12/03 16:43:23  hp
+Blurb about that the 3.5G-limitation is not a MMU limitation
+
+Revision 1.2  1999/12/03 16:04:21  hp
+Picky comment about not mapping the first page
+
+Revision 1.1  1999/12/03 15:41:30  bjornw
+First version of CRIS/MMU memory layout specification.
+
+
+
+
+
+------------------------------
+
+See the ETRAX-NG HSDD for reference.
+
+We use the page-size of 8 kbytes, as opposed to the i386 page-size of 4 kbytes.
+
+The MMU can, apart from the normal mapping of pages, also do a top-level
+segmentation of the kernel memory space. We use this feature to avoid having
+to use page-tables to map the physical memory into the kernel's address
+space. We also use it to keep the user-mode virtual mapping in the same
+map during kernel-mode, so that the kernel easily can access the corresponding
+user-mode process' data.
+
+As a comparision, the Linux/i386 2.0 puts the kernel and physical RAM at
+address 0, overlapping with the user-mode virtual space, so that descriptor
+registers are needed for each memory access to specify which MMU space to
+map through. That changed in 2.2, putting the kernel/physical RAM at 
+0xc0000000, to co-exist with the user-mode mapping. We will do something
+quite similar, but with the additional complexity of having to map the
+internal chip I/O registers and the flash memory area (including SRAM
+and peripherial chip-selets).
+
+The kernel-mode segmentation map:
+
+        ------------------------                ------------------------
+FFFFFFFF|                      | => cached      |                      | 
+        |    kernel seg_f      |    flash       |                      |
+F0000000|______________________|                |                      |
+EFFFFFFF|                      | => uncached    |                      | 
+        |    kernel seg_e      |    flash       |                      |
+E0000000|______________________|                |        DRAM          |
+DFFFFFFF|                      |  paged to any  |      Un-cached       | 
+        |    kernel seg_d      |    =======>    |                      |
+D0000000|______________________|                |                      |
+CFFFFFFF|                      |                |                      | 
+        |    kernel seg_c      |==\             |                      |
+C0000000|______________________|   \            |______________________|
+BFFFFFFF|                      |  uncached      |                      |
+        |    kernel seg_b      |=====\=========>|       Registers      |
+B0000000|______________________|      \c        |______________________|
+AFFFFFFF|                      |       \a       |                      |
+        |                      |        \c      | FLASH/SRAM/Peripheral|
+        |                      |         \h     |______________________|
+        |                      |          \e    |                      |
+        |                      |           \d   |                      |
+        | kernel seg_0 - seg_a |            \==>|         DRAM         | 
+        |                      |                |        Cached        |
+        |                      |  paged to any  |                      |
+        |                      |    =======>    |______________________| 
+        |                      |                |                      |
+        |                      |                |        Illegal       |
+        |                      |                |______________________|
+        |                      |                |                      |      
+        |                      |                | FLASH/SRAM/Peripheral|
+00000000|______________________|                |______________________|
+
+In user-mode it looks the same except that only the space 0-AFFFFFFF is
+available. Therefore, in this model, the virtual address space per process
+is limited to 0xb0000000 bytes (minus 8192 bytes, since the first page,
+0..8191, is never mapped, in order to trap NULL references).
+
+It also means that the total physical RAM that can be mapped is 256 MB
+(kseg_c above). More RAM can be mapped by choosing a different segmentation
+and shrinking the user-mode memory space.
+
+The MMU can map all 4 GB in user mode, but doing that would mean that a
+few extra instructions would be needed for each access to user mode
+memory.
+
+The kernel needs access to both cached and uncached flash. Uncached is
+necessary because of the special write/erase sequences. Also, the 
+peripherial chip-selects are decoded from that region.
+
+The kernel also needs its own virtual memory space. That is kseg_d. It
+is used by the vmalloc() kernel function to allocate virtual contiguous
+chunks of memory not possible using the normal kmalloc physical RAM 
+allocator.
+
+The setting of the actual MMU control registers to use this layout would
+be something like this:
+
+R_MMU_KSEG = ( ( seg_f, seg     ) |   // Flash cached
+               ( seg_e, seg     ) |   // Flash uncached
+               ( seg_d, page    ) |   // kernel vmalloc area    
+               ( seg_c, seg     ) |   // kernel linear segment
+               ( seg_b, seg     ) |   // kernel linear segment
+               ( seg_a, page    ) |
+               ( seg_9, page    ) |
+               ( seg_8, page    ) |
+               ( seg_7, page    ) |
+               ( seg_6, page    ) |
+               ( seg_5, page    ) |
+               ( seg_4, page    ) |
+               ( seg_3, page    ) |
+               ( seg_2, page    ) |
+               ( seg_1, page    ) |
+               ( seg_0, page    ) );
+
+R_MMU_KBASE_HI = ( ( base_f, 0x0 ) |   // flash/sram/periph cached
+                   ( base_e, 0x8 ) |   // flash/sram/periph uncached
+                   ( base_d, 0x0 ) |   // don't care
+                   ( base_c, 0x4 ) |   // physical RAM cached area
+                   ( base_b, 0xb ) |   // uncached on-chip registers
+                   ( base_a, 0x0 ) |   // don't care
+                   ( base_9, 0x0 ) |   // don't care
+                   ( base_8, 0x0 ) );  // don't care
+
+R_MMU_KBASE_LO = ( ( base_7, 0x0 ) |   // don't care
+                   ( base_6, 0x0 ) |   // don't care
+                   ( base_5, 0x0 ) |   // don't care
+                   ( base_4, 0x0 ) |   // don't care
+                   ( base_3, 0x0 ) |   // don't care
+                   ( base_2, 0x0 ) |   // don't care
+                   ( base_1, 0x0 ) |   // don't care
+                   ( base_0, 0x0 ) );  // don't care
+
+NOTE: while setting up the MMU, we run in a non-mapped mode in the DRAM (0x40
+segment) and need to setup the seg_4 to a unity mapping, so that we don't get
+a fault before we have had time to jump into the real kernel segment (0xc0). This
+is done in head.S temporarily, but fixed by the kernel later in paging_init.
+
+
+Paging - PTE's, PMD's and PGD's
+-------------------------------
+
+[ References: asm/pgtable.h, asm/page.h, asm/mmu.h ]
+
+The paging mechanism uses virtual addresses to split a process memory-space into
+pages, a page being the smallest unit that can be freely remapped in memory. On
+Linux/CRIS, a page is 8192 bytes (for technical reasons not equal to 4096 as in 
+most other 32-bit architectures). It would be inefficient to let a virtual memory
+mapping be controlled by a long table of page mappings, so it is broken down into
+a 2-level structure with a Page Directory containing pointers to Page Tables which
+each have maps of up to 2048 pages (8192 / sizeof(void *)). Linux can actually
+handle 3-level structures as well, with a Page Middle Directory in between, but
+in many cases, this is folded into a two-level structure by excluding the Middle
+Directory.
+
+We'll take a look at how an address is translated while we discuss how it's handled
+in the Linux kernel.
+
+The example address is 0xd004000c; in binary this is:
+
+31       23       15       7      0
+11010000 00000100 00000000 00001100
+
+|______| |__________||____________|
+  PGD        PTE       page offset
+
+Given the top-level Page Directory, the offset in that directory is calculated
+using the upper 8 bits:
+
+extern inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
+{
+	return mm->pgd + (address >> PGDIR_SHIFT);
+}
+
+PGDIR_SHIFT is the log2 of the amount of memory an entry in the PGD can map; in our
+case it is 24, corresponding to 16 MB. This means that each entry in the PGD 
+corresponds to 16 MB of virtual memory.
+
+The pgd_t from our example will therefore be the 208'th (0xd0) entry in mm->pgd.
+
+Since the Middle Directory does not exist, it is a unity mapping:
+
+extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+{
+	return (pmd_t *) dir;
+}
+
+The Page Table provides the final lookup by using bits 13 to 23 as index:
+
+extern inline pte_t * pte_offset(pmd_t * dir, unsigned long address)
+{
+	return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) &
+					   (PTRS_PER_PTE - 1));
+}
+
+PAGE_SHIFT is the log2 of the size of a page; 13 in our case. PTRS_PER_PTE is
+the number of pointers that fit in a Page Table and is used to mask off the 
+PGD-part of the address.
+
+The so-far unused bits 0 to 12 are used to index inside a page linearily.
+
+The VM system
+-------------
+
+The kernels own page-directory is the swapper_pg_dir, cleared in paging_init, 
+and contains the kernels virtual mappings (the kernel itself is not paged - it
+is mapped linearily using kseg_c as described above). Architectures without
+kernel segments like the i386, need to setup swapper_pg_dir directly in head.S
+to map the kernel itself. swapper_pg_dir is pointed to by init_mm.pgd as the
+init-task's PGD.
+
+To see what support functions are used to setup a page-table, let's look at the
+kernel's internal paged memory system, vmalloc/vfree.
+
+void * vmalloc(unsigned long size)
+
+The vmalloc-system keeps a paged segment in kernel-space at 0xd0000000. What
+happens first is that a virtual address chunk is allocated to the request using
+get_vm_area(size). After that, physical RAM pages are allocated and put into
+the kernel's page-table using alloc_area_pages(addr, size). 
+
+static int alloc_area_pages(unsigned long address, unsigned long size)
+
+First the PGD entry is found using init_mm.pgd. This is passed to
+alloc_area_pmd (remember the 3->2 folding). It uses pte_alloc_kernel to
+check if the PGD entry points anywhere - if not, a page table page is
+allocated and the PGD entry updated. Then the alloc_area_pte function is
+used just like alloc_area_pmd to check which page table entry is desired, 
+and a physical page is allocated and the table entry updated. All of this
+is repeated at the top-level until the entire address range specified has 
+been mapped.
+
+
+
diff --git a/arch/cris/arch-v10/boot/Makefile b/arch/cris/arch-v10/boot/Makefile
new file mode 100644
index 0000000..fe66503
--- /dev/null
+++ b/arch/cris/arch-v10/boot/Makefile
@@ -0,0 +1,12 @@
+#
+# arch/cris/boot/Makefile
+#
+
+zImage: compressed/vmlinuz
+
+compressed/vmlinuz: $(TOPDIR)/vmlinux
+	@$(MAKE) -C compressed vmlinuz
+
+clean:
+	rm -f zImage tools/build compressed/vmlinux.out
+	@$(MAKE) -C compressed clean
diff --git a/arch/cris/arch-v10/boot/compressed/Makefile b/arch/cris/arch-v10/boot/compressed/Makefile
new file mode 100644
index 0000000..5f71c2c
--- /dev/null
+++ b/arch/cris/arch-v10/boot/compressed/Makefile
@@ -0,0 +1,40 @@
+#
+# linux/arch/etrax100/boot/compressed/Makefile
+#
+# create a compressed vmlinux image from the original vmlinux files and romfs
+#
+
+CC = gcc-cris -melf -I $(TOPDIR)/include
+CFLAGS = -O2
+LD = ld-cris
+OBJCOPY = objcopy-cris
+OBJCOPYFLAGS = -O binary --remove-section=.bss
+OBJECTS = head.o misc.o
+
+# files to compress
+SYSTEM = $(TOPDIR)/vmlinux.bin
+
+all: vmlinuz
+
+decompress.bin: $(OBJECTS)
+	$(LD) -T decompress.ld -o decompress.o $(OBJECTS)
+	$(OBJCOPY) $(OBJCOPYFLAGS) decompress.o decompress.bin
+# save it for mkprod in the topdir.
+	cp decompress.bin $(TOPDIR)
+
+
+vmlinuz: piggy.img decompress.bin
+	cat decompress.bin piggy.img > vmlinuz
+	rm -f piggy.img
+
+head.o: head.S
+	$(CC) -D__ASSEMBLY__ -traditional -c head.S -o head.o
+
+# gzip the kernel image
+
+piggy.img: $(SYSTEM)
+	cat $(SYSTEM) | gzip -f -9 > piggy.img
+
+clean:
+	rm -f piggy.img vmlinuz vmlinuz.o
+
diff --git a/arch/cris/arch-v10/boot/compressed/README b/arch/cris/arch-v10/boot/compressed/README
new file mode 100644
index 0000000..48b3db9
--- /dev/null
+++ b/arch/cris/arch-v10/boot/compressed/README
@@ -0,0 +1,25 @@
+Creation of the self-extracting compressed kernel image (vmlinuz)
+-----------------------------------------------------------------
+$Id: README,v 1.1 2001/12/17 13:59:27 bjornw Exp $
+
+This can be slightly confusing because it's a process with many steps.
+
+The kernel object built by the arch/etrax100/Makefile, vmlinux, is split
+by that makefile into text and data binary files, vmlinux.text and 
+vmlinux.data.
+
+Those files together with a ROM filesystem can be catted together and
+burned into a flash or executed directly at the DRAM origin.
+
+They can also be catted together and compressed with gzip, which is what
+happens in this makefile. Together they make up piggy.img. 
+
+The decompressor is built into the file decompress.o. It is turned into
+the binary file decompress.bin, which is catted together with piggy.img
+into the file vmlinuz. It can be executed in an arbitrary place in flash.
+
+Be careful - it assumes some things about free locations in DRAM. It
+assumes the DRAM starts at 0x40000000 and that it is at least 8 MB,
+so it puts its code at 0x40700000, and initial stack at 0x40800000.
+
+-Bjorn
diff --git a/arch/cris/arch-v10/boot/compressed/decompress.ld b/arch/cris/arch-v10/boot/compressed/decompress.ld
new file mode 100644
index 0000000..0b0a14f
--- /dev/null
+++ b/arch/cris/arch-v10/boot/compressed/decompress.ld
@@ -0,0 +1,29 @@
+OUTPUT_FORMAT(elf32-us-cris)
+
+MEMORY 
+	{
+	dram : ORIGIN = 0x40700000,
+	       LENGTH = 0x00100000
+	}
+
+SECTIONS
+{
+	.text :
+	{
+		_stext = . ;
+		*(.text)
+		*(.rodata)
+		*(.rodata.*)
+		_etext = . ;
+	} > dram
+	.data :
+	{
+		*(.data)
+		_edata = . ;
+	} > dram
+	.bss :
+	{
+		*(.bss)
+		_end = ALIGN( 0x10 ) ;
+	} > dram
+}
diff --git a/arch/cris/arch-v10/boot/compressed/head.S b/arch/cris/arch-v10/boot/compressed/head.S
new file mode 100644
index 0000000..4cbdd4b
--- /dev/null
+++ b/arch/cris/arch-v10/boot/compressed/head.S
@@ -0,0 +1,111 @@
+/*
+ *  arch/cris/boot/compressed/head.S
+ *
+ *  Copyright (C) 1999, 2001 Axis Communications AB
+ *
+ *  Code that sets up the DRAM registers, calls the
+ *  decompressor to unpack the piggybacked kernel, and jumps.
+ *
+ */
+
+#include <linux/config.h>
+#define ASSEMBLER_MACROS_ONLY
+#include <asm/arch/sv_addr_ag.h>
+
+#define RAM_INIT_MAGIC 0x56902387
+	
+	;; Exported symbols
+	
+	.globl	_input_data
+
+	
+	.text
+
+	nop
+	di
+
+;; 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:	
+		
+	;; Initiate the PA and PB ports
+
+	move.b   CONFIG_ETRAX_DEF_R_PORT_PA_DATA, r0
+	move.b   r0, [R_PORT_PA_DATA]
+
+	move.b   CONFIG_ETRAX_DEF_R_PORT_PA_DIR, r0
+	move.b   r0, [R_PORT_PA_DIR]
+
+	move.b   CONFIG_ETRAX_DEF_R_PORT_PB_DATA, r0
+	move.b   r0, [R_PORT_PB_DATA]
+
+	move.b   CONFIG_ETRAX_DEF_R_PORT_PB_DIR, r0
+	move.b   r0, [R_PORT_PB_DIR]
+
+	;; Setup the stack to a suitably high address.
+	;; We assume 8 MB is the minimum DRAM in an eLinux
+	;; product and put the sp at the top for now.
+
+	move.d	0x40800000, sp
+
+	;; Figure out where the compressed piggyback image is
+	;; in the flash (since we wont try to copy it to DRAM
+	;; before unpacking). It is at _edata, but in flash.
+	;; Use (_edata - basse) as offset to the current PC.
+	
+basse:	move.d	pc, r5
+	and.d	0x7fffffff, r5	; strip any non-cache bit
+	subq	2, r5		; compensate for the move.d pc instr
+	move.d	r5, r0		; save for later - flash address of 'basse'
+	add.d	_edata, r5
+	sub.d	basse, r5	; r5 = flash address of '_edata'
+	
+	;; Copy text+data to DRAM
+	
+	move.d	basse, r1	; destination
+	move.d	_edata, r2	; end destination
+1:	move.w	[r0+], r3
+	move.w	r3, [r1+]
+	cmp.d	r2, r1
+	bcs	1b
+	nop
+
+	move.d	r5, [_input_data] ; for the decompressor
+
+
+	;; Clear the decompressors BSS (between _edata and _end)
+	
+	moveq	0, r0
+	move.d	_edata, r1
+	move.d	_end, r2
+1:	move.w	r0, [r1+]
+	cmp.d	r2, r1
+	bcs	1b
+	nop
+	
+	;; Do the decompression and save compressed size in _inptr
+
+	jsr	_decompress_kernel
+	
+	;; Put start address of root partition in r9 so the kernel can use it
+	;; when mounting from flash
+
+	move.d	[_input_data], r9	; flash address of compressed kernel
+	add.d	[_inptr], r9		; size of compressed kernel
+	 
+	;; Enter the decompressed kernel
+	move.d	RAM_INIT_MAGIC, r8	; Tell kernel that DRAM is initialized
+	jump	0x40004000	; kernel is linked to this address
+	
+	.data
+
+_input_data:
+	.dword	0		; used by the decompressor
+
+#include "../../lib/hw_settings.S"
diff --git a/arch/cris/arch-v10/boot/compressed/misc.c b/arch/cris/arch-v10/boot/compressed/misc.c
new file mode 100644
index 0000000..1b5e83f
--- /dev/null
+++ b/arch/cris/arch-v10/boot/compressed/misc.c
@@ -0,0 +1,273 @@
+/*
+ * misc.c
+ *
+ * $Id: misc.c,v 1.6 2003/10/27 08:04:31 starvik Exp $
+ * 
+ * This is a collection of several routines from gzip-1.0.3 
+ * adapted for Linux.
+ *
+ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
+ * puts by Nick Holloway 1993, better puts by Martin Mares 1995
+ * adoptation for Linux/CRIS Axis Communications AB, 1999
+ * 
+ */
+
+/* where the piggybacked kernel image expects itself to live.
+ * it is the same address we use when we network load an uncompressed
+ * image into DRAM, and it is the address the kernel is linked to live
+ * at by vmlinux.lds.S
+ */
+
+#define KERNEL_LOAD_ADR 0x40004000
+
+#include <linux/config.h>
+
+#include <linux/types.h>
+#include <asm/arch/svinto.h>
+
+/*
+ * gzip declarations
+ */
+
+#define OF(args)  args
+#define STATIC static
+
+void* memset(void* s, int c, size_t n);
+void* memcpy(void* __dest, __const void* __src,
+	     size_t __n);
+
+#define memzero(s, n)     memset ((s), 0, (n))
+
+
+typedef unsigned char  uch;
+typedef unsigned short ush;
+typedef unsigned long  ulg;
+
+#define WSIZE 0x8000		/* Window size must be at least 32k, */
+				/* and a power of two */
+
+static uch *inbuf;	     /* input buffer */
+static uch window[WSIZE];    /* Sliding window buffer */
+
+unsigned inptr = 0;	/* index of next byte to be processed in inbuf
+			 * After decompression it will contain the
+			 * compressed size, and head.S will read it.
+			 */
+
+static unsigned outcnt = 0;  /* bytes in output buffer */
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define COMMENT      0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
+#define RESERVED     0xC0 /* bit 6,7:   reserved */
+
+#define get_byte() inbuf[inptr++]	
+	
+/* Diagnostic functions */
+#ifdef DEBUG
+#  define Assert(cond,msg) {if(!(cond)) error(msg);}
+#  define Trace(x) fprintf x
+#  define Tracev(x) {if (verbose) fprintf x ;}
+#  define Tracevv(x) {if (verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+static int  fill_inbuf(void);
+static void flush_window(void);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+
+extern char *input_data;  /* lives in head.S */
+
+static long bytes_out = 0;
+static uch *output_data;
+static unsigned long output_ptr = 0;
+ 
+static void *malloc(int size);
+static void free(void *where);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+ 
+static void puts(const char *);
+
+/* the "heap" is put directly after the BSS ends, at end */
+  
+extern int end;
+static long free_mem_ptr = (long)&end;
+ 
+#include "../../../../../lib/inflate.c"
+
+static void *malloc(int size)
+{
+	void *p;
+
+	if (size <0) error("Malloc error");
+
+	free_mem_ptr = (free_mem_ptr + 3) & ~3;	/* Align */
+
+	p = (void *)free_mem_ptr;
+	free_mem_ptr += size;
+
+	return p;
+}
+
+static void free(void *where)
+{	/* Don't care */
+}
+
+static void gzip_mark(void **ptr)
+{
+	*ptr = (void *) free_mem_ptr;
+}
+
+static void gzip_release(void **ptr)
+{
+	free_mem_ptr = (long) *ptr;
+}
+
+/* decompressor info and error messages to serial console */
+
+static void
+puts(const char *s)
+{
+#ifndef CONFIG_ETRAX_DEBUG_PORT_NULL
+	while(*s) {
+#ifdef CONFIG_ETRAX_DEBUG_PORT0
+		while(!(*R_SERIAL0_STATUS & (1 << 5))) ;
+		*R_SERIAL0_TR_DATA = *s++;
+#endif
+#ifdef CONFIG_ETRAX_DEBUG_PORT1
+		while(!(*R_SERIAL1_STATUS & (1 << 5))) ;
+		*R_SERIAL1_TR_DATA = *s++;
+#endif
+#ifdef CONFIG_ETRAX_DEBUG_PORT2
+		while(!(*R_SERIAL2_STATUS & (1 << 5))) ;
+		*R_SERIAL2_TR_DATA = *s++;
+#endif
+#ifdef CONFIG_ETRAX_DEBUG_PORT3
+		while(!(*R_SERIAL3_STATUS & (1 << 5))) ;
+		*R_SERIAL3_TR_DATA = *s++;
+#endif
+	}
+#endif
+}
+
+void*
+memset(void* s, int c, size_t n)
+{
+	int i;
+	char *ss = (char*)s;
+
+	for (i=0;i<n;i++) ss[i] = c;
+}
+
+void*
+memcpy(void* __dest, __const void* __src,
+			    size_t __n)
+{
+	int i;
+	char *d = (char *)__dest, *s = (char *)__src;
+
+	for (i=0;i<__n;i++) d[i] = s[i];
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+
+static void
+flush_window()
+{
+    ulg c = crc;         /* temporary variable */
+    unsigned n;
+    uch *in, *out, ch;
+    
+    in = window;
+    out = &output_data[output_ptr]; 
+    for (n = 0; n < outcnt; n++) {
+	    ch = *out++ = *in++;
+	    c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+    }
+    crc = c;
+    bytes_out += (ulg)outcnt;
+    output_ptr += (ulg)outcnt;
+    outcnt = 0;
+}
+
+static void
+error(char *x)
+{
+	puts("\n\n");
+	puts(x);
+	puts("\n\n -- System halted\n");
+
+	while(1);	/* Halt */
+}
+
+void
+setup_normal_output_buffer()
+{
+	output_data = (char *)KERNEL_LOAD_ADR;
+}
+
+void
+decompress_kernel()
+{
+	char revision;
+	
+	/* input_data is set in head.S */
+	inbuf = input_data;
+
+#ifdef CONFIG_ETRAX_DEBUG_PORT0
+	*R_SERIAL0_XOFF = 0;
+	*R_SERIAL0_BAUD = 0x99;
+	*R_SERIAL0_TR_CTRL = 0x40;
+#endif
+#ifdef CONFIG_ETRAX_DEBUG_PORT1
+	*R_SERIAL1_XOFF = 0;
+	*R_SERIAL1_BAUD = 0x99;
+	*R_SERIAL1_TR_CTRL = 0x40;
+#endif
+#ifdef CONFIG_ETRAX_DEBUG_PORT2
+	*R_GEN_CONFIG = 0x08;
+	*R_SERIAL2_XOFF = 0;
+	*R_SERIAL2_BAUD = 0x99;
+	*R_SERIAL2_TR_CTRL = 0x40;
+#endif
+#ifdef CONFIG_ETRAX_DEBUG_PORT3
+	*R_GEN_CONFIG = 0x100;
+	*R_SERIAL3_XOFF = 0;
+	*R_SERIAL3_BAUD = 0x99;
+	*R_SERIAL3_TR_CTRL = 0x40;
+#endif
+
+	setup_normal_output_buffer();
+
+	makecrc();
+
+	__asm__ volatile ("move vr,%0" : "=rm" (revision));
+	if (revision < 10)
+	{
+		puts("You need an ETRAX 100LX to run linux 2.6\n");
+		while(1);
+	}
+
+	puts("Uncompressing Linux...\n");
+	gunzip();
+	puts("Done. Now booting the kernel.\n");
+}
diff --git a/arch/cris/arch-v10/boot/rescue/Makefile b/arch/cris/arch-v10/boot/rescue/Makefile
new file mode 100644
index 0000000..e9f2ba2
--- /dev/null
+++ b/arch/cris/arch-v10/boot/rescue/Makefile
@@ -0,0 +1,55 @@
+#
+# Makefile for rescue code
+#
+ifndef TOPDIR
+TOPDIR = ../../../..
+endif
+CC = gcc-cris -mlinux -I $(TOPDIR)/include
+CFLAGS = -O2
+LD = gcc-cris -mlinux -nostdlib
+OBJCOPY = objcopy-cris
+OBJCOPYFLAGS = -O binary --remove-section=.bss
+
+all: rescue.bin testrescue.bin kimagerescue.bin
+
+rescue: rescue.bin
+	# do nothing
+
+rescue.bin: head.o
+	$(LD) -T rescue.ld -o rescue.o head.o
+	$(OBJCOPY) $(OBJCOPYFLAGS) rescue.o rescue.bin
+	cp rescue.bin $(TOPDIR)
+
+testrescue.bin: testrescue.o
+	$(OBJCOPY) $(OBJCOPYFLAGS) testrescue.o tr.bin
+# Pad it to 784 bytes
+	dd if=/dev/zero of=tmp2423 bs=1 count=784
+	cat tr.bin tmp2423 >testrescue_tmp.bin
+	dd if=testrescue_tmp.bin of=testrescue.bin bs=1 count=784
+	rm tr.bin tmp2423 testrescue_tmp.bin
+
+kimagerescue.bin: kimagerescue.o
+	$(OBJCOPY) $(OBJCOPYFLAGS) kimagerescue.o ktr.bin
+# Pad it to 784 bytes, that's what the rescue loader expects
+	dd if=/dev/zero of=tmp2423 bs=1 count=784
+	cat ktr.bin tmp2423 >kimagerescue_tmp.bin
+	dd if=kimagerescue_tmp.bin of=kimagerescue.bin bs=1 count=784
+	rm ktr.bin tmp2423 kimagerescue_tmp.bin
+
+head.o: head.S
+	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
+
+testrescue.o: testrescue.S
+	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
+
+kimagerescue.o: kimagerescue.S
+	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
+
+clean:
+	rm -f *.o *.bin
+
+fastdep:
+
+modules:
+
+modules-install:
diff --git a/arch/cris/arch-v10/boot/rescue/head.S b/arch/cris/arch-v10/boot/rescue/head.S
new file mode 100644
index 0000000..8689ea9
--- /dev/null
+++ b/arch/cris/arch-v10/boot/rescue/head.S
@@ -0,0 +1,333 @@
+/* $Id: head.S,v 1.6 2003/04/09 08:12:43 pkj Exp $
+ * 
+ * Rescue code, made to reside at the beginning of the
+ * flash-memory. when it starts, it checks a partition
+ * table at the first sector after the rescue sector.
+ * the partition table was generated by the product builder
+ * script and contains offsets, lengths, types and checksums
+ * for each partition that this code should check.
+ *
+ * If any of the checksums fail, we assume the flash is so
+ * corrupt that we cant use it to boot into the ftp flash
+ * loader, and instead we initialize the serial port to
+ * receive a flash-loader and new flash image. we dont include
+ * any flash code here, but just accept a certain amount of
+ * bytes from the serial port and jump into it. the downloaded
+ * code is put in the cache.
+ *
+ * The partitiontable is designed so that it is transparent to
+ * code execution - it has a relative branch opcode in the
+ * beginning that jumps over it. each entry contains extra
+ * data so we can add stuff later.
+ *
+ * Partition table format:
+ *
+ *     Code transparency:
+ * 
+ *     2 bytes    [opcode 'nop']
+ *     2 bytes    [opcode 'di']
+ *     4 bytes    [opcode 'ba <offset>', 8-bit or 16-bit version]
+ *     2 bytes    [opcode 'nop', delay slot]
+ *
+ *     Table validation (at +10):	
+ * 
+ *     2 bytes    [magic/version word for partitiontable - 0xef, 0xbe]
+ *     2 bytes    [length of all entries plus the end marker]
+ *     4 bytes    [checksum for the partitiontable itself]
+ *
+ *     Entries, each with the following format, last has offset -1:	
+ *    
+ *        4 bytes    [offset in bytes, from start of flash]
+ *        4 bytes    [length in bytes of partition]
+ *        4 bytes    [checksum, simple longword sum]
+ *        2 bytes    [partition type]
+ *        2 bytes    [flags, only bit 0 used, ro/rw = 1/0]
+ *        16 bytes   [reserved for future use]
+ *
+ *     End marker
+ *
+ *        4 bytes    [-1]
+ * 
+ *	 10 bytes    [0, padding]
+ * 
+ * Bit 0 in flags signifies RW or RO. The rescue code only bothers
+ * to check the checksum for RO partitions, since the others will
+ * change their data without updating the checksums. A 1 in bit 0
+ * means RO, 0 means RW. That way, it is possible to set a partition
+ * in RO mode initially, and later mark it as RW, since you can always
+ * write 0's to the flash.
+ *
+ * During the wait for serial input, the status LED will flash so the
+ * user knows something went wrong.
+ * 
+ * Copyright (C) 1999, 2000, 2001, 2002, 2003 Axis Communications AB
+ */
+
+#include <linux/config.h>
+#define ASSEMBLER_MACROS_ONLY
+#include <asm/arch/sv_addr_ag.h>
+
+	;; The partitiontable is looked for at the first sector after the boot
+	;; sector. Sector size is 65536 bytes in all flashes we use.
+		
+#define PTABLE_START CONFIG_ETRAX_PTABLE_SECTOR
+#define PTABLE_MAGIC 0xbeef
+
+	;; The normal Etrax100 on-chip boot ROM does serial boot at 0x380000f0.
+	;; That is not where we put our downloaded serial boot-code. The length is
+	;; enough for downloading code that loads the rest of itself (after
+	;; having setup the DRAM etc). It is the same length as the on-chip
+	;; ROM loads, so the same host loader can be used to load a rescued
+	;; product as well as one booted through the Etrax serial boot code.
+		
+#define CODE_START 0x40000000
+#define CODE_LENGTH 784
+
+#ifdef CONFIG_ETRAX_RESCUE_SER0
+#define SERXOFF R_SERIAL0_XOFF
+#define SERBAUD R_SERIAL0_BAUD
+#define SERRECC R_SERIAL0_REC_CTRL
+#define SERRDAT R_SERIAL0_REC_DATA
+#define SERSTAT R_SERIAL0_STATUS
+#endif
+#ifdef CONFIG_ETRAX_RESCUE_SER1
+#define SERXOFF R_SERIAL1_XOFF
+#define SERBAUD R_SERIAL1_BAUD
+#define SERRECC R_SERIAL1_REC_CTRL
+#define SERRDAT R_SERIAL1_REC_DATA
+#define SERSTAT R_SERIAL1_STATUS
+#endif
+#ifdef CONFIG_ETRAX_RESCUE_SER2
+#define SERXOFF R_SERIAL2_XOFF
+#define SERBAUD R_SERIAL2_BAUD
+#define SERRECC R_SERIAL2_REC_CTRL
+#define SERRDAT R_SERIAL2_REC_DATA
+#define SERSTAT R_SERIAL2_STATUS
+#endif	
+#ifdef CONFIG_ETRAX_RESCUE_SER3
+#define SERXOFF R_SERIAL3_XOFF
+#define SERBAUD R_SERIAL3_BAUD
+#define SERRECC R_SERIAL3_REC_CTRL
+#define SERRDAT R_SERIAL3_REC_DATA
+#define SERSTAT R_SERIAL3_STATUS
+#endif
+
+#define NOP_DI 0xf025050f
+#define RAM_INIT_MAGIC 0x56902387
+
+	.text
+	
+	;; This is the entry point of the rescue code
+	;; 0x80000000 if loaded in flash (as it should be)
+	;; 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
+	
+	nop	
+	di
+
+	jump	in_cache	; enter cached area instead
+in_cache:	
+
+	;; first put a jump test to give a possibility of upgrading the rescue code
+	;; without erasing/reflashing the sector. we put a longword of -1 here and if
+	;; it is not -1, we jump using the value as jump target. since we can always
+	;; change 1's to 0's without erasing the sector, it is possible to add new
+	;; code after this and altering the jumptarget in an upgrade.
+
+jtcd:	move.d	[jumptarget], $r0
+	cmp.d	0xffffffff, $r0
+	beq	no_newjump
+	nop
+	
+	jump	[$r0]
+
+jumptarget:	
+	.dword	0xffffffff	; can be overwritten later to insert new code
+	
+no_newjump:
+#ifdef CONFIG_ETRAX_ETHERNET		
+	;; Start MII clock to make sure it is running when tranceiver is reset
+	move.d 0x3, $r0    ; enable = on, phy = mii_clk
+	move.d $r0, [R_NETWORK_GEN_CONFIG]
+#endif
+	
+	;; We need to setup the bus registers before we start using the DRAM
+#include "../../lib/dram_init.S"
+
+	;; we now should go through the checksum-table and check the listed
+	;; partitions for errors.
+	
+	move.d	PTABLE_START, $r3
+	move.d	[$r3], $r0
+	cmp.d	NOP_DI, $r0	; make sure the nop/di is there...
+	bne	do_rescue
+	nop
+	
+	;; skip the code transparency block (10 bytes).
+
+	addq	10, $r3
+	
+	;; check for correct magic
+	
+	move.w	[$r3+], $r0
+	cmp.w	PTABLE_MAGIC, $r0
+	bne	do_rescue	; didn't recognize - trig rescue
+	nop
+
+	;; check for correct ptable checksum
+
+	movu.w	[$r3+], $r2	; ptable length
+	move.d	$r2, $r8	; save for later, length of total ptable
+	addq	28, $r8		; account for the rest
+	move.d	[$r3+], $r4	; ptable checksum
+	move.d	$r3, $r1
+	jsr	checksum	; r1 source, r2 length, returns in r0
+
+	cmp.d	$r0, $r4
+	bne	do_rescue	; didn't match - trig rescue
+	nop
+	
+	;; ptable is ok. validate each entry.
+
+	moveq	-1, $r7
+	
+ploop:	move.d	[$r3+], $r1	; partition offset (from ptable start)
+	bne	notfirst	; check if it is the partition containing ptable
+	nop			; yes..
+	move.d	$r8, $r1	; for its checksum check, skip the ptable
+	move.d	[$r3+], $r2	; partition length
+	sub.d	$r8, $r2	; minus the ptable length
+	ba	bosse
+	nop
+notfirst:	
+	cmp.d	-1, $r1		; the end of the ptable ?
+	beq	flash_ok	;   if so, the flash is validated
+	move.d	[$r3+], $r2	; partition length
+bosse:	move.d	[$r3+], $r5	; checksum
+	move.d	[$r3+], $r4	; type and flags
+	addq	16, $r3		; skip the reserved bytes
+	btstq	16, $r4		; check ro flag
+	bpl	ploop		;   rw partition, skip validation
+	nop
+	btstq	17, $r4		; check bootable flag
+	bpl	1f
+	nop
+	move.d	$r1, $r7	; remember boot partition offset
+1:	
+
+	add.d	PTABLE_START, $r1
+	
+	jsr	checksum	; checksum the partition
+	
+	cmp.d	$r0, $r5
+	beq	ploop		; checksums matched, go to next entry
+	nop
+
+	;; otherwise fall through to the rescue code.
+	
+do_rescue:
+	;; setup port PA and PB default initial directions and data
+	;; (so we can flash LEDs, and so that DTR and others are set)
+	
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PA_DIR, $r0
+	move.b	$r0, [R_PORT_PA_DIR]
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PA_DATA, $r0
+	move.b	$r0, [R_PORT_PA_DATA]
+	
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_DIR, $r0
+	move.b	$r0, [R_PORT_PB_DIR]
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_DATA, $r0
+	move.b	$r0, [R_PORT_PB_DATA]
+
+	;; setup the serial port at 115200 baud
+	
+	moveq	0, $r0
+	move.d	$r0, [SERXOFF] 
+
+	move.b	0x99, $r0
+	move.b	$r0, [SERBAUD]		; 115.2kbaud for both transmit and receive
+
+	move.b	0x40, $r0		; rec enable
+	move.b	$r0, [SERRECC] 
+
+	moveq	0, $r1		; "timer" to clock out a LED red flash
+	move.d	CODE_START, $r3	; destination counter
+	movu.w	CODE_LENGTH, $r4; length
+	
+wait_ser:
+	addq	1, $r1
+#ifndef CONFIG_ETRAX_NO_LEDS
+#ifdef CONFIG_ETRAX_PA_LEDS
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PA_DATA, $r2
+#endif
+#ifdef CONFIG_ETRAX_PB_LEDS
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_DATA, $r2
+#endif
+	move.d	(1 << CONFIG_ETRAX_LED1R) | (1 << CONFIG_ETRAX_LED2R), $r0
+	btstq	16, $r1
+	bpl	1f
+	nop
+	or.d	$r0, $r2	; set bit
+	ba	2f
+	nop
+1:	not	$r0		; clear bit
+	and.d	$r0, $r2
+2:	
+#ifdef CONFIG_ETRAX_PA_LEDS
+	move.b	$r2, [R_PORT_PA_DATA]	
+#endif	
+#ifdef CONFIG_ETRAX_PB_LEDS
+	move.b	$r2, [R_PORT_PB_DATA]	
+#endif
+#ifdef CONFIG_ETRAX_90000000_LEDS
+	move.b	$r2, [0x90000000]
+#endif
+#endif
+	
+	;; check if we got something on the serial port
+	
+	move.b	[SERSTAT], $r0
+	btstq	0, $r0		; data_avail
+	bpl	wait_ser
+	nop
+
+	;; got something - copy the byte and loop
+
+	move.b	[SERRDAT], $r0
+	move.b	$r0, [$r3+]
+	
+	subq	1, $r4		; decrease length
+	bne	wait_ser
+	nop
+
+	;; jump into downloaded code
+
+	move.d	RAM_INIT_MAGIC, $r8	; Tell next product that DRAM is initialized
+	jump	CODE_START
+
+flash_ok:
+	;; check r7, which contains either -1 or the partition to boot from
+
+	cmp.d	-1, $r7
+	bne	1f
+	nop
+	move.d	PTABLE_START, $r7; otherwise use the ptable start
+1:
+	move.d	RAM_INIT_MAGIC, $r8	; Tell next product that DRAM is initialized
+	jump	$r7		; boot!
+
+
+	;; Helper subroutines
+
+	;; Will checksum by simple addition
+	;; r1 - source
+	;; r2 - length in bytes
+	;; result will be in r0
+checksum:
+	moveq	0, $r0
+1:	addu.b	[$r1+], $r0
+	subq	1, $r2
+	bne	1b
+	nop
+	ret
+	nop
diff --git a/arch/cris/arch-v10/boot/rescue/kimagerescue.S b/arch/cris/arch-v10/boot/rescue/kimagerescue.S
new file mode 100644
index 0000000..264bf7a
--- /dev/null
+++ b/arch/cris/arch-v10/boot/rescue/kimagerescue.S
@@ -0,0 +1,144 @@
+/* $Id: kimagerescue.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $
+ * 
+ * Rescue code to be prepended on a kimage and copied to the
+ * rescue serial port.
+ * This is called from the rescue code, it will copy received data to
+ * 4004000 and after a timeout jump to it.
+ */
+
+#include <linux/config.h>
+#define ASSEMBLER_MACROS_ONLY
+#include <asm/sv_addr_ag.h>
+
+#define CODE_START 0x40004000
+#define CODE_LENGTH 784
+#define TIMEOUT_VALUE 1000
+	
+		
+#ifdef CONFIG_ETRAX_RESCUE_SER0
+#define SERXOFF R_SERIAL0_XOFF
+#define SERBAUD R_SERIAL0_BAUD
+#define SERRECC R_SERIAL0_REC_CTRL
+#define SERRDAT R_SERIAL0_REC_DATA
+#define SERSTAT R_SERIAL0_STATUS
+#endif
+#ifdef CONFIG_ETRAX_RESCUE_SER1
+#define SERXOFF R_SERIAL1_XOFF
+#define SERBAUD R_SERIAL1_BAUD
+#define SERRECC R_SERIAL1_REC_CTRL
+#define SERRDAT R_SERIAL1_REC_DATA
+#define SERSTAT R_SERIAL1_STATUS
+#endif
+#ifdef CONFIG_ETRAX_RESCUE_SER2
+#define SERXOFF R_SERIAL2_XOFF
+#define SERBAUD R_SERIAL2_BAUD
+#define SERRECC R_SERIAL2_REC_CTRL
+#define SERRDAT R_SERIAL2_REC_DATA
+#define SERSTAT R_SERIAL2_STATUS
+#endif	
+#ifdef CONFIG_ETRAX_RESCUE_SER3
+#define SERXOFF R_SERIAL3_XOFF
+#define SERBAUD R_SERIAL3_BAUD
+#define SERRECC R_SERIAL3_REC_CTRL
+#define SERRDAT R_SERIAL3_REC_DATA
+#define SERSTAT R_SERIAL3_STATUS
+#endif
+
+	.text
+	;; This is the entry point of the rescue code
+	;; 0x80000000 if loaded in flash (as it should be)
+	;; 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
+	
+	nop	
+	di
+#ifndef CONFIG_SVINTO_SIM	
+	;; setup port PA and PB default initial directions and data
+	;; (so we can flash LEDs, and so that DTR and others are set)
+	
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PA_DIR, $r0
+	move.b	$r0, [R_PORT_PA_DIR]
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PA_DATA, $r0
+	move.b	$r0, [R_PORT_PA_DATA]
+	
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_DIR, $r0
+	move.b	$r0, [R_PORT_PB_DIR]
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_DATA, $r0
+	move.b	$r0, [R_PORT_PB_DATA]
+	
+	;; We need to setup the bus registers before we start using the DRAM
+#include "../../lib/dram_init.S"
+	
+#endif
+	;; Setup the stack to a suitably high address.
+	;; We assume 8 MB is the minimum DRAM in an eLinux
+	;; product and put the sp at the top for now.
+
+	move.d	0x40800000, $sp
+	
+	;; setup the serial port at 115200 baud
+	
+	moveq	0, $r0
+	move.d	$r0, [SERXOFF] 
+
+	move.b	0x99, $r0
+	move.b	$r0, [SERBAUD]		; 115.2kbaud for both transmit and receive
+
+	move.b	0x40, $r0		; rec enable
+	move.b	$r0, [SERRECC] 
+
+
+	moveq	0, $r1		; "timer" to clock out a LED red flash
+	move.d	CODE_START, $r3	; destination counter
+	move.d	CODE_LENGTH, $r4	; length
+	move.d	TIMEOUT_VALUE, $r5	; "timeout" until jump
+
+wait_ser:
+	addq	1, $r1
+	subq	1, $r5		; decrease timeout
+	beq	jump_start	; timed out
+	nop
+#ifndef CONFIG_ETRAX_NO_LEDS
+#ifdef CONFIG_ETRAX_PA_LEDS
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PA_DATA, $r2
+#endif
+#ifdef CONFIG_ETRAX_PB_LEDS
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_DATA, $r2
+#endif
+	move.d	(1 << CONFIG_ETRAX_LED1R) | (1 << CONFIG_ETRAX_LED2R), $r0
+	btstq	16, $r1
+	bpl	1f
+	nop
+	or.d	$r0, $r2		; set bit
+	ba	2f
+	nop
+1:	not	$r0		; clear bit
+	and.d	$r0, $r2
+2:	
+#ifdef CONFIG_ETRAX_PA_LEDS
+	move.b	$r2, [R_PORT_PA_DATA]
+#endif	
+#ifdef CONFIG_ETRAX_PB_LEDS
+	move.b	$r2, [R_PORT_PB_DATA]
+#endif
+#endif
+		
+	;; check if we got something on the serial port
+	
+	move.b	[SERSTAT], $r0
+	btstq	0, $r0		; data_avail
+	bpl	wait_ser
+	nop
+
+	;; got something - copy the byte and loop
+
+	move.b	[SERRDAT], $r0
+	move.b	$r0, [$r3+]
+	move.d	TIMEOUT_VALUE, $r5	; reset "timeout"
+	subq	1, $r4		; decrease length
+	bne	wait_ser
+	nop
+jump_start:
+	;; jump into downloaded code
+
+	jump	CODE_START
diff --git a/arch/cris/arch-v10/boot/rescue/rescue.ld b/arch/cris/arch-v10/boot/rescue/rescue.ld
new file mode 100644
index 0000000..0b52a94
--- /dev/null
+++ b/arch/cris/arch-v10/boot/rescue/rescue.ld
@@ -0,0 +1,20 @@
+MEMORY 
+	{
+	flash : ORIGIN = 0x00000000,
+	        LENGTH = 0x00100000
+	}
+
+SECTIONS
+{
+	.text :
+	{
+		stext = . ;
+		*(.text)
+		etext = . ;
+	} > flash
+	.data :
+	{
+		*(.data)
+		edata = . ;
+	} > flash
+}
diff --git a/arch/cris/arch-v10/boot/rescue/testrescue.S b/arch/cris/arch-v10/boot/rescue/testrescue.S
new file mode 100644
index 0000000..566a9f3
--- /dev/null
+++ b/arch/cris/arch-v10/boot/rescue/testrescue.S
@@ -0,0 +1,26 @@
+/* $Id: testrescue.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $
+ *
+ * Simple testcode to download by the rescue block.
+ * Just lits some LEDs to show it was downloaded correctly.
+ * 
+ * Copyright (C) 1999 Axis Communications AB
+ */
+
+#define ASSEMBLER_MACROS_ONLY
+#include <asm/sv_addr_ag.h>
+
+	.text
+
+	nop
+	nop
+	moveq	-1, $r2
+	move.b	$r2, [R_PORT_PA_DIR]
+	moveq	0, $r2
+	move.b	$r2, [R_PORT_PA_DATA]	
+
+endless:
+	nop
+	ba	endless
+	nop
+
+	
diff --git a/arch/cris/arch-v10/boot/tools/build.c b/arch/cris/arch-v10/boot/tools/build.c
new file mode 100644
index 0000000..2f9bbb2
--- /dev/null
+++ b/arch/cris/arch-v10/boot/tools/build.c
@@ -0,0 +1,288 @@
+/*
+ *  linux/tools/build.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * This file builds a disk-image from three different files:
+ *
+ * - bootsect: exactly 512 bytes of 8086 machine code, loads the rest
+ * - setup: 8086 machine code, sets up system parm
+ * - system: 80386 code for actual system
+ *
+ * It does some checking that all files are of the correct type, and
+ * just writes the result to stdout, removing headers and padding to
+ * the right amount. It also writes some system data to stderr.
+ */
+
+/*
+ * Changes by tytso to allow root device specification
+ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
+ * Cross compiling fixes by Gertjan van Wingerde, July 1996
+ */
+
+#include <stdio.h>	/* fprintf */
+#include <string.h>
+#include <stdlib.h>	/* contains exit */
+#include <sys/types.h>	/* unistd.h needs this */
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <unistd.h>	/* contains read/write */
+#include <fcntl.h>
+#include <linux/a.out.h>
+#include <errno.h>
+
+#define MINIX_HEADER 32
+
+#define N_MAGIC_OFFSET 1024
+#ifndef __BFD__
+static int GCC_HEADER = sizeof(struct exec);
+#endif
+
+#ifdef __BIG_KERNEL__
+#define SYS_SIZE 0xffff
+#else
+#define SYS_SIZE DEF_SYSSIZE
+#endif
+
+#define DEFAULT_MAJOR_ROOT 0
+#define DEFAULT_MINOR_ROOT 0
+
+/* max nr of sectors of setup: don't change unless you also change
+ * bootsect etc */
+#define SETUP_SECTS 4
+
+#define STRINGIFY(x) #x
+
+typedef union {
+	int i;
+	long l;
+	short s[2];
+	char b[4];
+} conv;
+
+long intel_long(long l)
+{
+	conv t;
+
+	t.b[0] = l & 0xff; l >>= 8;
+	t.b[1] = l & 0xff; l >>= 8;
+	t.b[2] = l & 0xff; l >>= 8;
+	t.b[3] = l & 0xff; l >>= 8;
+	return t.l;
+}
+
+int intel_int(int i)
+{
+	conv t;
+
+	t.b[0] = i & 0xff; i >>= 8;
+        t.b[1] = i & 0xff; i >>= 8;
+        t.b[2] = i & 0xff; i >>= 8;
+        t.b[3] = i & 0xff; i >>= 8;
+        return t.i;
+}
+
+short intel_short(short l)
+{
+	conv t;
+
+	t.b[0] = l & 0xff; l >>= 8;
+	t.b[1] = l & 0xff; l >>= 8;
+	return t.s[0];
+}
+
+void die(const char * str)
+{
+	fprintf(stderr,"%s\n",str);
+	exit(1);
+}
+
+void usage(void)
+{
+	die("Usage: build bootsect setup system [rootdev] [> image]");
+}
+
+int main(int argc, char ** argv)
+{
+	int i,c,id,sz,tmp_int;
+	unsigned long sys_size, tmp_long;
+	char buf[1024];
+#ifndef __BFD__
+	struct exec *ex = (struct exec *)buf;
+#endif
+	char major_root, minor_root;
+	struct stat sb;
+	unsigned char setup_sectors;
+
+	if ((argc < 4) || (argc > 5))
+		usage();
+	if (argc > 4) {
+		if (!strcmp(argv[4], "CURRENT")) {
+			if (stat("/", &sb)) {
+				perror("/");
+				die("Couldn't stat /");
+			}
+			major_root = major(sb.st_dev);
+			minor_root = minor(sb.st_dev);
+		} else if (strcmp(argv[4], "FLOPPY")) {
+			if (stat(argv[4], &sb)) {
+				perror(argv[4]);
+				die("Couldn't stat root device.");
+			}
+			major_root = major(sb.st_rdev);
+			minor_root = minor(sb.st_rdev);
+		} else {
+			major_root = 0;
+			minor_root = 0;
+		}
+	} else {
+		major_root = DEFAULT_MAJOR_ROOT;
+		minor_root = DEFAULT_MINOR_ROOT;
+	}
+	fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root);
+	for (i=0;i<sizeof buf; i++) buf[i]=0;
+	if ((id=open(argv[1],O_RDONLY,0))<0)
+		die("Unable to open 'boot'");
+	if (read(id,buf,MINIX_HEADER) != MINIX_HEADER)
+		die("Unable to read header of 'boot'");
+	if (((long *) buf)[0]!=intel_long(0x04100301))
+		die("Non-Minix header of 'boot'");
+	if (((long *) buf)[1]!=intel_long(MINIX_HEADER))
+		die("Non-Minix header of 'boot'");
+	if (((long *) buf)[3] != 0)
+		die("Illegal data segment in 'boot'");
+	if (((long *) buf)[4] != 0)
+		die("Illegal bss in 'boot'");
+	if (((long *) buf)[5] != 0)
+		die("Non-Minix header of 'boot'");
+	if (((long *) buf)[7] != 0)
+		die("Illegal symbol table in 'boot'");
+	i=read(id,buf,sizeof buf);
+	fprintf(stderr,"Boot sector %d bytes.\n",i);
+	if (i != 512)
+		die("Boot block must be exactly 512 bytes");
+	if ((*(unsigned short *)(buf+510)) != (unsigned short)intel_short(0xAA55))
+		die("Boot block hasn't got boot flag (0xAA55)");
+	buf[508] = (char) minor_root;
+	buf[509] = (char) major_root;	
+	i=write(1,buf,512);
+	if (i!=512)
+		die("Write call failed");
+	close (id);
+	
+	if ((id=open(argv[2],O_RDONLY,0))<0)
+		die("Unable to open 'setup'");
+	if (read(id,buf,MINIX_HEADER) != MINIX_HEADER)
+		die("Unable to read header of 'setup'");
+	if (((long *) buf)[0]!=intel_long(0x04100301))
+		die("Non-Minix header of 'setup'");
+	if (((long *) buf)[1]!=intel_long(MINIX_HEADER))
+		die("Non-Minix header of 'setup'");
+	if (((long *) buf)[3] != 0)
+		die("Illegal data segment in 'setup'");
+	if (((long *) buf)[4] != 0)
+		die("Illegal bss in 'setup'");
+	if (((long *) buf)[5] != 0)
+		die("Non-Minix header of 'setup'");
+	if (((long *) buf)[7] != 0)
+		die("Illegal symbol table in 'setup'");
+	for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c )
+#ifdef __BIG_KERNEL__
+	{
+		if (!i) {
+			/* Working with memcpy because of alignment constraints
+			   on Sparc - Gertjan */
+			memcpy(&tmp_long, &buf[2], sizeof(long));
+			if (tmp_long != intel_long(0x53726448) )
+				die("Wrong magic in loader header of 'setup'");
+			memcpy(&tmp_int, &buf[6], sizeof(int));
+			if (tmp_int < intel_int(0x200))
+				die("Wrong version of loader header of 'setup'");
+			buf[0x11] = 1; /* LOADED_HIGH */
+			tmp_long = intel_long(0x100000);
+			memcpy(&buf[0x14], &tmp_long, sizeof(long));  /* code32_start */
+		}
+#endif
+		if (write(1,buf,c)!=c)
+			die("Write call failed");
+#ifdef __BIG_KERNEL__
+	}
+#endif
+	if (c != 0)
+		die("read-error on 'setup'");
+	close (id);
+	setup_sectors = (unsigned char)((i + 511) / 512);
+	/* for compatibility with LILO */
+	if (setup_sectors < SETUP_SECTS)
+		setup_sectors = SETUP_SECTS;
+	fprintf(stderr,"Setup is %d bytes.\n",i);
+	for (c=0 ; c<sizeof(buf) ; c++)
+		buf[c] = '\0';
+	while (i < setup_sectors * 512) {
+		c = setup_sectors * 512 - i;
+		if (c > sizeof(buf))
+			c = sizeof(buf);
+		if (write(1,buf,c) != c)
+			die("Write call failed");
+		i += c;
+	}
+	
+	if ((id=open(argv[3],O_RDONLY,0))<0)
+		die("Unable to open 'system'");
+#ifndef __BFD__
+	if (read(id,buf,GCC_HEADER) != GCC_HEADER)
+		die("Unable to read header of 'system'");
+	if (N_MAGIC(*ex) == ZMAGIC) {
+		GCC_HEADER = N_MAGIC_OFFSET;
+		lseek(id, GCC_HEADER, SEEK_SET);
+	} else if (N_MAGIC(*ex) != QMAGIC)
+		die("Non-GCC header of 'system'");
+	fprintf(stderr,"System is %d kB (%d kB code, %d kB data and %d kB bss)\n",
+		(ex->a_text+ex->a_data+ex->a_bss)/1024,
+		ex->a_text /1024,
+		ex->a_data /1024,
+		ex->a_bss  /1024);
+	sz = N_SYMOFF(*ex) - GCC_HEADER + 4;
+#else
+	if (fstat (id, &sb)) {
+	  perror ("fstat");
+	  die ("Unable to stat 'system'");
+	}
+	sz = sb.st_size;
+	fprintf (stderr, "System is %d kB\n", sz/1024);
+#endif
+	sys_size = (sz + 15) / 16;
+	if (sys_size > SYS_SIZE)
+		die("System is too big");
+	while (sz > 0) {
+		int l, n;
+
+		l = sz;
+		if (l > sizeof(buf))
+			l = sizeof(buf);
+		if ((n=read(id, buf, l)) != l) {
+			if (n == -1) 
+				perror(argv[1]);
+			else
+				fprintf(stderr, "Unexpected EOF\n");
+			die("Can't read 'system'");
+		}
+		if (write(1, buf, l) != l)
+			die("Write failed");
+		sz -= l;
+	}
+	close(id);
+	if (lseek(1, 497, 0) == 497) {
+		if (write(1, &setup_sectors, 1) != 1)
+			die("Write of setup sectors failed");
+	}
+	if (lseek(1,500,0) == 500) {
+		buf[0] = (sys_size & 0xff);
+		buf[1] = ((sys_size >> 8) & 0xff);
+		if (write(1, buf, 2) != 2)
+			die("Write failed");
+	}
+	return(0);
+}
diff --git a/arch/cris/arch-v10/defconfig b/arch/cris/arch-v10/defconfig
new file mode 100644
index 0000000..2a3411ea
--- /dev/null
+++ b/arch/cris/arch-v10/defconfig
@@ -0,0 +1,505 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# General setup
+#
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_SYSCTL is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_ETRAX_KGDB is not set
+# CONFIG_ETRAX_WATCHDOG is not set
+
+#
+# Hardware setup
+#
+CONFIG_ETRAX100LX=y
+# CONFIG_ETRAX100LX_V2 is not set
+# CONFIG_SVINTO_SIM is not set
+CONFIG_CRIS_LOW_MAP=y
+CONFIG_ETRAX_DRAM_VIRTUAL_BASE=60000000
+CONFIG_ETRAX_DRAM_SIZE=8
+CONFIG_ETRAX_FLASH_BUSWIDTH=2
+CONFIG_ETRAX_ROOT_DEVICE="/dev/mtdblock3"
+CONFIG_ETRAX_PA_LEDS=y
+# CONFIG_ETRAX_PB_LEDS is not set
+# CONFIG_ETRAX_CSP0_LEDS is not set
+# CONFIG_ETRAX_NO_LEDS is not set
+CONFIG_ETRAX_LED1G=2
+CONFIG_ETRAX_LED1R=2
+CONFIG_ETRAX_LED2G=2
+CONFIG_ETRAX_LED2R=2
+CONFIG_ETRAX_LED3R=2
+CONFIG_ETRAX_LED3G=2
+CONFIG_ETRAX_LED4R=2
+CONFIG_ETRAX_LED4G=2
+CONFIG_ETRAX_LED5R=2
+CONFIG_ETRAX_LED5G=2
+CONFIG_ETRAX_LED6R=2
+CONFIG_ETRAX_LED6G=2
+CONFIG_ETRAX_LED7R=2
+CONFIG_ETRAX_LED7G=2
+CONFIG_ETRAX_LED8Y=2
+CONFIG_ETRAX_LED9Y=2
+CONFIG_ETRAX_LED10Y=2
+CONFIG_ETRAX_LED11Y=2
+CONFIG_ETRAX_LED12R=2
+CONFIG_ETRAX_DEBUG_PORT0=y
+# CONFIG_ETRAX_DEBUG_PORT1 is not set
+# CONFIG_ETRAX_DEBUG_PORT2 is not set
+# CONFIG_ETRAX_DEBUG_PORT3 is not set
+CONFIG_ETRAX_RESCUE_SER0=y
+# CONFIG_ETRAX_RESCUE_SER1 is not set
+# CONFIG_ETRAX_RESCUE_SER2 is not set
+# CONFIG_ETRAX_RESCUE_SER3 is not set
+CONFIG_ETRAX_DEF_R_WAITSTATES=95a6
+CONFIG_ETRAX_DEF_R_BUS_CONFIG=104
+# CONFIG_ETRAX_SDRAM is not set
+CONFIG_ETRAX_DEF_R_DRAM_CONFIG=1a200040
+CONFIG_ETRAX_DEF_R_DRAM_TIMING=5611
+CONFIG_ETRAX_DEF_R_PORT_PA_DIR=1d
+CONFIG_ETRAX_DEF_R_PORT_PA_DATA=f0
+CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG=00
+CONFIG_ETRAX_DEF_R_PORT_PB_DIR=1e
+CONFIG_ETRAX_DEF_R_PORT_PB_DATA=f3
+# CONFIG_ETRAX_SOFT_SHUTDOWN is not set
+
+#
+# Drivers for ETRAX 100LX built-in interfaces
+#
+CONFIG_ETRAX_ETHERNET=y
+CONFIG_NET_ETHERNET=y
+# CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK is not set
+CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY=y
+# CONFIG_ETRAX_ETHERNET_LPSLAVE is not set
+CONFIG_ETRAX_SERIAL=y
+CONFIG_ETRAX_SERIAL_PORT0=y
+# CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB is not set
+CONFIG_ETRAX_SERIAL_PORT1=y
+# CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB is not set
+# CONFIG_ETRAX_SERIAL_PORT2 is not set
+# CONFIG_ETRAX_SERIAL_PORT3 is not set
+# CONFIG_ETRAX_RS485 is not set
+# CONFIG_ETRAX_SYNCHRONOUS_SERIAL is not set
+# CONFIG_ETRAX_IDE is not set
+CONFIG_ETRAX_AXISFLASHMAP=y
+CONFIG_ETRAX_PTABLE_SECTOR=65536
+CONFIG_MTD=y
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_AMDSTD=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_ETRAX_I2C=y
+CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C=y
+# CONFIG_ETRAX_I2C_EEPROM is not set
+CONFIG_ETRAX_GPIO=y
+CONFIG_ETRAX_PA_BUTTON_BITMASK=02
+CONFIG_ETRAX_PA_CHANGEABLE_DIR=00
+CONFIG_ETRAX_PA_CHANGEABLE_BITS=FF
+CONFIG_ETRAX_PB_CHANGEABLE_DIR=00
+CONFIG_ETRAX_PB_CHANGEABLE_BITS=FF
+# CONFIG_ETRAX_USB_HOST is not set
+# CONFIG_USB is not set
+# CONFIG_ETRAX_DS1302 is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# RAM/ROM Device Drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_MTDRAM is not set
+
+#
+# Linearly Mapped Flash Device Drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_CFI_GEOMETRY is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_AMDSTD=y
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_NORA is not set
+# CONFIG_MTD_PNC2000 is not set
+# CONFIG_MTD_RPXLITE is not set
+# CONFIG_MTD_SC520CDP is not set
+# CONFIG_MTD_SBC_MEDIAGX is not set
+# CONFIG_MTD_ELAN_104NC is not set
+# CONFIG_MTD_SA1100 is not set
+# CONFIG_MTD_DC21285 is not set
+# CONFIG_MTD_CSTM_CFI_JEDEC is not set
+# CONFIG_MTD_JEDEC is not set
+# CONFIG_MTD_MIXMEM is not set
+# CONFIG_MTD_OCTAGON is not set
+# CONFIG_MTD_VMAX is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_NAND_SPIA is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+# CONFIG_BLK_DEV_IDE is not set
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_IDEDISK is not set
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_UNIX98_PTYS is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_CRAMFS=y
+CONFIG_RAMFS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_DEBUG is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_EXT2_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_NFS_FS is not set
+# CONFIG_NFS_V3 is not set
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_SUNRPC is not set
+# CONFIG_LOCKD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PROFILE is not set
diff --git a/arch/cris/arch-v10/drivers/Kconfig b/arch/cris/arch-v10/drivers/Kconfig
new file mode 100644
index 0000000..748374f
--- /dev/null
+++ b/arch/cris/arch-v10/drivers/Kconfig
@@ -0,0 +1,963 @@
+config ETRAX_ETHERNET
+	bool "Ethernet support"
+	depends on ETRAX_ARCH_V10
+	help
+	  This option enables the ETRAX 100LX built-in 10/100Mbit Ethernet
+	  controller.
+
+# this is just so that the user does not have to go into the
+# normal ethernet driver section just to enable ethernetworking
+config NET_ETHERNET
+	bool
+	depends on ETRAX_ETHERNET
+	default y
+
+choice
+	prompt "Network LED behavior"
+	depends on ETRAX_ETHERNET
+	default ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY
+
+config ETRAX_NETWORK_LED_ON_WHEN_LINK
+	bool "LED_on_when_link"
+	help
+	  Selecting LED_on_when_link will light the LED when there is a 
+	  connection and will flash off when there is activity. 
+
+	  Selecting LED_on_when_activity will light the LED only when 
+	  there is activity.
+
+	  This setting will also affect the behaviour of other activity LEDs 
+	  e.g. Bluetooth. 
+
+config ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY
+	bool "LED_on_when_activity"
+	help
+	  Selecting LED_on_when_link will light the LED when there is a 
+	  connection and will flash off when there is activity. 
+
+	  Selecting LED_on_when_activity will light the LED only when 
+	  there is activity.
+
+	  This setting will also affect the behaviour of other activity LEDs 
+	  e.g. Bluetooth. 
+
+endchoice
+
+config ETRAX_SERIAL
+	bool "Serial-port support"
+	depends on ETRAX_ARCH_V10
+	help
+	  Enables the ETRAX 100 serial driver for ser0 (ttyS0)
+	  You probably want this enabled.
+
+config ETRAX_SERIAL_FAST_TIMER
+	bool "Use fast timers for serial DMA flush (experimental)"
+	depends on ETRAX_SERIAL
+	help
+	  Select this to have the serial DMAs flushed at a higher rate than
+	  normally, possible by using the fast timer API, the timeout is
+	  approx. 4 character times.
+	  If unsure, say N.
+
+config ETRAX_SERIAL_FLUSH_DMA_FAST
+	bool "Fast serial port DMA flush"
+	depends on ETRAX_SERIAL && !ETRAX_SERIAL_FAST_TIMER
+	help
+	  Select this to have the serial DMAs flushed at a higher rate than
+	  normally possible through a fast timer interrupt (currently at
+	  15360 Hz).
+	  If unsure, say N.
+
+config ETRAX_SERIAL_RX_TIMEOUT_TICKS
+	int "Receive flush timeout (ticks) "
+	depends on ETRAX_SERIAL && !ETRAX_SERIAL_FAST_TIMER && !ETRAX_SERIAL_FLUSH_DMA_FAST
+	default "5"
+	help
+	  Number of timer ticks between flush of receive fifo (1 tick = 10ms).
+	  Try 0-3 for low latency applications.  Approx 5 for high load
+	  applications (e.g. PPP).  Maybe this should be more adaptive some
+	  day...
+
+config ETRAX_SERIAL_PORT0
+	bool "Serial port 0 enabled"
+	depends on ETRAX_SERIAL
+	help
+	  Enables the ETRAX 100 serial driver for ser0 (ttyS0)
+	  Normally you want this on, unless you use external DMA 1 that uses
+	  the same DMA channels.
+
+choice
+	prompt "Ser0 DMA out assignment"
+	depends on ETRAX_SERIAL_PORT0
+	default ETRAX_SERIAL_PORT0_DMA6_OUT
+
+config CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_OUT
+       bool "No DMA out"
+
+config CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
+       bool "DMA 6"
+
+endchoice
+
+choice
+	prompt "Ser0 DMA in assignment"
+	depends on ETRAX_SERIAL_PORT0
+	default ETRAX_SERIAL_PORT0_DMA7_IN
+
+config CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_IN
+       bool "No DMA in"
+
+config CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
+       bool "DMA 7"
+
+endchoice
+
+choice
+	prompt "Ser0 DTR, RI, DSR and CD assignment"
+	depends on ETRAX_SERIAL_PORT0
+	default ETRAX_SER0_DTR_RI_DSR_CD_ON_NONE
+
+config ETRAX_SER0_DTR_RI_DSR_CD_ON_NONE
+	bool "No_DTR_RI_DSR_CD"
+
+config ETRAX_SER0_DTR_RI_DSR_CD_ON_PA
+	bool "DTR_RI_DSR_CD_on_PA"
+
+config ETRAX_SER0_DTR_RI_DSR_CD_ON_PB
+	bool "DTR_RI_DSR_CD_on_PB"
+	help
+	  Enables the status and control signals DTR, RI, DSR and CD on PB for
+	  ser0.
+
+config ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+	bool "DTR_RI_DSR_CD_mixed_on_PA_and_PB"
+
+endchoice
+
+config ETRAX_SER0_DTR_ON_PA_BIT
+	int "Ser0 DTR on PA bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT0
+	default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+	default "4" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+
+config ETRAX_SER0_RI_ON_PA_BIT
+	int "Ser0 RI  on PA bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT0
+	default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+	default "5" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+
+config ETRAX_SER0_DSR_ON_PA_BIT
+	int "Ser0 DSR on PA bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT0
+	default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+	default "6" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+
+config ETRAX_SER0_CD_ON_PA_BIT
+	int "Ser0 CD  on PA bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT0
+	default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+	default "7" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+
+config ETRAX_SER0_DTR_ON_PB_BIT
+	int "Ser0 DTR on PB bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT0
+	default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+	default "4" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+	help
+	  Specify the pin of the PB port to carry the DTR signal for serial
+	  port 0.
+
+config ETRAX_SER0_RI_ON_PB_BIT
+	int "Ser0 RI  on PB bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT0
+	default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+	default "5" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+	help
+	  Specify the pin of the PB port to carry the RI signal for serial
+	  port 0.
+
+config ETRAX_SER0_DSR_ON_PB_BIT
+	int "Ser0 DSR on PB bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT0
+	default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+	default "6" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+	help
+	  Specify the pin of the PB port to carry the DSR signal for serial
+	  port 0.
+
+config ETRAX_SER0_CD_ON_PB_BIT
+	int "Ser0 CD  on PB bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT0
+	default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+	default "7" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+	help
+	  Specify the pin of the PB port to carry the CD signal for serial
+	  port 0.
+
+config ETRAX_SERIAL_PORT1
+	bool "Serial port 1 enabled"
+	depends on ETRAX_SERIAL
+	help
+	  Enables the ETRAX 100 serial driver for ser1 (ttyS1).
+
+choice
+	prompt "Ser1 DMA out assignment"
+	depends on ETRAX_SERIAL_PORT1
+	default ETRAX_SERIAL_PORT1_DMA8_OUT
+
+config CONFIG_ETRAX_SERIAL_PORT1_NO_DMA_OUT
+       bool "No DMA out"
+
+config CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT
+       bool "DMA 8"
+
+endchoice
+
+choice
+	prompt "Ser1 DMA in assignment"
+	depends on ETRAX_SERIAL_PORT1
+	default ETRAX_SERIAL_PORT1_DMA9_IN
+
+config CONFIG_ETRAX_SERIAL_PORT1_NO_DMA_IN
+       bool "No DMA in"
+
+config CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN
+       bool "DMA 9"
+
+endchoice
+
+choice
+	prompt "Ser1 DTR, RI, DSR and CD assignment"
+	depends on ETRAX_SERIAL_PORT1
+	default ETRAX_SER1_DTR_RI_DSR_CD_ON_NONE
+
+config ETRAX_SER1_DTR_RI_DSR_CD_ON_NONE
+	bool "No_DTR_RI_DSR_CD"
+
+config ETRAX_SER1_DTR_RI_DSR_CD_ON_PA
+	bool "DTR_RI_DSR_CD_on_PA"
+
+config ETRAX_SER1_DTR_RI_DSR_CD_ON_PB
+	bool "DTR_RI_DSR_CD_on_PB"
+	help
+	  Enables the status and control signals DTR, RI, DSR and CD on PB for
+	  ser1.
+
+config ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+	bool "DTR_RI_DSR_CD_mixed_on_PA_and_PB"
+
+endchoice
+
+config ETRAX_SER1_DTR_ON_PA_BIT
+	int "Ser1 DTR on PA bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT1
+	default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+	default "4" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+
+config ETRAX_SER1_RI_ON_PA_BIT
+	int "Ser1 RI  on PA bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT1
+	default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+	default "5" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+
+config ETRAX_SER1_DSR_ON_PA_BIT
+	int "Ser1 DSR on PA bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT1
+	default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+	default "6" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+
+config ETRAX_SER1_CD_ON_PA_BIT
+	int "Ser1 CD  on PA bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT1
+	default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+	default "7" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+
+config ETRAX_SER1_DTR_ON_PB_BIT
+	int "Ser1 DTR on PB bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT1
+	default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+	default "4" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+	help
+	  Specify the pin of the PB port to carry the DTR signal for serial
+	  port 1.
+
+config ETRAX_SER1_RI_ON_PB_BIT
+	int "Ser1 RI  on PB bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT1
+	default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+	default "5" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+	help
+	  Specify the pin of the PB port to carry the RI signal for serial
+	  port 1.
+
+config ETRAX_SER1_DSR_ON_PB_BIT
+	int "Ser1 DSR on PB bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT1
+	default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+	default "6" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+	help
+	  Specify the pin of the PB port to carry the DSR signal for serial
+	  port 1.
+
+config ETRAX_SER1_CD_ON_PB_BIT
+	int "Ser1 CD  on PB bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT1
+	default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+	default "7" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+	help
+	  Specify the pin of the PB port to carry the CD signal for serial
+	  port 1.
+
+comment "Make sure you dont have the same PB bits more than once!"
+	depends on ETRAX_SERIAL && ETRAX_SER0_DTR_RI_DSR_CD_ON_PB && ETRAX_SER1_DTR_RI_DSR_CD_ON_PB
+
+config ETRAX_SERIAL_PORT2
+	bool "Serial port 2 enabled"
+	depends on ETRAX_SERIAL
+	help
+	  Enables the ETRAX 100 serial driver for ser2 (ttyS2).
+
+choice
+	prompt "Ser2 DMA out assignment"
+	depends on ETRAX_SERIAL_PORT2
+	default ETRAX_SERIAL_PORT2_DMA2_OUT
+
+config CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_OUT
+       bool "No DMA out"
+
+config CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
+       bool "DMA 2"
+
+endchoice
+
+choice
+	prompt "Ser2 DMA in assignment"
+	depends on ETRAX_SERIAL_PORT2
+	default ETRAX_SERIAL_PORT2_DMA3_IN
+
+config CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_IN
+       bool "No DMA in"
+
+config CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
+       bool "DMA 3"
+
+endchoice
+
+choice
+	prompt "Ser2 DTR, RI, DSR and CD assignment"
+	depends on ETRAX_SERIAL_PORT2
+	default ETRAX_SER2_DTR_RI_DSR_CD_ON_NONE
+
+config ETRAX_SER2_DTR_RI_DSR_CD_ON_NONE
+	bool "No_DTR_RI_DSR_CD"
+
+config ETRAX_SER2_DTR_RI_DSR_CD_ON_PA
+	bool "DTR_RI_DSR_CD_on_PA"
+	help
+	  Enables the status and control signals DTR, RI, DSR and CD on PA for
+	  ser2.
+
+config ETRAX_SER2_DTR_RI_DSR_CD_ON_PB
+	bool "DTR_RI_DSR_CD_on_PB"
+
+config ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+	bool "DTR_RI_DSR_CD_mixed_on_PA_and_PB"
+
+endchoice
+
+config ETRAX_SER2_DTR_ON_PA_BIT
+	int "Ser2 DTR on PA bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT2
+	default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+	default "4" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+	help
+	  Specify the pin of the PA port to carry the DTR signal for serial
+	  port 2.
+
+config ETRAX_SER2_RI_ON_PA_BIT
+	int "Ser2 RI  on PA bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT2
+	default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+	default "5" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+	help
+	  Specify the pin of the PA port to carry the RI signal for serial
+	  port 2.
+
+config ETRAX_SER2_DSR_ON_PA_BIT
+	int "Ser2 DSR on PA bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT2
+	default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+	default "6" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+	help
+	  Specify the pin of the PA port to carry the DTR signal for serial
+	  port 2.
+
+config ETRAX_SER2_CD_ON_PA_BIT
+	int "Ser2 CD  on PA bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT2
+	default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+	default "7" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+	help
+	  Specify the pin of the PA port to carry the CD signal for serial
+	  port 2.
+
+config ETRAX_SER2_DTR_ON_PB_BIT
+	int "Ser2 DTR on PB bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT2
+	default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+	default "4" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+
+config ETRAX_SER2_RI_ON_PB_BIT
+	int "Ser2 RI  on PB bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT2
+	default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+	default "5" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+
+config ETRAX_SER2_DSR_ON_PB_BIT
+	int "Ser2 DSR on PB bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT2
+	default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+	default "6" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+
+config ETRAX_SER2_CD_ON_PB_BIT
+	int "Ser2 CD  on PB bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT2
+	default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+	default "7" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+
+config ETRAX_SERIAL_PORT3
+	bool "Serial port 3 enabled"
+	depends on ETRAX_SERIAL
+	help
+	  Enables the ETRAX 100 serial driver for ser3 (ttyS3).
+
+choice
+	prompt "Ser3 DMA out assignment"
+	depends on ETRAX_SERIAL_PORT3
+	default ETRAX_SERIAL_PORT3_DMA4_OUT
+
+config CONFIG_ETRAX_SERIAL_PORT3_NO_DMA_OUT
+       bool "No DMA out"
+
+config CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT
+       bool "DMA 4"
+
+endchoice
+
+choice
+	prompt "Ser3 DMA in assignment"
+	depends on ETRAX_SERIAL_PORT3
+	default ETRAX_SERIAL_PORT3_DMA5_IN
+
+config CONFIG_ETRAX_SERIAL_PORT3_NO_DMA_IN
+       bool "No DMA in"
+
+config CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN
+       bool "DMA 5"
+
+endchoice
+
+choice
+	prompt "Ser3 DTR, RI, DSR and CD assignment"
+	depends on ETRAX_SERIAL_PORT3
+	default ETRAX_SER3_DTR_RI_DSR_CD_ON_NONE
+
+config ETRAX_SER3_DTR_RI_DSR_CD_ON_NONE
+	bool "No_DTR_RI_DSR_CD"
+
+config ETRAX_SER3_DTR_RI_DSR_CD_ON_PA
+	bool "DTR_RI_DSR_CD_on_PA"
+
+config ETRAX_SER3_DTR_RI_DSR_CD_ON_PB
+	bool "DTR_RI_DSR_CD_on_PB"
+
+config ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+	bool "DTR_RI_DSR_CD_mixed_on_PA_and_PB"
+
+endchoice
+
+config ETRAX_SER3_DTR_ON_PA_BIT
+	int "Ser3 DTR on PA bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PA || ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT3
+	default "-1"
+
+config ETRAX_SER3_RI_ON_PA_BIT
+	int "Ser3 RI  on PA bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PA || ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT3
+	default "-1"
+
+config ETRAX_SER3_DSR_ON_PA_BIT
+	int "Ser3 DSR on PA bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PA || ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT3
+	default "-1"
+
+config ETRAX_SER3_CD_ON_PA_BIT
+	int "Ser3 CD  on PA bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PA || ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT3
+	default "-1"
+
+config ETRAX_SER3_DTR_ON_PB_BIT
+	int "Ser3 DTR on PB bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PB || ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT3
+	default "-1"
+
+config ETRAX_SER3_RI_ON_PB_BIT
+	int "Ser3 RI  on PB bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PB || ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT3
+	default "-1"
+
+config ETRAX_SER3_DSR_ON_PB_BIT
+	int "Ser3 DSR on PB bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PB || ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT3
+	default "-1"
+
+config ETRAX_SER3_CD_ON_PB_BIT
+	int "Ser3 CD  on PB bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PB || ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+	depends on ETRAX_SERIAL_PORT3
+	default "-1"
+
+config ETRAX_RS485
+	bool "RS-485 support"
+	depends on ETRAX_SERIAL
+	help
+	  Enables support for RS-485 serial communication.  For a primer on
+	  RS-485, see <http://www.hw.cz/english/docs/rs485/rs485.html>.
+
+config ETRAX_RS485_ON_PA
+	bool "RS-485 mode on PA"
+	depends on ETRAX_RS485
+	help
+	  Control Driver Output Enable on RS485 transceiver using a pin on PA
+	  port:
+	  Axis 2400/2401 uses PA 3.
+
+config ETRAX_RS485_ON_PA_BIT
+	int "RS-485 mode on PA bit"
+	depends on ETRAX_RS485_ON_PA
+	default "3"
+	help
+	  Control Driver Output Enable on RS485 transceiver using a this bit
+	  on PA port.
+
+config ETRAX_RS485_DISABLE_RECEIVER
+	bool "Disable serial receiver"
+	depends on ETRAX_RS485
+	help
+	  It's necessary to disable the serial receiver to avoid serial
+	  loopback.  Not all products are able to do this in software only.
+	  Axis 2400/2401 must disable receiver.
+
+config ETRAX_IDE
+	bool "ATA/IDE support"
+	select IDE
+	select BLK_DEV_IDE
+	select BLK_DEV_IDEDISK
+	select BLK_DEV_IDECD
+	select BLK_DEV_IDEDMA
+	select DMA_NONPCI
+	help
+	  Enable this to get support for ATA/IDE.
+	  You can't use paralell ports or SCSI ports
+	  at the same time.
+
+
+config ETRAX_IDE_DELAY
+	int "Delay for drives to regain consciousness"
+	depends on ETRAX_IDE
+	default 15
+	help
+	  Number of seconds to wait for IDE drives to spin up after an IDE
+	  reset.
+choice
+	prompt "IDE reset pin"
+	depends on ETRAX_IDE
+	default ETRAX_IDE_PB7_RESET
+
+config ETRAX_IDE_PB7_RESET
+	bool "Port_PB_Bit_7"
+	help
+	  IDE reset on pin 7 on port B
+
+config ETRAX_IDE_G27_RESET
+        bool "Port_G_Bit_27"
+	help
+	  IDE reset on pin 27 on port G
+
+endchoice
+
+
+config ETRAX_USB_HOST
+	bool "USB host"
+	help
+	   This option enables the host functionality of the ETRAX 100LX
+	   built-in USB controller. In host mode the controller is designed
+	   for CTRL and BULK traffic only, INTR traffic may work as well
+	   however (depending on the requirements of timeliness).
+
+config USB
+       tristate
+       depends on ETRAX_USB_HOST
+       default y
+
+config ETRAX_USB_HOST_PORT1
+       bool "  USB port 1 enabled"
+       depends on ETRAX_USB_HOST
+       default n
+
+config ETRAX_USB_HOST_PORT2
+       bool "  USB port 2 enabled"
+       depends on ETRAX_USB_HOST
+       default n
+
+config ETRAX_AXISFLASHMAP
+	bool "Axis flash-map support"
+	depends on ETRAX_ARCH_V10
+	help
+	  This option enables MTD mapping of flash devices.  Needed to use
+	  flash memories.  If unsure, say Y.
+
+config ETRAX_PTABLE_SECTOR
+	int "Byte-offset of partition table sector"
+	depends on ETRAX_AXISFLASHMAP
+	default "65536"
+	help
+	  Byte-offset of the partition table in the first flash chip.
+	  The default value is 64kB and should not be changed unless
+	  you know exactly what you are doing. The only valid reason
+	  for changing this is when the flash block size is bigger
+	  than 64kB (e.g. when using two parallel 16 bit flashes).
+
+# here we define the CONFIG_'s necessary to enable MTD support
+# for the flash
+config MTD
+	tristate
+	depends on ETRAX_AXISFLASHMAP
+	default y
+	help
+	  Memory Technology Devices are flash, RAM and similar chips, often
+	  used for solid state file systems on embedded devices. This option
+	  will provide the generic support for MTD drivers to register
+	  themselves with the kernel and for potential users of MTD devices
+	  to enumerate the devices which are present and obtain a handle on
+	  them. It will also allow you to select individual drivers for 
+	  particular hardware and users of MTD devices. If unsure, say N.
+
+config MTD_CFI
+	tristate
+	depends on ETRAX_AXISFLASHMAP
+	default y
+	help
+	  The Common Flash Interface specification was developed by Intel,
+	  AMD and other flash manufactures that provides a universal method
+	  for probing the capabilities of flash devices. If you wish to
+	  support any device that is CFI-compliant, you need to enable this
+	  option. Visit <http://www.amd.com/products/nvd/overview/cfi.html>
+	  for more information on CFI.
+
+config MTD_CFI_AMDSTD
+	tristate
+	depends on ETRAX_AXISFLASHMAP
+	default y
+	help
+	  The Common Flash Interface defines a number of different command
+	  sets which a CFI-compliant chip may claim to implement. This code
+	  provides support for one of those command sets, used on chips 
+	  chips including the AMD Am29LV320.
+
+config MTD_OBSOLETE_CHIPS
+	bool
+	depends on ETRAX_AXISFLASHMAP
+	default y
+	help
+	  This option does not enable any code directly, but will allow you to
+	  select some other chip drivers which are now considered obsolete,
+	  because the generic CONFIG_JEDEC_PROBE code above should now detect
+	  the chips which are supported by these drivers, and allow the generic
+	  CFI-compatible drivers to drive the chips. Say 'N' here unless you have
+	  already tried the CONFIG_JEDEC_PROBE method and reported its failure
+	  to the MTD mailing list at <linux-mtd@lists.infradead.org>
+
+config MTD_AMDSTD
+	tristate
+	depends on ETRAX_AXISFLASHMAP
+	default y
+	help
+	  This option enables support for flash chips using AMD-compatible
+	  commands, including some which are not CFI-compatible and hence 
+	  cannot be used with the CONFIG_MTD_CFI_AMDSTD option.
+
+	  It also works on AMD compatible chips that do conform to CFI.
+
+config MTD_CHAR
+	tristate
+	depends on ETRAX_AXISFLASHMAP
+	default y
+	help
+	  This provides a character device for each MTD device present in
+	  the system, allowing the user to read and write directly to the
+	  memory chips, and also use ioctl() to obtain information about
+	  the device, or to erase parts of it.
+
+config MTD_BLOCK
+	tristate
+	depends on ETRAX_AXISFLASHMAP
+	default y
+	---help---
+	  Although most flash chips have an erase size too large to be useful
+	  as block devices, it is possible to use MTD devices which are based
+	  on RAM chips in this manner. This block device is a user of MTD
+	  devices performing that function.
+
+	  At the moment, it is also required for the Journalling Flash File
+	  System(s) to obtain a handle on the MTD device when it's mounted
+	  (although JFFS and JFFS2 don't actually use any of the functionality
+	  of the mtdblock device).
+
+	  Later, it may be extended to perform read/erase/modify/write cycles
+	  on flash chips to emulate a smaller block size. Needless to say,
+	  this is very unsafe, but could be useful for file systems which are
+	  almost never written to.
+
+	  You do not need this option for use with the DiskOnChip devices. For
+	  those, enable NFTL support (CONFIG_NFTL) instead.
+
+config MTD_PARTITIONS
+	tristate
+	depends on ETRAX_AXISFLASHMAP
+	default y
+	help
+	  If you have a device which needs to divide its flash chip(s) up
+	  into multiple 'partitions', each of which appears to the user as
+	  a separate MTD device, you require this option to be enabled. If
+	  unsure, say 'Y'.
+
+	  Note, however, that you don't need this option for the DiskOnChip
+	  devices. Partitioning on NFTL 'devices' is a different - that's the
+	  'normal' form of partitioning used on a block device.
+
+config MTD_CONCAT
+	tristate
+	depends on ETRAX_AXISFLASHMAP
+	default y
+
+config ETRAX_I2C
+	bool "I2C support"
+	depends on ETRAX_ARCH_V10
+	help
+	  Enables an I2C driver on ETRAX100.
+	  EXAMPLE usage:
+	  i2c_arg = I2C_WRITEARG(STA013_WRITE_ADDR, reg, val);
+	  ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_WRITEREG), i2c_arg);
+	  i2c_arg = I2C_READARG(STA013_READ_ADDR, reg);
+	  val = ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_READREG), i2c_arg);
+
+# this is true for most products since PB-I2C seems to be somewhat
+# flawed.. 
+config ETRAX_I2C_USES_PB_NOT_PB_I2C
+	bool "I2C uses PB not PB-I2C"
+	depends on ETRAX_I2C
+	help
+	  Select whether to use the special I2C mode in the PB I/O register or
+	  not.  This option needs to be selected in order to use some drivers
+	  that access the I2C I/O pins directly instead of going through the
+	  I2C driver, like the DS1302 realtime-clock driver.  If you are
+	  uncertain, choose Y here.
+
+config ETRAX_I2C_DATA_PORT
+	int "I2C SDA bit number"
+	depends on ETRAX_I2C_USES_PB_NOT_PB_I2C
+	default "0"
+	help
+	  Selects the pin on Port B where the data pin is connected
+
+config ETRAX_I2C_CLK_PORT
+	int "I2C SCL bit number"
+	depends on ETRAX_I2C_USES_PB_NOT_PB_I2C
+	default "1"
+	help
+	  Select the pin on Port B where the clock pin is connected
+
+config ETRAX_I2C_EEPROM
+	bool "I2C EEPROM (non-volatile RAM) support"
+	depends on ETRAX_I2C
+	help
+	  Enables I2C EEPROM (non-volatile RAM) on PB0 and PB1 using the I2C
+	  driver.  Select size option: Probed, 2k, 8k, 16k.
+	  (Probing works for 2k and 8k but not that well for 16k)
+
+choice
+	prompt "EEPROM size"
+	depends on ETRAX_I2C_EEPROM
+	default ETRAX_I2C_EEPROM_PROBE
+
+config ETRAX_I2C_EEPROM_PROBE
+	bool "Probed"
+	help
+	  Specifies size or auto probe of the EEPROM size.
+	  Options: Probed, 2k, 8k, 16k.
+	  (Probing works for 2k and 8k but not that well for 16k)
+
+config ETRAX_I2C_EEPROM_2KB
+	bool "2kB"
+	help
+	  Use a 2kB EEPROM.
+
+config ETRAX_I2C_EEPROM_8KB
+	bool "8kB"
+	help
+	  Use a 8kB EEPROM.
+
+config ETRAX_I2C_EEPROM_16KB
+	bool "16kB"
+	help
+	  Use a 16kB EEPROM.
+
+endchoice
+
+config ETRAX_GPIO
+	bool "GPIO support"
+	depends on ETRAX_ARCH_V10
+	---help---
+	  Enables the ETRAX general port device (major 120, minors 0 and 1).
+	  You can use this driver to access the general port bits. It supports
+	  these ioctl's:
+	  #include <linux/etraxgpio.h>
+	  fd = open("/dev/gpioa", O_RDWR); // or /dev/gpiob
+	  ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_SETBITS), bits_to_set);
+	  ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_CLRBITS), bits_to_clear);
+	  val = ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_READBITS), NULL);
+	  Remember that you need to setup the port directions appropriately in
+	  the General configuration.
+
+config ETRAX_PA_BUTTON_BITMASK
+	hex "PA-buttons bitmask"
+	depends on ETRAX_GPIO
+	default "02"
+	help
+	  This is a bitmask with information about what bits on PA that
+	  are used for buttons.
+	  Most products has a so called TEST button on PA1, if that's true
+	  use 02 here.
+	  Use 00 if there are no buttons on PA.
+	  If the bitmask is <> 00 a button driver will be included in the gpio
+	  driver. ETRAX general I/O support must be enabled.
+
+config ETRAX_PA_CHANGEABLE_DIR
+	hex "PA user changeable dir mask"
+	depends on ETRAX_GPIO
+	default "00"
+	help
+	  This is a bitmask with information of what bits in PA that a user
+	  can change direction on using ioctl's.
+	  Bit set = changeable.
+	  You probably want 00 here.
+
+config ETRAX_PA_CHANGEABLE_BITS
+	hex "PA user changeable bits mask"
+	depends on ETRAX_GPIO
+	default "FF"
+	help
+	  This is a bitmask with information of what bits in PA that a user
+	  can change change the value on using ioctl's.
+	  Bit set = changeable.
+	  You probably want 00 here.
+
+config ETRAX_PB_CHANGEABLE_DIR
+	hex "PB user changeable dir mask"
+	depends on ETRAX_GPIO
+	default "00"
+	help
+	  This is a bitmask with information of what bits in PB that a user
+	  can change direction on using ioctl's.
+	  Bit set = changeable.
+	  You probably want 00 here.
+
+config ETRAX_PB_CHANGEABLE_BITS
+	hex "PB user changeable bits mask"
+	depends on ETRAX_GPIO
+	default "FF"
+	help
+	  This is a bitmask with information of what bits in PB that a user
+	  can change the value on using ioctl's.
+	  Bit set = changeable.
+	  You probably want 00 here.
+
+config ETRAX_RTC
+	bool "Real Time Clock support"
+	depends on ETRAX_ARCH_V10
+	help
+	  Enables drivers for the Real-Time Clock battery-backed chips on 
+	  some products. The kernel reads the time when booting, and
+	  the date can be set using ioctl(fd, RTC_SET_TIME, &rt) with rt a
+	  rtc_time struct (see <file:include/asm-cris/rtc.h>) on the /dev/rtc
+	  device, major 121.  You can check the time with cat /proc/rtc, but
+	  normal time reading should be done using libc function time and
+	  friends.
+
+choice
+	prompt "RTC chip"
+	depends on ETRAX_RTC
+	default ETRAX_DS1302
+
+config ETRAX_DS1302
+	bool "DS1302"
+	help
+	  Enables the driver for the DS1302 Real-Time Clock battery-backed
+	  chip on some products. 
+
+config ETRAX_PCF8563
+	bool "PCF8563"
+	help
+	  Enables the driver for the PCF8563 Real-Time Clock battery-backed
+	  chip on some products.  
+
+endchoice
+
+config ETRAX_DS1302_RST_ON_GENERIC_PORT
+	bool "DS1302 RST on Generic Port"
+	depends on ETRAX_DS1302
+	help
+	  If your product has the RST signal line for the DS1302 RTC on the
+	  Generic Port then say Y here, otherwise leave it as N in which
+	  case the RST signal line is assumed to be connected to Port PB
+	  (just like the SCL and SDA lines).
+
+config ETRAX_DS1302_RSTBIT
+	int "DS1302 RST bit number"
+	depends on ETRAX_DS1302
+	default "2"
+	help
+	  This is the bit number for the RST signal line of the DS1302 RTC on
+	  the selected port. If you have selected the generic port then it
+	  should be bit 27, otherwise your best bet is bit 5.
+
+config ETRAX_DS1302_SCLBIT
+	int "DS1302 SCL bit number"
+	depends on ETRAX_DS1302
+	default "1"
+	help
+	  This is the bit number for the SCL signal line of the DS1302 RTC on
+	  Port PB. This is probably best left at 3.
+
+config ETRAX_DS1302_SDABIT
+	int "DS1302 SDA bit number"
+	depends on ETRAX_DS1302
+	default "0"
+	help
+	  This is the bit number for the SDA signal line of the DS1302 RTC on
+	  Port PB. This is probably best left at 2.
+
+config ETRAX_DS1302_TRICKLE_CHARGE
+	int "DS1302 Trickle charger value"
+	depends on ETRAX_DS1302
+	default "0"
+	help
+	  This controls the initial value of the trickle charge register.
+	  0 = disabled (use this if you are unsure or have a non rechargable battery)
+	  Otherwise the following values can be OR:ed together to control the 
+	  charge current:
+	  1 = 2kohm, 2 = 4kohm, 3 = 4kohm
+	  4 = 1 diode, 8 = 2 diodes
+	  Allowed values are (increasing current): 0, 11, 10, 9, 7, 6, 5
+
+
diff --git a/arch/cris/arch-v10/drivers/Makefile b/arch/cris/arch-v10/drivers/Makefile
new file mode 100644
index 0000000..20258e3
--- /dev/null
+++ b/arch/cris/arch-v10/drivers/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for Etrax-specific drivers
+#
+
+obj-$(CONFIG_ETRAX_AXISFLASHMAP)        += axisflashmap.o
+obj-$(CONFIG_ETRAX_I2C) 	        += i2c.o
+obj-$(CONFIG_ETRAX_I2C_EEPROM)          += eeprom.o
+obj-$(CONFIG_ETRAX_GPIO) 	        += gpio.o
+obj-$(CONFIG_ETRAX_DS1302)              += ds1302.o
+obj-$(CONFIG_ETRAX_PCF8563)		+= pcf8563.o
+
+
diff --git a/arch/cris/arch-v10/drivers/axisflashmap.c b/arch/cris/arch-v10/drivers/axisflashmap.c
new file mode 100644
index 0000000..fb7d485
--- /dev/null
+++ b/arch/cris/arch-v10/drivers/axisflashmap.c
@@ -0,0 +1,541 @@
+/*
+ * Physical mapping layer for MTD using the Axis partitiontable format
+ *
+ * Copyright (c) 2001, 2002 Axis Communications AB
+ *
+ * This file is under the GPL.
+ *
+ * First partition is always sector 0 regardless of if we find a partitiontable
+ * or not. In the start of the next sector, there can be a partitiontable that
+ * tells us what other partitions to define. If there isn't, we use a default
+ * partition split defined below.
+ *
+ * $Log: axisflashmap.c,v $
+ * Revision 1.10  2004/08/16 12:37:22  starvik
+ * Merge of Linux 2.6.8
+ *
+ * Revision 1.8  2004/05/14 07:58:03  starvik
+ * Merge of changes from 2.4
+ *
+ * Revision 1.6  2003/07/04 08:27:37  starvik
+ * Merge of Linux 2.5.74
+ *
+ * Revision 1.5  2002/12/11 13:13:57  starvik
+ * Added arch/ to v10 specific includes
+ * Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer)
+ *
+ * Revision 1.4  2002/11/20 11:56:10  starvik
+ * Merge of Linux 2.5.48
+ *
+ * Revision 1.3  2002/11/13 14:54:13  starvik
+ * Copied from linux 2.4
+ *
+ * Revision 1.28  2002/10/01 08:08:43  jonashg
+ * The first partition ends at the start of the partition table.
+ *
+ * Revision 1.27  2002/08/21 09:23:13  jonashg
+ * Speling.
+ *
+ * Revision 1.26  2002/08/21 08:35:20  jonashg
+ * Cosmetic change to printouts.
+ *
+ * Revision 1.25  2002/08/21 08:15:42  jonashg
+ * Made it compile even without CONFIG_MTD_CONCAT defined.
+ *
+ * Revision 1.24  2002/08/20 13:12:35  jonashg
+ * * New approach to probing. Probe cse0 and cse1 separately and (mtd)concat
+ *   the results.
+ * * Removed compile time tests concerning how the mtdram driver has been
+ *   configured. The user will know about the misconfiguration at runtime
+ *   instead. (The old approach made it impossible to use mtdram for anything
+ *   else than RAM boot).
+ *
+ * Revision 1.23  2002/05/13 12:12:28  johana
+ * Allow compile without CONFIG_MTD_MTDRAM but warn at compiletime and
+ * be informative at runtime.
+ *
+ * Revision 1.22  2002/05/13 10:24:44  johana
+ * Added #if checks on MTDRAM CONFIG
+ *
+ * Revision 1.21  2002/05/06 16:05:20  johana
+ * Removed debug printout.
+ *
+ * Revision 1.20  2002/05/06 16:03:00  johana
+ * No more cramfs as root hack in generic code.
+ * It's handled by axisflashmap using mtdram.
+ *
+ * Revision 1.19  2002/03/15 17:10:28  bjornw
+ * Changed comment about cached access since we changed this before
+ *
+ * Revision 1.18  2002/03/05 17:06:15  jonashg
+ * Try amd_flash probe before cfi_probe since amd_flash driver can handle two
+ * (or more) flash chips of different model and the cfi driver cannot.
+ *
+ * Revision 1.17  2001/11/12 19:42:38  pkj
+ * Fixed compiler warnings.
+ *
+ * Revision 1.16  2001/11/08 11:18:58  jonashg
+ * Always read from uncached address to avoid problems with flushing
+ * cachelines after write and MTD-erase. No performance loss have been
+ * seen yet.
+ *
+ * Revision 1.15  2001/10/19 12:41:04  jonashg
+ * Name of probe has changed in MTD.
+ *
+ * Revision 1.14  2001/09/21 07:14:10  jonashg
+ * Made root filesystem (cramfs) use mtdblock driver when booting from flash.
+ *
+ * Revision 1.13  2001/08/15 13:57:35  jonashg
+ * Entire MTD updated to the linux 2.4.7 version.
+ *
+ * Revision 1.12  2001/06/11 09:50:30  jonashg
+ * Oops, 2MB is 0x200000 bytes.
+ *
+ * Revision 1.11  2001/06/08 11:39:44  jonashg
+ * Changed sizes and offsets in axis_default_partitions to use
+ * CONFIG_ETRAX_PTABLE_SECTOR.
+ *
+ * Revision 1.10  2001/05/29 09:42:03  jonashg
+ * Use macro for end marker length instead of sizeof.
+ *
+ * Revision 1.9  2001/05/29 08:52:52  jonashg
+ * Gave names to the magic fours (size of the ptable end marker).
+ *
+ * Revision 1.8  2001/05/28 15:36:20  jonashg
+ * * Removed old comment about ptable location in flash (it's a CONFIG_ option).
+ * * Variable ptable was initialized twice to the same value.
+ *
+ * Revision 1.7  2001/04/05 13:41:46  markusl
+ * Updated according to review remarks
+ *
+ * Revision 1.6  2001/03/07 09:21:21  bjornw
+ * No need to waste .data
+ *
+ * Revision 1.5  2001/03/06 16:27:01  jonashg
+ * Probe the entire flash area for flash devices.
+ *
+ * Revision 1.4  2001/02/23 12:47:15  bjornw
+ * Uncached flash in LOW_MAP moved from 0xe to 0x8
+ *
+ * Revision 1.3  2001/02/16 12:11:45  jonashg
+ * MTD driver amd_flash is now included in MTD CVS repository.
+ * (It's now in drivers/mtd).
+ *
+ * Revision 1.2  2001/02/09 11:12:22  jonashg
+ * Support for AMD compatible non-CFI flash chips.
+ * Only tested with Toshiba TC58FVT160 so far.
+ *
+ * Revision 1.1  2001/01/12 17:01:18  bjornw
+ * * Added axisflashmap.c, a physical mapping for MTD that reads and understands
+ *   Axis partition-table format.
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <linux/mtd/concat.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/mtdram.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/axisflashmap.h>
+#include <asm/mmu.h>
+#include <asm/arch/sv_addr_ag.h>
+
+#ifdef CONFIG_CRIS_LOW_MAP
+#define FLASH_UNCACHED_ADDR  KSEG_8
+#define FLASH_CACHED_ADDR    KSEG_5
+#else
+#define FLASH_UNCACHED_ADDR  KSEG_E
+#define FLASH_CACHED_ADDR    KSEG_F
+#endif
+
+#if CONFIG_ETRAX_FLASH_BUSWIDTH==1
+#define flash_data __u8
+#elif CONFIG_ETRAX_FLASH_BUSWIDTH==2
+#define flash_data __u16
+#elif CONFIG_ETRAX_FLASH_BUSWIDTH==4
+#define flash_data __u16
+#endif
+
+/* From head.S */
+extern unsigned long romfs_start, romfs_length, romfs_in_flash;
+
+/* The master mtd for the entire flash. */
+struct mtd_info* axisflash_mtd = NULL;
+
+/* Map driver functions. */
+
+static map_word flash_read(struct map_info *map, unsigned long ofs)
+{
+	map_word tmp;
+	tmp.x[0] = *(flash_data *)(map->map_priv_1 + ofs);
+	return tmp;
+}
+
+static void flash_copy_from(struct map_info *map, void *to,
+			    unsigned long from, ssize_t len)
+{
+	memcpy(to, (void *)(map->map_priv_1 + from), len);
+}
+
+static void flash_write(struct map_info *map, map_word d, unsigned long adr)
+{
+	*(flash_data *)(map->map_priv_1 + adr) = (flash_data)d.x[0];
+}
+
+/*
+ * The map for chip select e0.
+ *
+ * We run into tricky coherence situations if we mix cached with uncached
+ * accesses to we only use the uncached version here.
+ *
+ * The size field is the total size where the flash chips may be mapped on the
+ * chip select. MTD probes should find all devices there and it does not matter
+ * if there are unmapped gaps or aliases (mirrors of flash devices). The MTD
+ * probes will ignore them.
+ *
+ * The start address in map_priv_1 is in virtual memory so we cannot use
+ * MEM_CSE0_START but must rely on that FLASH_UNCACHED_ADDR is the start
+ * address of cse0.
+ */
+static struct map_info map_cse0 = {
+	.name = "cse0",
+	.size = MEM_CSE0_SIZE,
+	.bankwidth = CONFIG_ETRAX_FLASH_BUSWIDTH,
+	.read = flash_read,
+	.copy_from = flash_copy_from,
+	.write = flash_write,
+	.map_priv_1 = FLASH_UNCACHED_ADDR
+};
+
+/*
+ * The map for chip select e1.
+ *
+ * If there was a gap between cse0 and cse1, map_priv_1 would get the wrong
+ * address, but there isn't.
+ */
+static struct map_info map_cse1 = {
+	.name = "cse1",
+	.size = MEM_CSE1_SIZE,
+	.bankwidth = CONFIG_ETRAX_FLASH_BUSWIDTH,
+	.read = flash_read,
+	.copy_from = flash_copy_from,
+	.write = flash_write,
+	.map_priv_1 = FLASH_UNCACHED_ADDR + MEM_CSE0_SIZE
+};
+
+/* If no partition-table was found, we use this default-set. */
+#define MAX_PARTITIONS         7  
+#define NUM_DEFAULT_PARTITIONS 3
+
+/*
+ * Default flash size is 2MB. CONFIG_ETRAX_PTABLE_SECTOR is most likely the
+ * size of one flash block and "filesystem"-partition needs 5 blocks to be able
+ * to use JFFS.
+ */
+static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = {
+	{
+		.name = "boot firmware",
+		.size = CONFIG_ETRAX_PTABLE_SECTOR,
+		.offset = 0
+	},
+	{
+		.name = "kernel",
+		.size = 0x200000 - (6 * CONFIG_ETRAX_PTABLE_SECTOR),
+		.offset = CONFIG_ETRAX_PTABLE_SECTOR
+	},
+	{
+		.name = "filesystem",
+		.size = 5 * CONFIG_ETRAX_PTABLE_SECTOR,
+		.offset = 0x200000 - (5 * CONFIG_ETRAX_PTABLE_SECTOR)
+	}
+};
+
+/* Initialize the ones normally used. */
+static struct mtd_partition axis_partitions[MAX_PARTITIONS] = {
+	{
+		.name = "part0",
+		.size = CONFIG_ETRAX_PTABLE_SECTOR,
+		.offset = 0
+	},
+	{
+		.name = "part1",
+		.size = 0,
+		.offset = 0
+	},
+	{
+		.name = "part2",
+		.size = 0,
+		.offset = 0
+	},
+	{
+		.name = "part3",
+		.size = 0,
+		.offset = 0
+	},
+	{
+		.name = "part4",
+		.size = 0,
+		.offset = 0
+	},
+	{
+		.name = "part5",
+		.size = 0,
+		.offset = 0
+	},
+	{
+		.name = "part6",
+		.size = 0,
+		.offset = 0
+	},
+};
+
+/*
+ * Probe a chip select for AMD-compatible (JEDEC) or CFI-compatible flash
+ * chips in that order (because the amd_flash-driver is faster).
+ */
+static struct mtd_info *probe_cs(struct map_info *map_cs)
+{
+	struct mtd_info *mtd_cs = NULL;
+
+	printk(KERN_INFO
+               "%s: Probing a 0x%08lx bytes large window at 0x%08lx.\n",
+	       map_cs->name, map_cs->size, map_cs->map_priv_1);
+
+#ifdef CONFIG_MTD_AMDSTD
+	mtd_cs = do_map_probe("amd_flash", map_cs);
+#endif
+#ifdef CONFIG_MTD_CFI
+	if (!mtd_cs) {
+		mtd_cs = do_map_probe("cfi_probe", map_cs);
+	}
+#endif
+
+	return mtd_cs;
+}
+
+/* 
+ * Probe each chip select individually for flash chips. If there are chips on
+ * both cse0 and cse1, the mtd_info structs will be concatenated to one struct
+ * so that MTD partitions can cross chip boundries.
+ *
+ * The only known restriction to how you can mount your chips is that each
+ * chip select must hold similar flash chips. But you need external hardware
+ * to do that anyway and you can put totally different chips on cse0 and cse1
+ * so it isn't really much of a restriction.
+ */
+static struct mtd_info *flash_probe(void)
+{
+	struct mtd_info *mtd_cse0;
+	struct mtd_info *mtd_cse1;
+	struct mtd_info *mtd_cse;
+
+	mtd_cse0 = probe_cs(&map_cse0);
+	mtd_cse1 = probe_cs(&map_cse1);
+
+	if (!mtd_cse0 && !mtd_cse1) {
+		/* No chip found. */
+		return NULL;
+	}
+
+	if (mtd_cse0 && mtd_cse1) {
+#ifdef CONFIG_MTD_CONCAT
+		struct mtd_info *mtds[] = { mtd_cse0, mtd_cse1 };
+		
+		/* Since the concatenation layer adds a small overhead we
+		 * could try to figure out if the chips in cse0 and cse1 are
+		 * identical and reprobe the whole cse0+cse1 window. But since
+		 * flash chips are slow, the overhead is relatively small.
+		 * So we use the MTD concatenation layer instead of further
+		 * complicating the probing procedure.
+		 */
+		mtd_cse = mtd_concat_create(mtds,
+					    sizeof(mtds) / sizeof(mtds[0]),
+					    "cse0+cse1");
+#else
+		printk(KERN_ERR "%s and %s: Cannot concatenate due to kernel "
+		       "(mis)configuration!\n", map_cse0.name, map_cse1.name);
+		mtd_cse = NULL;
+#endif
+		if (!mtd_cse) {
+			printk(KERN_ERR "%s and %s: Concatenation failed!\n",
+			       map_cse0.name, map_cse1.name);
+
+			/* The best we can do now is to only use what we found
+			 * at cse0.
+			 */ 
+			mtd_cse = mtd_cse0;
+			map_destroy(mtd_cse1);
+		}
+	} else {
+		mtd_cse = mtd_cse0? mtd_cse0 : mtd_cse1;
+	}
+
+	return mtd_cse;
+}
+
+/*
+ * Probe the flash chip(s) and, if it succeeds, read the partition-table
+ * and register the partitions with MTD.
+ */
+static int __init init_axis_flash(void)
+{
+	struct mtd_info *mymtd;
+	int err = 0;
+	int pidx = 0;
+	struct partitiontable_head *ptable_head = NULL;
+	struct partitiontable_entry *ptable;
+	int use_default_ptable = 1; /* Until proven otherwise. */
+	const char *pmsg = "  /dev/flash%d at 0x%08x, size 0x%08x\n";
+
+	if (!(mymtd = flash_probe())) {
+		/* There's no reason to use this module if no flash chip can
+		 * be identified. Make sure that's understood.
+		 */
+		printk(KERN_INFO "axisflashmap: Found no flash chip.\n");
+	} else {
+		printk(KERN_INFO "%s: 0x%08x bytes of flash memory.\n",
+		       mymtd->name, mymtd->size);
+		axisflash_mtd = mymtd;
+	}
+
+	if (mymtd) {
+		mymtd->owner = THIS_MODULE;
+		ptable_head = (struct partitiontable_head *)(FLASH_CACHED_ADDR +
+			      CONFIG_ETRAX_PTABLE_SECTOR +
+			      PARTITION_TABLE_OFFSET);
+	}
+	pidx++;  /* First partition is always set to the default. */
+
+	if (ptable_head && (ptable_head->magic == PARTITION_TABLE_MAGIC)
+	    && (ptable_head->size <
+		(MAX_PARTITIONS * sizeof(struct partitiontable_entry) +
+		PARTITIONTABLE_END_MARKER_SIZE))
+	    && (*(unsigned long*)((void*)ptable_head + sizeof(*ptable_head) +
+				  ptable_head->size -
+				  PARTITIONTABLE_END_MARKER_SIZE)
+		== PARTITIONTABLE_END_MARKER)) {
+		/* Looks like a start, sane length and end of a
+		 * partition table, lets check csum etc.
+		 */
+		int ptable_ok = 0;
+		struct partitiontable_entry *max_addr =
+			(struct partitiontable_entry *)
+			((unsigned long)ptable_head + sizeof(*ptable_head) +
+			 ptable_head->size);
+		unsigned long offset = CONFIG_ETRAX_PTABLE_SECTOR;
+		unsigned char *p;
+		unsigned long csum = 0;
+		
+		ptable = (struct partitiontable_entry *)
+			((unsigned long)ptable_head + sizeof(*ptable_head));
+
+		/* Lets be PARANOID, and check the checksum. */
+		p = (unsigned char*) ptable;
+
+		while (p <= (unsigned char*)max_addr) {
+			csum += *p++;
+			csum += *p++;
+			csum += *p++;
+			csum += *p++;
+		}
+		ptable_ok = (csum == ptable_head->checksum);
+
+		/* Read the entries and use/show the info.  */
+		printk(KERN_INFO " Found a%s partition table at 0x%p-0x%p.\n",
+		       (ptable_ok ? " valid" : "n invalid"), ptable_head,
+		       max_addr);
+
+		/* We have found a working bootblock.  Now read the
+		 * partition table.  Scan the table.  It ends when
+		 * there is 0xffffffff, that is, empty flash.
+		 */
+		while (ptable_ok
+		       && ptable->offset != 0xffffffff
+		       && ptable < max_addr
+		       && pidx < MAX_PARTITIONS) {
+
+			axis_partitions[pidx].offset = offset + ptable->offset;
+			axis_partitions[pidx].size = ptable->size;
+
+			printk(pmsg, pidx, axis_partitions[pidx].offset,
+			       axis_partitions[pidx].size);
+			pidx++;
+			ptable++;
+		}
+		use_default_ptable = !ptable_ok;
+	}
+
+	if (romfs_in_flash) {
+		/* Add an overlapping device for the root partition (romfs). */
+
+		axis_partitions[pidx].name = "romfs";
+		axis_partitions[pidx].size = romfs_length;
+		axis_partitions[pidx].offset = romfs_start - FLASH_CACHED_ADDR;
+		axis_partitions[pidx].mask_flags |= MTD_WRITEABLE;
+
+		printk(KERN_INFO
+                       " Adding readonly flash partition for romfs image:\n");
+		printk(pmsg, pidx, axis_partitions[pidx].offset,
+		       axis_partitions[pidx].size);
+		pidx++;
+	}
+
+        if (mymtd) {
+		if (use_default_ptable) {
+			printk(KERN_INFO " Using default partition table.\n");
+			err = add_mtd_partitions(mymtd, axis_default_partitions,
+						 NUM_DEFAULT_PARTITIONS);
+		} else {
+			err = add_mtd_partitions(mymtd, axis_partitions, pidx);
+		}
+
+		if (err) {
+			panic("axisflashmap could not add MTD partitions!\n");
+		}
+	}
+
+	if (!romfs_in_flash) {
+		/* Create an RAM device for the root partition (romfs). */
+
+#if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0)
+		/* No use trying to boot this kernel from RAM. Panic! */
+		printk(KERN_EMERG "axisflashmap: Cannot create an MTD RAM "
+		       "device due to kernel (mis)configuration!\n");
+		panic("This kernel cannot boot from RAM!\n");
+#else
+		struct mtd_info *mtd_ram;
+
+		mtd_ram = (struct mtd_info *)kmalloc(sizeof(struct mtd_info),
+						     GFP_KERNEL);
+		if (!mtd_ram) {
+			panic("axisflashmap couldn't allocate memory for "
+			      "mtd_info!\n");
+		}
+
+		printk(KERN_INFO " Adding RAM partition for romfs image:\n");
+		printk(pmsg, pidx, romfs_start, romfs_length);
+
+		err = mtdram_init_device(mtd_ram, (void*)romfs_start, 
+		                         romfs_length, "romfs");
+		if (err) {
+			panic("axisflashmap could not initialize MTD RAM "
+			      "device!\n");
+		}
+#endif
+	}
+
+	return err;
+}
+
+/* This adds the above to the kernels init-call chain. */
+module_init(init_axis_flash);
+
+EXPORT_SYMBOL(axisflash_mtd);
diff --git a/arch/cris/arch-v10/drivers/ds1302.c b/arch/cris/arch-v10/drivers/ds1302.c
new file mode 100644
index 0000000..fba530f
--- /dev/null
+++ b/arch/cris/arch-v10/drivers/ds1302.c
@@ -0,0 +1,602 @@
+/*!***************************************************************************
+*!
+*! FILE NAME  : ds1302.c
+*!
+*! DESCRIPTION: Implements an interface for the DS1302 RTC through Etrax I/O
+*!
+*! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init
+*!
+*! $Log: ds1302.c,v $
+*! Revision 1.14  2004/08/24 06:48:43  starvik
+*! Whitespace cleanup
+*!
+*! Revision 1.13  2004/05/28 09:26:59  starvik
+*! Modified I2C initialization to work in 2.6.
+*!
+*! Revision 1.12  2004/05/14 07:58:03  starvik
+*! Merge of changes from 2.4
+*!
+*! Revision 1.10  2004/02/04 09:25:12  starvik
+*! Merge of Linux 2.6.2
+*!
+*! Revision 1.9  2003/07/04 08:27:37  starvik
+*! Merge of Linux 2.5.74
+*!
+*! Revision 1.8  2003/04/09 05:20:47  starvik
+*! Merge of Linux 2.5.67
+*!
+*! Revision 1.6  2003/01/09 14:42:51  starvik
+*! Merge of Linux 2.5.55
+*!
+*! Revision 1.4  2002/12/11 13:13:57  starvik
+*! Added arch/ to v10 specific includes
+*! Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer)
+*!
+*! Revision 1.3  2002/11/20 11:56:10  starvik
+*! Merge of Linux 2.5.48
+*!
+*! Revision 1.2  2002/11/18 13:16:06  starvik
+*! Linux 2.5 port of latest 2.4 drivers
+*!
+*! Revision 1.15  2002/10/11 16:14:33  johana
+*! Added CONFIG_ETRAX_DS1302_TRICKLE_CHARGE and initial setting of the
+*! trcklecharge register.
+*!
+*! Revision 1.14  2002/10/10 12:15:38  magnusmn
+*! Added support for having the RST signal on bit g0
+*!
+*! Revision 1.13  2002/05/29 15:16:08  johana
+*! Removed unused variables.
+*!
+*! Revision 1.12  2002/04/10 15:35:25  johana
+*! Moved probe function closer to init function and marked it __init.
+*!
+*! Revision 1.11  2001/06/14 12:35:52  jonashg
+*! The ATA hack is back. It is unfortunately the only way to set g27 to output.
+*!
+*! Revision 1.9  2001/06/14 10:00:14  jonashg
+*! No need for tempudelay to be inline anymore (had to adjust the usec to
+*! loops conversion because of this to make it slow enough to be a udelay).
+*!
+*! Revision 1.8  2001/06/14 08:06:32  jonashg
+*! Made tempudelay delay usecs (well, just a tad more).
+*!
+*! Revision 1.7  2001/06/13 14:18:11  jonashg
+*! Only allow processes with SYS_TIME capability to set time and charge.
+*!
+*! Revision 1.6  2001/06/12 15:22:07  jonashg
+*! * Made init function __init.
+*! * Parameter to out_byte() is unsigned char.
+*! * The magic number 42 has got a name.
+*! * Removed comment about /proc (nothing is exported there).
+*!
+*! Revision 1.5  2001/06/12 14:35:13  jonashg
+*! Gave the module a name and added it to printk's.
+*!
+*! Revision 1.4  2001/05/31 14:53:40  jonashg
+*! Made tempudelay() inline so that the watchdog doesn't reset (see
+*! function comment).
+*!
+*! Revision 1.3  2001/03/26 16:03:06  bjornw
+*! Needs linux/config.h
+*!
+*! Revision 1.2  2001/03/20 19:42:00  bjornw
+*! Use the ETRAX prefix on the DS1302 options
+*!
+*! Revision 1.1  2001/03/20 09:13:50  magnusmn
+*! Linux 2.4 port
+*!
+*! Revision 1.10  2000/07/05 15:38:23  bjornw
+*! Dont update kernel time when a RTC_SET_TIME is done
+*!
+*! Revision 1.9  2000/03/02 15:42:59  macce
+*! * Hack to make RTC work on all 2100/2400
+*!
+*! Revision 1.8  2000/02/23 16:59:18  torbjore
+*! added setup of R_GEN_CONFIG when RTC is connected to the generic port.
+*!
+*! Revision 1.7  2000/01/17 15:51:43  johana
+*! Added RTC_SET_CHARGE ioctl to enable trickle charger.
+*!
+*! Revision 1.6  1999/10/27 13:19:47  bjornw
+*! Added update_xtime_from_cmos which reads back the updated RTC into the kernel.
+*! /dev/rtc calls it now.
+*!
+*! Revision 1.5  1999/10/27 12:39:37  bjornw
+*! Disabled superuser check. Anyone can now set the time.
+*!
+*! Revision 1.4  1999/09/02 13:27:46  pkj
+*! Added shadow for R_PORT_PB_CONFIG.
+*! Renamed port_g_shadow to port_g_data_shadow.
+*!
+*! Revision 1.3  1999/09/02 08:28:06  pkj
+*! Made it possible to select either port PB or the generic port for the RST
+*! signal line to the DS1302 RTC.
+*! Also make sure the RST bit is configured as output on Port PB (if used).
+*!
+*! Revision 1.2  1999/09/01 14:47:20  bjornw
+*! Added support for /dev/rtc operations with ioctl RD_TIME and SET_TIME to read
+*! and set the date. Register as major 121.
+*!
+*! Revision 1.1  1999/09/01 09:45:29  bjornw
+*! Implemented a DS1302 RTC driver.
+*!
+*!
+*! ---------------------------------------------------------------------------
+*!
+*! (C) Copyright 1999, 2000, 2001  Axis Communications AB, LUND, SWEDEN
+*!
+*! $Id: ds1302.c,v 1.14 2004/08/24 06:48:43 starvik Exp $
+*!
+*!***************************************************************************/
+
+#include <linux/config.h>
+
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <linux/bcd.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/arch/svinto.h>
+#include <asm/io.h>
+#include <asm/rtc.h>
+
+#define RTC_MAJOR_NR 121 /* local major, change later */
+
+static const char ds1302_name[] = "ds1302";
+
+/* The DS1302 might be connected to different bits on different products. 
+ * It has three signals - SDA, SCL and RST. RST and SCL are always outputs,
+ * but SDA can have a selected direction.
+ * For now, only PORT_PB is hardcoded.
+ */
+
+/* The RST bit may be on either the Generic Port or Port PB. */
+#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
+#define TK_RST_OUT(x) REG_SHADOW_SET(R_PORT_G_DATA,  port_g_data_shadow,  CONFIG_ETRAX_DS1302_RSTBIT, x)
+#define TK_RST_DIR(x)
+#else
+#define TK_RST_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x)
+#define TK_RST_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR,  port_pb_dir_shadow,  CONFIG_ETRAX_DS1302_RSTBIT, x)
+#endif
+
+
+#define TK_SDA_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_SDABIT, x)
+#define TK_SCL_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_SCLBIT, x)
+
+#define TK_SDA_IN()   ((*R_PORT_PB_READ >> CONFIG_ETRAX_DS1302_SDABIT) & 1)
+/* 1 is out, 0 is in */
+#define TK_SDA_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR,  port_pb_dir_shadow,  CONFIG_ETRAX_DS1302_SDABIT, x)
+#define TK_SCL_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR,  port_pb_dir_shadow,  CONFIG_ETRAX_DS1302_SCLBIT, x)
+
+
+/*
+ * The reason for tempudelay and not udelay is that loops_per_usec
+ * (used in udelay) is not set when functions here are called from time.c 
+ */
+
+static void tempudelay(int usecs) 
+{
+	volatile int loops;
+
+	for(loops = usecs * 12; loops > 0; loops--)
+		/* nothing */;	
+}
+
+
+/* Send 8 bits. */
+static void
+out_byte(unsigned char x) 
+{
+	int i;
+	TK_SDA_DIR(1);
+	for (i = 8; i--;) {
+		/* The chip latches incoming bits on the rising edge of SCL. */
+		TK_SCL_OUT(0);
+		TK_SDA_OUT(x & 1);
+		tempudelay(1);
+		TK_SCL_OUT(1);
+		tempudelay(1);
+		x >>= 1;
+	}
+	TK_SDA_DIR(0);
+}
+
+static unsigned char
+in_byte(void) 
+{
+	unsigned char x = 0;
+	int i;
+
+	/* Read byte. Bits come LSB first, on the falling edge of SCL.
+	 * Assume SDA is in input direction already.
+	 */
+	TK_SDA_DIR(0);
+
+	for (i = 8; i--;) {
+		TK_SCL_OUT(0);
+		tempudelay(1);
+		x >>= 1;
+		x |= (TK_SDA_IN() << 7);
+		TK_SCL_OUT(1);
+		tempudelay(1);
+	}
+
+	return x;
+}
+
+/* Prepares for a transaction by de-activating RST (active-low). */
+
+static void
+start(void) 
+{
+	TK_SCL_OUT(0);
+	tempudelay(1);
+	TK_RST_OUT(0);
+	tempudelay(5);
+	TK_RST_OUT(1);	
+}
+
+/* Ends a transaction by taking RST active again. */
+
+static void
+stop(void) 
+{
+	tempudelay(2);
+	TK_RST_OUT(0);
+}
+
+/* Enable writing. */
+
+static void
+ds1302_wenable(void) 
+{
+	start(); 	
+	out_byte(0x8e); /* Write control register  */
+	out_byte(0x00); /* Disable write protect bit 7 = 0 */
+	stop();
+}
+
+/* Disable writing. */
+
+static void
+ds1302_wdisable(void) 
+{
+	start();
+	out_byte(0x8e); /* Write control register  */
+	out_byte(0x80); /* Disable write protect bit 7 = 0 */
+	stop();
+}
+
+
+
+/* Read a byte from the selected register in the DS1302. */
+
+unsigned char
+ds1302_readreg(int reg) 
+{
+	unsigned char x;
+
+	start();
+	out_byte(0x81 | (reg << 1)); /* read register */
+	x = in_byte();
+	stop();
+
+	return x;
+}
+
+/* Write a byte to the selected register. */
+
+void
+ds1302_writereg(int reg, unsigned char val) 
+{
+#ifndef CONFIG_ETRAX_RTC_READONLY
+	int do_writereg = 1;
+#else
+	int do_writereg = 0;
+
+	if (reg == RTC_TRICKLECHARGER)
+		do_writereg = 1;
+#endif
+
+	if (do_writereg) {
+		ds1302_wenable();
+		start();
+		out_byte(0x80 | (reg << 1)); /* write register */
+		out_byte(val);
+		stop();
+		ds1302_wdisable();
+	}
+}
+
+void
+get_rtc_time(struct rtc_time *rtc_tm) 
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	local_irq_disable();
+
+	rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
+	rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
+	rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
+	rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
+	rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
+	rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
+
+	local_irq_restore(flags);
+	
+	BCD_TO_BIN(rtc_tm->tm_sec);
+	BCD_TO_BIN(rtc_tm->tm_min);
+	BCD_TO_BIN(rtc_tm->tm_hour);
+	BCD_TO_BIN(rtc_tm->tm_mday);
+	BCD_TO_BIN(rtc_tm->tm_mon);
+	BCD_TO_BIN(rtc_tm->tm_year);
+
+	/*
+	 * Account for differences between how the RTC uses the values
+	 * and how they are defined in a struct rtc_time;
+	 */
+
+	if (rtc_tm->tm_year <= 69)
+		rtc_tm->tm_year += 100;
+
+	rtc_tm->tm_mon--;
+}
+
+static unsigned char days_in_mo[] = 
+    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+/* ioctl that supports RTC_RD_TIME and RTC_SET_TIME (read and set time/date). */
+
+static int
+rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	  unsigned long arg) 
+{
+        unsigned long flags;
+
+	switch(cmd) {
+		case RTC_RD_TIME:	/* read the time/date from RTC	*/
+		{
+			struct rtc_time rtc_tm;
+						
+			memset(&rtc_tm, 0, sizeof (struct rtc_time));
+			get_rtc_time(&rtc_tm);						
+			if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time)))
+				return -EFAULT;	
+			return 0;
+		}
+
+		case RTC_SET_TIME:	/* set the RTC */
+		{
+			struct rtc_time rtc_tm;
+			unsigned char mon, day, hrs, min, sec, leap_yr;
+			unsigned int yrs;
+
+			if (!capable(CAP_SYS_TIME))
+				return -EPERM;
+
+			if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)))
+				return -EFAULT;    	
+
+			yrs = rtc_tm.tm_year + 1900;
+			mon = rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
+			day = rtc_tm.tm_mday;
+			hrs = rtc_tm.tm_hour;
+			min = rtc_tm.tm_min;
+			sec = rtc_tm.tm_sec;
+			
+			
+			if ((yrs < 1970) || (yrs > 2069))
+				return -EINVAL;
+
+			leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
+
+			if ((mon > 12) || (day == 0))
+				return -EINVAL;
+
+			if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
+				return -EINVAL;
+			
+			if ((hrs >= 24) || (min >= 60) || (sec >= 60))
+				return -EINVAL;
+
+			if (yrs >= 2000)
+				yrs -= 2000;	/* RTC (0, 1, ... 69) */
+			else
+				yrs -= 1900;	/* RTC (70, 71, ... 99) */
+
+			BIN_TO_BCD(sec);
+			BIN_TO_BCD(min);
+			BIN_TO_BCD(hrs);
+			BIN_TO_BCD(day);
+			BIN_TO_BCD(mon);
+			BIN_TO_BCD(yrs);
+
+			local_irq_save(flags);
+			local_irq_disable();
+			CMOS_WRITE(yrs, RTC_YEAR);
+			CMOS_WRITE(mon, RTC_MONTH);
+			CMOS_WRITE(day, RTC_DAY_OF_MONTH);
+			CMOS_WRITE(hrs, RTC_HOURS);
+			CMOS_WRITE(min, RTC_MINUTES);
+			CMOS_WRITE(sec, RTC_SECONDS);
+			local_irq_restore(flags);
+
+			/* Notice that at this point, the RTC is updated but
+			 * the kernel is still running with the old time.
+			 * You need to set that separately with settimeofday
+			 * or adjtimex.
+			 */
+			return 0;
+		}
+
+		case RTC_SET_CHARGE: /* set the RTC TRICKLE CHARGE register */
+		{
+			int tcs_val;                        
+
+			if (!capable(CAP_SYS_TIME))
+				return -EPERM;
+			
+			if(copy_from_user(&tcs_val, (int*)arg, sizeof(int)))
+				return -EFAULT;
+
+			tcs_val = RTC_TCR_PATTERN | (tcs_val & 0x0F);
+			ds1302_writereg(RTC_TRICKLECHARGER, tcs_val);
+			return 0;
+		}
+		case RTC_VLOW_RD:
+		{
+			/* TODO:
+			 * Implement voltage low detection support
+			 */
+			printk(KERN_WARNING "DS1302: RTC Voltage Low detection"
+			       " is not supported\n");
+			return 0;
+		}
+		case RTC_VLOW_SET:
+		{
+			/* TODO:
+			 * Nothing to do since Voltage Low detection is not supported
+			 */
+			return 0;
+		}
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+
+static void
+print_rtc_status(void)
+{
+	struct rtc_time tm;
+
+	get_rtc_time(&tm);
+
+	/*
+	 * There is no way to tell if the luser has the RTC set for local
+	 * time or for Universal Standard Time (GMT). Probably local though.
+	 */
+
+	printk(KERN_INFO "rtc_time\t: %02d:%02d:%02d\n",
+	       tm.tm_hour, tm.tm_min, tm.tm_sec);
+	printk(KERN_INFO "rtc_date\t: %04d-%02d-%02d\n",
+	       tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+}
+
+/* The various file operations we support. */
+
+static struct file_operations rtc_fops = {
+        .owner          = THIS_MODULE,
+        .ioctl          = rtc_ioctl,	
+}; 
+
+/* Probe for the chip by writing something to its RAM and try reading it back. */
+
+#define MAGIC_PATTERN 0x42
+
+static int __init
+ds1302_probe(void) 
+{
+	int retval, res; 
+
+	TK_RST_DIR(1);
+	TK_SCL_DIR(1);
+	TK_SDA_DIR(0);
+	
+	/* Try to talk to timekeeper. */
+
+	ds1302_wenable();  
+	start();
+	out_byte(0xc0); /* write RAM byte 0 */	
+	out_byte(MAGIC_PATTERN); /* write something magic */
+	start();
+	out_byte(0xc1); /* read RAM byte 0 */
+
+	if((res = in_byte()) == MAGIC_PATTERN) {
+		stop();
+		ds1302_wdisable();
+		printk(KERN_INFO "%s: RTC found.\n", ds1302_name);
+		printk(KERN_INFO "%s: SDA, SCL, RST on PB%i, PB%i, %s%i\n",
+		       ds1302_name,
+		       CONFIG_ETRAX_DS1302_SDABIT,
+		       CONFIG_ETRAX_DS1302_SCLBIT,
+#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
+		       "GENIO",
+#else
+		       "PB",
+#endif
+		       CONFIG_ETRAX_DS1302_RSTBIT);
+                print_rtc_status();
+		retval = 1;
+	} else {
+		stop();
+		retval = 0;
+	}
+
+	return retval;
+}
+
+
+/* Just probe for the RTC and register the device to handle the ioctl needed. */
+
+int __init
+ds1302_init(void) 
+{
+	i2c_init();
+
+	if (!ds1302_probe()) {
+#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
+#if CONFIG_ETRAX_DS1302_RSTBIT == 27
+		/*
+		 * The only way to set g27 to output is to enable ATA.
+		 *
+		 * Make sure that R_GEN_CONFIG is setup correct.
+		 */
+    		genconfig_shadow = ((genconfig_shadow &
+				     ~IO_MASK(R_GEN_CONFIG, ata)) | 
+				   (IO_STATE(R_GEN_CONFIG, ata, select)));    
+    		*R_GEN_CONFIG = genconfig_shadow;
+#elif CONFIG_ETRAX_DS1302_RSTBIT == 0
+		
+		/* Set the direction of this bit to out. */		
+    		genconfig_shadow = ((genconfig_shadow &
+				     ~IO_MASK(R_GEN_CONFIG, g0dir)) | 
+				   (IO_STATE(R_GEN_CONFIG, g0dir, out)));    
+    		*R_GEN_CONFIG = genconfig_shadow;
+#endif
+		if (!ds1302_probe()) {
+			printk(KERN_WARNING "%s: RTC not found.\n", ds1302_name);
+      			return -1;
+		}
+#else
+		printk(KERN_WARNING "%s: RTC not found.\n", ds1302_name);
+    		return -1;
+#endif
+  	}
+	/* Initialise trickle charger */
+	ds1302_writereg(RTC_TRICKLECHARGER,
+			RTC_TCR_PATTERN |(CONFIG_ETRAX_DS1302_TRICKLE_CHARGE & 0x0F));
+        /* Start clock by resetting CLOCK_HALT */
+	ds1302_writereg(RTC_SECONDS, (ds1302_readreg(RTC_SECONDS) & 0x7F));
+	return 0;
+}
+
+static int __init ds1302_register(void)
+{
+	ds1302_init();
+	if (register_chrdev(RTC_MAJOR_NR, ds1302_name, &rtc_fops)) {
+		printk(KERN_INFO "%s: unable to get major %d for rtc\n", 
+		       ds1302_name, RTC_MAJOR_NR);
+		return -1;
+	}
+        return 0;
+
+}
+
+module_init(ds1302_register);
diff --git a/arch/cris/arch-v10/drivers/eeprom.c b/arch/cris/arch-v10/drivers/eeprom.c
new file mode 100644
index 0000000..316ca15
--- /dev/null
+++ b/arch/cris/arch-v10/drivers/eeprom.c
@@ -0,0 +1,945 @@
+/*!*****************************************************************************
+*!
+*!  Implements an interface for i2c compatible eeproms to run under linux.
+*!  Supports 2k, 8k(?) and 16k. Uses adaptive timing adjustents by
+*!  Johan.Adolfsson@axis.com
+*!
+*!  Probing results:
+*!    8k or not is detected (the assumes 2k or 16k)
+*!    2k or 16k detected using test reads and writes.
+*!
+*!------------------------------------------------------------------------
+*!  HISTORY
+*!
+*!  DATE          NAME              CHANGES
+*!  ----          ----              -------
+*!  Aug  28 1999  Edgar Iglesias    Initial Version
+*!  Aug  31 1999  Edgar Iglesias    Allow simultaneous users.
+*!  Sep  03 1999  Edgar Iglesias    Updated probe.
+*!  Sep  03 1999  Edgar Iglesias    Added bail-out stuff if we get interrupted
+*!                                  in the spin-lock.
+*!
+*!  $Log: eeprom.c,v $
+*!  Revision 1.10  2003/09/11 07:29:48  starvik
+*!  Merge of Linux 2.6.0-test5
+*!
+*!  Revision 1.9  2003/07/04 08:27:37  starvik
+*!  Merge of Linux 2.5.74
+*!
+*!  Revision 1.8  2003/04/09 05:20:47  starvik
+*!  Merge of Linux 2.5.67
+*!
+*!  Revision 1.6  2003/02/10 07:19:28  starvik
+*!  Removed misplaced ;
+*!
+*!  Revision 1.5  2002/12/11 13:13:57  starvik
+*!  Added arch/ to v10 specific includes
+*!  Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer)
+*!
+*!  Revision 1.4  2002/11/20 11:56:10  starvik
+*!  Merge of Linux 2.5.48
+*!
+*!  Revision 1.3  2002/11/18 13:16:06  starvik
+*!  Linux 2.5 port of latest 2.4 drivers
+*!
+*!  Revision 1.8  2001/06/15 13:24:29  jonashg
+*!  * Added verification of pointers from userspace in read and write.
+*!  * Made busy counter volatile.
+*!  * Added define for inital write delay.
+*!  * Removed warnings by using loff_t instead of unsigned long.
+*!
+*!  Revision 1.7  2001/06/14 15:26:54  jonashg
+*!  Removed test because condition is always true.
+*!
+*!  Revision 1.6  2001/06/14 15:18:20  jonashg
+*!  Kb -> kB (makes quite a difference if you don't know if you have 2k or 16k).
+*!
+*!  Revision 1.5  2001/06/14 14:39:51  jonashg
+*!  Forgot to use name when registering the driver.
+*!
+*!  Revision 1.4  2001/06/14 14:35:47  jonashg
+*!  * Gave driver a name and used it in printk's.
+*!  * Cleanup.
+*!
+*!  Revision 1.3  2001/03/19 16:04:46  markusl
+*!  Fixed init of fops struct
+*!
+*!  Revision 1.2  2001/03/19 10:35:07  markusl
+*!  2.4 port of eeprom driver
+*!
+*!  Revision 1.8  2000/05/18 10:42:25  edgar
+*!  Make sure to end write cycle on _every_ write
+*!
+*!  Revision 1.7  2000/01/17 17:41:01  johana
+*!  Adjusted probing and return -ENOSPC when writing outside EEPROM
+*!
+*!  Revision 1.6  2000/01/17 15:50:36  johana
+*!  Added adaptive timing adjustments and fixed autoprobing for 2k and 16k(?)
+*!  EEPROMs
+*!
+*!  Revision 1.5  1999/09/03 15:07:37  edgar
+*!  Added bail-out check to the spinlock
+*!
+*!  Revision 1.4  1999/09/03 12:11:17  bjornw
+*!  Proper atomicity (need to use spinlocks, not if's). users -> busy.
+*!
+*!
+*!        (c) 1999 Axis Communications AB, Lund, Sweden
+*!*****************************************************************************/
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+#include "i2c.h"
+
+#define D(x) 
+
+/* If we should use adaptive timing or not: */
+//#define EEPROM_ADAPTIVE_TIMING      
+
+#define EEPROM_MAJOR_NR 122  /* use a LOCAL/EXPERIMENTAL major for now */
+#define EEPROM_MINOR_NR 0
+
+/* Empirical sane initial value of the delay, the value will be adapted to
+ * what the chip needs when using EEPROM_ADAPTIVE_TIMING.
+ */
+#define INITIAL_WRITEDELAY_US 4000
+#define MAX_WRITEDELAY_US 10000 /* 10 ms according to spec for 2KB EEPROM */
+
+/* This one defines how many times to try when eeprom fails. */
+#define EEPROM_RETRIES 10
+
+#define EEPROM_2KB (2 * 1024)
+/*#define EEPROM_4KB (4 * 1024)*/ /* Exists but not used in Axis products */
+#define EEPROM_8KB (8 * 1024 - 1 ) /* Last byte has write protection bit */
+#define EEPROM_16KB (16 * 1024)
+
+#define i2c_delay(x) udelay(x)
+
+/*
+ *  This structure describes the attached eeprom chip.
+ *  The values are probed for.
+ */
+
+struct eeprom_type
+{
+  unsigned long size;
+  unsigned long sequential_write_pagesize;
+  unsigned char select_cmd;
+  unsigned long usec_delay_writecycles; /* Min time between write cycles
+					   (up to 10ms for some models) */
+  unsigned long usec_delay_step; /* For adaptive algorithm */
+  int adapt_state; /* 1 = To high , 0 = Even, -1 = To low */
+  
+  /* this one is to keep the read/write operations atomic */
+  wait_queue_head_t wait_q;
+  volatile int busy;
+  int retry_cnt_addr; /* Used to keep track of number of retries for
+                         adaptive timing adjustments */
+  int retry_cnt_read;
+};
+
+static int  eeprom_open(struct inode * inode, struct file * file);
+static loff_t  eeprom_lseek(struct file * file, loff_t offset, int orig);
+static ssize_t  eeprom_read(struct file * file, char * buf, size_t count,
+                            loff_t *off);
+static ssize_t  eeprom_write(struct file * file, const char * buf, size_t count,
+                             loff_t *off);
+static int eeprom_close(struct inode * inode, struct file * file);
+
+static int  eeprom_address(unsigned long addr);
+static int  read_from_eeprom(char * buf, int count);
+static int eeprom_write_buf(loff_t addr, const char * buf, int count);
+static int eeprom_read_buf(loff_t addr, char * buf, int count);
+
+static void eeprom_disable_write_protect(void);
+
+
+static const char eeprom_name[] = "eeprom";
+
+/* chip description */
+static struct eeprom_type eeprom;
+
+/* This is the exported file-operations structure for this device. */
+struct file_operations eeprom_fops =
+{
+  .llseek  = eeprom_lseek,
+  .read    = eeprom_read,
+  .write   = eeprom_write,
+  .open    = eeprom_open,
+  .release = eeprom_close
+};
+
+/* eeprom init call. Probes for different eeprom models. */
+
+int __init eeprom_init(void)
+{
+  init_waitqueue_head(&eeprom.wait_q);
+  eeprom.busy = 0;
+
+#ifdef CONFIG_ETRAX_I2C_EEPROM_PROBE
+#define EETEXT "Found"
+#else
+#define EETEXT "Assuming"
+#endif
+  if (register_chrdev(EEPROM_MAJOR_NR, eeprom_name, &eeprom_fops))
+  {
+    printk(KERN_INFO "%s: unable to get major %d for eeprom device\n",
+           eeprom_name, EEPROM_MAJOR_NR);
+    return -1;
+  }
+  
+  printk("EEPROM char device v0.3, (c) 2000 Axis Communications AB\n");
+
+  /*
+   *  Note: Most of this probing method was taken from the printserver (5470e)
+   *        codebase. It did not contain a way of finding the 16kB chips
+   *        (M24128 or variants). The method used here might not work
+   *        for all models. If you encounter problems the easiest way
+   *        is probably to define your model within #ifdef's, and hard-
+   *        code it.
+   */
+
+  eeprom.size = 0;
+  eeprom.usec_delay_writecycles = INITIAL_WRITEDELAY_US;
+  eeprom.usec_delay_step = 128;
+  eeprom.adapt_state = 0;
+  
+#ifdef CONFIG_ETRAX_I2C_EEPROM_PROBE
+  i2c_start();
+  i2c_outbyte(0x80);
+  if(!i2c_getack())
+  {
+    /* It's not 8k.. */
+    int success = 0;
+    unsigned char buf_2k_start[16];
+    
+    /* Im not sure this will work... :) */
+    /* assume 2kB, if failure go for 16kB */
+    /* Test with 16kB settings.. */
+    /* If it's a 2kB EEPROM and we address it outside it's range
+     * it will mirror the address space:
+     * 1. We read two locations (that are mirrored), 
+     *    if the content differs * it's a 16kB EEPROM.
+     * 2. if it doesn't differ - write different value to one of the locations,
+     *    check the other - if content still is the same it's a 2k EEPROM,
+     *    restore original data.
+     */
+#define LOC1 8
+#define LOC2 (0x1fb) /*1fb, 3ed, 5df, 7d1 */
+
+   /* 2k settings */  
+    i2c_stop();
+    eeprom.size = EEPROM_2KB;
+    eeprom.select_cmd = 0xA0;   
+    eeprom.sequential_write_pagesize = 16;
+    if( eeprom_read_buf( 0, buf_2k_start, 16 ) == 16 )
+    {
+      D(printk("2k start: '%16.16s'\n", buf_2k_start));
+    }
+    else
+    {
+      printk(KERN_INFO "%s: Failed to read in 2k mode!\n", eeprom_name);  
+    }
+    
+    /* 16k settings */
+    eeprom.size = EEPROM_16KB;
+    eeprom.select_cmd = 0xA0;   
+    eeprom.sequential_write_pagesize = 64;
+
+    {
+      unsigned char loc1[4], loc2[4], tmp[4];
+      if( eeprom_read_buf(LOC2, loc2, 4) == 4)
+      {
+        if( eeprom_read_buf(LOC1, loc1, 4) == 4)
+        {
+          D(printk("0 loc1: (%i) '%4.4s' loc2 (%i) '%4.4s'\n", 
+                   LOC1, loc1, LOC2, loc2));
+#if 0
+          if (memcmp(loc1, loc2, 4) != 0 )
+          {
+            /* It's 16k */
+            printk(KERN_INFO "%s: 16k detected in step 1\n", eeprom_name);
+            eeprom.size = EEPROM_16KB;     
+            success = 1;
+          }
+          else
+#endif
+          {
+            /* Do step 2 check */
+            /* Invert value */
+            loc1[0] = ~loc1[0];
+            if (eeprom_write_buf(LOC1, loc1, 1) == 1)
+            {
+              /* If 2k EEPROM this write will actually write 10 bytes
+               * from pos 0
+               */
+              D(printk("1 loc1: (%i) '%4.4s' loc2 (%i) '%4.4s'\n", 
+                       LOC1, loc1, LOC2, loc2));
+              if( eeprom_read_buf(LOC1, tmp, 4) == 4)
+              {
+                D(printk("2 loc1: (%i) '%4.4s' tmp '%4.4s'\n", 
+                         LOC1, loc1, tmp));
+                if (memcmp(loc1, tmp, 4) != 0 )
+                {
+                  printk(KERN_INFO "%s: read and write differs! Not 16kB\n",
+                         eeprom_name);
+                  loc1[0] = ~loc1[0];
+                  
+                  if (eeprom_write_buf(LOC1, loc1, 1) == 1)
+                  {
+                    success = 1;
+                  }
+                  else
+                  {
+                    printk(KERN_INFO "%s: Restore 2k failed during probe,"
+                           " EEPROM might be corrupt!\n", eeprom_name);
+                    
+                  }
+                  i2c_stop();
+                  /* Go to 2k mode and write original data */
+                  eeprom.size = EEPROM_2KB;
+                  eeprom.select_cmd = 0xA0;   
+                  eeprom.sequential_write_pagesize = 16;
+                  if( eeprom_write_buf(0, buf_2k_start, 16) == 16)
+                  {
+                  }
+                  else
+                  {
+                    printk(KERN_INFO "%s: Failed to write back 2k start!\n",
+                           eeprom_name);
+                  }
+                  
+                  eeprom.size = EEPROM_2KB;
+                }
+              }
+                
+              if(!success)
+              {
+                if( eeprom_read_buf(LOC2, loc2, 1) == 1)
+                {
+                  D(printk("0 loc1: (%i) '%4.4s' loc2 (%i) '%4.4s'\n", 
+                           LOC1, loc1, LOC2, loc2));
+                  if (memcmp(loc1, loc2, 4) == 0 )
+                  {
+                    /* Data the same, must be mirrored -> 2k */
+                    /* Restore data */
+                    printk(KERN_INFO "%s: 2k detected in step 2\n", eeprom_name);
+                    loc1[0] = ~loc1[0];
+                    if (eeprom_write_buf(LOC1, loc1, 1) == 1)
+                    {
+                      success = 1;
+                    }
+                    else
+                    {
+                      printk(KERN_INFO "%s: Restore 2k failed during probe,"
+                             " EEPROM might be corrupt!\n", eeprom_name);
+                      
+                    }
+                    
+                    eeprom.size = EEPROM_2KB;     
+                  }
+                  else
+                  {
+                    printk(KERN_INFO "%s: 16k detected in step 2\n",
+                           eeprom_name);
+                    loc1[0] = ~loc1[0];
+                    /* Data differs, assume 16k */
+                    /* Restore data */
+                    if (eeprom_write_buf(LOC1, loc1, 1) == 1)
+                    {
+                      success = 1;
+                    }
+                    else
+                    {
+                      printk(KERN_INFO "%s: Restore 16k failed during probe,"
+                             " EEPROM might be corrupt!\n", eeprom_name);
+                    }
+                    
+                    eeprom.size = EEPROM_16KB;
+                  }
+                }
+              }
+            }
+          } /* read LOC1 */
+        } /* address LOC1 */
+        if (!success)
+        {
+          printk(KERN_INFO "%s: Probing failed!, using 2KB!\n", eeprom_name);
+          eeprom.size = EEPROM_2KB;               
+        }
+      } /* read */
+    }
+  }
+  else
+  {
+    i2c_outbyte(0x00);
+    if(!i2c_getack())
+    {
+      /* No 8k */
+      eeprom.size = EEPROM_2KB;
+    }
+    else
+    {
+      i2c_start();
+      i2c_outbyte(0x81);
+      if (!i2c_getack())
+      {
+        eeprom.size = EEPROM_2KB;
+      }
+      else
+      {
+        /* It's a 8kB */
+        i2c_inbyte();
+        eeprom.size = EEPROM_8KB;
+      }
+    }
+  }
+  i2c_stop();
+#elif defined(CONFIG_ETRAX_I2C_EEPROM_16KB)
+  eeprom.size = EEPROM_16KB;
+#elif defined(CONFIG_ETRAX_I2C_EEPROM_8KB)
+  eeprom.size = EEPROM_8KB;
+#elif defined(CONFIG_ETRAX_I2C_EEPROM_2KB)
+  eeprom.size = EEPROM_2KB;
+#endif
+
+  switch(eeprom.size)
+  {
+   case (EEPROM_2KB):
+     printk("%s: " EETEXT " i2c compatible 2kB eeprom.\n", eeprom_name);
+     eeprom.sequential_write_pagesize = 16;
+     eeprom.select_cmd = 0xA0;
+     break;
+   case (EEPROM_8KB):
+     printk("%s: " EETEXT " i2c compatible 8kB eeprom.\n", eeprom_name);
+     eeprom.sequential_write_pagesize = 16;
+     eeprom.select_cmd = 0x80;
+     break;
+   case (EEPROM_16KB):
+     printk("%s: " EETEXT " i2c compatible 16kB eeprom.\n", eeprom_name);
+     eeprom.sequential_write_pagesize = 64;
+     eeprom.select_cmd = 0xA0;     
+     break;
+   default:
+     eeprom.size = 0;
+     printk("%s: Did not find a supported eeprom\n", eeprom_name);
+     break;
+  }
+
+  
+
+  eeprom_disable_write_protect();
+
+  return 0;
+}
+
+/* Opens the device. */
+
+static int eeprom_open(struct inode * inode, struct file * file)
+{
+
+  if(MINOR(inode->i_rdev) != EEPROM_MINOR_NR)
+     return -ENXIO;
+  if(MAJOR(inode->i_rdev) != EEPROM_MAJOR_NR)
+     return -ENXIO;
+
+  if( eeprom.size > 0 )
+  {
+    /* OK */
+    return 0;
+  }
+
+  /* No EEprom found */
+  return -EFAULT;
+}
+
+/* Changes the current file position. */
+
+static loff_t eeprom_lseek(struct file * file, loff_t offset, int orig)
+{
+/*
+ *  orig 0: position from begning of eeprom
+ *  orig 1: relative from current position
+ *  orig 2: position from last eeprom address
+ */
+  
+  switch (orig)
+  {
+   case 0:
+     file->f_pos = offset;
+     break;
+   case 1:
+     file->f_pos += offset;
+     break;
+   case 2:
+     file->f_pos = eeprom.size - offset;
+     break;
+   default:
+     return -EINVAL;
+  }
+
+  /* truncate position */
+  if (file->f_pos < 0)
+  {
+    file->f_pos = 0;    
+    return(-EOVERFLOW);
+  }
+  
+  if (file->f_pos >= eeprom.size)
+  {
+    file->f_pos = eeprom.size - 1;
+    return(-EOVERFLOW);
+  }
+
+  return ( file->f_pos );
+}
+
+/* Reads data from eeprom. */
+
+static int eeprom_read_buf(loff_t addr, char * buf, int count)
+{
+  struct file f;
+
+  f.f_pos = addr;
+  return eeprom_read(&f, buf, count, &addr);
+}
+
+
+
+/* Reads data from eeprom. */
+
+static ssize_t eeprom_read(struct file * file, char * buf, size_t count, loff_t *off)
+{
+  int read=0;
+  unsigned long p = file->f_pos;
+
+  unsigned char page;
+
+  if(p >= eeprom.size)  /* Address i 0 - (size-1) */
+  {
+    return -EFAULT;
+  }
+  
+  while(eeprom.busy)
+  {
+    interruptible_sleep_on(&eeprom.wait_q);
+
+    /* bail out if we get interrupted */
+    if (signal_pending(current))
+      return -EINTR;
+    
+  }
+  eeprom.busy++;
+
+  page = (unsigned char) (p >> 8);
+  
+  if(!eeprom_address(p))
+  {
+    printk(KERN_INFO "%s: Read failed to address the eeprom: "
+           "0x%08X (%i) page: %i\n", eeprom_name, (int)p, (int)p, page);
+    i2c_stop();
+    
+    /* don't forget to wake them up */
+    eeprom.busy--;
+    wake_up_interruptible(&eeprom.wait_q);  
+    return -EFAULT;
+  }
+
+  if( (p + count) > eeprom.size)
+  {
+    /* truncate count */
+    count = eeprom.size - p;
+  }
+
+  /* stop dummy write op and initiate the read op */
+  i2c_start();
+
+  /* special case for small eeproms */
+  if(eeprom.size < EEPROM_16KB)
+  {
+    i2c_outbyte( eeprom.select_cmd | 1 | (page << 1) );
+  }
+
+  /* go on with the actual read */
+  read = read_from_eeprom( buf, count);
+  
+  if(read > 0)
+  {
+    file->f_pos += read;
+  }
+
+  eeprom.busy--;
+  wake_up_interruptible(&eeprom.wait_q);
+  return read;
+}
+
+/* Writes data to eeprom. */
+
+static int eeprom_write_buf(loff_t addr, const char * buf, int count)
+{
+  struct file f;
+
+  f.f_pos = addr;
+  
+  return eeprom_write(&f, buf, count, &addr);
+}
+
+
+/* Writes data to eeprom. */
+
+static ssize_t eeprom_write(struct file * file, const char * buf, size_t count,
+                            loff_t *off)
+{
+  int i, written, restart=1;
+  unsigned long p;
+
+  if (!access_ok(VERIFY_READ, buf, count))
+  {
+    return -EFAULT;
+  }
+
+  while(eeprom.busy)
+  {
+    interruptible_sleep_on(&eeprom.wait_q);
+    /* bail out if we get interrupted */
+    if (signal_pending(current))
+      return -EINTR;
+  }
+  eeprom.busy++;
+  for(i = 0; (i < EEPROM_RETRIES) && (restart > 0); i++)
+  {
+    restart = 0;
+    written = 0;
+    p = file->f_pos;
+   
+    
+    while( (written < count) && (p < eeprom.size))
+    {
+      /* address the eeprom */
+      if(!eeprom_address(p))
+      {
+        printk(KERN_INFO "%s: Write failed to address the eeprom: "
+               "0x%08X (%i) \n", eeprom_name, (int)p, (int)p);
+        i2c_stop();
+        
+        /* don't forget to wake them up */
+        eeprom.busy--;
+        wake_up_interruptible(&eeprom.wait_q);
+        return -EFAULT;
+      }
+#ifdef EEPROM_ADAPTIVE_TIMING      
+      /* Adaptive algorithm to adjust timing */
+      if (eeprom.retry_cnt_addr > 0)
+      {
+        /* To Low now */
+        D(printk(">D=%i d=%i\n",
+               eeprom.usec_delay_writecycles, eeprom.usec_delay_step));
+
+        if (eeprom.usec_delay_step < 4)
+        {
+          eeprom.usec_delay_step++;
+          eeprom.usec_delay_writecycles += eeprom.usec_delay_step;
+        }
+        else
+        {
+
+          if (eeprom.adapt_state > 0)
+          {
+            /* To Low before */
+            eeprom.usec_delay_step *= 2;
+            if (eeprom.usec_delay_step > 2)
+            {
+              eeprom.usec_delay_step--;
+            }
+            eeprom.usec_delay_writecycles += eeprom.usec_delay_step;
+          }
+          else if (eeprom.adapt_state < 0)
+          {
+            /* To High before (toggle dir) */
+            eeprom.usec_delay_writecycles += eeprom.usec_delay_step;
+            if (eeprom.usec_delay_step > 1)
+            {
+              eeprom.usec_delay_step /= 2;
+              eeprom.usec_delay_step--;
+            }
+          }
+        }
+
+        eeprom.adapt_state = 1;
+      }
+      else
+      {
+        /* To High (or good) now */
+        D(printk("<D=%i d=%i\n",
+               eeprom.usec_delay_writecycles, eeprom.usec_delay_step));
+        
+        if (eeprom.adapt_state < 0)
+        {
+          /* To High before */
+          if (eeprom.usec_delay_step > 1)
+          {
+            eeprom.usec_delay_step *= 2;
+            eeprom.usec_delay_step--;
+            
+            if (eeprom.usec_delay_writecycles > eeprom.usec_delay_step)
+            {
+              eeprom.usec_delay_writecycles -= eeprom.usec_delay_step;
+            }
+          }
+        }
+        else if (eeprom.adapt_state > 0)
+        {
+          /* To Low before (toggle dir) */
+          if (eeprom.usec_delay_writecycles > eeprom.usec_delay_step)
+          {
+            eeprom.usec_delay_writecycles -= eeprom.usec_delay_step;
+          }
+          if (eeprom.usec_delay_step > 1)
+          {
+            eeprom.usec_delay_step /= 2;
+            eeprom.usec_delay_step--;
+          }
+          
+          eeprom.adapt_state = -1;
+        }
+
+        if (eeprom.adapt_state > -100)
+        {
+          eeprom.adapt_state--;
+        }
+        else
+        {
+          /* Restart adaption */
+          D(printk("#Restart\n"));
+          eeprom.usec_delay_step++;
+        }
+      }
+#endif /* EEPROM_ADAPTIVE_TIMING */
+      /* write until we hit a page boundary or count */
+      do
+      {
+        i2c_outbyte(buf[written]);        
+        if(!i2c_getack())
+        {
+          restart=1;
+          printk(KERN_INFO "%s: write error, retrying. %d\n", eeprom_name, i);
+          i2c_stop();
+          break;
+        }
+        written++;
+        p++;        
+      } while( written < count && ( p % eeprom.sequential_write_pagesize ));
+
+      /* end write cycle */
+      i2c_stop();
+      i2c_delay(eeprom.usec_delay_writecycles);
+    } /* while */
+  } /* for  */
+
+  eeprom.busy--;
+  wake_up_interruptible(&eeprom.wait_q);
+  if (written == 0 && file->f_pos >= eeprom.size){
+    return -ENOSPC;
+  }
+  file->f_pos += written;
+  return written;
+}
+
+/* Closes the device. */
+
+static int eeprom_close(struct inode * inode, struct file * file)
+{
+  /* do nothing for now */
+  return 0;
+}
+
+/* Sets the current address of the eeprom. */
+
+static int eeprom_address(unsigned long addr)
+{
+  int i;
+  unsigned char page, offset;
+
+  page   = (unsigned char) (addr >> 8);
+  offset = (unsigned char)  addr;
+
+  for(i = 0; i < EEPROM_RETRIES; i++)
+  {
+    /* start a dummy write for addressing */
+    i2c_start();
+
+    if(eeprom.size == EEPROM_16KB)
+    {
+      i2c_outbyte( eeprom.select_cmd ); 
+      i2c_getack();
+      i2c_outbyte(page); 
+    }
+    else
+    {
+      i2c_outbyte( eeprom.select_cmd | (page << 1) ); 
+    }
+    if(!i2c_getack())
+    {
+      /* retry */
+      i2c_stop();
+      /* Must have a delay here.. 500 works, >50, 100->works 5th time*/
+      i2c_delay(MAX_WRITEDELAY_US / EEPROM_RETRIES * i);
+      /* The chip needs up to 10 ms from write stop to next start */
+     
+    }
+    else
+    {
+      i2c_outbyte(offset);
+      
+      if(!i2c_getack())
+      {
+        /* retry */
+        i2c_stop();
+      }
+      else
+        break;
+    }
+  }    
+
+  
+  eeprom.retry_cnt_addr = i;
+  D(printk("%i\n", eeprom.retry_cnt_addr));
+  if(eeprom.retry_cnt_addr == EEPROM_RETRIES)
+  {
+    /* failed */
+    return 0;
+  }
+  return 1;
+}
+
+/* Reads from current address. */
+
+static int read_from_eeprom(char * buf, int count)
+{
+  int i, read=0;
+
+  for(i = 0; i < EEPROM_RETRIES; i++)
+  {    
+    if(eeprom.size == EEPROM_16KB)
+    {
+      i2c_outbyte( eeprom.select_cmd | 1 );
+    }
+
+    if(i2c_getack())
+    {
+      break;
+    }
+  }
+  
+  if(i == EEPROM_RETRIES)
+  {
+    printk(KERN_INFO "%s: failed to read from eeprom\n", eeprom_name);
+    i2c_stop();
+    
+    return -EFAULT;
+  }
+
+  while( (read < count))
+  {    
+    if (put_user(i2c_inbyte(), &buf[read++]))
+    {
+      i2c_stop();
+
+      return -EFAULT;
+    }
+
+    /*
+     *  make sure we don't ack last byte or you will get very strange
+     *  results!
+     */
+    if(read < count)
+    {
+      i2c_sendack();
+    }
+  }
+
+  /* stop the operation */
+  i2c_stop();
+
+  return read;
+}
+
+/* Disables write protection if applicable. */
+
+#define DBP_SAVE(x)
+#define ax_printf printk
+static void eeprom_disable_write_protect(void)
+{
+  /* Disable write protect */
+  if (eeprom.size == EEPROM_8KB)
+  {
+    /* Step 1 Set WEL = 1 (write 00000010 to address 1FFFh */
+    i2c_start();
+    i2c_outbyte(0xbe);
+    if(!i2c_getack())
+    {
+      DBP_SAVE(ax_printf("Get ack returns false\n"));
+    }
+    i2c_outbyte(0xFF);
+    if(!i2c_getack())
+    {
+      DBP_SAVE(ax_printf("Get ack returns false 2\n"));
+    }
+    i2c_outbyte(0x02);
+    if(!i2c_getack())
+    {
+      DBP_SAVE(ax_printf("Get ack returns false 3\n"));
+    }
+    i2c_stop();
+
+    i2c_delay(1000);
+
+    /* Step 2 Set RWEL = 1 (write 00000110 to address 1FFFh */
+    i2c_start();
+    i2c_outbyte(0xbe);
+    if(!i2c_getack())
+    {
+      DBP_SAVE(ax_printf("Get ack returns false 55\n"));
+    }
+    i2c_outbyte(0xFF);
+    if(!i2c_getack())
+    {
+      DBP_SAVE(ax_printf("Get ack returns false 52\n"));
+    }
+    i2c_outbyte(0x06);
+    if(!i2c_getack())
+    {
+      DBP_SAVE(ax_printf("Get ack returns false 53\n"));
+    }
+    i2c_stop();
+    
+    /* Step 3 Set BP1, BP0, and/or WPEN bits (write 00000110 to address 1FFFh */
+    i2c_start();
+    i2c_outbyte(0xbe);
+    if(!i2c_getack())
+    {
+      DBP_SAVE(ax_printf("Get ack returns false 56\n"));
+    }
+    i2c_outbyte(0xFF);
+    if(!i2c_getack())
+    {
+      DBP_SAVE(ax_printf("Get ack returns false 57\n"));
+    }
+    i2c_outbyte(0x06);
+    if(!i2c_getack())
+    {
+      DBP_SAVE(ax_printf("Get ack returns false 58\n"));
+    }
+    i2c_stop();
+    
+    /* Write protect disabled */
+  }
+}
+
+module_init(eeprom_init);
diff --git a/arch/cris/arch-v10/drivers/gpio.c b/arch/cris/arch-v10/drivers/gpio.c
new file mode 100644
index 0000000..c095de8
--- /dev/null
+++ b/arch/cris/arch-v10/drivers/gpio.c
@@ -0,0 +1,944 @@
+/* $Id: gpio.c,v 1.12 2004/08/24 07:19:59 starvik Exp $
+ *
+ * Etrax general port I/O device
+ *
+ * Copyright (c) 1999, 2000, 2001, 2002 Axis Communications AB
+ *
+ * Authors:    Bjorn Wesen      (initial version)
+ *             Ola Knutsson     (LED handling)
+ *             Johan Adolfsson  (read/set directions, write, port G)
+ *
+ * $Log: gpio.c,v $
+ * Revision 1.12  2004/08/24 07:19:59  starvik
+ * Whitespace cleanup
+ *
+ * Revision 1.11  2004/05/14 07:58:03  starvik
+ * Merge of changes from 2.4
+ *
+ * Revision 1.9  2003/09/11 07:29:48  starvik
+ * Merge of Linux 2.6.0-test5
+ *
+ * Revision 1.8  2003/07/04 08:27:37  starvik
+ * Merge of Linux 2.5.74
+ *
+ * Revision 1.7  2003/01/10 07:44:07  starvik
+ * init_ioremap is now called by kernel before drivers are initialized
+ *
+ * Revision 1.6  2002/12/11 13:13:57  starvik
+ * Added arch/ to v10 specific includes
+ * Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer)
+ *
+ * Revision 1.5  2002/11/20 11:56:11  starvik
+ * Merge of Linux 2.5.48
+ *
+ * Revision 1.4  2002/11/18 10:10:05  starvik
+ * Linux 2.5 port of latest gpio.c from Linux 2.4
+ *
+ * Revision 1.20  2002/10/16 21:16:24  johana
+ * Added support for PA high level interrupt.
+ * That gives 2ms response time with iodtest for high levels and 2-12 ms
+ * response time on low levels if the check is not made in
+ * process.c:cpu_idle() as well.
+ *
+ * Revision 1.19  2002/10/14 18:27:33  johana
+ * Implemented alarm handling so select() now works.
+ * Latency is around 6-9 ms with a etrax_gpio_wake_up_check() in
+ * cpu_idle().
+ * Otherwise I get 15-18 ms (same as doing the poll in userspace -
+ * but less overhead).
+ * TODO? Perhaps we should add the check in IMMEDIATE_BH (or whatever it
+ * is in 2.4) as well?
+ * TODO? Perhaps call request_irq()/free_irq() only when needed?
+ * Increased version to 2.5
+ *
+ * Revision 1.18  2002/10/11 15:02:00  johana
+ * Mask inverted 8 bit value in setget_input().
+ *
+ * Revision 1.17  2002/06/17 15:53:01  johana
+ * Added IO_READ_INBITS, IO_READ_OUTBITS, IO_SETGET_INPUT and IO_SETGET_OUTPUT
+ * that take a pointer as argument and thus can handle 32 bit ports (G)
+ * correctly.
+ * These should be used instead of IO_READBITS, IO_SETINPUT and IO_SETOUTPUT.
+ * (especially if Port G bit 31 is used)
+ *
+ * Revision 1.16  2002/06/17 09:59:51  johana
+ * Returning 32 bit values in the ioctl return value doesn't work if bit
+ * 31 is set (could happen for port G), so mask it of with 0x7FFFFFFF.
+ * A new set of ioctl's will be added.
+ *
+ * Revision 1.15  2002/05/06 13:19:13  johana
+ * IO_SETINPUT returns mask with bit set = inputs for PA and PB as well.
+ *
+ * Revision 1.14  2002/04/12 12:01:53  johana
+ * Use global r_port_g_data_shadow.
+ * Moved gpio_init_port_g() closer to gpio_init() and marked it __init.
+ *
+ * Revision 1.13  2002/04/10 12:03:55  johana
+ * Added support for port G /dev/gpiog (minor 3).
+ * Changed indentation on switch cases.
+ * Fixed other spaces to tabs.
+ *
+ * Revision 1.12  2001/11/12 19:42:15  pkj
+ * * Corrected return values from gpio_leds_ioctl().
+ * * Fixed compiler warnings.
+ *
+ * Revision 1.11  2001/10/30 14:39:12  johana
+ * Added D() around gpio_write printk.
+ *
+ * Revision 1.10  2001/10/25 10:24:42  johana
+ * Added IO_CFG_WRITE_MODE ioctl and write method that can do fast
+ * bittoggling in the kernel. (This speeds up programming an FPGA with 450kB
+ * from ~60 seconds to 4 seconds).
+ * Added save_flags/cli/restore_flags in ioctl.
+ *
+ * Revision 1.9  2001/05/04 14:16:07  matsfg
+ * Corrected spelling error
+ *
+ * Revision 1.8  2001/04/27 13:55:26  matsfg
+ * Moved initioremap.
+ * Turns off all LEDS on init.
+ * Added support for shutdown and powerbutton.
+ *
+ * Revision 1.7  2001/04/04 13:30:08  matsfg
+ * Added bitset and bitclear for leds. Calls init_ioremap to set up memmapping
+ *
+ * Revision 1.6  2001/03/26 16:03:06  bjornw
+ * Needs linux/config.h
+ *
+ * Revision 1.5  2001/03/26 14:22:03  bjornw
+ * Namechange of some config options
+ *
+ * Revision 1.4  2001/02/27 13:52:48  bjornw
+ * malloc.h -> slab.h
+ *
+ * Revision 1.3  2001/01/24 15:06:48  bjornw
+ * gpio_wq correct type
+ *
+ * Revision 1.2  2001/01/18 16:07:30  bjornw
+ * 2.4 port
+ *
+ * Revision 1.1  2001/01/18 15:55:16  bjornw
+ * Verbatim copy of etraxgpio.c from elinux 2.0 added
+ *
+ *
+ */
+
+#include <linux/config.h>
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include <asm/etraxgpio.h>
+#include <asm/arch/svinto.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+
+#define GPIO_MAJOR 120  /* experimental MAJOR number */
+
+#define D(x)
+
+#if 0
+static int dp_cnt;
+#define DP(x) do { dp_cnt++; if (dp_cnt % 1000 == 0) x; }while(0)
+#else
+#define DP(x)
+#endif
+	
+static char gpio_name[] = "etrax gpio";
+
+#if 0
+static wait_queue_head_t *gpio_wq;
+#endif
+
+static int gpio_ioctl(struct inode *inode, struct file *file,
+		      unsigned int cmd, unsigned long arg);
+static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
+                          loff_t *off);
+static int gpio_open(struct inode *inode, struct file *filp);
+static int gpio_release(struct inode *inode, struct file *filp);
+static unsigned int gpio_poll(struct file *filp, struct poll_table_struct *wait);
+
+/* private data per open() of this driver */
+
+struct gpio_private {
+	struct gpio_private *next;
+	/* These fields are for PA and PB only */
+	volatile unsigned char *port, *shadow;
+	volatile unsigned char *dir, *dir_shadow;
+	unsigned char changeable_dir;
+	unsigned char changeable_bits;
+	unsigned char clk_mask;
+	unsigned char data_mask;
+	unsigned char write_msb;
+	unsigned char pad1, pad2, pad3;
+	/* These fields are generic */
+	unsigned long highalarm, lowalarm;
+	wait_queue_head_t alarm_wq;
+	int minor;
+};
+
+/* linked list of alarms to check for */
+
+static struct gpio_private *alarmlist = 0;
+
+static int gpio_some_alarms = 0; /* Set if someone uses alarm */
+static unsigned long gpio_pa_irq_enabled_mask = 0;
+
+/* Port A and B use 8 bit access, but Port G is 32 bit */
+#define NUM_PORTS (GPIO_MINOR_B+1)
+
+static volatile unsigned char *ports[NUM_PORTS] = { 
+	R_PORT_PA_DATA, 
+	R_PORT_PB_DATA,
+};
+static volatile unsigned char *shads[NUM_PORTS] = {
+	&port_pa_data_shadow, 
+	&port_pb_data_shadow
+};
+
+/* What direction bits that are user changeable 1=changeable*/
+#ifndef CONFIG_ETRAX_PA_CHANGEABLE_DIR
+#define CONFIG_ETRAX_PA_CHANGEABLE_DIR 0x00
+#endif
+#ifndef CONFIG_ETRAX_PB_CHANGEABLE_DIR
+#define CONFIG_ETRAX_PB_CHANGEABLE_DIR 0x00
+#endif
+
+#ifndef CONFIG_ETRAX_PA_CHANGEABLE_BITS
+#define CONFIG_ETRAX_PA_CHANGEABLE_BITS 0xFF
+#endif
+#ifndef CONFIG_ETRAX_PB_CHANGEABLE_BITS
+#define CONFIG_ETRAX_PB_CHANGEABLE_BITS 0xFF
+#endif
+
+
+static unsigned char changeable_dir[NUM_PORTS] = { 
+	CONFIG_ETRAX_PA_CHANGEABLE_DIR,
+	CONFIG_ETRAX_PB_CHANGEABLE_DIR 
+};
+static unsigned char changeable_bits[NUM_PORTS] = { 
+	CONFIG_ETRAX_PA_CHANGEABLE_BITS,
+	CONFIG_ETRAX_PB_CHANGEABLE_BITS 
+};
+
+static volatile unsigned char *dir[NUM_PORTS] = { 
+	R_PORT_PA_DIR, 
+	R_PORT_PB_DIR 
+};
+
+static volatile unsigned char *dir_shadow[NUM_PORTS] = {
+	&port_pa_dir_shadow, 
+	&port_pb_dir_shadow 
+};
+
+/* Port G is 32 bit, handle it special, some bits are both inputs 
+   and outputs at the same time, only some of the bits can change direction
+   and some of them in groups of 8 bit. */
+static unsigned long changeable_dir_g;
+static unsigned long dir_g_in_bits;
+static unsigned long dir_g_out_bits;
+static unsigned long dir_g_shadow; /* 1=output */
+
+#define USE_PORTS(priv) ((priv)->minor <= GPIO_MINOR_B)
+
+
+
+static unsigned int 
+gpio_poll(struct file *file,
+	  poll_table *wait)
+{
+	unsigned int mask = 0;
+	struct gpio_private *priv = (struct gpio_private *)file->private_data;
+	unsigned long data;
+	poll_wait(file, &priv->alarm_wq, wait);
+	if (priv->minor == GPIO_MINOR_A) {
+		unsigned long flags;
+		unsigned long tmp;
+		data = *R_PORT_PA_DATA;
+		/* PA has support for high level interrupt -
+		 * lets activate for those low and with highalarm set
+		 */
+		tmp = ~data & priv->highalarm & 0xFF;
+		tmp = (tmp << R_IRQ_MASK1_SET__pa0__BITNR);
+		save_flags(flags); cli();
+		gpio_pa_irq_enabled_mask |= tmp;
+		*R_IRQ_MASK1_SET = tmp;
+		restore_flags(flags);
+
+	} else if (priv->minor == GPIO_MINOR_B)
+		data = *R_PORT_PB_DATA;
+	else if (priv->minor == GPIO_MINOR_G)
+		data = *R_PORT_G_DATA;
+	else
+		return 0;
+	
+	if ((data & priv->highalarm) ||
+	    (~data & priv->lowalarm)) {
+		mask = POLLIN|POLLRDNORM;
+	}
+	
+	DP(printk("gpio_poll ready: mask 0x%08X\n", mask));
+	return mask;
+}
+
+int etrax_gpio_wake_up_check(void)
+{
+	struct gpio_private *priv = alarmlist;
+	unsigned long data = 0;
+        int ret = 0;
+	while (priv) {
+		if (USE_PORTS(priv)) {
+			data = *priv->port;
+		} else if (priv->minor == GPIO_MINOR_G) {
+			data = *R_PORT_G_DATA;
+		}
+		if ((data & priv->highalarm) ||
+		    (~data & priv->lowalarm)) {
+			DP(printk("etrax_gpio_wake_up_check %i\n",priv->minor));
+			wake_up_interruptible(&priv->alarm_wq);
+                        ret = 1;
+		}
+		priv = priv->next;
+	}
+        return ret;
+}
+
+static irqreturn_t
+gpio_poll_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	if (gpio_some_alarms) {
+		etrax_gpio_wake_up_check();
+                return IRQ_HANDLED;
+	}
+        return IRQ_NONE;
+}
+
+static irqreturn_t
+gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long tmp;
+	/* Find what PA interrupts are active */
+	tmp = (*R_IRQ_READ1);
+
+	/* Find those that we have enabled */
+	tmp &= gpio_pa_irq_enabled_mask;
+
+	/* Clear them.. */
+	*R_IRQ_MASK1_CLR = tmp;
+	gpio_pa_irq_enabled_mask &= ~tmp;
+
+	if (gpio_some_alarms) {
+		return IRQ_RETVAL(etrax_gpio_wake_up_check());
+	}
+        return IRQ_NONE;
+}
+
+
+static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
+                          loff_t *off)
+{
+	struct gpio_private *priv = (struct gpio_private *)file->private_data;
+	unsigned char data, clk_mask, data_mask, write_msb;
+	unsigned long flags;
+	ssize_t retval = count;
+	if (priv->minor !=GPIO_MINOR_A && priv->minor != GPIO_MINOR_B) {
+		return -EFAULT;
+	}
+    
+	if (!access_ok(VERIFY_READ, buf, count)) {
+		return -EFAULT;
+	}
+	clk_mask = priv->clk_mask;
+	data_mask = priv->data_mask;
+	/* It must have been configured using the IO_CFG_WRITE_MODE */
+	/* Perhaps a better error code? */
+	if (clk_mask == 0 || data_mask == 0) {
+		return -EPERM;
+	}
+	write_msb = priv->write_msb;
+	D(printk("gpio_write: %lu to data 0x%02X clk 0x%02X msb: %i\n",count, data_mask, clk_mask, write_msb));
+	while (count--) {
+		int i;
+		data = *buf++;
+		if (priv->write_msb) {
+			for (i = 7; i >= 0;i--) {
+				local_irq_save(flags); local_irq_disable();
+				*priv->port = *priv->shadow &= ~clk_mask;
+				if (data & 1<<i)
+					*priv->port = *priv->shadow |= data_mask;
+				else
+					*priv->port = *priv->shadow &= ~data_mask;
+			/* For FPGA: min 5.0ns (DCC) before CCLK high */
+				*priv->port = *priv->shadow |= clk_mask;
+				local_irq_restore(flags);
+			}
+		} else {
+			for (i = 0; i <= 7;i++) {
+				local_irq_save(flags); local_irq_disable();
+				*priv->port = *priv->shadow &= ~clk_mask;
+				if (data & 1<<i)
+					*priv->port = *priv->shadow |= data_mask;
+				else
+					*priv->port = *priv->shadow &= ~data_mask;
+			/* For FPGA: min 5.0ns (DCC) before CCLK high */
+				*priv->port = *priv->shadow |= clk_mask;
+				local_irq_restore(flags);
+			}
+		}
+	}
+	return retval;
+}
+
+
+
+static int
+gpio_open(struct inode *inode, struct file *filp)
+{
+	struct gpio_private *priv;
+	int p = MINOR(inode->i_rdev);
+
+	if (p > GPIO_MINOR_LAST)
+		return -EINVAL;
+
+	priv = (struct gpio_private *)kmalloc(sizeof(struct gpio_private), 
+					      GFP_KERNEL);
+
+	if (!priv)
+		return -ENOMEM;
+
+	priv->minor = p;
+
+	/* initialize the io/alarm struct and link it into our alarmlist */
+
+	priv->next = alarmlist;
+	alarmlist = priv;
+	if (USE_PORTS(priv)) { /* A and B */
+		priv->port = ports[p];
+		priv->shadow = shads[p];
+		priv->dir = dir[p];
+		priv->dir_shadow = dir_shadow[p];
+		priv->changeable_dir = changeable_dir[p];
+		priv->changeable_bits = changeable_bits[p];
+	} else {
+		priv->port = NULL;
+		priv->shadow = NULL;
+		priv->dir = NULL;
+		priv->dir_shadow = NULL;
+		priv->changeable_dir = 0;
+		priv->changeable_bits = 0;
+	}
+
+	priv->highalarm = 0;
+	priv->lowalarm = 0;
+	priv->clk_mask = 0;
+	priv->data_mask = 0;
+	init_waitqueue_head(&priv->alarm_wq);
+
+	filp->private_data = (void *)priv;
+
+	return 0;
+}
+
+static int
+gpio_release(struct inode *inode, struct file *filp)
+{
+	struct gpio_private *p = alarmlist;
+	struct gpio_private *todel = (struct gpio_private *)filp->private_data;
+	
+	/* unlink from alarmlist and free the private structure */
+
+	if (p == todel) {
+		alarmlist = todel->next;
+	} else {
+		while (p->next != todel)
+			p = p->next;
+		p->next = todel->next;
+	}
+
+	kfree(todel);
+	/* Check if there are still any alarms set */
+	p = alarmlist;
+	while (p) {
+		if (p->highalarm | p->lowalarm) {
+			gpio_some_alarms = 1;
+			return 0;
+		}
+		p = p->next;
+	}
+	gpio_some_alarms = 0;
+		
+	return 0;
+}
+
+/* Main device API. ioctl's to read/set/clear bits, as well as to 
+ * set alarms to wait for using a subsequent select().
+ */
+
+unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg)
+{
+	/* Set direction 0=unchanged 1=input, 
+	 * return mask with 1=input 
+	 */
+	unsigned long flags;
+	if (USE_PORTS(priv)) {
+		local_irq_save(flags); local_irq_disable();
+		*priv->dir = *priv->dir_shadow &= 
+		~((unsigned char)arg & priv->changeable_dir);
+		local_irq_restore(flags);
+		return ~(*priv->dir_shadow) & 0xFF; /* Only 8 bits */
+	} else if (priv->minor == GPIO_MINOR_G) {
+		/* We must fiddle with R_GEN_CONFIG to change dir */
+		save_flags(flags); cli();
+		if (((arg & dir_g_in_bits) != arg) && 
+		    (arg & changeable_dir_g)) {
+			arg &= changeable_dir_g;
+			/* Clear bits in genconfig to set to input */
+			if (arg & (1<<0)) {
+				genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g0dir);
+				dir_g_in_bits |= (1<<0);
+				dir_g_out_bits &= ~(1<<0);
+			}
+			if ((arg & 0x0000FF00) == 0x0000FF00) {
+				genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g8_15dir);
+				dir_g_in_bits |= 0x0000FF00;
+				dir_g_out_bits &= ~0x0000FF00;
+			}
+			if ((arg & 0x00FF0000) == 0x00FF0000) {
+				genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g16_23dir);
+				dir_g_in_bits |= 0x00FF0000;
+				dir_g_out_bits &= ~0x00FF0000;
+			}
+			if (arg & (1<<24)) {
+				genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g24dir);
+				dir_g_in_bits |= (1<<24);
+				dir_g_out_bits &= ~(1<<24);
+			}
+			D(printk(KERN_INFO "gpio: SETINPUT on port G set "
+				 "genconfig to 0x%08lX "
+				 "in_bits: 0x%08lX "
+				 "out_bits: 0x%08lX\n",
+			         (unsigned long)genconfig_shadow,
+			         dir_g_in_bits, dir_g_out_bits));
+			*R_GEN_CONFIG = genconfig_shadow;
+			/* Must be a >120 ns delay before writing this again */
+				
+		}
+		restore_flags(flags);
+		return dir_g_in_bits;
+	}
+	return 0;
+} /* setget_input */
+
+unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg)
+{
+	unsigned long flags;
+	if (USE_PORTS(priv)) {
+		local_irq_save(flags); local_irq_disable();
+		*priv->dir = *priv->dir_shadow |= 
+		  ((unsigned char)arg & priv->changeable_dir);
+		local_irq_restore(flags);
+		return *priv->dir_shadow;
+	} else if (priv->minor == GPIO_MINOR_G) {
+		/* We must fiddle with R_GEN_CONFIG to change dir */			
+		save_flags(flags); cli();
+		if (((arg & dir_g_out_bits) != arg) &&
+		    (arg & changeable_dir_g)) {
+			/* Set bits in genconfig to set to output */
+			if (arg & (1<<0)) {
+				genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g0dir);
+				dir_g_out_bits |= (1<<0);
+				dir_g_in_bits &= ~(1<<0);
+			}
+			if ((arg & 0x0000FF00) == 0x0000FF00) {
+				genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g8_15dir);
+				dir_g_out_bits |= 0x0000FF00;
+				dir_g_in_bits &= ~0x0000FF00;
+			}
+			if ((arg & 0x00FF0000) == 0x00FF0000) {
+				genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g16_23dir);
+				dir_g_out_bits |= 0x00FF0000;
+				dir_g_in_bits &= ~0x00FF0000;
+			}
+			if (arg & (1<<24)) {
+				genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g24dir);
+				dir_g_out_bits |= (1<<24);
+				dir_g_in_bits &= ~(1<<24);
+			}
+			D(printk(KERN_INFO "gpio: SETOUTPUT on port G set "
+				 "genconfig to 0x%08lX "
+				 "in_bits: 0x%08lX "
+				 "out_bits: 0x%08lX\n",
+			         (unsigned long)genconfig_shadow,
+			         dir_g_in_bits, dir_g_out_bits));
+			*R_GEN_CONFIG = genconfig_shadow;
+			/* Must be a >120 ns delay before writing this again */
+		}
+		restore_flags(flags);
+		return dir_g_out_bits & 0x7FFFFFFF;
+	}
+	return 0;
+} /* setget_output */
+
+static int
+gpio_leds_ioctl(unsigned int cmd, unsigned long arg);
+
+static int
+gpio_ioctl(struct inode *inode, struct file *file,
+	   unsigned int cmd, unsigned long arg)
+{
+	unsigned long flags;
+	unsigned long val;
+	struct gpio_private *priv = (struct gpio_private *)file->private_data;
+	if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) {
+		return -EINVAL;
+	}
+
+	switch (_IOC_NR(cmd)) {
+	case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */
+		// read the port
+		if (USE_PORTS(priv)) {
+			return *priv->port;
+		} else if (priv->minor == GPIO_MINOR_G) {
+			return (*R_PORT_G_DATA) & 0x7FFFFFFF;
+		}
+		break;
+	case IO_SETBITS:
+		local_irq_save(flags); local_irq_disable();
+		// set changeable bits with a 1 in arg
+		if (USE_PORTS(priv)) {
+			*priv->port = *priv->shadow |= 
+			  ((unsigned char)arg & priv->changeable_bits);
+		} else if (priv->minor == GPIO_MINOR_G) {
+			*R_PORT_G_DATA = port_g_data_shadow |= (arg & dir_g_out_bits);
+		}
+		local_irq_restore(flags);
+		break;
+	case IO_CLRBITS:
+		local_irq_save(flags); local_irq_disable();
+		// clear changeable bits with a 1 in arg
+		if (USE_PORTS(priv)) {
+			*priv->port = *priv->shadow &= 
+			 ~((unsigned char)arg & priv->changeable_bits);
+		} else if (priv->minor == GPIO_MINOR_G) {
+			*R_PORT_G_DATA = port_g_data_shadow &= ~((unsigned long)arg & dir_g_out_bits);
+		}
+		local_irq_restore(flags);
+		break;
+	case IO_HIGHALARM:
+		// set alarm when bits with 1 in arg go high
+		priv->highalarm |= arg;
+		gpio_some_alarms = 1;
+		break;
+	case IO_LOWALARM:
+		// set alarm when bits with 1 in arg go low
+		priv->lowalarm |= arg;
+		gpio_some_alarms = 1;
+		break;
+	case IO_CLRALARM:
+		// clear alarm for bits with 1 in arg
+		priv->highalarm &= ~arg;
+		priv->lowalarm  &= ~arg;
+		{
+			/* Must update gpio_some_alarms */
+			struct gpio_private *p = alarmlist;
+			int some_alarms;
+			some_alarms = 0;
+			while (p) {
+				if (p->highalarm | p->lowalarm) {
+					some_alarms = 1;
+					break;
+				}
+				p = p->next;
+			}
+			gpio_some_alarms = some_alarms;
+		}
+		break;
+	case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */
+		/* Read direction 0=input 1=output */
+		if (USE_PORTS(priv)) {
+			return *priv->dir_shadow;
+		} else if (priv->minor == GPIO_MINOR_G) {
+			/* Note: Some bits are both in and out,
+			 * Those that are dual is set here as well.
+			 */
+			return (dir_g_shadow | dir_g_out_bits) & 0x7FFFFFFF;
+		}
+	case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */
+		/* Set direction 0=unchanged 1=input, 
+		 * return mask with 1=input 
+		 */
+		return setget_input(priv, arg) & 0x7FFFFFFF;
+		break;
+	case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */
+		/* Set direction 0=unchanged 1=output, 
+		 * return mask with 1=output 
+		 */
+		return setget_output(priv, arg) & 0x7FFFFFFF;
+
+	case IO_SHUTDOWN:
+		SOFT_SHUTDOWN();
+		break;
+	case IO_GET_PWR_BT:
+#if defined (CONFIG_ETRAX_SOFT_SHUTDOWN)
+		return (*R_PORT_G_DATA & ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT));
+#else
+		return 0;
+#endif
+		break;
+	case IO_CFG_WRITE_MODE:
+		priv->clk_mask = arg & 0xFF;
+		priv->data_mask = (arg >> 8) & 0xFF;
+		priv->write_msb = (arg >> 16) & 0x01;
+		/* Check if we're allowed to change the bits and
+		 * the direction is correct
+		 */
+		if (!((priv->clk_mask & priv->changeable_bits) &&
+		      (priv->data_mask & priv->changeable_bits) &&
+		      (priv->clk_mask & *priv->dir_shadow) &&
+		      (priv->data_mask & *priv->dir_shadow)))
+		{
+			priv->clk_mask = 0;
+			priv->data_mask = 0;
+			return -EPERM;
+		}
+		break;
+	case IO_READ_INBITS: 
+		/* *arg is result of reading the input pins */
+		if (USE_PORTS(priv)) {
+			val = *priv->port;
+		} else if (priv->minor == GPIO_MINOR_G) {
+			val = *R_PORT_G_DATA;
+		}
+		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
+			return -EFAULT;
+		return 0;
+		break;
+	case IO_READ_OUTBITS:
+		 /* *arg is result of reading the output shadow */
+		if (USE_PORTS(priv)) {
+			val = *priv->shadow;
+		} else if (priv->minor == GPIO_MINOR_G) {
+			val = port_g_data_shadow;
+		}
+		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
+			return -EFAULT;
+		break;
+	case IO_SETGET_INPUT: 
+		/* bits set in *arg is set to input,
+		 * *arg updated with current input pins.
+		 */
+		if (copy_from_user(&val, (unsigned long*)arg, sizeof(val)))
+			return -EFAULT;
+		val = setget_input(priv, val);
+		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
+			return -EFAULT;
+		break;
+	case IO_SETGET_OUTPUT:
+		/* bits set in *arg is set to output,
+		 * *arg updated with current output pins.
+		 */
+		if (copy_from_user(&val, (unsigned long*)arg, sizeof(val)))
+			return -EFAULT;
+		val = setget_output(priv, val);
+		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
+			return -EFAULT;
+		break;
+	default:
+		if (priv->minor == GPIO_MINOR_LEDS)
+			return gpio_leds_ioctl(cmd, arg);
+		else
+			return -EINVAL;
+	} /* switch */
+	
+	return 0;
+}
+
+static int
+gpio_leds_ioctl(unsigned int cmd, unsigned long arg)
+{
+	unsigned char green;
+	unsigned char red;
+
+	switch (_IOC_NR(cmd)) {
+	case IO_LEDACTIVE_SET:
+		green = ((unsigned char) arg) & 1;
+		red   = (((unsigned char) arg) >> 1) & 1;
+		LED_ACTIVE_SET_G(green);
+		LED_ACTIVE_SET_R(red);
+		break;
+
+	case IO_LED_SETBIT:
+		LED_BIT_SET(arg);
+		break;
+
+	case IO_LED_CLRBIT:
+		LED_BIT_CLR(arg);
+		break;
+
+	default:
+		return -EINVAL;
+	} /* switch */
+
+	return 0;
+}
+
+struct file_operations gpio_fops = {
+	.owner       = THIS_MODULE,
+	.poll        = gpio_poll,
+	.ioctl       = gpio_ioctl,
+	.write       = gpio_write,
+	.open        = gpio_open,
+	.release     = gpio_release,
+};
+
+
+static void __init gpio_init_port_g(void)
+{
+#define GROUPA (0x0000FF3F)
+#define GROUPB (1<<6 | 1<<7)
+#define GROUPC (1<<30 | 1<<31)
+#define GROUPD (0x3FFF0000)
+#define GROUPD_LOW (0x00FF0000)
+	unsigned long used_in_bits = 0;
+	unsigned long used_out_bits = 0;
+	if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi0, select)){
+		used_in_bits  |= GROUPA | GROUPB | 0 | 0;
+		used_out_bits |= GROUPA | GROUPB | 0 | 0;
+	}
+	if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ata, select)) {
+		used_in_bits  |= GROUPA | GROUPB | GROUPC | (GROUPD & ~(1<<25|1<<26));
+		used_out_bits |= GROUPA | GROUPB | GROUPC | GROUPD;
+	}
+
+	if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, par0, select)) {
+		used_in_bits  |= (GROUPA & ~(1<<0)) | 0 | 0 | 0;
+		used_out_bits |= (GROUPA & ~(1<<0)) | 0 | 0 | 0;
+	}
+	if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ser2, select)) {
+		used_in_bits  |= 0 | GROUPB | 0 | 0;
+		used_out_bits |= 0 | GROUPB | 0 | 0;
+	}
+	/* mio same as shared RAM ? */
+	if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, mio, select)) {
+		used_in_bits  |= (GROUPA & ~(1<<0)) | 0 |0 |GROUPD_LOW;
+		used_out_bits |= (GROUPA & ~(1<<0|1<<1|1<<2)) | 0 |0 |GROUPD_LOW;
+	}
+	if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi1, select)) {
+		used_in_bits  |= 0 | 0 | GROUPC | GROUPD;
+		used_out_bits |= 0 | 0 | GROUPC | GROUPD;
+	}
+	if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi0w, select)) {
+		used_in_bits  |= GROUPA | GROUPB | 0 | (GROUPD_LOW | 1<<24);
+		used_out_bits |= GROUPA | GROUPB | 0 | (GROUPD_LOW | 1<<24 | 1<<25|1<<26);
+	}
+
+	if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, par1, select)) {
+		used_in_bits  |= 0 | 0 | 0 | (GROUPD & ~(1<<24));
+		used_out_bits |= 0 | 0 | 0 | (GROUPD & ~(1<<24));
+	}
+	if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ser3, select)) {
+		used_in_bits  |= 0 | 0 | GROUPC | 0;
+		used_out_bits |= 0 | 0 | GROUPC | 0;
+	}
+	/* mio same as shared RAM-W? */
+	if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, mio_w, select)) {
+		used_in_bits  |= (GROUPA & ~(1<<0)) | 0 | 0 |GROUPD_LOW;
+		used_out_bits |= (GROUPA & ~(1<<0|1<<1|1<<2)) | 0 | 0 |GROUPD_LOW;
+	}
+	/* TODO: USB p2, parw, sync ser3? */
+
+	/* Initialise the dir_g_shadow etc. depending on genconfig */
+	/* 0=input 1=output */
+	if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g0dir, out)) 
+		dir_g_shadow |= (1 << 0);
+	if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g8_15dir, out))
+		dir_g_shadow |= 0x0000FF00;
+	if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g16_23dir, out))
+		dir_g_shadow |= 0x00FF0000;
+	if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g24dir, out))
+		dir_g_shadow |= (1 << 24);
+
+	dir_g_in_bits = ~used_in_bits;
+	dir_g_out_bits = ~used_out_bits;
+
+	changeable_dir_g = 0x01FFFF01; /* all that can change dir */
+	changeable_dir_g &= dir_g_out_bits;
+	changeable_dir_g &= dir_g_in_bits;
+	/* Correct the bits that can change direction */ 
+	dir_g_out_bits &= ~changeable_dir_g;
+	dir_g_out_bits |= dir_g_shadow;
+	dir_g_in_bits &= ~changeable_dir_g;
+	dir_g_in_bits |= (~dir_g_shadow & changeable_dir_g);
+
+
+	printk(KERN_INFO "GPIO port G: in_bits: 0x%08lX out_bits: 0x%08lX val: %08lX\n",
+	       dir_g_in_bits, dir_g_out_bits, (unsigned long)*R_PORT_G_DATA);
+	printk(KERN_INFO "GPIO port G: dir: %08lX changeable: %08lX\n",
+	       dir_g_shadow, changeable_dir_g);
+}
+
+/* main driver initialization routine, called from mem.c */
+
+static __init int
+gpio_init(void)
+{
+	int res;
+#if defined (CONFIG_ETRAX_CSP0_LEDS)
+	int i;
+#endif
+
+	/* do the formalities */
+
+	res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops);
+	if (res < 0) {
+		printk(KERN_ERR "gpio: couldn't get a major number.\n");
+		return res;
+	}
+
+	/* Clear all leds */
+#if defined (CONFIG_ETRAX_CSP0_LEDS) ||  defined (CONFIG_ETRAX_PA_LEDS) || defined (CONFIG_ETRAX_PB_LEDS)
+	LED_NETWORK_SET(0);
+	LED_ACTIVE_SET(0);
+	LED_DISK_READ(0);
+	LED_DISK_WRITE(0);
+
+#if defined (CONFIG_ETRAX_CSP0_LEDS)
+	for (i = 0; i < 32; i++) {
+		LED_BIT_SET(i);
+	}
+#endif
+
+#endif
+	gpio_init_port_g();
+	printk(KERN_INFO "ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002 Axis Communications AB\n");
+	/* We call etrax_gpio_wake_up_check() from timer interrupt and
+	 * from cpu_idle() in kernel/process.c
+	 * The check in cpu_idle() reduces latency from ~15 ms to ~6 ms
+	 * in some tests.
+	 */  
+	if (request_irq(TIMER0_IRQ_NBR, gpio_poll_timer_interrupt,
+			SA_SHIRQ | SA_INTERRUPT,"gpio poll", NULL)) {
+		printk(KERN_CRIT "err: timer0 irq for gpio\n");
+	}
+	if (request_irq(PA_IRQ_NBR, gpio_pa_interrupt,
+			SA_SHIRQ | SA_INTERRUPT,"gpio PA", NULL)) {
+		printk(KERN_CRIT "err: PA irq for gpio\n");
+	}
+	
+
+	return res;
+}
+
+/* this makes sure that gpio_init is called during kernel boot */
+
+module_init(gpio_init);
diff --git a/arch/cris/arch-v10/drivers/i2c.c b/arch/cris/arch-v10/drivers/i2c.c
new file mode 100644
index 0000000..8bbe233
--- /dev/null
+++ b/arch/cris/arch-v10/drivers/i2c.c
@@ -0,0 +1,730 @@
+/*!***************************************************************************
+*!
+*! FILE NAME  : i2c.c
+*!
+*! DESCRIPTION: implements an interface for IIC/I2C, both directly from other
+*!              kernel modules (i2c_writereg/readreg) and from userspace using
+*!              ioctl()'s
+*!
+*! Nov 30 1998  Torbjorn Eliasson  Initial version.
+*!              Bjorn Wesen        Elinux kernel version.
+*! Jan 14 2000  Johan Adolfsson    Fixed PB shadow register stuff - 
+*!                                 don't use PB_I2C if DS1302 uses same bits,
+*!                                 use PB.
+*! $Log: i2c.c,v $
+*! Revision 1.9  2004/08/24 06:49:14  starvik
+*! Whitespace cleanup
+*!
+*! Revision 1.8  2004/06/08 08:48:26  starvik
+*! Removed unused code
+*!
+*! Revision 1.7  2004/05/28 09:26:59  starvik
+*! Modified I2C initialization to work in 2.6.
+*!
+*! Revision 1.6  2004/05/14 07:58:03  starvik
+*! Merge of changes from 2.4
+*!
+*! Revision 1.4  2002/12/11 13:13:57  starvik
+*! Added arch/ to v10 specific includes
+*! Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer)
+*!
+*! Revision 1.3  2002/11/20 11:56:11  starvik
+*! Merge of Linux 2.5.48
+*!
+*! Revision 1.2  2002/11/18 13:16:06  starvik
+*! Linux 2.5 port of latest 2.4 drivers
+*!
+*! Revision 1.9  2002/10/31 15:32:26  starvik
+*! Update Port B register and shadow even when running with hardware support
+*!   to avoid glitches when reading bits
+*! Never set direction to out in i2c_inbyte
+*! Removed incorrect clock togling at end of i2c_inbyte
+*!
+*! Revision 1.8  2002/08/13 06:31:53  starvik
+*! Made SDA and SCL line configurable
+*! Modified i2c_inbyte to work with PCF8563
+*!
+*! Revision 1.7  2001/04/04 13:11:36  markusl
+*! Updated according to review remarks
+*!
+*! Revision 1.6  2001/03/19 12:43:00  markusl
+*! Made some symbols unstatic (used by the eeprom driver)
+*!
+*! Revision 1.5  2001/02/27 13:52:48  bjornw
+*! malloc.h -> slab.h
+*!
+*! Revision 1.4  2001/02/15 07:17:40  starvik
+*! Corrected usage if port_pb_i2c_shadow
+*!
+*! Revision 1.3  2001/01/26 17:55:13  bjornw
+*! * Made I2C_USES_PB_NOT_PB_I2C a CONFIG option instead of assigning it
+*!   magically. Config.in needs to set it for the options that need it, like
+*!   Dallas 1302 support. Actually, it should be default since it screws up
+*!   the PB bits even if you don't use I2C..
+*! * Include linux/config.h to get the above
+*!
+*! Revision 1.2  2001/01/18 15:49:30  bjornw
+*! 2.4 port of I2C including some cleanups (untested of course)
+*!
+*! Revision 1.1  2001/01/18 15:35:25  bjornw
+*! Verbatim copy of the Etrax i2c driver, 2.0 elinux version
+*!
+*!
+*! ---------------------------------------------------------------------------
+*!
+*! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN
+*!
+*!***************************************************************************/
+/* $Id: i2c.c,v 1.9 2004/08/24 06:49:14 starvik Exp $ */
+
+/****************** INCLUDE FILES SECTION ***********************************/
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/config.h>
+
+#include <asm/etraxi2c.h>
+
+#include <asm/system.h>
+#include <asm/arch/svinto.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+
+#include "i2c.h"
+
+/****************** I2C DEFINITION SECTION *************************/
+
+#define D(x)
+
+#define I2C_MAJOR 123  /* LOCAL/EXPERIMENTAL */
+static const char i2c_name[] = "i2c";
+
+#define CLOCK_LOW_TIME            8
+#define CLOCK_HIGH_TIME           8
+#define START_CONDITION_HOLD_TIME 8
+#define STOP_CONDITION_HOLD_TIME  8
+#define ENABLE_OUTPUT 0x01
+#define ENABLE_INPUT 0x00
+#define I2C_CLOCK_HIGH 1
+#define I2C_CLOCK_LOW 0
+#define I2C_DATA_HIGH 1
+#define I2C_DATA_LOW 0
+
+#ifdef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C
+/* Use PB and not PB_I2C */
+#ifndef CONFIG_ETRAX_I2C_DATA_PORT
+#define CONFIG_ETRAX_I2C_DATA_PORT 0
+#endif
+#ifndef CONFIG_ETRAX_I2C_CLK_PORT
+#define CONFIG_ETRAX_I2C_CLK_PORT 1
+#endif
+
+#define SDABIT CONFIG_ETRAX_I2C_DATA_PORT
+#define SCLBIT CONFIG_ETRAX_I2C_CLK_PORT
+#define i2c_enable() 
+#define i2c_disable() 
+
+/* enable or disable output-enable, to select output or input on the i2c bus */
+
+#define i2c_dir_out() \
+  REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, SDABIT, 1)
+#define i2c_dir_in()  \
+  REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, SDABIT, 0)
+
+/* control the i2c clock and data signals */
+
+#define i2c_clk(x) \
+  REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, SCLBIT, x)
+#define i2c_data(x) \
+  REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, SDABIT, x)
+
+/* read a bit from the i2c interface */
+
+#define i2c_getbit() (((*R_PORT_PB_READ & (1 << SDABIT))) >> SDABIT)
+
+#else
+/* enable or disable the i2c interface */
+
+#define i2c_enable() *R_PORT_PB_I2C = (port_pb_i2c_shadow |= IO_MASK(R_PORT_PB_I2C, i2c_en))
+#define i2c_disable() *R_PORT_PB_I2C = (port_pb_i2c_shadow &= ~IO_MASK(R_PORT_PB_I2C, i2c_en))
+
+/* enable or disable output-enable, to select output or input on the i2c bus */
+
+#define i2c_dir_out() \
+	*R_PORT_PB_I2C = (port_pb_i2c_shadow &= ~IO_MASK(R_PORT_PB_I2C, i2c_oe_)); \
+	REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, 0, 1); 
+#define i2c_dir_in() \
+	*R_PORT_PB_I2C = (port_pb_i2c_shadow |= IO_MASK(R_PORT_PB_I2C, i2c_oe_)); \
+	REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, 0, 0);
+
+/* control the i2c clock and data signals */
+
+#define i2c_clk(x) \
+	*R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \
+       ~IO_MASK(R_PORT_PB_I2C, i2c_clk)) | IO_FIELD(R_PORT_PB_I2C, i2c_clk, (x))); \
+       REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 1, x);
+
+#define i2c_data(x) \
+	*R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \
+	   ~IO_MASK(R_PORT_PB_I2C, i2c_d)) | IO_FIELD(R_PORT_PB_I2C, i2c_d, (x))); \
+	REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 0, x);
+
+/* read a bit from the i2c interface */
+
+#define i2c_getbit() (*R_PORT_PB_READ & 0x1)
+#endif
+
+/* use the kernels delay routine */
+
+#define i2c_delay(usecs) udelay(usecs)
+
+
+/****************** FUNCTION DEFINITION SECTION *************************/
+
+
+/* generate i2c start condition */
+
+void
+i2c_start(void)
+{
+	/*
+	 * SCL=1 SDA=1
+	 */
+	i2c_dir_out();
+	i2c_delay(CLOCK_HIGH_TIME/6);
+	i2c_data(I2C_DATA_HIGH);
+	i2c_clk(I2C_CLOCK_HIGH);
+	i2c_delay(CLOCK_HIGH_TIME);
+	/*
+	 * SCL=1 SDA=0
+	 */
+	i2c_data(I2C_DATA_LOW);
+	i2c_delay(START_CONDITION_HOLD_TIME);
+	/*
+	 * SCL=0 SDA=0
+	 */
+	i2c_clk(I2C_CLOCK_LOW);
+	i2c_delay(CLOCK_LOW_TIME);
+}
+
+/* generate i2c stop condition */
+
+void
+i2c_stop(void)
+{
+	i2c_dir_out();
+
+	/*
+	 * SCL=0 SDA=0
+	 */
+	i2c_clk(I2C_CLOCK_LOW);
+	i2c_data(I2C_DATA_LOW);
+	i2c_delay(CLOCK_LOW_TIME*2);
+	/*
+	 * SCL=1 SDA=0
+	 */
+	i2c_clk(I2C_CLOCK_HIGH);
+	i2c_delay(CLOCK_HIGH_TIME*2);
+	/*
+	 * SCL=1 SDA=1
+	 */
+	i2c_data(I2C_DATA_HIGH);
+	i2c_delay(STOP_CONDITION_HOLD_TIME);
+
+	i2c_dir_in();
+}
+
+/* write a byte to the i2c interface */
+
+void
+i2c_outbyte(unsigned char x)
+{
+	int i;
+
+	i2c_dir_out();
+
+	for (i = 0; i < 8; i++) {
+		if (x & 0x80) {
+			i2c_data(I2C_DATA_HIGH);
+		} else {
+			i2c_data(I2C_DATA_LOW);
+		}
+		
+		i2c_delay(CLOCK_LOW_TIME/2);
+		i2c_clk(I2C_CLOCK_HIGH);
+		i2c_delay(CLOCK_HIGH_TIME);
+		i2c_clk(I2C_CLOCK_LOW);
+		i2c_delay(CLOCK_LOW_TIME/2);
+		x <<= 1;
+	}
+	i2c_data(I2C_DATA_LOW);
+	i2c_delay(CLOCK_LOW_TIME/2);
+
+	/*
+	 * enable input
+	 */
+	i2c_dir_in();
+}
+
+/* read a byte from the i2c interface */
+
+unsigned char
+i2c_inbyte(void)
+{
+	unsigned char aBitByte = 0;
+	int i;
+
+	/* Switch off I2C to get bit */
+	i2c_disable();
+	i2c_dir_in();
+	i2c_delay(CLOCK_HIGH_TIME/2);
+
+	/* Get bit */
+	aBitByte |= i2c_getbit();
+
+	/* Enable I2C */
+	i2c_enable();
+	i2c_delay(CLOCK_LOW_TIME/2);
+
+	for (i = 1; i < 8; i++) {
+		aBitByte <<= 1;
+		/* Clock pulse */
+		i2c_clk(I2C_CLOCK_HIGH);
+		i2c_delay(CLOCK_HIGH_TIME);
+		i2c_clk(I2C_CLOCK_LOW);
+		i2c_delay(CLOCK_LOW_TIME);
+
+		/* Switch off I2C to get bit */
+		i2c_disable();
+		i2c_dir_in();
+		i2c_delay(CLOCK_HIGH_TIME/2);
+
+		/* Get bit */
+		aBitByte |= i2c_getbit();
+
+		/* Enable I2C */
+		i2c_enable();
+		i2c_delay(CLOCK_LOW_TIME/2);
+	}
+	i2c_clk(I2C_CLOCK_HIGH);
+	i2c_delay(CLOCK_HIGH_TIME);
+
+        /*
+	 * we leave the clock low, getbyte is usually followed
+	 * by sendack/nack, they assume the clock to be low
+	 */
+        i2c_clk(I2C_CLOCK_LOW);
+	return aBitByte;
+}
+
+/*#---------------------------------------------------------------------------
+*#
+*# FUNCTION NAME: i2c_getack
+*#
+*# DESCRIPTION  : checks if ack was received from ic2
+*#
+*#--------------------------------------------------------------------------*/
+
+int
+i2c_getack(void)
+{
+	int ack = 1;
+	/*
+	 * enable output
+	 */
+	i2c_dir_out();
+	/*
+	 * Release data bus by setting
+	 * data high
+	 */
+	i2c_data(I2C_DATA_HIGH);
+	/*
+	 * enable input
+	 */
+	i2c_dir_in();
+	i2c_delay(CLOCK_HIGH_TIME/4);
+	/*
+	 * generate ACK clock pulse
+	 */
+	i2c_clk(I2C_CLOCK_HIGH);
+	/*
+	 * Use PORT PB instead of I2C
+	 * for input. (I2C not working)
+	 */
+	i2c_clk(1);
+	i2c_data(1);
+	/*
+	 * switch off I2C
+	 */
+	i2c_data(1);
+	i2c_disable();
+	i2c_dir_in();
+	/*
+	 * now wait for ack
+	 */
+	i2c_delay(CLOCK_HIGH_TIME/2);
+	/*
+	 * check for ack
+	 */
+	if(i2c_getbit())
+		ack = 0;
+	i2c_delay(CLOCK_HIGH_TIME/2);
+	if(!ack){
+		if(!i2c_getbit()) /* receiver pulld SDA low */
+			ack = 1;
+		i2c_delay(CLOCK_HIGH_TIME/2);
+	}
+
+	/*
+	 * our clock is high now, make sure data is low
+	 * before we enable our output. If we keep data high
+	 * and enable output, we would generate a stop condition.
+	 */
+	i2c_data(I2C_DATA_LOW);
+
+	/*
+	 * end clock pulse
+	 */
+	i2c_enable();
+	i2c_dir_out();
+	i2c_clk(I2C_CLOCK_LOW);
+	i2c_delay(CLOCK_HIGH_TIME/4);
+	/*
+	 * enable output
+	 */
+	i2c_dir_out();
+	/*
+	 * remove ACK clock pulse
+	 */
+	i2c_data(I2C_DATA_HIGH);
+	i2c_delay(CLOCK_LOW_TIME/2);
+	return ack;
+}
+
+/*#---------------------------------------------------------------------------
+*#
+*# FUNCTION NAME: I2C::sendAck
+*#
+*# DESCRIPTION  : Send ACK on received data
+*#
+*#--------------------------------------------------------------------------*/
+void
+i2c_sendack(void)
+{
+	/*
+	 * enable output
+	 */
+	i2c_delay(CLOCK_LOW_TIME);
+	i2c_dir_out();
+	/*
+	 * set ack pulse high
+	 */
+	i2c_data(I2C_DATA_LOW);
+	/*
+	 * generate clock pulse
+	 */
+	i2c_delay(CLOCK_HIGH_TIME/6);
+	i2c_clk(I2C_CLOCK_HIGH);
+	i2c_delay(CLOCK_HIGH_TIME);
+	i2c_clk(I2C_CLOCK_LOW);
+	i2c_delay(CLOCK_LOW_TIME/6);
+	/*
+	 * reset data out
+	 */
+	i2c_data(I2C_DATA_HIGH);
+	i2c_delay(CLOCK_LOW_TIME);
+
+	i2c_dir_in();
+}
+
+/*#---------------------------------------------------------------------------
+*#
+*# FUNCTION NAME: i2c_sendnack
+*#
+*# DESCRIPTION  : Sends NACK on received data
+*#
+*#--------------------------------------------------------------------------*/
+void
+i2c_sendnack(void)
+{
+	/*
+	 * enable output
+	 */
+	i2c_delay(CLOCK_LOW_TIME);
+	i2c_dir_out();
+	/*
+	 * set data high
+	 */
+	i2c_data(I2C_DATA_HIGH);
+	/*
+	 * generate clock pulse
+	 */
+	i2c_delay(CLOCK_HIGH_TIME/6);
+	i2c_clk(I2C_CLOCK_HIGH);
+	i2c_delay(CLOCK_HIGH_TIME);
+	i2c_clk(I2C_CLOCK_LOW);
+	i2c_delay(CLOCK_LOW_TIME);
+
+	i2c_dir_in();
+}
+
+/*#---------------------------------------------------------------------------
+*#
+*# FUNCTION NAME: i2c_writereg
+*#
+*# DESCRIPTION  : Writes a value to an I2C device
+*#
+*#--------------------------------------------------------------------------*/
+int
+i2c_writereg(unsigned char theSlave, unsigned char theReg, 
+	     unsigned char theValue)
+{
+	int error, cntr = 3;
+	unsigned long flags;
+
+	do {
+		error = 0;
+		/*
+		 * we don't like to be interrupted
+		 */
+		local_irq_save(flags);
+		local_irq_disable();
+
+		i2c_start();
+		/*
+		 * send slave address
+		 */
+		i2c_outbyte((theSlave & 0xfe));
+		/*
+		 * wait for ack
+		 */
+		if(!i2c_getack())
+			error = 1;
+		/*
+		 * now select register
+		 */
+		i2c_dir_out();
+		i2c_outbyte(theReg);
+		/*
+		 * now it's time to wait for ack
+		 */
+		if(!i2c_getack())
+			error |= 2;
+		/*
+		 * send register register data
+		 */
+		i2c_outbyte(theValue);
+		/*
+		 * now it's time to wait for ack
+		 */
+		if(!i2c_getack())
+			error |= 4;
+		/*
+		 * end byte stream
+		 */
+		i2c_stop();
+		/*
+		 * enable interrupt again
+		 */
+		local_irq_restore(flags);
+		
+	} while(error && cntr--);
+
+	i2c_delay(CLOCK_LOW_TIME);
+
+	return -error;
+}
+
+/*#---------------------------------------------------------------------------
+*#
+*# FUNCTION NAME: i2c_readreg
+*#
+*# DESCRIPTION  : Reads a value from the decoder registers.
+*#
+*#--------------------------------------------------------------------------*/
+unsigned char
+i2c_readreg(unsigned char theSlave, unsigned char theReg)
+{
+	unsigned char b = 0;
+	int error, cntr = 3;
+	unsigned long flags;
+
+	do {
+		error = 0;
+		/*
+		 * we don't like to be interrupted
+		 */
+		local_irq_save(flags);
+		local_irq_disable();
+		/*
+		 * generate start condition
+		 */
+		i2c_start();
+    
+		/*
+		 * send slave address
+		 */
+		i2c_outbyte((theSlave & 0xfe));
+		/*
+		 * wait for ack
+		 */
+		if(!i2c_getack())
+			error = 1;
+		/*
+		 * now select register
+		 */
+		i2c_dir_out();
+		i2c_outbyte(theReg);
+		/*
+		 * now it's time to wait for ack
+		 */
+		if(!i2c_getack())
+			error = 1;
+		/*
+		 * repeat start condition
+		 */
+		i2c_delay(CLOCK_LOW_TIME);
+		i2c_start();
+		/*
+		 * send slave address
+		 */
+		i2c_outbyte(theSlave | 0x01);
+		/*
+		 * wait for ack
+		 */
+		if(!i2c_getack())
+			error = 1;
+		/*
+		 * fetch register
+		 */
+		b = i2c_inbyte();
+		/*
+		 * last received byte needs to be nacked
+		 * instead of acked
+		 */
+		i2c_sendack();
+		/*
+		 * end sequence
+		 */
+		i2c_stop();
+		/*
+		 * enable interrupt again
+		 */
+		local_irq_restore(flags);
+		
+	} while(error && cntr--);
+
+	return b;
+}
+
+static int
+i2c_open(struct inode *inode, struct file *filp)
+{
+	return 0;
+}
+
+static int
+i2c_release(struct inode *inode, struct file *filp)
+{
+	return 0;
+}
+
+/* Main device API. ioctl's to write or read to/from i2c registers.
+ */
+
+static int
+i2c_ioctl(struct inode *inode, struct file *file,
+	  unsigned int cmd, unsigned long arg)
+{
+	if(_IOC_TYPE(cmd) != ETRAXI2C_IOCTYPE) {
+		return -EINVAL;
+	}
+
+	switch (_IOC_NR(cmd)) {
+		case I2C_WRITEREG:
+			/* write to an i2c slave */
+			D(printk("i2cw %d %d %d\n", 
+				 I2C_ARGSLAVE(arg),
+				 I2C_ARGREG(arg),
+				 I2C_ARGVALUE(arg)));
+
+			return i2c_writereg(I2C_ARGSLAVE(arg),
+					    I2C_ARGREG(arg),
+					    I2C_ARGVALUE(arg));
+		case I2C_READREG:
+		{
+			unsigned char val;
+			/* read from an i2c slave */
+			D(printk("i2cr %d %d ", 
+				I2C_ARGSLAVE(arg),
+				I2C_ARGREG(arg)));
+			val = i2c_readreg(I2C_ARGSLAVE(arg), I2C_ARGREG(arg));
+			D(printk("= %d\n", val));
+			return val;
+		}					    
+		default:
+			return -EINVAL;
+
+	}
+	
+	return 0;
+}
+
+static struct file_operations i2c_fops = {
+	.owner    = THIS_MODULE,
+	.ioctl    = i2c_ioctl,
+	.open     = i2c_open,
+	.release  = i2c_release,
+};
+
+int __init
+i2c_init(void)
+{
+	/* Setup and enable the Port B I2C interface */
+
+#ifndef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C
+	*R_PORT_PB_I2C = port_pb_i2c_shadow |= 
+		IO_STATE(R_PORT_PB_I2C, i2c_en,  on) |
+		IO_FIELD(R_PORT_PB_I2C, i2c_d,   1)  |
+		IO_FIELD(R_PORT_PB_I2C, i2c_clk, 1)  |
+		IO_STATE(R_PORT_PB_I2C, i2c_oe_, enable);
+#endif
+
+	port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir0);
+	port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir1);
+
+	*R_PORT_PB_DIR = (port_pb_dir_shadow |=
+			  IO_STATE(R_PORT_PB_DIR, dir0, input)  |
+			  IO_STATE(R_PORT_PB_DIR, dir1, output));
+
+	return 0;
+}
+
+static int __init
+i2c_register(void)
+{
+	int res;
+
+	i2c_init();
+  	res = register_chrdev(I2C_MAJOR, i2c_name, &i2c_fops);
+	if(res < 0) {
+		printk(KERN_ERR "i2c: couldn't get a major number.\n");
+		return res;
+	}
+
+	printk(KERN_INFO "I2C driver v2.2, (c) 1999-2001 Axis Communications AB\n");
+	
+	return 0;
+}
+
+/* this makes sure that i2c_register is called during boot */
+
+module_init(i2c_register);
+
+/****************** END OF FILE i2c.c ********************************/
diff --git a/arch/cris/arch-v10/drivers/i2c.h b/arch/cris/arch-v10/drivers/i2c.h
new file mode 100644
index 0000000..4ee9142
--- /dev/null
+++ b/arch/cris/arch-v10/drivers/i2c.h
@@ -0,0 +1,18 @@
+/* $Id: i2c.h,v 1.3 2004/05/28 09:26:59 starvik Exp $ */
+
+int i2c_init(void);
+
+/* High level I2C actions */
+int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue);
+unsigned char i2c_readreg(unsigned char theSlave, unsigned char theReg);
+
+/* Low level I2C */
+void i2c_start(void);
+void i2c_stop(void);
+void i2c_outbyte(unsigned char x);
+unsigned char i2c_inbyte(void);
+int i2c_getack(void);
+void i2c_sendack(void);
+
+
+
diff --git a/arch/cris/arch-v10/drivers/pcf8563.c b/arch/cris/arch-v10/drivers/pcf8563.c
new file mode 100644
index 0000000..b3dfdf7
--- /dev/null
+++ b/arch/cris/arch-v10/drivers/pcf8563.c
@@ -0,0 +1,313 @@
+/*
+ * PCF8563 RTC
+ *
+ * From Phillips' datasheet:
+ *
+ * The PCF8563 is a CMOS real-time clock/calendar optimized for low power
+ * consumption. A programmable clock output, interupt output and voltage
+ * low detector are also provided. All address and data are transferred
+ * serially via two-line bidirectional I2C-bus. Maximum bus speed is
+ * 400 kbits/s. The built-in word address register is incremented
+ * automatically after each written or read bute.
+ *
+ * Copyright (c) 2002, Axis Communications AB
+ * All rights reserved.
+ *
+ * Author: Tobias Anderberg <tobiasa@axis.com>.
+ *
+ * $Id: pcf8563.c,v 1.8 2004/08/24 06:42:51 starvik Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/bcd.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/arch/svinto.h>
+#include <asm/rtc.h>
+#include "i2c.h"
+
+#define PCF8563_MAJOR 121		/* Local major number. */
+#define DEVICE_NAME "rtc"		/* Name which is registered in /proc/devices. */
+#define PCF8563_NAME "PCF8563"
+#define DRIVER_VERSION "$Revision: 1.8 $"
+
+/* I2C bus slave registers. */
+#define RTC_I2C_READ		0xa3
+#define RTC_I2C_WRITE		0xa2
+
+/* Two simple wrapper macros, saves a few keystrokes. */
+#define rtc_read(x) i2c_readreg(RTC_I2C_READ, x)
+#define rtc_write(x,y) i2c_writereg(RTC_I2C_WRITE, x, y)
+	
+static const unsigned char days_in_month[] =
+	{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+int pcf8563_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+
+static struct file_operations pcf8563_fops = {
+	.owner = THIS_MODULE,
+	.ioctl = pcf8563_ioctl,
+};
+
+unsigned char
+pcf8563_readreg(int reg) 
+{
+	unsigned char res = i2c_readreg(RTC_I2C_READ, reg);
+
+	/* The PCF8563 does not return 0 for unimplemented bits */
+	switch(reg)
+	{
+		case RTC_SECONDS:
+		case RTC_MINUTES:
+		     res &= 0x7f;
+		     break;
+		case RTC_HOURS:
+		case RTC_DAY_OF_MONTH:
+		     res &= 0x3f;
+		     break;
+		case RTC_MONTH:
+		     res = (res & 0x1f) - 1;  /* PCF8563 returns month in range 1-12 */
+		     break;
+	}
+	return res;
+}
+
+void
+pcf8563_writereg(int reg, unsigned char val) 
+{
+#ifdef CONFIG_ETRAX_RTC_READONLY
+	if (reg == RTC_CONTROL1 || (reg >= RTC_SECONDS && reg <= RTC_YEAR))
+		return;
+#endif
+
+	rtc_write(reg, val);
+}
+
+void
+get_rtc_time(struct rtc_time *tm)
+{
+	tm->tm_sec = rtc_read(RTC_SECONDS);
+	tm->tm_min = rtc_read(RTC_MINUTES);
+	tm->tm_hour = rtc_read(RTC_HOURS);
+	tm->tm_mday = rtc_read(RTC_DAY_OF_MONTH);
+	tm->tm_mon = rtc_read(RTC_MONTH);
+	tm->tm_year = rtc_read(RTC_YEAR);
+
+	if (tm->tm_sec & 0x80)
+		printk(KERN_WARNING "%s: RTC Low Voltage - date/time is not reliable!\n", PCF8563_NAME);
+
+	tm->tm_year = BCD_TO_BIN(tm->tm_year) + ((tm->tm_mon & 0x80) ? 100 : 0);
+	tm->tm_sec &= 0x7f;
+	tm->tm_min &= 0x7f;
+	tm->tm_hour &= 0x3f;
+	tm->tm_mday &= 0x3f;
+	tm->tm_mon &= 0x1f;
+
+	BCD_TO_BIN(tm->tm_sec);
+	BCD_TO_BIN(tm->tm_min);
+	BCD_TO_BIN(tm->tm_hour);
+	BCD_TO_BIN(tm->tm_mday);
+	BCD_TO_BIN(tm->tm_mon);
+	tm->tm_mon--; /* Month is 1..12 in RTC but 0..11 in linux */
+}
+
+int __init
+pcf8563_init(void)
+{
+	unsigned char ret;
+
+	i2c_init();
+
+	/*
+	 * First of all we need to reset the chip. This is done by
+	 * clearing control1, control2 and clk freq, clear the 
+	 * Voltage Low bit, and resetting all alarms.
+	 */
+	if (rtc_write(RTC_CONTROL1, 0x00) < 0)
+		goto err;
+
+	if (rtc_write(RTC_CONTROL2, 0x00) < 0)
+		goto err;
+
+	if (rtc_write(RTC_CLOCKOUT_FREQ, 0x00) < 0)
+		goto err;
+
+	/* Clear the VL bit in the seconds register. */
+	ret = rtc_read(RTC_SECONDS);
+	
+	if (rtc_write(RTC_SECONDS, (ret & 0x7f)) < 0)
+		goto err;
+		
+	/* Reset the alarms. */
+	if (rtc_write(RTC_MINUTE_ALARM, 0x00) < 0)
+		goto err;
+	
+	if (rtc_write(RTC_HOUR_ALARM, 0x00) < 0)
+		goto err;
+	
+	if (rtc_write(RTC_DAY_ALARM, 0x00) < 0)
+		goto err;
+	
+	if (rtc_write(RTC_WEEKDAY_ALARM, 0x00) < 0)
+		goto err;
+        
+	/* Check for low voltage, and warn about it.. */
+	if (rtc_read(RTC_SECONDS) & 0x80)
+		printk(KERN_WARNING "%s: RTC Low Voltage - date/time is not reliable!\n", PCF8563_NAME);
+	
+	return 0;
+
+err:
+	printk(KERN_INFO "%s: Error initializing chip.\n", PCF8563_NAME);
+	return -1;
+}
+
+void __exit
+pcf8563_exit(void)
+{
+	if (unregister_chrdev(PCF8563_MAJOR, DEVICE_NAME) < 0) {
+		printk(KERN_INFO "%s: Unable to unregister device.\n", PCF8563_NAME);
+	}
+}
+
+/*
+ * ioctl calls for this driver. Why return -ENOTTY upon error? Because
+ * POSIX says so!
+ */
+int
+pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	/* Some sanity checks. */
+	if (_IOC_TYPE(cmd) != RTC_MAGIC)
+		return -ENOTTY;
+
+	if (_IOC_NR(cmd) > RTC_MAX_IOCTL)
+		return -ENOTTY;
+
+	switch (cmd) {
+		case RTC_RD_TIME:
+			{
+				struct rtc_time tm;
+
+				get_rtc_time(&tm);
+
+				if (copy_to_user((struct rtc_time *) arg, &tm, sizeof(struct rtc_time))) {
+					return -EFAULT;
+				}
+
+				return 0;
+			}
+			break;
+		case RTC_SET_TIME:
+			{
+#ifdef CONFIG_ETRAX_RTC_READONLY
+				return -EPERM;
+#else
+				int leap;
+				int century;
+				struct rtc_time tm;
+
+				memset(&tm, 0, sizeof (struct rtc_time));
+				if (!capable(CAP_SYS_TIME))
+					return -EPERM;
+
+				if (copy_from_user(&tm, (struct rtc_time *) arg, sizeof(struct rtc_time)))
+					return -EFAULT;
+
+				/* Convert from struct tm to struct rtc_time. */
+				tm.tm_year += 1900;
+				tm.tm_mon += 1;
+				
+				leap = ((tm.tm_mon == 2) && ((tm.tm_year % 4) == 0)) ? 1 : 0;
+
+				/* Perform some sanity checks. */
+				if ((tm.tm_year < 1970) ||
+				    (tm.tm_mon > 12) ||
+				    (tm.tm_mday == 0) ||
+				    (tm.tm_mday > days_in_month[tm.tm_mon] + leap) ||
+				    (tm.tm_hour >= 24) ||
+				    (tm.tm_min >= 60) ||
+				    (tm.tm_sec >= 60))
+					return -EINVAL;
+
+				century = (tm.tm_year >= 2000) ? 0x80 : 0;
+				tm.tm_year = tm.tm_year % 100;
+
+				BIN_TO_BCD(tm.tm_year);
+				BIN_TO_BCD(tm.tm_mday);
+				BIN_TO_BCD(tm.tm_hour);
+				BIN_TO_BCD(tm.tm_min);
+				BIN_TO_BCD(tm.tm_sec);
+				tm.tm_mon |= century;
+				
+				rtc_write(RTC_YEAR, tm.tm_year);
+				rtc_write(RTC_MONTH, tm.tm_mon);
+				rtc_write(RTC_DAY_OF_MONTH, tm.tm_mday);
+				rtc_write(RTC_HOURS, tm.tm_hour);
+				rtc_write(RTC_MINUTES, tm.tm_min);
+				rtc_write(RTC_SECONDS, tm.tm_sec);
+
+				return 0;
+#endif /* !CONFIG_ETRAX_RTC_READONLY */
+			}
+
+		case RTC_VLOW_RD:
+		{
+			int vl_bit = 0;
+
+			if (rtc_read(RTC_SECONDS) & 0x80) {
+				vl_bit = 1;
+				printk(KERN_WARNING "%s: RTC Voltage Low - reliable "
+				       "date/time information is no longer guaranteed!\n",
+				       PCF8563_NAME);
+			}
+			if (copy_to_user((int *) arg, &vl_bit, sizeof(int)))
+				return -EFAULT;
+
+			return 0;
+		}
+
+		case RTC_VLOW_SET:
+		{
+			/* Clear the VL bit in the seconds register */
+			int ret = rtc_read(RTC_SECONDS);
+
+			rtc_write(RTC_SECONDS, (ret & 0x7F));
+
+			return 0;
+		}
+
+		default:
+				return -ENOTTY;
+	}
+
+	return 0;
+}
+
+static int __init
+pcf8563_register(void)
+{
+	pcf8563_init();
+	if (register_chrdev(PCF8563_MAJOR, DEVICE_NAME, &pcf8563_fops) < 0) {
+		printk(KERN_INFO "%s: Unable to get major numer %d for RTC device.\n",
+		       PCF8563_NAME, PCF8563_MAJOR);
+		return -1;
+	}
+
+	printk(KERN_INFO "%s Real-Time Clock Driver, %s\n", PCF8563_NAME, DRIVER_VERSION);
+        return 0;
+}
+
+module_init(pcf8563_register);
+module_exit(pcf8563_exit);
diff --git a/arch/cris/arch-v10/kernel/Makefile b/arch/cris/arch-v10/kernel/Makefile
new file mode 100644
index 0000000..5276160
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/Makefile
@@ -0,0 +1,17 @@
+# $Id: Makefile,v 1.5 2004/06/02 08:24:38 starvik Exp $
+#
+# Makefile for the linux kernel.
+#
+
+extra-y	:= head.o
+
+
+obj-y   := entry.o traps.o shadows.o debugport.o irq.o \
+	   process.o setup.o signal.o traps.o time.o ptrace.o
+
+obj-$(CONFIG_ETRAX_KGDB) += kgdb.o
+obj-$(CONFIG_ETRAX_FAST_TIMER) += fasttimer.o
+obj-$(CONFIG_MODULES)    += crisksyms.o
+
+clean:
+
diff --git a/arch/cris/arch-v10/kernel/asm-offsets.c b/arch/cris/arch-v10/kernel/asm-offsets.c
new file mode 100644
index 0000000..1aa3cc4
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/asm-offsets.c
@@ -0,0 +1,47 @@
+#include <linux/sched.h>
+#include <asm/thread_info.h>
+
+/*
+ * Generate definitions needed by assembly language modules.
+ * This code generates raw asm output which is post-processed to extract
+ * and format the required data.
+ */
+
+#define DEFINE(sym, val) \
+        asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define BLANK() asm volatile("\n->" : : )
+
+int main(void)
+{
+#define ENTRY(entry) DEFINE(PT_ ## entry, offsetof(struct pt_regs, entry))
+	ENTRY(orig_r10);
+	ENTRY(r13); 
+	ENTRY(r12); 
+	ENTRY(r11);
+        ENTRY(r10);
+        ENTRY(r9);
+        ENTRY(mof);
+        ENTRY(dccr);
+        ENTRY(srp);
+	BLANK();
+#undef ENTRY
+#define ENTRY(entry) DEFINE(TI_ ## entry, offsetof(struct thread_info, entry))
+        ENTRY(task);
+        ENTRY(flags);
+        ENTRY(preempt_count);
+        BLANK();
+#undef ENTRY
+#define ENTRY(entry) DEFINE(THREAD_ ## entry, offsetof(struct thread_struct, entry))
+	ENTRY(ksp);
+        ENTRY(usp);
+        ENTRY(dccr);
+        BLANK();
+#undef ENTRY
+#define ENTRY(entry) DEFINE(TASK_ ## entry, offsetof(struct task_struct, entry))
+        ENTRY(pid);
+        BLANK();
+        DEFINE(LCLONE_VM, CLONE_VM);
+        DEFINE(LCLONE_UNTRACED, CLONE_UNTRACED);
+        return 0;
+}
diff --git a/arch/cris/arch-v10/kernel/crisksyms.c b/arch/cris/arch-v10/kernel/crisksyms.c
new file mode 100644
index 0000000..b332bf9
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/crisksyms.c
@@ -0,0 +1,17 @@
+#include <linux/config.h>
+#include <linux/module.h>
+#include <asm/io.h>
+#include <asm/arch/svinto.h>
+
+/* Export shadow registers for the CPU I/O pins */
+EXPORT_SYMBOL(genconfig_shadow);
+EXPORT_SYMBOL(port_pa_data_shadow);
+EXPORT_SYMBOL(port_pa_dir_shadow);
+EXPORT_SYMBOL(port_pb_data_shadow);
+EXPORT_SYMBOL(port_pb_dir_shadow);
+EXPORT_SYMBOL(port_pb_config_shadow);
+EXPORT_SYMBOL(port_g_data_shadow);
+
+/* Cache flush functions */
+EXPORT_SYMBOL(flush_etrax_cache);
+EXPORT_SYMBOL(prepare_rx_descriptor);
diff --git a/arch/cris/arch-v10/kernel/debugport.c b/arch/cris/arch-v10/kernel/debugport.c
new file mode 100644
index 0000000..6cf069e
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/debugport.c
@@ -0,0 +1,531 @@
+/* Serialport functions for debugging
+ *
+ * Copyright (c) 2000 Axis Communications AB
+ *
+ * Authors:  Bjorn Wesen
+ *
+ * Exports:
+ *    console_print_etrax(char *buf)
+ *    int getDebugChar()
+ *    putDebugChar(int)
+ *    enableDebugIRQ()
+ *    init_etrax_debug()
+ *
+ * $Log: debugport.c,v $
+ * Revision 1.19  2004/10/21 07:26:16  starvik
+ * Made it possible to specify console settings on kernel command line.
+ *
+ * Revision 1.18  2004/10/19 13:07:37  starvik
+ * Merge of Linux 2.6.9
+ *
+ * Revision 1.17  2004/09/29 10:33:46  starvik
+ * Resolved a dealock when printing debug from kernel.
+ *
+ * Revision 1.16  2004/08/24 06:12:19  starvik
+ * Whitespace cleanup
+ *
+ * Revision 1.15  2004/08/16 12:37:19  starvik
+ * Merge of Linux 2.6.8
+ *
+ * Revision 1.14  2004/05/17 13:11:29  starvik
+ * Disable DMA until real serial driver is up
+ *
+ * Revision 1.13  2004/05/14 07:58:01  starvik
+ * Merge of changes from 2.4
+ *
+ * Revision 1.12  2003/09/11 07:29:49  starvik
+ * Merge of Linux 2.6.0-test5
+ *
+ * Revision 1.11  2003/07/07 09:53:36  starvik
+ * Revert all the 2.5.74 merge changes to make the console work again
+ *
+ * Revision 1.9  2003/02/17 17:07:23  starvik
+ * Solved the problem with corrupted debug output (from Linux 2.4)
+ *   * Wait until DMA, FIFO and pipe is empty before and after transmissions
+ *   * Buffer data until a FIFO flush can be triggered.
+ *
+ * Revision 1.8  2003/01/22 06:48:36  starvik
+ * Fixed warnings issued by GCC 3.2.1
+ *
+ * Revision 1.7  2002/12/12 08:26:32  starvik
+ * Don't use C-comments inside CVS comments
+ *
+ * Revision 1.6  2002/12/11 15:42:02  starvik
+ * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/
+ *
+ * Revision 1.5  2002/11/20 06:58:03  starvik
+ * Compiles with kgdb
+ *
+ * Revision 1.4  2002/11/19 14:35:24  starvik
+ * Changes from linux 2.4
+ * Changed struct initializer syntax to the currently prefered notation
+ *
+ * Revision 1.3  2002/11/06 09:47:03  starvik
+ * Modified for new interrupt macros
+ *
+ * Revision 1.2  2002/01/21 15:21:50  bjornw
+ * Update for kdev_t changes
+ *
+ * Revision 1.6  2001/04/17 13:58:39  orjanf
+ * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB.
+ *
+ * Revision 1.5  2001/03/26 14:22:05  bjornw
+ * Namechange of some config options
+ *
+ * Revision 1.4  2000/10/06 12:37:26  bjornw
+ * Use physical addresses when talking to DMA
+ *
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/major.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <asm/system.h>
+#include <asm/arch/svinto.h>
+#include <asm/io.h>             /* Get SIMCOUT. */
+
+struct dbg_port
+{
+  unsigned int index;
+  const volatile unsigned* read;
+  volatile char* write;
+  volatile unsigned* xoff;
+  volatile char* baud;
+  volatile char* tr_ctrl;
+  volatile char* rec_ctrl;
+  unsigned long irq;
+  unsigned int started;
+  unsigned long baudrate;
+  unsigned char parity;
+  unsigned int bits;
+};
+
+struct dbg_port ports[]=
+{
+  {
+    0,
+    R_SERIAL0_READ,
+    R_SERIAL0_TR_DATA,
+    R_SERIAL0_XOFF,
+    R_SERIAL0_BAUD,
+    R_SERIAL0_TR_CTRL,
+    R_SERIAL0_REC_CTRL,
+    IO_STATE(R_IRQ_MASK1_SET, ser0_data, set)
+  },
+  {
+    1,
+    R_SERIAL1_READ,
+    R_SERIAL1_TR_DATA,
+    R_SERIAL1_XOFF,
+    R_SERIAL1_BAUD,
+    R_SERIAL1_TR_CTRL,
+    R_SERIAL1_REC_CTRL,
+    IO_STATE(R_IRQ_MASK1_SET, ser1_data, set)
+  },
+  {
+    2,
+    R_SERIAL2_READ,
+    R_SERIAL2_TR_DATA,
+    R_SERIAL2_XOFF,
+    R_SERIAL2_BAUD,
+    R_SERIAL2_TR_CTRL,
+    R_SERIAL2_REC_CTRL,
+    IO_STATE(R_IRQ_MASK1_SET, ser2_data, set)
+  },
+  {
+    3,
+    R_SERIAL3_READ,
+    R_SERIAL3_TR_DATA,
+    R_SERIAL3_XOFF,
+    R_SERIAL3_BAUD,
+    R_SERIAL3_TR_CTRL,
+    R_SERIAL3_REC_CTRL,
+    IO_STATE(R_IRQ_MASK1_SET, ser3_data, set)
+  }
+};
+
+static struct tty_driver *serial_driver;
+
+struct dbg_port* port =
+#if defined(CONFIG_ETRAX_DEBUG_PORT0)
+  &ports[0];
+#elif defined(CONFIG_ETRAX_DEBUG_PORT1)
+  &ports[1];
+#elif defined(CONFIG_ETRAX_DEBUG_PORT2)
+  &ports[2];
+#elif defined(CONFIG_ETRAX_DEBUG_PORT3)
+  &ports[3];
+#else
+  NULL;
+#endif
+/* Used by serial.c to register a debug_write_function so that the normal
+ * serial driver is used for kernel debug output
+ */
+typedef int (*debugport_write_function)(int i, const char *buf, unsigned int len);
+
+debugport_write_function debug_write_function = NULL;
+
+static void
+start_port(void)
+{
+	unsigned long rec_ctrl = 0;
+	unsigned long tr_ctrl = 0;
+
+	if (!port)
+		return;
+
+	if (port->started)
+		return;
+	port->started = 1;
+
+	if (port->index == 0)
+	{
+		genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6);
+		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused);
+	}
+	else if (port->index == 1)
+	{
+		genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8);
+		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb);
+	}
+	else if (port->index == 2)
+	{
+		genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2);
+		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0);
+		genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma3);
+		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, par0);
+		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, ser2, select);
+	}
+	else
+	{
+		genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma4);
+		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, par1);
+		genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma5);
+		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, par1);
+		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, ser3, select);
+	}
+
+	*R_GEN_CONFIG = genconfig_shadow;
+
+	*port->xoff =
+		IO_STATE(R_SERIAL0_XOFF, tx_stop, enable) |
+		IO_STATE(R_SERIAL0_XOFF, auto_xoff, disable) |
+		IO_FIELD(R_SERIAL0_XOFF, xoff_char, 0);
+
+	switch (port->baudrate)
+	{
+	case 0:
+	case 115200:
+		*port->baud =
+		  IO_STATE(R_SERIAL0_BAUD, tr_baud, c115k2Hz) |
+		  IO_STATE(R_SERIAL0_BAUD, rec_baud, c115k2Hz);
+		break;
+	case 1200:
+		*port->baud =
+		  IO_STATE(R_SERIAL0_BAUD, tr_baud, c1200Hz) |
+		  IO_STATE(R_SERIAL0_BAUD, rec_baud, c1200Hz);
+		break;
+	case 2400:
+		*port->baud =
+		  IO_STATE(R_SERIAL0_BAUD, tr_baud, c2400Hz) |
+		  IO_STATE(R_SERIAL0_BAUD, rec_baud, c2400Hz);
+		break;
+	case 4800:
+		*port->baud =
+		  IO_STATE(R_SERIAL0_BAUD, tr_baud, c4800Hz) |
+		  IO_STATE(R_SERIAL0_BAUD, rec_baud, c4800Hz);
+		break;
+	case 9600:
+		*port->baud =
+		  IO_STATE(R_SERIAL0_BAUD, tr_baud, c9600Hz) |
+		  IO_STATE(R_SERIAL0_BAUD, rec_baud, c9600Hz);
+		  break;
+	case 19200:
+		*port->baud =
+		  IO_STATE(R_SERIAL0_BAUD, tr_baud, c19k2Hz) |
+		  IO_STATE(R_SERIAL0_BAUD, rec_baud, c19k2Hz);
+		 break;
+	case 38400:
+		*port->baud =
+		  IO_STATE(R_SERIAL0_BAUD, tr_baud, c38k4Hz) |
+		  IO_STATE(R_SERIAL0_BAUD, rec_baud, c38k4Hz);
+		break;
+	case 57600:
+		*port->baud =
+		  IO_STATE(R_SERIAL0_BAUD, tr_baud, c57k6Hz) |
+		  IO_STATE(R_SERIAL0_BAUD, rec_baud, c57k6Hz);
+		break;
+	default:
+		*port->baud =
+		  IO_STATE(R_SERIAL0_BAUD, tr_baud, c115k2Hz) |
+		  IO_STATE(R_SERIAL0_BAUD, rec_baud, c115k2Hz);
+		  break;
+        }
+
+	if (port->parity == 'E') {
+		rec_ctrl =
+		  IO_STATE(R_SERIAL0_REC_CTRL, rec_par, even) |
+		  IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable);
+		tr_ctrl =
+		  IO_STATE(R_SERIAL0_TR_CTRL, tr_par, even) |
+		  IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable);
+	} else if (port->parity == 'O') {
+		rec_ctrl =
+		  IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd) |
+		  IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable);
+		tr_ctrl =
+		  IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd) |
+		  IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable);
+	} else {
+		rec_ctrl =
+		  IO_STATE(R_SERIAL0_REC_CTRL, rec_par, even) |
+		  IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, disable);
+		tr_ctrl =
+		  IO_STATE(R_SERIAL0_TR_CTRL, tr_par, even) |
+		  IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, disable);
+	}
+
+	if (port->bits == 7)
+	{
+		rec_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_7bit);
+		tr_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_7bit);
+	}
+	else
+	{
+		rec_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_8bit);
+		tr_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_8bit);
+	}
+
+	*port->rec_ctrl =
+		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) |
+		rec_ctrl;
+
+	*port->tr_ctrl =
+		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) |
+		tr_ctrl;
+}
+
+static void
+console_write_direct(struct console *co, const char *buf, unsigned int len)
+{
+	int i;
+	unsigned long flags;
+	local_irq_save(flags);
+	/* Send data */
+	for (i = 0; i < len; i++) {
+		/* Wait until transmitter is ready and send.*/
+		while (!(*port->read & IO_MASK(R_SERIAL0_READ, tr_ready)))
+			;
+		*port->write = buf[i];
+	}
+	local_irq_restore(flags);
+}
+
+static void
+console_write(struct console *co, const char *buf, unsigned int len)
+{
+	if (!port)
+		return;
+
+#ifdef CONFIG_SVINTO_SIM
+	/* no use to simulate the serial debug output */
+	SIMCOUT(buf, len);
+	return;
+#endif
+
+	start_port();
+
+#ifdef CONFIG_ETRAX_KGDB
+	/* kgdb needs to output debug info using the gdb protocol */
+	putDebugString(buf, len);
+	return;
+#endif
+
+	if (debug_write_function)
+		debug_write_function(co->index, buf, len);
+	else
+		console_write_direct(co, buf, len);
+}
+
+/* legacy function */
+
+void
+console_print_etrax(const char *buf)
+{
+	console_write(NULL, buf, strlen(buf));
+}
+
+/* Use polling to get a single character FROM the debug port */
+
+int
+getDebugChar(void)
+{
+	unsigned long readval;
+
+	do {
+		readval = *port->read;
+	} while (!(readval & IO_MASK(R_SERIAL0_READ, data_avail)));
+
+	return (readval & IO_MASK(R_SERIAL0_READ, data_in));
+}
+
+/* Use polling to put a single character to the debug port */
+
+void
+putDebugChar(int val)
+{
+	while (!(*port->read & IO_MASK(R_SERIAL0_READ, tr_ready)))
+		;
+	*port->write = val;
+}
+
+/* Enable irq for receiving chars on the debug port, used by kgdb */
+
+void
+enableDebugIRQ(void)
+{
+	*R_IRQ_MASK1_SET = port->irq;
+	/* use R_VECT_MASK directly, since we really bypass Linux normal
+	 * IRQ handling in kgdb anyway, we don't need to use enable_irq
+	 */
+	*R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set);
+
+	*port->rec_ctrl = IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable);
+}
+
+static struct tty_driver*
+etrax_console_device(struct console* co, int *index)
+{
+	return serial_driver;
+}
+
+static int __init
+console_setup(struct console *co, char *options)
+{
+	char* s;
+
+	if (options) {
+		port = &ports[co->index];
+		port->baudrate = 115200;
+                port->parity = 'N';
+                port->bits = 8;
+		port->baudrate = simple_strtoul(options, NULL, 10);
+		s = options;
+		while(*s >= '0' && *s <= '9')
+			s++;
+		if (*s) port->parity = *s++;
+		if (*s) port->bits   = *s++ - '0';
+		port->started = 0;
+		start_port();
+	}
+	return 0;
+}
+
+static struct console sercons = {
+	name : "ttyS",
+	write: console_write,
+	read : NULL,
+	device : etrax_console_device,
+	unblank : NULL,
+	setup : console_setup,
+	flags : CON_PRINTBUFFER,
+	index : -1,
+	cflag : 0,
+	next : NULL
+};
+static struct console sercons0 = {
+	name : "ttyS",
+	write: console_write,
+	read : NULL,
+	device : etrax_console_device,
+	unblank : NULL,
+	setup : console_setup,
+	flags : CON_PRINTBUFFER,
+	index : 0,
+	cflag : 0,
+	next : NULL
+};
+
+static struct console sercons1 = {
+	name : "ttyS",
+	write: console_write,
+	read : NULL,
+	device : etrax_console_device,
+	unblank : NULL,
+	setup : console_setup,
+	flags : CON_PRINTBUFFER,
+	index : 1,
+	cflag : 0,
+	next : NULL
+};
+static struct console sercons2 = {
+	name : "ttyS",
+	write: console_write,
+	read : NULL,
+	device : etrax_console_device,
+	unblank : NULL,
+	setup : console_setup,
+	flags : CON_PRINTBUFFER,
+	index : 2,
+	cflag : 0,
+	next : NULL
+};
+static struct console sercons3 = {
+	name : "ttyS",
+	write: console_write,
+	read : NULL,
+	device : etrax_console_device,
+	unblank : NULL,
+	setup : console_setup,
+	flags : CON_PRINTBUFFER,
+	index : 3,
+	cflag : 0,
+	next : NULL
+};
+/*
+ *      Register console (for printk's etc)
+ */
+
+int __init
+init_etrax_debug(void)
+{
+	static int first = 1;
+
+	if (!first) {
+		if (!port) {
+			register_console(&sercons0);
+			register_console(&sercons1);
+			register_console(&sercons2);
+			register_console(&sercons3);
+			unregister_console(&sercons);
+		}
+		return 0;
+	}
+	first = 0;
+	if (port)
+		register_console(&sercons);
+	return 0;
+}
+
+int __init
+init_console(void)
+{
+	serial_driver = alloc_tty_driver(1);
+	if (!serial_driver)
+		return -ENOMEM;
+	return 0;
+}
+
+__initcall(init_etrax_debug);
diff --git a/arch/cris/arch-v10/kernel/entry.S b/arch/cris/arch-v10/kernel/entry.S
new file mode 100644
index 0000000..1bc44f4
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/entry.S
@@ -0,0 +1,1132 @@
+/* $Id: entry.S,v 1.23 2004/10/19 13:07:37 starvik Exp $
+ *
+ *  linux/arch/cris/entry.S
+ *
+ *  Copyright (C) 2000, 2001, 2002 Axis Communications AB
+ *
+ *  Authors:	Bjorn Wesen (bjornw@axis.com)
+ *
+ *  $Log: entry.S,v $
+ *  Revision 1.23  2004/10/19 13:07:37  starvik
+ *  Merge of Linux 2.6.9
+ *
+ *  Revision 1.22  2004/06/21 10:29:55  starvik
+ *  Merge of Linux 2.6.7
+ *
+ *  Revision 1.21  2004/06/09 05:30:27  starvik
+ *  Clean up multiple interrupt handling.
+ *    Prevent interrupts from interrupting each other.
+ *    Handle all active interrupts.
+ *
+ *  Revision 1.20  2004/06/08 08:55:32  starvik
+ *  Removed unused code
+ *
+ *  Revision 1.19  2004/06/04 11:56:15  starvik
+ *  Implemented page table lookup for refills in assembler for improved performance.
+ *
+ *  Revision 1.18  2004/05/11 12:28:25  starvik
+ *  Merge of Linux 2.6.6
+ *
+ *  Revision 1.17  2003/09/11 07:29:49  starvik
+ *  Merge of Linux 2.6.0-test5
+ *
+ *  Revision 1.16  2003/07/04 08:27:41  starvik
+ *  Merge of Linux 2.5.74
+ *
+ *  Revision 1.15  2003/04/09 07:32:55  starvik
+ *  resume should return task_struct, not thread_info
+ *
+ *  Revision 1.14  2003/04/09 05:20:44  starvik
+ *  Merge of Linux 2.5.67
+ *
+ *  Revision 1.13  2002/12/11 15:42:02  starvik
+ *  Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/*.c
+ *
+ *  Revision 1.12  2002/12/10 09:00:10  starvik
+ *  Merge of Linux 2.5.51
+ *
+ *  Revision 1.11  2002/12/05 07:53:10  starvik
+ *  Corrected constants used with btstq
+ *
+ *  Revision 1.10  2002/11/27 08:45:10  starvik
+ *  pid is in task_struct, not thread_info
+ *
+ *  Revision 1.9  2002/11/26 09:52:05  starvik
+ *  Added preemptive kernel scheduling (if CONFIG_PREEMPT)
+ *
+ *  Revision 1.8  2002/11/20 11:56:11  starvik
+ *  Merge of Linux 2.5.48
+ *
+ *  Revision 1.7  2002/11/18 13:02:42  starvik
+ *  Added fourth parameter to do_notify_resume
+ *  Minor cleanup
+ *
+ *  Revision 1.6  2002/11/11 10:37:50  starvik
+ *  Use new asm-offset defines
+ *  Modified for new location of current->work etc
+ *  Removed SYMBOL_NAME from syscalls
+ *  Added some new syscalls
+ *
+ *  Revision 1.5  2002/11/05 06:45:11  starvik
+ *  Merge of Linux 2.5.45
+ *
+ *  Revision 1.4  2002/02/05 15:41:31  bjornw
+ *  Rewritten to conform better to current 2.5 code (similar to arch/i386)
+ *
+ *  Revision 1.3  2002/01/21 15:22:20  bjornw
+ *  NICE_DOGGY fix from 2.4 arch/cris
+ *
+ *  Revision 1.37  2001/12/07 17:03:55  bjornw
+ *  Call a c-hook called watchdog_bite_hook instead of show_registers directly
+ *
+ *  Revision 1.36  2001/11/22 13:36:36  bjornw
+ *  * In ret_from_intr, check regs->dccr for usermode reentrance instead of
+ *    DCCR explicitely (because the latter might not reflect current reality)
+ *  * In mmu_bus_fault, set $r9 _after_ calling the C-code instead of before
+ *    since $r9 is call-clobbered and is potentially needed afterwards
+ *
+ *  Revision 1.35  2001/10/30 17:10:15  bjornw
+ *  Add some syscalls
+ *
+ *  Revision 1.34  2001/10/01 14:45:03  bjornw
+ *  Removed underscores and added register prefixes
+ *
+ *  Revision 1.33  2001/08/21 13:48:01  jonashg
+ *  Added fix by HP to avoid oops when doing a hard_reset_now.
+ *
+ *  Revision 1.32  2001/08/14 04:32:02  hp
+ *  In _resume, add comment why R9 is saved; don't sound like it's call-saved.
+ *
+ *  Revision 1.31  2001/07/25 16:07:42  bjornw
+ *  softirq_active/mask -> softirq_pending only
+ *
+ *  Revision 1.30  2001/07/05 01:03:32  hp
+ *  - include asm/errno.h to get ENOSYS.
+ *  - Use ENOSYS, not local constant LENOSYS; tweak comments.
+ *  - Explain why .include, not #include is used.
+ *  - Make oops-register-dump if watchdog bits and it's not expected.
+ *  - Don't jsr, use jump _hard_reset_now, and skip spurious nop.
+ *  - Use correct section attribute for section .rodata.
+ *  - Adjust sys_ni_syscall fill number.
+ *
+ *  Revision 1.29  2001/06/25 14:07:00  hp
+ *  	Fix review comment.
+ *  	* head.S: Use IO_STATE, IO_FIELD and IO_MASK constructs instead of
+ *  	magic numbers.  Add comment that -traditional must not be used.
+ *  	* entry.S (SYMBOL_NAME): Change redefinition to use ## concatenation.
+ *  	Correct and update comment.
+ *  	* Makefile (.S.o): Don't use -traditional.  Add comment why the
+ *  	toplevel rule can't be used (now that there's a reason).
+ *
+ *  Revision 1.28  2001/06/21 02:00:40  hp
+ *  	* entry.S: Include asm/unistd.h.
+ *  	(_sys_call_table): Use section .rodata, not .data.
+ *  	(_kernel_thread): Move from...
+ *  	* process.c: ... here.
+ *  	* entryoffsets.c (VAL): Break out from...
+ *  	(OF): Use VAL.
+ *  	(LCLONE_VM): New asmified value from CLONE_VM.
+ *
+ *  Revision 1.27  2001/05/29 11:25:27  markusl
+ *  In case of "spurious_interrupt", do hard_reset instead of hanging system in a loop...
+ *
+ *  Revision 1.26  2001/05/15 15:46:03  bjornw
+ *  Include config.h now that we use some CONFIG_ options
+ *
+ *  Revision 1.25  2001/05/15 05:38:47  hp
+ *  Tweaked code in _ret_from_sys_call
+ *
+ *  Revision 1.24  2001/05/15 05:27:49  hp
+ *  Save r9 in r1 over function call rather than on stack.
+ *
+ *  Revision 1.23  2001/05/15 05:10:00  hp
+ *  Generate entry.S structure offsets from C
+ *
+ *  Revision 1.22  2001/04/17 13:58:39  orjanf
+ *  * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB.
+ *
+ *  Revision 1.21  2001/04/17 11:33:29  orjanf
+ *  Updated according to review:
+ *  * Included asm/sv_addr_ag.h to get macro for internal register.
+ *  * Corrected comment regarding system call argument passing.
+ *  * Removed comment about instruction being in a delay slot.
+ *  * Added comment about SYMBOL_NAME macro.
+ *
+ *  Revision 1.20  2001/04/12 08:51:07  hp
+ *  - Add entry for sys_fcntl64.  In fact copy last piece from i386 including ...
+ *  - .rept to fill table to safe state with sys_ni_syscall.
+ *
+ *  Revision 1.19  2001/04/04 09:43:32  orjanf
+ *  * Moved do_sigtrap from traps.c to entry.S.
+ *  * LTASK_PID need not be global anymore.
+ *
+ *  Revision 1.18  2001/03/26 09:25:02  markusl
+ *  Updated after review, should now handle USB interrupts correctly.
+ *
+ *  Revision 1.17  2001/03/21 16:12:55  bjornw
+ *  * Always make room for the cpu status record in the frame, in order to
+ *    use the same framelength and layout for both mmu busfaults and normal
+ *    irqs. No need to check for the explicit CRIS_FRAME_FIXUP type anymore.
+ *  * Fixed bug with using addq for popping the stack in the epilogue - it
+ *    destroyed the flag register. Use instructions that don't affect the
+ *    flag register instead.
+ *  * Removed write to R_PORT_PA_DATA during spurious_interrupt
+ *
+ *  Revision 1.16  2001/03/20 19:43:02  bjornw
+ *  * Get rid of esp0 setting
+ *  * Give a 7th argument to a systemcall - the stackframe
+ *
+ *  Revision 1.15  2001/03/05 13:14:30  bjornw
+ *  Spelling fix
+ *
+ *  Revision 1.14  2001/02/23 08:36:36  perf
+ *  New ABI; syscallnr=r9, arg5=mof, arg6=srp.
+ *  Corrected tracesys call check.
+ *
+ *  Revision 1.13  2001/02/15 08:40:55  perf
+ *  H-P by way of perf;
+ *  - (_system_call): Don't read system call function address into r1.
+ *  - (RBFExit): There is no such thing as a null pop.  Adjust sp by addq.
+ *  - (_system_call): Don't use r10 and don't save and restore it.
+ *  - (THREAD_ESP0): New constant.
+ *  - (_system_call): Inline set_esp0.
+ *
+ *  Revision 1.12  2001/01/31 17:56:25  orjanf
+ *  Added definition of LTASK_PID and made it global.
+ *
+ *  Revision 1.11  2001/01/10 21:13:29  bjornw
+ *  SYMBOL_NAME is defined incorrectly for the compiler options we currently use
+ *
+ *  Revision 1.10  2000/12/18 23:47:56  bjornw
+ *  * Added syscall trace support (ptrace), completely untested of course
+ *  * Removed redundant check for NULL entries in syscall_table
+ *
+ *  Revision 1.9  2000/11/21 16:40:51  bjornw
+ *  * New frame type used when an SBFS frame needs to be popped without
+ *    actually restarting the instruction
+ *  * Enable interrupts in signal_return (they did so in x86, I hope it's a good
+ *    idea)
+ *
+ *  Revision 1.8  2000/11/17 16:53:35  bjornw
+ *  Added detection of frame-type in Rexit, so that mmu_bus_fault can
+ *  use ret_from_intr in the return-path to check for signals (like SEGV)
+ *  and other foul things that might have occurred during the fault.
+ *
+ *  Revision 1.7  2000/10/06 15:04:28  bjornw
+ *  Include mof in register savings
+ *
+ *  Revision 1.6  2000/09/12 16:02:44  bjornw
+ *  Linux-2.4.0-test7 derived updates
+ *
+ *  Revision 1.5  2000/08/17 15:35:15  bjornw
+ *  2.4.0-test6 changed local_irq_count and friends API
+ *
+ *  Revision 1.4  2000/08/02 13:59:30  bjornw
+ *  Removed olduname and uname from the syscall list
+ *
+ *  Revision 1.3  2000/07/31 13:32:58  bjornw
+ *  * Export ret_from_intr
+ *  * _resume updated (prev/last tjohejsan)
+ *  * timer_interrupt obsolete
+ *  * SIGSEGV detection in mmu_bus_fault temporarily disabled
+ *
+ *
+ */
+
+/*
+ * entry.S contains the system-call and fault low-level handling routines.
+ *
+ * NOTE: This code handles signal-recognition, which happens every time
+ * after a timer-interrupt and after each system call.
+ *
+ * Stack layout in 'ret_from_system_call':
+ * 	ptrace needs to have all regs on the stack.
+ *	if the order here is changed, it needs to be 
+ *	updated in fork.c:copy_process, signal.c:do_signal,
+ *	ptrace.c and ptrace.h
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <linux/sys.h>
+#include <asm/unistd.h>
+#include <asm/arch/sv_addr_ag.h>
+#include <asm/errno.h>
+#include <asm/thread_info.h>
+#include <asm/arch/offset.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+	;; functions exported from this file
+	
+	.globl system_call
+	.globl ret_from_intr
+	.globl ret_from_fork
+	.globl resume
+	.globl multiple_interrupt
+	.globl hwbreakpoint
+	.globl IRQ1_interrupt
+	.globl spurious_interrupt
+	.globl hw_bp_trigs
+	.globl mmu_bus_fault
+	.globl do_sigtrap
+	.globl gdb_handle_breakpoint
+	.globl sys_call_table
+	
+	;; below are various parts of system_call which are not in the fast-path
+	
+#ifdef CONFIG_PREEMPT	
+	; Check if preemptive kernel scheduling should be done
+_resume_kernel:
+	; Load current task struct
+	movs.w	-8192, $r0	;  THREAD_SIZE = 8192
+	and.d	$sp, $r0
+	move.d	[$r0+TI_preempt_count], $r10	;  Preemption disabled?
+	bne	_Rexit
+	nop
+_need_resched:
+	move.d	[$r0+TI_flags], $r10
+	btstq	TIF_NEED_RESCHED, $r10	; Check if need_resched is set
+	bpl	_Rexit
+	nop
+	; Ok, lets's do some preemptive kernel scheduling
+	move.d	PREEMPT_ACTIVE, $r10
+	move.d	$r10, [$r0+TI_preempt_count] ; Mark as active
+	ei
+	jsr	schedule
+	clear.d	[$r0+TI_preempt_count] ;  Mark as inactive
+	di
+	; Load new task struct
+	movs.w	-8192, $r0	;  THREAD_SIZE = 8192
+	and.d	$sp, $r0
+	; One more time (with new task)
+	ba	_need_resched
+	nop
+#else
+#define _resume_kernel _Rexit
+#endif	
+
+	; Called at exit from fork. schedule_tail must be called to drop
+	; spinlock if CONFIG_PREEMPT
+ret_from_fork:
+	jsr schedule_tail
+	ba  ret_from_sys_call
+	nop
+		
+ret_from_intr:
+	;; check for resched if preemptive kernel or if we're going back to user-mode 
+	;; this test matches the user_regs(regs) macro
+	;; we cannot simply test $dccr, because that does not necessarily
+	;; reflect what mode we'll return into.
+	
+	move.d	[$sp + PT_dccr], $r0; regs->dccr
+	btstq	8, $r0		; U-flag
+	bpl     _resume_kernel
+	; Note that di below is in delay slot 
+	
+_resume_userspace:
+	di			; so need_resched and sigpending don't change
+
+	movs.w	-8192, $r0	; THREAD_SIZE == 8192
+	and.d	$sp, $r0
+
+	move.d	[$r0+TI_flags], $r10	; current->work
+	and.d	_TIF_WORK_MASK, $r10	; is there any work to be done on return
+	bne	_work_pending
+	nop
+	ba	_Rexit
+	nop
+	
+	;; The system_call is called by a BREAK instruction, which works like
+	;; an interrupt call but it stores the return PC in BRP instead of IRP.
+	;; Since we dont really want to have two epilogues (one for system calls
+	;; and one for interrupts) we push the contents of BRP instead of IRP in the
+	;; system call prologue, to make it look like an ordinary interrupt on the
+	;; stackframe.
+	;;
+	;; Since we can't have system calls inside interrupts, it should not matter
+	;; that we don't stack IRP.
+	;; 
+	;; In r9 we have the wanted syscall number. Arguments come in r10,r11,r12,r13,mof,srp
+	;;
+	;; This function looks on the _surface_ like spaghetti programming, but it's
+	;; really designed so that the fast-path does not force cache-loading of non-used
+	;; instructions. Only the non-common cases cause the outlined code to run..
+
+system_call:
+	;; stack-frame similar to the irq heads, which is reversed in ret_from_sys_call
+	move	$brp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame
+	push	$srp
+	push	$dccr
+	push	$mof
+	subq	14*4, $sp		; make room for r0-r13
+	movem	$r13, [$sp]	; push r0-r13
+	push	$r10		; push orig_r10
+	clear.d [$sp=$sp-4]	; frametype == 0, normal stackframe
+	
+	movs.w	-ENOSYS, $r0
+	move.d	$r0, [$sp+PT_r10]	; put the default return value in r10 in the frame
+
+	;; check if this process is syscall-traced
+
+	movs.w	-8192, $r0	; THREAD_SIZE == 8192
+	and.d	$sp, $r0
+	
+	move.d	[$r0+TI_flags], $r0
+	btstq   TIF_SYSCALL_TRACE, $r0
+	bmi	_syscall_trace_entry
+	nop	
+
+_syscall_traced:	
+
+	;; check for sanity in the requested syscall number
+	
+	cmpu.w	NR_syscalls, $r9	
+	bcc	ret_from_sys_call
+	lslq	2, $r9		;  multiply by 4, in the delay slot
+
+	;; as a bonus 7th parameter, we give the location on the stack
+	;; of the register structure itself. some syscalls need this.
+
+	push	$sp
+	
+	;; the parameter carrying registers r10, r11, r12 and 13 are intact.
+	;; the fifth and sixth parameters (if any) was in mof and srp 
+	;; respectively, and we need to put them on the stack.
+
+	push	$srp
+	push	$mof
+	
+	jsr	[$r9+sys_call_table]	; actually do the system call
+	addq	3*4, $sp		; pop the mof, srp and regs parameters
+	move.d	$r10, [$sp+PT_r10]	; save the return value
+
+	moveq	1, $r9		; "parameter" to ret_from_sys_call to show it was a sys call
+	
+	;; fall through into ret_from_sys_call to return
+	
+ret_from_sys_call:
+	;; r9 is a parameter - if >=1 we came from a syscall, if 0, from an irq
+		
+	;; get the current task-struct pointer (see top for defs)
+
+	movs.w	-8192, $r0	; THREAD_SIZE == 8192 
+	and.d	$sp, $r0
+
+	di			; make sure need_resched and sigpending don't change
+	move.d	[$r0+TI_flags],$r1
+	and.d	_TIF_ALLWORK_MASK, $r1
+	bne	_syscall_exit_work
+	nop
+
+_Rexit:
+	;; this epilogue MUST match the prologues in multiple_interrupt, irq.h and ptregs.h
+	pop	$r10		; frametype
+	bne	_RBFexit	; was not CRIS_FRAME_NORMAL, handle otherwise
+	addq	4, $sp		; skip orig_r10, in delayslot
+	movem	[$sp+], $r13	; registers r0-r13
+	pop	$mof		; multiply overflow register 
+	pop	$dccr		; condition codes
+	pop	$srp		; subroutine return pointer
+	;; now we have a 4-word SBFS frame which we do not want to restore
+	;; using RBF since it was not stacked with SBFS. instead we would like to
+	;; just get the PC value to restart it with, and skip the rest of
+	;; the frame.
+	;; Also notice that it's important to use instructions here that
+	;; keep the interrupts disabled (since we've already popped DCCR)
+	move	[$sp=$sp+16], $p8; pop the SBFS frame from the sp
+	jmpu	[$sp-16]	; return through the irp field in the sbfs frame
+
+_RBFexit:
+	movem	[$sp+], $r13	; registers r0-r13, in delay slot
+	pop	$mof		; multiply overflow register 
+	pop	$dccr		; condition codes
+	pop	$srp		; subroutine return pointer
+	rbf	[$sp+]		; return by popping the CPU status
+
+	;; We get here after doing a syscall if extra work might need to be done
+	;; perform syscall exit tracing if needed
+	
+_syscall_exit_work:
+	;; $r0 contains current at this point and irq's are disabled
+
+	move.d  [$r0+TI_flags], $r1
+	btstq	TIF_SYSCALL_TRACE, $r1
+	bpl	_work_pending
+	nop
+	
+	ei
+
+	move.d	$r9, $r1	; preserve r9
+	jsr	do_syscall_trace
+	move.d	$r1, $r9
+	
+	ba	_resume_userspace
+	nop
+	
+_work_pending:
+	move.d  [$r0+TI_flags], $r1
+	btstq   TIF_NEED_RESCHED, $r1
+	bpl	_work_notifysig	; was neither trace nor sched, must be signal/notify
+	nop
+	
+_work_resched:
+	move.d	$r9, $r1	; preserve r9
+	jsr	schedule
+	move.d	$r1, $r9
+	di
+
+	move.d	[$r0+TI_flags], $r1
+	and.d	_TIF_WORK_MASK, $r1; ignore the syscall trace counter
+	beq	_Rexit
+	nop
+	btstq	TIF_NEED_RESCHED, $r1
+	bmi	_work_resched	; current->work.need_resched
+	nop
+
+_work_notifysig:
+	;; deal with pending signals and notify-resume requests
+
+	move.d	$r9, $r10	; do_notify_resume syscall/irq param
+	moveq	0, $r11		; oldset param - 0 in this case
+	move.d	$sp, $r12	; the regs param
+	move.d  $r1, $r13	; the thread_info_flags parameter
+	jsr	do_notify_resume
+	
+	ba _Rexit
+	nop
+
+	;; We get here as a sidetrack when we've entered a syscall with the
+	;; trace-bit set. We need to call do_syscall_trace and then continue
+	;; with the call.
+	
+_syscall_trace_entry:
+	;; PT_r10 in the frame contains -ENOSYS as required, at this point
+	
+	jsr	do_syscall_trace
+
+	;; now re-enter the syscall code to do the syscall itself
+	;; we need to restore $r9 here to contain the wanted syscall, and
+	;; the other parameter-bearing registers
+
+	move.d	[$sp+PT_r9], $r9
+	move.d	[$sp+PT_orig_r10], $r10  ; PT_r10 is already filled with -ENOSYS.
+	move.d	[$sp+PT_r11],      $r11
+	move.d	[$sp+PT_r12],      $r12
+	move.d	[$sp+PT_r13],      $r13
+	move	[$sp+PT_mof],      $mof
+	move	[$sp+PT_srp],      $srp
+	
+	ba	_syscall_traced
+	nop
+	
+	;; resume performs the actual task-switching, by switching stack pointers
+	;; input arguments: r10 = prev, r11 = next, r12 = thread offset in task struct
+	;; returns old current in r10
+	;;
+	;; TODO:  see the i386 version. The switch_to which calls resume in our version
+	;;        could really be an inline asm of this.
+
+resume:	
+	push	$srp		         ; we keep the old/new PC on the stack 
+	add.d	$r12, $r10		 ; r10 = current tasks tss
+	move	$dccr, [$r10+THREAD_dccr]; save irq enable state
+	di
+
+	move	$usp, [$r10+ THREAD_usp] ; save user-mode stackpointer
+	
+	;; See copy_thread for the reason why register R9 is saved.
+	subq	10*4, $sp
+	movem	$r9, [$sp]		 ; save non-scratch registers and R9.
+	
+	move.d	$sp, [$r10+THREAD_ksp]	 ; save the kernel stack pointer for the old task
+	move.d	$sp, $r10		 ; return last running task in r10
+	and.d   -8192, $r10	         ; get thread_info from stackpointer
+	move.d  [$r10+TI_task], $r10     ; get task  
+	add.d	$r12, $r11		 ; find the new tasks tss
+	move.d	[$r11+THREAD_ksp], $sp	 ; switch into the new stackframe by restoring kernel sp
+
+	movem	[$sp+], $r9		 ; restore non-scratch registers and R9.
+
+	move	[$r11+THREAD_usp], $usp ; restore user-mode stackpointer
+	
+	move	[$r11+THREAD_dccr], $dccr ; restore irq enable status
+	jump	[$sp+]		         ; restore PC
+
+	;; This is the MMU bus fault handler.
+	;; It needs to stack the CPU status and overall is different
+	;; from the other interrupt handlers.
+
+mmu_bus_fault:
+	;; For refills we try to do a quick page table lookup. If it is
+	;; a real fault we let the mm subsystem handle it.
+
+	;; the first longword in the sbfs frame was the interrupted PC
+	;; which fits nicely with the "IRP" slot in pt_regs normally used to
+	;; contain the return address. used by Oops to print kernel errors.
+	sbfs	[$sp=$sp-16]	; push the internal CPU status
+	push	$dccr
+	di
+	subq	2*4, $sp
+	movem	$r1, [$sp]
+	move.d  [R_MMU_CAUSE], $r1
+	;; ETRAX 100LX TR89 bugfix: if the second half of an unaligned
+	;; write causes a MMU-fault, it will not be restarted correctly.
+	;; This could happen if a write crosses a page-boundary and the
+	;; second page is not yet COW'ed or even loaded. The workaround
+	;; is to clear the unaligned bit in the CPU status record, so
+	;; that the CPU will rerun both the first and second halves of
+	;; the instruction. This will not have any sideeffects unless
+	;; the first half goes to any device or memory that can't be
+	;; written twice, and which is mapped through the MMU.
+	;;
+	;; We only need to do this for writes.
+	btstq	8, $r1		   ; Write access?
+	bpl	1f
+	nop
+	move.d	[$sp+16], $r0	   ; Clear unaligned bit in csrinstr
+	and.d	~(1<<5), $r0
+	move.d	$r0, [$sp+16]
+1:	btstq	12, $r1		   ; Refill?
+	bpl	2f
+	lsrq	PMD_SHIFT, $r1     ; Get PMD index into PGD (bit 24-31)
+	move.d  [current_pgd], $r0 ; PGD for the current process
+	move.d	[$r0+$r1.d], $r0   ; Get PMD
+	beq	2f
+	nop
+	and.w	PAGE_MASK, $r0	   ; Remove PMD flags
+	move.d  [R_MMU_CAUSE], $r1
+	lsrq	PAGE_SHIFT, $r1
+	and.d	0x7ff, $r1         ; Get PTE index into PMD (bit 13-24)
+	move.d	[$r0+$r1.d], $r1   ; Get PTE
+	beq	2f
+	nop
+	;; Store in TLB
+	move.d  $r1, [R_TLB_LO]
+	;; Return
+	movem	[$sp+], $r1
+	pop	$dccr
+	rbf	[$sp+]		; return by popping the CPU status
+
+2:	; PMD or PTE missing, let the mm subsystem fix it up.
+	movem	[$sp+], $r1
+	pop	$dccr
+
+	; Ok, not that easy, pass it on to the mm subsystem
+	; The MMU status record is now on the stack
+	push	$srp		; make a stackframe similar to pt_regs
+	push	$dccr
+	push	$mof
+	di
+	subq	14*4, $sp
+	movem	$r13, [$sp]
+	push	$r10		; dummy orig_r10
+	moveq	1, $r10
+	push	$r10		; frametype == 1, BUSFAULT frame type
+
+	move.d	$sp, $r10	; pt_regs argument to handle_mmu_bus_fault
+		
+	jsr	handle_mmu_bus_fault  ; in arch/cris/arch-v10/mm/fault.c
+
+	;; now we need to return through the normal path, we cannot just
+	;; do the RBFexit since we might have killed off the running
+	;; process due to a SEGV, scheduled due to a page blocking or
+	;; whatever.
+
+	moveq	0, $r9		; busfault is equivalent to an irq
+		
+	ba	ret_from_intr
+	nop
+		
+	;; special handlers for breakpoint and NMI
+hwbreakpoint:
+	push	$dccr
+	di
+	push	$r10
+	push	$r11
+	move.d	[hw_bp_trig_ptr],$r10
+	move	$brp,$r11
+	move.d	$r11,[$r10+]
+	move.d	$r10,[hw_bp_trig_ptr]
+1:	pop	$r11
+	pop	$r10
+	pop	$dccr
+	retb
+	nop
+	
+IRQ1_interrupt:
+
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+;; If we receive a watchdog interrupt while it is not expected, then set
+;; up a canonical frame and dump register contents before dying.
+
+	;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!!
+	move	$brp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame
+	push	$srp
+	push	$dccr
+	push	$mof
+	di
+	subq	14*4, $sp
+	movem	$r13, [$sp]
+	push	$r10		; push orig_r10
+	clear.d [$sp=$sp-4]	; frametype == 0, normal frame
+
+;; We don't check that we actually were bit by the watchdog as opposed to
+;; an external NMI, since there is currently no handler for external NMI.
+
+;; Check if we're waiting for reset to happen, as signalled by
+;; hard_reset_now setting cause_of_death to a magic value.  If so, just
+;; get stuck until reset happens.
+	.comm	cause_of_death, 4	;; Don't declare this anywhere.
+	move.d	[cause_of_death], $r10
+	cmp.d	0xbedead, $r10
+_killed_by_death:
+	beq	_killed_by_death
+	nop
+
+;; We'll see this in ksymoops dumps.
+Watchdog_bite:
+
+#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
+       ;; We just restart the watchdog here to be sure we dont get
+       ;; hit while printing the watchdogmsg below
+       ;; This restart is compatible with the rest of the C-code, so
+       ;; the C-code can keep restarting the watchdog after this point.
+       ;; The non-NICE_DOGGY code below though, disables the possibility
+       ;; to restart since it changes the watchdog key, to avoid any
+       ;; buggy loops etc. keeping the watchdog alive after this.
+       jsr     reset_watchdog
+#else
+
+;; We need to extend the 3.3ms after the NMI at watchdog bite, so we have
+;; time for an oops-dump over a 115k2 serial wire.  Another 100ms should do.
+
+;; Change the watchdog key to an arbitrary 3-bit value and restart the
+;; watchdog.
+#define WD_INIT 2
+	moveq	  IO_FIELD (R_WATCHDOG, key, WD_INIT), $r10
+	move.d	R_WATCHDOG, $r11
+
+	move.d	$r10, [$r11]
+	moveq	  IO_FIELD (R_WATCHDOG, key,				\
+			    IO_EXTRACT (R_WATCHDOG, key,		\
+					IO_MASK (R_WATCHDOG, key))	\
+			    ^ WD_INIT)					\
+		| IO_STATE (R_WATCHDOG, enable, start), $r10
+	move.d	$r10, [$r11]
+
+#endif
+	
+;; Note that we don't do "setf m" here (or after two necessary NOPs),
+;; since *not* doing that saves us from re-entrancy checks.  We don't want
+;; to get here again due to possible subsequent NMIs; we want the watchdog
+;; to reset us.
+
+	move.d	_watchdogmsg,$r10
+	jsr	printk
+
+	move.d	$sp, $r10
+	jsr	watchdog_bite_hook
+
+;; This nop is here so we see the "Watchdog_bite" label in ksymoops dumps
+;; rather than "spurious_interrupt".
+	nop
+;; At this point we drop down into spurious_interrupt, which will do a
+;; hard reset.
+
+	.section .rodata,"a"
+_watchdogmsg:
+	.ascii	"Oops: bitten by watchdog\n\0"
+	.previous
+
+#endif /* CONFIG_ETRAX_WATCHDOG and not CONFIG_SVINTO_SIM */
+
+spurious_interrupt:	
+	di
+	jump hard_reset_now
+
+	;; this handles the case when multiple interrupts arrive at the same time
+	;; we jump to the first set interrupt bit in a priority fashion
+	;; the hardware will call the unserved interrupts after the handler finishes
+	
+multiple_interrupt:
+	;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!!
+	move	$irp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame
+	push	$srp
+	push	$dccr
+	push	$mof
+	di
+	subq	14*4, $sp
+	movem	$r13, [$sp]
+	push	$r10		; push orig_r10
+	clear.d [$sp=$sp-4]	; frametype == 0, normal frame
+	
+	moveq	2, $r2		; first bit we care about is the timer0 irq
+	move.d	[R_VECT_MASK_RD], $r0; read the irq bits that triggered the multiple irq
+	move.d	$r0, [R_VECT_MASK_CLR] ; Block all active IRQs
+1:	
+	btst	$r2, $r0	; check for the irq given by bit r2
+	bpl	2f
+	move.d  $r2, $r10	; First argument to do_IRQ
+	move.d  $sp, $r11	; second argument to do_IRQ
+	jsr	do_IRQ
+2:
+	addq	1, $r2		; next vector bit
+	cmp.b	32, $r2
+	bne	1b	; process all irq's up to and including number 31
+	moveq	0, $r9  ; make ret_from_intr realise we came from an ir
+	
+	move.d	$r0, [R_VECT_MASK_SET] ;  Unblock all the IRQs
+	jump    ret_from_intr
+
+do_sigtrap:
+	;; 
+	;; SIGTRAP the process that executed the break instruction.
+	;; Make a frame that Rexit in entry.S expects.
+	;;
+	move	$brp, [$sp=$sp-16]	; Push BRP while faking a cpu status record.
+	push	$srp			; Push subroutine return pointer.
+	push	$dccr			; Push condition codes.
+	push	$mof			; Push multiply overflow reg.
+	di				; Need to disable irq's at this point.
+	subq	14*4, $sp		; Make room for r0-r13.
+	movem	$r13, [$sp]		; Push the r0-r13 registers.
+	push	$r10			; Push orig_r10.
+	clear.d	[$sp=$sp-4]		; Frametype - this is a normal stackframe.
+
+	movs.w	-8192,$r9		; THREAD_SIZE == 8192
+	and.d	$sp, $r9
+	move.d  [$r9+TI_task], $r10
+	move.d  [$r10+TASK_pid], $r10	; current->pid as arg1. 
+	moveq	5, $r11			; SIGTRAP as arg2.
+	jsr	sys_kill       
+	jump	ret_from_intr		; Use the return routine for interrupts.
+
+gdb_handle_breakpoint:	
+	push	$dccr
+	push	$r0
+#ifdef CONFIG_ETRAX_KGDB
+	move	$dccr, $r0		; U-flag not affected by previous insns. 
+	btstq	8, $r0			; Test the U-flag.
+	bmi	_ugdb_handle_breakpoint	; Go to user mode debugging. 
+	nop				; Empty delay slot (cannot pop r0 here). 
+	pop	$r0			; Restore r0.
+	ba	kgdb_handle_breakpoint	; Go to kernel debugging. 
+	pop	$dccr			; Restore dccr in delay slot.
+#endif
+	
+_ugdb_handle_breakpoint:	
+	move	$brp, $r0		; Use r0 temporarily for calculation.
+	subq	2, $r0			; Set to address of previous instruction.
+	move	$r0, $brp
+	pop	$r0			; Restore r0. 
+	ba	do_sigtrap		; SIGTRAP the offending process. 
+	pop	$dccr			; Restore dccr in delay slot.
+	
+	.data
+
+hw_bp_trigs:
+	.space 64*4
+hw_bp_trig_ptr:
+	.dword hw_bp_trigs
+
+	.section .rodata,"a"
+sys_call_table:	
+	.long sys_restart_syscall	/* 0 - old "setup()" system call, used for restarting */
+	.long sys_exit
+	.long sys_fork
+	.long sys_read
+	.long sys_write
+	.long sys_open		/* 5 */
+	.long sys_close
+	.long sys_waitpid
+	.long sys_creat
+	.long sys_link
+	.long sys_unlink	/* 10 */
+	.long sys_execve
+	.long sys_chdir
+	.long sys_time
+	.long sys_mknod
+	.long sys_chmod		/* 15 */
+	.long sys_lchown16
+	.long sys_ni_syscall	/* old break syscall holder */
+	.long sys_stat
+	.long sys_lseek
+	.long sys_getpid	/* 20 */
+	.long sys_mount
+	.long sys_oldumount
+	.long sys_setuid16
+	.long sys_getuid16
+	.long sys_stime		/* 25 */
+	.long sys_ptrace
+	.long sys_alarm
+	.long sys_fstat
+	.long sys_pause
+	.long sys_utime		/* 30 */
+	.long sys_ni_syscall	/* old stty syscall holder */
+	.long sys_ni_syscall	/* old gtty syscall holder */
+	.long sys_access
+	.long sys_nice
+	.long sys_ni_syscall	/* 35  old ftime syscall holder */
+	.long sys_sync
+	.long sys_kill
+	.long sys_rename
+	.long sys_mkdir
+	.long sys_rmdir		/* 40 */
+	.long sys_dup
+	.long sys_pipe
+	.long sys_times
+	.long sys_ni_syscall	/* old prof syscall holder */
+	.long sys_brk		/* 45 */
+	.long sys_setgid16
+	.long sys_getgid16
+	.long sys_signal
+	.long sys_geteuid16
+	.long sys_getegid16	/* 50 */
+	.long sys_acct
+	.long sys_umount	/* recycled never used phys( */
+	.long sys_ni_syscall	/* old lock syscall holder */
+	.long sys_ioctl
+	.long sys_fcntl		/* 55 */
+	.long sys_ni_syscall	/* old mpx syscall holder */
+	.long sys_setpgid
+	.long sys_ni_syscall	/* old ulimit syscall holder */
+	.long sys_ni_syscall	/* old sys_olduname holder */
+	.long sys_umask		/* 60 */
+	.long sys_chroot
+	.long sys_ustat
+	.long sys_dup2
+	.long sys_getppid
+	.long sys_getpgrp	/* 65 */
+	.long sys_setsid
+	.long sys_sigaction
+	.long sys_sgetmask
+	.long sys_ssetmask
+	.long sys_setreuid16	/* 70 */
+	.long sys_setregid16
+	.long sys_sigsuspend
+	.long sys_sigpending
+	.long sys_sethostname
+	.long sys_setrlimit	/* 75 */
+	.long sys_old_getrlimit
+	.long sys_getrusage
+	.long sys_gettimeofday
+	.long sys_settimeofday
+	.long sys_getgroups16	/* 80 */
+	.long sys_setgroups16
+	.long sys_select	/* was old_select in Linux/E100 */
+	.long sys_symlink
+	.long sys_lstat
+	.long sys_readlink	/* 85 */
+	.long sys_uselib
+	.long sys_swapon
+	.long sys_reboot
+	.long old_readdir
+	.long old_mmap		/* 90 */
+	.long sys_munmap
+	.long sys_truncate
+	.long sys_ftruncate
+	.long sys_fchmod
+	.long sys_fchown16	/* 95 */
+	.long sys_getpriority
+	.long sys_setpriority
+	.long sys_ni_syscall	/* old profil syscall holder */
+	.long sys_statfs
+	.long sys_fstatfs	/* 100 */
+	.long sys_ni_syscall	/* sys_ioperm in i386 */
+	.long sys_socketcall
+	.long sys_syslog
+	.long sys_setitimer
+	.long sys_getitimer	/* 105 */
+	.long sys_newstat
+	.long sys_newlstat
+	.long sys_newfstat
+	.long sys_ni_syscall	/* old sys_uname holder */
+	.long sys_ni_syscall	/* sys_iopl in i386 */
+	.long sys_vhangup
+	.long sys_ni_syscall	/* old "idle" system call */
+	.long sys_ni_syscall	/* vm86old in i386 */
+	.long sys_wait4
+	.long sys_swapoff	/* 115 */
+	.long sys_sysinfo
+	.long sys_ipc
+	.long sys_fsync
+	.long sys_sigreturn
+	.long sys_clone		/* 120 */
+	.long sys_setdomainname
+	.long sys_newuname
+	.long sys_ni_syscall	/* sys_modify_ldt */
+	.long sys_adjtimex
+	.long sys_mprotect	/* 125 */
+	.long sys_sigprocmask
+	.long sys_ni_syscall	/* old "create_module" */ 
+	.long sys_init_module
+	.long sys_delete_module
+	.long sys_ni_syscall	/* 130:	old "get_kernel_syms" */
+	.long sys_quotactl
+	.long sys_getpgid
+	.long sys_fchdir
+	.long sys_bdflush
+	.long sys_sysfs		/* 135 */
+	.long sys_personality
+	.long sys_ni_syscall	/* for afs_syscall */
+	.long sys_setfsuid16
+	.long sys_setfsgid16
+	.long sys_llseek	/* 140 */
+	.long sys_getdents
+	.long sys_select
+	.long sys_flock
+	.long sys_msync
+	.long sys_readv		/* 145 */
+	.long sys_writev
+	.long sys_getsid
+	.long sys_fdatasync
+	.long sys_sysctl
+	.long sys_mlock		/* 150 */
+	.long sys_munlock
+	.long sys_mlockall
+	.long sys_munlockall
+	.long sys_sched_setparam
+	.long sys_sched_getparam	/* 155 */
+	.long sys_sched_setscheduler
+	.long sys_sched_getscheduler
+	.long sys_sched_yield
+	.long sys_sched_get_priority_max
+	.long sys_sched_get_priority_min	/* 160 */
+	.long sys_sched_rr_get_interval
+	.long sys_nanosleep
+	.long sys_mremap
+	.long sys_setresuid16
+	.long sys_getresuid16	/* 165 */
+	.long sys_ni_syscall	/* sys_vm86 */
+	.long sys_ni_syscall	/* Old sys_query_module */
+	.long sys_poll
+	.long sys_nfsservctl
+	.long sys_setresgid16	/* 170 */
+	.long sys_getresgid16
+	.long sys_prctl
+	.long sys_rt_sigreturn
+	.long sys_rt_sigaction
+	.long sys_rt_sigprocmask	/* 175 */
+	.long sys_rt_sigpending
+	.long sys_rt_sigtimedwait
+	.long sys_rt_sigqueueinfo
+	.long sys_rt_sigsuspend
+	.long sys_pread64	/* 180 */
+	.long sys_pwrite64
+	.long sys_chown16
+	.long sys_getcwd
+	.long sys_capget
+	.long sys_capset	/* 185 */
+	.long sys_sigaltstack
+	.long sys_sendfile
+	.long sys_ni_syscall	/* streams1 */
+	.long sys_ni_syscall	/* streams2 */
+	.long sys_vfork		/* 190 */
+	.long sys_getrlimit
+	.long sys_mmap2
+	.long sys_truncate64
+	.long sys_ftruncate64
+	.long sys_stat64	/* 195 */
+	.long sys_lstat64
+	.long sys_fstat64
+	.long sys_lchown
+	.long sys_getuid
+	.long sys_getgid	/* 200 */
+	.long sys_geteuid
+	.long sys_getegid
+	.long sys_setreuid
+	.long sys_setregid
+	.long sys_getgroups	/* 205 */
+	.long sys_setgroups
+	.long sys_fchown
+	.long sys_setresuid
+	.long sys_getresuid
+	.long sys_setresgid	/* 210 */
+	.long sys_getresgid
+	.long sys_chown
+	.long sys_setuid
+	.long sys_setgid
+	.long sys_setfsuid	/* 215 */
+	.long sys_setfsgid
+	.long sys_pivot_root
+	.long sys_mincore
+	.long sys_madvise
+	.long sys_getdents64	/* 220 */
+	.long sys_fcntl64
+	.long sys_ni_syscall	/* reserved for TUX */
+	.long sys_ni_syscall
+	.long sys_gettid
+	.long sys_readahead	/* 225 */
+	.long sys_setxattr
+	.long sys_lsetxattr
+	.long sys_fsetxattr
+	.long sys_getxattr
+	.long sys_lgetxattr	/* 230 */
+	.long sys_fgetxattr
+	.long sys_listxattr
+	.long sys_llistxattr
+	.long sys_flistxattr
+	.long sys_removexattr	/* 235 */
+	.long sys_lremovexattr
+	.long sys_fremovexattr
+	.long sys_tkill
+	.long sys_sendfile64
+	.long sys_futex		/* 240 */
+	.long sys_sched_setaffinity
+	.long sys_sched_getaffinity
+	.long sys_ni_syscall	/* sys_set_thread_area */
+	.long sys_ni_syscall	/* sys_get_thread_area */
+	.long sys_io_setup	/* 245 */
+	.long sys_io_destroy
+	.long sys_io_getevents
+	.long sys_io_submit
+	.long sys_io_cancel
+	.long sys_fadvise64	/* 250 */
+	.long sys_ni_syscall
+	.long sys_exit_group
+	.long sys_lookup_dcookie
+	.long sys_epoll_create
+	.long sys_epoll_ctl	/* 255 */
+	.long sys_epoll_wait
+	.long sys_remap_file_pages
+ 	.long sys_set_tid_address
+ 	.long sys_timer_create
+ 	.long sys_timer_settime		/* 260 */
+ 	.long sys_timer_gettime
+ 	.long sys_timer_getoverrun
+ 	.long sys_timer_delete
+ 	.long sys_clock_settime
+ 	.long sys_clock_gettime		/* 265 */
+ 	.long sys_clock_getres
+ 	.long sys_clock_nanosleep
+	.long sys_statfs64
+	.long sys_fstatfs64	
+	.long sys_tgkill	/* 270 */
+	.long sys_utimes
+ 	.long sys_fadvise64_64
+	.long sys_ni_syscall	/* sys_vserver */
+	.long sys_ni_syscall	/* sys_mbind */
+	.long sys_ni_syscall	/* 275 sys_get_mempolicy */
+	.long sys_ni_syscall	/* sys_set_mempolicy */
+	.long sys_mq_open
+	.long sys_mq_unlink
+	.long sys_mq_timedsend
+	.long sys_mq_timedreceive	/* 280 */
+	.long sys_mq_notify
+	.long sys_mq_getsetattr
+	.long sys_ni_syscall		/* reserved for kexec */
+	.long sys_waitid
+
+        /*
+         * NOTE!! This doesn't have to be exact - we just have
+         * to make sure we have _enough_ of the "sys_ni_syscall"
+         * entries. Don't panic if you notice that this hasn't
+         * been shrunk every time we add a new system call.
+         */
+
+	.rept NR_syscalls-(.-sys_call_table)/4
+		.long sys_ni_syscall
+	.endr
+	
diff --git a/arch/cris/arch-v10/kernel/fasttimer.c b/arch/cris/arch-v10/kernel/fasttimer.c
new file mode 100644
index 0000000..4717f7a
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/fasttimer.c
@@ -0,0 +1,977 @@
+/* $Id: fasttimer.c,v 1.6 2004/05/14 10:18:39 starvik Exp $
+ * linux/arch/cris/kernel/fasttimer.c
+ *
+ * Fast timers for ETRAX100/ETRAX100LX
+ * This may be useful in other OS than Linux so use 2 space indentation...
+ *
+ * $Log: fasttimer.c,v $
+ * Revision 1.6  2004/05/14 10:18:39  starvik
+ * Export fast_timer_list
+ *
+ * Revision 1.5  2004/05/14 07:58:01  starvik
+ * Merge of changes from 2.4
+ *
+ * Revision 1.4  2003/07/04 08:27:41  starvik
+ * Merge of Linux 2.5.74
+ *
+ * Revision 1.3  2002/12/12 08:26:32  starvik
+ * Don't use C-comments inside CVS comments
+ *
+ * Revision 1.2  2002/12/11 15:42:02  starvik
+ * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/
+ *
+ * Revision 1.1  2002/11/18 07:58:06  starvik
+ * Fast timers (from Linux 2.4)
+ *
+ * Revision 1.5  2002/10/15 06:21:39  starvik
+ * Added call to init_waitqueue_head
+ *
+ * Revision 1.4  2002/05/28 17:47:59  johana
+ * Added del_fast_timer()
+ *
+ * Revision 1.3  2002/05/28 16:16:07  johana
+ * Handle empty fast_timer_list
+ *
+ * Revision 1.2  2002/05/27 15:38:42  johana
+ * Made it compile without warnings on Linux 2.4.
+ * (includes, wait_queue, PROC_FS and snprintf)
+ *
+ * Revision 1.1  2002/05/27 15:32:25  johana
+ * arch/etrax100/kernel/fasttimer.c v1.8 from the elinux tree.
+ *
+ * Revision 1.8  2001/11/27 13:50:40  pkj
+ * Disable interrupts while stopping the timer and while modifying the
+ * list of active timers in timer1_handler() as it may be interrupted
+ * by other interrupts (e.g., the serial interrupt) which may add fast
+ * timers.
+ *
+ * Revision 1.7  2001/11/22 11:50:32  pkj
+ * * Only store information about the last 16 timers.
+ * * proc_fasttimer_read() now uses an allocated buffer, since it
+ *   requires more space than just a page even for only writing the
+ *   last 16 timers. The buffer is only allocated on request, so
+ *   unless /proc/fasttimer is read, it is never allocated.
+ * * Renamed fast_timer_started to fast_timers_started to match
+ *   fast_timers_added and fast_timers_expired.
+ * * Some clean-up.
+ *
+ * Revision 1.6  2000/12/13 14:02:08  johana
+ * Removed volatile for fast_timer_list
+ *
+ * Revision 1.5  2000/12/13 13:55:35  johana
+ * Added DEBUG_LOG, added som cli() and cleanup
+ *
+ * Revision 1.4  2000/12/05 13:48:50  johana
+ * Added range check when writing proc file, modified timer int handling
+ *
+ * Revision 1.3  2000/11/23 10:10:20  johana
+ * More debug/logging possibilities.
+ * Moved GET_JIFFIES_USEC() to timex.h and time.c
+ *
+ * Revision 1.2  2000/11/01 13:41:04  johana
+ * Clean up and bugfixes.
+ * Created new do_gettimeofday_fast() that gets a timeval struct
+ * with time based on jiffies and *R_TIMER0_DATA, uses a table
+ * for fast conversion of timer value to microseconds.
+ * (Much faster the standard do_gettimeofday() and we don't really
+ * wan't to use the true time - we wan't the "uptime" so timers don't screw up
+ * when we change the time.
+ * TODO: Add efficient support for continuous timers as well.
+ *
+ * Revision 1.1  2000/10/26 15:49:16  johana
+ * Added fasttimer, highresolution timers.
+ *
+ * Copyright (C) 2000,2001 2002 Axis Communications AB, Lund, Sweden
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/delay.h>
+#include <asm/rtc.h>
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#include <asm/arch/svinto.h>
+#include <asm/fasttimer.h>
+#include <linux/proc_fs.h>
+
+
+#define DEBUG_LOG_INCLUDED
+#define FAST_TIMER_LOG
+//#define FAST_TIMER_TEST
+
+#define FAST_TIMER_SANITY_CHECKS
+
+#ifdef FAST_TIMER_SANITY_CHECKS
+#define SANITYCHECK(x) x
+static int sanity_failed = 0;
+#else
+#define SANITYCHECK(x)
+#endif
+
+#define D1(x)
+#define D2(x)
+#define DP(x)
+
+#define __INLINE__ inline
+
+static int fast_timer_running = 0;
+static int fast_timers_added = 0;
+static int fast_timers_started = 0;
+static int fast_timers_expired = 0;
+static int fast_timers_deleted = 0;
+static int fast_timer_is_init = 0;
+static int fast_timer_ints = 0;
+
+struct fast_timer *fast_timer_list = NULL;
+
+#ifdef DEBUG_LOG_INCLUDED
+#define DEBUG_LOG_MAX 128
+static const char * debug_log_string[DEBUG_LOG_MAX];
+static unsigned long debug_log_value[DEBUG_LOG_MAX];
+static int debug_log_cnt = 0;
+static int debug_log_cnt_wrapped = 0;
+
+#define DEBUG_LOG(string, value) \
+{ \
+  unsigned long log_flags; \
+  save_flags(log_flags); \
+  cli(); \
+  debug_log_string[debug_log_cnt] = (string); \
+  debug_log_value[debug_log_cnt] = (unsigned long)(value); \
+  if (++debug_log_cnt >= DEBUG_LOG_MAX) \
+  { \
+    debug_log_cnt = debug_log_cnt % DEBUG_LOG_MAX; \
+    debug_log_cnt_wrapped = 1; \
+  } \
+  restore_flags(log_flags); \
+}
+#else
+#define DEBUG_LOG(string, value)
+#endif
+
+
+/* The frequencies for index = clkselx number in R_TIMER_CTRL */
+#define NUM_TIMER_FREQ 15
+#define MAX_USABLE_TIMER_FREQ 7
+#define MAX_DELAY_US  853333L
+const unsigned long timer_freq_100[NUM_TIMER_FREQ] =
+{
+  3,   /* 0 3333 - 853333 us */
+  6,   /* 1 1666 - 426666 us */
+  12,  /* 2  833 - 213333 us */
+  24,  /* 3  416 - 106666 us */
+  48,  /* 4  208 -  53333 us */
+  96,  /* 5  104 -  26666 us */
+  192, /* 6   52 -  13333 us */
+  384, /* 7   26 -   6666 us */
+  576,
+  1152,
+  2304,
+  4608,
+  9216,
+  18432,
+  62500,
+  /* 15 = cascade */
+};
+#define NUM_TIMER_STATS 16
+#ifdef FAST_TIMER_LOG
+struct fast_timer timer_added_log[NUM_TIMER_STATS];
+struct fast_timer timer_started_log[NUM_TIMER_STATS];
+struct fast_timer timer_expired_log[NUM_TIMER_STATS];
+#endif
+
+int timer_div_settings[NUM_TIMER_STATS];
+int timer_freq_settings[NUM_TIMER_STATS];
+int timer_delay_settings[NUM_TIMER_STATS];
+
+/* Not true gettimeofday, only checks the jiffies (uptime) + useconds */
+void __INLINE__ do_gettimeofday_fast(struct timeval *tv)
+{
+  unsigned long sec = jiffies;
+  unsigned long usec = GET_JIFFIES_USEC();
+
+  usec += (sec % HZ) * (1000000 / HZ);
+  sec = sec / HZ;
+
+  if (usec > 1000000)
+  {
+    usec -= 1000000;
+    sec++;
+  }
+  tv->tv_sec = sec;
+  tv->tv_usec = usec;
+}
+
+int __INLINE__ timeval_cmp(struct timeval *t0, struct timeval *t1)
+{
+  if (t0->tv_sec < t1->tv_sec)
+  {
+    return -1;
+  }
+  else if (t0->tv_sec > t1->tv_sec)
+  {
+    return 1;
+  }
+  if (t0->tv_usec < t1->tv_usec)
+  {
+    return -1;
+  }
+  else if (t0->tv_usec > t1->tv_usec)
+  {
+    return 1;
+  }
+  return 0;
+}
+
+void __INLINE__ start_timer1(unsigned long delay_us)
+{
+  int freq_index = 0; /* This is the lowest resolution */
+  unsigned long upper_limit = MAX_DELAY_US;
+
+  unsigned long div;
+  /* Start/Restart the timer to the new shorter value */
+  /* t = 1/freq = 1/19200 = 53us
+   * T=div*t,  div = T/t = delay_us*freq/1000000
+   */
+#if 1 /* Adaptive timer settings */
+  while (delay_us < upper_limit && freq_index < MAX_USABLE_TIMER_FREQ)
+  {
+    freq_index++;
+    upper_limit >>= 1; /* Divide by 2 using shift */
+  }
+  if (freq_index > 0)
+  {
+    freq_index--;
+  }
+#else
+  freq_index = 6;
+#endif
+  div = delay_us * timer_freq_100[freq_index]/10000;
+  if (div < 2)
+  {
+    /* Maybe increase timer freq? */
+    div = 2;
+  }
+  if (div > 255)
+  {
+    div = 0; /* This means 256, the max the timer takes */
+    /* If a longer timeout than the timer can handle is used,
+     * then we must restart it when it goes off.
+     */
+  }
+
+  timer_div_settings[fast_timers_started % NUM_TIMER_STATS] = div;
+  timer_freq_settings[fast_timers_started % NUM_TIMER_STATS] = freq_index;
+  timer_delay_settings[fast_timers_started % NUM_TIMER_STATS] = delay_us;
+
+  D1(printk("start_timer1 : %d us freq: %i div: %i\n",
+            delay_us, freq_index, div));
+  /* Clear timer1 irq */
+  *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr);
+
+  /* Set timer values */
+  *R_TIMER_CTRL = r_timer_ctrl_shadow =
+    (r_timer_ctrl_shadow &
+     ~IO_MASK(R_TIMER_CTRL, timerdiv1) &
+     ~IO_MASK(R_TIMER_CTRL, tm1) &
+     ~IO_MASK(R_TIMER_CTRL, clksel1)) |
+    IO_FIELD(R_TIMER_CTRL, timerdiv1, div) |
+    IO_STATE(R_TIMER_CTRL, tm1, stop_ld) |
+    IO_FIELD(R_TIMER_CTRL, clksel1, freq_index ); /* 6=c19k2Hz */
+
+  /* Ack interrupt */
+  *R_TIMER_CTRL =  r_timer_ctrl_shadow |
+    IO_STATE(R_TIMER_CTRL, i1, clr);
+
+  /* Start timer */
+  *R_TIMER_CTRL = r_timer_ctrl_shadow =
+    (r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, tm1)) |
+    IO_STATE(R_TIMER_CTRL, tm1, run);
+
+  /* Enable timer1 irq */
+  *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer1, set);
+  fast_timers_started++;
+  fast_timer_running = 1;
+}
+
+/* In version 1.4 this function takes 27 - 50 us */
+void start_one_shot_timer(struct fast_timer *t,
+                          fast_timer_function_type *function,
+                          unsigned long data,
+                          unsigned long delay_us,
+                          const char *name)
+{
+  unsigned long flags;
+  struct fast_timer *tmp;
+
+  D1(printk("sft %s %d us\n", name, delay_us));
+
+  save_flags(flags);
+  cli();
+
+  do_gettimeofday_fast(&t->tv_set);
+  tmp = fast_timer_list;
+
+  SANITYCHECK({ /* Check so this is not in the list already... */
+    while (tmp != NULL)
+    {
+      if (tmp == t)
+      {
+        printk(KERN_WARNING
+               "timer name: %s data: 0x%08lX already in list!\n", name, data);
+        sanity_failed++;
+        return;
+      }
+      else
+      {
+        tmp = tmp->next;
+      }
+    }
+    tmp = fast_timer_list;
+  });
+
+  t->delay_us = delay_us;
+  t->function = function;
+  t->data = data;
+  t->name = name;
+
+  t->tv_expires.tv_usec = t->tv_set.tv_usec + delay_us % 1000000;
+  t->tv_expires.tv_sec  = t->tv_set.tv_sec  + delay_us / 1000000;
+  if (t->tv_expires.tv_usec > 1000000)
+  {
+    t->tv_expires.tv_usec -= 1000000;
+    t->tv_expires.tv_sec++;
+  }
+#ifdef FAST_TIMER_LOG
+  timer_added_log[fast_timers_added % NUM_TIMER_STATS] = *t;
+#endif
+  fast_timers_added++;
+
+  /* Check if this should timeout before anything else */
+  if (tmp == NULL || timeval_cmp(&t->tv_expires, &tmp->tv_expires) < 0)
+  {
+    /* Put first in list and modify the timer value */
+    t->prev = NULL;
+    t->next = fast_timer_list;
+    if (fast_timer_list)
+    {
+      fast_timer_list->prev = t;
+    }
+    fast_timer_list = t;
+#ifdef FAST_TIMER_LOG
+    timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t;
+#endif
+    start_timer1(delay_us);
+  } else {
+    /* Put in correct place in list */
+    while (tmp->next &&
+           timeval_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0)
+    {
+      tmp = tmp->next;
+    }
+    /* Insert t after tmp */
+    t->prev = tmp;
+    t->next = tmp->next;
+    if (tmp->next)
+    {
+      tmp->next->prev = t;
+    }
+    tmp->next = t;
+  }
+
+  D2(printk("start_one_shot_timer: %d us done\n", delay_us));
+
+  restore_flags(flags);
+} /* start_one_shot_timer */
+
+static inline int fast_timer_pending (const struct fast_timer * t)
+{
+  return (t->next != NULL) || (t->prev != NULL) || (t == fast_timer_list);
+}
+
+static inline int detach_fast_timer (struct fast_timer *t)
+{
+  struct fast_timer *next, *prev;
+  if (!fast_timer_pending(t))
+    return 0;
+  next = t->next;
+  prev = t->prev;
+  if (next)
+    next->prev = prev;
+  if (prev)
+    prev->next = next;
+  else
+    fast_timer_list = next;
+  fast_timers_deleted++;
+  return 1;
+}
+
+int del_fast_timer(struct fast_timer * t)
+{
+  unsigned long flags;
+  int ret;
+  
+  save_flags(flags);
+  cli();
+  ret = detach_fast_timer(t);
+  t->next = t->prev = NULL;
+  restore_flags(flags);
+  return ret;
+} /* del_fast_timer */
+
+
+/* Interrupt routines or functions called in interrupt context */
+
+/* Timer 1 interrupt handler */
+
+static irqreturn_t
+timer1_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+  struct fast_timer *t;
+  unsigned long flags;
+
+  save_flags(flags);
+  cli();
+
+  /* Clear timer1 irq */
+  *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr);
+
+  /* First stop timer, then ack interrupt */
+  /* Stop timer */
+  *R_TIMER_CTRL = r_timer_ctrl_shadow =
+    (r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, tm1)) |
+    IO_STATE(R_TIMER_CTRL, tm1, stop_ld);
+
+  /* Ack interrupt */
+  *R_TIMER_CTRL =  r_timer_ctrl_shadow | IO_STATE(R_TIMER_CTRL, i1, clr);
+
+  fast_timer_running = 0;
+  fast_timer_ints++;
+
+  restore_flags(flags);
+
+  t = fast_timer_list;
+  while (t)
+  {
+    struct timeval tv;
+
+    /* Has it really expired? */
+    do_gettimeofday_fast(&tv);
+    D1(printk("t: %is %06ius\n", tv.tv_sec, tv.tv_usec));
+
+    if (timeval_cmp(&t->tv_expires, &tv) <= 0)
+    {
+      /* Yes it has expired */
+#ifdef FAST_TIMER_LOG
+      timer_expired_log[fast_timers_expired % NUM_TIMER_STATS] = *t;
+#endif
+      fast_timers_expired++;
+
+      /* Remove this timer before call, since it may reuse the timer */
+      save_flags(flags);
+      cli();
+      if (t->prev)
+      {
+        t->prev->next = t->next;
+      }
+      else
+      {
+        fast_timer_list = t->next;
+      }
+      if (t->next)
+      {
+        t->next->prev = t->prev;
+      }
+      t->prev = NULL;
+      t->next = NULL;
+      restore_flags(flags);
+
+      if (t->function != NULL)
+      {
+        t->function(t->data);
+      }
+      else
+      {
+        DEBUG_LOG("!timer1 %i function==NULL!\n", fast_timer_ints);
+      }
+    }
+    else
+    {
+      /* Timer is to early, let's set it again using the normal routines */
+      D1(printk(".\n"));
+    }
+
+    save_flags(flags);
+    cli();
+    if ((t = fast_timer_list) != NULL)
+    {
+      /* Start next timer.. */
+      long us;
+      struct timeval tv;
+
+      do_gettimeofday_fast(&tv);
+      us = ((t->tv_expires.tv_sec - tv.tv_sec) * 1000000 +
+            t->tv_expires.tv_usec - tv.tv_usec);
+      if (us > 0)
+      {
+        if (!fast_timer_running)
+        {
+#ifdef FAST_TIMER_LOG
+          timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t;
+#endif
+          start_timer1(us);
+        }
+        restore_flags(flags);
+        break;
+      }
+      else
+      {
+        /* Timer already expired, let's handle it better late than never.
+         * The normal loop handles it
+         */
+        D1(printk("e! %d\n", us));
+      }
+    }
+    restore_flags(flags);
+  }
+
+  if (!t)
+  {
+    D1(printk("t1 stop!\n"));
+  }
+
+  return IRQ_HANDLED;
+}
+
+static void wake_up_func(unsigned long data)
+{
+#ifdef DECLARE_WAITQUEUE
+  wait_queue_head_t  *sleep_wait_p = (wait_queue_head_t*)data;
+#else
+  struct wait_queue **sleep_wait_p = (struct wait_queue **)data;
+#endif
+  wake_up(sleep_wait_p);
+}
+
+
+/* Useful API */
+
+void schedule_usleep(unsigned long us)
+{
+  struct fast_timer t;
+#ifdef DECLARE_WAITQUEUE
+  wait_queue_head_t sleep_wait;
+  init_waitqueue_head(&sleep_wait);
+  {
+  DECLARE_WAITQUEUE(wait, current);
+#else
+  struct wait_queue *sleep_wait = NULL;
+  struct wait_queue wait = { current, NULL };
+#endif
+
+  D1(printk("schedule_usleep(%d)\n", us));
+  add_wait_queue(&sleep_wait, &wait);
+  set_current_state(TASK_INTERRUPTIBLE);
+  start_one_shot_timer(&t, wake_up_func, (unsigned long)&sleep_wait, us,
+                       "usleep");
+  schedule();
+  set_current_state(TASK_RUNNING);
+  remove_wait_queue(&sleep_wait, &wait);
+  D1(printk("done schedule_usleep(%d)\n", us));
+#ifdef DECLARE_WAITQUEUE
+  }
+#endif  
+}
+
+#ifdef CONFIG_PROC_FS
+static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
+                       ,int *eof, void *data_unused);
+static struct proc_dir_entry *fasttimer_proc_entry;
+#endif /* CONFIG_PROC_FS */
+
+#ifdef CONFIG_PROC_FS
+
+/* This value is very much based on testing */
+#define BIG_BUF_SIZE (500 + NUM_TIMER_STATS * 300)
+
+static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
+                       ,int *eof, void *data_unused)
+{
+  unsigned long flags;
+  int i = 0;
+  int num_to_show;
+  struct timeval tv;
+  struct fast_timer *t, *nextt;
+  static char *bigbuf = NULL;
+  static unsigned long used;
+
+  if (!bigbuf && !(bigbuf = vmalloc(BIG_BUF_SIZE)))
+  {
+    used = 0;
+    bigbuf[0] = '\0';
+    return 0;
+  }
+
+  if (!offset || !used)
+  {
+    do_gettimeofday_fast(&tv);
+
+    used = 0;
+    used += sprintf(bigbuf + used, "Fast timers added:     %i\n",
+                    fast_timers_added);
+    used += sprintf(bigbuf + used, "Fast timers started:   %i\n",
+                    fast_timers_started);
+    used += sprintf(bigbuf + used, "Fast timer interrupts: %i\n",
+                    fast_timer_ints);
+    used += sprintf(bigbuf + used, "Fast timers expired:   %i\n",
+                    fast_timers_expired);
+    used += sprintf(bigbuf + used, "Fast timers deleted:   %i\n",
+                    fast_timers_deleted);
+    used += sprintf(bigbuf + used, "Fast timer running:    %s\n",
+                    fast_timer_running ? "yes" : "no");
+    used += sprintf(bigbuf + used, "Current time:          %lu.%06lu\n",
+                    (unsigned long)tv.tv_sec,
+                    (unsigned long)tv.tv_usec);
+#ifdef FAST_TIMER_SANITY_CHECKS
+    used += sprintf(bigbuf + used, "Sanity failed:         %i\n",
+                    sanity_failed);
+#endif
+    used += sprintf(bigbuf + used, "\n");
+
+#ifdef DEBUG_LOG_INCLUDED
+    {
+      int end_i = debug_log_cnt;
+      i = 0;
+
+      if (debug_log_cnt_wrapped)
+      {
+        i = debug_log_cnt;
+      }
+
+      while ((i != end_i || (debug_log_cnt_wrapped && !used)) &&
+             used+100 < BIG_BUF_SIZE)
+      {
+        used += sprintf(bigbuf + used, debug_log_string[i],
+                        debug_log_value[i]);
+        i = (i+1) % DEBUG_LOG_MAX;
+      }
+    }
+    used += sprintf(bigbuf + used, "\n");
+#endif
+
+    num_to_show = (fast_timers_started < NUM_TIMER_STATS ? fast_timers_started:
+                   NUM_TIMER_STATS);
+    used += sprintf(bigbuf + used, "Timers started: %i\n", fast_timers_started);
+    for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE) ; i++)
+    {
+      int cur = (fast_timers_started - i - 1) % NUM_TIMER_STATS;
+
+#if 1 //ndef FAST_TIMER_LOG
+      used += sprintf(bigbuf + used, "div: %i freq: %i delay: %i"
+                      "\n",
+                      timer_div_settings[cur],
+                      timer_freq_settings[cur],
+                      timer_delay_settings[cur]
+                      );
+#endif
+#ifdef FAST_TIMER_LOG
+      t = &timer_started_log[cur];
+      used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+                      "d: %6li us data: 0x%08lX"
+                      "\n",
+                      t->name,
+                      (unsigned long)t->tv_set.tv_sec,
+                      (unsigned long)t->tv_set.tv_usec,
+                      (unsigned long)t->tv_expires.tv_sec,
+                      (unsigned long)t->tv_expires.tv_usec,
+                      t->delay_us,
+                      t->data
+                      );
+#endif
+    }
+    used += sprintf(bigbuf + used, "\n");
+
+#ifdef FAST_TIMER_LOG
+    num_to_show = (fast_timers_added < NUM_TIMER_STATS ? fast_timers_added:
+                   NUM_TIMER_STATS);
+    used += sprintf(bigbuf + used, "Timers added: %i\n", fast_timers_added);
+    for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++)
+    {
+      t = &timer_added_log[(fast_timers_added - i - 1) % NUM_TIMER_STATS];
+      used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+                      "d: %6li us data: 0x%08lX"
+                      "\n",
+                      t->name,
+                      (unsigned long)t->tv_set.tv_sec,
+                      (unsigned long)t->tv_set.tv_usec,
+                      (unsigned long)t->tv_expires.tv_sec,
+                      (unsigned long)t->tv_expires.tv_usec,
+                      t->delay_us,
+                      t->data
+                      );
+    }
+    used += sprintf(bigbuf + used, "\n");
+
+    num_to_show = (fast_timers_expired < NUM_TIMER_STATS ? fast_timers_expired:
+                   NUM_TIMER_STATS);
+    used += sprintf(bigbuf + used, "Timers expired: %i\n", fast_timers_expired);
+    for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++)
+    {
+      t = &timer_expired_log[(fast_timers_expired - i - 1) % NUM_TIMER_STATS];
+      used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+                      "d: %6li us data: 0x%08lX"
+                      "\n",
+                      t->name,
+                      (unsigned long)t->tv_set.tv_sec,
+                      (unsigned long)t->tv_set.tv_usec,
+                      (unsigned long)t->tv_expires.tv_sec,
+                      (unsigned long)t->tv_expires.tv_usec,
+                      t->delay_us,
+                      t->data
+                      );
+    }
+    used += sprintf(bigbuf + used, "\n");
+#endif
+
+    used += sprintf(bigbuf + used, "Active timers:\n");
+    save_flags(flags);
+    cli();
+    t = fast_timer_list;
+    while (t != NULL && (used+100 < BIG_BUF_SIZE))
+    {
+      nextt = t->next;
+      restore_flags(flags);
+      used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+                      "d: %6li us data: 0x%08lX"
+/*                      " func: 0x%08lX" */
+                      "\n",
+                      t->name,
+                      (unsigned long)t->tv_set.tv_sec,
+                      (unsigned long)t->tv_set.tv_usec,
+                      (unsigned long)t->tv_expires.tv_sec,
+                      (unsigned long)t->tv_expires.tv_usec,
+                      t->delay_us,
+                      t->data
+/*                      , t->function */
+                      );
+      cli();
+      if (t->next != nextt)
+      {
+        printk(KERN_WARNING "timer removed!\n");
+      }
+      t = nextt;
+    }
+    restore_flags(flags);
+  }
+
+  if (used - offset < len)
+  {
+    len = used - offset;
+  }
+
+  memcpy(buf, bigbuf + offset, len);
+  *start = buf;
+  *eof = 1;
+
+  return len;
+}
+#endif /* PROC_FS */
+
+#ifdef FAST_TIMER_TEST
+static volatile unsigned long i = 0;
+static volatile int num_test_timeout = 0;
+static struct fast_timer tr[10];
+static int exp_num[10];
+
+static struct timeval tv_exp[100];
+
+static void test_timeout(unsigned long data)
+{
+  do_gettimeofday_fast(&tv_exp[data]);
+  exp_num[data] = num_test_timeout;
+
+  num_test_timeout++;
+}
+
+static void test_timeout1(unsigned long data)
+{
+  do_gettimeofday_fast(&tv_exp[data]);
+  exp_num[data] = num_test_timeout;
+  if (data < 7)
+  {
+    start_one_shot_timer(&tr[i], test_timeout1, i, 1000, "timeout1");
+    i++;
+  }
+  num_test_timeout++;
+}
+
+DP(
+static char buf0[2000];
+static char buf1[2000];
+static char buf2[2000];
+static char buf3[2000];
+static char buf4[2000];
+);
+
+static char buf5[6000];
+static int j_u[1000];
+
+static void fast_timer_test(void)
+{
+  int prev_num;
+  int j;
+
+  struct timeval tv, tv0, tv1, tv2;
+
+  printk("fast_timer_test() start\n");
+  do_gettimeofday_fast(&tv);
+
+  for (j = 0; j < 1000; j++)
+  {
+    j_u[j] = GET_JIFFIES_USEC();
+  }
+  for (j = 0; j < 100; j++)
+  {
+    do_gettimeofday_fast(&tv_exp[j]);
+  }
+  printk("fast_timer_test() %is %06i\n", tv.tv_sec, tv.tv_usec);
+
+  for (j = 0; j < 1000; j++)
+  {
+    printk("%i %i %i %i %i\n",j_u[j], j_u[j+1], j_u[j+2], j_u[j+3], j_u[j+4]);
+    j += 4;
+  }
+  for (j = 0; j < 100; j++)
+  {
+    printk("%i.%i %i.%i %i.%i %i.%i %i.%i\n",
+           tv_exp[j].tv_sec,tv_exp[j].tv_usec,
+           tv_exp[j+1].tv_sec,tv_exp[j+1].tv_usec,
+           tv_exp[j+2].tv_sec,tv_exp[j+2].tv_usec,
+           tv_exp[j+3].tv_sec,tv_exp[j+3].tv_usec,
+           tv_exp[j+4].tv_sec,tv_exp[j+4].tv_usec);
+    j += 4;
+  }
+  do_gettimeofday_fast(&tv0);
+  start_one_shot_timer(&tr[i], test_timeout, i, 50000, "test0");
+  DP(proc_fasttimer_read(buf0, NULL, 0, 0, 0));
+  i++;
+  start_one_shot_timer(&tr[i], test_timeout, i, 70000, "test1");
+  DP(proc_fasttimer_read(buf1, NULL, 0, 0, 0));
+  i++;
+  start_one_shot_timer(&tr[i], test_timeout, i, 40000, "test2");
+  DP(proc_fasttimer_read(buf2, NULL, 0, 0, 0));
+  i++;
+  start_one_shot_timer(&tr[i], test_timeout, i, 60000, "test3");
+  DP(proc_fasttimer_read(buf3, NULL, 0, 0, 0));
+  i++;
+  start_one_shot_timer(&tr[i], test_timeout1, i, 55000, "test4xx");
+  DP(proc_fasttimer_read(buf4, NULL, 0, 0, 0));
+  i++;
+  do_gettimeofday_fast(&tv1);
+
+  proc_fasttimer_read(buf5, NULL, 0, 0, 0);
+
+  prev_num = num_test_timeout;
+  while (num_test_timeout < i)
+  {
+    if (num_test_timeout != prev_num)
+    {
+      prev_num = num_test_timeout;
+    }
+  }
+  do_gettimeofday_fast(&tv2);
+  printk("Timers started    %is %06i\n", tv0.tv_sec, tv0.tv_usec);
+  printk("Timers started at %is %06i\n", tv1.tv_sec, tv1.tv_usec);
+  printk("Timers done       %is %06i\n", tv2.tv_sec, tv2.tv_usec);
+  DP(printk("buf0:\n");
+     printk(buf0);
+     printk("buf1:\n");
+     printk(buf1);
+     printk("buf2:\n");
+     printk(buf2);
+     printk("buf3:\n");
+     printk(buf3);
+     printk("buf4:\n");
+     printk(buf4);
+  );
+  printk("buf5:\n");
+  printk(buf5);
+
+  printk("timers set:\n");
+  for(j = 0; j<i; j++)
+  {
+    struct fast_timer *t = &tr[j];
+    printk("%-10s set: %6is %06ius exp: %6is %06ius "
+           "data: 0x%08X func: 0x%08X\n",
+           t->name,
+           t->tv_set.tv_sec,
+           t->tv_set.tv_usec,
+           t->tv_expires.tv_sec,
+           t->tv_expires.tv_usec,
+           t->data,
+           t->function
+           );
+
+    printk("           del: %6ius     did exp: %6is %06ius as #%i error: %6li\n",
+           t->delay_us,
+           tv_exp[j].tv_sec,
+           tv_exp[j].tv_usec,
+           exp_num[j],
+           (tv_exp[j].tv_sec - t->tv_expires.tv_sec)*1000000 + tv_exp[j].tv_usec - t->tv_expires.tv_usec);
+  }
+  proc_fasttimer_read(buf5, NULL, 0, 0, 0);
+  printk("buf5 after all done:\n");
+  printk(buf5);
+  printk("fast_timer_test() done\n");
+}
+#endif
+
+
+void fast_timer_init(void)
+{
+  /* For some reason, request_irq() hangs when called froom time_init() */
+  if (!fast_timer_is_init)
+  {
+#if 0 && defined(FAST_TIMER_TEST)
+    int i;
+#endif
+
+    printk(KERN_INFO "fast_timer_init()\n");
+
+#if 0 && defined(FAST_TIMER_TEST)
+    for (i = 0; i <= TIMER0_DIV; i++)
+    {
+      /* We must be careful not to get overflow... */
+      printk("%3i %6u\n", i, timer0_value_us[i]);
+    }
+#endif
+#ifdef CONFIG_PROC_FS
+   if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 )))
+     fasttimer_proc_entry->read_proc = proc_fasttimer_read;
+#endif /* PROC_FS */
+    if(request_irq(TIMER1_IRQ_NBR, timer1_handler, SA_SHIRQ,
+                   "fast timer int", NULL))
+    {
+      printk("err: timer1 irq\n");
+    }
+    fast_timer_is_init = 1;
+#ifdef FAST_TIMER_TEST
+    printk("do test\n");
+    fast_timer_test();
+#endif
+  }
+}
diff --git a/arch/cris/arch-v10/kernel/head.S b/arch/cris/arch-v10/kernel/head.S
new file mode 100644
index 0000000..2c1dd11
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/head.S
@@ -0,0 +1,882 @@
+/* $Id: head.S,v 1.7 2004/05/14 07:58:01 starvik 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.7  2004/05/14 07:58:01  starvik
+ * Merge of changes from 2.4
+ *
+ * Revision 1.6  2003/04/28 05:31:46  starvik
+ * Added section attributes
+ *
+ * Revision 1.5  2002/12/11 15:42:02  starvik
+ * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/*.c
+ *
+ * Revision 1.4  2002/11/07 09:00:44  starvik
+ * Names changed for init sections
+ * init_task_union -> init_thread_union
+ *
+ * Revision 1.3  2002/02/05 15:38:23  bjornw
+ * Oops.. non-CRAMFS_MAGIC should jump over the copying, not into it...
+ *
+ * Revision 1.2  2001/12/18 13:35:19  bjornw
+ * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15).
+ *
+ * Revision 1.43  2001/11/08 15:09:43  starvik
+ * Only start MII clock if Ethernet is configured
+ *
+ * Revision 1.42  2001/11/08 14:37:34  starvik
+ * Start MII clock early to make sure that it is running at tranceiver reset
+ *
+ * Revision 1.41  2001/10/29 14:55:58  pkj
+ * Corrected pa$r0 to par0.
+ *
+ * Revision 1.40  2001/10/03 14:59:57  pkj
+ * Added support for resetting the Bluetooth hardware.
+ *
+ * Revision 1.39  2001/10/01 14:45:03  bjornw
+ * Removed underscores and added register prefixes
+ *
+ * Revision 1.38  2001/09/21 07:14:11  jonashg
+ * Made root filesystem (cramfs) use mtdblock driver when booting from flash.
+ *
+ * Revision 1.37  2001/09/11 13:44:29  orjanf
+ * Decouple usage of serial ports for debug and kgdb.
+ *
+ * Revision 1.36  2001/06/29 12:39:31  pkj
+ * Added support for mirroring the first flash to just below the
+ * second one, to make them look consecutive to cramfs.
+ *
+ * Revision 1.35  2001/06/25 14:07:00  hp
+ * 	Fix review comment.
+ * 	* head.S: Use IO_STATE, IO_FIELD and IO_MASK constructs instead of
+ * 	magic numbers.  Add comment that -traditional must not be used.
+ * 	* entry.S (SYMBOL_NAME): Change redefinition to use ## concatenation.
+ * 	Correct and update comment.
+ * 	* Makefile (.S.o): Don't use -traditional.  Add comment why the
+ * 	toplevel rule can't be used (now that there's a reason).
+ *
+ * Revision 1.34  2001/05/15 07:08:14  hp
+ * Tweak "notice" to reflect that both r8 r9 are used
+ *
+ * Revision 1.33  2001/05/15 06:40:05  hp
+ * Put bulk of code in .text.init, data in .data.init
+ *
+ * Revision 1.32  2001/05/15 06:18:56  hp
+ * Execute review comment: s/bcc/bhs/g; s/bcs/blo/g
+ *
+ * Revision 1.31  2001/05/15 06:08:40  hp
+ * Add sentence about autodetecting the bit31-MMU-bug
+ *
+ * Revision 1.30  2001/05/15 06:00:05  hp
+ * Update comment: LOW_MAP is not forced on xsim anymore.
+ *
+ * Revision 1.29  2001/04/18 12:51:59  orjanf
+ * * Reverted review change regarding the use of bcs/bcc.
+ * * Removed non-working LED-clearing code.
+ *
+ * Revision 1.28  2001/04/17 13:58:39  orjanf
+ * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB.
+ *
+ * Revision 1.27  2001/04/17 11:42:35  orjanf
+ * Changed according to review:
+ * * Added comment explaining memory map bug.
+ * * Changed bcs and bcc to blo and bhs, respectively.
+ * * Removed mentioning of Stallone and Olga boards.
+ *
+ * Revision 1.26  2001/04/06 12:31:07  jonashg
+ * Check for cramfs in flash before RAM instead of RAM before flash.
+ *
+ * Revision 1.25  2001/04/04 06:23:53  starvik
+ * Initialize DRAM if not already initialized
+ *
+ * Revision 1.24  2001/04/03 11:12:00  starvik
+ * Removed dram init (done by rescue or etrax100boot
+ * Corrected include
+ *
+ * Revision 1.23  2001/04/03 09:53:03  starvik
+ * Include hw_settings.S
+ *
+ * Revision 1.22  2001/03/26 14:23:26  bjornw
+ * Namechange of some config options
+ *
+ * Revision 1.21  2001/03/08 12:14:41  bjornw
+ * * Config name for ETRAX IDE was renamed
+ * * Removed G27 auto-setting when JULIETTE is chosen (need to make this
+ *   a new config option later)
+ *
+ * Revision 1.20  2001/02/23 12:47:56  bjornw
+ * MMU regs during LOW_MAP updated to reflect a newer reality
+ *
+ * Revision 1.19  2001/02/19 11:12:07  bjornw
+ * Changed comment header format
+ *
+ * Revision 1.18  2001/02/15 07:25:38  starvik
+ * Added support for synchronous serial ports
+ *
+ * Revision 1.17  2001/02/08 15:53:13  starvik
+ * Last commit removed some important ifdefs
+ *
+ * Revision 1.16  2001/02/08 15:20:38  starvik
+ * Include dram_init.S as inline
+ *
+ * Revision 1.15  2001/01/29 18:12:01  bjornw
+ * Corrected some comments
+ *
+ * Revision 1.14  2001/01/29 13:11:29  starvik
+ * Include dram_init.S (with DRAM/SDRAM initialization)
+ *
+ * Revision 1.13  2001/01/23 14:54:57  markusl
+ * Updated for USB
+ * i.e. added r_gen_config settings
+ *
+ * Revision 1.12  2001/01/19 16:16:29  perf
+ * Added temporary mapping of 0x0c->0x0c to avoid flash loading confusion.
+ * Renamed serial options from ETRAX100 to ETRAX.
+ *
+ * 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
+/* The IO_* macros use the ## token concatenation operator, so
+   -traditional must not be used when assembling this file.  */
+#include <asm/arch/sv_addr_ag.h>
+
+#define CRAMFS_MAGIC 0x28cd3d45
+#define RAM_INIT_MAGIC 0x56902387
+
+#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
+					
+	.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 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.
+	.section ".init.text", "ax"
+_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.
+#ifndef CONFIG_SVINTO_SIM
+	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]
+#endif
+
+	;; 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	__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	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:
+
+	;; 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
+	
+#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]
+	; cnt enable, word size, output, stop, size 0
+	move.d	  IO_STATE (R_EXT_DMA_0_CMD, cnt, enable)	\
+		| IO_STATE (R_EXT_DMA_0_CMD, rqpol, ahigh)	\
+		| IO_STATE (R_EXT_DMA_0_CMD, apol, ahigh)	\
+		| IO_STATE (R_EXT_DMA_0_CMD, rq_ack, burst)	\
+		| IO_STATE (R_EXT_DMA_0_CMD, wid, word)		\
+		| IO_STATE (R_EXT_DMA_0_CMD, dir, output)	\
+		| IO_STATE (R_EXT_DMA_0_CMD, run, stop)		\
+		| IO_FIELD (R_EXT_DMA_0_CMD, trf_count, 0),$r0
+	move.d	$r0,[R_EXT_DMA_0_CMD]
+
+	;; reset dma4 and wait for completion
+	
+	moveq	IO_STATE (R_DMA_CH4_CMD, cmd, reset),$r0
+	move.b	$r0,[R_DMA_CH4_CMD]
+1:	move.b	[R_DMA_CH4_CMD],$r0
+	and.b	IO_MASK (R_DMA_CH4_CMD, cmd),$r0
+	cmp.b	IO_STATE (R_DMA_CH4_CMD, cmd, reset),$r0
+	beq	1b
+	nop
+
+	;; reset dma5 and wait for completion
+	
+	moveq	IO_STATE (R_DMA_CH5_CMD, cmd, reset),$r0
+	move.b	$r0,[R_DMA_CH5_CMD]
+1:	move.b	[R_DMA_CH5_CMD],$r0
+	and.b	IO_MASK (R_DMA_CH5_CMD, cmd),$r0
+	cmp.b	IO_STATE (R_DMA_CH5_CMD, cmd, reset),$r0
+	beq	1b
+	nop
+#endif	
+			
+	;; Etrax product HW genconfig setup
+
+	moveq	0,$r0
+#if (!defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT0)) \
+	&& !defined(CONFIG_DMA_MEMCPY)
+	; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA
+	or.d	  IO_STATE (R_GEN_CONFIG, dma7, serial0)	\
+		| IO_STATE (R_GEN_CONFIG, dma6, serial0),$r0
+#endif
+#if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT1)
+	; DMA channels 8 and 9 to ser1, kgdb doesnt want DMA
+	or.d	  IO_STATE (R_GEN_CONFIG, dma9, serial1)	\
+		| IO_STATE (R_GEN_CONFIG, dma8, serial1),$r0
+#endif	
+#ifdef CONFIG_DMA_MEMCPY
+	; 6/7 memory-memory DMA
+	or.d	  IO_STATE (R_GEN_CONFIG, dma7, intdma6)	\
+		| IO_STATE (R_GEN_CONFIG, dma6, intdma7),$r0
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+	; Enable serial port 2
+	or.w	IO_STATE (R_GEN_CONFIG, ser2, select),$r0
+#if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT2)
+	; DMA channels 2 and 3 to ser2, kgdb doesnt want DMA
+	or.d	  IO_STATE (R_GEN_CONFIG, dma3, serial2)	\
+		| IO_STATE (R_GEN_CONFIG, dma2, serial2),$r0
+#endif
+#endif
+#if defined(CONFIG_ETRAX_SERIAL_PORT3) || defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1)
+	; Enable serial port 3
+	or.w	IO_STATE (R_GEN_CONFIG, ser3, select),$r0
+#if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT3)
+	; DMA channels 4 and 5 to ser3, kgdb doesnt want DMA
+	or.d	  IO_STATE (R_GEN_CONFIG, dma5, serial3)	\
+		| IO_STATE (R_GEN_CONFIG, dma4, serial3),$r0
+#endif
+#endif
+#if defined(CONFIG_ETRAX_PARALLEL_PORT0) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE)
+	; parport 0 enabled using DMA 2/3
+	or.w	IO_STATE (R_GEN_CONFIG, par0, select),$r0
+#endif
+#if defined(CONFIG_ETRAX_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE)
+	; parport 1 enabled using DMA 4/5
+	or.w	IO_STATE (R_GEN_CONFIG, par1, select),$r0
+#endif
+#ifdef CONFIG_ETRAX_IDE
+	; DMA channels 2 and 3 to ATA, ATA enabled
+	or.d	  IO_STATE (R_GEN_CONFIG, dma3, ata)	\
+		| IO_STATE (R_GEN_CONFIG, dma2, ata)	\
+		| IO_STATE (R_GEN_CONFIG, ata, select),$r0
+#endif
+	
+#ifdef CONFIG_ETRAX_USB_HOST_PORT1
+	; Set the USB port 1 enable bit
+	or.d	IO_STATE (R_GEN_CONFIG, usb1, select),$r0
+#endif
+#ifdef CONFIG_ETRAX_USB_HOST_PORT2
+	; Set the USB port 2 enable bit
+	or.d	IO_STATE (R_GEN_CONFIG, usb2, select),$r0
+#endif
+#ifdef CONFIG_ETRAX_USB_HOST
+	; Connect DMA channels 8 and 9 to USB
+	and.d	(~(IO_MASK (R_GEN_CONFIG, dma9)		\
+		   | IO_MASK (R_GEN_CONFIG, dma8)))	\
+		| IO_STATE (R_GEN_CONFIG, dma9, usb)	\
+		| IO_STATE (R_GEN_CONFIG, dma8, usb),$r0
+#endif
+	
+#ifdef CONFIG_JULIETTE
+	; DMA channels 4 and 5 to EXTDMA0, for Juliette
+	or.d	  IO_STATE (R_GEN_CONFIG, dma5, extdma0)	\
+		| IO_STATE (R_GEN_CONFIG, dma4, extdma0),$r0
+#endif
+
+#if defined(CONFIG_ETRAX_DEF_R_PORT_G0_DIR_OUT)
+        or.d      IO_STATE (R_GEN_CONFIG, g0dir, out),$r0
+#endif
+
+#if defined(CONFIG_ETRAX_DEF_R_PORT_G8_15_DIR_OUT)
+        or.d      IO_STATE (R_GEN_CONFIG, g8_15dir, out),$r0
+#endif
+#if defined(CONFIG_ETRAX_DEF_R_PORT_G16_23_DIR_OUT)
+       or.d      IO_STATE (R_GEN_CONFIG, g16_23dir, out),$r0
+#endif
+
+#if defined(CONFIG_ETRAX_DEF_R_PORT_G24_DIR_OUT)
+       or.d      IO_STATE (R_GEN_CONFIG, g24dir, out),$r0
+#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)
+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
+#if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_PA7)
+	or.b	IO_STATE (R_PORT_PA_DIR, dir7, output),$r0
+#endif
+	move.b	$r0,[port_pa_dir_shadow]
+	move.b	$r0,[R_PORT_PA_DIR]
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PA_DATA,$r0
+#if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_PA7)
+#if defined(CONFIG_BLUETOOTH_RESET_ACTIVE_HIGH)
+	and.b	~(1 << 7),$r0
+#else
+	or.b	(1 << 7),$r0
+#endif
+#endif
+	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
+#if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_PB5)
+	or.b	IO_STATE (R_PORT_PB_DIR, dir5, output),$r0
+#endif
+	move.b	$r0,[port_pb_dir_shadow]
+	move.b	$r0,[R_PORT_PB_DIR]
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_DATA,$r0
+#if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_PB5)
+#if defined(CONFIG_BLUETOOTH_RESET_ACTIVE_HIGH)
+	and.b	~(1 << 5),$r0
+#else
+	or.b	(1 << 5),$r0
+#endif
+#endif
+	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
+#if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_G10)
+#if defined(CONFIG_BLUETOOTH_RESET_ACTIVE_HIGH)
+	and.d	~(1 << 10),$r0
+#else
+	or.d	(1 << 10),$r0
+#endif
+#endif
+#if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_G11)
+#if defined(CONFIG_BLUETOOTH_RESET_ACTIVE_HIGH)
+	and.d	~(1 << 11),$r0
+#else
+	or.d	(1 << 11),$r0
+#endif
+#endif
+	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_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
+	
+#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
+
+	.section ".init.data", "aw"
+#include "../lib/hw_settings.S"
diff --git a/arch/cris/arch-v10/kernel/irq.c b/arch/cris/arch-v10/kernel/irq.c
new file mode 100644
index 0000000..b2f16d6
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/irq.c
@@ -0,0 +1,204 @@
+/* $Id: irq.c,v 1.2 2004/06/09 05:30:27 starvik Exp $
+ *
+ *	linux/arch/cris/kernel/irq.c
+ *
+ *      Copyright (c) 2000-2002 Axis Communications AB
+ *
+ *      Authors: Bjorn Wesen (bjornw@axis.com)
+ *
+ *      This file contains the interrupt vectors and some 
+ *      helper functions
+ *
+ */
+
+#include <asm/irq.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/config.h>
+
+irqvectptr irq_shortcuts[NR_IRQS]; /* vector of shortcut jumps after the irq prologue */
+
+/* don't use set_int_vector, it bypasses the linux interrupt handlers. it is
+ * global just so that the kernel gdb can use it.
+ */
+
+void
+set_int_vector(int n, irqvectptr addr)
+{
+	etrax_irv->v[n + 0x20] = (irqvectptr)addr;
+}
+
+/* the breakpoint vector is obviously not made just like the normal irq handlers
+ * but needs to contain _code_ to jump to addr.
+ *
+ * the BREAK n instruction jumps to IBR + n * 8
+ */
+
+void
+set_break_vector(int n, irqvectptr addr)
+{
+	unsigned short *jinstr = (unsigned short *)&etrax_irv->v[n*2];
+	unsigned long *jaddr = (unsigned long *)(jinstr + 1);
+
+	/* if you don't know what this does, do not touch it! */
+	
+	*jinstr = 0x0d3f;
+	*jaddr = (unsigned long)addr;
+
+	/* 00000026 <clrlop+1a> 3f0d82000000     jump  0x82 */
+}
+
+/*
+ * This builds up the IRQ handler stubs using some ugly macros in irq.h
+ *
+ * These macros create the low-level assembly IRQ routines that do all
+ * the operations that are needed. They are also written to be fast - and to
+ * disable interrupts as little as humanly possible.
+ *
+ */
+
+/* IRQ0 and 1 are special traps */
+void hwbreakpoint(void);
+void IRQ1_interrupt(void);
+BUILD_TIMER_IRQ(2, 0x04)       /* the timer interrupt is somewhat special */
+BUILD_IRQ(3, 0x08)
+BUILD_IRQ(4, 0x10)
+BUILD_IRQ(5, 0x20)
+BUILD_IRQ(6, 0x40)
+BUILD_IRQ(7, 0x80)
+BUILD_IRQ(8, 0x100)
+BUILD_IRQ(9, 0x200)
+BUILD_IRQ(10, 0x400)
+BUILD_IRQ(11, 0x800)
+BUILD_IRQ(12, 0x1000)
+BUILD_IRQ(13, 0x2000)
+void mmu_bus_fault(void);      /* IRQ 14 is the bus fault interrupt */
+void multiple_interrupt(void); /* IRQ 15 is the multiple IRQ interrupt */
+BUILD_IRQ(16, 0x10000)
+BUILD_IRQ(17, 0x20000)
+BUILD_IRQ(18, 0x40000)
+BUILD_IRQ(19, 0x80000)
+BUILD_IRQ(20, 0x100000)
+BUILD_IRQ(21, 0x200000)
+BUILD_IRQ(22, 0x400000)
+BUILD_IRQ(23, 0x800000)
+BUILD_IRQ(24, 0x1000000)
+BUILD_IRQ(25, 0x2000000)
+/* IRQ 26-30 are reserved */
+BUILD_IRQ(31, 0x80000000)
+ 
+/*
+ * Pointers to the low-level handlers 
+ */
+
+static void (*interrupt[NR_IRQS])(void) = {
+	NULL, NULL, IRQ2_interrupt, IRQ3_interrupt,
+	IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt,
+	IRQ8_interrupt, IRQ9_interrupt, IRQ10_interrupt, IRQ11_interrupt,
+	IRQ12_interrupt, IRQ13_interrupt, NULL, NULL,	
+	IRQ16_interrupt, IRQ17_interrupt, IRQ18_interrupt, IRQ19_interrupt,	
+	IRQ20_interrupt, IRQ21_interrupt, IRQ22_interrupt, IRQ23_interrupt,	
+	IRQ24_interrupt, IRQ25_interrupt, NULL, NULL, NULL, NULL, NULL,
+	IRQ31_interrupt
+};
+
+static void (*bad_interrupt[NR_IRQS])(void) = {
+        NULL, NULL,
+	NULL, bad_IRQ3_interrupt,
+	bad_IRQ4_interrupt, bad_IRQ5_interrupt,
+	bad_IRQ6_interrupt, bad_IRQ7_interrupt,
+	bad_IRQ8_interrupt, bad_IRQ9_interrupt,
+	bad_IRQ10_interrupt, bad_IRQ11_interrupt,
+	bad_IRQ12_interrupt, bad_IRQ13_interrupt,
+	NULL, NULL,
+	bad_IRQ16_interrupt, bad_IRQ17_interrupt,
+	bad_IRQ18_interrupt, bad_IRQ19_interrupt,
+	bad_IRQ20_interrupt, bad_IRQ21_interrupt,
+	bad_IRQ22_interrupt, bad_IRQ23_interrupt,
+	bad_IRQ24_interrupt, bad_IRQ25_interrupt,
+	NULL, NULL, NULL, NULL, NULL,
+	bad_IRQ31_interrupt
+};
+
+void arch_setup_irq(int irq)
+{
+  set_int_vector(irq, interrupt[irq]);
+}
+
+void arch_free_irq(int irq)
+{
+  set_int_vector(irq, bad_interrupt[irq]);
+}
+
+void weird_irq(void);
+void system_call(void);  /* from entry.S */
+void do_sigtrap(void); /* from entry.S */
+void gdb_handle_breakpoint(void); /* from entry.S */
+
+/* init_IRQ() is called by start_kernel and is responsible for fixing IRQ masks and
+   setting the irq vector table to point to bad_interrupt ptrs.
+*/
+
+void __init
+init_IRQ(void)
+{
+	int i;
+
+	/* clear all interrupt masks */
+
+#ifndef CONFIG_SVINTO_SIM
+	*R_IRQ_MASK0_CLR = 0xffffffff;
+	*R_IRQ_MASK1_CLR = 0xffffffff;
+	*R_IRQ_MASK2_CLR = 0xffffffff;
+#endif
+
+	*R_VECT_MASK_CLR = 0xffffffff;
+
+	/* clear the shortcut entry points */
+
+	for(i = 0; i < NR_IRQS; i++)
+		irq_shortcuts[i] = NULL;
+        
+        for (i = 0; i < 256; i++)
+               etrax_irv->v[i] = weird_irq;
+
+        /* the entries in the break vector contain actual code to be
+           executed by the associated break handler, rather than just a jump
+           address. therefore we need to setup a default breakpoint handler
+           for all breakpoints */
+
+	for (i = 0; i < 16; i++)
+                set_break_vector(i, do_sigtrap);
+        
+	/* set all etrax irq's to the bad handlers */
+	for (i = 2; i < NR_IRQS; i++)
+		set_int_vector(i, bad_interrupt[i]);
+        
+	/* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */
+
+	set_int_vector(15, multiple_interrupt);
+	
+	/* 0 and 1 which are special breakpoint/NMI traps */
+
+	set_int_vector(0, hwbreakpoint);
+	set_int_vector(1, IRQ1_interrupt);
+
+	/* and irq 14 which is the mmu bus fault handler */
+
+	set_int_vector(14, mmu_bus_fault);
+
+	/* setup the system-call trap, which is reached by BREAK 13 */
+
+	set_break_vector(13, system_call);
+
+        /* setup a breakpoint handler for debugging used for both user and
+           kernel mode debugging  (which is why it is not inside an ifdef
+           CONFIG_ETRAX_KGDB) */
+        set_break_vector(8, gdb_handle_breakpoint);
+
+#ifdef CONFIG_ETRAX_KGDB
+	/* setup kgdb if its enabled, and break into the debugger */
+	kgdb_init();
+	breakpoint();
+#endif
+}
diff --git a/arch/cris/arch-v10/kernel/kgdb.c b/arch/cris/arch-v10/kernel/kgdb.c
new file mode 100644
index 0000000..7d368c8
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/kgdb.c
@@ -0,0 +1,1568 @@
+/*!**************************************************************************
+*!
+*! FILE NAME  : kgdb.c
+*!
+*! DESCRIPTION: Implementation of the gdb stub with respect to ETRAX 100.
+*!              It is a mix of arch/m68k/kernel/kgdb.c and cris_stub.c.
+*!
+*!---------------------------------------------------------------------------
+*! HISTORY
+*!
+*! DATE         NAME            CHANGES
+*! ----         ----            -------
+*! Apr 26 1999  Hendrik Ruijter Initial version.
+*! May  6 1999  Hendrik Ruijter Removed call to strlen in libc and removed
+*!                              struct assignment as it generates calls to
+*!                              memcpy in libc.
+*! Jun 17 1999  Hendrik Ruijter Added gdb 4.18 support. 'X', 'qC' and 'qL'.
+*! Jul 21 1999  Bjorn Wesen     eLinux port
+*!
+*! $Log: kgdb.c,v $
+*! Revision 1.5  2004/10/07 13:59:08  starvik
+*! Corrected call to set_int_vector
+*!
+*! Revision 1.4  2003/04/09 05:20:44  starvik
+*! Merge of Linux 2.5.67
+*!
+*! Revision 1.3  2003/01/21 19:11:08  starvik
+*! Modified include path for new dir layout
+*!
+*! Revision 1.2  2002/11/19 14:35:24  starvik
+*! Changes from linux 2.4
+*! Changed struct initializer syntax to the currently prefered notation
+*!
+*! Revision 1.1  2001/12/17 13:59:27  bjornw
+*! Initial revision
+*!
+*! Revision 1.6  2001/10/09 13:10:03  matsfg
+*! Added $ on registers and removed some underscores
+*!
+*! Revision 1.5  2001/04/17 13:58:39  orjanf
+*! * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB.
+*!
+*! Revision 1.4  2001/02/23 13:45:19  bjornw
+*! config.h check
+*!
+*! Revision 1.3  2001/01/31 18:08:23  orjanf
+*! Removed kgdb_handle_breakpoint from being the break 8 handler.
+*!
+*! Revision 1.2  2001/01/12 14:22:25  orjanf
+*! Updated kernel debugging support to work with ETRAX 100LX.
+*!
+*! Revision 1.1  2000/07/10 16:25:21  bjornw
+*! Initial revision
+*!
+*! Revision 1.1.1.1  1999/12/03 14:57:31  bjornw
+*! * Initial version of arch/cris, the latest CRIS architecture with an MMU.
+*!   Mostly copied from arch/etrax100 with appropriate renames of files.
+*!   The mm/ subdir is copied from arch/i386.
+*!   This does not compile yet at all.
+*!
+*!
+*! Revision 1.4  1999/07/22 17:25:25  bjornw
+*! Dont wait for + in putpacket if we havent hit the initial breakpoint yet. Added a kgdb_init function which sets up the break and irq vectors.
+*!
+*! Revision 1.3  1999/07/21 19:51:18  bjornw
+*! Check if the interrupting char is a ctrl-C, ignore otherwise.
+*!
+*! Revision 1.2  1999/07/21 18:09:39  bjornw
+*! Ported to eLinux architecture, and added some kgdb documentation.
+*!
+*!
+*!---------------------------------------------------------------------------
+*!
+*! $Id: kgdb.c,v 1.5 2004/10/07 13:59:08 starvik Exp $
+*!
+*! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN
+*!
+*!**************************************************************************/
+/* @(#) cris_stub.c 1.3 06/17/99 */
+
+/*
+ *  kgdb usage notes:
+ *  -----------------
+ *
+ * If you select CONFIG_ETRAX_KGDB in the configuration, the kernel will be 
+ * built with different gcc flags: "-g" is added to get debug infos, and
+ * "-fomit-frame-pointer" is omitted to make debugging easier. Since the
+ * resulting kernel will be quite big (approx. > 7 MB), it will be stripped
+ * before compresion. Such a kernel will behave just as usually, except if
+ * given a "debug=<device>" command line option. (Only serial devices are
+ * allowed for <device>, i.e. no printers or the like; possible values are
+ * machine depedend and are the same as for the usual debug device, the one
+ * for logging kernel messages.) If that option is given and the device can be
+ * initialized, the kernel will connect to the remote gdb in trap_init(). The
+ * serial parameters are fixed to 8N1 and 115200 bps, for easyness of
+ * implementation.
+ *
+ * To start a debugging session, start that gdb with the debugging kernel
+ * image (the one with the symbols, vmlinux.debug) named on the command line.
+ * This file will be used by gdb to get symbol and debugging infos about the
+ * kernel. Next, select remote debug mode by
+ *    target remote <device>
+ * where <device> is the name of the serial device over which the debugged
+ * machine is connected. Maybe you have to adjust the baud rate by
+ *    set remotebaud <rate>
+ * or also other parameters with stty:
+ *    shell stty ... </dev/...
+ * If the kernel to debug has already booted, it waited for gdb and now
+ * connects, and you'll see a breakpoint being reported. If the kernel isn't
+ * running yet, start it now. The order of gdb and the kernel doesn't matter.
+ * Another thing worth knowing about in the getting-started phase is how to
+ * debug the remote protocol itself. This is activated with
+ *    set remotedebug 1
+ * gdb will then print out each packet sent or received. You'll also get some
+ * messages about the gdb stub on the console of the debugged machine.
+ *
+ * If all that works, you can use lots of the usual debugging techniques on
+ * the kernel, e.g. inspecting and changing variables/memory, setting
+ * breakpoints, single stepping and so on. It's also possible to interrupt the
+ * debugged kernel by pressing C-c in gdb. Have fun! :-)
+ *
+ * The gdb stub is entered (and thus the remote gdb gets control) in the
+ * following situations:
+ *
+ *  - If breakpoint() is called. This is just after kgdb initialization, or if
+ *    a breakpoint() call has been put somewhere into the kernel source.
+ *    (Breakpoints can of course also be set the usual way in gdb.)
+ *    In eLinux, we call breakpoint() in init/main.c after IRQ initialization.
+ *
+ *  - If there is a kernel exception, i.e. bad_super_trap() or die_if_kernel()
+ *    are entered. All the CPU exceptions are mapped to (more or less..., see
+ *    the hard_trap_info array below) appropriate signal, which are reported
+ *    to gdb. die_if_kernel() is usually called after some kind of access
+ *    error and thus is reported as SIGSEGV.
+ *
+ *  - When panic() is called. This is reported as SIGABRT.
+ *
+ *  - If C-c is received over the serial line, which is treated as
+ *    SIGINT.
+ *
+ * Of course, all these signals are just faked for gdb, since there is no
+ * signal concept as such for the kernel. It also isn't possible --obviously--
+ * to set signal handlers from inside gdb, or restart the kernel with a
+ * signal.
+ *
+ * Current limitations:
+ *
+ *  - While the kernel is stopped, interrupts are disabled for safety reasons
+ *    (i.e., variables not changing magically or the like). But this also
+ *    means that the clock isn't running anymore, and that interrupts from the
+ *    hardware may get lost/not be served in time. This can cause some device
+ *    errors...
+ *
+ *  - When single-stepping, only one instruction of the current thread is
+ *    executed, but interrupts are allowed for that time and will be serviced
+ *    if pending. Be prepared for that.
+ *
+ *  - All debugging happens in kernel virtual address space. There's no way to
+ *    access physical memory not mapped in kernel space, or to access user
+ *    space. A way to work around this is using get_user_long & Co. in gdb
+ *    expressions, but only for the current process.
+ *
+ *  - Interrupting the kernel only works if interrupts are currently allowed,
+ *    and the interrupt of the serial line isn't blocked by some other means
+ *    (IPL too high, disabled, ...)
+ *
+ *  - The gdb stub is currently not reentrant, i.e. errors that happen therein
+ *    (e.g. accessing invalid memory) may not be caught correctly. This could
+ *    be removed in future by introducing a stack of struct registers.
+ *
+ */
+
+/*
+ *  To enable debugger support, two things need to happen.  One, a
+ *  call to kgdb_init() is necessary in order to allow any breakpoints
+ *  or error conditions to be properly intercepted and reported to gdb.
+ *  Two, a breakpoint needs to be generated to begin communication.  This
+ *  is most easily accomplished by a call to breakpoint(). 
+ *
+ *    The following gdb commands are supported:
+ *
+ * command          function                               Return value
+ *
+ *    g             return the value of the CPU registers  hex data or ENN
+ *    G             set the value of the CPU registers     OK or ENN
+ *
+ *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
+ *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
+ *
+ *    c             Resume at current address              SNN   ( signal NN)
+ *    cAA..AA       Continue at address AA..AA             SNN
+ *
+ *    s             Step one instruction                   SNN
+ *    sAA..AA       Step one instruction from AA..AA       SNN
+ *
+ *    k             kill
+ *
+ *    ?             What was the last sigval ?             SNN   (signal NN)
+ *
+ *    bBB..BB	    Set baud rate to BB..BB		   OK or BNN, then sets
+ *							   baud rate
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum.  A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer.  '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host:                  Reply:
+ * $m0,10#2a               +$00010203040506070809101112131415#42
+ *
+ */
+
+
+#include <linux/string.h>
+#include <linux/signal.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/linkage.h>
+
+#include <asm/setup.h>
+#include <asm/ptrace.h>
+
+#include <asm/arch/svinto.h>
+#include <asm/irq.h>
+
+static int kgdb_started = 0;
+
+/********************************* Register image ****************************/
+/* Use the order of registers as defined in "AXIS ETRAX CRIS Programmer's
+   Reference", p. 1-1, with the additional register definitions of the
+   ETRAX 100LX in cris-opc.h.
+   There are 16 general 32-bit registers, R0-R15, where R14 is the stack
+   pointer, SP, and R15 is the program counter, PC.
+   There are 16 special registers, P0-P15, where three of the unimplemented
+   registers, P0, P4 and P8, are reserved as zero-registers. A read from
+   any of these registers returns zero and a write has no effect. */
+
+typedef
+struct register_image
+{
+	/* Offset */
+	unsigned int     r0;   /* 0x00 */
+	unsigned int     r1;   /* 0x04 */
+	unsigned int     r2;   /* 0x08 */
+	unsigned int     r3;   /* 0x0C */
+	unsigned int     r4;   /* 0x10 */
+	unsigned int     r5;   /* 0x14 */
+	unsigned int     r6;   /* 0x18 */
+	unsigned int     r7;   /* 0x1C */
+	unsigned int     r8;   /* 0x20 Frame pointer */
+	unsigned int     r9;   /* 0x24 */
+	unsigned int    r10;   /* 0x28 */
+	unsigned int    r11;   /* 0x2C */
+	unsigned int    r12;   /* 0x30 */
+	unsigned int    r13;   /* 0x34 */
+	unsigned int     sp;   /* 0x38 Stack pointer */
+	unsigned int     pc;   /* 0x3C Program counter */
+
+        unsigned char    p0;   /* 0x40 8-bit zero-register */
+	unsigned char    vr;   /* 0x41 Version register */
+
+        unsigned short   p4;   /* 0x42 16-bit zero-register */
+	unsigned short  ccr;   /* 0x44 Condition code register */
+	
+	unsigned int    mof;   /* 0x46 Multiply overflow register */
+	
+        unsigned int     p8;   /* 0x4A 32-bit zero-register */
+	unsigned int    ibr;   /* 0x4E Interrupt base register */
+	unsigned int    irp;   /* 0x52 Interrupt return pointer */
+	unsigned int    srp;   /* 0x56 Subroutine return pointer */
+	unsigned int    bar;   /* 0x5A Breakpoint address register */
+	unsigned int   dccr;   /* 0x5E Double condition code register */
+	unsigned int    brp;   /* 0x62 Breakpoint return pointer (pc in caller) */
+	unsigned int    usp;   /* 0x66 User mode stack pointer */
+} registers;
+
+/************** Prototypes for local library functions ***********************/
+
+/* Copy of strcpy from libc. */
+static char *gdb_cris_strcpy (char *s1, const char *s2);
+
+/* Copy of strlen from libc. */
+static int gdb_cris_strlen (const char *s);
+
+/* Copy of memchr from libc. */
+static void *gdb_cris_memchr (const void *s, int c, int n);
+
+/* Copy of strtol from libc. Does only support base 16. */
+static int gdb_cris_strtol (const char *s, char **endptr, int base);
+
+/********************** Prototypes for local functions. **********************/
+/* Copy the content of a register image into another. The size n is
+   the size of the register image. Due to struct assignment generation of
+   memcpy in libc. */
+static void copy_registers (registers *dptr, registers *sptr, int n);
+
+/* Copy the stored registers from the stack. Put the register contents
+   of thread thread_id in the struct reg. */
+static void copy_registers_from_stack (int thread_id, registers *reg);
+
+/* Copy the registers to the stack. Put the register contents of thread
+   thread_id from struct reg to the stack. */
+static void copy_registers_to_stack (int thread_id, registers *reg);
+
+/* Write a value to a specified register regno in the register image
+   of the current thread. */
+static int write_register (int regno, char *val);
+
+/* Write a value to a specified register in the stack of a thread other
+   than the current thread. */
+static write_stack_register (int thread_id, int regno, char *valptr);
+
+/* Read a value from a specified register in the register image. Returns the
+   status of the read operation. The register value is returned in valptr. */
+static int read_register (char regno, unsigned int *valptr);
+
+/* Serial port, reads one character. ETRAX 100 specific. from debugport.c */
+int getDebugChar (void);
+
+/* Serial port, writes one character. ETRAX 100 specific. from debugport.c */
+void putDebugChar (int val);
+
+void enableDebugIRQ (void);
+
+/* Returns the character equivalent of a nibble, bit 7, 6, 5, and 4 of a byte,
+   represented by int x. */
+static char highhex (int x);
+
+/* Returns the character equivalent of a nibble, bit 3, 2, 1, and 0 of a byte,
+   represented by int x. */
+static char lowhex (int x);
+
+/* Returns the integer equivalent of a hexadecimal character. */
+static int hex (char ch);
+
+/* Convert the memory, pointed to by mem into hexadecimal representation.
+   Put the result in buf, and return a pointer to the last character
+   in buf (null). */
+static char *mem2hex (char *buf, unsigned char *mem, int count);
+
+/* Convert the array, in hexadecimal representation, pointed to by buf into
+   binary representation. Put the result in mem, and return a pointer to
+   the character after the last byte written. */
+static unsigned char *hex2mem (unsigned char *mem, char *buf, int count);
+
+/* Put the content of the array, in binary representation, pointed to by buf
+   into memory pointed to by mem, and return a pointer to
+   the character after the last byte written. */
+static unsigned char *bin2mem (unsigned char *mem, unsigned char *buf, int count);
+
+/* Await the sequence $<data>#<checksum> and store <data> in the array buffer
+   returned. */
+static void getpacket (char *buffer);
+
+/* Send $<data>#<checksum> from the <data> in the array buffer. */
+static void putpacket (char *buffer);
+
+/* Build and send a response packet in order to inform the host the
+   stub is stopped. */
+static void stub_is_stopped (int sigval);
+
+/* All expected commands are sent from remote.c. Send a response according
+   to the description in remote.c. */
+static void handle_exception (int sigval);
+
+/* Performs a complete re-start from scratch. ETRAX specific. */
+static void kill_restart (void);
+
+/******************** Prototypes for global functions. ***********************/
+
+/* The string str is prepended with the GDB printout token and sent. */
+void putDebugString (const unsigned char *str, int length); /* used by etrax100ser.c */
+
+/* The hook for both static (compiled) and dynamic breakpoints set by GDB.
+   ETRAX 100 specific. */
+void handle_breakpoint (void);                          /* used by irq.c */
+
+/* The hook for an interrupt generated by GDB. ETRAX 100 specific. */
+void handle_interrupt (void);                           /* used by irq.c */
+
+/* A static breakpoint to be used at startup. */
+void breakpoint (void);                                 /* called by init/main.c */
+
+/* From osys_int.c, executing_task contains the number of the current
+   executing task in osys. Does not know of object-oriented threads. */
+extern unsigned char executing_task;
+
+/* The number of characters used for a 64 bit thread identifier. */
+#define HEXCHARS_IN_THREAD_ID 16
+
+/* Avoid warning as the internal_stack is not used in the C-code. */
+#define USEDVAR(name)    { if (name) { ; } }
+#define USEDFUN(name) { void (*pf)(void) = (void *)name; USEDVAR(pf) }
+
+/********************************** Packet I/O ******************************/
+/* BUFMAX defines the maximum number of characters in
+   inbound/outbound buffers */
+#define BUFMAX 512
+
+/* Run-length encoding maximum length. Send 64 at most. */
+#define RUNLENMAX 64
+
+/* Definition of all valid hexadecimal characters */
+static const char hexchars[] = "0123456789abcdef";
+
+/* The inbound/outbound buffers used in packet I/O */
+static char remcomInBuffer[BUFMAX];
+static char remcomOutBuffer[BUFMAX];
+
+/* Error and warning messages. */
+enum error_type
+{
+	SUCCESS, E01, E02, E03, E04, E05, E06, E07
+};
+static char *error_message[] =
+{
+	"",
+	"E01 Set current or general thread - H[c,g] - internal error.",
+	"E02 Change register content - P - cannot change read-only register.",
+	"E03 Thread is not alive.", /* T, not used. */
+	"E04 The command is not supported - [s,C,S,!,R,d,r] - internal error.",
+	"E05 Change register content - P - the register is not implemented..",
+	"E06 Change memory content - M - internal error.",
+	"E07 Change register content - P - the register is not stored on the stack"
+};
+/********************************* Register image ****************************/
+/* Use the order of registers as defined in "AXIS ETRAX CRIS Programmer's
+   Reference", p. 1-1, with the additional register definitions of the
+   ETRAX 100LX in cris-opc.h.
+   There are 16 general 32-bit registers, R0-R15, where R14 is the stack
+   pointer, SP, and R15 is the program counter, PC.
+   There are 16 special registers, P0-P15, where three of the unimplemented
+   registers, P0, P4 and P8, are reserved as zero-registers. A read from
+   any of these registers returns zero and a write has no effect. */
+enum register_name
+{
+	R0,  R1,   R2,  R3,
+	R4,  R5,   R6,  R7,
+	R8,  R9,   R10, R11,
+	R12, R13,  SP,  PC,
+	P0,  VR,   P2,  P3,
+	P4,  CCR,  P6,  MOF,
+	P8,  IBR,  IRP, SRP,
+	BAR, DCCR, BRP, USP
+};
+
+/* The register sizes of the registers in register_name. An unimplemented register
+   is designated by size 0 in this array. */
+static int register_size[] =
+{
+	4, 4, 4, 4,
+	4, 4, 4, 4,
+	4, 4, 4, 4,
+	4, 4, 4, 4,
+	1, 1, 0, 0,
+	2, 2, 0, 4,
+	4, 4, 4, 4,
+	4, 4, 4, 4
+};
+
+/* Contains the register image of the executing thread in the assembler
+   part of the code in order to avoid horrible addressing modes. */
+static registers reg;
+
+/* FIXME: Should this be used? Delete otherwise. */
+/* Contains the assumed consistency state of the register image. Uses the
+   enum error_type for state information. */
+static int consistency_status = SUCCESS;
+
+/********************************** Handle exceptions ************************/
+/* The variable reg contains the register image associated with the
+   current_thread_c variable. It is a complete register image created at
+   entry. The reg_g contains a register image of a task where the general
+   registers are taken from the stack and all special registers are taken
+   from the executing task. It is associated with current_thread_g and used
+   in order to provide access mainly for 'g', 'G' and 'P'.
+*/
+
+/* Need two task id pointers in order to handle Hct and Hgt commands. */
+static int current_thread_c = 0;
+static int current_thread_g = 0;
+
+/* Need two register images in order to handle Hct and Hgt commands. The
+   variable reg_g is in addition to reg above. */
+static registers reg_g;
+
+/********************************** Breakpoint *******************************/
+/* Use an internal stack in the breakpoint and interrupt response routines */
+#define INTERNAL_STACK_SIZE 1024
+static char internal_stack[INTERNAL_STACK_SIZE];
+
+/* Due to the breakpoint return pointer, a state variable is needed to keep
+   track of whether it is a static (compiled) or dynamic (gdb-invoked)
+   breakpoint to be handled. A static breakpoint uses the content of register
+   BRP as it is whereas a dynamic breakpoint requires subtraction with 2
+   in order to execute the instruction. The first breakpoint is static. */
+static unsigned char is_dyn_brkp = 0;
+
+/********************************* String library ****************************/
+/* Single-step over library functions creates trap loops. */
+
+/* Copy char s2[] to s1[]. */
+static char*
+gdb_cris_strcpy (char *s1, const char *s2)
+{
+	char *s = s1;
+	
+	for (s = s1; (*s++ = *s2++) != '\0'; )
+		;
+	return (s1);
+}
+
+/* Find length of s[]. */
+static int
+gdb_cris_strlen (const char *s)
+{
+	const char *sc;
+	
+	for (sc = s; *sc != '\0'; sc++)
+		;
+	return (sc - s);
+}
+
+/* Find first occurrence of c in s[n]. */
+static void*
+gdb_cris_memchr (const void *s, int c, int n)
+{
+	const unsigned char uc = c;
+	const unsigned char *su;
+	
+	for (su = s; 0 < n; ++su, --n)
+		if (*su == uc)
+			return ((void *)su);
+	return (NULL);
+}
+/******************************* Standard library ****************************/
+/* Single-step over library functions creates trap loops. */
+/* Convert string to long. */
+static int
+gdb_cris_strtol (const char *s, char **endptr, int base)
+{
+	char *s1;
+	char *sd;
+	int x = 0;
+	
+	for (s1 = (char*)s; (sd = gdb_cris_memchr(hexchars, *s1, base)) != NULL; ++s1)
+		x = x * base + (sd - hexchars);
+        
+        if (endptr)
+        {
+                /* Unconverted suffix is stored in endptr unless endptr is NULL. */
+                *endptr = s1;
+        }
+        
+	return x;
+}
+
+int
+double_this(int x)
+{
+        return 2 * x;
+}
+
+/********************************* Register image ****************************/
+/* Copy the content of a register image into another. The size n is
+   the size of the register image. Due to struct assignment generation of
+   memcpy in libc. */
+static void
+copy_registers (registers *dptr, registers *sptr, int n)
+{
+	unsigned char *dreg;
+	unsigned char *sreg;
+	
+	for (dreg = (unsigned char*)dptr, sreg = (unsigned char*)sptr; n > 0; n--)
+		*dreg++ = *sreg++;
+}
+
+#ifdef PROCESS_SUPPORT
+/* Copy the stored registers from the stack. Put the register contents
+   of thread thread_id in the struct reg. */
+static void
+copy_registers_from_stack (int thread_id, registers *regptr)
+{
+	int j;
+	stack_registers *s = (stack_registers *)stack_list[thread_id];
+	unsigned int *d = (unsigned int *)regptr;
+	
+	for (j = 13; j >= 0; j--)
+		*d++ = s->r[j];
+	regptr->sp = (unsigned int)stack_list[thread_id];
+	regptr->pc = s->pc;
+	regptr->dccr = s->dccr;
+	regptr->srp = s->srp;
+}
+
+/* Copy the registers to the stack. Put the register contents of thread
+   thread_id from struct reg to the stack. */
+static void
+copy_registers_to_stack (int thread_id, registers *regptr)
+{
+	int i;
+	stack_registers *d = (stack_registers *)stack_list[thread_id];
+	unsigned int *s = (unsigned int *)regptr;
+	
+	for (i = 0; i < 14; i++) {
+		d->r[i] = *s++;
+	}
+	d->pc = regptr->pc;
+	d->dccr = regptr->dccr;
+	d->srp = regptr->srp;
+}
+#endif
+
+/* Write a value to a specified register in the register image of the current
+   thread. Returns status code SUCCESS, E02 or E05. */
+static int
+write_register (int regno, char *val)
+{
+	int status = SUCCESS;
+	registers *current_reg = &reg;
+
+        if (regno >= R0 && regno <= PC) {
+		/* 32-bit register with simple offset. */
+		hex2mem ((unsigned char *)current_reg + regno * sizeof(unsigned int),
+			 val, sizeof(unsigned int));
+	}
+        else if (regno == P0 || regno == VR || regno == P4 || regno == P8) {
+		/* Do not support read-only registers. */
+		status = E02;
+	}
+        else if (regno == CCR) {
+		/* 16 bit register with complex offset. (P4 is read-only, P6 is not implemented, 
+                   and P7 (MOF) is 32 bits in ETRAX 100LX. */
+		hex2mem ((unsigned char *)&(current_reg->ccr) + (regno-CCR) * sizeof(unsigned short),
+			 val, sizeof(unsigned short));
+	}
+	else if (regno >= MOF && regno <= USP) {
+		/* 32 bit register with complex offset.  (P8 has been taken care of.) */
+		hex2mem ((unsigned char *)&(current_reg->ibr) + (regno-IBR) * sizeof(unsigned int),
+			 val, sizeof(unsigned int));
+	} 
+        else {
+		/* Do not support nonexisting or unimplemented registers (P2, P3, and P6). */
+		status = E05;
+	}
+	return status;
+}
+
+#ifdef PROCESS_SUPPORT
+/* Write a value to a specified register in the stack of a thread other
+   than the current thread. Returns status code SUCCESS or E07. */
+static int
+write_stack_register (int thread_id, int regno, char *valptr)
+{
+	int status = SUCCESS;
+	stack_registers *d = (stack_registers *)stack_list[thread_id];
+	unsigned int val;
+	
+	hex2mem ((unsigned char *)&val, valptr, sizeof(unsigned int));
+	if (regno >= R0 && regno < SP) {
+		d->r[regno] = val;
+	}
+	else if (regno == SP) {
+		stack_list[thread_id] = val;
+	}
+	else if (regno == PC) {
+		d->pc = val;
+	}
+	else if (regno == SRP) {
+		d->srp = val;
+	}
+	else if (regno == DCCR) {
+		d->dccr = val;
+	}
+	else {
+		/* Do not support registers in the current thread. */
+		status = E07;
+	}
+	return status;
+}
+#endif
+
+/* Read a value from a specified register in the register image. Returns the
+   value in the register or -1 for non-implemented registers.
+   Should check consistency_status after a call which may be E05 after changes
+   in the implementation. */
+static int
+read_register (char regno, unsigned int *valptr)
+{
+	registers *current_reg = &reg;
+
+	if (regno >= R0 && regno <= PC) {
+		/* 32-bit register with simple offset. */
+		*valptr = *(unsigned int *)((char *)current_reg + regno * sizeof(unsigned int));
+                return SUCCESS;
+	}
+	else if (regno == P0 || regno == VR) {
+		/* 8 bit register with complex offset. */
+		*valptr = (unsigned int)(*(unsigned char *)
+                                         ((char *)&(current_reg->p0) + (regno-P0) * sizeof(char)));
+                return SUCCESS;
+	}
+	else if (regno == P4 || regno == CCR) {
+		/* 16 bit register with complex offset. */
+		*valptr = (unsigned int)(*(unsigned short *)
+                                         ((char *)&(current_reg->p4) + (regno-P4) * sizeof(unsigned short)));
+                return SUCCESS;
+	}
+	else if (regno >= MOF && regno <= USP) {
+		/* 32 bit register with complex offset. */
+		*valptr = *(unsigned int *)((char *)&(current_reg->p8)
+                                            + (regno-P8) * sizeof(unsigned int));
+                return SUCCESS;
+	}
+	else {
+		/* Do not support nonexisting or unimplemented registers (P2, P3, and P6). */
+		consistency_status = E05;
+		return E05;
+	}
+}
+
+/********************************** Packet I/O ******************************/
+/* Returns the character equivalent of a nibble, bit 7, 6, 5, and 4 of a byte,
+   represented by int x. */
+static inline char
+highhex(int x)
+{
+	return hexchars[(x >> 4) & 0xf];
+}
+
+/* Returns the character equivalent of a nibble, bit 3, 2, 1, and 0 of a byte,
+   represented by int x. */
+static inline char
+lowhex(int x)
+{
+	return hexchars[x & 0xf];
+}
+
+/* Returns the integer equivalent of a hexadecimal character. */
+static int
+hex (char ch)
+{
+	if ((ch >= 'a') && (ch <= 'f'))
+		return (ch - 'a' + 10);
+	if ((ch >= '0') && (ch <= '9'))
+		return (ch - '0');
+	if ((ch >= 'A') && (ch <= 'F'))
+		return (ch - 'A' + 10);
+	return (-1);
+}
+
+/* Convert the memory, pointed to by mem into hexadecimal representation.
+   Put the result in buf, and return a pointer to the last character
+   in buf (null). */
+
+static int do_printk = 0;
+
+static char *
+mem2hex(char *buf, unsigned char *mem, int count)
+{
+	int i;
+	int ch;
+        
+        if (mem == NULL) {
+                /* Bogus read from m0. FIXME: What constitutes a valid address? */
+                for (i = 0; i < count; i++) {
+                        *buf++ = '0';
+                        *buf++ = '0';
+                }
+        } else {
+                /* Valid mem address. */
+                for (i = 0; i < count; i++) {
+                        ch = *mem++;
+                        *buf++ = highhex (ch);
+                        *buf++ = lowhex (ch);
+                }
+        }
+        
+        /* Terminate properly. */
+	*buf = '\0';
+	return (buf);
+}
+
+/* Convert the array, in hexadecimal representation, pointed to by buf into
+   binary representation. Put the result in mem, and return a pointer to
+   the character after the last byte written. */
+static unsigned char*
+hex2mem (unsigned char *mem, char *buf, int count)
+{
+	int i;
+	unsigned char ch;
+	for (i = 0; i < count; i++) {
+		ch = hex (*buf++) << 4;
+		ch = ch + hex (*buf++);
+		*mem++ = ch;
+	}
+	return (mem);
+}
+
+/* Put the content of the array, in binary representation, pointed to by buf
+   into memory pointed to by mem, and return a pointer to the character after
+   the last byte written.
+   Gdb will escape $, #, and the escape char (0x7d). */
+static unsigned char*
+bin2mem (unsigned char *mem, unsigned char *buf, int count)
+{
+	int i;
+	unsigned char *next;
+	for (i = 0; i < count; i++) {
+		/* Check for any escaped characters. Be paranoid and
+		   only unescape chars that should be escaped. */
+		if (*buf == 0x7d) {
+			next = buf + 1;
+			if (*next == 0x3 || *next == 0x4 || *next == 0x5D) /* #, $, ESC */
+				{
+					buf++;
+					*buf += 0x20;
+				}
+		}
+		*mem++ = *buf++;
+	}
+	return (mem);
+}
+
+/* Await the sequence $<data>#<checksum> and store <data> in the array buffer
+   returned. */
+static void
+getpacket (char *buffer)
+{
+	unsigned char checksum;
+	unsigned char xmitcsum;
+	int i;
+	int count;
+	char ch;
+	do {
+		while ((ch = getDebugChar ()) != '$')
+			/* Wait for the start character $ and ignore all other characters */;
+		checksum = 0;
+		xmitcsum = -1;
+		count = 0;
+		/* Read until a # or the end of the buffer is reached */
+		while (count < BUFMAX) {
+			ch = getDebugChar ();
+			if (ch == '#')
+				break;
+			checksum = checksum + ch;
+			buffer[count] = ch;
+			count = count + 1;
+		}
+		buffer[count] = '\0';
+		
+		if (ch == '#') {
+			xmitcsum = hex (getDebugChar ()) << 4;
+			xmitcsum += hex (getDebugChar ());
+			if (checksum != xmitcsum) {
+				/* Wrong checksum */
+				putDebugChar ('-');
+			}
+			else {
+				/* Correct checksum */
+				putDebugChar ('+');
+				/* If sequence characters are received, reply with them */
+				if (buffer[2] == ':') {
+					putDebugChar (buffer[0]);
+					putDebugChar (buffer[1]);
+					/* Remove the sequence characters from the buffer */
+					count = gdb_cris_strlen (buffer);
+					for (i = 3; i <= count; i++)
+						buffer[i - 3] = buffer[i];
+				}
+			}
+		}
+	} while (checksum != xmitcsum);
+}
+
+/* Send $<data>#<checksum> from the <data> in the array buffer. */
+
+static void
+putpacket(char *buffer)
+{
+	int checksum;
+	int runlen;
+	int encode;
+	
+	do {
+		char *src = buffer;
+		putDebugChar ('$');
+		checksum = 0;
+		while (*src) {
+			/* Do run length encoding */
+			putDebugChar (*src);
+			checksum += *src;
+			runlen = 0;
+			while (runlen < RUNLENMAX && *src == src[runlen]) {
+				runlen++;
+			}
+			if (runlen > 3) {
+				/* Got a useful amount */
+				putDebugChar ('*');
+				checksum += '*';
+				encode = runlen + ' ' - 4;
+				putDebugChar (encode);
+				checksum += encode;
+				src += runlen;
+			}
+			else {
+				src++;
+			}
+		}
+		putDebugChar ('#');
+		putDebugChar (highhex (checksum));
+		putDebugChar (lowhex (checksum));
+	} while(kgdb_started && (getDebugChar() != '+'));
+}
+
+/* The string str is prepended with the GDB printout token and sent. Required
+   in traditional implementations. */
+void
+putDebugString (const unsigned char *str, int length)
+{
+        remcomOutBuffer[0] = 'O';
+        mem2hex(&remcomOutBuffer[1], (unsigned char *)str, length);
+        putpacket(remcomOutBuffer);
+}
+
+/********************************** Handle exceptions ************************/
+/* Build and send a response packet in order to inform the host the
+   stub is stopped. TAAn...:r...;n...:r...;n...:r...;
+                    AA = signal number
+                    n... = register number (hex)
+                    r... = register contents
+                    n... = `thread'
+                    r... = thread process ID.  This is a hex integer.
+                    n... = other string not starting with valid hex digit.
+                    gdb should ignore this n,r pair and go on to the next.
+                    This way we can extend the protocol. */
+static void
+stub_is_stopped(int sigval)
+{
+	char *ptr = remcomOutBuffer;
+	int regno;
+
+	unsigned int reg_cont;
+	int status;
+        
+	/* Send trap type (converted to signal) */
+
+	*ptr++ = 'T';	
+	*ptr++ = highhex (sigval);
+	*ptr++ = lowhex (sigval);
+
+	/* Send register contents. We probably only need to send the
+	 * PC, frame pointer and stack pointer here. Other registers will be
+	 * explicitely asked for. But for now, send all. 
+	 */
+	
+	for (regno = R0; regno <= USP; regno++) {
+		/* Store n...:r...; for the registers in the buffer. */
+
+                status = read_register (regno, &reg_cont);
+                
+		if (status == SUCCESS) {
+                        
+                        *ptr++ = highhex (regno);
+                        *ptr++ = lowhex (regno);
+                        *ptr++ = ':';
+
+                        ptr = mem2hex(ptr, (unsigned char *)&reg_cont,
+                                      register_size[regno]);
+                        *ptr++ = ';';
+                }
+                
+	}
+
+#ifdef PROCESS_SUPPORT
+	/* Store the registers of the executing thread. Assume that both step,
+	   continue, and register content requests are with respect to this
+	   thread. The executing task is from the operating system scheduler. */
+
+	current_thread_c = executing_task;
+	current_thread_g = executing_task;
+
+	/* A struct assignment translates into a libc memcpy call. Avoid
+	   all libc functions in order to prevent recursive break points. */
+	copy_registers (&reg_g, &reg, sizeof(registers));
+
+	/* Store thread:r...; with the executing task TID. */
+	gdb_cris_strcpy (&remcomOutBuffer[pos], "thread:");
+	pos += gdb_cris_strlen ("thread:");
+	remcomOutBuffer[pos++] = highhex (executing_task);
+	remcomOutBuffer[pos++] = lowhex (executing_task);
+	gdb_cris_strcpy (&remcomOutBuffer[pos], ";");
+#endif
+
+	/* null-terminate and send it off */
+
+	*ptr = 0;
+
+	putpacket (remcomOutBuffer);
+}
+
+/* All expected commands are sent from remote.c. Send a response according
+   to the description in remote.c. */
+static void
+handle_exception (int sigval)
+{
+	/* Avoid warning of not used. */
+
+	USEDFUN(handle_exception);
+	USEDVAR(internal_stack[0]);
+
+	/* Send response. */
+
+	stub_is_stopped (sigval);
+
+	for (;;) {
+		remcomOutBuffer[0] = '\0';
+		getpacket (remcomInBuffer);
+		switch (remcomInBuffer[0]) {
+			case 'g':
+				/* Read registers: g
+				   Success: Each byte of register data is described by two hex digits.
+				   Registers are in the internal order for GDB, and the bytes
+				   in a register  are in the same order the machine uses.
+				   Failure: void. */
+				
+				{
+#ifdef PROCESS_SUPPORT
+					/* Use the special register content in the executing thread. */
+					copy_registers (&reg_g, &reg, sizeof(registers));
+					/* Replace the content available on the stack. */
+					if (current_thread_g != executing_task) {
+						copy_registers_from_stack (current_thread_g, &reg_g);
+					}
+					mem2hex ((unsigned char *)remcomOutBuffer, (unsigned char *)&reg_g, sizeof(registers));
+#else
+					mem2hex(remcomOutBuffer, (char *)&reg, sizeof(registers));
+#endif
+				}
+				break;
+				
+			case 'G':
+				/* Write registers. GXX..XX
+				   Each byte of register data  is described by two hex digits.
+				   Success: OK
+				   Failure: void. */
+#ifdef PROCESS_SUPPORT
+				hex2mem ((unsigned char *)&reg_g, &remcomInBuffer[1], sizeof(registers));
+				if (current_thread_g == executing_task) {
+					copy_registers (&reg, &reg_g, sizeof(registers));
+				}
+				else {
+					copy_registers_to_stack(current_thread_g, &reg_g);
+				}
+#else
+				hex2mem((char *)&reg, &remcomInBuffer[1], sizeof(registers));
+#endif
+				gdb_cris_strcpy (remcomOutBuffer, "OK");
+				break;
+				
+			case 'P':
+				/* Write register. Pn...=r...
+				   Write register n..., hex value without 0x, with value r...,
+				   which contains a hex value without 0x and two hex digits
+				   for each byte in the register (target byte order). P1f=11223344 means
+				   set register 31 to 44332211.
+				   Success: OK
+				   Failure: E02, E05 */
+				{
+					char *suffix;
+					int regno = gdb_cris_strtol (&remcomInBuffer[1], &suffix, 16);
+					int status;
+#ifdef PROCESS_SUPPORT
+					if (current_thread_g != executing_task)
+						status = write_stack_register (current_thread_g, regno, suffix+1);
+					else
+#endif
+						status = write_register (regno, suffix+1);
+
+					switch (status) {
+						case E02:
+							/* Do not support read-only registers. */
+							gdb_cris_strcpy (remcomOutBuffer, error_message[E02]);
+							break;
+						case E05:
+							/* Do not support non-existing registers. */
+							gdb_cris_strcpy (remcomOutBuffer, error_message[E05]);
+							break;
+						case E07:
+							/* Do not support non-existing registers on the stack. */
+							gdb_cris_strcpy (remcomOutBuffer, error_message[E07]);
+							break;
+						default:
+							/* Valid register number. */
+							gdb_cris_strcpy (remcomOutBuffer, "OK");
+							break;
+					}
+				}
+				break;
+				
+			case 'm':
+				/* Read from memory. mAA..AA,LLLL
+				   AA..AA is the address and LLLL is the length.
+				   Success: XX..XX is the memory content.  Can be fewer bytes than
+				   requested if only part of the data may be read. m6000120a,6c means
+				   retrieve 108 byte from base address 6000120a.
+				   Failure: void. */
+				{
+                                        char *suffix;
+					unsigned char *addr = (unsigned char *)gdb_cris_strtol(&remcomInBuffer[1],
+                                                                                               &suffix, 16);                                        int length = gdb_cris_strtol(suffix+1, 0, 16);
+                                        
+                                        mem2hex(remcomOutBuffer, addr, length);
+                                }
+				break;
+				
+			case 'X':
+				/* Write to memory. XAA..AA,LLLL:XX..XX
+				   AA..AA is the start address,  LLLL is the number of bytes, and
+				   XX..XX is the binary data.
+				   Success: OK
+				   Failure: void. */
+			case 'M':
+				/* Write to memory. MAA..AA,LLLL:XX..XX
+				   AA..AA is the start address,  LLLL is the number of bytes, and
+				   XX..XX is the hexadecimal data.
+				   Success: OK
+				   Failure: void. */
+				{
+					char *lenptr;
+					char *dataptr;
+					unsigned char *addr = (unsigned char *)gdb_cris_strtol(&remcomInBuffer[1],
+										      &lenptr, 16);
+					int length = gdb_cris_strtol(lenptr+1, &dataptr, 16);
+					if (*lenptr == ',' && *dataptr == ':') {
+						if (remcomInBuffer[0] == 'M') {
+							hex2mem(addr, dataptr + 1, length);
+						}
+						else /* X */ {
+							bin2mem(addr, dataptr + 1, length);
+						}
+						gdb_cris_strcpy (remcomOutBuffer, "OK");
+					}
+					else {
+						gdb_cris_strcpy (remcomOutBuffer, error_message[E06]);
+					}
+				}
+				break;
+				
+			case 'c':
+				/* Continue execution. cAA..AA
+				   AA..AA is the address where execution is resumed. If AA..AA is
+				   omitted, resume at the present address.
+				   Success: return to the executing thread.
+				   Failure: will never know. */
+				if (remcomInBuffer[1] != '\0') {
+					reg.pc = gdb_cris_strtol (&remcomInBuffer[1], 0, 16);
+				}
+				enableDebugIRQ();
+				return;
+				
+			case 's':
+				/* Step. sAA..AA
+				   AA..AA is the address where execution is resumed. If AA..AA is
+				   omitted, resume at the present address. Success: return to the
+				   executing thread. Failure: will never know.
+				   
+				   Should never be invoked. The single-step is implemented on
+				   the host side. If ever invoked, it is an internal error E04. */
+				gdb_cris_strcpy (remcomOutBuffer, error_message[E04]);
+				putpacket (remcomOutBuffer);
+				return;
+				
+			case '?':
+				/* The last signal which caused a stop. ?
+				   Success: SAA, where AA is the signal number.
+				   Failure: void. */
+				remcomOutBuffer[0] = 'S';
+				remcomOutBuffer[1] = highhex (sigval);
+				remcomOutBuffer[2] = lowhex (sigval);
+				remcomOutBuffer[3] = 0;
+				break;
+				
+			case 'D':
+				/* Detach from host. D
+				   Success: OK, and return to the executing thread.
+				   Failure: will never know */
+				putpacket ("OK");
+				return;
+				
+			case 'k':
+			case 'r':
+				/* kill request or reset request.
+				   Success: restart of target.
+				   Failure: will never know. */
+				kill_restart ();
+				break;
+				
+			case 'C':
+			case 'S':
+			case '!':
+			case 'R':
+			case 'd':
+				/* Continue with signal sig. Csig;AA..AA
+				   Step with signal sig. Ssig;AA..AA
+				   Use the extended remote protocol. !
+				   Restart the target system. R0
+				   Toggle debug flag. d
+				   Search backwards. tAA:PP,MM
+				   Not supported: E04 */
+				gdb_cris_strcpy (remcomOutBuffer, error_message[E04]);
+				break;
+#ifdef PROCESS_SUPPORT
+
+			case 'T':
+				/* Thread alive. TXX
+				   Is thread XX alive?
+				   Success: OK, thread XX is alive.
+				   Failure: E03, thread XX is dead. */
+				{
+					int thread_id = (int)gdb_cris_strtol (&remcomInBuffer[1], 0, 16);
+					/* Cannot tell whether it is alive or not. */
+					if (thread_id >= 0 && thread_id < number_of_tasks)
+						gdb_cris_strcpy (remcomOutBuffer, "OK");
+				}
+				break;
+								
+			case 'H':
+				/* Set thread for subsequent operations: Hct
+				   c = 'c' for thread used in step and continue;
+				   t can be -1 for all threads.
+				   c = 'g' for thread used in other  operations.
+				   t = 0 means pick any thread.
+				   Success: OK
+				   Failure: E01 */
+				{
+					int thread_id = gdb_cris_strtol (&remcomInBuffer[2], 0, 16);
+					if (remcomInBuffer[1] == 'c') {
+						/* c = 'c' for thread used in step and continue */
+						/* Do not change current_thread_c here. It would create a mess in
+						   the scheduler. */
+						gdb_cris_strcpy (remcomOutBuffer, "OK");
+					}
+					else if (remcomInBuffer[1] == 'g') {
+						/* c = 'g' for thread used in other  operations.
+						   t = 0 means pick any thread. Impossible since the scheduler does
+						   not allow that. */
+						if (thread_id >= 0 && thread_id < number_of_tasks) {
+							current_thread_g = thread_id;
+							gdb_cris_strcpy (remcomOutBuffer, "OK");
+						}
+						else {
+							/* Not expected - send an error message. */
+							gdb_cris_strcpy (remcomOutBuffer, error_message[E01]);
+						}
+					}
+					else {
+						/* Not expected - send an error message. */
+						gdb_cris_strcpy (remcomOutBuffer, error_message[E01]);
+					}
+				}
+				break;
+				
+			case 'q':
+			case 'Q':
+				/* Query of general interest. qXXXX
+				   Set general value XXXX. QXXXX=yyyy */
+				{
+					int pos;
+					int nextpos;
+					int thread_id;
+					
+					switch (remcomInBuffer[1]) {
+						case 'C':
+							/* Identify the remote current thread. */
+							gdb_cris_strcpy (&remcomOutBuffer[0], "QC");
+							remcomOutBuffer[2] = highhex (current_thread_c);
+							remcomOutBuffer[3] = lowhex (current_thread_c);
+							remcomOutBuffer[4] = '\0';
+							break;
+						case 'L':
+							gdb_cris_strcpy (&remcomOutBuffer[0], "QM");
+							/* Reply with number of threads. */
+							if (os_is_started()) {
+								remcomOutBuffer[2] = highhex (number_of_tasks);
+								remcomOutBuffer[3] = lowhex (number_of_tasks);
+							}
+							else {
+								remcomOutBuffer[2] = highhex (0);
+								remcomOutBuffer[3] = lowhex (1);
+							}
+							/* Done with the reply. */
+							remcomOutBuffer[4] = lowhex (1);
+							pos = 5;
+							/* Expects the argument thread id. */
+							for (; pos < (5 + HEXCHARS_IN_THREAD_ID); pos++)
+								remcomOutBuffer[pos] = remcomInBuffer[pos];
+							/* Reply with the thread identifiers. */
+							if (os_is_started()) {
+								/* Store the thread identifiers of all tasks. */
+								for (thread_id = 0; thread_id < number_of_tasks; thread_id++) {
+									nextpos = pos + HEXCHARS_IN_THREAD_ID - 1;
+									for (; pos < nextpos; pos ++)
+										remcomOutBuffer[pos] = lowhex (0);
+									remcomOutBuffer[pos++] = lowhex (thread_id);
+								}
+							}
+							else {
+								/* Store the thread identifier of the boot task. */
+								nextpos = pos + HEXCHARS_IN_THREAD_ID - 1;
+								for (; pos < nextpos; pos ++)
+									remcomOutBuffer[pos] = lowhex (0);
+								remcomOutBuffer[pos++] = lowhex (current_thread_c);
+							}
+							remcomOutBuffer[pos] = '\0';
+							break;
+						default:
+							/* Not supported: "" */
+							/* Request information about section offsets: qOffsets. */
+							remcomOutBuffer[0] = 0;
+							break;
+					}
+				}
+				break;
+#endif /* PROCESS_SUPPORT */
+				
+			default:
+				/* The stub should ignore other request and send an empty
+				   response ($#<checksum>). This way we can extend the protocol and GDB
+				   can tell whether the stub it is talking to uses the old or the new. */
+				remcomOutBuffer[0] = 0;
+				break;
+		}
+		putpacket(remcomOutBuffer);
+	}
+}
+
+/* The jump is to the address 0x00000002. Performs a complete re-start
+   from scratch. */
+static void
+kill_restart ()
+{
+	__asm__ volatile ("jump 2");
+}
+
+/********************************** Breakpoint *******************************/
+/* The hook for both a static (compiled) and a dynamic breakpoint set by GDB.
+   An internal stack is used by the stub. The register image of the caller is
+   stored in the structure register_image.
+   Interactive communication with the host is handled by handle_exception and
+   finally the register image is restored. */
+
+void kgdb_handle_breakpoint(void);
+
+asm ("
+  .global kgdb_handle_breakpoint
+kgdb_handle_breakpoint:
+;;
+;; Response to the break-instruction
+;;
+;; Create a register image of the caller
+;;
+  move     $dccr,[reg+0x5E] ; Save the flags in DCCR before disable interrupts
+  di                        ; Disable interrupts
+  move.d   $r0,[reg]        ; Save R0
+  move.d   $r1,[reg+0x04]   ; Save R1
+  move.d   $r2,[reg+0x08]   ; Save R2
+  move.d   $r3,[reg+0x0C]   ; Save R3
+  move.d   $r4,[reg+0x10]   ; Save R4
+  move.d   $r5,[reg+0x14]   ; Save R5
+  move.d   $r6,[reg+0x18]   ; Save R6
+  move.d   $r7,[reg+0x1C]   ; Save R7
+  move.d   $r8,[reg+0x20]   ; Save R8
+  move.d   $r9,[reg+0x24]   ; Save R9
+  move.d   $r10,[reg+0x28]  ; Save R10
+  move.d   $r11,[reg+0x2C]  ; Save R11
+  move.d   $r12,[reg+0x30]  ; Save R12
+  move.d   $r13,[reg+0x34]  ; Save R13
+  move.d   $sp,[reg+0x38]   ; Save SP (R14)
+;; Due to the old assembler-versions BRP might not be recognized
+  .word 0xE670              ; move brp,$r0
+  subq     2,$r0             ; Set to address of previous instruction.
+  move.d   $r0,[reg+0x3c]   ; Save the address in PC (R15)
+  clear.b  [reg+0x40]      ; Clear P0
+  move     $vr,[reg+0x41]   ; Save special register P1
+  clear.w  [reg+0x42]      ; Clear P4
+  move     $ccr,[reg+0x44]  ; Save special register CCR
+  move     $mof,[reg+0x46]  ; P7
+  clear.d  [reg+0x4A]      ; Clear P8
+  move     $ibr,[reg+0x4E]  ; P9,
+  move     $irp,[reg+0x52]  ; P10,
+  move     $srp,[reg+0x56]  ; P11,
+  move     $dtp0,[reg+0x5A] ; P12, register BAR, assembler might not know BAR
+                            ; P13, register DCCR already saved
+;; Due to the old assembler-versions BRP might not be recognized
+  .word 0xE670              ; move brp,r0
+;; Static (compiled) breakpoints must return to the next instruction in order
+;; to avoid infinite loops. Dynamic (gdb-invoked) must restore the instruction
+;; in order to execute it when execution is continued.
+  test.b   [is_dyn_brkp]    ; Is this a dynamic breakpoint?
+  beq      is_static         ; No, a static breakpoint
+  nop
+  subq     2,$r0              ; rerun the instruction the break replaced
+is_static:
+  moveq    1,$r1
+  move.b   $r1,[is_dyn_brkp] ; Set the state variable to dynamic breakpoint
+  move.d   $r0,[reg+0x62]    ; Save the return address in BRP
+  move     $usp,[reg+0x66]   ; USP
+;;
+;; Handle the communication
+;;
+  move.d   internal_stack+1020,$sp ; Use the internal stack which grows upward
+  moveq    5,$r10                   ; SIGTRAP
+  jsr      handle_exception       ; Interactive routine
+;;
+;; Return to the caller
+;;
+   move.d  [reg],$r0         ; Restore R0
+   move.d  [reg+0x04],$r1    ; Restore R1
+   move.d  [reg+0x08],$r2    ; Restore R2
+   move.d  [reg+0x0C],$r3    ; Restore R3
+   move.d  [reg+0x10],$r4    ; Restore R4
+   move.d  [reg+0x14],$r5    ; Restore R5
+   move.d  [reg+0x18],$r6    ; Restore R6
+   move.d  [reg+0x1C],$r7    ; Restore R7
+   move.d  [reg+0x20],$r8    ; Restore R8
+   move.d  [reg+0x24],$r9    ; Restore R9
+   move.d  [reg+0x28],$r10   ; Restore R10
+   move.d  [reg+0x2C],$r11   ; Restore R11
+   move.d  [reg+0x30],$r12   ; Restore R12
+   move.d  [reg+0x34],$r13   ; Restore R13
+;;
+;; FIXME: Which registers should be restored?
+;;
+   move.d  [reg+0x38],$sp    ; Restore SP (R14)
+   move    [reg+0x56],$srp   ; Restore the subroutine return pointer.
+   move    [reg+0x5E],$dccr  ; Restore DCCR
+   move    [reg+0x66],$usp   ; Restore USP
+   jump    [reg+0x62]       ; A jump to the content in register BRP works.
+   nop                       ;
+");
+
+/* The hook for an interrupt generated by GDB. An internal stack is used
+   by the stub. The register image of the caller is stored in the structure
+   register_image. Interactive communication with the host is handled by
+   handle_exception and finally the register image is restored. Due to the
+   old assembler which does not recognise the break instruction and the
+   breakpoint return pointer hex-code is used. */
+
+void kgdb_handle_serial(void);
+
+asm ("
+  .global kgdb_handle_serial
+kgdb_handle_serial:
+;;
+;; Response to a serial interrupt
+;;
+
+  move     $dccr,[reg+0x5E] ; Save the flags in DCCR
+  di                        ; Disable interrupts
+  move.d   $r0,[reg]        ; Save R0
+  move.d   $r1,[reg+0x04]   ; Save R1
+  move.d   $r2,[reg+0x08]   ; Save R2
+  move.d   $r3,[reg+0x0C]   ; Save R3
+  move.d   $r4,[reg+0x10]   ; Save R4
+  move.d   $r5,[reg+0x14]   ; Save R5
+  move.d   $r6,[reg+0x18]   ; Save R6
+  move.d   $r7,[reg+0x1C]   ; Save R7
+  move.d   $r8,[reg+0x20]   ; Save R8
+  move.d   $r9,[reg+0x24]   ; Save R9
+  move.d   $r10,[reg+0x28]  ; Save R10
+  move.d   $r11,[reg+0x2C]  ; Save R11
+  move.d   $r12,[reg+0x30]  ; Save R12
+  move.d   $r13,[reg+0x34]  ; Save R13
+  move.d   $sp,[reg+0x38]   ; Save SP (R14)
+  move     $irp,[reg+0x3c]  ; Save the address in PC (R15)
+  clear.b  [reg+0x40]      ; Clear P0
+  move     $vr,[reg+0x41]   ; Save special register P1,
+  clear.w  [reg+0x42]      ; Clear P4
+  move     $ccr,[reg+0x44]  ; Save special register CCR
+  move     $mof,[reg+0x46]  ; P7
+  clear.d  [reg+0x4A]      ; Clear P8
+  move     $ibr,[reg+0x4E]  ; P9,
+  move     $irp,[reg+0x52]  ; P10,
+  move     $srp,[reg+0x56]  ; P11,
+  move     $dtp0,[reg+0x5A] ; P12, register BAR, assembler might not know BAR
+                            ; P13, register DCCR already saved
+;; Due to the old assembler-versions BRP might not be recognized
+  .word 0xE670              ; move brp,r0
+  move.d   $r0,[reg+0x62]   ; Save the return address in BRP
+  move     $usp,[reg+0x66]  ; USP
+
+;; get the serial character (from debugport.c) and check if it is a ctrl-c
+
+  jsr getDebugChar
+  cmp.b 3, $r10
+  bne goback
+  nop
+
+;;
+;; Handle the communication
+;;
+  move.d   internal_stack+1020,$sp ; Use the internal stack
+  moveq    2,$r10                   ; SIGINT
+  jsr      handle_exception       ; Interactive routine
+
+goback:
+;;
+;; Return to the caller
+;;
+   move.d  [reg],$r0         ; Restore R0
+   move.d  [reg+0x04],$r1    ; Restore R1
+   move.d  [reg+0x08],$r2    ; Restore R2
+   move.d  [reg+0x0C],$r3    ; Restore R3
+   move.d  [reg+0x10],$r4    ; Restore R4
+   move.d  [reg+0x14],$r5    ; Restore R5
+   move.d  [reg+0x18],$r6    ; Restore R6
+   move.d  [reg+0x1C],$r7    ; Restore R7
+   move.d  [reg+0x20],$r8    ; Restore R8
+   move.d  [reg+0x24],$r9    ; Restore R9
+   move.d  [reg+0x28],$r10   ; Restore R10
+   move.d  [reg+0x2C],$r11   ; Restore R11
+   move.d  [reg+0x30],$r12   ; Restore R12
+   move.d  [reg+0x34],$r13   ; Restore R13
+;;
+;; FIXME: Which registers should be restored?
+;;
+   move.d  [reg+0x38],$sp    ; Restore SP (R14)
+   move    [reg+0x56],$srp   ; Restore the subroutine return pointer.
+   move    [reg+0x5E],$dccr  ; Restore DCCR
+   move    [reg+0x66],$usp   ; Restore USP
+   reti                      ; Return from the interrupt routine
+   nop
+");
+
+/* Use this static breakpoint in the start-up only. */
+
+void
+breakpoint(void)
+{
+	kgdb_started = 1;
+	is_dyn_brkp = 0;     /* This is a static, not a dynamic breakpoint. */
+	__asm__ volatile ("break 8"); /* Jump to handle_breakpoint. */
+}
+
+/* initialize kgdb. doesn't break into the debugger, but sets up irq and ports */
+
+void
+kgdb_init(void)
+{
+	/* could initialize debug port as well but it's done in head.S already... */
+
+        /* breakpoint handler is now set in irq.c */
+	set_int_vector(8, kgdb_handle_serial);
+	
+	enableDebugIRQ();
+}
+
+/****************************** End of file **********************************/
diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c
new file mode 100644
index 0000000..87ff377
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/process.c
@@ -0,0 +1,270 @@
+/* $Id: process.c,v 1.9 2004/10/19 13:07:37 starvik Exp $
+ * 
+ *  linux/arch/cris/kernel/process.c
+ *
+ *  Copyright (C) 1995  Linus Torvalds
+ *  Copyright (C) 2000-2002  Axis Communications AB
+ *
+ *  Authors:   Bjorn Wesen (bjornw@axis.com)
+ *             Mikael Starvik (starvik@axis.com)
+ *
+ * This file handles the architecture-dependent parts of process handling..
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <asm/arch/svinto.h>
+#include <linux/init.h>
+
+#ifdef CONFIG_ETRAX_GPIO
+void etrax_gpio_wake_up_check(void); /* drivers/gpio.c */
+#endif
+
+/*
+ * We use this if we don't have any better
+ * idle routine..
+ */
+void default_idle(void)
+{
+#ifdef CONFIG_ETRAX_GPIO
+  etrax_gpio_wake_up_check();
+#endif
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+
+void exit_thread(void)
+{
+	/* Nothing needs to be done.  */
+}
+
+/* if the watchdog is enabled, we can simply disable interrupts and go
+ * into an eternal loop, and the watchdog will reset the CPU after 0.1s
+ * if on the other hand the watchdog wasn't enabled, we just enable it and wait
+ */
+
+void hard_reset_now (void)
+{
+	/*
+	 * Don't declare this variable elsewhere.  We don't want any other
+	 * code to know about it than the watchdog handler in entry.S and
+	 * this code, implementing hard reset through the watchdog.
+	 */
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+	extern int cause_of_death;
+#endif
+
+	printk("*** HARD RESET ***\n");
+	local_irq_disable();
+
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+	cause_of_death = 0xbedead;
+#else
+	/* Since we dont plan to keep on reseting the watchdog,
+	   the key can be arbitrary hence three */
+	*R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, 3) |
+		IO_STATE(R_WATCHDOG, enable, start);
+#endif
+
+	while(1) /* waiting for RETRIBUTION! */ ;
+}
+
+/*
+ * Return saved PC of a blocked thread.
+ */
+unsigned long thread_saved_pc(struct task_struct *t)
+{
+	return (unsigned long)user_regs(t->thread_info)->irp;
+}
+
+static void kernel_thread_helper(void* dummy, int (*fn)(void *), void * arg)
+{
+  fn(arg);
+  do_exit(-1); /* Should never be called, return bad exit value */
+}
+
+/*
+ * Create a kernel thread
+ */
+int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+	struct pt_regs regs;
+
+	memset(&regs, 0, sizeof(regs));
+
+        /* Don't use r10 since that is set to 0 in copy_thread */
+	regs.r11 = (unsigned long)fn;
+	regs.r12 = (unsigned long)arg;
+	regs.irp = (unsigned long)kernel_thread_helper;
+
+	/* Ok, create the new process.. */
+        return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
+}
+
+/* setup the child's kernel stack with a pt_regs and switch_stack on it.
+ * it will be un-nested during _resume and _ret_from_sys_call when the
+ * new thread is scheduled.
+ *
+ * also setup the thread switching structure which is used to keep
+ * thread-specific data during _resumes.
+ *
+ */
+asmlinkage void ret_from_fork(void);
+
+int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+		unsigned long unused,
+		struct task_struct *p, struct pt_regs *regs)
+{
+	struct pt_regs * childregs;
+	struct switch_stack *swstack;
+	
+	/* put the pt_regs structure at the end of the new kernel stack page and fix it up
+	 * remember that the task_struct doubles as the kernel stack for the task
+	 */
+
+	childregs = user_regs(p->thread_info);        
+        
+	*childregs = *regs;  /* struct copy of pt_regs */
+        
+        p->set_child_tid = p->clear_child_tid = NULL;
+
+        childregs->r10 = 0;  /* child returns 0 after a fork/clone */
+	
+	/* put the switch stack right below the pt_regs */
+
+	swstack = ((struct switch_stack *)childregs) - 1;
+
+	swstack->r9 = 0; /* parameter to ret_from_sys_call, 0 == dont restart the syscall */
+
+	/* we want to return into ret_from_sys_call after the _resume */
+
+	swstack->return_ip = (unsigned long) ret_from_fork; /* Will call ret_from_sys_call */
+	
+	/* fix the user-mode stackpointer */
+
+	p->thread.usp = usp;	
+
+	/* and the kernel-mode one */
+
+	p->thread.ksp = (unsigned long) swstack;
+
+#ifdef DEBUG
+	printk("copy_thread: new regs at 0x%p, as shown below:\n", childregs);
+	show_registers(childregs);
+#endif
+
+	return 0;
+}
+
+/* 
+ * Be aware of the "magic" 7th argument in the four system-calls below.
+ * They need the latest stackframe, which is put as the 7th argument by
+ * entry.S. The previous arguments are dummies or actually used, but need
+ * to be defined to reach the 7th argument.
+ *
+ * N.B.: Another method to get the stackframe is to use current_regs(). But
+ * it returns the latest stack-frame stacked when going from _user mode_ and
+ * some of these (at least sys_clone) are called from kernel-mode sometimes
+ * (for example during kernel_thread, above) and thus cannot use it. Thus,
+ * to be sure not to get any surprises, we use the method for the other calls
+ * as well.
+ */
+
+asmlinkage int sys_fork(long r10, long r11, long r12, long r13, long mof, long srp,
+			struct pt_regs *regs)
+{
+	return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL);
+}
+
+/* if newusp is 0, we just grab the old usp */
+/* FIXME: Is parent_tid/child_tid really third/fourth argument? Update lib? */
+asmlinkage int sys_clone(unsigned long newusp, unsigned long flags,
+			 int* parent_tid, int* child_tid, long mof, long srp,
+			 struct pt_regs *regs)
+{
+	if (!newusp)
+		newusp = rdusp();
+	return do_fork(flags, newusp, regs, 0, parent_tid, child_tid);
+}
+
+/* vfork is a system call in i386 because of register-pressure - maybe
+ * we can remove it and handle it in libc but we put it here until then.
+ */
+
+asmlinkage int sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp,
+			 struct pt_regs *regs)
+{
+        return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL);
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+asmlinkage int sys_execve(const char *fname, char **argv, char **envp,
+			  long r13, long mof, long srp, 
+			  struct pt_regs *regs)
+{
+	int error;
+	char *filename;
+
+	filename = getname(fname);
+	error = PTR_ERR(filename);
+
+	if (IS_ERR(filename))
+	        goto out;
+	error = do_execve(filename, argv, envp, regs);
+	putname(filename);
+ out:
+	return error;
+}
+
+unsigned long get_wchan(struct task_struct *p)
+{
+#if 0
+	/* YURGH. TODO. */
+
+        unsigned long ebp, esp, eip;
+        unsigned long stack_page;
+        int count = 0;
+        if (!p || p == current || p->state == TASK_RUNNING)
+                return 0;
+        stack_page = (unsigned long)p;
+        esp = p->thread.esp;
+        if (!stack_page || esp < stack_page || esp > 8188+stack_page)
+                return 0;
+        /* include/asm-i386/system.h:switch_to() pushes ebp last. */
+        ebp = *(unsigned long *) esp;
+        do {
+                if (ebp < stack_page || ebp > 8184+stack_page)
+                        return 0;
+                eip = *(unsigned long *) (ebp+4);
+		if (!in_sched_functions(eip))
+			return eip;
+                ebp = *(unsigned long *) ebp;
+        } while (count++ < 16);
+#endif
+        return 0;
+}
+#undef last_sched
+#undef first_sched
+
+void show_regs(struct pt_regs * regs)
+{
+	unsigned long usp = rdusp();
+	printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n",
+	       regs->irp, regs->srp, regs->dccr, usp, regs->mof );
+	printk(" r0: %08lx  r1: %08lx   r2: %08lx  r3: %08lx\n",
+	       regs->r0, regs->r1, regs->r2, regs->r3);
+	printk(" r4: %08lx  r5: %08lx   r6: %08lx  r7: %08lx\n",
+	       regs->r4, regs->r5, regs->r6, regs->r7);
+	printk(" r8: %08lx  r9: %08lx  r10: %08lx r11: %08lx\n",
+	       regs->r8, regs->r9, regs->r10, regs->r11);
+	printk("r12: %08lx r13: %08lx oR10: %08lx\n",
+	       regs->r12, regs->r13, regs->orig_r10);
+}
+
diff --git a/arch/cris/arch-v10/kernel/ptrace.c b/arch/cris/arch-v10/kernel/ptrace.c
new file mode 100644
index 0000000..da15db8
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/ptrace.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2000-2003, Axis Communications AB.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+
+#include <asm/uaccess.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+
+/* 
+ * Determines which bits in DCCR the user has access to.
+ * 1 = access, 0 = no access.
+ */
+#define DCCR_MASK 0x0000001f     /* XNZVC */
+
+/*
+ * Get contents of register REGNO in task TASK.
+ */
+inline long get_reg(struct task_struct *task, unsigned int regno)
+{
+	/* USP is a special case, it's not in the pt_regs struct but
+	 * in the tasks thread struct
+	 */
+
+	if (regno == PT_USP)
+		return task->thread.usp;
+	else if (regno < PT_MAX)
+		return ((unsigned long *)user_regs(task->thread_info))[regno];
+	else
+		return 0;
+}
+
+/*
+ * Write contents of register REGNO in task TASK.
+ */
+inline int put_reg(struct task_struct *task, unsigned int regno,
+			  unsigned long data)
+{
+	if (regno == PT_USP)
+		task->thread.usp = data;
+	else if (regno < PT_MAX)
+		((unsigned long *)user_regs(task->thread_info))[regno] = data;
+	else
+		return -1;
+	return 0;
+}
+
+/*
+ * Called by kernel/ptrace.c when detaching.
+ *
+ * Make sure the single step bit is not set.
+ */
+void 
+ptrace_disable(struct task_struct *child)
+{
+       /* Todo - pending singlesteps? */
+}
+
+/* 
+ * Note that this implementation of ptrace behaves differently from vanilla
+ * ptrace.  Contrary to what the man page says, in the PTRACE_PEEKTEXT,
+ * PTRACE_PEEKDATA, and PTRACE_PEEKUSER requests the data variable is not
+ * ignored.  Instead, the data variable is expected to point at a location
+ * (in user space) where the result of the ptrace call is written (instead of
+ * being returned).
+ */
+asmlinkage int 
+sys_ptrace(long request, long pid, long addr, long data)
+{
+	struct task_struct *child;
+	int ret;
+	unsigned long __user *datap = (unsigned long __user *)data;
+
+	lock_kernel();
+	ret = -EPERM;
+	
+	if (request == PTRACE_TRACEME) {
+		if (current->ptrace & PT_PTRACED)
+			goto out;
+
+		current->ptrace |= PT_PTRACED;
+		ret = 0;
+		goto out;
+	}
+	
+	ret = -ESRCH;
+	read_lock(&tasklist_lock);
+	child = find_task_by_pid(pid);
+	
+	if (child)
+		get_task_struct(child);
+	
+	read_unlock(&tasklist_lock);
+	
+	if (!child)
+		goto out;
+	
+	ret = -EPERM;
+	
+	if (pid == 1)		/* Leave the init process alone! */
+		goto out_tsk;
+	
+	if (request == PTRACE_ATTACH) {
+		ret = ptrace_attach(child);
+		goto out_tsk;
+	}
+	
+	ret = ptrace_check_attach(child, request == PTRACE_KILL);
+	if (ret < 0)
+		goto out_tsk;
+
+	switch (request) {
+		/* Read word at location address. */ 
+		case PTRACE_PEEKTEXT:
+		case PTRACE_PEEKDATA: {
+			unsigned long tmp;
+			int copied;
+
+			copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+			ret = -EIO;
+			
+			if (copied != sizeof(tmp))
+				break;
+			
+			ret = put_user(tmp,datap);
+			break;
+		}
+
+		/* Read the word at location address in the USER area. */
+		case PTRACE_PEEKUSR: {
+			unsigned long tmp;
+
+			ret = -EIO;
+			if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
+				break;
+
+			tmp = get_reg(child, addr >> 2);
+			ret = put_user(tmp, datap);
+			break;
+		}
+		
+		/* Write the word at location address. */
+		case PTRACE_POKETEXT:
+		case PTRACE_POKEDATA:
+			ret = 0;
+			
+			if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
+				break;
+			
+			ret = -EIO;
+			break;
+ 
+ 		/* Write the word at location address in the USER area. */
+		case PTRACE_POKEUSR:
+			ret = -EIO;
+			if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
+				break;
+
+			addr >>= 2;
+
+			if (addr == PT_DCCR) {
+				/* don't allow the tracing process to change stuff like
+				 * interrupt enable, kernel/user bit, dma enables etc.
+				 */
+				data &= DCCR_MASK;
+				data |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
+			}
+			if (put_reg(child, addr, data))
+				break;
+			ret = 0;
+			break;
+
+		case PTRACE_SYSCALL:
+		case PTRACE_CONT:
+			ret = -EIO;
+			
+			if ((unsigned long) data > _NSIG)
+				break;
+                        
+			if (request == PTRACE_SYSCALL) {
+				set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+			}
+			else {
+				clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+			}
+			
+			child->exit_code = data;
+			
+			/* TODO: make sure any pending breakpoint is killed */
+			wake_up_process(child);
+			ret = 0;
+			
+			break;
+		
+ 		/* Make the child exit by sending it a sigkill. */
+		case PTRACE_KILL:
+			ret = 0;
+			
+			if (child->state == TASK_ZOMBIE)
+				break;
+			
+			child->exit_code = SIGKILL;
+			
+			/* TODO: make sure any pending breakpoint is killed */
+			wake_up_process(child);
+			break;
+
+		/* Set the trap flag. */
+		case PTRACE_SINGLESTEP:
+			ret = -EIO;
+			
+			if ((unsigned long) data > _NSIG)
+				break;
+			
+			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+
+			/* TODO: set some clever breakpoint mechanism... */
+
+			child->exit_code = data;
+			wake_up_process(child);
+			ret = 0;
+			break;
+
+		case PTRACE_DETACH:
+			ret = ptrace_detach(child, data);
+			break;
+
+		/* Get all GP registers from the child. */
+		case PTRACE_GETREGS: {
+		  	int i;
+			unsigned long tmp;
+			
+			for (i = 0; i <= PT_MAX; i++) {
+				tmp = get_reg(child, i);
+				
+				if (put_user(tmp, datap)) {
+					ret = -EFAULT;
+					goto out_tsk;
+				}
+				
+				data += sizeof(long);
+			}
+
+			ret = 0;
+			break;
+		}
+
+		/* Set all GP registers in the child. */
+		case PTRACE_SETREGS: {
+			int i;
+			unsigned long tmp;
+			
+			for (i = 0; i <= PT_MAX; i++) {
+				if (get_user(tmp, datap)) {
+					ret = -EFAULT;
+					goto out_tsk;
+				}
+				
+				if (i == PT_DCCR) {
+					tmp &= DCCR_MASK;
+					tmp |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
+				}
+				
+				put_reg(child, i, tmp);
+				data += sizeof(long);
+			}
+			
+			ret = 0;
+			break;
+		}
+
+		default:
+			ret = ptrace_request(child, request, addr, data);
+			break;
+	}
+out_tsk:
+	put_task_struct(child);
+out:
+	unlock_kernel();
+	return ret;
+}
+
+void do_syscall_trace(void)
+{
+	if (!test_thread_flag(TIF_SYSCALL_TRACE))
+		return;
+	
+	if (!(current->ptrace & PT_PTRACED))
+		return;
+	
+	/* the 0x80 provides a way for the tracing parent to distinguish
+	   between a syscall stop and SIGTRAP delivery */
+	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+				 ? 0x80 : 0));
+	
+	/*
+	 * This isn't the same as continuing with a signal, but it will do for
+	 * normal use.
+	 */
+	if (current->exit_code) {
+		send_sig(current->exit_code, current, 1);
+		current->exit_code = 0;
+	}
+}
diff --git a/arch/cris/arch-v10/kernel/setup.c b/arch/cris/arch-v10/kernel/setup.c
new file mode 100644
index 0000000..b668d7f
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/setup.c
@@ -0,0 +1,103 @@
+/*
+ *
+ *  linux/arch/cris/arch-v10/kernel/setup.c
+ *
+ *  Copyright (C) 1995  Linus Torvalds
+ *  Copyright (c) 2001-2002  Axis Communications AB
+ */
+
+/*
+ * This file handles the architecture-dependent parts of initialization
+ */
+
+#include <linux/config.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+
+#ifdef CONFIG_PROC_FS
+#define HAS_FPU		0x0001
+#define HAS_MMU		0x0002
+#define HAS_ETHERNET100	0x0004
+#define HAS_TOKENRING	0x0008
+#define HAS_SCSI	0x0010
+#define HAS_ATA		0x0020
+#define HAS_USB		0x0040
+#define HAS_IRQ_BUG	0x0080
+#define HAS_MMU_BUG	0x0100
+
+static struct cpu_info {
+	char *model;
+	unsigned short cache;
+	unsigned short flags;
+} cpu_info[] = {
+	/* The first four models will never ever run this code and are
+	   only here for display.  */
+	{ "ETRAX 1",         0, 0 },
+	{ "ETRAX 2",         0, 0 },
+	{ "ETRAX 3",         0, HAS_TOKENRING },
+	{ "ETRAX 4",         0, HAS_TOKENRING | HAS_SCSI },
+	{ "Unknown",         0, 0 },
+	{ "Unknown",         0, 0 },
+	{ "Unknown",         0, 0 },
+	{ "Simulator",       8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA },
+	{ "ETRAX 100",       8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_IRQ_BUG },
+	{ "ETRAX 100",       8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA },
+	{ "ETRAX 100LX",     8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU | HAS_MMU_BUG },
+	{ "ETRAX 100LX v2",  8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU  },
+	{ "Unknown",         0, 0 }  /* This entry MUST be the last */
+};
+
+int show_cpuinfo(struct seq_file *m, void *v)
+{
+	unsigned long revision;
+	struct cpu_info *info;
+
+	/* read the version register in the CPU and print some stuff */
+
+	revision = rdvr();
+
+	if (revision >= sizeof cpu_info/sizeof *cpu_info)
+		info = &cpu_info[sizeof cpu_info/sizeof *cpu_info - 1];
+	else
+		info = &cpu_info[revision];
+
+	return seq_printf(m,
+		       "processor\t: 0\n" 
+		       "cpu\t\t: CRIS\n"
+		       "cpu revision\t: %lu\n"
+		       "cpu model\t: %s\n"
+		       "cache size\t: %d kB\n"
+		       "fpu\t\t: %s\n"
+		       "mmu\t\t: %s\n"
+		       "mmu DMA bug\t: %s\n"
+		       "ethernet\t: %s Mbps\n"
+		       "token ring\t: %s\n"
+		       "scsi\t\t: %s\n"
+		       "ata\t\t: %s\n"
+		       "usb\t\t: %s\n"
+		       "bogomips\t: %lu.%02lu\n",
+
+		       revision,
+		       info->model,
+		       info->cache,
+		       info->flags & HAS_FPU ? "yes" : "no",
+		       info->flags & HAS_MMU ? "yes" : "no",
+		       info->flags & HAS_MMU_BUG ? "yes" : "no",
+		       info->flags & HAS_ETHERNET100 ? "10/100" : "10",
+		       info->flags & HAS_TOKENRING ? "4/16 Mbps" : "no",
+		       info->flags & HAS_SCSI ? "yes" : "no",
+		       info->flags & HAS_ATA ? "yes" : "no",
+		       info->flags & HAS_USB ? "yes" : "no",
+		       (loops_per_jiffy * HZ + 500) / 500000,
+		       ((loops_per_jiffy * HZ + 500) / 5000) % 100);
+}
+
+#endif /* CONFIG_PROC_FS */
+
+void
+show_etrax_copyright(void)
+{
+	printk(KERN_INFO
+               "Linux/CRIS port on ETRAX 100LX (c) 2001 Axis Communications AB\n");
+}
diff --git a/arch/cris/arch-v10/kernel/shadows.c b/arch/cris/arch-v10/kernel/shadows.c
new file mode 100644
index 0000000..561a890
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/shadows.c
@@ -0,0 +1,36 @@
+/* $Id: shadows.c,v 1.1 2001/12/17 13:59:27 bjornw Exp $
+ * 
+ * Various shadow registers. Defines for these are in include/asm-etrax100/io.h
+ */
+
+/* Shadows for internal Etrax-registers */
+
+unsigned long genconfig_shadow;
+unsigned long port_g_data_shadow;
+unsigned char port_pa_dir_shadow;
+unsigned char port_pa_data_shadow;
+unsigned char port_pb_i2c_shadow;
+unsigned char port_pb_config_shadow;
+unsigned char port_pb_dir_shadow;
+unsigned char port_pb_data_shadow;
+unsigned long r_timer_ctrl_shadow;
+
+/* Shadows for external I/O port registers.
+ * These are only usable if there actually IS a latch connected
+ * to the corresponding external chip-select pin.
+ *
+ * A common usage is that CSP0 controls LED's and CSP4 video chips.
+ */
+
+unsigned long port_cse1_shadow;
+unsigned long port_csp0_shadow;
+unsigned long port_csp4_shadow;
+
+/* Corresponding addresses for the ports.
+ * These are initialized in arch/cris/mm/init.c using ioremap.
+ */
+
+volatile unsigned long *port_cse1_addr;
+volatile unsigned long *port_csp0_addr;
+volatile unsigned long *port_csp4_addr;
+
diff --git a/arch/cris/arch-v10/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c
new file mode 100644
index 0000000..85e0032
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/signal.c
@@ -0,0 +1,580 @@
+/*
+ *  linux/arch/cris/kernel/signal.c
+ *
+ *  Based on arch/i386/kernel/signal.c by
+ *     Copyright (C) 1991, 1992  Linus Torvalds
+ *     1997-11-28  Modified for POSIX.1b signals by Richard Henderson *
+ *
+ *  Ideas also taken from arch/arm.
+ *
+ *  Copyright (C) 2000, 2001 Axis Communications AB
+ *
+ *  Authors:  Bjorn Wesen (bjornw@axis.com)
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+
+#include <asm/processor.h>
+#include <asm/ucontext.h>
+#include <asm/uaccess.h>
+
+#define DEBUG_SIG 0
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+/* a syscall in Linux/CRIS is a break 13 instruction which is 2 bytes */
+/* manipulate regs so that upon return, it will be re-executed */
+
+/* We rely on that pc points to the instruction after "break 13", so the
+ * library must never do strange things like putting it in a delay slot.
+ */
+#define RESTART_CRIS_SYS(regs) regs->r10 = regs->orig_r10; regs->irp -= 2;
+
+int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs);
+
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.  Define 
+ * dummy arguments to be able to reach the regs argument.  (Note that this
+ * arrangement relies on old_sigset_t occupying one register.)
+ */
+int
+sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof, 
+               long srp, struct pt_regs *regs)
+{
+	sigset_t saveset;
+
+	mask &= _BLOCKABLE;
+	spin_lock_irq(&current->sighand->siglock);
+	saveset = current->blocked;
+	siginitset(&current->blocked, mask);
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	regs->r10 = -EINTR;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal(0, &saveset, regs))
+			/* We will get here twice: once to call the signal
+			   handler, then again to return from the
+			   sigsuspend system call.  When calling the
+			   signal handler, R10 holds the signal number as
+			   set through do_signal.  The sigsuspend call
+			   will return with the restored value set above;
+			   always -EINTR.  */
+			return regs->r10;
+	}
+}
+
+/* Define dummy arguments to be able to reach the regs argument.  (Note that
+ * this arrangement relies on size_t occupying one register.)
+ */
+int
+sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, long r12, long r13, 
+                  long mof, long srp, struct pt_regs *regs)
+{
+	sigset_t saveset, newset;
+
+	/* XXX: Don't preclude handling different sized sigset_t's.  */
+	if (sigsetsize != sizeof(sigset_t))
+		return -EINVAL;
+
+	if (copy_from_user(&newset, unewset, sizeof(newset)))
+		return -EFAULT;
+	sigdelsetmask(&newset, ~_BLOCKABLE);
+
+	spin_lock_irq(&current->sighand->siglock);
+	saveset = current->blocked;
+	current->blocked = newset;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	regs->r10 = -EINTR;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal(0, &saveset, regs))
+			/* We will get here twice: once to call the signal
+			   handler, then again to return from the
+			   sigsuspend system call.  When calling the
+			   signal handler, R10 holds the signal number as
+			   set through do_signal.  The sigsuspend call
+			   will return with the restored value set above;
+			   always -EINTR.  */
+			return regs->r10;
+	}
+}
+
+int 
+sys_sigaction(int sig, const struct old_sigaction __user *act,
+	      struct old_sigaction *oact)
+{
+	struct k_sigaction new_ka, old_ka;
+	int ret;
+
+	if (act) {
+		old_sigset_t mask;
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
+		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+			return -EFAULT;
+		__get_user(new_ka.sa.sa_flags, &act->sa_flags);
+		__get_user(mask, &act->sa_mask);
+		siginitset(&new_ka.sa.sa_mask, mask);
+	}
+
+	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+	if (!ret && oact) {
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+			return -EFAULT;
+		__put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+		__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+	}
+
+	return ret;
+}
+
+int
+sys_sigaltstack(const stack_t *uss, stack_t __user *uoss)
+{
+	return do_sigaltstack(uss, uoss, rdusp());
+}
+
+
+/*
+ * Do a signal return; undo the signal stack.
+ */
+
+struct sigframe {
+	struct sigcontext sc;
+	unsigned long extramask[_NSIG_WORDS-1];
+	unsigned char retcode[8];  /* trampoline code */
+};
+
+struct rt_sigframe {
+	struct siginfo *pinfo;
+	void *puc;
+	struct siginfo info;
+	struct ucontext uc;
+	unsigned char retcode[8];  /* trampoline code */
+};
+
+
+static int
+restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
+{
+	unsigned int err = 0;
+	unsigned long old_usp;
+
+        /* Always make any pending restarted system calls return -EINTR */
+	current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+	/* restore the regs from &sc->regs (same as sc, since regs is first)
+	 * (sc is already checked for VERIFY_READ since the sigframe was
+	 *  checked in sys_sigreturn previously)
+	 */
+
+	if (__copy_from_user(regs, sc, sizeof(struct pt_regs)))
+                goto badframe;
+
+	/* make sure the U-flag is set so user-mode cannot fool us */
+
+	regs->dccr |= 1 << 8;
+
+	/* restore the old USP as it was before we stacked the sc etc.
+	 * (we cannot just pop the sigcontext since we aligned the sp and
+	 *  stuff after pushing it)
+	 */
+
+	err |= __get_user(old_usp, &sc->usp);
+
+	wrusp(old_usp);
+
+	/* TODO: the other ports use regs->orig_XX to disable syscall checks
+	 * after this completes, but we don't use that mechanism. maybe we can
+	 * use it now ? 
+	 */
+
+	return err;
+
+badframe:
+	return 1;
+}
+
+/* Define dummy arguments to be able to reach the regs argument.  */
+
+asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof, 
+                             long srp, struct pt_regs *regs)
+{
+	struct sigframe __user *frame = (struct sigframe *)rdusp();
+	sigset_t set;
+
+        /*
+         * Since we stacked the signal on a dword boundary,
+         * then frame should be dword aligned here.  If it's
+         * not, then the user is trying to mess with us.
+         */
+        if (((long)frame) & 3)
+                goto badframe;
+
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+	if (__get_user(set.sig[0], &frame->sc.oldmask)
+	    || (_NSIG_WORDS > 1
+		&& __copy_from_user(&set.sig[1], frame->extramask,
+				    sizeof(frame->extramask))))
+		goto badframe;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sighand->siglock);
+	current->blocked = set;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+	
+	if (restore_sigcontext(regs, &frame->sc))
+		goto badframe;
+
+	/* TODO: SIGTRAP when single-stepping as in arm ? */
+
+	return regs->r10;
+
+badframe:
+	force_sig(SIGSEGV, current);
+	return 0;
+}	
+
+/* Define dummy arguments to be able to reach the regs argument.  */
+
+asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13, 
+                                long mof, long srp, struct pt_regs *regs)
+{
+	struct rt_sigframe __user *frame = (struct rt_sigframe *)rdusp();
+	sigset_t set;
+
+        /*
+         * Since we stacked the signal on a dword boundary,
+         * then frame should be dword aligned here.  If it's
+         * not, then the user is trying to mess with us.
+         */
+        if (((long)frame) & 3)
+                goto badframe;
+
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+		goto badframe;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sighand->siglock);
+	current->blocked = set;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+	
+	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
+		goto badframe;
+
+	if (do_sigaltstack(&frame->uc.uc_stack, NULL, rdusp()) == -EFAULT)
+		goto badframe;
+
+	return regs->r10;
+
+badframe:
+	force_sig(SIGSEGV, current);
+	return 0;
+}	
+
+/*
+ * Set up a signal frame.
+ */
+
+static int
+setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned long mask)
+{
+	int err = 0;
+	unsigned long usp = rdusp();
+
+	/* copy the regs. they are first in sc so we can use sc directly */
+
+	err |= __copy_to_user(sc, regs, sizeof(struct pt_regs));
+
+        /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
+           the signal handler. The frametype will be restored to its previous
+           value in restore_sigcontext. */
+        regs->frametype = CRIS_FRAME_NORMAL;
+
+	/* then some other stuff */
+
+	err |= __put_user(mask, &sc->oldmask);
+
+	err |= __put_user(usp, &sc->usp);
+
+	return err;
+}
+
+/* figure out where we want to put the new signal frame - usually on the stack */
+
+static inline void __user *
+get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
+{
+	unsigned long sp = rdusp();
+
+	/* This is the X/Open sanctioned signal stack switching.  */
+	if (ka->sa.sa_flags & SA_ONSTACK) {
+		if (! on_sig_stack(sp))
+			sp = current->sas_ss_sp + current->sas_ss_size;
+	}
+
+	/* make sure the frame is dword-aligned */
+
+	sp &= ~3;
+
+	return (void __user*)(sp - frame_size);
+}
+
+/* grab and setup a signal frame.
+ * 
+ * basically we stack a lot of state info, and arrange for the
+ * user-mode program to return to the kernel using either a
+ * trampoline which performs the syscall sigreturn, or a provided
+ * user-mode trampoline.
+ */
+
+static void setup_frame(int sig, struct k_sigaction *ka,
+			sigset_t *set, struct pt_regs * regs)
+{
+	struct sigframe __user *frame;
+	unsigned long return_ip;
+	int err = 0;
+
+	frame = get_sigframe(ka, regs, sizeof(*frame));
+
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+		goto give_sigsegv;
+
+	err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
+	if (err)
+		goto give_sigsegv;
+
+	if (_NSIG_WORDS > 1) {
+		err |= __copy_to_user(frame->extramask, &set->sig[1],
+				      sizeof(frame->extramask));
+	}
+	if (err)
+		goto give_sigsegv;
+
+	/* Set up to return from userspace.  If provided, use a stub
+	   already in userspace.  */
+	if (ka->sa.sa_flags & SA_RESTORER) {
+		return_ip = (unsigned long)ka->sa.sa_restorer;
+	} else {
+		/* trampoline - the desired return ip is the retcode itself */
+		return_ip = (unsigned long)&frame->retcode;
+		/* This is movu.w __NR_sigreturn, r9; break 13; */
+		err |= __put_user(0x9c5f,         (short __user*)(frame->retcode+0));
+		err |= __put_user(__NR_sigreturn, (short __user*)(frame->retcode+2));
+		err |= __put_user(0xe93d,         (short __user*)(frame->retcode+4));
+	}
+
+	if (err)
+		goto give_sigsegv;
+
+	/* Set up registers for signal handler */
+
+	regs->irp = (unsigned long) ka->sa.sa_handler;  /* what we enter NOW   */
+	regs->srp = return_ip;                          /* what we enter LATER */
+	regs->r10 = sig;                                /* first argument is signo */
+
+	/* actually move the usp to reflect the stacked frame */
+
+	wrusp((unsigned long)frame);
+
+	return;
+
+give_sigsegv:
+	force_sigsegv(sig, current);
+}
+
+static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+			   sigset_t *set, struct pt_regs * regs)
+{
+	struct rt_sigframe __user *frame;
+	unsigned long return_ip;
+	int err = 0;
+
+	frame = get_sigframe(ka, regs, sizeof(*frame));
+
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+		goto give_sigsegv;
+
+	err |= __put_user(&frame->info, &frame->pinfo);
+	err |= __put_user(&frame->uc, &frame->puc);
+	err |= copy_siginfo_to_user(&frame->info, info);
+	if (err)
+		goto give_sigsegv;
+
+	/* Clear all the bits of the ucontext we don't use.  */
+        err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
+
+	err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);
+
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
+	if (err)
+		goto give_sigsegv;
+
+	/* Set up to return from userspace.  If provided, use a stub
+	   already in userspace.  */
+	if (ka->sa.sa_flags & SA_RESTORER) {
+		return_ip = (unsigned long)ka->sa.sa_restorer;
+	} else {
+		/* trampoline - the desired return ip is the retcode itself */
+		return_ip = (unsigned long)&frame->retcode;
+		/* This is movu.w __NR_rt_sigreturn, r9; break 13; */
+		err |= __put_user(0x9c5f,            (short __user*)(frame->retcode+0));
+		err |= __put_user(__NR_rt_sigreturn, (short __user*)(frame->retcode+2));
+		err |= __put_user(0xe93d,            (short __user*)(frame->retcode+4));
+	}
+
+	if (err)
+		goto give_sigsegv;
+
+	/* TODO what is the current->exec_domain stuff and invmap ? */
+
+	/* Set up registers for signal handler */
+
+	regs->irp = (unsigned long) ka->sa.sa_handler;  /* what we enter NOW   */
+	regs->srp = return_ip;                          /* what we enter LATER */
+	regs->r10 = sig;                                /* first argument is signo */
+        regs->r11 = (unsigned long) &frame->info;       /* second argument is (siginfo_t *) */
+        regs->r12 = 0;                                  /* third argument is unused */
+
+	/* actually move the usp to reflect the stacked frame */
+
+	wrusp((unsigned long)frame);
+
+	return;
+
+give_sigsegv:
+	force_sigsegv(sig, current);
+}
+
+/*
+ * OK, we're invoking a handler
+ */	
+
+extern inline void
+handle_signal(int canrestart, unsigned long sig,
+	      siginfo_t *info, struct k_sigaction *ka,
+              sigset_t *oldset, struct pt_regs * regs)
+{
+	/* Are we from a system call? */
+	if (canrestart) {
+		/* If so, check system call restarting.. */
+		switch (regs->r10) {
+			case -ERESTART_RESTARTBLOCK:
+			case -ERESTARTNOHAND:
+				/* ERESTARTNOHAND means that the syscall should only be
+				   restarted if there was no handler for the signal, and since
+				   we only get here if there is a handler, we don't restart */
+				regs->r10 = -EINTR;
+				break;
+
+			case -ERESTARTSYS:
+				/* ERESTARTSYS means to restart the syscall if there is no
+				   handler or the handler was registered with SA_RESTART */
+				if (!(ka->sa.sa_flags & SA_RESTART)) {
+					regs->r10 = -EINTR;
+					break;
+				}
+			/* fallthrough */
+			case -ERESTARTNOINTR:
+				/* ERESTARTNOINTR means that the syscall should be called again
+				   after the signal handler returns. */
+				RESTART_CRIS_SYS(regs);
+		}
+	}
+
+	/* Set up the stack frame */
+	if (ka->sa.sa_flags & SA_SIGINFO)
+		setup_rt_frame(sig, ka, info, oldset, regs);
+	else
+		setup_frame(sig, ka, oldset, regs);
+
+	if (ka->sa.sa_flags & SA_ONESHOT)
+		ka->sa.sa_handler = SIG_DFL;
+
+	if (!(ka->sa.sa_flags & SA_NODEFER)) {
+		spin_lock_irq(&current->sighand->siglock);
+		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+		sigaddset(&current->blocked,sig);
+		recalc_sigpending();
+		spin_unlock_irq(&current->sighand->siglock);
+	}
+}
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ *
+ * Also note that the regs structure given here as an argument, is the latest
+ * pushed pt_regs. It may or may not be the same as the first pushed registers
+ * when the initial usermode->kernelmode transition took place. Therefore
+ * we can use user_mode(regs) to see if we came directly from kernel or user
+ * mode below.
+ */
+
+int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
+{
+	siginfo_t info;
+	int signr;
+        struct k_sigaction ka;
+
+	/*
+	 * We want the common case to go fast, which
+	 * is why we may in certain cases get here from
+	 * kernel mode. Just return without doing anything
+	 * if so.
+	 */
+	if (!user_mode(regs))
+		return 1;
+
+	if (!oldset)
+		oldset = &current->blocked;
+
+	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+	if (signr > 0) {
+		/* Whee!  Actually deliver the signal.  */
+		handle_signal(canrestart, signr, &info, &ka, oldset, regs);
+		return 1;
+	}
+
+	/* Did we come from a system call? */
+	if (canrestart) {
+		/* Restart the system call - no handlers present */
+		if (regs->r10 == -ERESTARTNOHAND ||
+		    regs->r10 == -ERESTARTSYS ||
+		    regs->r10 == -ERESTARTNOINTR) {
+			RESTART_CRIS_SYS(regs);
+		}
+		if (regs->r10 == -ERESTART_RESTARTBLOCK){
+			regs->r10 = __NR_restart_syscall;
+			regs->irp -= 2;
+		}
+	}
+	return 0;
+}
diff --git a/arch/cris/arch-v10/kernel/time.c b/arch/cris/arch-v10/kernel/time.c
new file mode 100644
index 0000000..6b7b4e0
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/time.c
@@ -0,0 +1,369 @@
+/* $Id: time.c,v 1.5 2004/09/29 06:12:46 starvik Exp $
+ *
+ *  linux/arch/cris/arch-v10/kernel/time.c
+ *
+ *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *  Copyright (C) 1999-2002 Axis Communications AB
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/timex.h>
+#include <linux/time.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/swap.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <asm/arch/svinto.h>
+#include <asm/types.h>
+#include <asm/signal.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <asm/rtc.h>
+
+/* define this if you need to use print_timestamp */
+/* it will make jiffies at 96 hz instead of 100 hz though */
+#undef USE_CASCADE_TIMERS
+
+extern void update_xtime_from_cmos(void);
+extern int set_rtc_mmss(unsigned long nowtime);
+extern int setup_irq(int, struct irqaction *);
+extern int have_rtc;
+
+unsigned long get_ns_in_jiffie(void)
+{
+	unsigned char timer_count, t1;
+	unsigned short presc_count;
+	unsigned long ns;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	local_irq_disable();
+	timer_count = *R_TIMER0_DATA;
+	presc_count = *R_TIM_PRESC_STATUS;  
+	/* presc_count might be wrapped */
+	t1 = *R_TIMER0_DATA;
+
+	if (timer_count != t1){
+		/* it wrapped, read prescaler again...  */
+		presc_count = *R_TIM_PRESC_STATUS;
+		timer_count = t1;
+	}
+	local_irq_restore(flags);
+	if (presc_count >= PRESCALE_VALUE/2 ){
+		presc_count =  PRESCALE_VALUE - presc_count + PRESCALE_VALUE/2;
+	} else {
+		presc_count =  PRESCALE_VALUE - presc_count - PRESCALE_VALUE/2;
+	}
+
+	ns = ( (TIMER0_DIV - timer_count) * ((1000000000/HZ)/TIMER0_DIV )) + 
+	     ( (presc_count) * (1000000000/PRESCALE_FREQ));
+	return ns;
+}
+
+unsigned long do_slow_gettimeoffset(void)
+{
+	unsigned long count, t1;
+	unsigned long usec_count = 0;
+	unsigned short presc_count;
+
+	static unsigned long count_p = TIMER0_DIV;/* for the first call after boot */
+	static unsigned long jiffies_p = 0;
+
+	/*
+	 * cache volatile jiffies temporarily; we have IRQs turned off. 
+	 */
+	unsigned long jiffies_t;
+
+	/* The timer interrupt comes from Etrax timer 0. In order to get
+	 * better precision, we check the current value. It might have
+	 * underflowed already though.
+	 */
+
+#ifndef CONFIG_SVINTO_SIM
+	/* Not available in the xsim simulator. */
+	count = *R_TIMER0_DATA;
+	presc_count = *R_TIM_PRESC_STATUS;  
+	/* presc_count might be wrapped */
+	t1 = *R_TIMER0_DATA;
+	if (count != t1){
+		/* it wrapped, read prescaler again...  */
+		presc_count = *R_TIM_PRESC_STATUS;
+		count = t1;
+	}
+#else
+	count = 0;
+	presc_count = 0;
+#endif
+
+ 	jiffies_t = jiffies;
+
+	/*
+	 * avoiding timer inconsistencies (they are rare, but they happen)...
+	 * there are one problem that must be avoided here:
+	 *  1. the timer counter underflows
+	 */
+	if( jiffies_t == jiffies_p ) {
+		if( count > count_p ) {
+			/* Timer wrapped, use new count and prescale 
+			 * increase the time corresponding to one jiffie
+			 */
+			usec_count = 1000000/HZ;
+		}
+	} else
+		jiffies_p = jiffies_t;
+        count_p = count;
+	if (presc_count >= PRESCALE_VALUE/2 ){
+		presc_count =  PRESCALE_VALUE - presc_count + PRESCALE_VALUE/2;
+	} else {
+		presc_count =  PRESCALE_VALUE - presc_count - PRESCALE_VALUE/2;
+	}
+	/* Convert timer value to usec */
+	usec_count += ( (TIMER0_DIV - count) * (1000000/HZ)/TIMER0_DIV ) +
+	              (( (presc_count) * (1000000000/PRESCALE_FREQ))/1000);
+
+	return usec_count;
+}
+
+/* Excerpt from the Etrax100 HSDD about the built-in watchdog:
+ *
+ * 3.10.4 Watchdog timer
+
+ * When the watchdog timer is started, it generates an NMI if the watchdog
+ * isn't restarted or stopped within 0.1 s. If it still isn't restarted or
+ * stopped after an additional 3.3 ms, the watchdog resets the chip.
+ * The watchdog timer is stopped after reset. The watchdog timer is controlled
+ * by the R_WATCHDOG register. The R_WATCHDOG register contains an enable bit
+ * and a 3-bit key value. The effect of writing to the R_WATCHDOG register is
+ * described in the table below:
+ * 
+ *   Watchdog    Value written:
+ *   state:      To enable:  To key:      Operation:
+ *   --------    ----------  -------      ----------
+ *   stopped         0         X          No effect.
+ *   stopped         1       key_val      Start watchdog with key = key_val.
+ *   started         0       ~key         Stop watchdog
+ *   started         1       ~key         Restart watchdog with key = ~key.
+ *   started         X       new_key_val  Change key to new_key_val.
+ * 
+ * Note: '~' is the bitwise NOT operator.
+ * 
+ */
+
+/* right now, starting the watchdog is the same as resetting it */
+#define start_watchdog reset_watchdog
+
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+static int watchdog_key = 0;  /* arbitrary number */
+#endif
+
+/* number of pages to consider "out of memory". it is normal that the memory
+ * is used though, so put this really low.
+ */
+
+#define WATCHDOG_MIN_FREE_PAGES 8
+
+void
+reset_watchdog(void)
+{
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+	/* only keep watchdog happy as long as we have memory left! */
+	if(nr_free_pages() > WATCHDOG_MIN_FREE_PAGES) {
+		/* reset the watchdog with the inverse of the old key */
+		watchdog_key ^= 0x7; /* invert key, which is 3 bits */
+		*R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) |
+			IO_STATE(R_WATCHDOG, enable, start);
+	}
+#endif
+}
+
+/* stop the watchdog - we still need the correct key */
+
+void 
+stop_watchdog(void)
+{
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+	watchdog_key ^= 0x7; /* invert key, which is 3 bits */
+	*R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) |
+		IO_STATE(R_WATCHDOG, enable, stop);
+#endif	
+}
+
+/* last time the cmos clock got updated */
+static long last_rtc_update = 0;
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+
+//static unsigned short myjiff; /* used by our debug routine print_timestamp */
+
+extern void cris_do_profile(struct pt_regs *regs);
+
+static inline irqreturn_t
+timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	/* acknowledge the timer irq */
+
+#ifdef USE_CASCADE_TIMERS
+	*R_TIMER_CTRL =
+		IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) |
+		IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) |
+		IO_STATE( R_TIMER_CTRL, i1, clr) |
+		IO_STATE( R_TIMER_CTRL, tm1, run) |
+		IO_STATE( R_TIMER_CTRL, clksel1, cascade0) |
+		IO_STATE( R_TIMER_CTRL, i0, clr) |
+		IO_STATE( R_TIMER_CTRL, tm0, run) |
+		IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz);
+#else
+	*R_TIMER_CTRL = r_timer_ctrl_shadow | 
+		IO_STATE(R_TIMER_CTRL, i0, clr);
+#endif
+
+	/* reset watchdog otherwise it resets us! */
+
+	reset_watchdog();
+	
+	/* call the real timer interrupt handler */
+
+	do_timer(regs);
+	
+        cris_do_profile(regs); /* Save profiling information */
+
+	/*
+	 * If we have an externally synchronized Linux clock, then update
+	 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+	 * called as close as possible to 500 ms before the new second starts.
+	 *
+	 * The division here is not time critical since it will run once in 
+	 * 11 minutes
+	 */
+	if ((time_status & STA_UNSYNC) == 0 &&
+	    xtime.tv_sec > last_rtc_update + 660 &&
+	    (xtime.tv_nsec / 1000) >= 500000 - (tick_nsec / 1000) / 2 &&
+	    (xtime.tv_nsec / 1000) <= 500000 + (tick_nsec / 1000) / 2) {
+		if (set_rtc_mmss(xtime.tv_sec) == 0)
+			last_rtc_update = xtime.tv_sec;
+		else
+			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+	}
+        return IRQ_HANDLED;
+}
+
+/* timer is SA_SHIRQ so drivers can add stuff to the timer irq chain
+ * it needs to be SA_INTERRUPT to make the jiffies update work properly
+ */
+
+static struct irqaction irq2  = { timer_interrupt, SA_SHIRQ | SA_INTERRUPT,
+				  CPU_MASK_NONE, "timer", NULL, NULL};
+
+void __init
+time_init(void)
+{	
+	/* probe for the RTC and read it if it exists 
+	 * Before the RTC can be probed the loops_per_usec variable needs 
+	 * to be initialized to make usleep work. A better value for 
+	 * loops_per_usec is calculated by the kernel later once the 
+	 * clock has started.  
+	 */
+	loops_per_usec = 50;
+
+	if(RTC_INIT() < 0) {
+		/* no RTC, start at 1980 */
+		xtime.tv_sec = 0;
+		xtime.tv_nsec = 0;
+		have_rtc = 0;
+	} else {		
+		/* get the current time */
+		have_rtc = 1;
+		update_xtime_from_cmos();
+	}
+
+	/*
+	 * Initialize wall_to_monotonic such that adding it to xtime will yield zero, the
+	 * tv_nsec field must be normalized (i.e., 0 <= nsec < NSEC_PER_SEC).
+	 */
+	set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec);
+
+	/* Setup the etrax timers
+	 * Base frequency is 25000 hz, divider 250 -> 100 HZ
+	 * In normal mode, we use timer0, so timer1 is free. In cascade
+	 * mode (which we sometimes use for debugging) both timers are used.
+	 * Remember that linux/timex.h contains #defines that rely on the
+	 * timer settings below (hz and divide factor) !!!
+	 */
+	
+#ifdef USE_CASCADE_TIMERS
+	*R_TIMER_CTRL =
+		IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) |
+		IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) |
+		IO_STATE( R_TIMER_CTRL, i1, nop) |
+		IO_STATE( R_TIMER_CTRL, tm1, stop_ld) |
+		IO_STATE( R_TIMER_CTRL, clksel1, cascade0) |
+		IO_STATE( R_TIMER_CTRL, i0, nop) |
+		IO_STATE( R_TIMER_CTRL, tm0, stop_ld) |
+		IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz);
+	
+	*R_TIMER_CTRL = r_timer_ctrl_shadow = 
+		IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) |
+		IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) |
+		IO_STATE( R_TIMER_CTRL, i1, nop) |
+		IO_STATE( R_TIMER_CTRL, tm1, run) |
+		IO_STATE( R_TIMER_CTRL, clksel1, cascade0) |
+		IO_STATE( R_TIMER_CTRL, i0, nop) |
+		IO_STATE( R_TIMER_CTRL, tm0, run) |
+		IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz);
+#else
+	*R_TIMER_CTRL = 
+		IO_FIELD(R_TIMER_CTRL, timerdiv1, 192)      | 
+		IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER0_DIV)      |
+		IO_STATE(R_TIMER_CTRL, i1,        nop)      | 
+		IO_STATE(R_TIMER_CTRL, tm1,       stop_ld)  |
+		IO_STATE(R_TIMER_CTRL, clksel1,   c19k2Hz)  |
+		IO_STATE(R_TIMER_CTRL, i0,        nop)      |
+		IO_STATE(R_TIMER_CTRL, tm0,       stop_ld)  |
+		IO_STATE(R_TIMER_CTRL, clksel0,   flexible);
+	
+	*R_TIMER_CTRL = r_timer_ctrl_shadow =
+		IO_FIELD(R_TIMER_CTRL, timerdiv1, 192)      | 
+		IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER0_DIV)      |
+		IO_STATE(R_TIMER_CTRL, i1,        nop)      |
+		IO_STATE(R_TIMER_CTRL, tm1,       run)      |
+		IO_STATE(R_TIMER_CTRL, clksel1,   c19k2Hz)  |
+		IO_STATE(R_TIMER_CTRL, i0,        nop)      |
+		IO_STATE(R_TIMER_CTRL, tm0,       run)      |
+		IO_STATE(R_TIMER_CTRL, clksel0,   flexible);
+
+	*R_TIMER_PRESCALE = PRESCALE_VALUE;
+#endif
+
+	*R_IRQ_MASK0_SET =
+		IO_STATE(R_IRQ_MASK0_SET, timer0, set); /* unmask the timer irq */
+	
+	/* now actually register the timer irq handler that calls timer_interrupt() */
+	
+	setup_irq(2, &irq2); /* irq 2 is the timer0 irq in etrax */
+
+	/* enable watchdog if we should use one */
+
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+	printk("Enabling watchdog...\n");
+	start_watchdog();
+
+	/* If we use the hardware watchdog, we want to trap it as an NMI
+	   and dump registers before it resets us.  For this to happen, we
+	   must set the "m" NMI enable flag (which once set, is unset only
+	   when an NMI is taken).
+
+	   The same goes for the external NMI, but that doesn't have any
+	   driver or infrastructure support yet.  */
+	asm ("setf m");
+
+	*R_IRQ_MASK0_SET =
+		IO_STATE(R_IRQ_MASK0_SET, watchdog_nmi, set);
+	*R_VECT_MASK_SET =
+		IO_STATE(R_VECT_MASK_SET, nmi, set);
+#endif
+}
diff --git a/arch/cris/arch-v10/kernel/traps.c b/arch/cris/arch-v10/kernel/traps.c
new file mode 100644
index 0000000..da491f4
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/traps.c
@@ -0,0 +1,132 @@
+/* $Id: traps.c,v 1.2 2003/07/04 08:27:41 starvik Exp $
+ *
+ *  linux/arch/cris/arch-v10/traps.c
+ *
+ *  Heler functions for trap handlers
+ * 
+ *  Copyright (C) 2000-2002 Axis Communications AB
+ *
+ *  Authors:   Bjorn Wesen
+ *  	       Hans-Peter Nilsson
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/ptrace.h>
+#include <asm/uaccess.h>
+#include <asm/arch/sv_addr_ag.h>
+
+void 
+show_registers(struct pt_regs * regs)
+{
+	/* We either use rdusp() - the USP register, which might not
+	   correspond to the current process for all cases we're called,
+	   or we use the current->thread.usp, which is not up to date for
+	   the current process.  Experience shows we want the USP
+	   register.  */
+	unsigned long usp = rdusp();
+
+	printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n",
+	       regs->irp, regs->srp, regs->dccr, usp, regs->mof );
+	printk(" r0: %08lx  r1: %08lx   r2: %08lx  r3: %08lx\n",
+	       regs->r0, regs->r1, regs->r2, regs->r3);
+	printk(" r4: %08lx  r5: %08lx   r6: %08lx  r7: %08lx\n",
+	       regs->r4, regs->r5, regs->r6, regs->r7);
+	printk(" r8: %08lx  r9: %08lx  r10: %08lx r11: %08lx\n",
+	       regs->r8, regs->r9, regs->r10, regs->r11);
+	printk("r12: %08lx r13: %08lx oR10: %08lx\n",
+	       regs->r12, regs->r13, regs->orig_r10);
+	printk("R_MMU_CAUSE: %08lx\n", (unsigned long)*R_MMU_CAUSE);
+	printk("Process %s (pid: %d, stackpage=%08lx)\n",
+	       current->comm, current->pid, (unsigned long)current);
+
+	/*
+         * When in-kernel, we also print out the stack and code at the
+         * time of the fault..
+         */
+        if (! user_mode(regs)) {
+	  	int i;
+
+                show_stack(NULL, (unsigned long*)usp);
+
+		/* Dump kernel stack if the previous dump wasn't one.  */
+		if (usp != 0)
+			show_stack (NULL, NULL);
+
+                printk("\nCode: ");
+                if(regs->irp < PAGE_OFFSET)
+                        goto bad;
+
+		/* Often enough the value at regs->irp does not point to
+		   the interesting instruction, which is most often the
+		   _previous_ instruction.  So we dump at an offset large
+		   enough that instruction decoding should be in sync at
+		   the interesting point, but small enough to fit on a row
+		   (sort of).  We point out the regs->irp location in a
+		   ksymoops-friendly way by wrapping the byte for that
+		   address in parentheses.  */
+                for(i = -12; i < 12; i++)
+                {
+                        unsigned char c;
+                        if(__get_user(c, &((unsigned char*)regs->irp)[i])) {
+bad:
+                                printk(" Bad IP value.");
+                                break;
+                        }
+
+			if (i == 0)
+			  printk("(%02x) ", c);
+			else
+			  printk("%02x ", c);
+                }
+		printk("\n");
+        }
+}
+
+/* Called from entry.S when the watchdog has bitten
+ * We print out something resembling an oops dump, and if
+ * we have the nice doggy development flag set, we halt here
+ * instead of rebooting.
+ */
+
+extern void reset_watchdog(void);
+extern void stop_watchdog(void);
+
+
+void
+watchdog_bite_hook(struct pt_regs *regs)
+{
+#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
+	local_irq_disable();
+	stop_watchdog();
+	show_registers(regs);
+	while(1) /* nothing */;
+#else
+	show_registers(regs);
+#endif	
+}
+
+/* This is normally the 'Oops' routine */
+void 
+die_if_kernel(const char * str, struct pt_regs * regs, long err)
+{
+	if(user_mode(regs))
+		return;
+
+#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
+	/* This printout might take too long and trigger the 
+	 * watchdog normally. If we're in the nice doggy
+	 * development mode, stop the watchdog during printout.
+	 */
+	stop_watchdog();
+#endif
+
+	printk("%s: %04lx\n", str, err & 0xffff);
+
+	show_registers(regs);
+
+#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
+	reset_watchdog();
+#endif
+	do_exit(SIGSEGV);
+}
diff --git a/arch/cris/arch-v10/lib/Makefile b/arch/cris/arch-v10/lib/Makefile
new file mode 100644
index 0000000..36e9a9c
--- /dev/null
+++ b/arch/cris/arch-v10/lib/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for Etrax-specific library files..
+#
+
+
+EXTRA_AFLAGS := -traditional
+
+lib-y  = checksum.o checksumcopy.o string.o usercopy.o memset.o csumcpfruser.o
+
diff --git a/arch/cris/arch-v10/lib/checksum.S b/arch/cris/arch-v10/lib/checksum.S
new file mode 100644
index 0000000..85c48f0
--- /dev/null
+++ b/arch/cris/arch-v10/lib/checksum.S
@@ -0,0 +1,124 @@
+/* $Id: checksum.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $
+ * A fast checksum routine using movem
+ * Copyright (c) 1998-2001 Axis Communications AB
+ *
+ * csum_partial(const unsigned char * buff, int len, unsigned int sum)
+ */
+
+	.globl	csum_partial
+csum_partial:
+	
+	;; r10 - src
+	;; r11 - length
+	;; r12 - checksum
+
+	;; check for breakeven length between movem and normal word looping versions
+	;; we also do _NOT_ want to compute a checksum over more than the 
+	;; actual length when length < 40
+	
+	cmpu.w	80,$r11
+	blo	_word_loop
+	nop
+
+	;; need to save the registers we use below in the movem loop
+	;; this overhead is why we have a check above for breakeven length
+	;; only r0 - r8 have to be saved, the other ones are clobber-able
+	;; according to the ABI
+	
+	subq	9*4,$sp
+	movem	$r8,[$sp]
+	
+	;; do a movem checksum
+
+	subq	10*4,$r11	; update length for the first loop
+	
+_mloop:	movem	[$r10+],$r9	; read 10 longwords
+
+	;; perform dword checksumming on the 10 longwords
+	
+	add.d	$r0,$r12
+	ax
+	add.d	$r1,$r12
+	ax
+	add.d	$r2,$r12
+	ax
+	add.d	$r3,$r12
+	ax
+	add.d	$r4,$r12
+	ax
+	add.d	$r5,$r12
+	ax
+	add.d	$r6,$r12
+	ax
+	add.d	$r7,$r12
+	ax
+	add.d	$r8,$r12
+	ax
+	add.d	$r9,$r12
+
+	;; fold the carry into the checksum, to avoid having to loop the carry
+	;; back into the top
+	
+	ax
+	addq	0,$r12
+	ax			; do it again, since we might have generated a carry
+	addq	0,$r12
+
+	subq	10*4,$r11
+	bge	_mloop
+	nop
+
+	addq	10*4,$r11	; compensate for last loop underflowing length
+
+	movem	[$sp+],$r8	; restore regs
+
+_word_loop:
+	;; only fold if there is anything to fold.
+
+	cmpq	0,$r12
+	beq	_no_fold
+
+	;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below.
+	;; r9 and r13 can be used as temporaries.
+	
+	moveq	-1,$r9		; put 0xffff in r9, faster than move.d 0xffff,r9
+	lsrq	16,$r9
+	
+	move.d	$r12,$r13
+	lsrq	16,$r13		; r13 = checksum >> 16
+	and.d	$r9,$r12		; checksum = checksum & 0xffff
+	add.d	$r13,$r12		; checksum += r13
+	move.d	$r12,$r13		; do the same again, maybe we got a carry last add
+	lsrq	16,$r13
+	and.d	$r9,$r12
+	add.d	$r13,$r12
+
+_no_fold:
+	cmpq	2,$r11
+	blt	_no_words
+	nop
+	
+	;; checksum the rest of the words
+	
+	subq	2,$r11
+	
+_wloop:	subq	2,$r11
+	bge	_wloop
+	addu.w	[$r10+],$r12
+	
+	addq	2,$r11
+		
+_no_words:
+	;; see if we have one odd byte more
+	cmpq	1,$r11
+	beq	_do_byte
+	nop
+	ret
+	move.d	$r12, $r10
+
+_do_byte:	
+	;; copy and checksum the last byte
+	addu.b	[$r10],$r12
+	ret
+	move.d	$r12, $r10
+		
diff --git a/arch/cris/arch-v10/lib/checksumcopy.S b/arch/cris/arch-v10/lib/checksumcopy.S
new file mode 100644
index 0000000..35cbffb
--- /dev/null
+++ b/arch/cris/arch-v10/lib/checksumcopy.S
@@ -0,0 +1,132 @@
+/* $Id: checksumcopy.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $
+ * A fast checksum+copy routine using movem
+ * Copyright (c) 1998, 2001 Axis Communications AB
+ *
+ * Authors:	Bjorn Wesen
+ * 
+ * csum_partial_copy_nocheck(const char *src, char *dst,
+ *		             int len, unsigned int sum)
+ */
+
+	.globl	csum_partial_copy_nocheck
+csum_partial_copy_nocheck:	
+	
+	;; r10 - src
+	;; r11 - dst
+	;; r12 - length
+	;; r13 - checksum
+
+	;; check for breakeven length between movem and normal word looping versions
+	;; we also do _NOT_ want to compute a checksum over more than the 
+	;; actual length when length < 40
+	
+	cmpu.w	80, $r12
+	blo	_word_loop
+	nop
+
+	;; need to save the registers we use below in the movem loop
+	;; this overhead is why we have a check above for breakeven length
+	;; only r0 - r8 have to be saved, the other ones are clobber-able
+	;; according to the ABI
+	
+	subq	9*4, $sp
+	movem	$r8, [$sp]
+	
+	;; do a movem copy and checksum
+
+	subq	10*4, $r12	; update length for the first loop
+	
+_mloop:	movem	[$r10+],$r9	; read 10 longwords
+1:	;; A failing userspace access will have this as PC.
+	movem	$r9,[$r11+]	; write 10 longwords
+
+	;; perform dword checksumming on the 10 longwords
+	
+	add.d	$r0,$r13
+	ax
+	add.d	$r1,$r13
+	ax
+	add.d	$r2,$r13
+	ax
+	add.d	$r3,$r13
+	ax
+	add.d	$r4,$r13
+	ax
+	add.d	$r5,$r13
+	ax
+	add.d	$r6,$r13
+	ax
+	add.d	$r7,$r13
+	ax
+	add.d	$r8,$r13
+	ax
+	add.d	$r9,$r13
+
+	;; fold the carry into the checksum, to avoid having to loop the carry
+	;; back into the top
+	
+	ax
+	addq	0,$r13
+	ax			; do it again, since we might have generated a carry
+	addq	0,$r13
+
+	subq	10*4,$r12
+	bge	_mloop
+	nop
+
+	addq	10*4,$r12	; compensate for last loop underflowing length
+
+	movem	[$sp+],$r8	; restore regs
+
+_word_loop:
+	;; only fold if there is anything to fold.
+
+	cmpq	0,$r13
+	beq	_no_fold
+
+	;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below
+	;; r9 can be used as temporary.
+	
+	move.d	$r13,$r9
+	lsrq	16,$r9		; r0 = checksum >> 16
+	and.d	0xffff,$r13	; checksum = checksum & 0xffff
+	add.d	$r9,$r13	; checksum += r0
+	move.d	$r13,$r9	; do the same again, maybe we got a carry last add
+	lsrq	16,$r9
+	and.d	0xffff,$r13
+	add.d	$r9,$r13
+	
+_no_fold:
+	cmpq	2,$r12
+	blt	_no_words
+	nop
+	
+	;; copy and checksum the rest of the words
+	
+	subq	2,$r12
+	
+_wloop:	move.w	[$r10+],$r9
+2:	;; A failing userspace access will have this as PC.
+	addu.w	$r9,$r13
+	subq	2,$r12
+	bge	_wloop
+	move.w	$r9,[$r11+]
+	
+	addq	2,$r12
+		
+_no_words:
+	;; see if we have one odd byte more
+	cmpq	1,$r12
+	beq	_do_byte
+	nop
+	ret
+	move.d	$r13, $r10
+
+_do_byte:	
+	;; copy and checksum the last byte
+	move.b	[$r10],$r9
+3:	;; A failing userspace access will have this as PC.
+	addu.b	$r9,$r13
+	move.b	$r9,[$r11]
+	ret
+	move.d	$r13, $r10
diff --git a/arch/cris/arch-v10/lib/csumcpfruser.S b/arch/cris/arch-v10/lib/csumcpfruser.S
new file mode 100644
index 0000000..5f41ccd
--- /dev/null
+++ b/arch/cris/arch-v10/lib/csumcpfruser.S
@@ -0,0 +1,64 @@
+/*
+ * Add-on to transform csum_partial_copy_nocheck in checksumcopy.S into
+ * csum_partial_copy_from_user by adding exception records.
+ *
+ * Copyright (C) 2001 Axis Communications AB.
+ *
+ * Author: Hans-Peter Nilsson.
+ */
+
+#include <asm/errno.h>
+
+/* Same function body, but a different name.  If we just added exception
+   records to _csum_partial_copy_nocheck and made it generic, we wouldn't
+   know a user fault from a kernel fault and we would have overhead in
+   each kernel caller for the error-pointer argument.
+
+   unsigned int csum_partial_copy_from_user
+     (const char *src, char *dst, int len, unsigned int sum, int *errptr);
+
+   Note that the errptr argument is only set if we encounter an error.
+   It is conveniently located on the stack, so the normal function body
+   does not have to handle it.  */
+
+#define csum_partial_copy_nocheck csum_partial_copy_from_user
+
+/* There are local labels numbered 1, 2 and 3 present to mark the
+   different from-user accesses.  */
+#include "checksumcopy.S"
+
+	.section .fixup,"ax"
+
+;; Here from the movem loop; restore stack.
+4:
+	movem	[$sp+],$r8
+;; r12 is already decremented.  Add back chunk_size-2.
+	addq	40-2,$r12
+
+;; Here from the word loop; r12 is off by 2; add it back.
+5:
+	addq	2,$r12
+
+;; Here from a failing single byte.
+6:
+
+;; Signal in *errptr that we had a failing access.
+	moveq	-EFAULT,$r9
+	move.d	$r9,[[$sp]]
+
+;; Clear the rest of the destination area using memset.  Preserve the
+;; checksum for the readable bytes.
+	push	$srp
+	push	$r13
+	move.d	$r11,$r10
+	clear.d	$r11
+	jsr	memset
+	pop	$r10
+	jump	[$sp+]
+
+	.previous
+	.section __ex_table,"a"
+	.dword 1b,4b
+	.dword 2b,5b
+	.dword 3b,6b
+	.previous
diff --git a/arch/cris/arch-v10/lib/dmacopy.c b/arch/cris/arch-v10/lib/dmacopy.c
new file mode 100644
index 0000000..e5fb44f
--- /dev/null
+++ b/arch/cris/arch-v10/lib/dmacopy.c
@@ -0,0 +1,43 @@
+/* $Id: dmacopy.c,v 1.1 2001/12/17 13:59:27 bjornw Exp $ 
+ *
+ * memcpy for large blocks, using memory-memory DMA channels 6 and 7 in Etrax
+ */
+
+#include <asm/svinto.h>
+#include <asm/io.h>
+
+#define D(x)
+
+void *dma_memcpy(void *pdst,
+		 const void *psrc,
+		 unsigned int pn)
+{
+	static etrax_dma_descr indma, outdma;
+	
+	D(printk("dma_memcpy %d bytes... ", pn));
+
+#if 0
+	*R_GEN_CONFIG = genconfig_shadow = 
+		(genconfig_shadow & ~0x3c0000) |
+		IO_STATE(R_GEN_CONFIG, dma6, intdma7) |
+		IO_STATE(R_GEN_CONFIG, dma7, intdma6);
+#endif
+	indma.sw_len = outdma.sw_len = pn;
+	indma.ctrl = d_eol | d_eop;
+	outdma.ctrl = d_eol;
+	indma.buf = psrc;
+	outdma.buf = pdst;
+
+	*R_DMA_CH6_FIRST = &indma;
+	*R_DMA_CH7_FIRST = &outdma;
+	*R_DMA_CH6_CMD = IO_STATE(R_DMA_CH6_CMD, cmd, start);
+	*R_DMA_CH7_CMD = IO_STATE(R_DMA_CH7_CMD, cmd, start);
+	
+	while(*R_DMA_CH7_CMD == 1) /* wait for completion */ ;
+
+	D(printk("done\n"));
+
+}
+
+
+
diff --git a/arch/cris/arch-v10/lib/dram_init.S b/arch/cris/arch-v10/lib/dram_init.S
new file mode 100644
index 0000000..2ef4ad57
--- /dev/null
+++ b/arch/cris/arch-v10/lib/dram_init.S
@@ -0,0 +1,205 @@
+/* $Id: dram_init.S,v 1.4 2003/09/22 09:21:59 starvik Exp $
+ * 
+ * DRAM/SDRAM initialization - alter with care
+ * This file is intended to be included from other assembler files
+ *
+ * Note: This file may not modify r9 because r9 is used to carry
+ *       information from the decompresser to the kernel
+ *
+ * Copyright (C) 2000, 2001 Axis Communications AB
+ *
+ * Authors:  Mikael Starvik (starvik@axis.com)	
+ * 
+ * $Log: dram_init.S,v $
+ * Revision 1.4  2003/09/22 09:21:59  starvik
+ * Decompresser is linked to 0x407xxxxx and sdram commands are at 0x000xxxxx
+ * so we need to mask off 12 bits.
+ *
+ * Revision 1.3  2003/03/31 09:38:37  starvik
+ * Corrected calculation of end of sdram init commands
+ *
+ * Revision 1.2  2002/11/19 13:33:29  starvik
+ * Changes from Linux 2.4
+ *
+ * Revision 1.13  2002/10/30 07:42:28  starvik
+ * Always read SDRAM command sequence from flash
+ *
+ * Revision 1.12  2002/08/09 11:37:37  orjanf
+ * Added double initialization work-around for Samsung SDRAMs.
+ *
+ * Revision 1.11  2002/06/04 11:43:21  starvik
+ * Check if mrs_data is specified in kernelconfig (necessary for MCM)
+ *
+ * Revision 1.10  2001/10/04 12:00:21  martinnn
+ * Added missing underscores.
+ *
+ * Revision 1.9  2001/10/01 14:47:35  bjornw
+ * Added register prefixes and removed underscores
+ *
+ * Revision 1.8  2001/05/15 07:12:45  hp
+ * Copy warning from head.S about r8 and r9
+ *
+ * Revision 1.7  2001/04/18 12:05:39  bjornw
+ * Fixed comments, and explicitely include config.h to be sure its there
+ *
+ * Revision 1.6  2001/04/10 06:20:16  starvik
+ * Delay should be 200us, not 200ns
+ *
+ * Revision 1.5  2001/04/09 06:01:13  starvik
+ * Added support for 100 MHz SDRAMs
+ *
+ * Revision 1.4  2001/03/26 14:24:01  bjornw
+ * Namechange of some config options
+ *
+ * Revision 1.3  2001/03/23 08:29:41  starvik
+ * Corrected calculation of mrs_data
+ *
+ * Revision 1.2  2001/02/08 15:20:00  starvik
+ * Corrected SDRAM initialization
+ * Should now be included as inline
+ *
+ * Revision 1.1  2001/01/29 13:08:02  starvik
+ * Initial version
+ * This file should be included from all assembler files that needs to
+ * initialize DRAM/SDRAM.
+ *
+ */
+
+/* Just to be certain the config file is included, we include it here
+ * explicitely instead of depending on it being included in the file that
+ * uses this code.
+ */
+
+#include <linux/config.h>
+
+	;; WARNING! 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.
+
+#ifndef CONFIG_SVINTO_SIM	
+	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]
+	
+#ifndef CONFIG_ETRAX_SDRAM
+	move.d   CONFIG_ETRAX_DEF_R_DRAM_CONFIG, $r0
+	move.d   $r0, [R_DRAM_CONFIG]
+
+	move.d   CONFIG_ETRAX_DEF_R_DRAM_TIMING, $r0
+	move.d   $r0, [R_DRAM_TIMING]
+#else
+	;; Samsung SDRAMs seem to require to be initialized twice to work properly.
+	moveq    2, $r6	
+_sdram_init:
+	
+	; Refer to ETRAX 100LX Designers Reference for a description of SDRAM initialization
+	
+	; Bank configuration
+	move.d   CONFIG_ETRAX_DEF_R_SDRAM_CONFIG, $r0
+	move.d   $r0, [R_SDRAM_CONFIG]
+
+	; Calculate value of mrs_data 
+	; CAS latency = 2 && bus_width = 32 => 0x40
+	; CAS latency = 3 && bus_width = 32 => 0x60
+	; CAS latency = 2 && bus_width = 16 => 0x20
+	; CAS latency = 3 && bus_width = 16 => 0x30
+
+	; Check if value is already supplied in kernel config
+	move.d   CONFIG_ETRAX_DEF_R_SDRAM_TIMING, $r2
+	and.d    0x00ff0000, $r2
+	bne	 _set_timing
+	lsrq     16, $r2
+	
+	move.d   0x40, $r2       ; Assume 32 bits and CAS latency = 2
+	move.d   CONFIG_ETRAX_DEF_R_SDRAM_TIMING, $r1
+	move.d   $r1, $r3
+ 	and.d    0x03, $r1       ; Get CAS latency
+	and.d    0x1000, $r3     ; 50 or 100 MHz?
+	beq      _speed_50
+	nop
+_speed_100:		
+	cmp.d    0x00, $r1	; CAS latency = 2?
+	beq      _bw_check
+	nop
+	or.d     0x20, $r2	; CAS latency = 3 
+	ba       _bw_check
+	nop
+_speed_50:			
+	cmp.d    0x01, $r1	; CAS latency = 2?
+	beq      _bw_check
+	nop
+	or.d     0x20, $r2       ; CAS latency = 3
+_bw_check:
+	move.d   CONFIG_ETRAX_DEF_R_SDRAM_CONFIG, $r1
+	and.d    0x800000, $r1	; DRAM width is bit 23
+	bne      _set_timing
+	nop
+	lsrq     1, $r2		;  16 bits. Shift down value.
+
+	; Set timing parameters. Starts master clock
+_set_timing:
+	move.d   CONFIG_ETRAX_DEF_R_SDRAM_TIMING, $r1
+	and.d    0x8000f9ff, $r1 ; Make sure mrs data and command is 0 
+	or.d     0x80000000, $r1	; Make sure sdram enable bit is set
+	move.d   $r1, $r5
+	or.d     0x0000c000, $r1 ; ref = disable
+	lslq     16, $r2		; mrs data starts at bit 16
+	or.d     $r2, $r1 
+	move.d   $r1, [R_SDRAM_TIMING]	
+		
+	; Wait 200us
+	move.d   10000, $r2
+1:	bne      1b
+	subq     1, $r2
+	
+	; Issue initialization command sequence
+	move.d   _sdram_commands_start, $r2
+	and.d    0x000fffff, $r2 ; Make sure commands are read from flash
+	move.d   _sdram_commands_end,  $r3
+	and.d    0x000fffff, $r3
+1:	clear.d  $r4
+	move.b   [$r2+], $r4
+	lslq     9, $r4	; Command starts at bit 9
+	or.d     $r1, $r4
+	move.d   $r4, [R_SDRAM_TIMING]
+	nop		; Wait five nop cycles between each command
+	nop
+	nop
+	nop
+	nop
+	cmp.d    $r2, $r3
+	bne      1b
+	nop
+	move.d   $r5, [R_SDRAM_TIMING]
+	subq     1, $r6
+	bne      _sdram_init
+	nop
+	ba       _sdram_commands_end
+	nop
+
+_sdram_commands_start:
+	.byte   3	; Precharge
+	.byte   0       ; nop
+	.byte   2	; refresh
+	.byte   0	; nop
+	.byte   2	; refresh
+	.byte   0	; nop
+	.byte   2	; refresh
+	.byte   0	; nop
+	.byte   2	; refresh
+	.byte   0	; nop
+	.byte   2	; refresh
+	.byte   0	; nop
+	.byte   2	; refresh
+	.byte   0	; nop
+	.byte   2	; refresh
+	.byte   0	; nop
+	.byte   2	; refresh
+	.byte   0	; nop
+	.byte   1	; mrs
+	.byte   0	; nop 
+_sdram_commands_end:		
+#endif
+#endif
diff --git a/arch/cris/arch-v10/lib/hw_settings.S b/arch/cris/arch-v10/lib/hw_settings.S
new file mode 100644
index 0000000..56905aa
--- /dev/null
+++ b/arch/cris/arch-v10/lib/hw_settings.S
@@ -0,0 +1,62 @@
+/*
+ * $Id: hw_settings.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $
+ * 
+ * This table is used by some tools to extract hardware parameters.
+ * The table should be included in the kernel and the decompressor.
+ * Don't forget to update the tools if you change this table.
+ *
+ * Copyright (C) 2001 Axis Communications AB
+ *
+ * Authors:  Mikael Starvik (starvik@axis.com)	
+ */
+
+#define PA_SET_VALUE ((CONFIG_ETRAX_DEF_R_PORT_PA_DIR << 8) | \
+		(CONFIG_ETRAX_DEF_R_PORT_PA_DATA))
+#define PB_SET_VALUE ((CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG << 16) | \
+		(CONFIG_ETRAX_DEF_R_PORT_PB_DIR << 8) | \
+		(CONFIG_ETRAX_DEF_R_PORT_PB_DATA))
+	
+	.ascii "HW_PARAM_MAGIC" ; Magic number
+	.dword 0xc0004000	; Kernel start address
+
+	; Debug port
+#ifdef CONFIG_ETRAX_DEBUG_PORT0
+	.dword 0		
+#elif defined(CONFIG_ETRAX_DEBUG_PORT1)
+	.dword 1
+#elif defined(CONFIG_ETRAX_DEBUG_PORT2)
+	.dword 2
+#elif defined(CONFIG_ETRAX_DEBUG_PORT3)
+	.dword 3
+#else
+	.dword 4 ; No debug
+#endif			
+
+	; SDRAM or EDO DRAM?
+#ifdef CONFIG_ETRAX_SDRAM
+	.dword 1
+#else
+	.dword 0
+#endif
+
+	; Register values 
+	.dword R_WAITSTATES
+	.dword CONFIG_ETRAX_DEF_R_WAITSTATES
+	.dword R_BUS_CONFIG
+	.dword CONFIG_ETRAX_DEF_R_BUS_CONFIG
+#ifdef CONFIG_ETRAX_SDRAM
+	.dword R_SDRAM_CONFIG
+	.dword CONFIG_ETRAX_DEF_R_SDRAM_CONFIG
+	.dword R_SDRAM_TIMING
+	.dword CONFIG_ETRAX_DEF_R_SDRAM_TIMING
+#else
+	.dword R_DRAM_CONFIG
+	.dword CONFIG_ETRAX_DEF_R_DRAM_CONFIG
+	.dword R_DRAM_TIMING
+	.dword CONFIG_ETRAX_DEF_R_DRAM_TIMING
+#endif
+	.dword R_PORT_PA_SET
+	.dword PA_SET_VALUE 
+	.dword R_PORT_PB_SET
+	.dword PB_SET_VALUE
+	.dword 0 ; No more register values
diff --git a/arch/cris/arch-v10/lib/memset.c b/arch/cris/arch-v10/lib/memset.c
new file mode 100644
index 0000000..82bb668
--- /dev/null
+++ b/arch/cris/arch-v10/lib/memset.c
@@ -0,0 +1,252 @@
+/*#************************************************************************#*/
+/*#-------------------------------------------------------------------------*/
+/*#                                                                         */
+/*# FUNCTION NAME: memset()                                                 */
+/*#                                                                         */
+/*# PARAMETERS:  void* dst;   Destination address.                          */
+/*#              int     c;   Value of byte to write.                       */
+/*#              int   len;   Number of bytes to write.                     */
+/*#                                                                         */
+/*# RETURNS:     dst.                                                       */
+/*#                                                                         */
+/*# DESCRIPTION: Sets the memory dst of length len bytes to c, as standard. */
+/*#              Framework taken from memcpy.  This routine is              */
+/*#              very sensitive to compiler changes in register allocation. */
+/*#              Should really be rewritten to avoid this problem.          */
+/*#                                                                         */
+/*#-------------------------------------------------------------------------*/
+/*#                                                                         */
+/*# HISTORY                                                                 */
+/*#                                                                         */
+/*# DATE      NAME            CHANGES                                       */
+/*# ----      ----            -------                                       */
+/*# 990713    HP              Tired of watching this function (or           */
+/*#                           really, the nonoptimized generic              */
+/*#                           implementation) take up 90% of simulator      */
+/*#                           output.  Measurements needed.                 */
+/*#                                                                         */
+/*#-------------------------------------------------------------------------*/
+
+#include <linux/types.h>
+
+/* No, there's no macro saying 12*4, since it is "hard" to get it into
+   the asm in a good way.  Thus better to expose the problem everywhere.
+   */
+
+/* Assuming 1 cycle per dword written or read (ok, not really true), and
+   one per instruction, then 43+3*(n/48-1) <= 24+24*(n/48-1)
+   so n >= 45.7; n >= 0.9; we win on the first full 48-byte block to set. */
+
+#define ZERO_BLOCK_SIZE (1*12*4)
+
+void *memset(void *pdst,
+             int c,
+             size_t plen)
+{
+  /* Ok.  Now we want the parameters put in special registers.
+     Make sure the compiler is able to make something useful of this. */
+
+  register char *return_dst __asm__ ("r10") = pdst;
+  register int n __asm__ ("r12") = plen;
+  register int lc __asm__ ("r11") = c;
+
+  /* Most apps use memset sanely.  Only those memsetting about 3..4
+     bytes or less get penalized compared to the generic implementation
+     - and that's not really sane use. */
+
+  /* Ugh.  This is fragile at best.  Check with newer GCC releases, if
+     they compile cascaded "x |= x << 8" sanely! */
+  __asm__("movu.b %0,$r13\n\t"
+          "lslq 8,$r13\n\t"
+	  "move.b %0,$r13\n\t"
+	  "move.d $r13,%0\n\t"
+	  "lslq 16,$r13\n\t"
+	  "or.d $r13,%0"
+          : "=r" (lc) : "0" (lc) : "r13");
+
+  {
+    register char *dst __asm__ ("r13") = pdst;
+ 
+  /* This is NONPORTABLE, but since this whole routine is     */
+  /* grossly nonportable that doesn't matter.                 */
+
+  if (((unsigned long) pdst & 3) != 0
+     /* Oops! n=0 must be a legal call, regardless of alignment. */
+      && n >= 3)
+  {
+    if ((unsigned long)dst & 1)
+    {
+      *dst = (char) lc;
+      n--;
+      dst++;
+    }
+
+    if ((unsigned long)dst & 2)
+    {
+      *(short *)dst = lc;
+      n -= 2;
+      dst += 2;
+    }
+  }
+
+  /* Now the fun part.  For the threshold value of this, check the equation
+     above. */
+  /* Decide which copying method to use. */
+  if (n >= ZERO_BLOCK_SIZE)
+  {
+    /* For large copies we use 'movem' */
+
+  /* It is not optimal to tell the compiler about clobbering any
+     registers; that will move the saving/restoring of those registers
+     to the function prologue/epilogue, and make non-movem sizes
+     suboptimal.
+
+      This method is not foolproof; it assumes that the "asm reg"
+     declarations at the beginning of the function really are used
+     here (beware: they may be moved to temporary registers).
+      This way, we do not have to save/move the registers around into
+     temporaries; we can safely use them straight away.
+
+      If you want to check that the allocation was right; then
+      check the equalities in the first comment.  It should say
+      "r13=r13, r12=r12, r11=r11" */
+    __asm__ volatile ("
+        ;; Check that the following is true (same register names on
+        ;; both sides of equal sign, as in r8=r8):
+        ;; %0=r13, %1=r12, %4=r11
+        ;;
+	;; Save the registers we'll clobber in the movem process
+	;; on the stack.  Don't mention them to gcc, it will only be
+	;; upset.
+	subq 	11*4,$sp
+        movem   $r10,[$sp]
+
+        move.d  $r11,$r0
+        move.d  $r11,$r1
+        move.d  $r11,$r2
+        move.d  $r11,$r3
+        move.d  $r11,$r4
+        move.d  $r11,$r5
+        move.d  $r11,$r6
+        move.d  $r11,$r7
+        move.d  $r11,$r8
+        move.d  $r11,$r9
+        move.d  $r11,$r10
+
+        ;; Now we've got this:
+	;; r13 - dst
+	;; r12 - n
+	
+        ;; Update n for the first loop
+        subq    12*4,$r12
+0:
+        subq   12*4,$r12
+        bge     0b
+	movem	$r11,[$r13+]
+
+        addq   12*4,$r12  ;; compensate for last loop underflowing n
+
+	;; Restore registers from stack
+        movem [$sp+],$r10" 
+
+     /* Outputs */ : "=r" (dst), "=r" (n)
+     /* Inputs */ : "0" (dst), "1" (n), "r" (lc));
+    
+  }
+
+    /* Either we directly starts copying, using dword copying
+       in a loop, or we copy as much as possible with 'movem' 
+       and then the last block (<44 bytes) is copied here.
+       This will work since 'movem' will have updated src,dst,n. */
+
+    while ( n >= 16 )
+    {
+      *((long*)dst)++ = lc;
+      *((long*)dst)++ = lc;
+      *((long*)dst)++ = lc;
+      *((long*)dst)++ = lc;
+      n -= 16;
+    }
+
+    /* A switch() is definitely the fastest although it takes a LOT of code.
+     * Particularly if you inline code this.
+     */
+    switch (n)
+    {
+      case 0:
+        break;
+      case 1:
+        *(char*)dst = (char) lc;
+        break;
+      case 2:
+        *(short*)dst = (short) lc;
+        break;
+      case 3:
+        *((short*)dst)++ = (short) lc;
+        *(char*)dst = (char) lc;
+        break;
+      case 4:
+        *((long*)dst)++ = lc;
+        break;
+      case 5:
+        *((long*)dst)++ = lc;
+        *(char*)dst = (char) lc;
+        break;
+      case 6:
+        *((long*)dst)++ = lc;
+        *(short*)dst = (short) lc;
+        break;
+      case 7:
+        *((long*)dst)++ = lc;
+        *((short*)dst)++ = (short) lc;
+        *(char*)dst = (char) lc;
+        break;
+      case 8:
+        *((long*)dst)++ = lc;
+        *((long*)dst)++ = lc;
+        break;
+      case 9:
+        *((long*)dst)++ = lc;
+        *((long*)dst)++ = lc;
+        *(char*)dst = (char) lc;
+        break;
+      case 10:
+        *((long*)dst)++ = lc;
+        *((long*)dst)++ = lc;
+        *(short*)dst = (short) lc;
+        break;
+      case 11:
+        *((long*)dst)++ = lc;
+        *((long*)dst)++ = lc;
+        *((short*)dst)++ = (short) lc;
+        *(char*)dst = (char) lc;
+        break;
+      case 12:
+        *((long*)dst)++ = lc;
+        *((long*)dst)++ = lc;
+        *((long*)dst)++ = lc;
+        break;
+      case 13:
+        *((long*)dst)++ = lc;
+        *((long*)dst)++ = lc;
+        *((long*)dst)++ = lc;
+        *(char*)dst = (char) lc;
+        break;
+      case 14:
+        *((long*)dst)++ = lc;
+        *((long*)dst)++ = lc;
+        *((long*)dst)++ = lc;
+        *(short*)dst = (short) lc;
+        break;
+      case 15:
+        *((long*)dst)++ = lc;
+        *((long*)dst)++ = lc;
+        *((long*)dst)++ = lc;
+        *((short*)dst)++ = (short) lc;
+        *(char*)dst = (char) lc;
+        break;
+    }
+  }
+
+  return return_dst; /* destination pointer. */
+} /* memset() */
diff --git a/arch/cris/arch-v10/lib/old_checksum.c b/arch/cris/arch-v10/lib/old_checksum.c
new file mode 100644
index 0000000..22a6f0a
--- /dev/null
+++ b/arch/cris/arch-v10/lib/old_checksum.c
@@ -0,0 +1,85 @@
+/* $Id: old_checksum.c,v 1.3 2003/10/27 08:04:32 starvik Exp $
+ *
+ * INET		An implementation of the TCP/IP protocol suite for the LINUX
+ *		operating system.  INET is implemented using the  BSD Socket
+ *		interface as the means of communication with the user level.
+ *
+ *		IP/TCP/UDP checksumming routines
+ *
+ * Authors:	Jorge Cwik, <jorge@laser.satlink.net>
+ *		Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ *		Tom May, <ftom@netcom.com>
+ *		Lots of code moved from tcp.c and ip.c; see those files
+ *		for more names.
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ */
+
+#include <net/checksum.h>
+#include <net/module.h>
+
+#undef PROFILE_CHECKSUM
+
+#ifdef PROFILE_CHECKSUM
+/* these are just for profiling the checksum code with an oscillioscope.. uh */
+#if 0
+#define BITOFF *((unsigned char *)0xb0000030) = 0xff
+#define BITON *((unsigned char *)0xb0000030) = 0x0
+#endif
+#include <asm/io.h>
+#define CBITON LED_ACTIVE_SET(1)
+#define CBITOFF LED_ACTIVE_SET(0)
+#define BITOFF
+#define BITON
+#else
+#define BITOFF
+#define BITON
+#define CBITOFF
+#define CBITON
+#endif
+
+/*
+ * computes a partial checksum, e.g. for TCP/UDP fragments
+ */
+
+#include <asm/delay.h>
+
+unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
+{
+  /*
+   * Experiments with ethernet and slip connections show that buff
+   * is aligned on either a 2-byte or 4-byte boundary.
+   */
+  const unsigned char *endMarker = buff + len;
+  const unsigned char *marker = endMarker - (len % 16);
+#if 0
+  if((int)buff & 0x3)
+    printk("unaligned buff %p\n", buff);
+  __delay(900); /* extra delay of 90 us to test performance hit */
+#endif
+  BITON;
+  while (buff < marker) {
+    sum += *((unsigned short *)buff)++;
+    sum += *((unsigned short *)buff)++;
+    sum += *((unsigned short *)buff)++;
+    sum += *((unsigned short *)buff)++;
+    sum += *((unsigned short *)buff)++;
+    sum += *((unsigned short *)buff)++;
+    sum += *((unsigned short *)buff)++;
+    sum += *((unsigned short *)buff)++;
+  }
+  marker = endMarker - (len % 2);
+  while(buff < marker) {
+    sum += *((unsigned short *)buff)++;
+  }
+  if(endMarker - buff > 0) {
+    sum += *buff;                 /* add extra byte seperately */
+  }
+  BITOFF;
+  return(sum);
+}
+
+EXPORT_SYMBOL(csum_partial);
diff --git a/arch/cris/arch-v10/lib/string.c b/arch/cris/arch-v10/lib/string.c
new file mode 100644
index 0000000..8ffde49
--- /dev/null
+++ b/arch/cris/arch-v10/lib/string.c
@@ -0,0 +1,225 @@
+/*#************************************************************************#*/
+/*#-------------------------------------------------------------------------*/
+/*#                                                                         */
+/*# FUNCTION NAME: memcpy()                                                 */
+/*#                                                                         */
+/*# PARAMETERS:  void* dst;   Destination address.                          */
+/*#              void* src;   Source address.                               */
+/*#              int   len;   Number of bytes to copy.                      */
+/*#                                                                         */
+/*# RETURNS:     dst.                                                       */
+/*#                                                                         */
+/*# DESCRIPTION: Copies len bytes of memory from src to dst.  No guarantees */
+/*#              about copying of overlapping memory areas. This routine is */
+/*#              very sensitive to compiler changes in register allocation. */
+/*#              Should really be rewritten to avoid this problem.          */
+/*#                                                                         */
+/*#-------------------------------------------------------------------------*/
+/*#                                                                         */
+/*# HISTORY                                                                 */
+/*#                                                                         */
+/*# DATE      NAME            CHANGES                                       */
+/*# ----      ----            -------                                       */
+/*# 941007    Kenny R         Creation                                      */
+/*# 941011    Kenny R         Lots of optimizations and inlining.           */
+/*# 941129    Ulf A           Adapted for use in libc.                      */
+/*# 950216    HP              N==0 forgotten if non-aligned src/dst.        */
+/*#                           Added some optimizations.                     */
+/*# 001025    HP              Make src and dst char *.  Align dst to	    */
+/*#			      dword, not just word-if-both-src-and-dst-	    */
+/*#			      are-misaligned.				    */
+/*#                                                                         */
+/*#-------------------------------------------------------------------------*/
+
+#include <linux/types.h>
+
+void *memcpy(void *pdst,
+             const void *psrc,
+             size_t pn)
+{
+  /* Ok.  Now we want the parameters put in special registers.
+     Make sure the compiler is able to make something useful of this.
+      As it is now: r10 -> r13; r11 -> r11 (nop); r12 -> r12 (nop).
+
+     If gcc was allright, it really would need no temporaries, and no
+     stack space to save stuff on. */
+
+  register void *return_dst __asm__ ("r10") = pdst;
+  register char *dst __asm__ ("r13") = pdst;
+  register const char *src __asm__ ("r11") = psrc;
+  register int n __asm__ ("r12") = pn;
+  
+ 
+  /* When src is aligned but not dst, this makes a few extra needless
+     cycles.  I believe it would take as many to check that the
+     re-alignment was unnecessary.  */
+  if (((unsigned long) dst & 3) != 0
+      /* Don't align if we wouldn't copy more than a few bytes; so we
+	 don't have to check further for overflows.  */
+      && n >= 3)
+  {
+    if ((unsigned long) dst & 1)
+    {
+      n--;
+      *(char*)dst = *(char*)src;
+      src++;
+      dst++;
+    }
+
+    if ((unsigned long) dst & 2)
+    {
+      n -= 2;
+      *(short*)dst = *(short*)src;
+      src += 2;
+      dst += 2;
+    }
+  }
+
+  /* Decide which copying method to use. */
+  if (n >= 44*2)                /* Break even between movem and
+                                   move16 is at 38.7*2, but modulo 44. */
+  {
+    /* For large copies we use 'movem' */
+
+  /* It is not optimal to tell the compiler about clobbering any
+     registers; that will move the saving/restoring of those registers
+     to the function prologue/epilogue, and make non-movem sizes
+     suboptimal.
+
+      This method is not foolproof; it assumes that the "asm reg"
+     declarations at the beginning of the function really are used
+     here (beware: they may be moved to temporary registers).
+      This way, we do not have to save/move the registers around into
+     temporaries; we can safely use them straight away.
+
+      If you want to check that the allocation was right; then
+      check the equalities in the first comment.  It should say
+      "r13=r13, r11=r11, r12=r12" */
+    __asm__ volatile ("
+        ;; Check that the following is true (same register names on
+        ;; both sides of equal sign, as in r8=r8):
+        ;; %0=r13, %1=r11, %2=r12
+        ;;
+	;; Save the registers we'll use in the movem process
+	;; on the stack.
+	subq 	11*4,$sp
+	movem	$r10,[$sp]
+
+        ;; Now we've got this:
+	;; r11 - src
+	;; r13 - dst
+	;; r12 - n
+	
+        ;; Update n for the first loop
+        subq    44,$r12
+0:
+	movem	[$r11+],$r10
+        subq   44,$r12
+        bge     0b
+	movem	$r10,[$r13+]
+
+        addq   44,$r12  ;; compensate for last loop underflowing n
+
+	;; Restore registers from stack
+        movem [$sp+],$r10" 
+
+     /* Outputs */ : "=r" (dst), "=r" (src), "=r" (n) 
+     /* Inputs */ : "0" (dst), "1" (src), "2" (n));
+    
+  }
+
+  /* Either we directly starts copying, using dword copying
+     in a loop, or we copy as much as possible with 'movem' 
+     and then the last block (<44 bytes) is copied here.
+     This will work since 'movem' will have updated src,dst,n. */
+
+  while ( n >= 16 )
+  {
+    *((long*)dst)++ = *((long*)src)++;
+    *((long*)dst)++ = *((long*)src)++;
+    *((long*)dst)++ = *((long*)src)++;
+    *((long*)dst)++ = *((long*)src)++;
+    n -= 16;
+  }
+
+  /* A switch() is definitely the fastest although it takes a LOT of code.
+   * Particularly if you inline code this.
+   */
+  switch (n)
+  {
+    case 0:
+      break;
+    case 1:
+      *(char*)dst = *(char*)src;
+      break;
+    case 2:
+      *(short*)dst = *(short*)src;
+      break;
+    case 3:
+      *((short*)dst)++ = *((short*)src)++;
+      *(char*)dst = *(char*)src;
+      break;
+    case 4:
+      *((long*)dst)++ = *((long*)src)++;
+      break;
+    case 5:
+      *((long*)dst)++ = *((long*)src)++;
+      *(char*)dst = *(char*)src;
+      break;
+    case 6:
+      *((long*)dst)++ = *((long*)src)++;
+      *(short*)dst = *(short*)src;
+      break;
+    case 7:
+      *((long*)dst)++ = *((long*)src)++;
+      *((short*)dst)++ = *((short*)src)++;
+      *(char*)dst = *(char*)src;
+      break;
+    case 8:
+      *((long*)dst)++ = *((long*)src)++;
+      *((long*)dst)++ = *((long*)src)++;
+      break;
+    case 9:
+      *((long*)dst)++ = *((long*)src)++;
+      *((long*)dst)++ = *((long*)src)++;
+      *(char*)dst = *(char*)src;
+      break;
+    case 10:
+      *((long*)dst)++ = *((long*)src)++;
+      *((long*)dst)++ = *((long*)src)++;
+      *(short*)dst = *(short*)src;
+      break;
+    case 11:
+      *((long*)dst)++ = *((long*)src)++;
+      *((long*)dst)++ = *((long*)src)++;
+      *((short*)dst)++ = *((short*)src)++;
+      *(char*)dst = *(char*)src;
+      break;
+    case 12:
+      *((long*)dst)++ = *((long*)src)++;
+      *((long*)dst)++ = *((long*)src)++;
+      *((long*)dst)++ = *((long*)src)++;
+      break;
+    case 13:
+      *((long*)dst)++ = *((long*)src)++;
+      *((long*)dst)++ = *((long*)src)++;
+      *((long*)dst)++ = *((long*)src)++;
+      *(char*)dst = *(char*)src;
+      break;
+    case 14:
+      *((long*)dst)++ = *((long*)src)++;
+      *((long*)dst)++ = *((long*)src)++;
+      *((long*)dst)++ = *((long*)src)++;
+      *(short*)dst = *(short*)src;
+      break;
+    case 15:
+      *((long*)dst)++ = *((long*)src)++;
+      *((long*)dst)++ = *((long*)src)++;
+      *((long*)dst)++ = *((long*)src)++;
+      *((short*)dst)++ = *((short*)src)++;
+      *(char*)dst = *(char*)src;
+      break;
+  }
+
+  return return_dst; /* destination pointer. */
+} /* memcpy() */
diff --git a/arch/cris/arch-v10/lib/usercopy.c b/arch/cris/arch-v10/lib/usercopy.c
new file mode 100644
index 0000000..43778d5
--- /dev/null
+++ b/arch/cris/arch-v10/lib/usercopy.c
@@ -0,0 +1,523 @@
+/*
+ * User address space access functions.
+ * The non-inlined parts of asm-cris/uaccess.h are here.
+ *
+ * Copyright (C) 2000, Axis Communications AB.
+ *
+ * Written by Hans-Peter Nilsson.
+ * Pieces used from memcpy, originally by Kenny Ranerup long time ago.
+ */
+
+#include <asm/uaccess.h>
+
+/* Asm:s have been tweaked (within the domain of correctness) to give
+   satisfactory results for "gcc version 2.96 20000427 (experimental)".
+
+   Check regularly...
+
+   Note that the PC saved at a bus-fault is the address *after* the
+   faulting instruction, which means the branch-target for instructions in
+   delay-slots for taken branches.  Note also that the postincrement in
+   the instruction is performed regardless of bus-fault; the register is
+   seen updated in fault handlers.
+
+   Oh, and on the code formatting issue, to whomever feels like "fixing
+   it" to Conformity: I'm too "lazy", but why don't you go ahead and "fix"
+   string.c too.  I just don't think too many people will hack this file
+   for the code format to be an issue.  */
+
+
+/* Copy to userspace.  This is based on the memcpy used for
+   kernel-to-kernel copying; see "string.c".  */
+
+unsigned long
+__copy_user (void __user *pdst, const void *psrc, unsigned long pn)
+{
+  /* We want the parameters put in special registers.
+     Make sure the compiler is able to make something useful of this.
+     As it is now: r10 -> r13; r11 -> r11 (nop); r12 -> r12 (nop).
+
+     FIXME: Comment for old gcc version.  Check.
+     If gcc was allright, it really would need no temporaries, and no
+     stack space to save stuff on. */
+
+  register char *dst __asm__ ("r13") = pdst;
+  register const char *src __asm__ ("r11") = psrc;
+  register int n __asm__ ("r12") = pn;
+  register int retn __asm__ ("r10") = 0;
+
+
+  /* When src is aligned but not dst, this makes a few extra needless
+     cycles.  I believe it would take as many to check that the
+     re-alignment was unnecessary.  */
+  if (((unsigned long) dst & 3) != 0
+      /* Don't align if we wouldn't copy more than a few bytes; so we
+	 don't have to check further for overflows.  */
+      && n >= 3)
+  {
+    if ((unsigned long) dst & 1)
+    {
+      __asm_copy_to_user_1 (dst, src, retn);
+      n--;
+    }
+
+    if ((unsigned long) dst & 2)
+    {
+      __asm_copy_to_user_2 (dst, src, retn);
+      n -= 2;
+    }
+  }
+
+  /* Decide which copying method to use. */
+  if (n >= 44*2)		/* Break even between movem and
+				   move16 is at 38.7*2, but modulo 44. */
+  {
+    /* For large copies we use 'movem'.  */
+
+    /* It is not optimal to tell the compiler about clobbering any
+       registers; that will move the saving/restoring of those registers
+       to the function prologue/epilogue, and make non-movem sizes
+       suboptimal.
+
+       This method is not foolproof; it assumes that the "asm reg"
+       declarations at the beginning of the function really are used
+       here (beware: they may be moved to temporary registers).
+       This way, we do not have to save/move the registers around into
+       temporaries; we can safely use them straight away.
+
+       If you want to check that the allocation was right; then
+       check the equalities in the first comment.  It should say
+       "r13=r13, r11=r11, r12=r12".  */
+    __asm__ volatile ("\
+	.ifnc %0%1%2%3,$r13$r11$r12$r10					\n\
+	.err								\n\
+	.endif								\n\
+
+	;; Save the registers we'll use in the movem process
+	;; on the stack.
+	subq	11*4,$sp
+	movem	$r10,[$sp]
+
+	;; Now we've got this:
+	;; r11 - src
+	;; r13 - dst
+	;; r12 - n
+
+	;; Update n for the first loop
+	subq	44,$r12
+
+; Since the noted PC of a faulting instruction in a delay-slot of a taken
+; branch, is that of the branch target, we actually point at the from-movem
+; for this case.  There is no ambiguity here; if there was a fault in that
+; instruction (meaning a kernel oops), the faulted PC would be the address
+; after *that* movem.
+
+0:
+	movem	[$r11+],$r10
+	subq   44,$r12
+	bge	0b
+	movem	$r10,[$r13+]
+1:
+	addq   44,$r12  ;; compensate for last loop underflowing n
+
+	;; Restore registers from stack
+	movem [$sp+],$r10
+2:
+	.section .fixup,\"ax\"
+
+; To provide a correct count in r10 of bytes that failed to be copied,
+; we jump back into the loop if the loop-branch was taken.  There is no
+; performance penalty for sany use; the program will segfault soon enough.
+
+3:
+	move.d [$sp],$r10
+	addq 44,$r10
+	move.d $r10,[$sp]
+	jump 0b
+4:
+	movem [$sp+],$r10
+	addq 44,$r10
+	addq 44,$r12
+	jump 2b
+
+	.previous
+	.section __ex_table,\"a\"
+	.dword 0b,3b
+	.dword 1b,4b
+	.previous"
+
+     /* Outputs */ : "=r" (dst), "=r" (src), "=r" (n), "=r" (retn)
+     /* Inputs */ : "0" (dst), "1" (src), "2" (n), "3" (retn));
+
+  }
+
+  /* Either we directly start copying, using dword copying in a loop, or
+     we copy as much as possible with 'movem' and then the last block (<44
+     bytes) is copied here.  This will work since 'movem' will have
+     updated SRC, DST and N.  */
+
+  while (n >= 16)
+  {
+    __asm_copy_to_user_16 (dst, src, retn);
+    n -= 16;
+  }
+
+  /* Having a separate by-four loops cuts down on cache footprint.
+     FIXME:  Test with and without; increasing switch to be 0..15.  */
+  while (n >= 4)
+  {
+    __asm_copy_to_user_4 (dst, src, retn);
+    n -= 4;
+  }
+
+  switch (n)
+  {
+    case 0:
+      break;
+    case 1:
+      __asm_copy_to_user_1 (dst, src, retn);
+      break;
+    case 2:
+      __asm_copy_to_user_2 (dst, src, retn);
+      break;
+    case 3:
+      __asm_copy_to_user_3 (dst, src, retn);
+      break;
+  }
+
+  return retn;
+}
+
+/* Copy from user to kernel, zeroing the bytes that were inaccessible in
+   userland.  The return-value is the number of bytes that were
+   inaccessible.  */
+
+unsigned long
+__copy_user_zeroing (void __user *pdst, const void *psrc, unsigned long pn)
+{
+  /* We want the parameters put in special registers.
+     Make sure the compiler is able to make something useful of this.
+     As it is now: r10 -> r13; r11 -> r11 (nop); r12 -> r12 (nop).
+
+     FIXME: Comment for old gcc version.  Check.
+     If gcc was allright, it really would need no temporaries, and no
+     stack space to save stuff on.  */
+
+  register char *dst __asm__ ("r13") = pdst;
+  register const char *src __asm__ ("r11") = psrc;
+  register int n __asm__ ("r12") = pn;
+  register int retn __asm__ ("r10") = 0;
+
+  /* The best reason to align src is that we then know that a read-fault
+     was for aligned bytes; there's no 1..3 remaining good bytes to
+     pickle.  */
+  if (((unsigned long) src & 3) != 0)
+  {
+    if (((unsigned long) src & 1) && n != 0)
+    {
+      __asm_copy_from_user_1 (dst, src, retn);
+      n--;
+    }
+
+    if (((unsigned long) src & 2) && n >= 2)
+    {
+      __asm_copy_from_user_2 (dst, src, retn);
+      n -= 2;
+    }
+
+    /* We only need one check after the unalignment-adjustments, because
+       if both adjustments were done, either both or neither reference
+       had an exception.  */
+    if (retn != 0)
+      goto copy_exception_bytes;
+  }
+
+  /* Decide which copying method to use. */
+  if (n >= 44*2)		/* Break even between movem and
+				   move16 is at 38.7*2, but modulo 44.
+				   FIXME: We use move4 now.  */
+  {
+    /* For large copies we use 'movem' */
+
+    /* It is not optimal to tell the compiler about clobbering any
+       registers; that will move the saving/restoring of those registers
+       to the function prologue/epilogue, and make non-movem sizes
+       suboptimal.
+
+       This method is not foolproof; it assumes that the "asm reg"
+       declarations at the beginning of the function really are used
+       here (beware: they may be moved to temporary registers).
+       This way, we do not have to save/move the registers around into
+       temporaries; we can safely use them straight away.
+
+       If you want to check that the allocation was right; then
+       check the equalities in the first comment.  It should say
+       "r13=r13, r11=r11, r12=r12" */
+    __asm__ volatile ("
+	.ifnc %0%1%2%3,$r13$r11$r12$r10					\n\
+	.err								\n\
+	.endif								\n\
+
+	;; Save the registers we'll use in the movem process
+	;; on the stack.
+	subq	11*4,$sp
+	movem	$r10,[$sp]
+
+	;; Now we've got this:
+	;; r11 - src
+	;; r13 - dst
+	;; r12 - n
+
+	;; Update n for the first loop
+	subq	44,$r12
+0:
+	movem	[$r11+],$r10
+1:
+	subq   44,$r12
+	bge	0b
+	movem	$r10,[$r13+]
+
+	addq   44,$r12  ;; compensate for last loop underflowing n
+
+	;; Restore registers from stack
+	movem [$sp+],$r10
+4:
+	.section .fixup,\"ax\"
+
+;; Do not jump back into the loop if we fail.  For some uses, we get a
+;; page fault somewhere on the line.  Without checking for page limits,
+;; we don't know where, but we need to copy accurately and keep an
+;; accurate count; not just clear the whole line.  To do that, we fall
+;; down in the code below, proceeding with smaller amounts.  It should
+;; be kept in mind that we have to cater to code like what at one time
+;; was in fs/super.c:
+;;  i = size - copy_from_user((void *)page, data, size);
+;; which would cause repeated faults while clearing the remainder of
+;; the SIZE bytes at PAGE after the first fault.
+;; A caveat here is that we must not fall through from a failing page
+;; to a valid page.
+
+3:
+	movem  [$sp+],$r10
+	addq	44,$r12 ;; Get back count before faulting point.
+	subq	44,$r11 ;; Get back pointer to faulting movem-line.
+	jump	4b	;; Fall through, pretending the fault didn't happen.
+
+	.previous
+	.section __ex_table,\"a\"
+	.dword 1b,3b
+	.previous"
+
+     /* Outputs */ : "=r" (dst), "=r" (src), "=r" (n), "=r" (retn)
+     /* Inputs */ : "0" (dst), "1" (src), "2" (n), "3" (retn));
+
+  }
+
+  /* Either we directly start copying here, using dword copying in a loop,
+     or we copy as much as possible with 'movem' and then the last block
+     (<44 bytes) is copied here.  This will work since 'movem' will have
+     updated src, dst and n.  (Except with failing src.)
+
+     Since we want to keep src accurate, we can't use
+     __asm_copy_from_user_N with N != (1, 2, 4); it updates dst and
+     retn, but not src (by design; it's value is ignored elsewhere).  */
+
+  while (n >= 4)
+  {
+    __asm_copy_from_user_4 (dst, src, retn);
+    n -= 4;
+
+    if (retn)
+      goto copy_exception_bytes;
+  }
+
+  /* If we get here, there were no memory read faults.  */
+  switch (n)
+  {
+    /* These copies are at least "naturally aligned" (so we don't have
+       to check each byte), due to the src alignment code before the
+       movem loop.  The *_3 case *will* get the correct count for retn.  */
+    case 0:
+      /* This case deliberately left in (if you have doubts check the
+	 generated assembly code).  */
+      break;
+    case 1:
+      __asm_copy_from_user_1 (dst, src, retn);
+      break;
+    case 2:
+      __asm_copy_from_user_2 (dst, src, retn);
+      break;
+    case 3:
+      __asm_copy_from_user_3 (dst, src, retn);
+      break;
+  }
+
+  /* If we get here, retn correctly reflects the number of failing
+     bytes.  */
+  return retn;
+
+copy_exception_bytes:
+  /* We already have "retn" bytes cleared, and need to clear the
+     remaining "n" bytes.  A non-optimized simple byte-for-byte in-line
+     memset is preferred here, since this isn't speed-critical code and
+     we'd rather have this a leaf-function than calling memset.  */
+  {
+    char *endp;
+    for (endp = dst + n; dst < endp; dst++)
+      *dst = 0;
+  }
+
+  return retn + n;
+}
+
+/* Zero userspace.  */
+
+unsigned long
+__do_clear_user (void __user *pto, unsigned long pn)
+{
+  /* We want the parameters put in special registers.
+     Make sure the compiler is able to make something useful of this.
+      As it is now: r10 -> r13; r11 -> r11 (nop); r12 -> r12 (nop).
+
+     FIXME: Comment for old gcc version.  Check.
+     If gcc was allright, it really would need no temporaries, and no
+     stack space to save stuff on. */
+
+  register char *dst __asm__ ("r13") = pto;
+  register int n __asm__ ("r12") = pn;
+  register int retn __asm__ ("r10") = 0;
+
+
+  if (((unsigned long) dst & 3) != 0
+     /* Don't align if we wouldn't copy more than a few bytes.  */
+      && n >= 3)
+  {
+    if ((unsigned long) dst & 1)
+    {
+      __asm_clear_1 (dst, retn);
+      n--;
+    }
+
+    if ((unsigned long) dst & 2)
+    {
+      __asm_clear_2 (dst, retn);
+      n -= 2;
+    }
+  }
+
+  /* Decide which copying method to use.
+     FIXME: This number is from the "ordinary" kernel memset.  */
+  if (n >= (1*48))
+  {
+    /* For large clears we use 'movem' */
+
+    /* It is not optimal to tell the compiler about clobbering any
+       call-saved registers; that will move the saving/restoring of
+       those registers to the function prologue/epilogue, and make
+       non-movem sizes suboptimal.
+
+       This method is not foolproof; it assumes that the "asm reg"
+       declarations at the beginning of the function really are used
+       here (beware: they may be moved to temporary registers).
+       This way, we do not have to save/move the registers around into
+       temporaries; we can safely use them straight away.
+
+      If you want to check that the allocation was right; then
+      check the equalities in the first comment.  It should say
+      something like "r13=r13, r11=r11, r12=r12". */
+    __asm__ volatile ("
+	.ifnc %0%1%2,$r13$r12$r10					\n\
+	.err								\n\
+	.endif								\n\
+
+	;; Save the registers we'll clobber in the movem process
+	;; on the stack.  Don't mention them to gcc, it will only be
+	;; upset.
+	subq	11*4,$sp
+	movem	$r10,[$sp]
+
+	clear.d $r0
+	clear.d $r1
+	clear.d $r2
+	clear.d $r3
+	clear.d $r4
+	clear.d $r5
+	clear.d $r6
+	clear.d $r7
+	clear.d $r8
+	clear.d $r9
+	clear.d $r10
+	clear.d $r11
+
+	;; Now we've got this:
+	;; r13 - dst
+	;; r12 - n
+
+	;; Update n for the first loop
+	subq	12*4,$r12
+0:
+	subq   12*4,$r12
+	bge	0b
+	movem	$r11,[$r13+]
+1:
+	addq   12*4,$r12        ;; compensate for last loop underflowing n
+
+	;; Restore registers from stack
+	movem [$sp+],$r10
+2:
+	.section .fixup,\"ax\"
+3:
+	move.d [$sp],$r10
+	addq 12*4,$r10
+	move.d $r10,[$sp]
+	clear.d $r10
+	jump 0b
+
+4:
+	movem [$sp+],$r10
+	addq 12*4,$r10
+	addq 12*4,$r12
+	jump 2b
+
+	.previous
+	.section __ex_table,\"a\"
+	.dword 0b,3b
+	.dword 1b,4b
+	.previous"
+
+     /* Outputs */ : "=r" (dst), "=r" (n), "=r" (retn)
+     /* Inputs */ : "0" (dst), "1" (n), "2" (retn)
+     /* Clobber */ : "r11");
+  }
+
+  while (n >= 16)
+  {
+    __asm_clear_16 (dst, retn);
+    n -= 16;
+  }
+
+  /* Having a separate by-four loops cuts down on cache footprint.
+     FIXME:  Test with and without; increasing switch to be 0..15.  */
+  while (n >= 4)
+  {
+    __asm_clear_4 (dst, retn);
+    n -= 4;
+  }
+
+  switch (n)
+  {
+    case 0:
+      break;
+    case 1:
+      __asm_clear_1 (dst, retn);
+      break;
+    case 2:
+      __asm_clear_2 (dst, retn);
+      break;
+    case 3:
+      __asm_clear_3 (dst, retn);
+      break;
+  }
+
+  return retn;
+}
diff --git a/arch/cris/arch-v10/mm/Makefile b/arch/cris/arch-v10/mm/Makefile
new file mode 100644
index 0000000..588b4ba
--- /dev/null
+++ b/arch/cris/arch-v10/mm/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the linux cris-specific parts of the memory manager.
+#
+
+obj-y	 := fault.o init.o tlb.o
+
diff --git a/arch/cris/arch-v10/mm/fault.c b/arch/cris/arch-v10/mm/fault.c
new file mode 100644
index 0000000..6805cdb
--- /dev/null
+++ b/arch/cris/arch-v10/mm/fault.c
@@ -0,0 +1,117 @@
+/*
+ *  linux/arch/cris/mm/fault.c
+ *
+ *  Low level bus fault handler
+ *
+ *
+ *  Copyright (C) 2000, 2001  Axis Communications AB
+ *
+ *  Authors:  Bjorn Wesen 
+ * 
+ */
+
+#include <linux/mm.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/arch/svinto.h>
+
+/* debug of low-level TLB reload */
+#undef DEBUG
+
+#ifdef DEBUG
+#define D(x) x
+#else
+#define D(x)
+#endif
+
+extern volatile pgd_t *current_pgd;
+
+extern const struct exception_table_entry
+	*search_exception_tables(unsigned long addr);
+
+asmlinkage void do_page_fault(unsigned long address, struct pt_regs *regs,
+                              int protection, int writeaccess);
+
+/* fast TLB-fill fault handler
+ * this is called from entry.S with interrupts disabled
+ */
+
+void
+handle_mmu_bus_fault(struct pt_regs *regs)
+{
+	int cause;
+	int select;
+#ifdef DEBUG
+	int index;
+	int page_id;
+	int acc, inv;
+#endif
+	pgd_t* pgd = (pgd_t*)current_pgd;
+	pmd_t *pmd;
+	pte_t pte;
+	int miss, we, writeac;
+	unsigned long address;
+	unsigned long flags;
+
+	cause = *R_MMU_CAUSE;
+
+	address = cause & PAGE_MASK; /* get faulting address */
+	select = *R_TLB_SELECT;
+
+#ifdef DEBUG
+	page_id = IO_EXTRACT(R_MMU_CAUSE,  page_id,   cause);
+	acc     = IO_EXTRACT(R_MMU_CAUSE,  acc_excp,  cause);
+	inv     = IO_EXTRACT(R_MMU_CAUSE,  inv_excp,  cause);  
+	index   = IO_EXTRACT(R_TLB_SELECT, index,     select);
+#endif
+	miss    = IO_EXTRACT(R_MMU_CAUSE,  miss_excp, cause);
+	we      = IO_EXTRACT(R_MMU_CAUSE,  we_excp,   cause);
+	writeac = IO_EXTRACT(R_MMU_CAUSE,  wr_rd,     cause);
+
+	D(printk("bus_fault from IRP 0x%lx: addr 0x%lx, miss %d, inv %d, we %d, acc %d, dx %d pid %d\n",
+		 regs->irp, address, miss, inv, we, acc, index, page_id));
+
+	/* leave it to the MM system fault handler */
+	if (miss)
+		do_page_fault(address, regs, 0, writeac);
+        else
+		do_page_fault(address, regs, 1, we);
+
+        /* Reload TLB with new entry to avoid an extra miss exception.
+	 * do_page_fault may have flushed the TLB so we have to restore
+	 * the MMU registers.
+	 */
+	local_save_flags(flags);
+	local_irq_disable();
+	pmd = (pmd_t *)(pgd + pgd_index(address));
+	if (pmd_none(*pmd))
+		return;
+	pte = *pte_offset_kernel(pmd, address);
+	if (!pte_present(pte))
+		return;
+	*R_TLB_SELECT = select;
+	*R_TLB_HI = cause;
+	*R_TLB_LO = pte_val(pte);
+	local_irq_restore(flags);
+}
+
+/* Called from arch/cris/mm/fault.c to find fixup code. */
+int
+find_fixup_code(struct pt_regs *regs)
+{
+	const struct exception_table_entry *fixup;
+
+	if ((fixup = search_exception_tables(regs->irp)) != 0) {
+		/* Adjust the instruction pointer in the stackframe. */
+		regs->irp = fixup->fixup;
+		
+		/* 
+		 * Don't return by restoring the CPU state, so switch
+		 * frame-type. 
+		 */
+		regs->frametype = CRIS_FRAME_NORMAL;
+		return 1;
+	}
+
+	return 0;
+}
diff --git a/arch/cris/arch-v10/mm/init.c b/arch/cris/arch-v10/mm/init.c
new file mode 100644
index 0000000..a9f975a
--- /dev/null
+++ b/arch/cris/arch-v10/mm/init.c
@@ -0,0 +1,264 @@
+/*
+ *  linux/arch/cris/arch-v10/mm/init.c
+ *
+ */
+#include <linux/config.h>
+#include <linux/mmzone.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/mm.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/types.h>
+#include <asm/mmu.h>
+#include <asm/io.h>
+#include <asm/mmu_context.h>
+#include <asm/arch/svinto.h>
+
+extern void tlb_init(void);
+
+/*
+ * The kernel is already mapped with a kernel segment at kseg_c so 
+ * we don't need to map it with a page table. However head.S also
+ * temporarily mapped it at kseg_4 so we should set up the ksegs again,
+ * clear the TLB and do some other paging setup stuff.
+ */
+
+void __init 
+paging_init(void)
+{
+	int i;
+	unsigned long zones_size[MAX_NR_ZONES];
+
+	printk("Setting up paging and the MMU.\n");
+	
+	/* clear out the init_mm.pgd that will contain the kernel's mappings */
+
+	for(i = 0; i < PTRS_PER_PGD; i++)
+		swapper_pg_dir[i] = __pgd(0);
+	
+	/* make sure the current pgd table points to something sane
+	 * (even if it is most probably not used until the next 
+	 *  switch_mm)
+	 */
+
+	current_pgd = init_mm.pgd;
+
+	/* initialise the TLB (tlb.c) */
+
+	tlb_init();
+
+	/* see README.mm for details on the KSEG setup */
+
+#ifdef CONFIG_CRIS_LOW_MAP
+	/* Etrax-100 LX version 1 has a bug so that we cannot map anything
+	 * across the 0x80000000 boundary, so we need to shrink the user-virtual
+	 * area to 0x50000000 instead of 0xb0000000 and map things slightly
+	 * different. The unused areas are marked as paged so that we can catch
+	 * freak kernel accesses there.
+	 *
+	 * The ARTPEC chip is mapped at 0xa so we pass that segment straight
+	 * through. We cannot vremap it because the vmalloc area is below 0x8
+	 * and Juliette needs an uncached area above 0x8.
+	 *
+	 * Same thing with 0xc and 0x9, which is memory-mapped I/O on some boards.
+	 * We map them straight over in LOW_MAP, but use vremap in LX version 2.
+	 */
+
+#define CACHED_BOOTROM (KSEG_F | 0x08000000UL)
+
+	*R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, seg  ) |  /* bootrom */
+			IO_STATE(R_MMU_KSEG, seg_e, page ) |
+			IO_STATE(R_MMU_KSEG, seg_d, page ) | 
+			IO_STATE(R_MMU_KSEG, seg_c, page ) |   
+			IO_STATE(R_MMU_KSEG, seg_b, seg  ) |  /* kernel reg area */
+#ifdef CONFIG_JULIETTE
+			IO_STATE(R_MMU_KSEG, seg_a, seg  ) |  /* ARTPEC etc. */
+#else
+			IO_STATE(R_MMU_KSEG, seg_a, page ) |
+#endif
+			IO_STATE(R_MMU_KSEG, seg_9, seg  ) |  /* LED's on some boards */
+			IO_STATE(R_MMU_KSEG, seg_8, seg  ) |  /* CSE0/1, flash and I/O */
+			IO_STATE(R_MMU_KSEG, seg_7, page ) |  /* kernel vmalloc area */
+			IO_STATE(R_MMU_KSEG, seg_6, seg  ) |  /* kernel DRAM area */
+			IO_STATE(R_MMU_KSEG, seg_5, seg  ) |  /* cached flash */
+			IO_STATE(R_MMU_KSEG, seg_4, page ) |  /* user area */
+			IO_STATE(R_MMU_KSEG, seg_3, page ) |  /* user area */
+			IO_STATE(R_MMU_KSEG, seg_2, page ) |  /* user area */
+			IO_STATE(R_MMU_KSEG, seg_1, page ) |  /* user area */
+			IO_STATE(R_MMU_KSEG, seg_0, page ) ); /* user area */
+
+	*R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x3 ) |
+			    IO_FIELD(R_MMU_KBASE_HI, base_e, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_HI, base_c, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) |
+#ifdef CONFIG_JULIETTE
+			    IO_FIELD(R_MMU_KBASE_HI, base_a, 0xa ) |
+#else
+			    IO_FIELD(R_MMU_KBASE_HI, base_a, 0x0 ) |
+#endif
+			    IO_FIELD(R_MMU_KBASE_HI, base_9, 0x9 ) |
+			    IO_FIELD(R_MMU_KBASE_HI, base_8, 0x8 ) );
+	
+	*R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_LO, base_6, 0x4 ) |
+			    IO_FIELD(R_MMU_KBASE_LO, base_5, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_LO, base_4, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_LO, base_3, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) );
+#else
+	/* This code is for the corrected Etrax-100 LX version 2... */
+
+#define CACHED_BOOTROM (KSEG_A | 0x08000000UL)
+
+	*R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, seg  ) | /* cached flash */
+			IO_STATE(R_MMU_KSEG, seg_e, seg  ) | /* uncached flash */
+			IO_STATE(R_MMU_KSEG, seg_d, page ) | /* vmalloc area */
+			IO_STATE(R_MMU_KSEG, seg_c, seg  ) | /* kernel area */
+			IO_STATE(R_MMU_KSEG, seg_b, seg  ) | /* kernel reg area */
+			IO_STATE(R_MMU_KSEG, seg_a, seg  ) | /* bootrom */
+			IO_STATE(R_MMU_KSEG, seg_9, page ) | /* user area */
+			IO_STATE(R_MMU_KSEG, seg_8, page ) |
+			IO_STATE(R_MMU_KSEG, seg_7, page ) |
+			IO_STATE(R_MMU_KSEG, seg_6, page ) |
+			IO_STATE(R_MMU_KSEG, seg_5, page ) |
+			IO_STATE(R_MMU_KSEG, seg_4, page ) |
+			IO_STATE(R_MMU_KSEG, seg_3, page ) |
+			IO_STATE(R_MMU_KSEG, seg_2, page ) |
+			IO_STATE(R_MMU_KSEG, seg_1, page ) |
+			IO_STATE(R_MMU_KSEG, seg_0, page ) );
+
+	*R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_HI, base_e, 0x8 ) |
+			    IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_HI, base_c, 0x4 ) |
+			    IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) |
+			    IO_FIELD(R_MMU_KBASE_HI, base_a, 0x3 ) |
+			    IO_FIELD(R_MMU_KBASE_HI, base_9, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_HI, base_8, 0x0 ) );
+	
+	*R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_LO, base_6, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_LO, base_5, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_LO, base_4, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_LO, base_3, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) );
+#endif
+
+	*R_MMU_CONTEXT = ( IO_FIELD(R_MMU_CONTEXT, page_id, 0 ) );
+	
+	/* The MMU has been enabled ever since head.S but just to make
+	 * it totally obvious we do it here as well.
+	 */
+
+	*R_MMU_CTRL = ( IO_STATE(R_MMU_CTRL, inv_excp, enable ) |
+			IO_STATE(R_MMU_CTRL, acc_excp, enable ) |
+			IO_STATE(R_MMU_CTRL, we_excp,  enable ) );
+	
+	*R_MMU_ENABLE = IO_STATE(R_MMU_ENABLE, mmu_enable, enable);
+
+	/*
+	 * initialize the bad page table and bad page to point
+	 * to a couple of allocated pages
+	 */
+
+	empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
+	memset((void *)empty_zero_page, 0, PAGE_SIZE);
+
+	/* All pages are DMA'able in Etrax, so put all in the DMA'able zone */
+
+	zones_size[0] = ((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT;
+
+	for (i = 1; i < MAX_NR_ZONES; i++)
+		zones_size[i] = 0;
+
+	/* Use free_area_init_node instead of free_area_init, because the former
+	 * is designed for systems where the DRAM starts at an address substantially
+	 * higher than 0, like us (we start at PAGE_OFFSET). This saves space in the
+	 * mem_map page array.
+	 */
+
+	free_area_init_node(0, &contig_page_data, zones_size, PAGE_OFFSET >> PAGE_SHIFT, 0);
+}
+
+/* Initialize remaps of some I/O-ports. It is important that this
+ * is called before any driver is initialized.
+ */
+
+static int
+__init init_ioremap(void)
+{
+  
+	/* Give the external I/O-port addresses their values */
+
+#ifdef CONFIG_CRIS_LOW_MAP
+	/* Simply a linear map (see the KSEG map above in paging_init) */
+	port_cse1_addr = (volatile unsigned long *)(MEM_CSE1_START | 
+	                                            MEM_NON_CACHEABLE);
+	port_csp0_addr = (volatile unsigned long *)(MEM_CSP0_START |
+	                                            MEM_NON_CACHEABLE);
+	port_csp4_addr = (volatile unsigned long *)(MEM_CSP4_START |
+	                                            MEM_NON_CACHEABLE);
+#else
+	/* Note that nothing blows up just because we do this remapping 
+	 * it's ok even if the ports are not used or connected 
+	 * to anything (or connected to a non-I/O thing) */        
+	port_cse1_addr = (volatile unsigned long *)
+	  ioremap((unsigned long)(MEM_CSE1_START | MEM_NON_CACHEABLE), 16);
+	port_csp0_addr = (volatile unsigned long *)
+	  ioremap((unsigned long)(MEM_CSP0_START | MEM_NON_CACHEABLE), 16);
+	port_csp4_addr = (volatile unsigned long *)
+	  ioremap((unsigned long)(MEM_CSP4_START | MEM_NON_CACHEABLE), 16);
+#endif	
+	return 0;
+}
+
+__initcall(init_ioremap);
+
+/* Helper function for the two below */
+
+static inline void
+flush_etrax_cacherange(void *startadr, int length)
+{
+	/* CACHED_BOOTROM is mapped to the boot-rom area (cached) which
+	 * we can use to get fast dummy-reads of cachelines
+	 */
+
+	volatile short *flushadr = (volatile short *)(((unsigned long)startadr & ~PAGE_MASK) |
+						      CACHED_BOOTROM);
+
+	length = length > 8192 ? 8192 : length;  /* No need to flush more than cache size */
+
+	while(length > 0) {
+		*flushadr; /* dummy read to flush */
+		flushadr += (32/sizeof(short));  /* a cacheline is 32 bytes */
+		length -= 32;
+	}
+}
+
+/* Due to a bug in Etrax100(LX) all versions, receiving DMA buffers
+ * will occationally corrupt certain CPU writes if the DMA buffers
+ * happen to be hot in the cache.
+ * 
+ * As a workaround, we have to flush the relevant parts of the cache
+ * before (re) inserting any receiving descriptor into the DMA HW.
+ */
+
+void
+prepare_rx_descriptor(struct etrax_dma_descr *desc)
+{
+	flush_etrax_cacherange((void *)desc->buf, desc->sw_len ? desc->sw_len : 65536);
+}
+
+/* Do the same thing but flush the entire cache */
+
+void
+flush_etrax_cache(void)
+{
+	flush_etrax_cacherange(0, 8192);
+}
diff --git a/arch/cris/arch-v10/mm/tlb.c b/arch/cris/arch-v10/mm/tlb.c
new file mode 100644
index 0000000..9d06125
--- /dev/null
+++ b/arch/cris/arch-v10/mm/tlb.c
@@ -0,0 +1,248 @@
+/*
+ *  linux/arch/cris/arch-v10/mm/tlb.c
+ *
+ *  Low level TLB handling
+ *
+ *
+ *  Copyright (C) 2000-2002  Axis Communications AB
+ *  
+ *  Authors:   Bjorn Wesen (bjornw@axis.com)
+ *
+ */
+
+#include <asm/tlb.h>
+#include <asm/mmu_context.h>
+#include <asm/arch/svinto.h>
+
+#define D(x)
+
+/* The TLB can host up to 64 different mm contexts at the same time.
+ * The running context is R_MMU_CONTEXT, and each TLB entry contains a
+ * page_id that has to match to give a hit. In page_id_map, we keep track
+ * of which mm's we have assigned which page_id's, so that we know when
+ * to invalidate TLB entries.
+ *
+ * The last page_id is never running - it is used as an invalid page_id
+ * so we can make TLB entries that will never match.
+ *
+ * Notice that we need to make the flushes atomic, otherwise an interrupt
+ * handler that uses vmalloced memory might cause a TLB load in the middle
+ * of a flush causing.
+ */
+
+/* invalidate all TLB entries */
+
+void
+flush_tlb_all(void)
+{
+	int i;
+	unsigned long flags;
+
+	/* the vpn of i & 0xf is so we dont write similar TLB entries
+	 * in the same 4-way entry group. details.. 
+	 */
+
+	local_save_flags(flags);
+	local_irq_disable();
+	for(i = 0; i < NUM_TLB_ENTRIES; i++) {
+		*R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) );
+		*R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) |
+			      IO_FIELD(R_TLB_HI, vpn,     i & 0xf ) );
+		
+		*R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no       ) |
+			      IO_STATE(R_TLB_LO, valid, no       ) |
+			      IO_STATE(R_TLB_LO, kernel,no	 ) |
+			      IO_STATE(R_TLB_LO, we,    no       ) |
+			      IO_FIELD(R_TLB_LO, pfn,   0        ) );
+	}
+	local_irq_restore(flags);
+	D(printk("tlb: flushed all\n"));
+}
+
+/* invalidate the selected mm context only */
+
+void
+flush_tlb_mm(struct mm_struct *mm)
+{
+	int i;
+	int page_id = mm->context.page_id;
+	unsigned long flags;
+
+	D(printk("tlb: flush mm context %d (%p)\n", page_id, mm));
+
+	if(page_id == NO_CONTEXT)
+		return;
+	
+	/* mark the TLB entries that match the page_id as invalid.
+	 * here we could also check the _PAGE_GLOBAL bit and NOT flush
+	 * global pages. is it worth the extra I/O ? 
+	 */
+
+	local_save_flags(flags);
+	local_irq_disable();
+	for(i = 0; i < NUM_TLB_ENTRIES; i++) {
+		*R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i);
+		if (IO_EXTRACT(R_TLB_HI, page_id, *R_TLB_HI) == page_id) {
+			*R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) |
+				      IO_FIELD(R_TLB_HI, vpn,     i & 0xf ) );
+			
+			*R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no  ) |
+				      IO_STATE(R_TLB_LO, valid, no  ) |
+				      IO_STATE(R_TLB_LO, kernel,no  ) |
+				      IO_STATE(R_TLB_LO, we,    no  ) |
+				      IO_FIELD(R_TLB_LO, pfn,   0   ) );
+		}
+	}
+	local_irq_restore(flags);
+}
+
+/* invalidate a single page */
+
+void
+flush_tlb_page(struct vm_area_struct *vma, 
+	       unsigned long addr)
+{
+	struct mm_struct *mm = vma->vm_mm;
+	int page_id = mm->context.page_id;
+	int i;
+	unsigned long flags;
+
+	D(printk("tlb: flush page %p in context %d (%p)\n", addr, page_id, mm));
+
+	if(page_id == NO_CONTEXT)
+		return;
+
+	addr &= PAGE_MASK; /* perhaps not necessary */
+
+	/* invalidate those TLB entries that match both the mm context
+	 * and the virtual address requested 
+	 */
+
+	local_save_flags(flags);
+	local_irq_disable();
+	for(i = 0; i < NUM_TLB_ENTRIES; i++) {
+		unsigned long tlb_hi;
+		*R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i);
+		tlb_hi = *R_TLB_HI;
+		if (IO_EXTRACT(R_TLB_HI, page_id, tlb_hi) == page_id &&
+		    (tlb_hi & PAGE_MASK) == addr) {
+			*R_TLB_HI = IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) |
+				addr; /* same addr as before works. */
+			
+			*R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no  ) |
+				      IO_STATE(R_TLB_LO, valid, no  ) |
+				      IO_STATE(R_TLB_LO, kernel,no  ) |
+				      IO_STATE(R_TLB_LO, we,    no  ) |
+				      IO_FIELD(R_TLB_LO, pfn,   0   ) );
+		}
+	}
+	local_irq_restore(flags);
+}
+
+/* invalidate a page range */
+
+void
+flush_tlb_range(struct vm_area_struct *vma, 
+		unsigned long start,
+		unsigned long end)
+{
+	struct mm_struct *mm = vma->vm_mm;
+	int page_id = mm->context.page_id;
+	int i;
+	unsigned long flags;
+
+	D(printk("tlb: flush range %p<->%p in context %d (%p)\n",
+		 start, end, page_id, mm));
+
+	if(page_id == NO_CONTEXT)
+		return;
+
+	start &= PAGE_MASK;  /* probably not necessary */
+	end &= PAGE_MASK;    /* dito */
+
+	/* invalidate those TLB entries that match both the mm context
+	 * and the virtual address range
+	 */
+
+	local_save_flags(flags);
+	local_irq_disable();
+	for(i = 0; i < NUM_TLB_ENTRIES; i++) {
+		unsigned long tlb_hi, vpn;
+		*R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i);
+		tlb_hi = *R_TLB_HI;
+		vpn = tlb_hi & PAGE_MASK;
+		if (IO_EXTRACT(R_TLB_HI, page_id, tlb_hi) == page_id &&
+		    vpn >= start && vpn < end) {
+			*R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) |
+				      IO_FIELD(R_TLB_HI, vpn,     i & 0xf ) );
+			
+			*R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no  ) |
+				      IO_STATE(R_TLB_LO, valid, no  ) |
+				      IO_STATE(R_TLB_LO, kernel,no  ) |
+				      IO_STATE(R_TLB_LO, we,    no  ) |
+				      IO_FIELD(R_TLB_LO, pfn,   0   ) );
+		}
+	}
+	local_irq_restore(flags);
+}
+
+/* dump the entire TLB for debug purposes */
+
+#if 0
+void
+dump_tlb_all(void)
+{
+	int i;
+	unsigned long flags;
+	
+	printk("TLB dump. LO is: pfn | reserved | global | valid | kernel | we  |\n");
+
+	local_save_flags(flags);
+	local_irq_disable();
+	for(i = 0; i < NUM_TLB_ENTRIES; i++) {
+		*R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) );
+		printk("Entry %d: HI 0x%08lx, LO 0x%08lx\n",
+		       i, *R_TLB_HI, *R_TLB_LO);
+	}
+	local_irq_restore(flags);
+}
+#endif
+
+/*
+ * Initialize the context related info for a new mm_struct
+ * instance.
+ */
+
+int
+init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+	mm->context.page_id = NO_CONTEXT;
+	return 0;
+}
+
+/* called in schedule() just before actually doing the switch_to */
+
+void 
+switch_mm(struct mm_struct *prev, struct mm_struct *next,
+	  struct task_struct *tsk)
+{
+	/* make sure we have a context */
+
+	get_mmu_context(next);
+
+	/* remember the pgd for the fault handlers
+	 * this is similar to the pgd register in some other CPU's.
+	 * we need our own copy of it because current and active_mm
+	 * might be invalid at points where we still need to derefer
+	 * the pgd.
+	 */
+
+	current_pgd = next->pgd;
+
+	/* switch context in the MMU */
+	
+	D(printk("switching mmu_context to %d (%p)\n", next->context, next));
+
+	*R_MMU_CONTEXT = IO_FIELD(R_MMU_CONTEXT, page_id, next->context.page_id);
+}
+
diff --git a/arch/cris/arch-v10/output_arch.ld b/arch/cris/arch-v10/output_arch.ld
new file mode 100644
index 0000000..2f32880
--- /dev/null
+++ b/arch/cris/arch-v10/output_arch.ld
@@ -0,0 +1,2 @@
+/* At the time of this writing, there's no equivalent ld option. */
+OUTPUT_ARCH (cris)
diff --git a/arch/cris/arch-v10/vmlinux.lds.S b/arch/cris/arch-v10/vmlinux.lds.S
new file mode 100644
index 0000000..71ba736
--- /dev/null
+++ b/arch/cris/arch-v10/vmlinux.lds.S
@@ -0,0 +1,120 @@
+/* ld script to make the Linux/CRIS kernel
+ * Authors: Bjorn Wesen (bjornw@axis.com)
+ *
+ * It is VERY DANGEROUS to fiddle around with the symbols in this
+ * script. It is for example quite vital that all generated sections
+ * that are used are actually named here, otherwise the linker will
+ * put them at the end, where the init stuff is which is FREED after
+ * the kernel has booted. 
+ */	
+
+#include <linux/config.h>
+#include <asm-generic/vmlinux.lds.h>
+		
+jiffies = jiffies_64;
+SECTIONS
+{
+	. = DRAM_VIRTUAL_BASE;
+	dram_start = .;
+	ibr_start = .;
+	. = . + 0x4000; /* see head.S and pages reserved at the start */
+
+	_text = .;                    /* Text and read-only data */
+	text_start = .;              /* lots of aliases */
+	_stext = .;
+	__stext = .;
+	.text : {
+		*(.text)
+		SCHED_TEXT
+		LOCK_TEXT
+		*(.fixup)
+		*(.text.__*)
+	}
+
+	_etext = . ;                  /* End of text section */ 
+	__etext = .;
+
+	. = ALIGN(4);                /* Exception table */
+  	__start___ex_table = .;
+  	__ex_table : { *(__ex_table) }
+  	__stop___ex_table = .;
+
+	RODATA
+
+	. = ALIGN (4);
+	___data_start = . ;
+	__Sdata = . ;
+	.data : {                     /* Data */
+		*(.data)
+	}
+	__edata = . ;                 /* End of data section */
+	_edata = . ;
+
+	. = ALIGN(8192);              /* init_task and stack, must be aligned */
+  	.data.init_task : { *(.data.init_task) }
+
+  	. = ALIGN(8192);              /* Init code and data */
+  	__init_begin = .;
+	.init.text : { 
+		   _sinittext = .;
+		   *(.init.text)
+		   _einittext = .;
+	}
+  	.init.data : { *(.init.data) }
+  	. = ALIGN(16);
+  	__setup_start = .;
+  	.init.setup : { *(.init.setup) }
+  	__setup_end = .;
+  	.initcall.init : {
+		__initcall_start = .;
+		*(.initcall1.init);
+		*(.initcall2.init);
+		*(.initcall3.init);
+		*(.initcall4.init);
+		*(.initcall5.init);
+		*(.initcall6.init);
+		*(.initcall7.init);
+		__initcall_end = .;	
+	}
+
+	.con_initcall.init : {
+		__con_initcall_start = .;
+		*(.con_initcall.init)
+		__con_initcall_end = .;
+	}	
+	SECURITY_INIT
+		
+	.init.ramfs : {
+		__initramfs_start = .;
+		*(.init.ramfs)
+		__initramfs_end = .;
+		/* We fill to the next page, so we can discard all init
+		   pages without needing to consider what payload might be
+		   appended to the kernel image.  */
+		FILL (0); 
+		. = ALIGN (8192);
+	}
+	
+	__vmlinux_end = .;            /* last address of the physical file */
+  	__init_end = .;
+
+	__data_end = . ;              /* Move to _edata ? */
+	__bss_start = .;              /* BSS */
+	.bss : {
+		*(COMMON)
+		*(.bss)
+	}
+
+	. =  ALIGN (0x20);
+	_end = .;
+	__end = .;
+
+	/* Sections to be discarded */
+  	/DISCARD/ : {
+        	*(.text.exit)
+        	*(.data.exit)
+		*(.exitcall.exit)
+        }
+
+	dram_end = dram_start + CONFIG_ETRAX_DRAM_SIZE*1024*1024;
+}