summary refs log tree commit diff
path: root/arch/cris
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-08 10:01:28 -0800
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-08 10:01:28 -0800
commit0cf975e16927fd70f34cee20d3856246c13bb4c8 (patch)
treebb955d50f28e5d98c198701798c8341d9763299a /arch/cris
parent03054de1e0b90b33e9974107d84dabd2509f5898 (diff)
parentbc10ac3f2fe44e65f787d6197fd5d17304bf7d83 (diff)
downloadlinux-0cf975e16927fd70f34cee20d3856246c13bb4c8.tar.gz
Merge branch 'cris' of git://www.jni.nu/cris
* 'cris' of git://www.jni.nu/cris: (158 commits)
  CRIS v32: Remove hwregs/timer_defs.h, it is now architecture specific.
  CRIS v32: Change drivers/i2c.c locking.
  CRIS v32: Rewrite ARTPEC-3 gpio driver to avoid volatiles and general cleanup.
  CRIS: Add new timerfd syscall entries.
  MAINTAINERS: Add my information for the CRIS port.
  CRIS v32: Correct spelling of bandwidth in function name.
  CRIS v32: Clean up nandflash.c for ARTPEC-3 and ETRAX FS.
  CRIS v10: Cleanup of drivers/gpio.c
  CRIS v10: drivers/net/cris/eth_v10.c rename LED defines to CRIS_LED to avoid name clash.
  CRIS: Make io_pwm_set_period members unsigned in etraxgpio.h
  CRIS: Move ETRAX_AXISFLASHMAP to common Kconfig file.
  CRIS: Drop regs parameter from call to profile_tick in kernel/time.c
  CRIS v32: Fix minor formatting issue in mach-a3/io.c
  CRIS v32: Initialize GIO even if we're rambooting in kernel/head.S
  CRIS v32: Remove kernel/arbiter.c, it now exists in machine dependent directory.
  CRIS v32: Minor changes to avoid errors in asm-cris/arch-v32/hwregs/reg_rdwr.h
  CRIS v32: arch-v32/hwregs/intr_vect_defs.h moved to machine dependent directory.
  CRIS v32: Correct offset for TASK_pid in asm-cris/arch-v32/offset.h
  CRIS v32: Move register map header to machine dependent directory.
  CRIS v32: Let compiler know that memory is clobbered after a break op.
  ...
Diffstat (limited to 'arch/cris')
-rw-r--r--arch/cris/Kconfig538
-rw-r--r--arch/cris/Makefile139
-rw-r--r--arch/cris/arch-v10/Kconfig67
-rw-r--r--arch/cris/arch-v10/boot/Makefile24
-rw-r--r--arch/cris/arch-v10/boot/compressed/Makefile48
-rw-r--r--arch/cris/arch-v10/boot/compressed/misc.c6
-rw-r--r--arch/cris/arch-v10/boot/rescue/Makefile56
-rw-r--r--arch/cris/arch-v10/boot/rescue/head.S129
-rw-r--r--arch/cris/arch-v10/boot/rescue/kimagerescue.S58
-rw-r--r--arch/cris/arch-v10/boot/rescue/testrescue.S12
-rw-r--r--arch/cris/arch-v10/drivers/Kconfig181
-rw-r--r--arch/cris/arch-v10/drivers/Makefile12
-rw-r--r--arch/cris/arch-v10/drivers/axisflashmap.c181
-rw-r--r--arch/cris/arch-v10/drivers/ds1302.c4
-rw-r--r--arch/cris/arch-v10/drivers/eeprom.c75
-rw-r--r--arch/cris/arch-v10/drivers/gpio.c634
-rw-r--r--arch/cris/arch-v10/drivers/i2c.c81
-rw-r--r--arch/cris/arch-v10/drivers/pcf8563.c393
-rw-r--r--arch/cris/arch-v10/drivers/sync_serial.c1441
-rw-r--r--arch/cris/arch-v10/kernel/debugport.c134
-rw-r--r--arch/cris/arch-v10/kernel/dma.c3
-rw-r--r--arch/cris/arch-v10/kernel/entry.S249
-rw-r--r--arch/cris/arch-v10/kernel/fasttimer.c35
-rw-r--r--arch/cris/arch-v10/kernel/head.S221
-rw-r--r--arch/cris/arch-v10/kernel/io_interface_mux.c515
-rw-r--r--arch/cris/arch-v10/kernel/irq.c7
-rw-r--r--arch/cris/arch-v10/kernel/kgdb.c58
-rw-r--r--arch/cris/arch-v10/kernel/process.c3
-rw-r--r--arch/cris/arch-v10/kernel/ptrace.c1
-rw-r--r--arch/cris/arch-v10/kernel/shadows.c3
-rw-r--r--arch/cris/arch-v10/kernel/traps.c198
-rw-r--r--arch/cris/arch-v10/lib/checksum.S8
-rw-r--r--arch/cris/arch-v10/lib/checksumcopy.S8
-rw-r--r--arch/cris/arch-v10/lib/dram_init.S58
-rw-r--r--arch/cris/arch-v10/lib/old_checksum.c3
-rw-r--r--arch/cris/arch-v10/mm/fault.c13
-rw-r--r--arch/cris/arch-v10/mm/tlb.c58
-rw-r--r--arch/cris/arch-v32/Kconfig127
-rw-r--r--arch/cris/arch-v32/boot/Makefile23
-rw-r--r--arch/cris/arch-v32/boot/compressed/Makefile45
-rw-r--r--arch/cris/arch-v32/boot/compressed/README1
-rw-r--r--arch/cris/arch-v32/boot/compressed/head.S137
-rw-r--r--arch/cris/arch-v32/boot/compressed/misc.c72
-rw-r--r--arch/cris/arch-v32/boot/rescue/Makefile41
-rw-r--r--arch/cris/arch-v32/boot/rescue/head.S42
-rw-r--r--arch/cris/arch-v32/boot/rescue/rescue.ld37
-rw-r--r--arch/cris/arch-v32/drivers/Kconfig711
-rw-r--r--arch/cris/arch-v32/drivers/Makefile5
-rw-r--r--arch/cris/arch-v32/drivers/axisflashmap.c488
-rw-r--r--arch/cris/arch-v32/drivers/cryptocop.c104
-rw-r--r--arch/cris/arch-v32/drivers/i2c.c206
-rw-r--r--arch/cris/arch-v32/drivers/i2c.h2
-rw-r--r--arch/cris/arch-v32/drivers/iop_fw_load.c16
-rw-r--r--arch/cris/arch-v32/drivers/mach-a3/Makefile6
-rw-r--r--arch/cris/arch-v32/drivers/mach-a3/gpio.c984
-rw-r--r--arch/cris/arch-v32/drivers/mach-a3/nandflash.c180
-rw-r--r--arch/cris/arch-v32/drivers/mach-fs/Makefile6
-rw-r--r--arch/cris/arch-v32/drivers/mach-fs/gpio.c (renamed from arch/cris/arch-v32/drivers/gpio.c)612
-rw-r--r--arch/cris/arch-v32/drivers/mach-fs/nandflash.c (renamed from arch/cris/arch-v32/drivers/nandflash.c)122
-rw-r--r--arch/cris/arch-v32/drivers/pcf8563.c296
-rw-r--r--arch/cris/arch-v32/drivers/sync_serial.c938
-rw-r--r--arch/cris/arch-v32/kernel/Makefile5
-rw-r--r--arch/cris/arch-v32/kernel/arbiter.c296
-rw-r--r--arch/cris/arch-v32/kernel/crisksyms.c7
-rw-r--r--arch/cris/arch-v32/kernel/debugport.c342
-rw-r--r--arch/cris/arch-v32/kernel/entry.S83
-rw-r--r--arch/cris/arch-v32/kernel/fasttimer.c535
-rw-r--r--arch/cris/arch-v32/kernel/head.S204
-rw-r--r--arch/cris/arch-v32/kernel/io.c153
-rw-r--r--arch/cris/arch-v32/kernel/irq.c274
-rw-r--r--arch/cris/arch-v32/kernel/kgdb.c12
-rw-r--r--arch/cris/arch-v32/kernel/process.c14
-rw-r--r--arch/cris/arch-v32/kernel/ptrace.c10
-rw-r--r--arch/cris/arch-v32/kernel/signal.c144
-rw-r--r--arch/cris/arch-v32/kernel/smp.c31
-rw-r--r--arch/cris/arch-v32/kernel/time.c237
-rw-r--r--arch/cris/arch-v32/kernel/traps.c192
-rw-r--r--arch/cris/arch-v32/kernel/vcs_hook.c96
-rw-r--r--arch/cris/arch-v32/lib/Makefile3
-rw-r--r--arch/cris/arch-v32/lib/checksum.S72
-rw-r--r--arch/cris/arch-v32/lib/checksumcopy.S69
-rw-r--r--arch/cris/arch-v32/lib/delay.c28
-rw-r--r--arch/cris/arch-v32/lib/spinlock.S10
-rw-r--r--arch/cris/arch-v32/mach-a3/Kconfig110
-rw-r--r--arch/cris/arch-v32/mach-a3/Makefile11
-rw-r--r--arch/cris/arch-v32/mach-a3/arbiter.c634
-rw-r--r--arch/cris/arch-v32/mach-a3/cpufreq.c153
-rw-r--r--arch/cris/arch-v32/mach-a3/dma.c185
-rw-r--r--arch/cris/arch-v32/mach-a3/dram_init.S104
-rw-r--r--arch/cris/arch-v32/mach-a3/hw_settings.S51
-rw-r--r--arch/cris/arch-v32/mach-a3/io.c149
-rw-r--r--arch/cris/arch-v32/mach-a3/pinmux.c386
-rw-r--r--arch/cris/arch-v32/mach-a3/vcs_hook.c103
-rw-r--r--arch/cris/arch-v32/mach-a3/vcs_hook.h58
-rw-r--r--arch/cris/arch-v32/mach-fs/Kconfig216
-rw-r--r--arch/cris/arch-v32/mach-fs/Makefile11
-rw-r--r--arch/cris/arch-v32/mach-fs/arbiter.c404
-rw-r--r--arch/cris/arch-v32/mach-fs/cpufreq.c146
-rw-r--r--arch/cris/arch-v32/mach-fs/dma.c (renamed from arch/cris/arch-v32/kernel/dma.c)46
-rw-r--r--arch/cris/arch-v32/mach-fs/dram_init.S (renamed from arch/cris/arch-v32/lib/dram_init.S)23
-rw-r--r--arch/cris/arch-v32/mach-fs/hw_settings.S (renamed from arch/cris/arch-v32/lib/hw_settings.S)12
-rw-r--r--arch/cris/arch-v32/mach-fs/io.c191
-rw-r--r--arch/cris/arch-v32/mach-fs/pinmux.c309
-rw-r--r--arch/cris/arch-v32/mach-fs/vcs_hook.c100
-rw-r--r--arch/cris/arch-v32/mach-fs/vcs_hook.h (renamed from arch/cris/arch-v32/kernel/vcs_hook.h)8
-rw-r--r--arch/cris/arch-v32/mm/Makefile3
-rw-r--r--arch/cris/arch-v32/mm/init.c8
-rw-r--r--arch/cris/arch-v32/mm/intmem.c48
-rw-r--r--arch/cris/arch-v32/mm/l2cache.c29
-rw-r--r--arch/cris/arch-v32/mm/mmu.S93
-rw-r--r--arch/cris/arch-v32/mm/tlb.c56
-rw-r--r--arch/cris/arch-v32/vmlinux.lds.S74
-rw-r--r--arch/cris/artpec_3_defconfig582
-rw-r--r--arch/cris/defconfig795
-rw-r--r--arch/cris/etraxfs_defconfig585
-rw-r--r--arch/cris/kernel/module.c14
-rw-r--r--arch/cris/kernel/process.c103
-rw-r--r--arch/cris/kernel/ptrace.c58
-rw-r--r--arch/cris/kernel/semaphore.c1
-rw-r--r--arch/cris/kernel/setup.c27
-rw-r--r--arch/cris/kernel/time.c13
-rw-r--r--arch/cris/kernel/traps.c226
-rw-r--r--arch/cris/mm/fault.c169
-rw-r--r--arch/cris/mm/init.c111
124 files changed, 13323 insertions, 6754 deletions
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig
index ff078e60e76d..8456bc8efb7c 100644
--- a/arch/cris/Kconfig
+++ b/arch/cris/Kconfig
@@ -13,10 +13,6 @@ config ZONE_DMA
 	bool
 	default y
 
-config NO_DMA
-	bool
-	default y
-
 config RWSEM_GENERIC_SPINLOCK
 	bool
 	default y
@@ -24,6 +20,10 @@ config RWSEM_GENERIC_SPINLOCK
 config RWSEM_XCHGADD_ALGORITHM
 	bool
 
+config GENERIC_IOMAP
+       bool
+       default y
+
 config ARCH_HAS_ILOG2_U32
 	bool
 	default n
@@ -44,13 +44,13 @@ config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
 
-config IRQ_PER_CPU
-	bool
-	default y
-
 config NO_IOPORT
 	def_bool y
 
+config FORCE_MAX_ZONEORDER
+	int
+	default 6
+
 config CRIS
 	bool
 	default y
@@ -97,17 +97,15 @@ config ETRAX_FAST_TIMER
 	 timers).
 	 This is needed if CONFIG_ETRAX_SERIAL_FAST_TIMER is enabled.
 
-config PREEMPT
-	bool "Preemptible Kernel"
+config ETRAX_KMALLOCED_MODULES
+	bool "Enable module allocation with kmalloc"
 	help
-	  This option reduces the latency of the kernel when reacting to
-	  real-time or interactive events by allowing a low priority process to
-	  be preempted even if it is in kernel mode executing a system call.
-	  This allows applications to run more reliably even when the system is
-	  under load.
+	  Enable module allocation with kmalloc instead of vmalloc.
+
+config OOM_REBOOT
+       bool "Enable reboot at out of memory"
 
-	  Say Y here if you are building a kernel for a desktop, embedded
-	  or real-time system.  Say N if you are unsure.
+source "kernel/Kconfig.preempt"
 
 source mm/Kconfig
 
@@ -134,24 +132,124 @@ config SVINTO_SIM
 	help
 	  Support the xsim ETRAX Simulator.
 
+config ETRAXFS
+	bool "ETRAX-FS-V32"
+	help
+	  Support CRIS V32.
+
+config CRIS_MACH_ARTPEC3
+        bool "ARTPEC-3"
+        help
+          Support Axis ARTPEC-3.
+
 endchoice
 
+config ETRAX_VCS_SIM
+	bool "VCS Simulator"
+	help
+	  Setup hardware to be run in the VCS simulator.
+
 config ETRAX_ARCH_V10
        bool
        default y if ETRAX100LX || ETRAX100LX_V2
        default n if !(ETRAX100LX || ETRAX100LX_V2)
 
+config ETRAX_ARCH_V32
+       bool
+       default y if (ETRAXFS || CRIS_MACH_ARTPEC3)
+       default n if !(ETRAXFS || CRIS_MACH_ARTPEC3)
+
 config ETRAX_DRAM_SIZE
 	int "DRAM size (dec, in MB)"
 	default "8"
 	help
 	  Size of DRAM (decimal in MB) typically 2, 8 or 16.
 
+config ETRAX_VMEM_SIZE
+       int "Video memory size (dec, in MB)"
+       depends on ETRAX_ARCH_V32 && !ETRAXFS
+       default 8 if !ETRAXFS
+       help
+	Size of Video accessible memory (decimal, in MB).
+
 config ETRAX_FLASH_BUSWIDTH
-	int "Buswidth of flash in bytes"
+	int "Buswidth of NOR flash in bytes"
 	default "2"
 	help
-	  Width in bytes of the Flash bus (1, 2 or 4). Is usually 2.
+	  Width in bytes of the NOR Flash bus (1, 2 or 4). Is usually 2.
+
+config ETRAX_NANDFLASH_BUSWIDTH
+	int "Buswidth of NAND flash in bytes"
+	default "1"
+	help
+	  Width in bytes of the NAND flash (1 or 2).
+
+config ETRAX_FLASH1_SIZE
+       int "FLASH1 size (dec, in MB. 0 = Unknown)"
+       default "0"
+
+choice
+	prompt "Product debug-port"
+	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 "Kernel GDB port"
+	depends on ETRAX_KGDB
+	default ETRAX_KGDB_PORT0
+	help
+	  Choose a serial port for kernel debugging.  NOTE: This port should
+	  not be enabled under Drivers for built-in interfaces (as it has its
+	  own initialization code) and should not be the same as the debug port.
+
+config ETRAX_KGDB_PORT0
+	bool "Serial-0"
+	help
+	  Use serial port 0 for kernel debugging.
+
+config ETRAX_KGDB_PORT1
+	bool "Serial-1"
+	help
+	  Use serial port 1 for kernel debugging.
+
+config ETRAX_KGDB_PORT2
+	bool "Serial-2"
+	help
+	  Use serial port 2 for kernel debugging.
+
+config ETRAX_KGDB_PORT3
+	bool "Serial-3"
+	help
+	  Use serial port 3 for kernel debugging.
+
+endchoice
 
 source arch/cris/arch-v10/Kconfig
 source arch/cris/arch-v32/Kconfig
@@ -165,6 +263,387 @@ menu "Drivers for built-in interfaces"
 source arch/cris/arch-v10/drivers/Kconfig
 source arch/cris/arch-v32/drivers/Kconfig
 
+config ETRAX_AXISFLASHMAP
+	bool "Axis flash-map support"
+	select MTD
+	select MTD_CFI
+	select MTD_CFI_AMDSTD
+	select MTD_JEDECPROBE if ETRAX_ARCH_V32
+	select MTD_CHAR
+	select MTD_BLOCK
+	select MTD_PARTITIONS
+	select MTD_CONCAT
+	select MTD_COMPLEX_MAPPINGS
+	help
+	  This option enables MTD mapping of flash devices.  Needed to use
+	  flash memories.  If unsure, say Y.
+
+config ETRAX_RTC
+	bool "Real Time Clock support"
+	depends on ETRAX_I2C
+	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.  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_PCF8563 if ETRAX_ARCH_V32
+	default ETRAX_DS1302 if ETRAX_ARCH_V10
+
+config ETRAX_DS1302
+	depends on ETRAX_ARCH_V10
+	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_SYNCHRONOUS_SERIAL
+	bool "Synchronous serial-port support"
+	help
+	  Select this to enable the synchronous serial port driver.
+
+config ETRAX_SYNCHRONOUS_SERIAL_PORT0
+	bool "Synchronous serial port 0 enabled"
+	depends on ETRAX_SYNCHRONOUS_SERIAL
+	help
+	  Enabled synchronous serial port 0.
+
+config ETRAX_SYNCHRONOUS_SERIAL0_DMA
+	bool "Enable DMA on synchronous serial port 0."
+	depends on ETRAX_SYNCHRONOUS_SERIAL_PORT0
+	help
+	  A synchronous serial port can run in manual or DMA mode.
+	  Selecting this option will make it run in DMA mode.
+
+config ETRAX_SYNCHRONOUS_SERIAL_PORT1
+	bool "Synchronous serial port 1 enabled"
+	depends on ETRAX_SYNCHRONOUS_SERIAL && (ETRAXFS || ETRAX_ARCH_V10)
+	help
+	  Enabled synchronous serial port 1.
+
+config ETRAX_SYNCHRONOUS_SERIAL1_DMA
+	bool "Enable DMA on synchronous serial port 1."
+	depends on ETRAX_SYNCHRONOUS_SERIAL_PORT1
+	help
+	  A synchronous serial port can run in manual or DMA mode.
+	  Selecting this option will make it run in DMA mode.
+
+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
+
+choice
+	prompt "Ser0 DMA out channel"
+	depends on ETRAX_SERIAL_PORT0
+	default ETRAX_SERIAL_PORT0_DMA6_OUT if ETRAX_ARCH_V32
+	default ETRAX_SERIAL_PORT0_NO_DMA_OUT if ETRAX_ARCH_V10
+
+config ETRAX_SERIAL_PORT0_NO_DMA_OUT
+	bool "Ser0 uses no DMA for output"
+	help
+	  Do not use DMA for ser0 output.
+
+config ETRAX_SERIAL_PORT0_DMA6_OUT
+	bool "Ser0 uses DMA6 for output"
+	depends on ETRAXFS
+	help
+	  Enables the DMA6 output channel for ser0 (ttyS0).
+	  If you do not enable DMA, an interrupt for each character will be
+	  used when transmitting data.
+	  Normally you want to use DMA, unless you use the DMA channel for
+	  something else.
+
+config ETRAX_SERIAL_PORT0_DMA0_OUT
+	bool "Ser0 uses DMA0 for output"
+	depends on CRIS_MACH_ARTPEC3
+	help
+	  Enables the DMA0 output channel for ser0 (ttyS0).
+	  If you do not enable DMA, an interrupt for each character will be
+	  used when transmitting data.
+	  Normally you want to use DMA, unless you use the DMA channel for
+	  something else.
+
+endchoice
+
+choice
+	prompt "Ser0 DMA in channel "
+	depends on ETRAX_SERIAL_PORT0
+	default ETRAX_SERIAL_PORT0_NO_DMA_IN if ETRAX_ARCH_V32
+	default ETRAX_SERIAL_PORT0_DMA7_IN if ETRAX_ARCH_V10
+	help
+	  What DMA channel to use for ser0.
+
+config ETRAX_SERIAL_PORT0_NO_DMA_IN
+	bool "Ser0 uses no DMA for input"
+	help
+	  Do not use DMA for ser0 input.
+
+config ETRAX_SERIAL_PORT0_DMA7_IN
+	bool "Ser0 uses DMA7 for input"
+	depends on ETRAXFS
+	help
+	  Enables the DMA7 input channel for ser0 (ttyS0).
+	  If you do not enable DMA, an interrupt for each character will be
+	  used when receiving data.
+	  Normally you want to use DMA, unless you use the DMA channel for
+	  something else.
+
+config ETRAX_SERIAL_PORT0_DMA1_IN
+	bool "Ser0 uses DMA1 for input"
+	depends on CRIS_MACH_ARTPEC3
+	help
+	  Enables the DMA1 input channel for ser0 (ttyS0).
+	  If you do not enable DMA, an interrupt for each character will be
+	  used when receiveing data.
+	  Normally you want to use DMA, unless you use the DMA channel for
+	  something else.
+
+endchoice
+
+choice
+	prompt "Ser1 DMA in channel "
+	depends on ETRAX_SERIAL_PORT1
+	default ETRAX_SERIAL_PORT1_NO_DMA_IN if ETRAX_ARCH_V32
+	default ETRAX_SERIAL_PORT1_DMA9_IN if ETRAX_ARCH_V10
+	help
+	  What DMA channel to use for ser1.
+
+config ETRAX_SERIAL_PORT1_NO_DMA_IN
+	bool "Ser1 uses no DMA for input"
+	help
+	  Do not use DMA for ser1 input.
+
+config ETRAX_SERIAL_PORT1_DMA5_IN
+	bool "Ser1 uses DMA5 for input"
+	depends on ETRAX_ARCH_V32
+	help
+	  Enables the DMA5 input channel for ser1 (ttyS1).
+	  If you do not enable DMA, an interrupt for each character will be
+	  used when receiving data.
+	  Normally you want this on, unless you use the DMA channel for
+	  something else.
+
+config ETRAX_SERIAL_PORT1_DMA9_IN
+	depends on ETRAX_ARCH_V10
+	bool "Ser1 uses DMA9 for input"
+
+endchoice
+
+
+choice
+	prompt "Ser1 DMA out channel"
+	depends on ETRAX_SERIAL_PORT1
+	default ETRAX_SERIAL_PORT1_NO_DMA_OUT if ETRAX_ARCH_V32
+	default ETRAX_SERIAL_PORT1_DMA8_OUT if ETRAX_ARCH_V10
+	help
+	  What DMA channel to use for ser1.
+
+config ETRAX_SERIAL_PORT1_NO_DMA_OUT
+	bool "Ser1 uses no DMA for output"
+	help
+	  Do not use DMA for ser1 output.
+
+config ETRAX_SERIAL_PORT1_DMA8_OUT
+	depends on ETRAX_ARCH_V10
+	bool "Ser1 uses DMA8 for output"
+
+config ETRAX_SERIAL_PORT1_DMA4_OUT
+	depends on ETRAX_ARCH_V32
+	bool "Ser1 uses DMA4 for output"
+	help
+	  Enables the DMA4 output channel for ser1 (ttyS1).
+	  If you do not enable DMA, an interrupt for each character will be
+	  used when transmitting data.
+	  Normally you want this on, unless you use the DMA channel for
+	  something else.
+
+endchoice
+
+choice
+	prompt "Ser2 DMA out channel"
+	depends on ETRAX_SERIAL_PORT2
+	default ETRAX_SERIAL_PORT2_NO_DMA_OUT if ETRAX_ARCH_V32
+	default ETRAX_SERIAL_PORT2_DMA2_OUT if ETRAX_ARCH_V10
+
+config ETRAX_SERIAL_PORT2_NO_DMA_OUT
+	bool "Ser2 uses no DMA for output"
+	help
+	  Do not use DMA for ser2 output.
+
+config ETRAX_SERIAL_PORT2_DMA2_OUT
+	bool "Ser2 uses DMA2 for output"
+	depends on ETRAXFS || ETRAX_ARCH_V10
+	help
+	  Enables the DMA2 output channel for ser2 (ttyS2).
+	  If you do not enable DMA, an interrupt for each character will be
+	  used when transmitting data.
+	  Normally you want to use DMA, unless you use the DMA channel for
+	  something else.
+
+config ETRAX_SERIAL_PORT2_DMA6_OUT
+	bool "Ser2 uses DMA6 for output"
+	depends on CRIS_MACH_ARTPEC3
+	help
+	  Enables the DMA6 output channel for ser2 (ttyS2).
+	  If you do not enable DMA, an interrupt for each character will be
+	  used when transmitting data.
+	  Normally you want to use DMA, unless you use the DMA channel for
+	  something else.
+
+endchoice
+
+choice
+	prompt "Ser2 DMA in channel"
+	depends on ETRAX_SERIAL_PORT2
+	default ETRAX_SERIAL_PORT2_NO_DMA_IN if ETRAX_ARCH_V32
+	default ETRAX_SERIAL_PORT2_DMA3_IN if ETRAX_ARCH_V10
+	help
+	  What DMA channel to use for ser2.
+
+config ETRAX_SERIAL_PORT2_NO_DMA_IN
+	bool "Ser2 uses no DMA for input"
+	help
+	  Do not use DMA for ser2 input.
+
+config ETRAX_SERIAL_PORT2_DMA3_IN
+	bool "Ser2 uses DMA3 for input"
+	depends on ETRAXFS || ETRAX_ARCH_V10
+	help
+	  Enables the DMA3 input channel for ser2 (ttyS2).
+	  If you do not enable DMA, an interrupt for each character will be
+	  used when receiving data.
+	  Normally you want to use DMA, unless you use the DMA channel for
+	  something else.
+
+config ETRAX_SERIAL_PORT2_DMA7_IN
+	bool "Ser2 uses DMA7 for input"
+	depends on CRIS_MACH_ARTPEC3
+	help
+	  Enables the DMA7 input channel for ser2 (ttyS2).
+	  If you do not enable DMA, an interrupt for each character will be
+	  used when receiveing data.
+	  Normally you want to use DMA, unless you use the DMA channel for
+	  something else.
+
+endchoice
+
+choice
+	prompt "Ser3 DMA in channel"
+	depends on ETRAX_SERIAL_PORT3
+	default ETRAX_SERIAL_PORT3_NO_DMA_IN if ETRAX_ARCH_V32
+	default ETRAX_SERIAL_PORT3_DMA5_IN if ETRAX_ARCH_V10
+	help
+	  What DMA channel to use for ser3.
+
+config ETRAX_SERIAL_PORT3_NO_DMA_IN
+	bool "Ser3 uses no DMA for input"
+	help
+	  Do not use DMA for ser3 input.
+
+config ETRAX_SERIAL_PORT3_DMA5_IN
+	depends on ETRAX_ARCH_V10
+	bool "DMA 5"
+
+config ETRAX_SERIAL_PORT3_DMA9_IN
+	bool "Ser3 uses DMA9 for input"
+	depends on ETRAXFS
+	help
+	  Enables the DMA9 input channel for ser3 (ttyS3).
+	  If you do not enable DMA, an interrupt for each character will be
+	  used when receiving data.
+	  Normally you want to use DMA, unless you use the DMA channel for
+	  something else.
+
+config ETRAX_SERIAL_PORT3_DMA3_IN
+	bool "Ser3 uses DMA3 for input"
+	depends on CRIS_MACH_ARTPEC3
+	help
+	  Enables the DMA3 input channel for ser3 (ttyS3).
+	  If you do not enable DMA, an interrupt for each character will be
+	  used when receiveing data.
+	  Normally you want to use DMA, unless you use the DMA channel for
+	  something else.
+
+endchoice
+
+choice
+	prompt "Ser3 DMA out channel"
+	depends on ETRAX_SERIAL_PORT3
+	default ETRAX_SERIAL_PORT3_NO_DMA_OUT if ETRAX_ARCH_V32
+	default ETRAX_SERIAL_PORT3_DMA4_OUT if ETRAX_ARCH_V10
+
+config ETRAX_SERIAL_PORT3_NO_DMA_OUT
+	bool "Ser3 uses no DMA for output"
+	help
+	  Do not use DMA for ser3 output.
+
+config ETRAX_SERIAL_PORT3_DMA4_OUT
+	depends on ETRAX_ARCH_V10
+	bool "DMA 4"
+
+config ETRAX_SERIAL_PORT3_DMA8_OUT
+	bool "Ser3 uses DMA8 for output"
+	depends on ETRAXFS
+	help
+	  Enables the DMA8 output channel for ser3 (ttyS3).
+	  If you do not enable DMA, an interrupt for each character will be
+	  used when transmitting data.
+	  Normally you want to use DMA, unless you use the DMA channel for
+	  something else.
+
+config ETRAX_SERIAL_PORT3_DMA2_OUT
+	bool "Ser3 uses DMA2 for output"
+	depends on CRIS_MACH_ARTPEC3
+	help
+	  Enables the DMA2 output channel for ser3 (ttyS3).
+	  If you do not enable DMA, an interrupt for each character will be
+	  used when transmitting data.
+	  Normally you want to use DMA, unless you use the DMA channel for
+	  something else.
+
+endchoice
+
 endmenu
 
 source "drivers/base/Kconfig"
@@ -178,22 +657,10 @@ source "drivers/pnp/Kconfig"
 
 source "drivers/block/Kconfig"
 
-source "drivers/md/Kconfig"
-
 source "drivers/ide/Kconfig"
 
-source "drivers/scsi/Kconfig"
-
-source "drivers/ieee1394/Kconfig"
-
-source "drivers/message/i2o/Kconfig"
-
 source "drivers/net/Kconfig"
 
-source "drivers/isdn/Kconfig"
-
-source "drivers/telephony/Kconfig"
-
 source "drivers/i2c/Kconfig"
 
 source "drivers/rtc/Kconfig"
@@ -205,17 +672,8 @@ source "drivers/input/Kconfig"
 
 source "drivers/char/Kconfig"
 
-#source drivers/misc/Config.in
-source "drivers/media/Kconfig"
-
 source "fs/Kconfig"
 
-source "sound/Kconfig"
-
-source "drivers/pcmcia/Kconfig"
-
-source "drivers/pci/Kconfig"
-
 source "drivers/usb/Kconfig"
 
 source "arch/cris/Kconfig.debug"
diff --git a/arch/cris/Makefile b/arch/cris/Makefile
index e6bf00c262e0..838cd2ae03ae 100644
--- a/arch/cris/Makefile
+++ b/arch/cris/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.28 2005/03/17 10:44:37 larsv Exp $
+#
 # cris/Makefile
 #
 # This file is included by the global makefile so that you can add your own
@@ -10,28 +10,36 @@
 # License.  See the file "COPYING" in the main directory of this archive
 # for more details.
 
-# A bug in ld prevents us from having a (constant-value) symbol in a
-# "ORIGIN =" or "LENGTH =" expression.
-
 arch-y := v10
 arch-$(CONFIG_ETRAX_ARCH_V10) := v10
 arch-$(CONFIG_ETRAX_ARCH_V32) := v32
 
-# No config avaiable for make clean etc
+# No config available for make clean etc
+mach-y := fs
+mach-$(CONFIG_CRIS_MACH_ARTPEC3) := a3
+mach-$(CONFIG_ETRAXFS) := fs
+
 ifneq ($(arch-y),)
 SARCH := arch-$(arch-y)
 else
 SARCH :=
 endif
 
+ifneq ($(mach-y),)
+MACH := mach-$(mach-y)
+else
+MACH :=
+endif
+
 LD = $(CROSS_COMPILE)ld -mcrislinux
 
 OBJCOPYFLAGS := -O binary -R .note -R .comment -S
 
 CPPFLAGS_vmlinux.lds = -DDRAM_VIRTUAL_BASE=0x$(CONFIG_ETRAX_DRAM_VIRTUAL_BASE)
-KBUILD_AFLAGS += -mlinux
 
-KBUILD_CFLAGS += -mlinux -march=$(arch-y) -pipe
+KBUILD_AFLAGS += -mlinux -march=$(arch-y) -Iinclude/asm/arch/mach -Iinclude/asm/arch
+
+KBUILD_CFLAGS += -mlinux -march=$(arch-y) -pipe -Iinclude/asm/arch/mach -Iinclude/asm/arch
 
 ifdef CONFIG_FRAME_POINTER
 KBUILD_CFLAGS := $(subst -fomit-frame-pointer,,$(KBUILD_CFLAGS)) -g
@@ -44,6 +52,9 @@ LIBGCC = $(shell $(CC) $(KBUILD_CFLAGS) -print-file-name=libgcc.a)
 
 core-y		+= arch/$(ARCH)/kernel/ arch/$(ARCH)/mm/
 core-y		+= arch/$(ARCH)/$(SARCH)/kernel/ arch/$(ARCH)/$(SARCH)/mm/
+ifdef CONFIG_ETRAX_ARCH_V32
+core-y		+= arch/$(ARCH)/$(SARCH)/$(MACH)/
+endif
 drivers-y	+= arch/$(ARCH)/$(SARCH)/drivers/
 libs-y		+= arch/$(ARCH)/$(SARCH)/lib/ $(LIBGCC)
 
@@ -52,79 +63,69 @@ SRC_ARCH              = $(srctree)/arch/$(ARCH)
 # cris object files path
 OBJ_ARCH              = $(objtree)/arch/$(ARCH)
 
-target_boot_arch_dir  = $(OBJ_ARCH)/$(SARCH)/boot
-target_boot_dir       = $(OBJ_ARCH)/boot
-src_boot_dir          = $(SRC_ARCH)/boot
-target_compressed_dir = $(OBJ_ARCH)/boot/compressed
-src_compressed_dir    = $(SRC_ARCH)/boot/compressed
-target_rescue_dir     = $(OBJ_ARCH)/boot/rescue
-src_rescue_dir        = $(SRC_ARCH)/boot/rescue
-
-export target_boot_arch_dir target_boot_dir src_boot_dir target_compressed_dir src_compressed_dir target_rescue_dir src_rescue_dir
-
-vmlinux.bin: vmlinux
-	$(OBJCOPY) $(OBJCOPYFLAGS) vmlinux vmlinux.bin
-
-timage: vmlinux.bin
-	cat vmlinux.bin cramfs.img >timage
-
-simimage: timage
-	cp vmlinux.bin simvmlinux.bin
-
-# the following will remake timage without compiling the kernel
-# it does of course require that all object files exist...
-
-cramfs:
-## cramfs      - Creates a cramfs image
-	mkcramfs -b 8192 -m romfs_meta.txt root cramfs.img
-	cat vmlinux.bin cramfs.img >timage
+boot := arch/$(ARCH)/boot
+MACHINE := arch/$(ARCH)/$(SARCH)
 
-clinux: vmlinux.bin decompress.bin rescue.bin
+all: zImage
 
-decompress.bin: $(target_boot_dir)
-	@$(MAKE) -f $(src_compressed_dir)/Makefile $(target_compressed_dir)/decompress.bin
+zImage Image: vmlinux
+	$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
 
-$(target_rescue_dir)/rescue.bin: $(target_boot_dir)
-	@$(MAKE) -f $(src_rescue_dir)/Makefile $(target_rescue_dir)/rescue.bin
-
-zImage: $(target_boot_dir) vmlinux.bin $(target_rescue_dir)/rescue.bin
-## zImage     - Compressed kernel (gzip)
-	@$(MAKE) -f $(src_boot_dir)/Makefile zImage
-
-$(target_boot_dir): $(target_boot_arch_dir)
-	ln -sfn $< $@
-
-$(target_boot_arch_dir):
-	mkdir -p $@
-
-compressed: zImage
-
-archmrproper:
-archclean:
-	@if [ -d arch/$(ARCH)/boot ]; then \
-		$(MAKE) $(clean)=arch/$(ARCH)/boot ; \
-	fi
-	rm -f timage vmlinux.bin decompress.bin rescue.bin cramfs.img
-	rm -rf $(LD_SCRIPT).tmp
-
-archprepare: $(SRC_ARCH)/.links $(srctree)/include/asm-$(ARCH)/.arch
+archprepare: $(SRC_ARCH)/.links $(srctree)/include/asm-$(ARCH)/.arch FORCE
 
 # Create some links to make all tools happy
 $(SRC_ARCH)/.links:
 	@rm -rf $(SRC_ARCH)/drivers
-	@ln -sfn $(SRC_ARCH)/$(SARCH)/drivers $(SRC_ARCH)/drivers
+	@ln -sfn $(SARCH)/drivers $(SRC_ARCH)/drivers
 	@rm -rf $(SRC_ARCH)/boot
-	@ln -sfn $(SRC_ARCH)/$(SARCH)/boot $(SRC_ARCH)/boot
+	@ln -sfn $(SARCH)/boot $(SRC_ARCH)/boot
 	@rm -rf $(SRC_ARCH)/lib
-	@ln -sfn $(SRC_ARCH)/$(SARCH)/lib $(SRC_ARCH)/lib
-	@ln -sfn $(SRC_ARCH)/$(SARCH) $(SRC_ARCH)/arch
-	@ln -sfn $(SRC_ARCH)/$(SARCH)/vmlinux.lds.S $(SRC_ARCH)/kernel/vmlinux.lds.S
-	@ln -sfn $(SRC_ARCH)/$(SARCH)/kernel/asm-offsets.c $(SRC_ARCH)/kernel/asm-offsets.c
+	@ln -sfn $(SARCH)/lib $(SRC_ARCH)/lib
+	@rm -f $(SRC_ARCH)/arch/mach
+	@rm -rf $(SRC_ARCH)/arch
+	@ln -sfn $(SARCH) $(SRC_ARCH)/arch
+ifdef CONFIG_ETRAX_ARCH_V32
+	@ln -sfn ../$(SARCH)/$(MACH) $(SRC_ARCH)/arch/mach
+endif
+	@rm -rf $(SRC_ARCH)/kernel/vmlinux.lds.S
+	@ln -sfn ../$(SARCH)/vmlinux.lds.S $(SRC_ARCH)/kernel/vmlinux.lds.S
+	@rm -rf $(SRC_ARCH)/kernel/asm-offsets.c
+	@ln -sfn ../$(SARCH)/kernel/asm-offsets.c $(SRC_ARCH)/kernel/asm-offsets.c
 	@touch $@
 
 # Create link to sub arch includes
 $(srctree)/include/asm-$(ARCH)/.arch: $(wildcard include/config/arch/*.h)
-	@echo '  Making $(srctree)/include/asm-$(ARCH)/arch -> $(srctree)/include/asm-$(ARCH)/$(SARCH) symlink'
-	@rm -f include/asm-$(ARCH)/arch
-	@ln -sf $(srctree)/include/asm-$(ARCH)/$(SARCH) $(srctree)/include/asm-$(ARCH)/arch
+	@echo '  SYMLINK include/asm-$(ARCH)/arch -> include/asm-$(ARCH)/$(SARCH)'
+	@rm -f $(srctree)/include/asm-$(ARCH)/arch/mach
+	@rm -f $(srctree)/include/asm-$(ARCH)/arch
+	@ln -sf $(SARCH) $(srctree)/include/asm-$(ARCH)/arch
+ifdef CONFIG_ETRAX_ARCH_V32
+	@ln -sf $(MACH) $(srctree)/include/asm-$(ARCH)/arch/mach
+endif
 	@touch $@
+
+archclean:
+	$(Q)if [ -e arch/$(ARCH)/boot ]; then \
+		$(MAKE) $(clean)=arch/$(ARCH)/boot; \
+	fi
+
+CLEAN_FILES += \
+	$(MACHINE)/boot/zImage \
+	$(MACHINE)/boot/compressed/decompress.bin \
+	$(MACHINE)/boot/compressed/piggy.gz \
+	$(MACHINE)/boot/rescue/rescue.bin \
+	$(SRC_ARCH)/.links \
+	$(srctree)/include/asm-$(ARCH)/.arch
+
+MRPROPER_FILES += \
+	$(SRC_ARCH)/drivers \
+	$(SRC_ARCH)/boot \
+	$(SRC_ARCH)/lib \
+	$(SRC_ARCH)/arch \
+	$(SRC_ARCH)/kernel/vmlinux.lds.S \
+	$(SRC_ARCH)/kernel/asm-offsets.c
+
+define archhelp
+  echo  '* zImage        - Compressed kernel image (arch/$(ARCH)/boot/zImage)'
+  echo  '* Image         - Uncompressed kernel image (arch/$(ARCH)/boot/Image)'
+endef
diff --git a/arch/cris/arch-v10/Kconfig b/arch/cris/arch-v10/Kconfig
index 1d61faec77cd..adc164e99339 100644
--- a/arch/cris/arch-v10/Kconfig
+++ b/arch/cris/arch-v10/Kconfig
@@ -1,5 +1,7 @@
 if ETRAX_ARCH_V10
 
+menu "CRIS v10 options"
+
 # ETRAX 100LX v1 has a MMU "feature" requiring a low mapping
 config CRIS_LOW_MAP
 	bool
@@ -228,69 +230,6 @@ config ETRAX_LED12R
 	  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 "Kernel GDB port"
-	depends on ETRAX_KGDB
-	default ETRAX_KGDB_PORT0
-	help
-	  Choose a serial port for kernel debugging.  NOTE: This port should
-	  not be enabled under Drivers for built-in interfaces (as it has its
-	  own initialization code) and should not be the same as the debug port.
-
-config ETRAX_KGDB_PORT0
-	bool "Serial-0"
-	help
-	  Use serial port 0 for kernel debugging.
-
-config ETRAX_KGDB_PORT1
-	bool "Serial-1"
-	help
-	  Use serial port 1 for kernel debugging.
-
-config ETRAX_KGDB_PORT2
-	bool "Serial-2"
-	help
-	  Use serial port 2 for kernel debugging.
-
-config ETRAX_KGDB_PORT3
-	bool "Serial-3"
-	help
-	  Use serial port 3 for kernel debugging.
-
-endchoice
 
 choice
 	prompt "Product rescue-port"
@@ -454,4 +393,6 @@ config ETRAX_POWERBUTTON_BIT
 	help
 	  Configure where power button is connected.
 
+endmenu
+
 endif
diff --git a/arch/cris/arch-v10/boot/Makefile b/arch/cris/arch-v10/boot/Makefile
index e5b105851108..20c83a53caf3 100644
--- a/arch/cris/arch-v10/boot/Makefile
+++ b/arch/cris/arch-v10/boot/Makefile
@@ -1,13 +1,21 @@
 #
-# arch/cris/boot/Makefile
+# arch/cris/arch-v10/boot/Makefile
 #
-target = $(target_boot_dir)
-src    = $(src_boot_dir)
 
-zImage: compressed/vmlinuz
+OBJCOPY = objcopy-cris
+OBJCOPYFLAGS = -O binary --remove-section=.bss
 
-compressed/vmlinuz:
-	@$(MAKE) -f $(src)/compressed/Makefile $(target_compressed_dir)/vmlinuz
+subdir- := compressed rescue
+targets := Image
 
-clean:
-	@$(MAKE) -f $(src)/compressed/Makefile clean
+$(obj)/Image: vmlinux FORCE
+	$(call if_changed,objcopy)
+	@echo '  Kernel: $@ is ready'
+
+$(obj)/compressed/vmlinux: $(obj)/Image FORCE
+	$(Q)$(MAKE) $(build)=$(obj)/compressed $@
+	$(Q)$(MAKE) $(build)=$(obj)/rescue $(obj)/rescue/rescue.bin
+
+$(obj)/zImage:  $(obj)/compressed/vmlinux
+	@cp $< $@
+	@echo '  Kernel: $@ is ready'
diff --git a/arch/cris/arch-v10/boot/compressed/Makefile b/arch/cris/arch-v10/boot/compressed/Makefile
index 6584a44820f4..4a031cb27eb9 100644
--- a/arch/cris/arch-v10/boot/compressed/Makefile
+++ b/arch/cris/arch-v10/boot/compressed/Makefile
@@ -1,45 +1,35 @@
 #
-# create a compressed vmlinuz image from the binary vmlinux.bin file
+# arch/cris/arch-v10/boot/compressed/Makefile
 #
-target = $(target_compressed_dir)
-src    = $(src_compressed_dir)
 
 CC = gcc-cris -melf $(LINUXINCLUDE)
-CFLAGS = -O2
+ccflags-y += -O2
 LD = ld-cris
+ldflags-y += -T $(obj)/decompress.ld
+OBJECTS = $(obj)/head.o $(obj)/misc.o
 OBJCOPY = objcopy-cris
 OBJCOPYFLAGS = -O binary --remove-section=.bss
-OBJECTS = $(target)/head.o $(target)/misc.o
 
-# files to compress
-SYSTEM = $(objtree)/vmlinux.bin
+quiet_cmd_image = BUILD   $@
+cmd_image = cat $(obj)/decompress.bin $(obj)/piggy.gz > $@
 
-all: $(target_compressed_dir)/vmlinuz
+targets := vmlinux piggy.gz decompress.o decompress.bin
 
-$(target)/decompress.bin: $(OBJECTS)
-	$(LD) -T $(src)/decompress.ld -o $(target)/decompress.o $(OBJECTS)
-	$(OBJCOPY) $(OBJCOPYFLAGS) $(target)/decompress.o $(target)/decompress.bin
+$(obj)/decompress.o: $(OBJECTS) FORCE
+	$(call if_changed,ld)
 
-# Create vmlinuz image in top-level build directory
-$(target_compressed_dir)/vmlinuz: $(target) piggy.img $(target)/decompress.bin
-	@echo "  COMPR   vmlinux.bin --> vmlinuz"
-	@cat $(target)/decompress.bin piggy.img > $(target_compressed_dir)/vmlinuz
-	@rm -f piggy.img
+$(obj)/decompress.bin: $(obj)/decompress.o FORCE
+	$(call if_changed,objcopy)
 
-$(target)/head.o: $(src)/head.S
-	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $@
+$(obj)/head.o: $(obj)/head.S .config
+	@$(CC) -D__ASSEMBLY__ -traditional -c $< -o $@
 
-$(target)/misc.o: $(src)/misc.c
-	$(CC) -D__KERNEL__ -c $< -o $@
+$(obj)/misc.o: $(obj)/misc.c .config
+	@$(CC) -D__KERNEL__ -c $< -o $@
 
-# gzip the kernel image
+$(obj)/vmlinux: $(obj)/piggy.gz $(obj)/decompress.bin FORCE
+	$(call if_changed,image)
 
-piggy.img: $(SYSTEM)
-	@cat $(SYSTEM) | gzip -f -9 > piggy.img
-
-$(target):
-	mkdir -p $(target)
-
-clean:
-	rm -f piggy.img $(objtree)/vmlinuz
+$(obj)/piggy.gz: $(obj)/../Image FORCE
+	$(call if_changed,gzip)
 
diff --git a/arch/cris/arch-v10/boot/compressed/misc.c b/arch/cris/arch-v10/boot/compressed/misc.c
index e205d2e7e089..9a43ab19391e 100644
--- a/arch/cris/arch-v10/boot/compressed/misc.c
+++ b/arch/cris/arch-v10/boot/compressed/misc.c
@@ -1,15 +1,13 @@
 /*
  * 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 
+ * 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
  * adaptation for Linux/CRIS Axis Communications AB, 1999
- * 
+ *
  */
 
 /* where the piggybacked kernel image expects itself to live.
diff --git a/arch/cris/arch-v10/boot/rescue/Makefile b/arch/cris/arch-v10/boot/rescue/Makefile
index 8be9b3130312..2e5045b9e19c 100644
--- a/arch/cris/arch-v10/boot/rescue/Makefile
+++ b/arch/cris/arch-v10/boot/rescue/Makefile
@@ -1,56 +1,38 @@
 #
-# Makefile for rescue code
+# Makefile for rescue (bootstrap) code
 #
-target = $(target_rescue_dir)
-src    = $(src_rescue_dir)
 
 CC = gcc-cris -mlinux $(LINUXINCLUDE)
-CFLAGS = -O2
+ccflags-y += -O2
+asflags-y += -traditional
 LD = gcc-cris -mlinux -nostdlib
+ldflags-y += -T $(obj)/rescue.ld
 OBJCOPY = objcopy-cris
 OBJCOPYFLAGS = -O binary --remove-section=.bss
+obj-$(CONFIG_ETRAX_AXISFLASHMAP) = head.o
+OBJECT := $(obj)/head.o
 
-all: $(target)/rescue.bin $(target)/testrescue.bin $(target)/kimagerescue.bin
+targets := rescue.o rescue.bin
 
-$(target)/rescue.bin: $(target) $(target)/head.o
-	$(LD) -T $(src)/rescue.ld -o $(target)/rescue.o $(target)/head.o
-	$(OBJCOPY) $(OBJCOPYFLAGS) $(target)/rescue.o $(target)/rescue.bin
-# Place a copy in top-level build directory
-	cp -p $(target)/rescue.bin $(objtree)
+$(obj)/rescue.o: $(OBJECT) FORCE
+	$(call if_changed,ld)
 
-$(target)/testrescue.bin: $(target) $(target)/testrescue.o
-	$(OBJCOPY) $(OBJCOPYFLAGS) $(target)/testrescue.o tr.bin
+$(obj)/rescue.bin: $(obj)/rescue.o FORCE
+	$(call if_changed,objcopy)
+	cp -p $(obj)/rescue.bin $(objtree)
+
+$(obj)/testrescue.bin: $(obj)/testrescue.o
+	$(OBJCOPY) $(OBJCOPYFLAGS) $(obj)/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=$(target)/testrescue.bin bs=1 count=784
+	dd if=testrescue_tmp.bin of=$(obj)/testrescue.bin bs=1 count=784
 	rm tr.bin tmp2423 testrescue_tmp.bin
 
-$(target)/kimagerescue.bin: $(target) $(target)/kimagerescue.o
-	$(OBJCOPY) $(OBJCOPYFLAGS) $(target)/kimagerescue.o ktr.bin
+$(obj)/kimagerescue.bin: $(obj)/kimagerescue.o
+	$(OBJCOPY) $(OBJCOPYFLAGS) $(obj)/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=$(target)/kimagerescue.bin bs=1 count=784
+	dd if=kimagerescue_tmp.bin of=$(obj)/kimagerescue.bin bs=1 count=784
 	rm ktr.bin tmp2423 kimagerescue_tmp.bin
-
-$(target):
-	mkdir -p $(target)
-
-$(target)/head.o: $(src)/head.S
-	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
-
-$(target)/testrescue.o: $(src)/testrescue.S
-	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
-
-$(target)/kimagerescue.o: $(src)/kimagerescue.S
-	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
-
-clean:
-	rm -f $(target)/*.o $(target)/*.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
index f223cc0c00bb..6ba7be8ac4a0 100644
--- a/arch/cris/arch-v10/boot/rescue/head.S
+++ b/arch/cris/arch-v10/boot/rescue/head.S
@@ -1,5 +1,4 @@
-/* $Id: head.S,v 1.7 2005/03/07 12:11:06 starvik 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.
@@ -23,20 +22,20 @@
  * 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):	
- * 
+ *     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:	
- *    
+ *     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]
@@ -47,9 +46,9 @@
  *     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
@@ -59,26 +58,29 @@
  *
  * 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
+ *
+ * Copyright (C) 1999-2007 Axis Communications AB
  */
 
+#ifdef CONFIG_ETRAX_AXISFLASHMAP
+
 #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.
-		
+	;; 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
 
@@ -102,7 +104,7 @@
 #define SERRECC R_SERIAL2_REC_CTRL
 #define SERRDAT R_SERIAL2_REC_DATA
 #define SERSTAT R_SERIAL2_STATUS
-#endif	
+#endif
 #ifdef CONFIG_ETRAX_RESCUE_SER3
 #define SERXOFF R_SERIAL3_XOFF
 #define SERBAUD R_SERIAL3_BAUD
@@ -115,60 +117,61 @@
 #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
+	;; 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	
+	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
+	;; 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:	
+jumptarget:
 	.dword	0xffffffff	; can be overwritten later to insert new code
-	
+
 no_newjump:
-#ifdef CONFIG_ETRAX_ETHERNET		
+#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
@@ -186,11 +189,11 @@ no_newjump:
 	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..
@@ -199,7 +202,7 @@ ploop:	move.d	[$r3+], $r1	; partition offset (from ptable start)
 	sub.d	$r8, $r2	; minus the ptable length
 	ba	bosse
 	nop
-notfirst:	
+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
@@ -213,47 +216,46 @@ bosse:	move.d	[$r3+], $r5	; checksum
 	bpl	1f
 	nop
 	move.d	$r1, $r7	; remember boot partition offset
-1:	
-
+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.d	$r0, [SERXOFF]
 
 	move.b	0x99, $r0
-	move.b	$r0, [SERBAUD]		; 115.2kbaud for both transmit and receive
+	move.b	$r0, [SERBAUD]	; 115.2kbaud for both transmit and receive
 
-	move.b	0x40, $r0		; rec enable
-	move.b	$r0, [SERRECC] 
+	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
@@ -272,20 +274,20 @@ wait_ser:
 	nop
 1:	not	$r0		; clear bit
 	and.d	$r0, $r2
-2:	
+2:
 #ifdef CONFIG_ETRAX_PA_LEDS
-	move.b	$r2, [R_PORT_PA_DATA]	
-#endif	
+	move.b	$r2, [R_PORT_PA_DATA]
+#endif
 #ifdef CONFIG_ETRAX_PB_LEDS
-	move.b	$r2, [R_PORT_PB_DATA]	
+	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
@@ -295,14 +297,15 @@ wait_ser:
 
 	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
+	move.d	RAM_INIT_MAGIC, $r8	; Tell next product that DRAM is
+					; initialized
 	jump	CODE_START
 
 flash_ok:
@@ -313,7 +316,8 @@ flash_ok:
 	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
+	move.d	RAM_INIT_MAGIC, $r8	; Tell next product that DRAM is
+					; initialized
 	jump	$r7		; boot!
 
 
@@ -327,7 +331,8 @@ checksum:
 	moveq	0, $r0
 	moveq   CONFIG_ETRAX_FLASH1_SIZE, $r6
 
-	;; If the first physical flash memory is exceeded wrap to the second one.
+	;; If the first physical flash memory is exceeded wrap to the
+	;; second one
 	btstq	26, $r1		; Are we addressing first flash?
 	bpl	1f
 	nop
@@ -351,3 +356,5 @@ checksum:
 3:	move.d	MEM_CSE1_START, $r1 ; wrap to second flash
 	ba	2b
 	nop
+
+#endif
diff --git a/arch/cris/arch-v10/boot/rescue/kimagerescue.S b/arch/cris/arch-v10/boot/rescue/kimagerescue.S
index cbccd6316d39..55eeff8bb08e 100644
--- a/arch/cris/arch-v10/boot/rescue/kimagerescue.S
+++ b/arch/cris/arch-v10/boot/rescue/kimagerescue.S
@@ -1,5 +1,4 @@
-/* $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
@@ -7,13 +6,13 @@
  */
 
 #define ASSEMBLER_MACROS_ONLY
-#include <asm/sv_addr_ag.h>
+#include <asm/arch/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
@@ -34,7 +33,7 @@
 #define SERRECC R_SERIAL2_REC_CTRL
 #define SERRDAT R_SERIAL2_REC_DATA
 #define SERSTAT R_SERIAL2_STATUS
-#endif	
+#endif
 #ifdef CONFIG_ETRAX_RESCUE_SER3
 #define SERXOFF R_SERIAL3_XOFF
 #define SERBAUD R_SERIAL3_BAUD
@@ -48,54 +47,55 @@
 	;; 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	
+
+	nop
 	di
-#ifndef CONFIG_SVINTO_SIM	
+#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.d	$r0, [SERXOFF]
 
 	move.b	0x99, $r0
-	move.b	$r0, [SERBAUD]		; 115.2kbaud for both transmit and receive
+	move.b	$r0, [SERBAUD]		; 115.2kbaud for both transmit
+					; and receive
 
 	move.b	0x40, $r0		; rec enable
-	move.b	$r0, [SERRECC] 
+	move.b	$r0, [SERRECC]
 
 
-	moveq	0, $r1		; "timer" to clock out a LED red flash
-	move.d	CODE_START, $r3	; destination counter
+	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
+	subq	1, $r5			; decrease timeout
+	beq	jump_start		; timed out
 	nop
 #ifndef CONFIG_ETRAX_NO_LEDS
 #ifdef CONFIG_ETRAX_PA_LEDS
@@ -111,21 +111,21 @@ wait_ser:
 	or.d	$r0, $r2		; set bit
 	ba	2f
 	nop
-1:	not	$r0		; clear bit
+1:	not	$r0			; clear bit
 	and.d	$r0, $r2
-2:	
+2:
 #ifdef CONFIG_ETRAX_PA_LEDS
 	move.b	$r2, [R_PORT_PA_DATA]
-#endif	
+#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
+	btstq	0, $r0			; data_avail
 	bpl	wait_ser
 	nop
 
@@ -134,7 +134,7 @@ wait_ser:
 	move.b	[SERRDAT], $r0
 	move.b	$r0, [$r3+]
 	move.d	TIMEOUT_VALUE, $r5	; reset "timeout"
-	subq	1, $r4		; decrease length
+	subq	1, $r4			; decrease length
 	bne	wait_ser
 	nop
 jump_start:
diff --git a/arch/cris/arch-v10/boot/rescue/testrescue.S b/arch/cris/arch-v10/boot/rescue/testrescue.S
index 566a9f341254..2d937f9afe23 100644
--- a/arch/cris/arch-v10/boot/rescue/testrescue.S
+++ b/arch/cris/arch-v10/boot/rescue/testrescue.S
@@ -1,13 +1,12 @@
-/* $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.
- * 
+ * Just lights some LEDs to show it was downloaded correctly.
+ *
  * Copyright (C) 1999 Axis Communications AB
  */
 
 #define ASSEMBLER_MACROS_ONLY
-#include <asm/sv_addr_ag.h>
+#include <asm/arch/sv_addr_ag.h>
 
 	.text
 
@@ -16,11 +15,10 @@
 	moveq	-1, $r2
 	move.b	$r2, [R_PORT_PA_DIR]
 	moveq	0, $r2
-	move.b	$r2, [R_PORT_PA_DATA]	
+	move.b	$r2, [R_PORT_PA_DATA]
 
 endless:
 	nop
 	ba	endless
 	nop
 
-	
diff --git a/arch/cris/arch-v10/drivers/Kconfig b/arch/cris/arch-v10/drivers/Kconfig
index 96740ef497d4..58f5864a6680 100644
--- a/arch/cris/arch-v10/drivers/Kconfig
+++ b/arch/cris/arch-v10/drivers/Kconfig
@@ -9,37 +9,6 @@ config ETRAX_ETHERNET
 	  This option enables the ETRAX 100LX built-in 10/100Mbit Ethernet
 	  controller.
 
-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
@@ -84,32 +53,6 @@ config ETRAX_SERIAL_PORT0
 	  the same DMA channels.
 
 choice
-	prompt "Ser0 DMA out assignment"
-	depends on ETRAX_SERIAL_PORT0
-	default ETRAX_SERIAL_PORT0_DMA6_OUT
-
-config ETRAX_SERIAL_PORT0_NO_DMA_OUT
-	bool "No DMA out"
-
-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 ETRAX_SERIAL_PORT0_NO_DMA_IN
-	bool "No DMA in"
-
-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
@@ -198,32 +141,6 @@ config ETRAX_SERIAL_PORT1
 	  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 ETRAX_SERIAL_PORT1_NO_DMA_OUT
-	bool "No DMA out"
-
-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 ETRAX_SERIAL_PORT1_NO_DMA_IN
-	bool "No DMA in"
-
-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
@@ -315,32 +232,6 @@ config ETRAX_SERIAL_PORT2
 	  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 ETRAX_SERIAL_PORT2_NO_DMA_OUT
-	bool "No DMA out"
-
-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 ETRAX_SERIAL_PORT2_NO_DMA_IN
-	bool "No DMA in"
-
-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
@@ -429,32 +320,6 @@ config ETRAX_SERIAL_PORT3
 	  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 ETRAX_SERIAL_PORT3_NO_DMA_OUT
-	bool "No DMA out"
-
-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 ETRAX_SERIAL_PORT3_NO_DMA_IN
-	bool "No DMA in"
-
-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
@@ -563,21 +428,6 @@ config ETRAX_USB_HOST_PORT2
 	depends on ETRAX_USB_HOST
 	default n
 
-config ETRAX_AXISFLASHMAP
-	bool "Axis flash-map support"
-	depends on ETRAX_ARCH_V10
-	select MTD
-	select MTD_CFI
-	select MTD_CFI_AMDSTD
-	select MTD_CHAR
-	select MTD_BLOCK
-	select MTD_PARTITIONS
-	select MTD_CONCAT
-	select MTD_COMPLEX_MAPPINGS
-	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
@@ -731,37 +581,6 @@ config ETRAX_PB_CHANGEABLE_BITS
 	  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
diff --git a/arch/cris/arch-v10/drivers/Makefile b/arch/cris/arch-v10/drivers/Makefile
index 20258e36f384..44bf2e88c26e 100644
--- a/arch/cris/arch-v10/drivers/Makefile
+++ b/arch/cris/arch-v10/drivers/Makefile
@@ -2,11 +2,11 @@
 # 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_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
-
+obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL)	+= sync_serial.o
 
diff --git a/arch/cris/arch-v10/drivers/axisflashmap.c b/arch/cris/arch-v10/drivers/axisflashmap.c
index ea3cf2e39a14..b3bdda93ffef 100644
--- a/arch/cris/arch-v10/drivers/axisflashmap.c
+++ b/arch/cris/arch-v10/drivers/axisflashmap.c
@@ -10,129 +10,6 @@
  * 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.11  2004/11/15 10:27:14  starvik
- * Corrected typo (Thanks to Milton Miller <miltonm@bga.com>).
- *
- * 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>
@@ -235,7 +112,7 @@ static struct map_info map_cse1 = {
 };
 
 /* If no partition-table was found, we use this default-set. */
-#define MAX_PARTITIONS         7  
+#define MAX_PARTITIONS         7
 #define NUM_DEFAULT_PARTITIONS 3
 
 /*
@@ -300,6 +177,15 @@ static struct mtd_partition axis_partitions[MAX_PARTITIONS] = {
 	},
 };
 
+#ifdef CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE
+/* Main flash device */
+static struct mtd_partition main_partition = {
+	.name = "main",
+	.size = 0,
+	.offset = 0
+};
+#endif
+
 /*
  * Probe a chip select for AMD-compatible (JEDEC) or CFI-compatible flash
  * chips in that order (because the amd_flash-driver is faster).
@@ -316,15 +202,14 @@ static struct mtd_info *probe_cs(struct map_info *map_cs)
 	mtd_cs = do_map_probe("cfi_probe", map_cs);
 #endif
 #ifdef CONFIG_MTD_JEDECPROBE
-	if (!mtd_cs) {
+	if (!mtd_cs)
 		mtd_cs = do_map_probe("jedec_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.
@@ -351,7 +236,7 @@ static struct mtd_info *flash_probe(void)
 	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
@@ -372,7 +257,7 @@ static struct mtd_info *flash_probe(void)
 
 			/* The best we can do now is to only use what we found
 			 * at cse0.
-			 */ 
+			 */
 			mtd_cse = mtd_cse0;
 			map_destroy(mtd_cse1);
 		}
@@ -395,7 +280,7 @@ static int __init init_axis_flash(void)
 	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";
+	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
@@ -435,7 +320,7 @@ static int __init init_axis_flash(void)
 		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));
 
@@ -490,6 +375,16 @@ static int __init init_axis_flash(void)
 		pidx++;
 	}
 
+#ifdef CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE
+	if (mymtd) {
+		main_partition.size = mymtd->size;
+		err = add_mtd_partitions(mymtd, &main_partition, 1);
+		if (err)
+			panic("axisflashmap: Could not initialize "
+			      "partition for whole main mtd device!\n");
+	}
+#endif
+
         if (mymtd) {
 		if (use_default_ptable) {
 			printk(KERN_INFO " Using default partition table.\n");
@@ -499,9 +394,8 @@ static int __init init_axis_flash(void)
 			err = add_mtd_partitions(mymtd, axis_partitions, pidx);
 		}
 
-		if (err) {
+		if (err)
 			panic("axisflashmap could not add MTD partitions!\n");
-		}
 	}
 
 	if (!romfs_in_flash) {
@@ -515,25 +409,24 @@ static int __init init_axis_flash(void)
 #else
 		struct mtd_info *mtd_ram;
 
-		mtd_ram = kmalloc(sizeof(struct mtd_info),
-						     GFP_KERNEL);
-		if (!mtd_ram) {
+		mtd_ram = 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) {
+		printk(pmsg, pidx, (unsigned)romfs_start,
+			(unsigned)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;
 }
 
diff --git a/arch/cris/arch-v10/drivers/ds1302.c b/arch/cris/arch-v10/drivers/ds1302.c
index 1d1936a18133..c9aa3904be05 100644
--- a/arch/cris/arch-v10/drivers/ds1302.c
+++ b/arch/cris/arch-v10/drivers/ds1302.c
@@ -333,7 +333,7 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 			ds1302_writereg(RTC_TRICKLECHARGER, tcs_val);
 			return 0;
 		}
-		case RTC_VLOW_RD:
+		case RTC_VL_READ:
 		{
 			/* TODO:
 			 * Implement voltage low detection support
@@ -342,7 +342,7 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 			       " is not supported\n");
 			return 0;
 		}
-		case RTC_VLOW_SET:
+		case RTC_VL_CLR:
 		{
 			/* TODO:
 			 * Nothing to do since Voltage Low detection is not supported
diff --git a/arch/cris/arch-v10/drivers/eeprom.c b/arch/cris/arch-v10/drivers/eeprom.c
index be35a70798aa..f1cac9dc75b8 100644
--- a/arch/cris/arch-v10/drivers/eeprom.c
+++ b/arch/cris/arch-v10/drivers/eeprom.c
@@ -19,77 +19,6 @@
 *!  Sep  03 1999  Edgar Iglesias    Added bail-out stuff if we get interrupted
 *!                                  in the spin-lock.
 *!
-*!  $Log: eeprom.c,v $
-*!  Revision 1.12  2005/06/19 17:06:46  starvik
-*!  Merge of Linux 2.6.12.
-*!
-*!  Revision 1.11  2005/01/26 07:14:46  starvik
-*!  Applied diff from kernel janitors (Nish Aravamudan).
-*!
-*!  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 initial 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
 *!*****************************************************************************/
 
@@ -103,10 +32,10 @@
 #include <asm/uaccess.h>
 #include "i2c.h"
 
-#define D(x) 
+#define D(x)
 
 /* If we should use adaptive timing or not: */
-//#define EEPROM_ADAPTIVE_TIMING      
+/* #define EEPROM_ADAPTIVE_TIMING */
 
 #define EEPROM_MAJOR_NR 122  /* use a LOCAL/EXPERIMENTAL major for now */
 #define EEPROM_MINOR_NR 0
diff --git a/arch/cris/arch-v10/drivers/gpio.c b/arch/cris/arch-v10/drivers/gpio.c
index 0d347a705835..68a998bd1069 100644
--- a/arch/cris/arch-v10/drivers/gpio.c
+++ b/arch/cris/arch-v10/drivers/gpio.c
@@ -1,138 +1,11 @@
-/* $Id: gpio.c,v 1.17 2005/06/19 17:06:46 starvik Exp $
- *
+/*
  * Etrax general port I/O device
  *
- * Copyright (c) 1999, 2000, 2001, 2002 Axis Communications AB
+ * Copyright (c) 1999-2007 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.17  2005/06/19 17:06:46  starvik
- * Merge of Linux 2.6.12.
- *
- * Revision 1.16  2005/03/07 13:02:29  starvik
- * Protect driver global states with spinlock
- *
- * Revision 1.15  2005/01/05 06:08:55  starvik
- * No need to do local_irq_disable after local_irq_save.
- *
- * Revision 1.14  2004/12/13 12:21:52  starvik
- * Added I/O and DMA allocators from Linux 2.4
- *
- * 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
- *
- *
  */
 
 
@@ -165,7 +38,7 @@ static int dp_cnt;
 #else
 #define DP(x)
 #endif
-	
+
 static char gpio_name[] = "etrax gpio";
 
 #if 0
@@ -173,9 +46,9 @@ 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);
+	unsigned int cmd, unsigned long arg);
+static ssize_t gpio_write(struct file *file, const char __user *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);
@@ -201,22 +74,22 @@ struct gpio_private {
 
 /* linked list of alarms to check for */
 
-static struct gpio_private *alarmlist = 0;
+static struct gpio_private *alarmlist;
 
-static int gpio_some_alarms = 0; /* Set if someone uses alarm */
-static unsigned long gpio_pa_irq_enabled_mask = 0;
+static int gpio_some_alarms; /* Set if someone uses alarm */
+static unsigned long gpio_pa_irq_enabled_mask;
 
 static DEFINE_SPINLOCK(gpio_lock); /* Protect directions etc */
 
 /* 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, 
+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_pa_data_shadow,
 	&port_pb_data_shadow
 };
 
@@ -236,29 +109,29 @@ static volatile unsigned char *shads[NUM_PORTS] = {
 #endif
 
 
-static unsigned char changeable_dir[NUM_PORTS] = { 
+static unsigned char changeable_dir[NUM_PORTS] = {
 	CONFIG_ETRAX_PA_CHANGEABLE_DIR,
-	CONFIG_ETRAX_PB_CHANGEABLE_DIR 
+	CONFIG_ETRAX_PB_CHANGEABLE_DIR
 };
-static unsigned char changeable_bits[NUM_PORTS] = { 
+static unsigned char changeable_bits[NUM_PORTS] = {
 	CONFIG_ETRAX_PA_CHANGEABLE_BITS,
-	CONFIG_ETRAX_PB_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[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_pa_dir_shadow,
+	&port_pb_dir_shadow
 };
 
 /* All bits in port g that can change dir. */
 static const unsigned long int changeable_dir_g_mask = 0x01FFFF01;
 
-/* Port G is 32 bit, handle it special, some bits are both inputs 
+/* 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;
@@ -269,18 +142,17 @@ 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)
+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;
+	struct gpio_private *priv = file->private_data;
 	unsigned long data;
-	spin_lock(&gpio_lock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&gpio_lock, flags);
+
 	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 -
@@ -288,27 +160,25 @@ gpio_poll(struct file *file,
 		 */
 		tmp = ~data & priv->highalarm & 0xFF;
 		tmp = (tmp << R_IRQ_MASK1_SET__pa0__BITNR);
-		local_irq_save(flags);
+
 		gpio_pa_irq_enabled_mask |= tmp;
 		*R_IRQ_MASK1_SET = tmp;
-		local_irq_restore(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 {
-		spin_unlock(&gpio_lock);
-		return 0;
+		mask = 0;
+		goto out;
 	}
-	
+
 	if ((data & priv->highalarm) ||
 	    (~data & priv->lowalarm)) {
 		mask = POLLIN|POLLRDNORM;
 	}
 
-	spin_unlock(&gpio_lock);
-	
+out:
+	spin_unlock_irqrestore(&gpio_lock, flags);
 	DP(printk("gpio_poll ready: mask 0x%08X\n", mask));
 
 	return mask;
@@ -316,16 +186,19 @@ gpio_poll(struct file *file,
 
 int etrax_gpio_wake_up_check(void)
 {
-	struct gpio_private *priv = alarmlist;
+	struct gpio_private *priv;
 	unsigned long data = 0;
         int ret = 0;
-	spin_lock(&gpio_lock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&gpio_lock, flags);
+	priv = alarmlist;
 	while (priv) {
-		if (USE_PORTS(priv)) {
+		if (USE_PORTS(priv))
 			data = *priv->port;
-		} else if (priv->minor == GPIO_MINOR_G) {
+		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));
@@ -334,12 +207,12 @@ int etrax_gpio_wake_up_check(void)
 		}
 		priv = priv->next;
 	}
-	spin_unlock(&gpio_lock);
+	spin_unlock_irqrestore(&gpio_lock, flags);
         return ret;
 }
 
 static irqreturn_t
-gpio_poll_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+gpio_poll_timer_interrupt(int irq, void *dev_id)
 {
 	if (gpio_some_alarms) {
 		etrax_gpio_wake_up_check();
@@ -349,10 +222,13 @@ gpio_poll_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 }
 
 static irqreturn_t
-gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+gpio_interrupt(int irq, void *dev_id)
 {
 	unsigned long tmp;
-	spin_lock(&gpio_lock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&gpio_lock, flags);
+
 	/* Find what PA interrupts are active */
 	tmp = (*R_IRQ_READ1);
 
@@ -363,75 +239,70 @@ gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 	*R_IRQ_MASK1_CLR = tmp;
 	gpio_pa_irq_enabled_mask &= ~tmp;
 
-	spin_unlock(&gpio_lock);
+	spin_unlock_irqrestore(&gpio_lock, flags);
 
-	if (gpio_some_alarms) {
+	if (gpio_some_alarms)
 		return IRQ_RETVAL(etrax_gpio_wake_up_check());
-	}
+
         return IRQ_NONE;
 }
 
+static void gpio_write_bit(struct gpio_private *priv,
+	unsigned char data, int bit)
+{
+	*priv->port = *priv->shadow &= ~(priv->clk_mask);
+	if (data & 1 << bit)
+		*priv->port = *priv->shadow |= priv->data_mask;
+	else
+		*priv->port = *priv->shadow &= ~(priv->data_mask);
+
+	/* For FPGA: min 5.0ns (DCC) before CCLK high */
+	*priv->port = *priv->shadow |= priv->clk_mask;
+}
 
-static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
-                          loff_t *off)
+static void gpio_write_byte(struct gpio_private *priv, unsigned char data)
 {
-	struct gpio_private *priv = (struct gpio_private *)file->private_data;
-	unsigned char data, clk_mask, data_mask, write_msb;
-	unsigned long flags;
+	int i;
 
-	spin_lock(&gpio_lock);
+	if (priv->write_msb)
+		for (i = 7; i >= 0; i--)
+			gpio_write_bit(priv, data, i);
+	else
+		for (i = 0; i <= 7; i++)
+			gpio_write_bit(priv, data, i);
+}
 
+static ssize_t gpio_write(struct file *file, const char __user *buf,
+	size_t count, loff_t *off)
+{
+	struct gpio_private *priv = file->private_data;
+	unsigned long flags;
 	ssize_t retval = count;
-	if (priv->minor !=GPIO_MINOR_A && priv->minor != GPIO_MINOR_B) {
-		retval = -EFAULT;
-		goto out;
-	}
-    
-	if (!access_ok(VERIFY_READ, buf, count)) {
-		retval = -EFAULT;
-		goto out;
-	}
-	clk_mask = priv->clk_mask;
-	data_mask = priv->data_mask;
+
+	if (priv->minor != GPIO_MINOR_A && priv->minor != GPIO_MINOR_B)
+		return -EFAULT;
+
+	if (!access_ok(VERIFY_READ, buf, count))
+		return -EFAULT;
+
+	spin_lock_irqsave(&gpio_lock, flags);
+
 	/* It must have been configured using the IO_CFG_WRITE_MODE */
 	/* Perhaps a better error code? */
-	if (clk_mask == 0 || data_mask == 0) {
+	if (priv->clk_mask == 0 || priv->data_mask == 0) {
 		retval = -EPERM;
 		goto out;
 	}
-	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);
-				*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);
-				*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);
-			}
-		}
-	}
+
+	D(printk(KERN_DEBUG "gpio_write: %02X to data 0x%02X "
+		"clk 0x%02X msb: %i\n",
+		count, priv->data_mask, priv->clk_mask, priv->write_msb));
+
+	while (count--)
+		gpio_write_byte(priv, *buf++);
+
 out:
-	spin_unlock(&gpio_lock);
+	spin_unlock_irqrestore(&gpio_lock, flags);
 	return retval;
 }
 
@@ -442,22 +313,20 @@ gpio_open(struct inode *inode, struct file *filp)
 {
 	struct gpio_private *priv;
 	int p = iminor(inode);
+	unsigned long flags;
 
 	if (p > GPIO_MINOR_LAST)
 		return -EINVAL;
 
-	priv = kmalloc(sizeof(struct gpio_private),
-					      GFP_KERNEL);
+	priv = kzalloc(sizeof(struct gpio_private), GFP_KERNEL);
 
 	if (!priv)
 		return -ENOMEM;
 
 	priv->minor = p;
 
-	/* initialize the io/alarm struct and link it into our alarmlist */
+	/* initialize the io/alarm struct */
 
-	priv->next = alarmlist;
-	alarmlist = priv;
 	if (USE_PORTS(priv)) { /* A and B */
 		priv->port = ports[p];
 		priv->shadow = shads[p];
@@ -480,7 +349,13 @@ gpio_open(struct inode *inode, struct file *filp)
 	priv->data_mask = 0;
 	init_waitqueue_head(&priv->alarm_wq);
 
-	filp->private_data = (void *)priv;
+	filp->private_data = priv;
+
+	/* link it into our alarmlist */
+	spin_lock_irqsave(&gpio_lock, flags);
+	priv->next = alarmlist;
+	alarmlist = priv;
+	spin_unlock_irqrestore(&gpio_lock, flags);
 
 	return 0;
 }
@@ -490,11 +365,12 @@ gpio_release(struct inode *inode, struct file *filp)
 {
 	struct gpio_private *p;
 	struct gpio_private *todel;
+	unsigned long flags;
 
-	spin_lock(&gpio_lock);
+	spin_lock_irqsave(&gpio_lock, flags);
 
-        p = alarmlist;
-        todel = (struct gpio_private *)filp->private_data;
+	p = alarmlist;
+	todel = filp->private_data;
 
 	/* unlink from alarmlist and free the private structure */
 
@@ -512,123 +388,114 @@ gpio_release(struct inode *inode, struct file *filp)
 	while (p) {
 		if (p->highalarm | p->lowalarm) {
 			gpio_some_alarms = 1;
-			spin_unlock(&gpio_lock);
-			return 0;
+			goto out;
 		}
 		p = p->next;
 	}
 	gpio_some_alarms = 0;
-	spin_unlock(&gpio_lock);
+out:
+	spin_unlock_irqrestore(&gpio_lock, flags);
 	return 0;
 }
 
-/* Main device API. ioctl's to read/set/clear bits, as well as to 
+/* 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;
+	/* Set direction 0=unchanged 1=input,
+	 * return mask with 1=input */
 	if (USE_PORTS(priv)) {
-		local_irq_save(flags);
-		*priv->dir = *priv->dir_shadow &= 
+		*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 */
-		local_irq_save(flags);
-		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 */
-				
+	}
+
+	if (priv->minor != GPIO_MINOR_G)
+		return 0;
+
+	/* We must fiddle with R_GEN_CONFIG to change dir */
+	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);
 		}
-		local_irq_restore(flags);
-		return dir_g_in_bits;
+		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_DEBUG "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 */
+
 	}
-	return 0;
+	return dir_g_in_bits;
 } /* 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);
-		*priv->dir = *priv->dir_shadow |= 
-		  ((unsigned char)arg & priv->changeable_dir);
-		local_irq_restore(flags);
+		*priv->dir = *priv->dir_shadow |=
+			((unsigned char)arg & priv->changeable_dir);
 		return *priv->dir_shadow;
-	} else if (priv->minor == GPIO_MINOR_G) {
-		/* We must fiddle with R_GEN_CONFIG to change dir */			
-		local_irq_save(flags);
-		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 */
+	}
+	if (priv->minor != GPIO_MINOR_G)
+		return 0;
+
+	/* We must fiddle with R_GEN_CONFIG to change dir */
+	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);
 		}
-		local_irq_restore(flags);
-		return dir_g_out_bits & 0x7FFFFFFF;
+		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 */
 	}
-	return 0;
+	return dir_g_out_bits & 0x7FFFFFFF;
 } /* setget_output */
 
 static int
@@ -642,12 +509,11 @@ gpio_ioctl(struct inode *inode, struct file *file,
 	unsigned long val;
         int ret = 0;
 
-	struct gpio_private *priv = (struct gpio_private *)file->private_data;
-	if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) {
+	struct gpio_private *priv = file->private_data;
+	if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE)
 		return -EINVAL;
-	}
 
-	spin_lock(&gpio_lock);
+	spin_lock_irqsave(&gpio_lock, flags);
 
 	switch (_IOC_NR(cmd)) {
 	case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */
@@ -659,7 +525,6 @@ gpio_ioctl(struct inode *inode, struct file *file,
 		}
 		break;
 	case IO_SETBITS:
-		local_irq_save(flags);
 		// set changeable bits with a 1 in arg
 		if (USE_PORTS(priv)) {
 			*priv->port = *priv->shadow |= 
@@ -667,10 +532,8 @@ gpio_ioctl(struct inode *inode, struct file *file,
 		} 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);
 		// clear changeable bits with a 1 in arg
 		if (USE_PORTS(priv)) {
 			*priv->port = *priv->shadow &= 
@@ -678,7 +541,6 @@ gpio_ioctl(struct inode *inode, struct file *file,
 		} 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
@@ -698,6 +560,8 @@ gpio_ioctl(struct inode *inode, struct file *file,
 			/* Must update gpio_some_alarms */
 			struct gpio_private *p = alarmlist;
 			int some_alarms;
+			spin_lock_irq(&gpio_lock);
+			p = alarmlist;
 			some_alarms = 0;
 			while (p) {
 				if (p->highalarm | p->lowalarm) {
@@ -707,6 +571,7 @@ gpio_ioctl(struct inode *inode, struct file *file,
 				p = p->next;
 			}
 			gpio_some_alarms = some_alarms;
+			spin_unlock_irq(&gpio_lock);
 		}
 		break;
 	case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */
@@ -766,7 +631,7 @@ gpio_ioctl(struct inode *inode, struct file *file,
 		} else if (priv->minor == GPIO_MINOR_G) {
 			val = *R_PORT_G_DATA;
 		}
-		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
+		if (copy_to_user((void __user *)arg, &val, sizeof(val)))
 			ret = -EFAULT;
 		break;
 	case IO_READ_OUTBITS:
@@ -776,33 +641,32 @@ gpio_ioctl(struct inode *inode, struct file *file,
 		} else if (priv->minor == GPIO_MINOR_G) {
 			val = port_g_data_shadow;
 		}
-		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
+		if (copy_to_user((void __user *)arg, &val, sizeof(val)))
 			ret = -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)))
+		if (copy_from_user(&val, (void __user *)arg, sizeof(val)))
 		{
 			ret = -EFAULT;
 			break;
 		}
 		val = setget_input(priv, val);
-		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
+		if (copy_to_user((void __user *)arg, &val, sizeof(val)))
 			ret = -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)))
-		{
+		if (copy_from_user(&val, (void __user *)arg, sizeof(val))) {
 			ret = -EFAULT;
 			break;
 		}
 		val = setget_output(priv, val);
-		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
+		if (copy_to_user((void __user *)arg, &val, sizeof(val)))
 			ret = -EFAULT;
 		break;
 	default:
@@ -812,7 +676,7 @@ gpio_ioctl(struct inode *inode, struct file *file,
 			ret = -EINVAL;
 	} /* switch */
 
-	spin_unlock(&gpio_lock);
+	spin_unlock_irqrestore(&gpio_lock, flags);
 	return ret;
 }
 
@@ -824,18 +688,18 @@ gpio_leds_ioctl(unsigned int cmd, unsigned long arg)
 
 	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);
+		green = ((unsigned char)arg) & 1;
+		red   = (((unsigned char)arg) >> 1) & 1;
+		CRIS_LED_ACTIVE_SET_G(green);
+		CRIS_LED_ACTIVE_SET_R(red);
 		break;
 
 	case IO_LED_SETBIT:
-		LED_BIT_SET(arg);
+		CRIS_LED_BIT_SET(arg);
 		break;
 
 	case IO_LED_CLRBIT:
-		LED_BIT_CLR(arg);
+		CRIS_LED_BIT_CLR(arg);
 		break;
 
 	default:
@@ -845,7 +709,7 @@ gpio_leds_ioctl(unsigned int cmd, unsigned long arg)
 	return 0;
 }
 
-const struct file_operations gpio_fops = {
+static const struct file_operations gpio_fops = {
 	.owner       = THIS_MODULE,
 	.poll        = gpio_poll,
 	.ioctl       = gpio_ioctl,
@@ -854,16 +718,18 @@ const struct file_operations gpio_fops = {
 	.release     = gpio_release,
 };
 
-
-void ioif_watcher(const unsigned int gpio_in_available,
-		  const unsigned int gpio_out_available,
-		  const unsigned char pa_available,
-		  const unsigned char pb_available)
+static void ioif_watcher(const unsigned int gpio_in_available,
+	const unsigned int gpio_out_available,
+	const unsigned char pa_available,
+	const unsigned char pb_available)
 {
 	unsigned long int flags;
-	D(printk("gpio.c: ioif_watcher called\n"));
-	D(printk("gpio.c: G in: 0x%08x G out: 0x%08x PA: 0x%02x PB: 0x%02x\n",
-		 gpio_in_available, gpio_out_available, pa_available, pb_available));
+
+	D(printk(KERN_DEBUG "gpio.c: ioif_watcher called\n"));
+	D(printk(KERN_DEBUG "gpio.c: G in: 0x%08x G out: 0x%08x "
+		"PA: 0x%02x PB: 0x%02x\n",
+		gpio_in_available, gpio_out_available,
+		pa_available, pb_available));
 
 	spin_lock_irqsave(&gpio_lock, flags);
 
@@ -872,7 +738,7 @@ void ioif_watcher(const unsigned int gpio_in_available,
 
 	/* Initialise the dir_g_shadow etc. depending on genconfig */
 	/* 0=input 1=output */
-	if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g0dir, out)) 
+	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;
@@ -884,7 +750,8 @@ void ioif_watcher(const unsigned int gpio_in_available,
 	changeable_dir_g = changeable_dir_g_mask;
 	changeable_dir_g &= dir_g_out_bits;
 	changeable_dir_g &= dir_g_in_bits;
-	/* Correct the bits that can change direction */ 
+
+	/* 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;
@@ -892,7 +759,8 @@ void ioif_watcher(const unsigned int gpio_in_available,
 
 	spin_unlock_irqrestore(&gpio_lock, flags);
 
-	printk(KERN_INFO "GPIO port G: in_bits: 0x%08lX out_bits: 0x%08lX val: %08lX\n",
+	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);
@@ -900,16 +768,12 @@ void ioif_watcher(const unsigned int gpio_in_available,
 
 /* main driver initialization routine, called from mem.c */
 
-static __init int
-gpio_init(void)
+static int __init gpio_init(void)
 {
 	int res;
 #if defined (CONFIG_ETRAX_CSP0_LEDS)
 	int i;
 #endif
-        printk("gpio init\n");
-
-	/* do the formalities */
 
 	res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops);
 	if (res < 0) {
@@ -919,43 +783,45 @@ gpio_init(void)
 
 	/* 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);
+	CRIS_LED_NETWORK_SET(0);
+	CRIS_LED_ACTIVE_SET(0);
+	CRIS_LED_DISK_READ(0);
+	CRIS_LED_DISK_WRITE(0);
 
 #if defined (CONFIG_ETRAX_CSP0_LEDS)
-	for (i = 0; i < 32; i++) {
-		LED_BIT_SET(i);
-	}
+	for (i = 0; i < 32; i++)
+		CRIS_LED_BIT_SET(i);
 #endif
 
 #endif
 	/* The I/O interface allocation watcher will be called when
 	 * registering it. */
 	if (cris_io_interface_register_watcher(ioif_watcher)){
-		printk(KERN_WARNING "gpio_init: Failed to install IO if allocator watcher\n");
+		printk(KERN_WARNING "gpio_init: Failed to install IO "
+			"if allocator watcher\n");
 	}
 
-	printk(KERN_INFO "ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002, 2003, 2004 Axis Communications AB\n");
+	printk(KERN_INFO "ETRAX 100LX GPIO driver v2.5, (c) 2001-2008 "
+		"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,
-			IRQF_SHARED | IRQF_DISABLED,"gpio poll", NULL)) {
+	 */
+	res = request_irq(TIMER0_IRQ_NBR, gpio_poll_timer_interrupt,
+		IRQF_SHARED | IRQF_DISABLED, "gpio poll", gpio_name);
+	if (res) {
 		printk(KERN_CRIT "err: timer0 irq for gpio\n");
+		return res;
 	}
-	if (request_irq(PA_IRQ_NBR, gpio_pa_interrupt,
-			IRQF_SHARED | IRQF_DISABLED,"gpio PA", NULL)) {
+	res = request_irq(PA_IRQ_NBR, gpio_interrupt,
+		IRQF_SHARED | IRQF_DISABLED, "gpio PA", gpio_name);
+	if (res)
 		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
index aca81ddaf60f..d6d22067d0c8 100644
--- a/arch/cris/arch-v10/drivers/i2c.c
+++ b/arch/cris/arch-v10/drivers/i2c.c
@@ -6,85 +6,9 @@
 *!              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.13  2005/03/07 13:13:07  starvik
-*! Added spinlocks to protect states etc
-*!
-*! Revision 1.12  2005/01/05 06:11:22  starvik
-*! No need to do local_irq_disable after local_irq_save.
-*!
-*! Revision 1.11  2004/12/13 12:21:52  starvik
-*! Added I/O and DMA allocators from Linux 2.4
-*!
-*! 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 toggling 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
+*! (C) Copyright 1999-2007 Axis Communications AB, LUND, SWEDEN
 *!
 *!***************************************************************************/
-/* $Id: i2c.c,v 1.13 2005/03/07 13:13:07 starvik Exp $ */
 
 /****************** INCLUDE FILES SECTION ***********************************/
 
@@ -622,7 +546,7 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg)
 		 * last received byte needs to be nacked
 		 * instead of acked
 		 */
-		i2c_sendack();
+		i2c_sendnack();
 		/*
 		 * end sequence
 		 */
@@ -708,6 +632,7 @@ i2c_init(void)
 	if (!first) {
 		return res;
 	}
+	first = 0;
 
 	/* Setup and enable the Port B I2C interface */
 
diff --git a/arch/cris/arch-v10/drivers/pcf8563.c b/arch/cris/arch-v10/drivers/pcf8563.c
index c263b8232dbc..52103d16dc6c 100644
--- a/arch/cris/arch-v10/drivers/pcf8563.c
+++ b/arch/cris/arch-v10/drivers/pcf8563.c
@@ -8,14 +8,13 @@
  * 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.
+ * automatically after each written or read byte.
  *
- * Copyright (c) 2002, Axis Communications AB
+ * Copyright (c) 2002-2007, Axis Communications AB
  * All rights reserved.
  *
  * Author: Tobias Anderberg <tobiasa@axis.com>.
  *
- * $Id: pcf8563.c,v 1.11 2005/03/07 13:13:07 starvik Exp $
  */
 
 #include <linux/module.h>
@@ -27,19 +26,19 @@
 #include <linux/ioctl.h>
 #include <linux/delay.h>
 #include <linux/bcd.h>
-#include <linux/capability.h>
+#include <linux/mutex.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_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.11 $"
+#define DRIVER_VERSION "$Revision: 1.24 $"
 
 /* I2C bus slave registers. */
 #define RTC_I2C_READ		0xa3
@@ -49,71 +48,88 @@
 #define rtc_read(x) i2c_readreg(RTC_I2C_READ, x)
 #define rtc_write(x,y) i2c_writereg(RTC_I2C_WRITE, x, y)
 
-static DEFINE_SPINLOCK(rtc_lock); /* Protect state etc */
-	
+static DEFINE_MUTEX(rtc_lock); /* Protect state etc */
+
 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);
 
+/* Cache VL bit value read at driver init since writing the RTC_SECOND
+ * register clears the VL status.
+ */
+static int voltage_low;
+
 static const struct file_operations pcf8563_fops = {
 	.owner = THIS_MODULE,
 	.ioctl = pcf8563_ioctl,
 };
 
 unsigned char
-pcf8563_readreg(int reg) 
+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;
+	unsigned char res = rtc_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_WEEKDAY:
+		res &= 0x07;
+		break;
+	case RTC_MONTH:
+		res &= 0x1F;
+		break;
+	case RTC_CONTROL1:
+		res &= 0xA8;
+		break;
+	case RTC_CONTROL2:
+		res &= 0x1F;
+		break;
+	case RTC_CLOCKOUT_FREQ:
+	case RTC_TIMER_CONTROL:
+		res &= 0x83;
+		break;
 	}
 	return res;
 }
 
 void
-pcf8563_writereg(int reg, unsigned char val) 
+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_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_wday = rtc_read(RTC_WEEKDAY);
+	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);
+	if (tm->tm_sec & 0x80) {
+		printk(KERN_ERR "%s: RTC Voltage Low - reliable date/time "
+		       "information is no longer guaranteed!\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;
+	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_wday &= 0x07; /* Not coded in BCD. */
+	tm->tm_mon  &= 0x1F;
 
 	BCD_TO_BIN(tm->tm_sec);
 	BCD_TO_BIN(tm->tm_min);
@@ -126,17 +142,24 @@ get_rtc_time(struct rtc_time *tm)
 int __init
 pcf8563_init(void)
 {
-	int ret;
-
-	if ((ret = i2c_init())) {
-		printk(KERN_CRIT "pcf8563_init: failed to init i2c\n");
-		return ret;
+	static int res;
+	static int first = 1;
+
+	if (!first)
+		return res;
+	first = 0;
+
+	/* Initiate the i2c protocol. */
+	res = i2c_init();
+	if (res < 0) {
+		printk(KERN_CRIT "pcf8563_init: Failed to init i2c.\n");
+		return res;
 	}
 
 	/*
 	 * 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.
+	 * clearing control1, control2 and clk freq and resetting
+	 * all alarms.
 	 */
 	if (rtc_write(RTC_CONTROL1, 0x00) < 0)
 		goto err;
@@ -147,34 +170,36 @@ pcf8563_init(void)
 	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)
+	if (rtc_write(RTC_TIMER_CONTROL, 0x03) < 0)
 		goto err;
-		
+
 	/* Reset the alarms. */
-	if (rtc_write(RTC_MINUTE_ALARM, 0x00) < 0)
+	if (rtc_write(RTC_MINUTE_ALARM, 0x80) < 0)
 		goto err;
-	
-	if (rtc_write(RTC_HOUR_ALARM, 0x00) < 0)
+
+	if (rtc_write(RTC_HOUR_ALARM, 0x80) < 0)
 		goto err;
-	
-	if (rtc_write(RTC_DAY_ALARM, 0x00) < 0)
+
+	if (rtc_write(RTC_DAY_ALARM, 0x80) < 0)
 		goto err;
-	
-	if (rtc_write(RTC_WEEKDAY_ALARM, 0x00) < 0)
+
+	if (rtc_write(RTC_WEEKDAY_ALARM, 0x80) < 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;
+
+	/* Check for low voltage, and warn about it. */
+	if (rtc_read(RTC_SECONDS) & 0x80) {
+		voltage_low = 1;
+		printk(KERN_WARNING "%s: RTC Voltage Low - reliable "
+		       "date/time information is no longer guaranteed!\n",
+		       PCF8563_NAME);
+	}
+
+	return res;
 
 err:
 	printk(KERN_INFO "%s: Error initializing chip.\n", PCF8563_NAME);
-	return -1;
+	res = -1;
+	return res;
 }
 
 void __exit
@@ -187,8 +212,8 @@ pcf8563_exit(void)
  * 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)
+int pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+	unsigned long arg)
 {
 	/* Some sanity checks. */
 	if (_IOC_TYPE(cmd) != RTC_MAGIC)
@@ -198,124 +223,146 @@ pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned
 		return -ENOTTY;
 
 	switch (cmd) {
-		case RTC_RD_TIME:
-			{
-				struct rtc_time tm;
-
-				spin_lock(&rtc_lock);
-				get_rtc_time(&tm);
-
-				if (copy_to_user((struct rtc_time *) arg, &tm, sizeof(struct rtc_time))) {
-					spin_unlock(&rtc_lock);
-					return -EFAULT;
-				}
-
-				spin_unlock(&rtc_lock);
-				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;
-
-				spin_lock(&rtc_lock);
-				
-				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);
-
-				spin_unlock(&rtc_lock);
-
-				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_RD_TIME:
+	{
+		struct rtc_time tm;
 
-		case RTC_VLOW_SET:
-		{
-			/* Clear the VL bit in the seconds register */
-			int ret = rtc_read(RTC_SECONDS);
+		mutex_lock(&rtc_lock);
+		memset(&tm, 0, sizeof tm);
+		get_rtc_time(&tm);
 
-			rtc_write(RTC_SECONDS, (ret & 0x7F));
+		if (copy_to_user((struct rtc_time *) arg, &tm,
+				 sizeof tm)) {
+			spin_unlock(&rtc_lock);
+			return -EFAULT;
+		}
+
+		mutex_unlock(&rtc_lock);
 
-			return 0;
+		return 0;
+	}
+	case RTC_SET_TIME:
+	{
+		int leap;
+		int year;
+		int century;
+		struct rtc_time tm;
+
+		memset(&tm, 0, sizeof tm);
+		if (!capable(CAP_SYS_TIME))
+			return -EPERM;
+
+		if (copy_from_user(&tm, (struct rtc_time *) arg, sizeof tm))
+			return -EFAULT;
+
+		/* Convert from struct tm to struct rtc_time. */
+		tm.tm_year += 1900;
+		tm.tm_mon += 1;
+
+		/*
+		 * Check if tm.tm_year is a leap year. A year is a leap
+		 * year if it is divisible by 4 but not 100, except
+		 * that years divisible by 400 _are_ leap years.
+		 */
+		year = tm.tm_year;
+		leap = (tm.tm_mon == 2) &&
+			((year % 4 == 0 && year % 100 != 0) || year % 400 == 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_wday >= 7) ||
+		    (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_mon);
+		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;
+
+		mutex_lock(&rtc_lock);
+
+		rtc_write(RTC_YEAR, tm.tm_year);
+		rtc_write(RTC_MONTH, tm.tm_mon);
+		rtc_write(RTC_WEEKDAY, tm.tm_wday); /* Not coded in BCD. */
+		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);
+
+		mutex_unlock(&rtc_lock);
+
+		return 0;
+	}
+	case RTC_VL_READ:
+		if (voltage_low) {
+			printk(KERN_ERR "%s: RTC Voltage Low - "
+			       "reliable date/time information is no "
+			       "longer guaranteed!\n", PCF8563_NAME);
 		}
 
-		default:
-				return -ENOTTY;
+		if (copy_to_user((int *) arg, &voltage_low, sizeof(int)))
+			return -EFAULT;
+		return 0;
+
+	case RTC_VL_CLR:
+	{
+		/* Clear the VL bit in the seconds register in case
+		 * the time has not been set already (which would
+		 * have cleared it). This does not really matter
+		 * because of the cached voltage_low value but do it
+		 * anyway for consistency. */
+
+		int ret = rtc_read(RTC_SECONDS);
+
+		rtc_write(RTC_SECONDS, (ret & 0x7F));
+
+		/* Clear the cached value. */
+		voltage_low = 0;
+
+		return 0;
+	}
+	default:
+		return -ENOTTY;
 	}
 
 	return 0;
 }
 
-static int __init
-pcf8563_register(void)
+static int __init pcf8563_register(void)
 {
-	pcf8563_init();
+	if (pcf8563_init() < 0) {
+		printk(KERN_INFO "%s: Unable to initialize Real-Time Clock "
+		       "Driver, %s\n", PCF8563_NAME, DRIVER_VERSION);
+		return -1;
+	}
+
 	if (register_chrdev(PCF8563_MAJOR, DEVICE_NAME, &pcf8563_fops) < 0) {
 		printk(KERN_INFO "%s: Unable to get major number %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;
+	printk(KERN_INFO "%s Real-Time Clock Driver, %s\n", PCF8563_NAME,
+	       DRIVER_VERSION);
+
+	/* Check for low voltage, and warn about it. */
+	if (voltage_low) {
+		printk(KERN_WARNING "%s: RTC Voltage Low - reliable date/time "
+		       "information is no longer guaranteed!\n", PCF8563_NAME);
+	}
+
+	return 0;
 }
 
 module_init(pcf8563_register);
diff --git a/arch/cris/arch-v10/drivers/sync_serial.c b/arch/cris/arch-v10/drivers/sync_serial.c
new file mode 100644
index 000000000000..069546e342c5
--- /dev/null
+++ b/arch/cris/arch-v10/drivers/sync_serial.c
@@ -0,0 +1,1441 @@
+/*
+ * Simple synchronous serial port driver for ETRAX 100LX.
+ *
+ * Synchronous serial ports are used for continuous streamed data like audio.
+ * The default setting for this driver is compatible with the STA 013 MP3
+ * decoder. The driver can easily be tuned to fit other audio encoder/decoders
+ * and SPI
+ *
+ * Copyright (c) 2001-2008 Axis Communications AB
+ *
+ * Author: Mikael Starvik, Johan Adolfsson
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/arch/svinto.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/sync_serial.h>
+#include <asm/arch/io_interface_mux.h>
+
+/* The receiver is a bit tricky beacuse of the continuous stream of data.*/
+/*                                                                       */
+/* Three DMA descriptors are linked together. Each DMA descriptor is     */
+/* responsible for port->bufchunk of a common buffer.                    */
+/*                                                                       */
+/* +---------------------------------------------+                       */
+/* |   +----------+   +----------+   +----------+ |                      */
+/* +-> | Descr[0] |-->| Descr[1] |-->| Descr[2] |-+                      */
+/*     +----------+   +----------+   +----------+                        */
+/*         |            |              |                                 */
+/*         v            v              v                                 */
+/*   +-------------------------------------+                             */
+/*   |        BUFFER                       |                             */
+/*   +-------------------------------------+                             */
+/*      |<- data_avail ->|                                               */
+/*    readp          writep                                              */
+/*                                                                       */
+/* If the application keeps up the pace readp will be right after writep.*/
+/* If the application can't keep the pace we have to throw away data.    */
+/* The idea is that readp should be ready with the data pointed out by	 */
+/* Descr[i] when the DMA has filled in Descr[i+1].                       */
+/* Otherwise we will discard	                                         */
+/* the rest of the data pointed out by Descr1 and set readp to the start */
+/* of Descr2                                                             */
+
+#define SYNC_SERIAL_MAJOR 125
+
+/* IN_BUFFER_SIZE should be a multiple of 6 to make sure that 24 bit */
+/* words can be handled */
+#define IN_BUFFER_SIZE 12288
+#define IN_DESCR_SIZE 256
+#define NUM_IN_DESCR (IN_BUFFER_SIZE/IN_DESCR_SIZE)
+#define OUT_BUFFER_SIZE 4096
+
+#define DEFAULT_FRAME_RATE 0
+#define DEFAULT_WORD_RATE 7
+
+/* NOTE: Enabling some debug will likely cause overrun or underrun,
+ * especially if manual mode is use.
+ */
+#define DEBUG(x)
+#define DEBUGREAD(x)
+#define DEBUGWRITE(x)
+#define DEBUGPOLL(x)
+#define DEBUGRXINT(x)
+#define DEBUGTXINT(x)
+
+/* Define some macros to access ETRAX 100 registers */
+#define SETF(var, reg, field, val) \
+	do { \
+		var = (var & ~IO_MASK_(reg##_, field##_)) | \
+			IO_FIELD_(reg##_, field##_, val); \
+	} while (0)
+
+#define SETS(var, reg, field, val) \
+	do { \
+		var = (var & ~IO_MASK_(reg##_, field##_)) | \
+			IO_STATE_(reg##_, field##_, _##val); \
+	} while (0)
+
+struct sync_port {
+	/* Etrax registers and bits*/
+	const volatile unsigned *const status;
+	volatile unsigned *const ctrl_data;
+	volatile unsigned *const output_dma_first;
+	volatile unsigned char *const output_dma_cmd;
+	volatile unsigned char *const output_dma_clr_irq;
+	volatile unsigned *const input_dma_first;
+	volatile unsigned char *const input_dma_cmd;
+	volatile unsigned *const input_dma_descr;
+	/* 8*4 */
+	volatile unsigned char *const input_dma_clr_irq;
+	volatile unsigned *const data_out;
+	const volatile unsigned *const data_in;
+	char data_avail_bit; /* In R_IRQ_MASK1_RD/SET/CLR */
+	char transmitter_ready_bit; /* In R_IRQ_MASK1_RD/SET/CLR */
+	char input_dma_descr_bit; /* In R_IRQ_MASK2_RD */
+
+	char output_dma_bit; /* In R_IRQ_MASK2_RD */
+	/* End of fields initialised in array */
+	char started; /* 1 if port has been started */
+	char port_nbr; /* Port 0 or 1 */
+	char busy; /* 1 if port is busy */
+
+	char enabled;  /* 1 if port is enabled */
+	char use_dma;  /* 1 if port uses dma */
+	char tr_running;
+
+	char init_irqs;
+
+	/* Register shadow */
+	unsigned int ctrl_data_shadow;
+	/* Remaining bytes for current transfer */
+	volatile unsigned int out_count;
+	/* Current position in out_buffer */
+	unsigned char *outp;
+	/* 16*4 */
+	/* Next byte to be read by application */
+	volatile unsigned char *volatile readp;
+	/* Next byte to be written by etrax */
+	volatile unsigned char *volatile writep;
+
+	unsigned int in_buffer_size;
+	unsigned int inbufchunk;
+	struct etrax_dma_descr out_descr __attribute__ ((aligned(32)));
+	struct etrax_dma_descr in_descr[NUM_IN_DESCR] __attribute__ ((aligned(32)));
+	unsigned char out_buffer[OUT_BUFFER_SIZE] __attribute__ ((aligned(32)));
+	unsigned char in_buffer[IN_BUFFER_SIZE]__attribute__ ((aligned(32)));
+	unsigned char flip[IN_BUFFER_SIZE] __attribute__ ((aligned(32)));
+	struct etrax_dma_descr *next_rx_desc;
+	struct etrax_dma_descr *prev_rx_desc;
+	int full;
+
+	wait_queue_head_t out_wait_q;
+	wait_queue_head_t in_wait_q;
+};
+
+
+static int etrax_sync_serial_init(void);
+static void initialize_port(int portnbr);
+static inline int sync_data_avail(struct sync_port *port);
+
+static int sync_serial_open(struct inode *inode, struct file *file);
+static int sync_serial_release(struct inode *inode, struct file *file);
+static unsigned int sync_serial_poll(struct file *filp, poll_table *wait);
+
+static int sync_serial_ioctl(struct inode *inode, struct file *file,
+	unsigned int cmd, unsigned long arg);
+static ssize_t sync_serial_write(struct file *file, const char *buf,
+	size_t count, loff_t *ppos);
+static ssize_t sync_serial_read(struct file *file, char *buf,
+	size_t count, loff_t *ppos);
+
+#if ((defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) && \
+     defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)) || \
+    (defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) && \
+     defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA)))
+#define SYNC_SER_DMA
+#endif
+
+static void send_word(struct sync_port *port);
+static void start_dma(struct sync_port *port, const char *data, int count);
+static void start_dma_in(struct sync_port *port);
+#ifdef SYNC_SER_DMA
+static irqreturn_t tr_interrupt(int irq, void *dev_id);
+static irqreturn_t rx_interrupt(int irq, void *dev_id);
+#endif
+#if ((defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) && \
+     !defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)) || \
+    (defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) && \
+     !defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA)))
+#define SYNC_SER_MANUAL
+#endif
+#ifdef SYNC_SER_MANUAL
+static irqreturn_t manual_interrupt(int irq, void *dev_id);
+#endif
+
+/* The ports */
+static struct sync_port ports[] = {
+	{
+		.status                = R_SYNC_SERIAL1_STATUS,
+		.ctrl_data             = R_SYNC_SERIAL1_CTRL,
+		.output_dma_first      = R_DMA_CH8_FIRST,
+		.output_dma_cmd        = R_DMA_CH8_CMD,
+		.output_dma_clr_irq    = R_DMA_CH8_CLR_INTR,
+		.input_dma_first       = R_DMA_CH9_FIRST,
+		.input_dma_cmd         = R_DMA_CH9_CMD,
+		.input_dma_descr       = R_DMA_CH9_DESCR,
+		.input_dma_clr_irq     = R_DMA_CH9_CLR_INTR,
+		.data_out              = R_SYNC_SERIAL1_TR_DATA,
+		.data_in               = R_SYNC_SERIAL1_REC_DATA,
+		.data_avail_bit        = IO_BITNR(R_IRQ_MASK1_RD, ser1_data),
+		.transmitter_ready_bit = IO_BITNR(R_IRQ_MASK1_RD, ser1_ready),
+		.input_dma_descr_bit   = IO_BITNR(R_IRQ_MASK2_RD, dma9_descr),
+		.output_dma_bit        = IO_BITNR(R_IRQ_MASK2_RD, dma8_eop),
+		.init_irqs             = 1,
+#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)
+		.use_dma               = 1,
+#else
+		.use_dma               = 0,
+#endif
+	},
+	{
+		.status                = R_SYNC_SERIAL3_STATUS,
+		.ctrl_data             = R_SYNC_SERIAL3_CTRL,
+		.output_dma_first      = R_DMA_CH4_FIRST,
+		.output_dma_cmd        = R_DMA_CH4_CMD,
+		.output_dma_clr_irq    = R_DMA_CH4_CLR_INTR,
+		.input_dma_first       = R_DMA_CH5_FIRST,
+		.input_dma_cmd         = R_DMA_CH5_CMD,
+		.input_dma_descr       = R_DMA_CH5_DESCR,
+		.input_dma_clr_irq     = R_DMA_CH5_CLR_INTR,
+		.data_out              = R_SYNC_SERIAL3_TR_DATA,
+		.data_in               = R_SYNC_SERIAL3_REC_DATA,
+		.data_avail_bit        = IO_BITNR(R_IRQ_MASK1_RD, ser3_data),
+		.transmitter_ready_bit = IO_BITNR(R_IRQ_MASK1_RD, ser3_ready),
+		.input_dma_descr_bit   = IO_BITNR(R_IRQ_MASK2_RD, dma5_descr),
+		.output_dma_bit        = IO_BITNR(R_IRQ_MASK2_RD, dma4_eop),
+		.init_irqs             = 1,
+#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA)
+		.use_dma               = 1,
+#else
+		.use_dma               = 0,
+#endif
+	}
+};
+
+/* Register shadows */
+static unsigned sync_serial_prescale_shadow;
+
+#define NUMBER_OF_PORTS 2
+
+static struct file_operations sync_serial_fops = {
+	.owner   = THIS_MODULE,
+	.write   = sync_serial_write,
+	.read    = sync_serial_read,
+	.poll    = sync_serial_poll,
+	.ioctl   = sync_serial_ioctl,
+	.open    = sync_serial_open,
+	.release = sync_serial_release
+};
+
+static int __init etrax_sync_serial_init(void)
+{
+	ports[0].enabled = 0;
+	ports[1].enabled = 0;
+
+#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0)
+	if (cris_request_io_interface(if_sync_serial_1, "sync_ser1")) {
+		printk(KERN_CRIT "ETRAX100LX sync_serial: "
+			"Could not allocate IO group for port %d\n", 0);
+		return -EBUSY;
+	}
+#endif
+#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1)
+	if (cris_request_io_interface(if_sync_serial_3, "sync_ser3")) {
+#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0)
+		cris_free_io_interface(if_sync_serial_1);
+#endif
+		printk(KERN_CRIT "ETRAX100LX sync_serial: "
+			"Could not allocate IO group for port %d\n", 1);
+		return -EBUSY;
+	}
+#endif
+
+	if (register_chrdev(SYNC_SERIAL_MAJOR, "sync serial",
+			&sync_serial_fops) < 0) {
+#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1)
+		cris_free_io_interface(if_sync_serial_3);
+#endif
+#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0)
+		cris_free_io_interface(if_sync_serial_1);
+#endif
+		printk("unable to get major for synchronous serial port\n");
+		return -EBUSY;
+	}
+
+	/* Deselect synchronous serial ports while configuring. */
+	SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, async);
+	SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, async);
+	*R_GEN_CONFIG_II = gen_config_ii_shadow;
+
+	/* Initialize Ports */
+#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0)
+	ports[0].enabled = 1;
+	SETS(port_pb_i2c_shadow, R_PORT_PB_I2C, syncser1, ss1extra);
+	SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, sync);
+#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)
+	ports[0].use_dma = 1;
+#else
+	ports[0].use_dma = 0;
+#endif
+	initialize_port(0);
+#endif
+
+#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1)
+	ports[1].enabled = 1;
+	SETS(port_pb_i2c_shadow, R_PORT_PB_I2C, syncser3, ss3extra);
+	SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, sync);
+#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA)
+	ports[1].use_dma = 1;
+#else
+	ports[1].use_dma = 0;
+#endif
+	initialize_port(1);
+#endif
+
+	*R_PORT_PB_I2C = port_pb_i2c_shadow; /* Use PB4/PB7 */
+
+	/* Set up timing */
+	*R_SYNC_SERIAL_PRESCALE = sync_serial_prescale_shadow = (
+		IO_STATE(R_SYNC_SERIAL_PRESCALE, clk_sel_u1, codec) |
+		IO_STATE(R_SYNC_SERIAL_PRESCALE, word_stb_sel_u1, external) |
+		IO_STATE(R_SYNC_SERIAL_PRESCALE, clk_sel_u3, codec) |
+		IO_STATE(R_SYNC_SERIAL_PRESCALE, word_stb_sel_u3, external) |
+		IO_STATE(R_SYNC_SERIAL_PRESCALE, prescaler, div4) |
+		IO_FIELD(R_SYNC_SERIAL_PRESCALE, frame_rate,
+			DEFAULT_FRAME_RATE) |
+		IO_FIELD(R_SYNC_SERIAL_PRESCALE, word_rate, DEFAULT_WORD_RATE) |
+		IO_STATE(R_SYNC_SERIAL_PRESCALE, warp_mode, normal));
+
+	/* Select synchronous ports */
+	*R_GEN_CONFIG_II = gen_config_ii_shadow;
+
+	printk(KERN_INFO "ETRAX 100LX synchronous serial port driver\n");
+	return 0;
+}
+
+static void __init initialize_port(int portnbr)
+{
+	struct sync_port *port = &ports[portnbr];
+
+	DEBUG(printk(KERN_DEBUG "Init sync serial port %d\n", portnbr));
+
+	port->started = 0;
+	port->port_nbr = portnbr;
+	port->busy = 0;
+	port->tr_running = 0;
+
+	port->out_count = 0;
+	port->outp = port->out_buffer;
+
+	port->readp = port->flip;
+	port->writep = port->flip;
+	port->in_buffer_size = IN_BUFFER_SIZE;
+	port->inbufchunk = IN_DESCR_SIZE;
+	port->next_rx_desc = &port->in_descr[0];
+	port->prev_rx_desc = &port->in_descr[NUM_IN_DESCR-1];
+	port->prev_rx_desc->ctrl = d_eol;
+
+	init_waitqueue_head(&port->out_wait_q);
+	init_waitqueue_head(&port->in_wait_q);
+
+	port->ctrl_data_shadow =
+		IO_STATE(R_SYNC_SERIAL1_CTRL, tr_baud, c115k2Hz)   |
+		IO_STATE(R_SYNC_SERIAL1_CTRL, mode, master_output) |
+		IO_STATE(R_SYNC_SERIAL1_CTRL, error, ignore)       |
+		IO_STATE(R_SYNC_SERIAL1_CTRL, rec_enable, disable) |
+		IO_STATE(R_SYNC_SERIAL1_CTRL, f_synctype, normal)  |
+		IO_STATE(R_SYNC_SERIAL1_CTRL, f_syncsize, word)    |
+		IO_STATE(R_SYNC_SERIAL1_CTRL, f_sync, on)	     |
+		IO_STATE(R_SYNC_SERIAL1_CTRL, clk_mode, normal)    |
+		IO_STATE(R_SYNC_SERIAL1_CTRL, clk_halt, stopped)   |
+		IO_STATE(R_SYNC_SERIAL1_CTRL, bitorder, msb)	     |
+		IO_STATE(R_SYNC_SERIAL1_CTRL, tr_enable, disable)  |
+		IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size8bit)  |
+		IO_STATE(R_SYNC_SERIAL1_CTRL, buf_empty, lmt_8)    |
+		IO_STATE(R_SYNC_SERIAL1_CTRL, buf_full, lmt_8)     |
+		IO_STATE(R_SYNC_SERIAL1_CTRL, flow_ctrl, enabled)  |
+		IO_STATE(R_SYNC_SERIAL1_CTRL, clk_polarity, neg)   |
+		IO_STATE(R_SYNC_SERIAL1_CTRL, frame_polarity, normal)|
+		IO_STATE(R_SYNC_SERIAL1_CTRL, status_polarity, inverted)|
+		IO_STATE(R_SYNC_SERIAL1_CTRL, clk_driver, normal)   |
+		IO_STATE(R_SYNC_SERIAL1_CTRL, frame_driver, normal) |
+		IO_STATE(R_SYNC_SERIAL1_CTRL, status_driver, normal)|
+		IO_STATE(R_SYNC_SERIAL1_CTRL, def_out0, high);
+
+	if (port->use_dma)
+		port->ctrl_data_shadow |= IO_STATE(R_SYNC_SERIAL1_CTRL,
+			dma_enable, on);
+	else
+		port->ctrl_data_shadow |= IO_STATE(R_SYNC_SERIAL1_CTRL,
+			dma_enable, off);
+
+	*port->ctrl_data = port->ctrl_data_shadow;
+}
+
+static inline int sync_data_avail(struct sync_port *port)
+{
+	int avail;
+	unsigned char *start;
+	unsigned char *end;
+
+	start = (unsigned char *)port->readp; /* cast away volatile */
+	end = (unsigned char *)port->writep;  /* cast away volatile */
+	/* 0123456789  0123456789
+	 *  -----      -    -----
+	 *  ^rp  ^wp    ^wp ^rp
+	 */
+	if (end >= start)
+		avail = end - start;
+	else
+		avail = port->in_buffer_size - (start - end);
+	return avail;
+}
+
+static inline int sync_data_avail_to_end(struct sync_port *port)
+{
+	int avail;
+	unsigned char *start;
+	unsigned char *end;
+
+	start = (unsigned char *)port->readp; /* cast away volatile */
+	end = (unsigned char *)port->writep;  /* cast away volatile */
+	/* 0123456789  0123456789
+	 *  -----           -----
+	 *  ^rp  ^wp    ^wp ^rp
+	 */
+
+	if (end >= start)
+		avail = end - start;
+	else
+		avail = port->flip + port->in_buffer_size - start;
+	return avail;
+}
+
+
+static int sync_serial_open(struct inode *inode, struct file *file)
+{
+	int dev = MINOR(inode->i_rdev);
+	struct sync_port *port;
+	int mode;
+
+	DEBUG(printk(KERN_DEBUG "Open sync serial port %d\n", dev));
+
+	if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) {
+		DEBUG(printk(KERN_DEBUG "Invalid minor %d\n", dev));
+		return -ENODEV;
+	}
+	port = &ports[dev];
+	/* Allow open this device twice (assuming one reader and one writer) */
+	if (port->busy == 2) {
+		DEBUG(printk(KERN_DEBUG "Device is busy.. \n"));
+		return -EBUSY;
+	}
+	if (port->init_irqs) {
+		if (port->use_dma) {
+			if (port == &ports[0]) {
+#ifdef SYNC_SER_DMA
+				if (request_irq(24, tr_interrupt, 0,
+						"synchronous serial 1 dma tr",
+						&ports[0])) {
+					printk(KERN_CRIT "Can't alloc "
+						"sync serial port 1 IRQ");
+					return -EBUSY;
+				} else if (request_irq(25, rx_interrupt, 0,
+						"synchronous serial 1 dma rx",
+						&ports[0])) {
+					free_irq(24, &port[0]);
+					printk(KERN_CRIT "Can't alloc "
+						"sync serial port 1 IRQ");
+					return -EBUSY;
+				} else if (cris_request_dma(8,
+						"synchronous serial 1 dma tr",
+						DMA_VERBOSE_ON_ERROR,
+						dma_ser1)) {
+					free_irq(24, &port[0]);
+					free_irq(25, &port[0]);
+					printk(KERN_CRIT "Can't alloc "
+						"sync serial port 1 "
+						"TX DMA channel");
+					return -EBUSY;
+				} else if (cris_request_dma(9,
+						"synchronous serial 1 dma rec",
+						DMA_VERBOSE_ON_ERROR,
+						dma_ser1)) {
+					cris_free_dma(8, NULL);
+					free_irq(24, &port[0]);
+					free_irq(25, &port[0]);
+					printk(KERN_CRIT "Can't alloc "
+						"sync serial port 1 "
+						"RX DMA channel");
+					return -EBUSY;
+				}
+#endif
+				RESET_DMA(8); WAIT_DMA(8);
+				RESET_DMA(9); WAIT_DMA(9);
+				*R_DMA_CH8_CLR_INTR =
+					IO_STATE(R_DMA_CH8_CLR_INTR, clr_eop,
+						do) |
+					IO_STATE(R_DMA_CH8_CLR_INTR, clr_descr,
+						do);
+				*R_DMA_CH9_CLR_INTR =
+					IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop,
+						do) |
+					IO_STATE(R_DMA_CH9_CLR_INTR, clr_descr,
+						do);
+				*R_IRQ_MASK2_SET =
+					IO_STATE(R_IRQ_MASK2_SET, dma8_eop,
+						set) |
+					IO_STATE(R_IRQ_MASK2_SET, dma9_descr,
+						set);
+			} else if (port == &ports[1]) {
+#ifdef SYNC_SER_DMA
+				if (request_irq(20, tr_interrupt, 0,
+						"synchronous serial 3 dma tr",
+						&ports[1])) {
+					printk(KERN_CRIT "Can't alloc "
+						"sync serial port 3 IRQ");
+					return -EBUSY;
+				} else if (request_irq(21, rx_interrupt, 0,
+						"synchronous serial 3 dma rx",
+						&ports[1])) {
+					free_irq(20, &ports[1]);
+					printk(KERN_CRIT "Can't alloc "
+						"sync serial port 3 IRQ");
+					return -EBUSY;
+				} else if (cris_request_dma(4,
+						"synchronous serial 3 dma tr",
+						DMA_VERBOSE_ON_ERROR,
+						dma_ser3)) {
+					free_irq(21, &ports[1]);
+					free_irq(20, &ports[1]);
+					printk(KERN_CRIT "Can't alloc "
+						"sync serial port 3 "
+						"TX DMA channel");
+					return -EBUSY;
+				} else if (cris_request_dma(5,
+						"synchronous serial 3 dma rec",
+						DMA_VERBOSE_ON_ERROR,
+						dma_ser3)) {
+					cris_free_dma(4, NULL);
+					free_irq(21, &ports[1]);
+					free_irq(20, &ports[1]);
+					printk(KERN_CRIT "Can't alloc "
+						"sync serial port 3 "
+						"RX DMA channel");
+					return -EBUSY;
+				}
+#endif
+				RESET_DMA(4); WAIT_DMA(4);
+				RESET_DMA(5); WAIT_DMA(5);
+				*R_DMA_CH4_CLR_INTR =
+					IO_STATE(R_DMA_CH4_CLR_INTR, clr_eop,
+						do) |
+					IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr,
+						do);
+				*R_DMA_CH5_CLR_INTR =
+					IO_STATE(R_DMA_CH5_CLR_INTR, clr_eop,
+						do) |
+					IO_STATE(R_DMA_CH5_CLR_INTR, clr_descr,
+						do);
+				*R_IRQ_MASK2_SET =
+					IO_STATE(R_IRQ_MASK2_SET, dma4_eop,
+						set) |
+					IO_STATE(R_IRQ_MASK2_SET, dma5_descr,
+						set);
+			}
+			start_dma_in(port);
+			port->init_irqs = 0;
+		} else { /* !port->use_dma */
+#ifdef SYNC_SER_MANUAL
+			if (port == &ports[0]) {
+				if (request_irq(8,
+						manual_interrupt,
+						IRQF_SHARED | IRQF_DISABLED,
+						"synchronous serial manual irq",
+						&ports[0])) {
+					printk(KERN_CRIT "Can't alloc "
+						"sync serial manual irq");
+					return -EBUSY;
+				}
+			} else if (port == &ports[1]) {
+				if (request_irq(8,
+						manual_interrupt,
+						IRQF_SHARED | IRQF_DISABLED,
+						"synchronous serial manual irq",
+						&ports[1])) {
+					printk(KERN_CRIT "Can't alloc "
+						"sync serial manual irq");
+					return -EBUSY;
+				}
+			}
+			port->init_irqs = 0;
+#else
+			panic("sync_serial: Manual mode not supported.\n");
+#endif /* SYNC_SER_MANUAL */
+		}
+	} /* port->init_irqs */
+
+	port->busy++;
+	/* Start port if we use it as input */
+	mode = IO_EXTRACT(R_SYNC_SERIAL1_CTRL, mode, port->ctrl_data_shadow);
+	if (mode == IO_STATE_VALUE(R_SYNC_SERIAL1_CTRL, mode, master_input) ||
+	    mode == IO_STATE_VALUE(R_SYNC_SERIAL1_CTRL, mode, slave_input) ||
+	    mode == IO_STATE_VALUE(R_SYNC_SERIAL1_CTRL, mode, master_bidir) ||
+	    mode == IO_STATE_VALUE(R_SYNC_SERIAL1_CTRL, mode, slave_bidir)) {
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt,
+			running);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_enable,
+			enable);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, rec_enable,
+			enable);
+		port->started = 1;
+		*port->ctrl_data = port->ctrl_data_shadow;
+		if (!port->use_dma)
+			*R_IRQ_MASK1_SET = 1 << port->data_avail_bit;
+		DEBUG(printk(KERN_DEBUG "sser%d rec started\n", dev));
+	}
+	return 0;
+}
+
+static int sync_serial_release(struct inode *inode, struct file *file)
+{
+	int dev = MINOR(inode->i_rdev);
+	struct sync_port *port;
+
+	if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) {
+		DEBUG(printk(KERN_DEBUG "Invalid minor %d\n", dev));
+		return -ENODEV;
+	}
+	port = &ports[dev];
+	if (port->busy)
+		port->busy--;
+	if (!port->busy)
+		*R_IRQ_MASK1_CLR = ((1 << port->data_avail_bit) |
+				    (1 << port->transmitter_ready_bit));
+
+	return 0;
+}
+
+
+
+static unsigned int sync_serial_poll(struct file *file, poll_table *wait)
+{
+	int dev = MINOR(file->f_dentry->d_inode->i_rdev);
+	unsigned int mask = 0;
+	struct sync_port *port;
+	DEBUGPOLL(static unsigned int prev_mask = 0);
+
+	port = &ports[dev];
+	poll_wait(file, &port->out_wait_q, wait);
+	poll_wait(file, &port->in_wait_q, wait);
+	/* Some room to write */
+	if (port->out_count < OUT_BUFFER_SIZE)
+		mask |=  POLLOUT | POLLWRNORM;
+	/* At least an inbufchunk of data */
+	if (sync_data_avail(port) >= port->inbufchunk)
+		mask |= POLLIN | POLLRDNORM;
+
+	DEBUGPOLL(if (mask != prev_mask)
+		printk(KERN_DEBUG "sync_serial_poll: mask 0x%08X %s %s\n",
+			mask,
+			mask & POLLOUT ? "POLLOUT" : "",
+			mask & POLLIN ? "POLLIN" : "");
+		prev_mask = mask;
+	);
+	return mask;
+}
+
+static int sync_serial_ioctl(struct inode *inode, struct file *file,
+		  unsigned int cmd, unsigned long arg)
+{
+	int return_val = 0;
+	unsigned long flags;
+
+	int dev = MINOR(file->f_dentry->d_inode->i_rdev);
+	struct sync_port *port;
+
+	if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) {
+		DEBUG(printk(KERN_DEBUG "Invalid minor %d\n", dev));
+		return -1;
+	}
+	port = &ports[dev];
+
+	local_irq_save(flags);
+	/* Disable port while changing config */
+	if (dev) {
+		if (port->use_dma) {
+			RESET_DMA(4); WAIT_DMA(4);
+			port->tr_running = 0;
+			port->out_count = 0;
+			port->outp = port->out_buffer;
+			*R_DMA_CH4_CLR_INTR =
+				IO_STATE(R_DMA_CH4_CLR_INTR, clr_eop, do) |
+				IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do);
+		}
+		SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, async);
+	} else {
+		if (port->use_dma) {
+			RESET_DMA(8); WAIT_DMA(8);
+			port->tr_running = 0;
+			port->out_count = 0;
+			port->outp = port->out_buffer;
+			*R_DMA_CH8_CLR_INTR =
+				IO_STATE(R_DMA_CH8_CLR_INTR, clr_eop, do) |
+				IO_STATE(R_DMA_CH8_CLR_INTR, clr_descr, do);
+		}
+		SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, async);
+	}
+	*R_GEN_CONFIG_II = gen_config_ii_shadow;
+	local_irq_restore(flags);
+
+	switch (cmd) {
+	case SSP_SPEED:
+		if (GET_SPEED(arg) == CODEC) {
+			if (dev)
+				SETS(sync_serial_prescale_shadow,
+					R_SYNC_SERIAL_PRESCALE, clk_sel_u3,
+					codec);
+			else
+				SETS(sync_serial_prescale_shadow,
+					R_SYNC_SERIAL_PRESCALE, clk_sel_u1,
+					codec);
+
+			SETF(sync_serial_prescale_shadow,
+				R_SYNC_SERIAL_PRESCALE, prescaler,
+				GET_FREQ(arg));
+			SETF(sync_serial_prescale_shadow,
+				R_SYNC_SERIAL_PRESCALE, frame_rate,
+				GET_FRAME_RATE(arg));
+			SETF(sync_serial_prescale_shadow,
+				R_SYNC_SERIAL_PRESCALE, word_rate,
+				GET_WORD_RATE(arg));
+		} else {
+			SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				tr_baud, GET_SPEED(arg));
+			if (dev)
+				SETS(sync_serial_prescale_shadow,
+					R_SYNC_SERIAL_PRESCALE, clk_sel_u3,
+					baudrate);
+			else
+				SETS(sync_serial_prescale_shadow,
+					R_SYNC_SERIAL_PRESCALE, clk_sel_u1,
+					baudrate);
+		}
+		break;
+	case SSP_MODE:
+		if (arg > 5)
+			return -EINVAL;
+		if (arg == MASTER_OUTPUT || arg == SLAVE_OUTPUT)
+			*R_IRQ_MASK1_CLR = 1 << port->data_avail_bit;
+		else if (!port->use_dma)
+			*R_IRQ_MASK1_SET = 1 << port->data_avail_bit;
+		SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, mode, arg);
+		break;
+	case SSP_FRAME_SYNC:
+		if (arg & NORMAL_SYNC)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				f_synctype, normal);
+		else if (arg & EARLY_SYNC)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				f_synctype, early);
+
+		if (arg & BIT_SYNC)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				f_syncsize, bit);
+		else if (arg & WORD_SYNC)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				f_syncsize, word);
+		else if (arg & EXTENDED_SYNC)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				f_syncsize, extended);
+
+		if (arg & SYNC_ON)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				f_sync, on);
+		else if (arg & SYNC_OFF)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				f_sync, off);
+
+		if (arg & WORD_SIZE_8)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				wordsize, size8bit);
+		else if (arg & WORD_SIZE_12)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				wordsize, size12bit);
+		else if (arg & WORD_SIZE_16)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				wordsize, size16bit);
+		else if (arg & WORD_SIZE_24)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				wordsize, size24bit);
+		else if (arg & WORD_SIZE_32)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				wordsize, size32bit);
+
+		if (arg & BIT_ORDER_MSB)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				bitorder, msb);
+		else if (arg & BIT_ORDER_LSB)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				bitorder, lsb);
+
+		if (arg & FLOW_CONTROL_ENABLE)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				flow_ctrl, enabled);
+		else if (arg & FLOW_CONTROL_DISABLE)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				flow_ctrl, disabled);
+
+		if (arg & CLOCK_NOT_GATED)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				clk_mode, normal);
+		else if (arg & CLOCK_GATED)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				clk_mode, gated);
+
+		break;
+	case SSP_IPOLARITY:
+		/* NOTE!! negedge is considered NORMAL */
+		if (arg & CLOCK_NORMAL)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				clk_polarity, neg);
+		else if (arg & CLOCK_INVERT)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				clk_polarity, pos);
+
+		if (arg & FRAME_NORMAL)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				frame_polarity, normal);
+		else if (arg & FRAME_INVERT)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				frame_polarity, inverted);
+
+		if (arg & STATUS_NORMAL)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				status_polarity, normal);
+		else if (arg & STATUS_INVERT)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				status_polarity, inverted);
+		break;
+	case SSP_OPOLARITY:
+		if (arg & CLOCK_NORMAL)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				clk_driver, normal);
+		else if (arg & CLOCK_INVERT)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				clk_driver, inverted);
+
+		if (arg & FRAME_NORMAL)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				frame_driver, normal);
+		else if (arg & FRAME_INVERT)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				frame_driver, inverted);
+
+		if (arg & STATUS_NORMAL)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				status_driver, normal);
+		else if (arg & STATUS_INVERT)
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				status_driver, inverted);
+		break;
+	case SSP_SPI:
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, flow_ctrl,
+			disabled);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, bitorder,
+			msb);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize,
+			size8bit);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_sync, on);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_syncsize,
+			word);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_synctype,
+			normal);
+		if (arg & SPI_SLAVE) {
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				frame_polarity, inverted);
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				clk_polarity, neg);
+			SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				mode, SLAVE_INPUT);
+		} else {
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				frame_driver, inverted);
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				clk_driver, inverted);
+			SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL,
+				mode, MASTER_OUTPUT);
+		}
+		break;
+	case SSP_INBUFCHUNK:
+#if 0
+		if (arg > port->in_buffer_size/NUM_IN_DESCR)
+			return -EINVAL;
+		port->inbufchunk = arg;
+		/* Make sure in_buffer_size is a multiple of inbufchunk */
+		port->in_buffer_size =
+			(port->in_buffer_size/port->inbufchunk) *
+			port->inbufchunk;
+		DEBUG(printk(KERN_DEBUG "inbufchunk %i in_buffer_size: %i\n",
+			port->inbufchunk, port->in_buffer_size));
+		if (port->use_dma) {
+			if (port->port_nbr == 0) {
+				RESET_DMA(9);
+				WAIT_DMA(9);
+			} else {
+				RESET_DMA(5);
+				WAIT_DMA(5);
+			}
+			start_dma_in(port);
+		}
+#endif
+		break;
+	default:
+		return_val = -1;
+	}
+	/* Make sure we write the config without interruption */
+	local_irq_save(flags);
+	/* Set config and enable port */
+	*port->ctrl_data = port->ctrl_data_shadow;
+	nop(); nop(); nop(); nop();
+	*R_SYNC_SERIAL_PRESCALE = sync_serial_prescale_shadow;
+	nop(); nop(); nop(); nop();
+	if (dev)
+		SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, sync);
+	else
+		SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, sync);
+
+	*R_GEN_CONFIG_II = gen_config_ii_shadow;
+	/* Reset DMA. At readout from serial port the data could be shifted
+	 * one byte if not resetting DMA.
+	 */
+	if (port->use_dma) {
+		if (port->port_nbr == 0) {
+			RESET_DMA(9);
+			WAIT_DMA(9);
+		} else {
+			RESET_DMA(5);
+			WAIT_DMA(5);
+		}
+		start_dma_in(port);
+	}
+	local_irq_restore(flags);
+	return return_val;
+}
+
+
+static ssize_t sync_serial_write(struct file *file, const char *buf,
+	size_t count, loff_t *ppos)
+{
+	int dev = MINOR(file->f_dentry->d_inode->i_rdev);
+	DECLARE_WAITQUEUE(wait, current);
+	struct sync_port *port;
+	unsigned long flags;
+	unsigned long c, c1;
+	unsigned long free_outp;
+	unsigned long outp;
+	unsigned long out_buffer;
+
+	if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) {
+		DEBUG(printk(KERN_DEBUG "Invalid minor %d\n", dev));
+		return -ENODEV;
+	}
+	port = &ports[dev];
+
+	DEBUGWRITE(printk(KERN_DEBUG "W d%d c %lu (%d/%d)\n",
+		port->port_nbr, count, port->out_count, OUT_BUFFER_SIZE));
+	/* Space to end of buffer */
+	/*
+	 * out_buffer <c1>012345<-   c    ->OUT_BUFFER_SIZE
+	 *            outp^    +out_count
+	 *                      ^free_outp
+	 * out_buffer 45<-     c      ->0123OUT_BUFFER_SIZE
+	 *             +out_count   outp^
+	 *              free_outp
+	 *
+	 */
+
+	/* Read variables that may be updated by interrupts */
+	local_irq_save(flags);
+	if (count > OUT_BUFFER_SIZE - port->out_count)
+		count = OUT_BUFFER_SIZE - port->out_count;
+
+	outp = (unsigned long)port->outp;
+	free_outp = outp + port->out_count;
+	local_irq_restore(flags);
+	out_buffer = (unsigned long)port->out_buffer;
+
+	/* Find out where and how much to write */
+	if (free_outp >= out_buffer + OUT_BUFFER_SIZE)
+		free_outp -= OUT_BUFFER_SIZE;
+	if (free_outp >= outp)
+		c = out_buffer + OUT_BUFFER_SIZE - free_outp;
+	else
+		c = outp - free_outp;
+	if (c > count)
+		c = count;
+
+	DEBUGWRITE(printk(KERN_DEBUG "w op %08lX fop %08lX c %lu\n",
+		outp, free_outp, c));
+	if (copy_from_user((void *)free_outp, buf, c))
+		return -EFAULT;
+
+	if (c != count) {
+		buf += c;
+		c1 = count - c;
+		DEBUGWRITE(printk(KERN_DEBUG "w2 fi %lu c %lu c1 %lu\n",
+			free_outp-out_buffer, c, c1));
+		if (copy_from_user((void *)out_buffer, buf, c1))
+			return -EFAULT;
+	}
+	local_irq_save(flags);
+	port->out_count += count;
+	local_irq_restore(flags);
+
+	/* Make sure transmitter/receiver is running */
+	if (!port->started) {
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt,
+			running);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_enable,
+			enable);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, rec_enable,
+			enable);
+		port->started = 1;
+	}
+
+	*port->ctrl_data = port->ctrl_data_shadow;
+
+	if (file->f_flags & O_NONBLOCK)	{
+		local_irq_save(flags);
+		if (!port->tr_running) {
+			if (!port->use_dma) {
+				/* Start sender by writing data */
+				send_word(port);
+				/* and enable transmitter ready IRQ */
+				*R_IRQ_MASK1_SET = 1 <<
+					port->transmitter_ready_bit;
+			} else
+				start_dma(port,
+					(unsigned char *volatile)port->outp, c);
+		}
+		local_irq_restore(flags);
+		DEBUGWRITE(printk(KERN_DEBUG "w d%d c %lu NB\n",
+			port->port_nbr, count));
+		return count;
+	}
+
+	/* Sleep until all sent */
+	add_wait_queue(&port->out_wait_q, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+	local_irq_save(flags);
+	if (!port->tr_running) {
+		if (!port->use_dma) {
+			/* Start sender by writing data */
+			send_word(port);
+			/* and enable transmitter ready IRQ */
+			*R_IRQ_MASK1_SET = 1 << port->transmitter_ready_bit;
+		} else
+			start_dma(port, port->outp, c);
+	}
+	local_irq_restore(flags);
+	schedule();
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&port->out_wait_q, &wait);
+	if (signal_pending(current))
+		return -EINTR;
+
+	DEBUGWRITE(printk(KERN_DEBUG "w d%d c %lu\n", port->port_nbr, count));
+	return count;
+}
+
+static ssize_t sync_serial_read(struct file *file, char *buf,
+				size_t count, loff_t *ppos)
+{
+	int dev = MINOR(file->f_dentry->d_inode->i_rdev);
+	int avail;
+	struct sync_port *port;
+	unsigned char *start;
+	unsigned char *end;
+	unsigned long flags;
+
+	if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) {
+		DEBUG(printk(KERN_DEBUG "Invalid minor %d\n", dev));
+		return -ENODEV;
+	}
+	port = &ports[dev];
+
+	DEBUGREAD(printk(KERN_DEBUG "R%d c %d ri %lu wi %lu /%lu\n",
+		dev, count, port->readp - port->flip,
+		port->writep - port->flip, port->in_buffer_size));
+
+	if (!port->started) {
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt,
+			running);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_enable,
+			enable);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, rec_enable,
+			enable);
+		port->started = 1;
+	}
+	*port->ctrl_data = port->ctrl_data_shadow;
+
+	/* Calculate number of available bytes */
+	/* Save pointers to avoid that they are modified by interrupt */
+	local_irq_save(flags);
+	start = (unsigned char *)port->readp; /* cast away volatile */
+	end = (unsigned char *)port->writep;  /* cast away volatile */
+	local_irq_restore(flags);
+	while (start == end && !port->full) {
+		/* No data */
+		if (file->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+
+		interruptible_sleep_on(&port->in_wait_q);
+		if (signal_pending(current))
+			return -EINTR;
+
+		local_irq_save(flags);
+		start = (unsigned char *)port->readp; /* cast away volatile */
+		end = (unsigned char *)port->writep;  /* cast away volatile */
+		local_irq_restore(flags);
+	}
+
+	/* Lazy read, never return wrapped data. */
+	if (port->full)
+		avail = port->in_buffer_size;
+	else if (end > start)
+		avail = end - start;
+	else
+		avail = port->flip + port->in_buffer_size - start;
+
+	count = count > avail ? avail : count;
+	if (copy_to_user(buf, start, count))
+		return -EFAULT;
+	/* Disable interrupts while updating readp */
+	local_irq_save(flags);
+	port->readp += count;
+	if (port->readp >= port->flip + port->in_buffer_size) /* Wrap? */
+		port->readp = port->flip;
+	port->full = 0;
+	local_irq_restore(flags);
+	DEBUGREAD(printk(KERN_DEBUG "r %d\n", count));
+	return count;
+}
+
+static void send_word(struct sync_port *port)
+{
+	switch (IO_EXTRACT(R_SYNC_SERIAL1_CTRL, wordsize,
+			port->ctrl_data_shadow)) {
+	case IO_STATE_VALUE(R_SYNC_SERIAL1_CTRL, wordsize, size8bit):
+		 port->out_count--;
+		 *port->data_out = *port->outp++;
+		 if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE)
+			 port->outp = port->out_buffer;
+		 break;
+	case IO_STATE_VALUE(R_SYNC_SERIAL1_CTRL, wordsize, size12bit):
+	{
+		int data = (*port->outp++) << 8;
+		data |= *port->outp++;
+		port->out_count -= 2;
+		*port->data_out = data;
+		if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE)
+			port->outp = port->out_buffer;
+		break;
+	}
+	case IO_STATE_VALUE(R_SYNC_SERIAL1_CTRL, wordsize, size16bit):
+		port->out_count -= 2;
+		*port->data_out = *(unsigned short *)port->outp;
+		port->outp += 2;
+		if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE)
+			port->outp = port->out_buffer;
+		break;
+	case IO_STATE_VALUE(R_SYNC_SERIAL1_CTRL, wordsize, size24bit):
+		port->out_count -= 3;
+		*port->data_out = *(unsigned int *)port->outp;
+		port->outp += 3;
+		if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE)
+			port->outp = port->out_buffer;
+		break;
+	case IO_STATE_VALUE(R_SYNC_SERIAL1_CTRL, wordsize, size32bit):
+		port->out_count -= 4;
+		*port->data_out = *(unsigned int *)port->outp;
+		port->outp += 4;
+		if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE)
+			port->outp = port->out_buffer;
+		break;
+	}
+}
+
+
+static void start_dma(struct sync_port *port, const char *data, int count)
+{
+	port->tr_running = 1;
+	port->out_descr.hw_len = 0;
+	port->out_descr.next = 0;
+	port->out_descr.ctrl = d_eol | d_eop; /* No d_wait to avoid glitches */
+	port->out_descr.sw_len = count;
+	port->out_descr.buf = virt_to_phys(data);
+	port->out_descr.status = 0;
+
+	*port->output_dma_first = virt_to_phys(&port->out_descr);
+	*port->output_dma_cmd = IO_STATE(R_DMA_CH0_CMD, cmd, start);
+	DEBUGTXINT(printk(KERN_DEBUG "dma %08lX c %d\n",
+		(unsigned long)data, count));
+}
+
+static void start_dma_in(struct sync_port *port)
+{
+	int i;
+	unsigned long buf;
+	port->writep = port->flip;
+
+	if (port->writep > port->flip + port->in_buffer_size) {
+		panic("Offset too large in sync serial driver\n");
+		return;
+	}
+	buf = virt_to_phys(port->in_buffer);
+	for (i = 0; i < NUM_IN_DESCR; i++) {
+		port->in_descr[i].sw_len = port->inbufchunk;
+		port->in_descr[i].ctrl = d_int;
+		port->in_descr[i].next = virt_to_phys(&port->in_descr[i+1]);
+		port->in_descr[i].buf = buf;
+		port->in_descr[i].hw_len = 0;
+		port->in_descr[i].status = 0;
+		port->in_descr[i].fifo_len = 0;
+		buf += port->inbufchunk;
+		prepare_rx_descriptor(&port->in_descr[i]);
+	}
+	/* Link the last descriptor to the first */
+	port->in_descr[i-1].next = virt_to_phys(&port->in_descr[0]);
+	port->in_descr[i-1].ctrl |= d_eol;
+	port->next_rx_desc = &port->in_descr[0];
+	port->prev_rx_desc = &port->in_descr[NUM_IN_DESCR - 1];
+	*port->input_dma_first = virt_to_phys(port->next_rx_desc);
+	*port->input_dma_cmd = IO_STATE(R_DMA_CH0_CMD, cmd, start);
+}
+
+#ifdef SYNC_SER_DMA
+static irqreturn_t tr_interrupt(int irq, void *dev_id)
+{
+	unsigned long ireg = *R_IRQ_MASK2_RD;
+	struct etrax_dma_descr *descr;
+	unsigned int sentl;
+	int handled = 0;
+	int i;
+
+	for (i = 0; i < NUMBER_OF_PORTS; i++) {
+		struct sync_port *port = &ports[i];
+		if (!port->enabled  || !port->use_dma)
+			continue;
+
+		/* IRQ active for the port? */
+		if (!(ireg & (1 << port->output_dma_bit)))
+			continue;
+
+		handled = 1;
+
+		/* Clear IRQ */
+		*port->output_dma_clr_irq =
+			IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do) |
+			IO_STATE(R_DMA_CH0_CLR_INTR, clr_descr, do);
+
+		descr = &port->out_descr;
+		if (!(descr->status & d_stop))
+			sentl = descr->sw_len;
+		else
+			/* Otherwise find amount of data sent here */
+			sentl = descr->hw_len;
+
+		port->out_count -= sentl;
+		port->outp += sentl;
+		if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE)
+			port->outp = port->out_buffer;
+		if (port->out_count) {
+			int c = port->out_buffer + OUT_BUFFER_SIZE - port->outp;
+			if (c > port->out_count)
+				c = port->out_count;
+			DEBUGTXINT(printk(KERN_DEBUG
+				"tx_int DMAWRITE %i %i\n", sentl, c));
+			start_dma(port, port->outp, c);
+		} else  {
+			DEBUGTXINT(printk(KERN_DEBUG
+				"tx_int DMA stop %i\n", sentl));
+			port->tr_running = 0;
+		}
+		/* wake up the waiting process */
+		wake_up_interruptible(&port->out_wait_q);
+	}
+	return IRQ_RETVAL(handled);
+} /* tr_interrupt */
+
+static irqreturn_t rx_interrupt(int irq, void *dev_id)
+{
+	unsigned long ireg = *R_IRQ_MASK2_RD;
+	int i;
+	int handled = 0;
+
+	for (i = 0; i < NUMBER_OF_PORTS; i++) {
+		struct sync_port *port = &ports[i];
+
+		if (!port->enabled || !port->use_dma)
+			continue;
+
+		if (!(ireg & (1 << port->input_dma_descr_bit)))
+			continue;
+
+		/* Descriptor interrupt */
+		handled = 1;
+		while (*port->input_dma_descr !=
+				virt_to_phys(port->next_rx_desc)) {
+			if (port->writep + port->inbufchunk > port->flip +
+					port->in_buffer_size) {
+				int first_size = port->flip +
+					port->in_buffer_size - port->writep;
+				memcpy(port->writep,
+					phys_to_virt(port->next_rx_desc->buf),
+					first_size);
+				memcpy(port->flip,
+					phys_to_virt(port->next_rx_desc->buf +
+					first_size),
+					port->inbufchunk - first_size);
+				port->writep = port->flip +
+					port->inbufchunk - first_size;
+			} else {
+				memcpy(port->writep,
+					phys_to_virt(port->next_rx_desc->buf),
+					port->inbufchunk);
+				port->writep += port->inbufchunk;
+				if (port->writep >= port->flip
+						+ port->in_buffer_size)
+					port->writep = port->flip;
+			}
+			if (port->writep == port->readp)
+				port->full = 1;
+			prepare_rx_descriptor(port->next_rx_desc);
+			port->next_rx_desc->ctrl |= d_eol;
+			port->prev_rx_desc->ctrl &= ~d_eol;
+			port->prev_rx_desc = phys_to_virt((unsigned)
+				port->next_rx_desc);
+			port->next_rx_desc = phys_to_virt((unsigned)
+				port->next_rx_desc->next);
+			/* Wake up the waiting process */
+			wake_up_interruptible(&port->in_wait_q);
+			*port->input_dma_cmd = IO_STATE(R_DMA_CH1_CMD,
+				cmd, restart);
+			/* DMA has reached end of descriptor */
+			*port->input_dma_clr_irq = IO_STATE(R_DMA_CH0_CLR_INTR,
+				clr_descr, do);
+		}
+	}
+	return IRQ_RETVAL(handled);
+} /* rx_interrupt */
+#endif /* SYNC_SER_DMA */
+
+#ifdef SYNC_SER_MANUAL
+static irqreturn_t manual_interrupt(int irq, void *dev_id)
+{
+	int i;
+	int handled = 0;
+
+	for (i = 0; i < NUMBER_OF_PORTS; i++) {
+		struct sync_port *port = &ports[i];
+
+		if (!port->enabled || port->use_dma)
+			continue;
+
+		/* Data received? */
+		if (*R_IRQ_MASK1_RD & (1 << port->data_avail_bit)) {
+			handled = 1;
+			/* Read data */
+			switch (port->ctrl_data_shadow &
+				IO_MASK(R_SYNC_SERIAL1_CTRL, wordsize)) {
+			case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size8bit):
+				*port->writep++ =
+					*(volatile char *)port->data_in;
+				break;
+			case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size12bit):
+			{
+				int data = *(unsigned short *)port->data_in;
+				*port->writep = (data & 0x0ff0) >> 4;
+				*(port->writep + 1) = data & 0x0f;
+				port->writep += 2;
+				break;
+			}
+			case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size16bit):
+				*(unsigned short *)port->writep =
+					*(volatile unsigned short *)port->data_in;
+				port->writep += 2;
+				break;
+			case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size24bit):
+				*(unsigned int *)port->writep = *port->data_in;
+				port->writep += 3;
+				break;
+			case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size32bit):
+				*(unsigned int *)port->writep = *port->data_in;
+				port->writep += 4;
+				break;
+			}
+
+			/* Wrap? */
+			if (port->writep >= port->flip + port->in_buffer_size)
+				port->writep = port->flip;
+			if (port->writep == port->readp) {
+				/* Receive buffer overrun, discard oldest */
+				port->readp++;
+				/* Wrap? */
+				if (port->readp >= port->flip +
+						port->in_buffer_size)
+					port->readp = port->flip;
+			}
+			if (sync_data_avail(port) >= port->inbufchunk) {
+				/* Wake up application */
+				wake_up_interruptible(&port->in_wait_q);
+			}
+		}
+
+		/* Transmitter ready? */
+		if (*R_IRQ_MASK1_RD & (1 << port->transmitter_ready_bit)) {
+			if (port->out_count > 0) {
+				/* More data to send */
+				send_word(port);
+			} else {
+				/* Transmission finished */
+				/* Turn off IRQ */
+				*R_IRQ_MASK1_CLR = 1 <<
+					port->transmitter_ready_bit;
+				/* Wake up application */
+				wake_up_interruptible(&port->out_wait_q);
+			}
+		}
+	}
+	return IRQ_RETVAL(handled);
+}
+#endif
+
+module_init(etrax_sync_serial_init);
diff --git a/arch/cris/arch-v10/kernel/debugport.c b/arch/cris/arch-v10/kernel/debugport.c
index 93679a48c791..04d5eee2c90c 100644
--- a/arch/cris/arch-v10/kernel/debugport.c
+++ b/arch/cris/arch-v10/kernel/debugport.c
@@ -1,6 +1,6 @@
 /* Serialport functions for debugging
  *
- * Copyright (c) 2000 Axis Communications AB
+ * Copyright (c) 2000-2007 Axis Communications AB
  *
  * Authors:  Bjorn Wesen
  *
@@ -11,96 +11,6 @@
  *    enableDebugIRQ()
  *    init_etrax_debug()
  *
- * $Log: debugport.c,v $
- * Revision 1.27  2005/06/10 10:34:14  starvik
- * Real console support
- *
- * Revision 1.26  2005/06/07 07:06:07  starvik
- * Added LF->CR translation to make ETRAX customers happy.
- *
- * Revision 1.25  2005/03/08 08:56:47  mikaelam
- * Do only set index as port->index if port is defined, otherwise use the index from the command line
- *
- * Revision 1.24  2005/01/19 10:26:33  mikaelam
- * Return the cris serial driver in console device driver callback function
- *
- * Revision 1.23  2005/01/14 10:12:17  starvik
- * KGDB on separate port.
- * Console fixes from 2.4.
- *
- * Revision 1.22  2005/01/11 16:06:13  starvik
- * typo
- *
- * Revision 1.21  2005/01/11 13:49:14  starvik
- * Added raw_printk to be used where we don't trust the console.
- *
- * Revision 1.20  2004/12/27 11:18:32  starvik
- * Merge of Linux 2.6.10 (not functional yet).
- *
- * 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 preferred 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/console.h>
@@ -112,6 +22,8 @@
 #include <asm/arch/svinto.h>
 #include <asm/io.h>             /* Get SIMCOUT. */
 
+extern void reset_watchdog(void);
+
 struct dbg_port
 {
   unsigned int index;
@@ -188,7 +100,9 @@ struct dbg_port ports[]=
   }
 };
 
+#ifdef CONFIG_ETRAX_SERIAL
 extern struct tty_driver *serial_driver;
+#endif
 
 struct dbg_port* port =
 #if defined(CONFIG_ETRAX_DEBUG_PORT0)
@@ -368,11 +282,12 @@ console_write_direct(struct console *co, const char *buf, unsigned int len)
 {
 	int i;
 	unsigned long flags;
-	local_irq_save(flags);
 
         if (!port)
 		return;
 
+	local_irq_save(flags);
+
 	/* Send data */
 	for (i = 0; i < len; i++) {
 		/* LF -> CRLF */
@@ -386,26 +301,16 @@ console_write_direct(struct console *co, const char *buf, unsigned int len)
 			;
 		*port->write = buf[i];
 	}
-	local_irq_restore(flags);
-}
 
-int raw_printk(const char *fmt, ...)
-{
-	static char buf[1024];
-	int printed_len;
-	static int first = 1;
-	if (first) {
-		/* Force reinitialization of the port to get manual mode. */
-		port->started = 0;
-		start_port(port);
-		first = 0;
-	}
-	va_list args;
-	va_start(args, fmt);
-	printed_len = vsnprintf(buf, sizeof(buf), fmt, args);
-	va_end(args);
-	console_write_direct(NULL, buf, strlen(buf));
-	return printed_len;
+	/*
+	 * Feed the watchdog, otherwise it will reset the chip during boot.
+	 * The time to send an ordinary boot message line (10-90 chars)
+	 * varies between 1-8ms at 115200. What makes up for the additional
+	 * 90ms that allows the watchdog to bite?
+	*/
+	reset_watchdog();
+
+	local_irq_restore(flags);
 }
 
 static void
@@ -500,6 +405,7 @@ console_setup(struct console *co, char *options)
 	return 0;
 }
 
+
 /* This is a dummy serial device that throws away anything written to it.
  * This is used when no debug output is wanted.
  */
@@ -555,7 +461,13 @@ etrax_console_device(struct console* co, int *index)
 {
 	if (port)
 		*index = port->index;
+	else
+		*index = 0;
+#ifdef CONFIG_ETRAX_SERIAL
         return port ? serial_driver : &dummy_driver;
+#else
+	return &dummy_driver;
+#endif
 }
 
 static struct console sercons = {
diff --git a/arch/cris/arch-v10/kernel/dma.c b/arch/cris/arch-v10/kernel/dma.c
index e9a0311b141d..eb1fa0d2b49f 100644
--- a/arch/cris/arch-v10/kernel/dma.c
+++ b/arch/cris/arch-v10/kernel/dma.c
@@ -1,6 +1,5 @@
 /* Wrapper for DMA channel allocator that updates DMA client muxing.
- * Copyright 2004, Axis Communications AB
- * $Id: dma.c,v 1.1 2004/12/13 12:21:51 starvik Exp $
+ * Copyright 2004-2007, Axis Communications AB
  */
 
 #include <linux/kernel.h>
diff --git a/arch/cris/arch-v10/kernel/entry.S b/arch/cris/arch-v10/kernel/entry.S
index d1361dc119e2..3a65f322ae07 100644
--- a/arch/cris/arch-v10/kernel/entry.S
+++ b/arch/cris/arch-v10/kernel/entry.S
@@ -1,252 +1,9 @@
-/* $Id: entry.S,v 1.28 2005/06/20 05:06:30 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.28  2005/06/20 05:06:30  starvik
- *  Remove unnecessary diff to kernel.org tree
- *
- *  Revision 1.27  2005/03/04 08:16:16  starvik
- *  Merge of Linux 2.6.11.
- *
- *  Revision 1.26  2005/01/11 13:49:47  starvik
- *  Added NMI handler.
- *
- *  Revision 1.25  2004/12/27 11:18:32  starvik
- *  Merge of Linux 2.6.10 (not functional yet).
- *
- *  Revision 1.24  2004/12/22 10:41:23  starvik
- *  Updates to make v10 compile with the latest SMP aware generic code (even
- *  though v10 will never have SMP).
- *
- *  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 explicitly (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
- *
- *
  */
 
 /*
@@ -1167,9 +924,11 @@ sys_call_table:
 	.long sys_epoll_pwait
 	.long sys_utimensat		/* 320 */
 	.long sys_signalfd
-	.long sys_ni_syscall
+	.long sys_timerfd_create
 	.long sys_eventfd
 	.long sys_fallocate
+	.long sys_timerfd_settime	/* 325 */
+	.long sys_timerfd_gettime
 
         /*
          * NOTE!! This doesn't have to be exact - we just have
diff --git a/arch/cris/arch-v10/kernel/fasttimer.c b/arch/cris/arch-v10/kernel/fasttimer.c
index c1a3a2100ee7..31ff35cff02c 100644
--- a/arch/cris/arch-v10/kernel/fasttimer.c
+++ b/arch/cris/arch-v10/kernel/fasttimer.c
@@ -31,15 +31,12 @@
 
 #define DEBUG_LOG_INCLUDED
 #define FAST_TIMER_LOG
-//#define FAST_TIMER_TEST
+/* #define FAST_TIMER_TEST */
 
 #define FAST_TIMER_SANITY_CHECKS
 
 #ifdef FAST_TIMER_SANITY_CHECKS
-#define SANITYCHECK(x) x
 static int sanity_failed;
-#else
-#define SANITYCHECK(x)
 #endif
 
 #define D1(x)
@@ -226,23 +223,19 @@ void start_one_shot_timer(struct fast_timer *t,
   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++;
-				goto done;
-      }
-      else
-      {
-        tmp = tmp->next;
-      }
-    }
-    tmp = fast_timer_list;
-  });
+#ifdef FAST_TIMER_SANITY_CHECKS
+	/* 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++;
+			goto done;
+		} else
+			tmp = tmp->next;
+	}
+	tmp = fast_timer_list;
+#endif
 
   t->delay_us = delay_us;
   t->function = function;
diff --git a/arch/cris/arch-v10/kernel/head.S b/arch/cris/arch-v10/kernel/head.S
index d946d8b8d277..96344afc4ebc 100644
--- a/arch/cris/arch-v10/kernel/head.S
+++ b/arch/cris/arch-v10/kernel/head.S
@@ -1,186 +1,10 @@
-/* $Id: head.S,v 1.10 2005/06/20 05:12:54 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.10  2005/06/20 05:12:54  starvik
- * Remove unnecessary diff to kernel.org tree
- *
- * Revision 1.9  2004/12/13 12:21:51  starvik
- * Added I/O and DMA allocators from Linux 2.4
- *
- * Revision 1.8  2004/11/22 11:41:14  starvik
- * Kernel command line may be supplied to kernel. Not used by Axis but may
- * be used by customers.
- *
- * 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
- *
  */
 	
 #define ASSEMBLER_MACROS_ONLY
@@ -595,11 +419,17 @@ no_command_line:
 
 	moveq	0,$r0
 
+	;; Select or disable serial port 2
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+	or.d	  IO_STATE (R_GEN_CONFIG, ser2, select),$r0
+#else
+	or.d	  IO_STATE (R_GEN_CONFIG, ser2, disable),$r0
+#endif
+
 	;; Init interfaces (disable them).
 	or.d	  IO_STATE (R_GEN_CONFIG, scsi0, disable) \
 		| IO_STATE (R_GEN_CONFIG, ata, disable) \
 		| IO_STATE (R_GEN_CONFIG, par0, disable) \
-		| IO_STATE (R_GEN_CONFIG, ser2, disable) \
 		| IO_STATE (R_GEN_CONFIG, mio, disable) \
 		| IO_STATE (R_GEN_CONFIG, scsi1, disable) \
 		| IO_STATE (R_GEN_CONFIG, scsi0w, disable) \
@@ -801,6 +631,41 @@ no_command_line:
 		| IO_STATE (R_SERIAL1_TR_CTRL, tr_bitnr, tr_8bit),$r0
 	move.b	$r0,[R_SERIAL1_TR_CTRL]
 
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+	;; setup the serial port 2 at 115200 baud for debug purposes
+
+	moveq	  IO_STATE (R_SERIAL2_XOFF, tx_stop, enable)		\
+		| IO_STATE (R_SERIAL2_XOFF, auto_xoff, disable)		\
+		| IO_FIELD (R_SERIAL2_XOFF, xoff_char, 0),$r0
+	move.d	$r0,[R_SERIAL2_XOFF]
+
+	; 115.2kbaud for both transmit and receive
+	move.b	  IO_STATE (R_SERIAL2_BAUD, tr_baud, c115k2Hz)		\
+		| IO_STATE (R_SERIAL2_BAUD, rec_baud, c115k2Hz),$r0
+	move.b	$r0,[R_SERIAL2_BAUD]
+
+	; Set up and enable the serial2 receiver.
+	move.b	  IO_STATE (R_SERIAL2_REC_CTRL, dma_err, stop)		\
+		| IO_STATE (R_SERIAL2_REC_CTRL, rec_enable, enable)	\
+		| IO_STATE (R_SERIAL2_REC_CTRL, rts_, active)		\
+		| IO_STATE (R_SERIAL2_REC_CTRL, sampling, middle)	\
+		| IO_STATE (R_SERIAL2_REC_CTRL, rec_stick_par, normal)	\
+		| IO_STATE (R_SERIAL2_REC_CTRL, rec_par, even)		\
+		| IO_STATE (R_SERIAL2_REC_CTRL, rec_par_en, disable)	\
+		| IO_STATE (R_SERIAL2_REC_CTRL, rec_bitnr, rec_8bit),$r0
+	move.b	$r0,[R_SERIAL2_REC_CTRL]
+
+	; Set up and enable the serial2 transmitter.
+	move.b	  IO_FIELD (R_SERIAL2_TR_CTRL, txd, 0)			\
+		| IO_STATE (R_SERIAL2_TR_CTRL, tr_enable, enable)	\
+		| IO_STATE (R_SERIAL2_TR_CTRL, auto_cts, disabled)	\
+		| IO_STATE (R_SERIAL2_TR_CTRL, stop_bits, one_bit)	\
+		| IO_STATE (R_SERIAL2_TR_CTRL, tr_stick_par, normal)	\
+		| IO_STATE (R_SERIAL2_TR_CTRL, tr_par, even)		\
+		| IO_STATE (R_SERIAL2_TR_CTRL, tr_par_en, disable)	\
+		| IO_STATE (R_SERIAL2_TR_CTRL, tr_bitnr, tr_8bit),$r0
+	move.b	$r0,[R_SERIAL2_TR_CTRL]
+#endif
 	
 #ifdef CONFIG_ETRAX_SERIAL_PORT3	
 	;; setup the serial port 3 at 115200 baud for debug purposes
diff --git a/arch/cris/arch-v10/kernel/io_interface_mux.c b/arch/cris/arch-v10/kernel/io_interface_mux.c
index f3b327d4ed9c..add98e0941b5 100644
--- a/arch/cris/arch-v10/kernel/io_interface_mux.c
+++ b/arch/cris/arch-v10/kernel/io_interface_mux.c
@@ -1,10 +1,9 @@
 /* IO interface mux allocator for ETRAX100LX.
- * Copyright 2004, Axis Communications AB
- * $Id: io_interface_mux.c,v 1.2 2004/12/21 12:08:38 starvik Exp $
+ * Copyright 2004-2007, Axis Communications AB
  */
 
 
-/* C.f. ETRAX100LX Designer's Reference 20.9 */
+/* C.f. ETRAX100LX Designer's Reference chapter 19.9 */
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -45,17 +44,39 @@ struct watcher
 struct if_group
 {
 	enum io_if_group        group;
-	unsigned char           used;
-	enum cris_io_interface  owner;
+	/* name	- the name of the group 'A' to 'F' */
+	char                   *name;
+	/* used	- a bit mask of all pins in the group in the order listed
+	 * in the tables in 19.9.1 to 19.9.6.  Note that no
+	 * distinction is made between in, out and in/out pins. */
+	unsigned int            used;
 };
 
 
 struct interface
 {
 	enum cris_io_interface   ioif;
+	/* name - the name of the interface */
+	char                    *name;
+	/* groups - OR'ed together io_if_group flags describing what pin groups
+	 * the interface uses pins in. */
 	unsigned char            groups;
+	/* used - set when the interface is allocated. */
 	unsigned char            used;
 	char                    *owner;
+	/* group_a through group_f - bit masks describing what pins in the
+	 * pin groups the interface uses. */
+	unsigned int             group_a;
+	unsigned int             group_b;
+	unsigned int             group_c;
+	unsigned int             group_d;
+	unsigned int             group_e;
+	unsigned int             group_f;
+
+	/* gpio_g_in, gpio_g_out, gpio_b - bit masks telling what pins in the
+	 * GPIO ports the interface uses.  This could be reconstucted using
+	 * the group_X masks and a table of what pins the GPIO ports use,
+	 * but that would be messy. */
 	unsigned int             gpio_g_in;
 	unsigned int             gpio_g_out;
 	unsigned char            gpio_b;
@@ -64,26 +85,32 @@ struct interface
 static struct if_group if_groups[6] = {
 	{
 		.group = group_a,
+		.name = "A",
 		.used = 0,
 	},
 	{
 		.group = group_b,
+		.name = "B",
 		.used = 0,
 	},
 	{
 		.group = group_c,
+		.name = "C",
 		.used = 0,
 	},
 	{
 		.group = group_d,
+		.name = "D",
 		.used = 0,
 	},
 	{
 		.group = group_e,
+		.name = "E",
 		.used = 0,
 	},
 	{
 		.group = group_f,
+		.name = "F",
 		.used = 0,
 	}
 };
@@ -94,14 +121,32 @@ static struct interface interfaces[] = {
 	/* Begin Non-multiplexed interfaces */
 	{
 		.ioif = if_eth,
+		.name = "ethernet",
 		.groups = 0,
+
+		.group_a = 0,
+		.group_b = 0,
+		.group_c = 0,
+		.group_d = 0,
+		.group_e = 0,
+		.group_f = 0,
+
 		.gpio_g_in = 0,
 		.gpio_g_out = 0,
 		.gpio_b = 0
 	},
 	{
 		.ioif = if_serial_0,
+		.name = "serial_0",
 		.groups = 0,
+
+		.group_a = 0,
+		.group_b = 0,
+		.group_c = 0,
+		.group_d = 0,
+		.group_e = 0,
+		.group_f = 0,
+
 		.gpio_g_in = 0,
 		.gpio_g_out = 0,
 		.gpio_b = 0
@@ -109,172 +154,385 @@ static struct interface interfaces[] = {
 	/* End Non-multiplexed interfaces */
 	{
 		.ioif = if_serial_1,
+		.name = "serial_1",
 		.groups = group_e,
+
+		.group_a = 0,
+		.group_b = 0,
+		.group_c = 0,
+		.group_d = 0,
+		.group_e = 0x0f,
+		.group_f = 0,
+
 		.gpio_g_in =  0x00000000,
 		.gpio_g_out = 0x00000000,
 		.gpio_b = 0x00
 	},
 	{
 		.ioif = if_serial_2,
+		.name = "serial_2",
 		.groups = group_b,
+
+		.group_a = 0,
+		.group_b = 0x0f,
+		.group_c = 0,
+		.group_d = 0,
+		.group_e = 0,
+		.group_f = 0,
+
 		.gpio_g_in =  0x000000c0,
 		.gpio_g_out = 0x000000c0,
 		.gpio_b = 0x00
 	},
 	{
 		.ioif = if_serial_3,
+		.name = "serial_3",
 		.groups = group_c,
+
+		.group_a = 0,
+		.group_b = 0,
+		.group_c = 0x0f,
+		.group_d = 0,
+		.group_e = 0,
+		.group_f = 0,
+
 		.gpio_g_in =  0xc0000000,
 		.gpio_g_out = 0xc0000000,
 		.gpio_b = 0x00
 	},
 	{
 		.ioif = if_sync_serial_1,
-		.groups = group_e | group_f, /* if_sync_serial_1 and if_sync_serial_3
-					       can be used simultaneously */
+		.name = "sync_serial_1",
+		.groups = group_e | group_f,
+
+		.group_a = 0,
+		.group_b = 0,
+		.group_c = 0,
+		.group_d = 0,
+		.group_e = 0x0f,
+		.group_f = 0x10,
+
 		.gpio_g_in =  0x00000000,
 		.gpio_g_out = 0x00000000,
 		.gpio_b = 0x10
 	},
 	{
 		.ioif = if_sync_serial_3,
+		.name = "sync_serial_3",
 		.groups = group_c | group_f,
+
+		.group_a = 0,
+		.group_b = 0,
+		.group_c = 0x0f,
+		.group_d = 0,
+		.group_e = 0,
+		.group_f = 0x80,
+
 		.gpio_g_in =  0xc0000000,
 		.gpio_g_out = 0xc0000000,
 		.gpio_b = 0x80
 	},
 	{
 		.ioif = if_shared_ram,
+		.name = "shared_ram",
 		.groups = group_a,
+
+		.group_a = 0x7f8ff,
+		.group_b = 0,
+		.group_c = 0,
+		.group_d = 0,
+		.group_e = 0,
+		.group_f = 0,
+
 		.gpio_g_in =  0x0000ff3e,
 		.gpio_g_out = 0x0000ff38,
 		.gpio_b = 0x00
 	},
 	{
 		.ioif = if_shared_ram_w,
+		.name = "shared_ram_w",
 		.groups = group_a | group_d,
+
+		.group_a = 0x7f8ff,
+		.group_b = 0,
+		.group_c = 0,
+		.group_d = 0xff,
+		.group_e = 0,
+		.group_f = 0,
+
 		.gpio_g_in =  0x00ffff3e,
 		.gpio_g_out = 0x00ffff38,
 		.gpio_b = 0x00
 	},
 	{
 		.ioif = if_par_0,
+		.name = "par_0",
 		.groups = group_a,
+
+		.group_a = 0x7fbff,
+		.group_b = 0,
+		.group_c = 0,
+		.group_d = 0,
+		.group_e = 0,
+		.group_f = 0,
+
 		.gpio_g_in =  0x0000ff3e,
 		.gpio_g_out = 0x0000ff3e,
 		.gpio_b = 0x00
 	},
 	{
 		.ioif = if_par_1,
+		.name = "par_1",
 		.groups = group_d,
+
+		.group_a = 0,
+		.group_b = 0,
+		.group_c = 0,
+		.group_d = 0x7feff,
+		.group_e = 0,
+		.group_f = 0,
+
 		.gpio_g_in =  0x3eff0000,
 		.gpio_g_out = 0x3eff0000,
 		.gpio_b = 0x00
 	},
 	{
 		.ioif = if_par_w,
+		.name = "par_w",
 		.groups = group_a | group_d,
+
+		.group_a = 0x7fbff,
+		.group_b = 0,
+		.group_c = 0,
+		.group_d = 0xff,
+		.group_e = 0,
+		.group_f = 0,
+
 		.gpio_g_in =  0x00ffff3e,
 		.gpio_g_out = 0x00ffff3e,
 		.gpio_b = 0x00
 	},
 	{
 		.ioif = if_scsi8_0,
-		.groups = group_a | group_b | group_f, /* if_scsi8_0 and if_scsi8_1
-							  can be used simultaneously */
+		.name = "scsi8_0",
+		.groups = group_a | group_b | group_f,
+
+		.group_a = 0x7ffff,
+		.group_b = 0x0f,
+		.group_c = 0,
+		.group_d = 0,
+		.group_e = 0,
+		.group_f = 0x10,
+
 		.gpio_g_in =  0x0000ffff,
 		.gpio_g_out = 0x0000ffff,
 		.gpio_b = 0x10
 	},
 	{
 		.ioif = if_scsi8_1,
-		.groups = group_c | group_d | group_f, /* if_scsi8_0 and if_scsi8_1
-							  can be used simultaneously */
+		.name = "scsi8_1",
+		.groups = group_c | group_d | group_f,
+
+		.group_a = 0,
+		.group_b = 0,
+		.group_c = 0x0f,
+		.group_d = 0x7ffff,
+		.group_e = 0,
+		.group_f = 0x80,
+
 		.gpio_g_in =  0xffff0000,
 		.gpio_g_out = 0xffff0000,
 		.gpio_b = 0x80
 	},
 	{
 		.ioif = if_scsi_w,
+		.name = "scsi_w",
 		.groups = group_a | group_b | group_d | group_f,
+
+		.group_a = 0x7ffff,
+		.group_b = 0x0f,
+		.group_c = 0,
+		.group_d = 0x601ff,
+		.group_e = 0,
+		.group_f = 0x90,
+
 		.gpio_g_in =  0x01ffffff,
 		.gpio_g_out = 0x07ffffff,
 		.gpio_b = 0x80
 	},
 	{
 		.ioif = if_ata,
+		.name = "ata",
 		.groups = group_a | group_b | group_c | group_d,
+
+		.group_a = 0x7ffff,
+		.group_b = 0x0f,
+		.group_c = 0x0f,
+		.group_d = 0x7cfff,
+		.group_e = 0,
+		.group_f = 0,
+
 		.gpio_g_in =  0xf9ffffff,
 		.gpio_g_out = 0xffffffff,
 		.gpio_b = 0x80
 	},
 	{
 		.ioif = if_csp,
-		.groups = group_f, /* if_csp and if_i2c can be used simultaneously */
+		.name = "csp",
+		.groups = group_f,
+
+		.group_a = 0,
+		.group_b = 0,
+		.group_c = 0,
+		.group_d = 0,
+		.group_e = 0,
+		.group_f = 0xfc,
+
 		.gpio_g_in =  0x00000000,
 		.gpio_g_out = 0x00000000,
 		.gpio_b = 0xfc
 	},
 	{
 		.ioif = if_i2c,
-		.groups = group_f, /* if_csp and if_i2c can be used simultaneously */
+		.name = "i2c",
+		.groups = group_f,
+
+		.group_a = 0,
+		.group_b = 0,
+		.group_c = 0,
+		.group_d = 0,
+		.group_e = 0,
+		.group_f = 0x03,
+
 		.gpio_g_in =  0x00000000,
 		.gpio_g_out = 0x00000000,
 		.gpio_b = 0x03
 	},
 	{
 		.ioif = if_usb_1,
+		.name = "usb_1",
 		.groups = group_e | group_f,
+
+		.group_a = 0,
+		.group_b = 0,
+		.group_c = 0,
+		.group_d = 0,
+		.group_e = 0x0f,
+		.group_f = 0x2c,
+
 		.gpio_g_in =  0x00000000,
 		.gpio_g_out = 0x00000000,
 		.gpio_b = 0x2c
 	},
 	{
 		.ioif = if_usb_2,
+		.name = "usb_2",
 		.groups = group_d,
-		.gpio_g_in =  0x0e000000,
-		.gpio_g_out = 0x3c000000,
+
+		.group_a = 0,
+		.group_b = 0,
+		.group_c = 0,
+		.group_d = 0,
+		.group_e = 0x33e00,
+		.group_f = 0,
+
+		.gpio_g_in =  0x3e000000,
+		.gpio_g_out = 0x0c000000,
 		.gpio_b = 0x00
 	},
 	/* GPIO pins */
 	{
 		.ioif = if_gpio_grp_a,
+		.name = "gpio_a",
 		.groups = group_a,
+
+		.group_a = 0,
+		.group_b = 0,
+		.group_c = 0,
+		.group_d = 0,
+		.group_e = 0,
+		.group_f = 0,
+
 		.gpio_g_in =  0x0000ff3f,
 		.gpio_g_out = 0x0000ff3f,
 		.gpio_b = 0x00
 	},
 	{
 		.ioif = if_gpio_grp_b,
+		.name = "gpio_b",
 		.groups = group_b,
+
+		.group_a = 0,
+		.group_b = 0,
+		.group_c = 0,
+		.group_d = 0,
+		.group_e = 0,
+		.group_f = 0,
+
 		.gpio_g_in =  0x000000c0,
 		.gpio_g_out = 0x000000c0,
 		.gpio_b = 0x00
 	},
 	{
 		.ioif = if_gpio_grp_c,
+		.name = "gpio_c",
 		.groups = group_c,
+
+		.group_a = 0,
+		.group_b = 0,
+		.group_c = 0,
+		.group_d = 0,
+		.group_e = 0,
+		.group_f = 0,
+
 		.gpio_g_in =  0xc0000000,
 		.gpio_g_out = 0xc0000000,
 		.gpio_b = 0x00
 	},
 	{
 		.ioif = if_gpio_grp_d,
+		.name = "gpio_d",
 		.groups = group_d,
+
+		.group_a = 0,
+		.group_b = 0,
+		.group_c = 0,
+		.group_d = 0,
+		.group_e = 0,
+		.group_f = 0,
+
 		.gpio_g_in =  0x3fff0000,
 		.gpio_g_out = 0x3fff0000,
 		.gpio_b = 0x00
 	},
 	{
 		.ioif = if_gpio_grp_e,
+		.name = "gpio_e",
 		.groups = group_e,
+
+		.group_a = 0,
+		.group_b = 0,
+		.group_c = 0,
+		.group_d = 0,
+		.group_e = 0,
+		.group_f = 0,
+
 		.gpio_g_in =  0x00000000,
 		.gpio_g_out = 0x00000000,
 		.gpio_b = 0x00
 	},
 	{
 		.ioif = if_gpio_grp_f,
+		.name = "gpio_f",
 		.groups = group_f,
+
+		.group_a = 0,
+		.group_b = 0,
+		.group_c = 0,
+		.group_d = 0,
+		.group_e = 0,
+		.group_f = 0,
+
 		.gpio_g_in =  0x00000000,
 		.gpio_g_out = 0x00000000,
 		.gpio_b = 0xff
@@ -284,11 +542,13 @@ static struct interface interfaces[] = {
 
 static struct watcher *watchers = NULL;
 
+/* The pins that are free to use in the GPIO ports. */
 static unsigned int gpio_in_pins =  0xffffffff;
 static unsigned int gpio_out_pins = 0xffffffff;
 static unsigned char gpio_pb_pins = 0xff;
 static unsigned char gpio_pa_pins = 0xff;
 
+/* Identifiers for the owners of the GPIO pins. */
 static enum cris_io_interface gpio_pa_owners[8];
 static enum cris_io_interface gpio_pb_owners[8];
 static enum cris_io_interface gpio_pg_owners[32];
@@ -338,13 +598,15 @@ int cris_request_io_interface(enum cris_io_interface ioif, const char *device_id
 	struct if_group *grp;
 	unsigned char group_set;
 	unsigned long flags;
+	int res = 0;
 
 	(void)cris_io_interface_init();
 
 	DBG(printk("cris_request_io_interface(%d, \"%s\")\n", ioif, device_id));
 
 	if ((ioif >= if_max_interfaces) || (ioif < 0)) {
-		printk(KERN_CRIT "cris_request_io_interface: Bad interface %u submitted for %s\n",
+		printk(KERN_CRIT "cris_request_io_interface: Bad interface "
+			"%u submitted for %s\n",
 		       ioif,
 		       device_id);
 		return -EINVAL;
@@ -353,59 +615,69 @@ int cris_request_io_interface(enum cris_io_interface ioif, const char *device_id
 	local_irq_save(flags);
 
 	if (interfaces[ioif].used) {
-		local_irq_restore(flags);
-		printk(KERN_CRIT "cris_io_interface: Cannot allocate interface for %s, in use by %s\n",
+		printk(KERN_CRIT "cris_io_interface: Cannot allocate interface "
+			"%s for %s, in use by %s\n",
+		       interfaces[ioif].name,
 		       device_id,
 		       interfaces[ioif].owner);
-		return -EBUSY;
+		res = -EBUSY;
+		goto exit;
 	}
 
-	/* Check that all required groups are free before allocating, */
+	/* Check that all required pins in the used groups are free
+	 * before allocating. */
 	group_set = interfaces[ioif].groups;
 	while (NULL != (grp = get_group(group_set))) {
-		if (grp->used) {
-			if (grp->group == group_f) {
-				if ((if_sync_serial_1 ==  ioif) ||
-				    (if_sync_serial_3 ==  ioif)) {
-					if ((grp->owner != if_sync_serial_1) &&
-					    (grp->owner != if_sync_serial_3)) {
-						local_irq_restore(flags);
-						return -EBUSY;
-					}
-				} else if ((if_scsi8_0 == ioif) ||
-					   (if_scsi8_1 == ioif)) {
-					if ((grp->owner != if_scsi8_0) &&
-					    (grp->owner != if_scsi8_1)) {
-						local_irq_restore(flags);
-						return -EBUSY;
-					}
-				}
-			} else {
-				local_irq_restore(flags);
-				return -EBUSY;
-			}
+		unsigned int if_group_use = 0;
+
+		switch (grp->group) {
+		case group_a:
+			if_group_use = interfaces[ioif].group_a;
+			break;
+		case group_b:
+			if_group_use = interfaces[ioif].group_b;
+			break;
+		case group_c:
+			if_group_use = interfaces[ioif].group_c;
+			break;
+		case group_d:
+			if_group_use = interfaces[ioif].group_d;
+			break;
+		case group_e:
+			if_group_use = interfaces[ioif].group_e;
+			break;
+		case group_f:
+			if_group_use = interfaces[ioif].group_f;
+			break;
+		default:
+			BUG_ON(1);
 		}
+
+		if (if_group_use & grp->used) {
+			printk(KERN_INFO "cris_request_io_interface: group "
+				"%s needed by %s not available\n",
+				grp->name, interfaces[ioif].name);
+			res = -EBUSY;
+			goto exit;
+		}
+
 		group_set = clear_group_from_set(group_set, grp);
 	}
 
 	/* Are the required GPIO pins available too? */
-	if (((interfaces[ioif].gpio_g_in & gpio_in_pins) != interfaces[ioif].gpio_g_in) ||
-	    ((interfaces[ioif].gpio_g_out & gpio_out_pins) != interfaces[ioif].gpio_g_out) ||
-	    ((interfaces[ioif].gpio_b & gpio_pb_pins) != interfaces[ioif].gpio_b)) {
-		local_irq_restore(flags);
-		printk(KERN_CRIT "cris_request_io_interface: Could not get required pins for interface %u\n",
-		       ioif);
-		return -EBUSY;
-	}
-
-	/* All needed I/O pins and pin groups are free, allocate. */
-	group_set = interfaces[ioif].groups;
-	while (NULL != (grp = get_group(group_set))) {
-		grp->used = 1;
-		grp->owner = ioif;
-		group_set = clear_group_from_set(group_set, grp);
+	if (((interfaces[ioif].gpio_g_in & gpio_in_pins) !=
+			interfaces[ioif].gpio_g_in) ||
+		((interfaces[ioif].gpio_g_out & gpio_out_pins) !=
+			interfaces[ioif].gpio_g_out) ||
+		((interfaces[ioif].gpio_b & gpio_pb_pins) !=
+			interfaces[ioif].gpio_b)) {
+		printk(KERN_CRIT "cris_request_io_interface: Could not get "
+			"required pins for interface %u\n", ioif);
+		res = -EBUSY;
+		goto exit;
 	}
 
+	/* Check which registers need to be reconfigured. */
 	gens = genconfig_shadow;
 	gens_ii = gen_config_ii_shadow;
 
@@ -495,9 +767,43 @@ int cris_request_io_interface(enum cris_io_interface ioif, const char *device_id
 		set_gen_config = 0;
 		break;
 	default:
-		panic("cris_request_io_interface: Bad interface %u submitted for %s\n",
-		      ioif,
-		      device_id);
+		printk(KERN_INFO "cris_request_io_interface: Bad interface "
+			"%u submitted for %s\n",
+			ioif, device_id);
+		res = -EBUSY;
+		goto exit;
+	}
+
+	/* All needed I/O pins and pin groups are free, allocate. */
+	group_set = interfaces[ioif].groups;
+	while (NULL != (grp = get_group(group_set))) {
+		unsigned int if_group_use = 0;
+
+		switch (grp->group) {
+		case group_a:
+			if_group_use = interfaces[ioif].group_a;
+			break;
+		case group_b:
+			if_group_use = interfaces[ioif].group_b;
+			break;
+		case group_c:
+			if_group_use = interfaces[ioif].group_c;
+			break;
+		case group_d:
+			if_group_use = interfaces[ioif].group_d;
+			break;
+		case group_e:
+			if_group_use = interfaces[ioif].group_e;
+			break;
+		case group_f:
+			if_group_use = interfaces[ioif].group_f;
+			break;
+		default:
+			BUG_ON(1);
+		}
+		grp->used |= if_group_use;
+
+		group_set = clear_group_from_set(group_set, grp);
 	}
 
 	interfaces[ioif].used = 1;
@@ -516,25 +822,28 @@ int cris_request_io_interface(enum cris_io_interface ioif, const char *device_id
 		*R_GEN_CONFIG_II = gen_config_ii_shadow;
 	}
 
-	DBG(printk("GPIO pins: available before: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
-		   gpio_in_pins, gpio_out_pins, gpio_pb_pins));
-	DBG(printk("grabbing pins: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
-		   interfaces[ioif].gpio_g_in,
-		   interfaces[ioif].gpio_g_out,
-		   interfaces[ioif].gpio_b));
+	DBG(printk(KERN_DEBUG "GPIO pins: available before: "
+		"g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
+		gpio_in_pins, gpio_out_pins, gpio_pb_pins));
+	DBG(printk(KERN_DEBUG
+		"grabbing pins: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
+		interfaces[ioif].gpio_g_in,
+		interfaces[ioif].gpio_g_out,
+		interfaces[ioif].gpio_b));
 
 	gpio_in_pins &= ~interfaces[ioif].gpio_g_in;
 	gpio_out_pins &= ~interfaces[ioif].gpio_g_out;
 	gpio_pb_pins &= ~interfaces[ioif].gpio_b;
 
-	DBG(printk("GPIO pins: available after: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
-		   gpio_in_pins, gpio_out_pins, gpio_pb_pins));
+	DBG(printk(KERN_DEBUG "GPIO pins: available after: "
+		"g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
+		gpio_in_pins, gpio_out_pins, gpio_pb_pins));
 
+exit:
 	local_irq_restore(flags);
-
-	notify_watchers();
-
-	return 0;
+	if (res == 0)
+		notify_watchers();
+	return res;
 }
 
 
@@ -560,43 +869,35 @@ void cris_free_io_interface(enum cris_io_interface ioif)
 	}
 	group_set = interfaces[ioif].groups;
 	while (NULL != (grp = get_group(group_set))) {
-		if (grp->group == group_f) {
-			switch (ioif)
-			{
-			case if_sync_serial_1:
-				if ((grp->owner == if_sync_serial_1) &&
-				    interfaces[if_sync_serial_3].used) {
-					grp->owner = if_sync_serial_3;
-				} else
-					grp->used = 0;
-				break;
-			case if_sync_serial_3:
-				if ((grp->owner == if_sync_serial_3) &&
-				    interfaces[if_sync_serial_1].used) {
-					grp->owner = if_sync_serial_1;
-				} else
-					grp->used = 0;
-				break;
-			case if_scsi8_0:
-				if ((grp->owner == if_scsi8_0) &&
-				    interfaces[if_scsi8_1].used) {
-					grp->owner = if_scsi8_1;
-				} else
-					grp->used = 0;
-				break;
-			case if_scsi8_1:
-				if ((grp->owner == if_scsi8_1) &&
-				    interfaces[if_scsi8_0].used) {
-					grp->owner = if_scsi8_0;
-				} else
-					grp->used = 0;
-				break;
-			default:
-				grp->used = 0;
-			}
-		} else {
-			grp->used = 0;
+		unsigned int if_group_use = 0;
+
+		switch (grp->group) {
+		case group_a:
+			if_group_use = interfaces[ioif].group_a;
+			break;
+		case group_b:
+			if_group_use = interfaces[ioif].group_b;
+			break;
+		case group_c:
+			if_group_use = interfaces[ioif].group_c;
+			break;
+		case group_d:
+			if_group_use = interfaces[ioif].group_d;
+			break;
+		case group_e:
+			if_group_use = interfaces[ioif].group_e;
+			break;
+		case group_f:
+			if_group_use = interfaces[ioif].group_f;
+			break;
+		default:
+			BUG_ON(1);
 		}
+
+		if ((grp->used & if_group_use) != if_group_use)
+			BUG_ON(1);
+		grp->used = grp->used & ~if_group_use;
+
 		group_set = clear_group_from_set(group_set, grp);
 	}
 	interfaces[ioif].used = 0;
diff --git a/arch/cris/arch-v10/kernel/irq.c b/arch/cris/arch-v10/kernel/irq.c
index e06ab0050d37..65ed803dae6f 100644
--- a/arch/cris/arch-v10/kernel/irq.c
+++ b/arch/cris/arch-v10/kernel/irq.c
@@ -1,5 +1,4 @@
-/* $Id: irq.c,v 1.4 2005/01/04 12:22:28 starvik Exp $
- *
+/*
  *	linux/arch/cris/kernel/irq.c
  *
  *      Copyright (c) 2000-2002 Axis Communications AB
@@ -18,10 +17,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 
-/* From kgdb.c. */
-extern void kgdb_init(void);
-extern void breakpoint(void);
-
 #define mask_irq(irq_nr) (*R_VECT_MASK_CLR = 1 << (irq_nr));
 #define unmask_irq(irq_nr) (*R_VECT_MASK_SET = 1 << (irq_nr));
 
diff --git a/arch/cris/arch-v10/kernel/kgdb.c b/arch/cris/arch-v10/kernel/kgdb.c
index 77f4b1423725..a3ca55150745 100644
--- a/arch/cris/arch-v10/kernel/kgdb.c
+++ b/arch/cris/arch-v10/kernel/kgdb.c
@@ -17,66 +17,8 @@
 *! 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.6  2005/01/14 10:12:17  starvik
-*! KGDB on separate port.
-*! Console fixes from 2.4.
-*!
-*! 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 preferred 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.6 2005/01/14 10:12:17 starvik Exp $
-*!
 *! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN
 *!
 *!**************************************************************************/
diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c
index 1a3760c94f85..53117f07cc1a 100644
--- a/arch/cris/arch-v10/kernel/process.c
+++ b/arch/cris/arch-v10/kernel/process.c
@@ -1,5 +1,4 @@
-/* $Id: process.c,v 1.12 2004/12/27 11:18:32 starvik Exp $
- * 
+/*
  *  linux/arch/cris/kernel/process.c
  *
  *  Copyright (C) 1995  Linus Torvalds
diff --git a/arch/cris/arch-v10/kernel/ptrace.c b/arch/cris/arch-v10/kernel/ptrace.c
index b570ae9b6cad..ee505b2eb4db 100644
--- a/arch/cris/arch-v10/kernel/ptrace.c
+++ b/arch/cris/arch-v10/kernel/ptrace.c
@@ -65,6 +65,7 @@ void
 ptrace_disable(struct task_struct *child)
 {
        /* Todo - pending singlesteps? */
+       clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 }
 
 /* 
diff --git a/arch/cris/arch-v10/kernel/shadows.c b/arch/cris/arch-v10/kernel/shadows.c
index 326178aef6ee..2454a0b02f54 100644
--- a/arch/cris/arch-v10/kernel/shadows.c
+++ b/arch/cris/arch-v10/kernel/shadows.c
@@ -1,5 +1,4 @@
-/* $Id: shadows.c,v 1.2 2004/12/13 12:21:51 starvik Exp $
- * 
+/*
  * Various shadow registers. Defines for these are in include/asm-etrax100/io.h
  */
 
diff --git a/arch/cris/arch-v10/kernel/traps.c b/arch/cris/arch-v10/kernel/traps.c
index 4becc1bcced9..9eada5d8893b 100644
--- a/arch/cris/arch-v10/kernel/traps.c
+++ b/arch/cris/arch-v10/kernel/traps.c
@@ -1,13 +1,10 @@
-/* $Id: traps.c,v 1.4 2005/04/24 18:47:55 starvik Exp $
+/*
+ * Helper functions for trap handlers
  *
- *  linux/arch/cris/arch-v10/traps.c
+ * Copyright (C) 2000-2007, Axis Communications AB.
  *
- *  Heler functions for trap handlers
- * 
- *  Copyright (C) 2000-2002 Axis Communications AB
- *
- *  Authors:   Bjorn Wesen
- *  	       Hans-Peter Nilsson
+ * Authors:   Bjorn Wesen
+ *            Hans-Peter Nilsson
  *
  */
 
@@ -15,124 +12,119 @@
 #include <asm/uaccess.h>
 #include <asm/arch/sv_addr_ag.h>
 
-extern int raw_printk(const char *fmt, ...);
-
-void 
-show_registers(struct pt_regs * regs)
+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.  */
+	/*
+	 * It's possible to use either the USP register or current->thread.usp.
+	 * USP might not correspond to the current process for all cases this
+	 * function is called, and current->thread.usp isn't up to date for the
+	 * current process. Experience shows that using USP is the way to go.
+	 */
 	unsigned long usp = rdusp();
 
-	raw_printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n",
-	       regs->irp, regs->srp, regs->dccr, usp, regs->mof );
-	raw_printk(" r0: %08lx  r1: %08lx   r2: %08lx  r3: %08lx\n",
+	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);
-	raw_printk(" r4: %08lx  r5: %08lx   r6: %08lx  r7: %08lx\n",
+
+	printk(" r4: %08lx  r5: %08lx   r6: %08lx  r7: %08lx\n",
 	       regs->r4, regs->r5, regs->r6, regs->r7);
-	raw_printk(" r8: %08lx  r9: %08lx  r10: %08lx r11: %08lx\n",
+
+	printk(" r8: %08lx  r9: %08lx  r10: %08lx r11: %08lx\n",
 	       regs->r8, regs->r9, regs->r10, regs->r11);
-	raw_printk("r12: %08lx r13: %08lx oR10: %08lx  sp: %08lx\n",
-	       regs->r12, regs->r13, regs->orig_r10, regs);
-	raw_printk("R_MMU_CAUSE: %08lx\n", (unsigned long)*R_MMU_CAUSE);
-	raw_printk("Process %s (pid: %d, stackpage=%08lx)\n",
+
+	printk("r12: %08lx r13: %08lx oR10: %08lx  sp: %08lx\n",
+	       regs->r12, regs->r13, regs->orig_r10, (long unsigned)regs);
+
+	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;
+	 * 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);
+		show_stack(NULL, (unsigned long *)usp);
 
-		/* Dump kernel stack if the previous dump wasn't one.  */
+		/*
+		 * If the previous stack-dump wasn't a kernel one, dump the
+		 * kernel stack now.
+		 */
 		if (usp != 0)
-			show_stack (NULL, NULL);
-
-                raw_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:
-                                raw_printk(" Bad IP value.");
-                                break;
-                        }
+			show_stack(NULL, NULL);
+
+		printk("\nCode: ");
+
+		if (regs->irp < PAGE_OFFSET)
+			goto bad_value;
+
+		/*
+		 * Quite often the value at regs->irp doesn't point to the
+		 * interesting instruction, which often is the previous
+		 * instruction. So dump at an offset large enough that the
+		 * instruction decoding should be in sync at the interesting
+		 * point, but small enough to fit on a row. The regs->irp
+		 * location is pointed out in a ksymoops-friendly way by
+		 * wrapping the byte for that address in parenthesises.
+		 */
+		for (i = -12; i < 12; i++) {
+			unsigned char c;
+
+			if (__get_user(c, &((unsigned char *)regs->irp)[i])) {
+bad_value:
+				printk(" Bad IP value.");
+				break;
+			}
 
 			if (i == 0)
-			  raw_printk("(%02x) ", c);
+				printk("(%02x) ", c);
 			else
-			  raw_printk("%02x ", c);
-                }
-		raw_printk("\n");
-        }
+				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)
+arch_enable_nmi(void)
 {
-#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
-	local_irq_disable();
-	stop_watchdog();
-	show_registers(regs);
-	while(1) /* nothing */;
-#else
-	show_registers(regs);
-#endif	
+	asm volatile ("setf m");
 }
 
-/* This is normally the 'Oops' routine */
-void 
-die_if_kernel(const char * str, struct pt_regs * regs, long err)
+extern void (*nmi_handler)(struct pt_regs *);
+void handle_nmi(struct pt_regs *regs)
 {
-	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
-
-	raw_printk("%s: %04lx\n", str, err & 0xffff);
-
-	show_registers(regs);
-
-#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
-	reset_watchdog();
-#endif
-	do_exit(SIGSEGV);
+	if (nmi_handler)
+		nmi_handler(regs);
+
+	/* Wait until nmi is no longer active. (We enable NMI immediately after
+	   returning from this function, and we don't want it happening while
+	   exiting from the NMI interrupt handler.) */
+	while (*R_IRQ_MASK0_RD & IO_STATE(R_IRQ_MASK0_RD, nmi_pin, active))
+		;
 }
 
-void arch_enable_nmi(void)
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+void
+handle_BUG(struct pt_regs *regs)
 {
-  asm volatile("setf m");
+	struct bug_frame f;
+	unsigned char c;
+	unsigned long irp = regs->irp;
+
+	if (__copy_from_user(&f, (const void __user *)(irp - 8), sizeof f))
+		return;
+	if (f.prefix != BUG_PREFIX || f.magic != BUG_MAGIC)
+		return;
+	if (__get_user(c, f.filename))
+		f.filename = "<bad filename>";
+
+	printk("kernel BUG at %s:%d!\n", f.filename, f.line);
 }
+#endif
diff --git a/arch/cris/arch-v10/lib/checksum.S b/arch/cris/arch-v10/lib/checksum.S
index 85c48f0a9ec2..7d552f4bd5ae 100644
--- a/arch/cris/arch-v10/lib/checksum.S
+++ b/arch/cris/arch-v10/lib/checksum.S
@@ -1,4 +1,4 @@
-/* $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
  *
@@ -61,8 +61,6 @@ _mloop:	movem	[$r10+],$r9	; read 10 longwords
 	
 	ax
 	addq	0,$r12
-	ax			; do it again, since we might have generated a carry
-	addq	0,$r12
 
 	subq	10*4,$r11
 	bge	_mloop
@@ -88,10 +86,6 @@ _word_loop:
 	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
diff --git a/arch/cris/arch-v10/lib/checksumcopy.S b/arch/cris/arch-v10/lib/checksumcopy.S
index 35cbffb306fd..540db8a5f849 100644
--- a/arch/cris/arch-v10/lib/checksumcopy.S
+++ b/arch/cris/arch-v10/lib/checksumcopy.S
@@ -1,4 +1,4 @@
-/* $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
  *
@@ -67,8 +67,6 @@ _mloop:	movem	[$r10+],$r9	; read 10 longwords
 	
 	ax
 	addq	0,$r13
-	ax			; do it again, since we might have generated a carry
-	addq	0,$r13
 
 	subq	10*4,$r12
 	bge	_mloop
@@ -91,10 +89,6 @@ _word_loop:
 	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
diff --git a/arch/cris/arch-v10/lib/dram_init.S b/arch/cris/arch-v10/lib/dram_init.S
index 6a6bdfd6984d..b9190ff7d0a4 100644
--- a/arch/cris/arch-v10/lib/dram_init.S
+++ b/arch/cris/arch-v10/lib/dram_init.S
@@ -1,5 +1,4 @@
-/* $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
  *
@@ -8,60 +7,7 @@
  *
  * 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 explicitly 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.
+ * Authors:  Mikael Starvik (starvik@axis.com)
  *
  */
 
diff --git a/arch/cris/arch-v10/lib/old_checksum.c b/arch/cris/arch-v10/lib/old_checksum.c
index 497634a64829..1734b467efa6 100644
--- a/arch/cris/arch-v10/lib/old_checksum.c
+++ b/arch/cris/arch-v10/lib/old_checksum.c
@@ -1,5 +1,4 @@
-/* $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.
diff --git a/arch/cris/arch-v10/mm/fault.c b/arch/cris/arch-v10/mm/fault.c
index fe2615022b97..65504fd80928 100644
--- a/arch/cris/arch-v10/mm/fault.c
+++ b/arch/cris/arch-v10/mm/fault.c
@@ -4,10 +4,10 @@
  *  Low level bus fault handler
  *
  *
- *  Copyright (C) 2000, 2001  Axis Communications AB
+ *  Copyright (C) 2000-2007  Axis Communications AB
+ *
+ *  Authors:  Bjorn Wesen
  *
- *  Authors:  Bjorn Wesen 
- * 
  */
 
 #include <linux/mm.h>
@@ -60,7 +60,7 @@ handle_mmu_bus_fault(struct pt_regs *regs)
 #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);  
+	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);
@@ -84,12 +84,13 @@ handle_mmu_bus_fault(struct pt_regs *regs)
 	local_irq_disable();
 	pmd = (pmd_t *)(pgd + pgd_index(address));
 	if (pmd_none(*pmd))
-		return;
+		goto exit;
 	pte = *pte_offset_kernel(pmd, address);
 	if (!pte_present(pte))
-		return;
+		goto exit;
 	*R_TLB_SELECT = select;
 	*R_TLB_HI = cause;
 	*R_TLB_LO = pte_val(pte);
+exit:
 	local_irq_restore(flags);
 }
diff --git a/arch/cris/arch-v10/mm/tlb.c b/arch/cris/arch-v10/mm/tlb.c
index 7d9fec88dee5..6baf5bd209e7 100644
--- a/arch/cris/arch-v10/mm/tlb.c
+++ b/arch/cris/arch-v10/mm/tlb.c
@@ -4,8 +4,8 @@
  *  Low level TLB handling
  *
  *
- *  Copyright (C) 2000-2002  Axis Communications AB
- *  
+ *  Copyright (C) 2000-2007  Axis Communications AB
+ *
  *  Authors:   Bjorn Wesen (bjornw@axis.com)
  *
  */
@@ -39,7 +39,7 @@ flush_tlb_all(void)
 	unsigned long flags;
 
 	/* the vpn of i & 0xf is so we dont write similar TLB entries
-	 * in the same 4-way entry group. details.. 
+	 * in the same 4-way entry group. details...
 	 */
 
 	local_irq_save(flags);
@@ -47,7 +47,7 @@ flush_tlb_all(void)
 		*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	 ) |
@@ -71,10 +71,10 @@ flush_tlb_mm(struct mm_struct *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 ? 
+	 * global pages. is it worth the extra I/O ?
 	 */
 
 	local_irq_save(flags);
@@ -83,7 +83,7 @@ flush_tlb_mm(struct mm_struct *mm)
 		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  ) |
@@ -96,9 +96,7 @@ flush_tlb_mm(struct mm_struct *mm)
 
 /* invalidate a single page */
 
-void
-flush_tlb_page(struct vm_area_struct *vma, 
-	       unsigned long addr)
+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;
@@ -113,7 +111,7 @@ flush_tlb_page(struct vm_area_struct *vma,
 	addr &= PAGE_MASK; /* perhaps not necessary */
 
 	/* invalidate those TLB entries that match both the mm context
-	 * and the virtual address requested 
+	 * and the virtual address requested
 	 */
 
 	local_irq_save(flags);
@@ -125,7 +123,7 @@ flush_tlb_page(struct vm_area_struct *vma,
 		    (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  ) |
@@ -144,7 +142,7 @@ 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);
@@ -172,27 +170,29 @@ init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 
 /* 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)
+void switch_mm(struct mm_struct *prev, struct mm_struct *next,
+	struct task_struct *tsk)
 {
-	/* make sure we have a context */
+	if (prev != next) {
+		/* make sure we have a context */
+		get_mmu_context(next);
 
-	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.
+		 */
 
-	/* 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.
-	 */
+		per_cpu(current_pgd, smp_processor_id()) = next->pgd;
 
-	per_cpu(current_pgd, smp_processor_id()) = next->pgd;
+		/* switch context in the MMU */
 
-	/* switch context in the MMU */
-	
-	D(printk("switching mmu_context to %d (%p)\n", next->context, next));
+		D(printk(KERN_DEBUG "switching mmu_context to %d (%p)\n",
+			next->context, next));
 
-	*R_MMU_CONTEXT = IO_FIELD(R_MMU_CONTEXT, page_id, next->context.page_id);
+		*R_MMU_CONTEXT = IO_FIELD(R_MMU_CONTEXT,
+					  page_id, next->context.page_id);
+	}
 }
 
diff --git a/arch/cris/arch-v32/Kconfig b/arch/cris/arch-v32/Kconfig
index d8acaa920e1c..005ed2b3f7f4 100644
--- a/arch/cris/arch-v32/Kconfig
+++ b/arch/cris/arch-v32/Kconfig
@@ -1,27 +1,73 @@
 if ETRAX_ARCH_V32
 
+source arch/cris/arch-v32/mach-fs/Kconfig
+source arch/cris/arch-v32/mach-a3/Kconfig
+
+source drivers/cpufreq/Kconfig
+
 config ETRAX_DRAM_VIRTUAL_BASE
 	hex
 	depends on ETRAX_ARCH_V32
 	default "c0000000"
 
-config ETRAX_LED1G
-	string "First green LED bit"
+choice
+	prompt "Nbr of Ethernet LED groups"
 	depends on ETRAX_ARCH_V32
+	default ETRAX_NBR_LED_GRP_ONE
+	help
+	  Select how many Ethernet LED groups that can be used. Usually one per Ethernet
+	  interface is a good choice.
+
+config	ETRAX_NBR_LED_GRP_ZERO
+	bool "Use zero LED groups"
+	help
+	  Select this if you do not want any Ethernet LEDs.
+
+config	ETRAX_NBR_LED_GRP_ONE
+	bool "Use one LED group"
+	help
+	  Select this if you want one Ethernet LED group. This LED group
+	  can be used for one or more Ethernet interfaces. However, it is
+	  recomended that each Ethernet interface use a dedicated LED group.
+
+config	ETRAX_NBR_LED_GRP_TWO
+	bool "Use two LED groups"
+	help
+	  Select this if you want two Ethernet LED groups. This is the
+	  best choice if you have more than one Ethernet interface and
+	  would like to have separate LEDs for the interfaces.
+
+endchoice
+
+config ETRAX_LED_G_NET0
+	string "Ethernet LED group 0 green LED bit"
+	depends on ETRAX_ARCH_V32 && (ETRAX_NBR_LED_GRP_ONE || ETRAX_NBR_LED_GRP_TWO)
 	default "PA3"
 	help
-	  Bit to use for the first green LED (network LED).
-	  Most Axis products use bit A3 here.
+	  Bit to use for the green LED in Ethernet LED group 0.
 
-config ETRAX_LED1R
-	string "First red LED bit"
-	depends on ETRAX_ARCH_V32
+config ETRAX_LED_R_NET0
+	string "Ethernet LED group 0 red LED bit"
+	depends on ETRAX_ARCH_V32 && (ETRAX_NBR_LED_GRP_ONE || ETRAX_NBR_LED_GRP_TWO)
 	default "PA4"
 	help
-	  Bit to use for the first red LED (network LED).
-	  Most Axis products use bit A4 here.
+	  Bit to use for the red LED in Ethernet LED group 0.
 
-config ETRAX_LED2G
+config ETRAX_LED_G_NET1
+	string "Ethernet group 1 green LED bit"
+	depends on ETRAX_ARCH_V32 && ETRAX_NBR_LED_GRP_TWO
+	default ""
+	help
+	  Bit to use for the green LED in Ethernet LED group 1.
+
+config ETRAX_LED_R_NET1
+	string "Ethernet group 1 red LED bit"
+	depends on ETRAX_ARCH_V32 && ETRAX_NBR_LED_GRP_TWO
+	default ""
+	help
+	  Bit to use for the red LED in Ethernet LED group 1.
+
+config ETRAX_V32_LED2G
 	string "Second green LED bit"
 	depends on ETRAX_ARCH_V32
 	default "PA5"
@@ -29,7 +75,7 @@ config ETRAX_LED2G
 	  Bit to use for the first green LED (status LED).
 	  Most Axis products use bit A5 here.
 
-config ETRAX_LED2R
+config ETRAX_V32_LED2R
 	string "Second red LED bit"
 	depends on ETRAX_ARCH_V32
 	default "PA6"
@@ -37,7 +83,7 @@ config ETRAX_LED2R
 	  Bit to use for the first red LED (network LED).
 	  Most Axis products use bit A6 here.
 
-config ETRAX_LED3G
+config ETRAX_V32_LED3G
 	string "Third green LED bit"
 	depends on ETRAX_ARCH_V32
 	default "PA7"
@@ -45,7 +91,7 @@ config ETRAX_LED3G
 	  Bit to use for the first green LED (drive/power LED).
 	  Most Axis products use bit A7 here.
 
-config ETRAX_LED3R
+config ETRAX_V32_LED3R
 	string "Third red LED bit"
 	depends on ETRAX_ARCH_V32
 	default "PA7"
@@ -54,39 +100,6 @@ config ETRAX_LED3R
 	  Most Axis products use bit A7 here.
 
 choice
-	prompt "Product debug-port"
-	depends on ETRAX_ARCH_V32
-	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 "Kernel GDB port"
 	depends on ETRAX_KGDB
 	default ETRAX_KGDB_PORT0
@@ -95,25 +108,11 @@ choice
 	  not be enabled under Drivers for built-in interfaces (as it has its
 	  own initialization code) and should not be the same as the debug port.
 
-config ETRAX_KGDB_PORT0
-	bool "Serial-0"
-	help
-	  Use serial port 0 for kernel debugging.
-
-config ETRAX_KGDB_PORT1
-	bool "Serial-1"
-	help
-	  Use serial port 1 for kernel debugging.
-
-config ETRAX_KGDB_PORT2
-	bool "Serial-2"
-	help
-	  Use serial port 2 for kernel debugging.
-
-config ETRAX_KGDB_PORT3
-	bool "Serial-3"
+config ETRAX_KGDB_PORT4
+	bool "Serial-4"
+	depends on ETRAX_SERIAL_PORTS = 5
 	help
-	  Use serial port 3 for kernel debugging.
+	  Use serial port 4 for kernel debugging.
 
 endchoice
 
diff --git a/arch/cris/arch-v32/boot/Makefile b/arch/cris/arch-v32/boot/Makefile
index 26f293ab9617..3f91349c5f12 100644
--- a/arch/cris/arch-v32/boot/Makefile
+++ b/arch/cris/arch-v32/boot/Makefile
@@ -1,14 +1,21 @@
 #
 # arch/cris/arch-v32/boot/Makefile
 #
-target = $(target_boot_dir)
-src    = $(src_boot_dir)
 
-zImage: compressed/vmlinuz
+OBJCOPY = objcopy-cris
+OBJCOPYFLAGS = -O binary -R .note -R .comment
 
-compressed/vmlinuz: $(objtree)/vmlinux
-	@$(MAKE) -f $(src)/compressed/Makefile $(objtree)/vmlinuz
+subdir- := compressed rescue
+targets := Image
 
-clean:
-	rm -f zImage tools/build compressed/vmlinux.out
-	@$(MAKE) -f $(src)/compressed/Makefile clean
+$(obj)/Image: vmlinux FORCE
+	$(call if_changed,objcopy)
+	@echo '  Kernel: $@ is ready'
+
+$(obj)/compressed/vmlinux: $(obj)/Image FORCE
+	$(Q)$(MAKE) $(build)=$(obj)/compressed $@
+	$(Q)$(MAKE) $(build)=$(obj)/rescue $(obj)/rescue/rescue.bin
+
+$(obj)/zImage:  $(obj)/compressed/vmlinux
+	@cp $< $@
+	@echo '  Kernel: $@ is ready'
diff --git a/arch/cris/arch-v32/boot/compressed/Makefile b/arch/cris/arch-v32/boot/compressed/Makefile
index 609692f9d5eb..2c8c2c3039c5 100644
--- a/arch/cris/arch-v32/boot/compressed/Makefile
+++ b/arch/cris/arch-v32/boot/compressed/Makefile
@@ -1,41 +1,30 @@
 #
-# lx25/arch/cris/arch-v32/boot/compressed/Makefile
+# arch/cris/arch-v32/boot/compressed/Makefile
 #
-# create a compressed vmlinux image from the original vmlinux files and romfs
-#
-
-target = $(target_compressed_dir)
-src    = $(src_compressed_dir)
 
 CC = gcc-cris -mlinux -march=v32 $(LINUXINCLUDE)
-CFLAGS = -O2
+asflags-y += -I $(srctree)/include/asm/mach/ -I $(srctree)/include/asm/arch
+ccflags-y += -O2 -I $(srctree)/include/asm/mach/ -I $(srctree)/include/asm/arch
 LD = gcc-cris -mlinux -march=v32 -nostdlib
+ldflags-y += -T $(obj)/decompress.ld
+obj-y = head.o misc.o
+OBJECTS = $(obj)/head.o $(obj)/misc.o
 OBJCOPY = objcopy-cris
 OBJCOPYFLAGS = -O binary --remove-section=.bss
-OBJECTS = $(target)/head.o $(target)/misc.o
-
-# files to compress
-SYSTEM = $(objtree)/vmlinux.bin
-
-all: vmlinuz
-
-$(target)/decompress.bin: $(OBJECTS)
-	$(LD) -T $(src)/decompress.ld -o $(target)/decompress.o $(OBJECTS)
-	$(OBJCOPY) $(OBJCOPYFLAGS) $(target)/decompress.o $(target)/decompress.bin
 
-$(objtree)/vmlinuz: $(target) piggy.img $(target)/decompress.bin
-	cat $(target)/decompress.bin piggy.img > $(objtree)/vmlinuz
-	rm -f piggy.img
-	cp $(objtree)/vmlinuz $(src)
+quiet_cmd_image = BUILD   $@
+cmd_image = cat $(obj)/decompress.bin $(obj)/piggy.gz > $@
 
-$(target)/head.o: $(src)/head.S
-	$(CC) -D__ASSEMBLY__ -c $< -o $@
+targets := vmlinux piggy.gz decompress.o decompress.bin
 
-# gzip the kernel image
+$(obj)/decompress.o: $(OBJECTS) FORCE
+	$(call if_changed,ld)
 
-piggy.img: $(SYSTEM)
-	cat $(SYSTEM) | gzip -f -9 > piggy.img
+$(obj)/decompress.bin: $(obj)/decompress.o FORCE
+	$(call if_changed,objcopy)
 
-clean:
-	rm -f piggy.img $(objtree)/vmlinuz vmlinuz.o decompress.o decompress.bin $(OBJECTS)
+$(obj)/vmlinux: $(obj)/piggy.gz $(obj)/decompress.bin FORCE
+	$(call if_changed,image)
 
+$(obj)/piggy.gz: $(obj)/../Image FORCE
+	$(call if_changed,gzip)
diff --git a/arch/cris/arch-v32/boot/compressed/README b/arch/cris/arch-v32/boot/compressed/README
index e33691d15c57..182c5d75784b 100644
--- a/arch/cris/arch-v32/boot/compressed/README
+++ b/arch/cris/arch-v32/boot/compressed/README
@@ -1,6 +1,5 @@
 Creation of the self-extracting compressed kernel image (vmlinuz)
 -----------------------------------------------------------------
-$Id: README,v 1.1 2003/08/21 09:37:03 johana Exp $
 
 This can be slightly confusing because it's a process with many steps.
 
diff --git a/arch/cris/arch-v32/boot/compressed/head.S b/arch/cris/arch-v32/boot/compressed/head.S
index 34cea10a8998..f86208caf32d 100644
--- a/arch/cris/arch-v32/boot/compressed/head.S
+++ b/arch/cris/arch-v32/boot/compressed/head.S
@@ -2,13 +2,12 @@
  *  Code that sets up the DRAM registers, calls the
  *  decompressor to unpack the piggybacked kernel, and jumps.
  *
- *  Copyright (C) 1999 - 2003, Axis Communications AB
+ *  Copyright (C) 1999 - 2006, Axis Communications AB
  */
 
 #define ASSEMBLER_MACROS_ONLY
-#include <asm/arch/hwregs/asm/reg_map_asm.h>
-#include <asm/arch/hwregs/asm/gio_defs_asm.h>
-#include <asm/arch/hwregs/asm/config_defs_asm.h>
+#include <hwregs/asm/reg_map_asm.h>
+#include <asm/arch/mach/startup.inc>
 
 #define RAM_INIT_MAGIC 0x56902387
 #define COMMAND_LINE_MAGIC 0x87109563
@@ -22,114 +21,49 @@ start:
 	di
 
 	;; Start clocks for used blocks.
-	move.d REG_ADDR(config, regi_config, rw_clk_ctrl), $r1
-	move.d [$r1], $r0
-	or.d   REG_STATE(config, rw_clk_ctrl, cpu, yes) | \
-	       REG_STATE(config, rw_clk_ctrl, bif, yes) | \
-	       REG_STATE(config, rw_clk_ctrl, fix_io, yes), $r0
-	move.d $r0, [$r1]
-
-	;; If booting from NAND flash we first have to copy some
-	;; data from NAND flash to internal RAM to get the code
-	;; that initializes the SDRAM. Lets copy 20 KB. This
-	;; code executes at 0x38010000 if booting from NAND and
-	;; we are guaranted that at least 0x200 bytes are good so
-	;; lets start from there. The first 8192 bytes in the nand
-	;; flash is spliced with zeroes and is thus 16384 bytes.
-	move.d 0x38010200, $r10
-	move.d 0x14200, $r11	; Start offset in NAND flash 0x10200 + 16384
-	move.d 0x5000, $r12	; Length of copy
-
-	;; Before this code the tools add a partitiontable so the PC
-	;; has an offset from the linked address.
-offset1:
-	lapcq  ., $r13		; get PC
-	add.d	first_copy_complete-offset1, $r13
-
-#include "../../lib/nand_init.S"
-
-first_copy_complete:
-	;; Initialze the DRAM registers.
+	START_CLOCKS
+
+	;; Initialize the DRAM registers.
 	cmp.d	RAM_INIT_MAGIC, $r8	; Already initialized?
 	beq	dram_init_finished
 	nop
 
-#include "../../lib/dram_init.S"
+#include "../../mach/dram_init.S"
 
 dram_init_finished:
-	lapcq  ., $r13		; get PC
-	add.d	second_copy_complete-dram_init_finished, $r13
-
-	move.d REG_ADDR(config, regi_config, r_bootsel), $r0
-	move.d [$r0], $r0
-	and.d  REG_MASK(config, r_bootsel, boot_mode), $r0
-	cmp.d  REG_STATE(config, r_bootsel, boot_mode, nand), $r0
-	bne second_copy_complete ; No NAND boot
-	nop
-
-	;; Copy 2MB from NAND flash to SDRAM (at 2-4MB into the SDRAM)
-	move.d 0x40204000, $r10
-	move.d 0x8000, $r11
-	move.d 0x200000, $r12
-	ba copy_nand_to_ram
-	nop
-second_copy_complete:
-
-	;; Initiate the PA port.
-	move.d	CONFIG_ETRAX_DEF_GIO_PA_OUT, $r0
-	move.d	REG_ADDR(gio, regi_gio, rw_pa_dout), $r1
-	move.d	$r0, [$r1]
-
-	move.d	CONFIG_ETRAX_DEF_GIO_PA_OE, $r0
-	move.d	REG_ADDR(gio, regi_gio, rw_pa_oe), $r1
-	move.d	$r0, [$r1]
 
+	GIO_INIT
 	;; Setup the stack to a suitably high address.
 	;; We assume 8 MB is the minimum DRAM 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.
+	;; Figure out where the compressed piggyback image is.
+	;; It is either in [NOR] flash (we don't want to copy it
+	;; to DRAM before unpacking), or copied to DRAM
+	;; by the [NAND] flash boot loader.
+	;; The piggyback image is at _edata, but relative to where the
+	;; image is actually located in memory, not where it is linked
+	;; (the decompressor is linked at 0x40700000+ and runs there).
 	;; Use (_edata - herami) as offset to the current PC.
 
-	move.d REG_ADDR(config, regi_config, r_bootsel), $r0
-	move.d [$r0], $r0
-	and.d  REG_MASK(config, r_bootsel, boot_mode), $r0
-	cmp.d  REG_STATE(config, r_bootsel, boot_mode, nand), $r0
-	beq hereami2
-	nop
 hereami:
 	lapcq	., $r5		; get PC
 	and.d	0x7fffffff, $r5	; strip any non-cache bit
-	move.d	$r5, $r0	; save for later - flash address of 'herami'
+	move.d	$r5, $r0	; source address of 'herami'
 	add.d	_edata, $r5
 	sub.d	hereami, $r5	; r5 = flash address of '_edata'
 	move.d	hereami, $r1	; destination
-	ba 2f
-	nop
-hereami2:
-	lapcq	., $r5		; get PC
-	and.d	0x00ffffff, $r5	; strip any non-cache bit
-	move.d  $r5, $r6
-	or.d    0x40200000, $r6
-	move.d	$r6, $r0	; save for later - flash address of 'herami'
-	add.d	_edata, $r5
-	sub.d	hereami2, $r5	; r5 = flash address of '_edata'
-	add.d   0x40200000, $r5
-	move.d	hereami2, $r1	; destination
-2:
+
 	;; Copy text+data to DRAM
 
 	move.d	_edata, $r2	; end destination
-1:	move.w	[$r0+], $r3
-	move.w	$r3, [$r1+]
-	cmp.d	$r2, $r1
+1:	move.w	[$r0+], $r3	; from herami+ source
+	move.w	$r3, [$r1+]	; to hereami+ destination (linked address)
+	cmp.d	$r2, $r1	; finish when destination == _edata
 	bcs	1b
 	nop
-
 	move.d	input_data, $r0 ; for the decompressor
 	move.d	$r5, [$r0]	; for the decompressor
 
@@ -144,16 +78,24 @@ hereami2:
 	nop
 
 	;;  Save command line magic and address.
-	move.d	_cmd_line_magic, $r12
-	move.d  $r10, [$r12]
-	move.d	_cmd_line_addr, $r12
-	move.d  $r11, [$r12]
+	move.d	_cmd_line_magic, $r0
+	move.d  $r10, [$r0]
+	move.d	_cmd_line_addr, $r0
+	move.d  $r11, [$r0]
+
+	;;  Save boot source indicator
+	move.d	_boot_source, $r0
+	move.d	$r12, [$r0]
 
 	;; Do the decompression and save compressed size in _inptr
 
 	jsr	decompress_kernel
 	nop
 
+	;; Restore boot source indicator
+	move.d	_boot_source, $r12
+	move.d	[$r12], $r12
+
 	;; Restore command line magic and address.
 	move.d  _cmd_line_magic, $r10
 	move.d  [$r10], $r10
@@ -166,11 +108,10 @@ hereami2:
 	move.d	[$r0], $r9		; flash address of compressed kernel
 	move.d  inptr, $r0
 	add.d	[$r0], $r9		; size of compressed kernel
-	cmp.d   0x40200000, $r9
-	blo	enter_kernel
-	nop
-	sub.d   0x40200000, $r9
-	add.d   0x4000, $r9
+	cmp.d   0x40000000, $r9		; image in DRAM ?
+	blo	enter_kernel		; no, must be [NOR] flash, jump
+	nop				; delay slot
+	and.d   0x001fffff, $r9		; assume compressed kernel was < 2M
 
 enter_kernel:
 	;; Enter the decompressed kernel
@@ -186,7 +127,7 @@ _cmd_line_magic:
 	.dword 0
 _cmd_line_addr:
 	.dword 0
-is_nand_boot:
-	.dword  0
+_boot_source:
+	.dword 0
 
-#include "../../lib/hw_settings.S"
+#include "../../mach/hw_settings.S"
diff --git a/arch/cris/arch-v32/boot/compressed/misc.c b/arch/cris/arch-v32/boot/compressed/misc.c
index 0169ba1ca9c9..55b2695c5d70 100644
--- a/arch/cris/arch-v32/boot/compressed/misc.c
+++ b/arch/cris/arch-v32/boot/compressed/misc.c
@@ -1,8 +1,6 @@
 /*
  * misc.c
  *
- * $Id: misc.c,v 1.8 2005/04/24 18:34:29 starvik Exp $
- *
  * This is a collection of several routines from gzip-1.0.3
  * adapted for Linux.
  *
@@ -22,9 +20,13 @@
 
 
 #include <linux/types.h>
-#include <asm/arch/hwregs/reg_rdwr.h>
-#include <asm/arch/hwregs/reg_map.h>
-#include <asm/arch/hwregs/ser_defs.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/reg_map.h>
+#include <hwregs/ser_defs.h>
+#include <hwregs/pinmux_defs.h>
+#ifdef CONFIG_CRIS_MACH_ARTPEC3
+#include <hwregs/clkgen_defs.h>
+#endif
 
 /*
  * gzip declarations
@@ -85,7 +87,6 @@ static unsigned outcnt = 0;  /* bytes in output buffer */
 #  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 **);
@@ -186,6 +187,8 @@ memset(void* s, int c, size_t n)
 	char *ss = (char*)s;
 
 	for (i=0;i<n;i++) ss[i] = c;
+
+	return s;
 }
 
 void*
@@ -196,6 +199,8 @@ memcpy(void* __dest, __const void* __src,
 	char *d = (char *)__dest, *s = (char *)__src;
 
 	for (i=0;i<__n;i++) d[i] = s[i];
+
+	return __dest;
 }
 
 /* ===========================================================================
@@ -225,15 +230,15 @@ flush_window()
 static void
 error(char *x)
 {
-	puts("\n\n");
+	puts("\r\n\n");
 	puts(x);
-	puts("\n\n -- System halted\n");
+	puts("\r\n\n -- System halted\n");
 
 	while(1);	/* Halt */
 }
 
 void
-setup_normal_output_buffer()
+setup_normal_output_buffer(void)
 {
 	output_data = (char *)KERNEL_LOAD_ADR;
 }
@@ -262,15 +267,17 @@ serial_setup(reg_scope_instances regi_ser)
 	rec_baud = REG_RD(ser, regi_ser, rw_rec_baud_div);
 
 	tr_ctrl.stop_bits = 1;	/* 2 stop bits. */
+	tr_ctrl.en = 1; /* enable transmitter */
+	rec_ctrl.en = 1; /* enabler receiver */
 
 	/*
-	 * The baudrate setup is a bit fishy, but in the end the transceiver is
-	 * set to 4800 and the receiver to 115200. The magic value is
-	 * 29.493 MHz.
+	 * The baudrate setup used to be a bit fishy, but now transmitter and
+	 * receiver are both set to the intended baud rate, 115200.
+	 * The magic value is 29.493 MHz.
 	 */
 	tr_ctrl.base_freq = regk_ser_f29_493;
 	rec_ctrl.base_freq = regk_ser_f29_493;
-	tr_baud.div = (29493000 / 8) / 4800;
+	tr_baud.div = (29493000 / 8) / 115200;
 	rec_baud.div = (29493000 / 8) / 115200;
 
 	REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl);
@@ -280,25 +287,52 @@ serial_setup(reg_scope_instances regi_ser)
 }
 
 void
-decompress_kernel()
+decompress_kernel(void)
 {
 	char revision;
 
-	/* input_data is set in head.S */
-	inbuf = input_data;
+#if defined(CONFIG_ETRAX_DEBUG_PORT1) || \
+    defined(CONFIG_ETRAX_DEBUG_PORT2) || \
+    defined(CONFIG_ETRAX_DEBUG_PORT3)
+	reg_pinmux_rw_hwprot hwprot;
+
+#ifdef CONFIG_CRIS_MACH_ARTPEC3
+	reg_clkgen_rw_clk_ctrl clk_ctrl;
+
+	/* Enable corresponding clock region when serial 1..3 selected */
+
+	clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl);
+	clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes;
+	REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, clk_ctrl);
+#endif
+
+	/* pinmux setup for ports 1..3 */
+	hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot);
+#endif
 
 #ifdef CONFIG_ETRAX_DEBUG_PORT0
 	serial_setup(regi_ser0);
 #endif
 #ifdef CONFIG_ETRAX_DEBUG_PORT1
+	hwprot.ser1 = regk_pinmux_yes;
 	serial_setup(regi_ser1);
 #endif
 #ifdef CONFIG_ETRAX_DEBUG_PORT2
+	hwprot.ser2 = regk_pinmux_yes;
 	serial_setup(regi_ser2);
 #endif
 #ifdef CONFIG_ETRAX_DEBUG_PORT3
+	hwprot.ser3 = regk_pinmux_yes;
 	serial_setup(regi_ser3);
 #endif
+#if defined(CONFIG_ETRAX_DEBUG_PORT1) || \
+    defined(CONFIG_ETRAX_DEBUG_PORT2) || \
+    defined(CONFIG_ETRAX_DEBUG_PORT3)
+	REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot);
+#endif
+
+	/* input_data is set in head.S */
+	inbuf = input_data;
 
 	setup_normal_output_buffer();
 
@@ -307,11 +341,11 @@ decompress_kernel()
 	__asm__ volatile ("move $vr,%0" : "=rm" (revision));
 	if (revision < 32)
 	{
-		puts("You need an ETRAX FS to run Linux 2.6/crisv32.\n");
+		puts("You need an ETRAX FS to run Linux 2.6/crisv32.\r\n");
 		while(1);
 	}
 
-	puts("Uncompressing Linux...\n");
+	puts("Uncompressing Linux...\r\n");
 	gunzip();
-	puts("Done. Now booting the kernel.\n");
+	puts("Done. Now booting the kernel.\r\n");
 }
diff --git a/arch/cris/arch-v32/boot/rescue/Makefile b/arch/cris/arch-v32/boot/rescue/Makefile
index f668a8198724..c0987795dcb7 100644
--- a/arch/cris/arch-v32/boot/rescue/Makefile
+++ b/arch/cris/arch-v32/boot/rescue/Makefile
@@ -1,36 +1,27 @@
 #
-# Makefile for rescue code
+# Makefile for rescue (bootstrap) code
 #
-target = $(target_rescue_dir)
-src    = $(src_rescue_dir)
 
 CC = gcc-cris -mlinux -march=v32 $(LINUXINCLUDE)
-CFLAGS = -O2
+ccflags-y += -O2 -I $(srctree)/include/asm/arch/mach/ \
+		-I $(srctree)/include/asm/arch
+asflags-y += -I $(srctree)/include/asm/arch/mach/ -I $(srctree)/include/asm/arch
 LD = gcc-cris -mlinux -march=v32 -nostdlib
+ldflags-y += -T $(obj)/rescue.ld
+LDPOSTFLAGS = -lgcc
 OBJCOPY = objcopy-cris
 OBJCOPYFLAGS = -O binary --remove-section=.bss
+obj-$(CONFIG_ETRAX_AXISFLASHMAP) = head.o
+OBJECT := $(obj)/head.o
 
-all: $(target)/rescue.bin
+targets := rescue.o rescue.bin
 
-rescue: rescue.bin
-	# do nothing
+quiet_cmd_ldlibgcc = LD      $@
+cmd_ldlibgcc = $(LD) $(LDFLAGS) $(filter-out FORCE,$^) $(LDPOSTFLAGS) -o $@
 
-$(target)/rescue.bin: $(target) $(target)/head.o
-	$(LD) -T $(src)/rescue.ld -o $(target)/rescue.o $(target)/head.o
-	$(OBJCOPY) $(OBJCOPYFLAGS) $(target)/rescue.o $(target)/rescue.bin
-	cp -p $(target)/rescue.bin $(objtree)
+$(obj)/rescue.o: $(OBJECTS) FORCE
+	$(call if_changed,ldlibgcc)
 
-$(target):
-	mkdir -p $(target)
-
-$(target)/head.o: $(src)/head.S
-	$(CC) -D__ASSEMBLY__ -c $< -o $*.o
-
-clean:
-	rm -f $(target)/*.o $(target)/*.bin
-
-fastdep:
-
-modules:
-
-modules-install:
+$(obj)/rescue.bin: $(obj)/rescue.o FORCE
+	$(call if_changed,objcopy)
+	cp -p $(obj)/rescue.bin $(objtree)
diff --git a/arch/cris/arch-v32/boot/rescue/head.S b/arch/cris/arch-v32/boot/rescue/head.S
index 8cdb4011bc16..5f846b7700a3 100644
--- a/arch/cris/arch-v32/boot/rescue/head.S
+++ b/arch/cris/arch-v32/boot/rescue/head.S
@@ -1,38 +1,26 @@
-/* $Id: head.S,v 1.4 2004/11/01 16:10:28 starvik Exp $
+/*
+ * Just get started by jumping to CONFIG_ETRAX_PTABLE_SECTOR to start
+ * kernel decompressor.
+ *
+ * In practice, this only works for NOR flash (or some convoluted RAM boot)
+ * and hence is not really useful for Artpec-3, so it's Etrax FS / NOR only.
  *
- * This used to be the rescue code but now that is handled by the
- * RedBoot based RFL instead. Nothing to see here, move along.
  */
 
-#include <asm/arch/hwregs/reg_map_asm.h>
-#include <asm/arch/hwregs/config_defs_asm.h>
+#include <mach/startup.inc>
 
-	.text
+#ifdef CONFIG_ETRAX_AXISFLASHMAP
 
-	;; Start clocks for used blocks.
-	move.d REG_ADDR(config, regi_config, rw_clk_ctrl), $r1
-	move.d [$r1], $r0
-	or.d   REG_STATE(config, rw_clk_ctrl, cpu, yes) | \
-	       REG_STATE(config, rw_clk_ctrl, bif, yes) | \
-	       REG_STATE(config, rw_clk_ctrl, fix_io, yes), $r0
-	move.d $r0, [$r1]
+;; Code
 
-	;; Copy 68KB NAND flash to Internal RAM (if NAND boot)
-	move.d 0x38004000, $r10
-	move.d 0x8000, $r11
-	move.d 0x11000, $r12
-	move.d copy_complete, $r13
-	and.d  0x000fffff, $r13
-	or.d   0x38000000, $r13
+	.text
+start:
 
-#include "../../lib/nand_init.S"
+	;; Start clocks for used blocks.
+	START_CLOCKS
 
-	;; No NAND found
 	move.d	CONFIG_ETRAX_PTABLE_SECTOR, $r10
-	jump	$r10 ; Jump to decompresser
+	jump	$r10			; Jump to decompressor
 	nop
 
-copy_complete:
-	move.d	0x38000000 + CONFIG_ETRAX_PTABLE_SECTOR, $r10
-	jump	$r10 ; Jump to decompresser
-	nop
+#endif
diff --git a/arch/cris/arch-v32/boot/rescue/rescue.ld b/arch/cris/arch-v32/boot/rescue/rescue.ld
index 42b11aa122b2..8ac646bc1a2b 100644
--- a/arch/cris/arch-v32/boot/rescue/rescue.ld
+++ b/arch/cris/arch-v32/boot/rescue/rescue.ld
@@ -1,20 +1,43 @@
+/*#OUTPUT_FORMAT(elf32-us-cris) */
+OUTPUT_ARCH (crisv32)
+/* Now that NAND support has been stripped, this file could be simplified,
+ * but it doesn't do any harm on the other hand so why bother. */
+
 MEMORY
 	{
-	flash : ORIGIN = 0x00000000,
-	        LENGTH = 0x00100000
+	bootblk : ORIGIN = 0x38000000,
+	          LENGTH = 0x00004000
+	intmem  : ORIGIN = 0x38004000,
+		  LENGTH = 0x00005000
 	}
 
 SECTIONS
 {
 	.text :
 	{
-		stext = . ;
+		_stext = . ;
 		*(.text)
-		etext = . ;
-	} > flash
+		*(.init.text)
+		*(.rodata)
+		*(.rodata.*)
+		_etext = . ;
+	} > bootblk
 	.data :
 	{
 		*(.data)
-		edata = . ;
-	} > flash
+		_edata = . ;
+	} > bootblk
+	.bss :
+	{
+		_bss = . ;
+		*(.bss)
+		_end = ALIGN( 0x10 ) ;
+	} > intmem
+
+	/* Get rid of stuff from EXPORT_SYMBOL(foo). */
+	/DISCARD/ :
+	{
+	        *(__ksymtab_strings)
+	        *(__ksymtab)
+	}
 }
diff --git a/arch/cris/arch-v32/drivers/Kconfig b/arch/cris/arch-v32/drivers/Kconfig
index c329cce2a0c3..2a92cb1886ca 100644
--- a/arch/cris/arch-v32/drivers/Kconfig
+++ b/arch/cris/arch-v32/drivers/Kconfig
@@ -4,64 +4,102 @@ config ETRAX_ETHERNET
 	bool "Ethernet support"
 	depends on ETRAX_ARCH_V32
 	select NET_ETHERNET
+	select MII
 	help
 	  This option enables the ETRAX FS built-in 10/100Mbit Ethernet
 	  controller.
 
-config ETRAX_ETHERNET_HW_CSUM
-	bool "Hardware accelerated ethernet checksum and scatter/gather"
+config ETRAX_NO_PHY
+	bool "PHY not present"
 	depends on ETRAX_ETHERNET
-	depends on ETRAX_STREAMCOPROC
-	default y
+	default N
 	help
-	  Hardware acceleration of checksumming and scatter/gather
+	  This option disables all MDIO communication with an ethernet
+	  transceiver connected to the MII interface. This option shall
+	  typically be enabled if the MII interface is connected to a
+	  switch. This option should normally be disabled. If enabled,
+	  speed and duplex will be locked to 100 Mbit and full duplex.
 
 config ETRAX_ETHERNET_IFACE0
 	depends on ETRAX_ETHERNET
 	bool "Enable network interface 0"
 
 config ETRAX_ETHERNET_IFACE1
-	depends on ETRAX_ETHERNET
+	depends on (ETRAX_ETHERNET && ETRAXFS)
 	bool "Enable network interface 1 (uses DMA6 and DMA7)"
 
+config ETRAX_ETHERNET_GBIT
+	depends on (ETRAX_ETHERNET && CRIS_MACH_ARTPEC3)
+	bool "Enable gigabit Ethernet support"
+
 choice
-	prompt "Network LED behavior"
-	depends on ETRAX_ETHERNET
-	default ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY
+	prompt "Eth0 led group"
+	depends on ETRAX_ETHERNET_IFACE0
+	default ETRAX_ETH0_USE_LEDGRP0
 
-config ETRAX_NETWORK_LED_ON_WHEN_LINK
-	bool "LED_on_when_link"
+config ETRAX_ETH0_USE_LEDGRP0
+	bool "Use LED grp 0"
+	depends on ETRAX_NBR_LED_GRP_ONE || ETRAX_NBR_LED_GRP_TWO
 	help
-	  Selecting LED_on_when_link will light the LED when there is a
-	  connection and will flash off when there is activity.
+	  Use LED grp 0 for eth0
 
-	  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_ETH0_USE_LEDGRP1
+	bool "Use LED grp 1"
+	depends on ETRAX_NBR_LED_GRP_TWO
+	help
+	  Use LED grp 1 for eth0
 
-config ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY
-	bool "LED_on_when_activity"
+config ETRAX_ETH0_USE_LEDGRPNULL
+	bool "Use no LEDs for eth0"
 	help
-	  Selecting LED_on_when_link will light the LED when there is a
-	  connection and will flash off when there is activity.
+	  Use no LEDs for eth0
+endchoice
 
-	  Selecting LED_on_when_activity will light the LED only when
-	  there is activity.
+choice
+	prompt "Eth1 led group"
+	depends on ETRAX_ETHERNET_IFACE1
+	default ETRAX_ETH1_USE_LEDGRP1
+
+config ETRAX_ETH1_USE_LEDGRP0
+	bool "Use LED grp 0"
+	depends on ETRAX_NBR_LED_GRP_ONE || ETRAX_NBR_LED_GRP_TWO
+	help
+	  Use LED grp 0 for eth1
 
-	  This setting will also affect the behaviour of other activity LEDs
-	  e.g. Bluetooth.
+config ETRAX_ETH1_USE_LEDGRP1
+	bool "Use LED grp 1"
+	depends on ETRAX_NBR_LED_GRP_TWO
+	help
+	  Use LED grp 1 for eth1
 
+config ETRAX_ETH1_USE_LEDGRPNULL
+	bool "Use no LEDs for eth1"
+	help
+	  Use no LEDs for eth1
 endchoice
 
 config ETRAXFS_SERIAL
 	bool "Serial-port support"
 	depends on ETRAX_ARCH_V32
+	select SERIAL_CORE
+	select SERIAL_CORE_CONSOLE
 	help
 	  Enables the ETRAX FS serial driver for ser0 (ttyS0)
 	  You probably want this enabled.
 
+config ETRAX_RS485
+	bool "RS-485 support"
+	depends on ETRAXFS_SERIAL
+	help
+	  Enables support for RS-485 serial communication.
+
+config ETRAX_RS485_DISABLE_RECEIVER
+	bool "Disable serial receiver"
+	depends on ETRAX_RS485
+	help
+	  It is necessary to disable the serial receiver to avoid serial
+	  loopback.  Not all products are able to do this in software only.
+
 config ETRAX_SERIAL_PORT0
 	bool "Serial port 0 enabled"
 	depends on ETRAXFS_SERIAL
@@ -72,50 +110,28 @@ config ETRAX_SERIAL_PORT0
 	  ser0 can use dma4 or dma6 for output and dma5 or dma7 for input.
 
 choice
-	prompt "Ser0 DMA in channel "
+	prompt "Ser0 default port type "
 	depends on ETRAX_SERIAL_PORT0
-	default ETRAX_SERIAL_PORT0_NO_DMA_IN
+	default ETRAX_SERIAL_PORT0_TYPE_232
 	help
-	  What DMA channel to use for ser0.
-
+	  Type of serial port.
 
-config ETRAX_SERIAL_PORT0_NO_DMA_IN
-	bool "Ser0 uses no DMA for input"
+config ETRAX_SERIAL_PORT0_TYPE_232
+	bool "Ser0 is a RS-232 port"
 	help
-	  Do not use DMA for ser0 input.
+	  Configure serial port 0 to be a RS-232 port.
 
-config ETRAX_SERIAL_PORT0_DMA7_IN
-	bool "Ser0 uses DMA7 for input"
-	depends on ETRAX_SERIAL_PORT0
-	help
-	  Enables the DMA7 input channel for ser0 (ttyS0).
-	  If you do not enable DMA, an interrupt for each character will be
-	  used when receiving data.
-	  Normally you want to use DMA, unless you use the DMA channel for
-	  something else.
-
-endchoice
-
-choice
-	prompt "Ser0 DMA out channel"
-	depends on ETRAX_SERIAL_PORT0
-	default ETRAX_SERIAL_PORT0_NO_DMA_OUT
-
-config ETRAX_SERIAL_PORT0_NO_DMA_OUT
-	bool "Ser0 uses no DMA for output"
+config ETRAX_SERIAL_PORT0_TYPE_485HD
+	bool "Ser0 is a half duplex RS-485 port"
+	depends on ETRAX_RS485
 	help
-	  Do not use DMA for ser0 output.
+	  Configure serial port 0 to be a half duplex (two wires) RS-485 port.
 
-config ETRAX_SERIAL_PORT0_DMA6_OUT
-	bool "Ser0 uses DMA6 for output"
-	depends on ETRAX_SERIAL_PORT0
+config ETRAX_SERIAL_PORT0_TYPE_485FD
+	bool "Ser0 is a full duplex RS-485 port"
+	depends on ETRAX_RS485
 	help
-	  Enables the DMA6 output channel for ser0 (ttyS0).
-	  If you do not enable DMA, an interrupt for each character will be
-	  used when transmitting data.
-	  Normally you want to use DMA, unless you use the DMA channel for
-	  something else.
-
+	  Configure serial port 0 to be a full duplex (four wires) RS-485 port.
 endchoice
 
 config ETRAX_SER0_DTR_BIT
@@ -141,52 +157,28 @@ config ETRAX_SERIAL_PORT1
 	  Enables the ETRAX FS serial driver for ser1 (ttyS1).
 
 choice
-	prompt "Ser1 DMA in channel "
+	prompt "Ser1 default port type"
 	depends on ETRAX_SERIAL_PORT1
-	default ETRAX_SERIAL_PORT1_NO_DMA_IN
-	help
-	  What DMA channel to use for ser1.
-
-
-config ETRAX_SERIAL_PORT1_NO_DMA_IN
-	bool "Ser1 uses no DMA for input"
+	default ETRAX_SERIAL_PORT1_TYPE_232
 	help
-	  Do not use DMA for ser1 input.
+	  Type of serial port.
 
-config ETRAX_SERIAL_PORT1_DMA5_IN
-	bool "Ser1 uses DMA5 for input"
-	depends on ETRAX_SERIAL_PORT1
+config ETRAX_SERIAL_PORT1_TYPE_232
+	bool "Ser1 is a RS-232 port"
 	help
-	  Enables the DMA5 input channel for ser1 (ttyS1).
-	  If you do not enable DMA, an interrupt for each character will be
-	  used when receiving data.
-	  Normally you want this on, unless you use the DMA channel for
-	  something else.
-
-endchoice
+	  Configure serial port 1 to be a RS-232 port.
 
-choice
-	prompt "Ser1 DMA out channel "
-	depends on ETRAX_SERIAL_PORT1
-	default ETRAX_SERIAL_PORT1_NO_DMA_OUT
-	help
-	  What DMA channel to use for ser1.
-
-config ETRAX_SERIAL_PORT1_NO_DMA_OUT
-	bool "Ser1 uses no DMA for output"
+config ETRAX_SERIAL_PORT1_TYPE_485HD
+	bool "Ser1 is a half duplex RS-485 port"
+	depends on ETRAX_RS485
 	help
-	  Do not use DMA for ser1 output.
+	  Configure serial port 1 to be a half duplex (two wires) RS-485 port.
 
-config ETRAX_SERIAL_PORT1_DMA4_OUT
-	bool "Ser1 uses DMA4 for output"
-	depends on ETRAX_SERIAL_PORT1
+config ETRAX_SERIAL_PORT1_TYPE_485FD
+	bool "Ser1 is a full duplex RS-485 port"
+	depends on ETRAX_RS485
 	help
-	  Enables the DMA4 output channel for ser1 (ttyS1).
-	  If you do not enable DMA, an interrupt for each character will be
-	  used when transmitting data.
-	  Normally you want this on, unless you use the DMA channel for
-	  something else.
-
+	  Configure serial port 1 to be a full duplex (four wires) RS-485 port.
 endchoice
 
 config ETRAX_SER1_DTR_BIT
@@ -212,52 +204,31 @@ config ETRAX_SERIAL_PORT2
 	  Enables the ETRAX FS serial driver for ser2 (ttyS2).
 
 choice
-	prompt "Ser2 DMA in channel "
+	prompt "Ser2 default port type"
 	depends on ETRAX_SERIAL_PORT2
-	default ETRAX_SERIAL_PORT2_NO_DMA_IN
+	default ETRAX_SERIAL_PORT2_TYPE_232
 	help
-	  What DMA channel to use for ser2.
+	  What DMA channel to use for ser2
 
-
-config ETRAX_SERIAL_PORT2_NO_DMA_IN
-	bool "Ser2 uses no DMA for input"
+config ETRAX_SERIAL_PORT2_TYPE_232
+	bool "Ser2 is a RS-232 port"
 	help
-	  Do not use DMA for ser2 input.
+	  Configure serial port 2 to be a RS-232 port.
 
-config ETRAX_SERIAL_PORT2_DMA3_IN
-	bool "Ser2 uses DMA3 for input"
-	depends on ETRAX_SERIAL_PORT2
-	help
-	  Enables the DMA3 input channel for ser2 (ttyS2).
-	  If you do not enable DMA, an interrupt for each character will be
-	  used when receiving data.
-	  Normally you want to use DMA, unless you use the DMA channel for
-	  something else.
-
-endchoice
-
-choice
-	prompt "Ser2 DMA out channel"
-	depends on ETRAX_SERIAL_PORT2
-	default ETRAX_SERIAL_PORT2_NO_DMA_OUT
-
-config ETRAX_SERIAL_PORT2_NO_DMA_OUT
-	bool "Ser2 uses no DMA for output"
+config ETRAX_SERIAL_PORT2_TYPE_485HD
+	bool "Ser2 is a half duplex RS-485 port"
+	depends on ETRAX_RS485
 	help
-	  Do not use DMA for ser2 output.
+	  Configure serial port 2 to be a half duplex (two wires) RS-485 port.
 
-config ETRAX_SERIAL_PORT2_DMA2_OUT
-	bool "Ser2 uses DMA2 for output"
-	depends on ETRAX_SERIAL_PORT2
+config ETRAX_SERIAL_PORT2_TYPE_485FD
+	bool "Ser2 is a full duplex RS-485 port"
+	depends on ETRAX_RS485
 	help
-	  Enables the DMA2 output channel for ser2 (ttyS2).
-	  If you do not enable DMA, an interrupt for each character will be
-	  used when transmitting data.
-	  Normally you want to use DMA, unless you use the DMA channel for
-	  something else.
-
+	  Configure serial port 2 to be a full duplex (four wires) RS-485 port.
 endchoice
 
+
 config ETRAX_SER2_DTR_BIT
 	string "Ser 2 DTR bit (empty = not used)"
 	depends on ETRAX_SERIAL_PORT2
@@ -281,71 +252,121 @@ config ETRAX_SERIAL_PORT3
 	  Enables the ETRAX FS serial driver for ser3 (ttyS3).
 
 choice
-	prompt "Ser3 DMA in channel "
+	prompt "Ser3 default port type"
 	depends on ETRAX_SERIAL_PORT3
-	default ETRAX_SERIAL_PORT3_NO_DMA_IN
+	default ETRAX_SERIAL_PORT3_TYPE_232
 	help
 	  What DMA channel to use for ser3.
 
+config ETRAX_SERIAL_PORT3_TYPE_232
+	bool "Ser3 is a RS-232 port"
+	help
+	  Configure serial port 3 to be a RS-232 port.
 
-config ETRAX_SERIAL_PORT3_NO_DMA_IN
-	bool "Ser3 uses no DMA for input"
+config ETRAX_SERIAL_PORT3_TYPE_485HD
+	bool "Ser3 is a half duplex RS-485 port"
+	depends on ETRAX_RS485
 	help
-	  Do not use DMA for ser3 input.
+	  Configure serial port 3 to be a half duplex (two wires) RS-485 port.
 
-config ETRAX_SERIAL_PORT3_DMA9_IN
-	bool "Ser3 uses DMA9 for input"
+config ETRAX_SERIAL_PORT3_TYPE_485FD
+	bool "Ser3 is a full duplex RS-485 port"
+	depends on ETRAX_RS485
+	help
+	  Configure serial port 3 to be a full duplex (four wires) RS-485 port.
+endchoice
+
+config ETRAX_SER3_DTR_BIT
+	string "Ser 3 DTR bit (empty = not used)"
+	depends on ETRAX_SERIAL_PORT3
+
+config ETRAX_SER3_RI_BIT
+	string "Ser 3 RI bit (empty = not used)"
+	depends on ETRAX_SERIAL_PORT3
+
+config ETRAX_SER3_DSR_BIT
+	string "Ser 3 DSR bit (empty = not used)"
+	depends on ETRAX_SERIAL_PORT3
+
+config ETRAX_SER3_CD_BIT
+	string "Ser 3 CD bit (empty = not used)"
 	depends on ETRAX_SERIAL_PORT3
+
+config ETRAX_SERIAL_PORT4
+	bool "Serial port 4 enabled"
+	depends on ETRAXFS_SERIAL && CRIS_MACH_ARTPEC3
 	help
-	  Enables the DMA9 input channel for ser3 (ttyS3).
-	  If you do not enable DMA, an interrupt for each character will be
-	  used when receiving data.
-	  Normally you want to use DMA, unless you use the DMA channel for
-	  something else.
+	  Enables the ETRAX FS serial driver for ser4 (ttyS4).
+
+choice
+	prompt "Ser4 default port type"
+	depends on ETRAX_SERIAL_PORT4
+	default ETRAX_SERIAL_PORT4_TYPE_232
+	help
+	  What DMA channel to use for ser4.
 
+config ETRAX_SERIAL_PORT4_TYPE_232
+	bool "Ser4 is a RS-232 port"
+	help
+	  Configure serial port 4 to be a RS-232 port.
+
+config ETRAX_SERIAL_PORT4_TYPE_485HD
+	bool "Ser4 is a half duplex RS-485 port"
+	depends on ETRAX_RS485
+	help
+	  Configure serial port 4 to be a half duplex (two wires) RS-485 port.
+
+config ETRAX_SERIAL_PORT4_TYPE_485FD
+	bool "Ser4 is a full duplex RS-485 port"
+	depends on ETRAX_RS485
+	help
+	  Configure serial port 4 to be a full duplex (four wires) RS-485 port.
 endchoice
 
 choice
-	prompt "Ser3 DMA out channel"
-	depends on ETRAX_SERIAL_PORT3
-	default ETRAX_SERIAL_PORT3_NO_DMA_OUT
+	prompt "Ser4 DMA in channel "
+	depends on ETRAX_SERIAL_PORT4
+	default ETRAX_SERIAL_PORT4_NO_DMA_IN
+	help
+	  What DMA channel to use for ser4.
+
 
-config ETRAX_SERIAL_PORT3_NO_DMA_OUT
-	bool "Ser3 uses no DMA for output"
+config ETRAX_SERIAL_PORT4_NO_DMA_IN
+	bool "Ser4 uses no DMA for input"
 	help
-	  Do not use DMA for ser3 output.
+	  Do not use DMA for ser4 input.
 
-config ETRAX_SERIAL_PORT3_DMA8_OUT
-	bool "Ser3 uses DMA8 for output"
-	depends on ETRAX_SERIAL_PORT3
+config ETRAX_SERIAL_PORT4_DMA9_IN
+	bool "Ser4 uses DMA9 for input"
+	depends on ETRAX_SERIAL_PORT4
 	help
-	  Enables the DMA8 output channel for ser3 (ttyS3).
+	  Enables the DMA9 input channel for ser4 (ttyS4).
 	  If you do not enable DMA, an interrupt for each character will be
-	  used when transmitting data.
+	  used when receiveing data.
 	  Normally you want to use DMA, unless you use the DMA channel for
 	  something else.
 
 endchoice
 
-config ETRAX_SER3_DTR_BIT
-	string "Ser 3 DTR bit (empty = not used)"
-	depends on ETRAX_SERIAL_PORT3
+config ETRAX_SER4_DTR_BIT
+	string "Ser 4 DTR bit (empty = not used)"
+	depends on ETRAX_SERIAL_PORT4
 
-config ETRAX_SER3_RI_BIT
-	string "Ser 3 RI bit (empty = not used)"
-	depends on ETRAX_SERIAL_PORT3
+config ETRAX_SER4_RI_BIT
+	string "Ser 4 RI bit (empty = not used)"
+	depends on ETRAX_SERIAL_PORT4
 
-config ETRAX_SER3_DSR_BIT
-	string "Ser 3 DSR bit (empty = not used)"
-	depends on ETRAX_SERIAL_PORT3
+config ETRAX_SER4_DSR_BIT
+	string "Ser 4 DSR bit (empty = not used)"
+	depends on ETRAX_SERIAL_PORT4
 
 config ETRAX_SER3_CD_BIT
-	string "Ser 3 CD bit (empty = not used)"
-	depends on ETRAX_SERIAL_PORT3
+	string "Ser 4 CD bit (empty = not used)"
+	depends on ETRAX_SERIAL_PORT4
 
 config ETRAX_RS485
 	bool "RS-485 support"
-	depends on ETRAX_SERIAL
+	depends on ETRAXFS_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>.
@@ -356,22 +377,6 @@ config ETRAX_RS485_DISABLE_RECEIVER
 	help
 	  It is 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_AXISFLASHMAP
-	bool "Axis flash-map support"
-	depends on ETRAX_ARCH_V32
-	select MTD
-	select MTD_CFI
-	select MTD_CFI_AMDSTD
-	select MTD_CHAR
-	select MTD_BLOCK
-	select MTD_PARTITIONS
-	select MTD_CONCAT
-	select MTD_COMPLEX_MAPPINGS
-	help
-	  This option enables MTD mapping of flash devices.  Needed to use
-	  flash memories.  If unsure, say Y.
 
 config ETRAX_SYNCHRONOUS_SERIAL
 	bool "Synchronous serial-port support"
@@ -394,7 +399,7 @@ config ETRAX_SYNCHRONOUS_SERIAL0_DMA
 
 config ETRAX_SYNCHRONOUS_SERIAL_PORT1
          bool "Synchronous serial port 1 enabled"
-         depends on ETRAX_SYNCHRONOUS_SERIAL
+         depends on ETRAX_SYNCHRONOUS_SERIAL && ETRAXFS
          help
            Enabled synchronous serial port 1.
 
@@ -405,6 +410,31 @@ config ETRAX_SYNCHRONOUS_SERIAL1_DMA
            A synchronous serial port can run in manual or DMA mode.
            Selecting this option will make it run in DMA mode.
 
+config ETRAX_AXISFLASHMAP
+	bool "Axis flash-map support"
+	depends on ETRAX_ARCH_V32
+	select MTD
+	select MTD_CFI
+	select MTD_CFI_AMDSTD
+	select MTD_JEDECPROBE
+	select MTD_CHAR
+	select MTD_BLOCK
+	select MTD_PARTITIONS
+	select MTD_CONCAT
+	select MTD_COMPLEX_MAPPINGS
+	help
+	  This option enables MTD mapping of flash devices.  Needed to use
+	  flash memories.  If unsure, say Y.
+
+config ETRAX_AXISFLASHMAP_MTD0WHOLE
+	bool "MTD0 is whole boot flash device"
+	depends on ETRAX_AXISFLASHMAP
+	default N
+	help
+	  When this option is not set, mtd0 refers to the first partition
+	  on the boot flash device. When set, mtd0 refers to the whole
+	  device, with mtd1 referring to the first partition etc.
+
 config ETRAX_PTABLE_SECTOR
 	int "Byte-offset of partition table sector"
 	depends on ETRAX_AXISFLASHMAP
@@ -425,42 +455,32 @@ config ETRAX_NANDFLASH
 	  This option enables MTD mapping of NAND flash devices.  Needed to use
 	  NAND flash memories.  If unsure, say Y.
 
+config ETRAX_NANDBOOT
+	bool "Boot from NAND flash"
+	depends on ETRAX_NANDFLASH
+	help
+	  This options enables booting from NAND flash devices.
+	  Say Y if your boot code, kernel and root file system is in
+	  NAND flash. Say N if they are in NOR flash.
+
 config ETRAX_I2C
 	bool "I2C driver"
 	depends on ETRAX_ARCH_V32
 	help
-	  This option enabled the I2C driver used by e.g. the RTC driver.
+	  This option enables the I2C driver used by e.g. the RTC driver.
 
-config ETRAX_I2C_DATA_PORT
+config ETRAX_V32_I2C_DATA_PORT
 	string "I2C data pin"
 	depends on ETRAX_I2C
 	help
 	  The pin to use for I2C data.
 
-config ETRAX_I2C_CLK_PORT
+config ETRAX_V32_I2C_CLK_PORT
 	string "I2C clock pin"
 	depends on ETRAX_I2C
 	help
 	  The pin to use for I2C clock.
 
-config ETRAX_RTC
-	bool "Real Time Clock support"
-	depends on ETRAX_ARCH_V32
-	help
-	  Enabled RTC support.
-
-choice
-	prompt "RTC chip"
-	depends on ETRAX_RTC
-	default ETRAX_PCF8563
-
-config ETRAX_PCF8563
-	bool "PCF8563"
-	help
-	  Philips PCF8563 RTC
-
-endchoice
-
 config ETRAX_GPIO
 	bool "GPIO support"
 	depends on ETRAX_ARCH_V32
@@ -476,33 +496,36 @@ config ETRAX_GPIO
 	  Remember that you need to setup the port directions appropriately in
 	  the General configuration.
 
-config ETRAX_PA_BUTTON_BITMASK
-	hex "PA-buttons bitmask"
+config ETRAX_VIRTUAL_GPIO
+	bool "Virtual GPIO support"
 	depends on ETRAX_GPIO
-	default "0x02"
 	help
-	  This is a bitmask (8 bits) with information about what bits on PA
-	  that are used for buttons.
-	  Most products has a so called TEST button on PA1, if that is true
-	  use 0x02 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.
+	  Enables the virtual Etrax general port device (major 120, minor 6).
+	  It uses an I/O expander for the I2C-bus.
+
+config ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN
+	int "Virtual GPIO interrupt pin on PA pin"
+	range 0 7
+	depends on ETRAX_VIRTUAL_GPIO
+	help
+	  The pin to use on PA for virtual gpio interrupt.
 
 config ETRAX_PA_CHANGEABLE_DIR
 	hex "PA user changeable dir mask"
 	depends on ETRAX_GPIO
-	default "0x00"
+	default "0x00" if ETRAXFS
+	default "0x00000000" if !ETRAXFS
 	help
 	  This is a bitmask (8 bits) with information of what bits in PA that a
 	  user can change direction on using ioctl's.
 	  Bit set = changeable.
-	  You probably want 0x00 here, but it depends on your hardware.
+	  You probably want 0 here, but it depends on your hardware.
 
 config ETRAX_PA_CHANGEABLE_BITS
 	hex "PA user changeable bits mask"
 	depends on ETRAX_GPIO
-	default "0x00"
+	default "0x00" if ETRAXFS
+	default "0x00000000" if !ETRAXFS
 	help
 	  This is a bitmask (8 bits) with information of what bits in PA
 	  that a user can change the value on using ioctl's.
@@ -511,17 +534,19 @@ config ETRAX_PA_CHANGEABLE_BITS
 config ETRAX_PB_CHANGEABLE_DIR
 	hex "PB user changeable dir mask"
 	depends on ETRAX_GPIO
-	default "0x00000"
+	default "0x00000" if ETRAXFS
+	default "0x00000000" if !ETRAXFS
 	help
 	  This is a bitmask (18 bits) with information of what bits in PB
 	  that a user can change direction on using ioctl's.
 	  Bit set = changeable.
-	  You probably want 0x00000 here, but it depends on your hardware.
+	  You probably want 0 here, but it depends on your hardware.
 
 config ETRAX_PB_CHANGEABLE_BITS
 	hex "PB user changeable bits mask"
 	depends on ETRAX_GPIO
-	default "0x00000"
+	default "0x00000" if ETRAXFS
+	default "0x00000000" if !ETRAXFS
 	help
 	  This is a bitmask (18 bits) with information of what bits in PB
 	  that a user can change the value on using ioctl's.
@@ -530,17 +555,19 @@ config ETRAX_PB_CHANGEABLE_BITS
 config ETRAX_PC_CHANGEABLE_DIR
 	hex "PC user changeable dir mask"
 	depends on ETRAX_GPIO
-	default "0x00000"
+	default "0x00000" if ETRAXFS
+	default "0x00000000" if !ETRAXFS
 	help
 	  This is a bitmask (18 bits) with information of what bits in PC
 	  that a user can change direction on using ioctl's.
 	  Bit set = changeable.
-	  You probably want 0x00000 here, but it depends on your hardware.
+	  You probably want 0 here, but it depends on your hardware.
 
 config ETRAX_PC_CHANGEABLE_BITS
 	hex "PC user changeable bits mask"
 	depends on ETRAX_GPIO
-	default "0x00000"
+	default "0x00000" if ETRAXFS
+	default "0x00000000" if ETRAXFS
 	help
 	  This is a bitmask (18 bits) with information of what bits in PC
 	  that a user can change the value on using ioctl's.
@@ -548,7 +575,7 @@ config ETRAX_PC_CHANGEABLE_BITS
 
 config ETRAX_PD_CHANGEABLE_DIR
 	hex "PD user changeable dir mask"
-	depends on ETRAX_GPIO
+	depends on ETRAX_GPIO && ETRAXFS
 	default "0x00000"
 	help
 	  This is a bitmask (18 bits) with information of what bits in PD
@@ -558,7 +585,7 @@ config ETRAX_PD_CHANGEABLE_DIR
 
 config ETRAX_PD_CHANGEABLE_BITS
 	hex "PD user changeable bits mask"
-	depends on ETRAX_GPIO
+	depends on ETRAX_GPIO && ETRAXFS
 	default "0x00000"
 	help
 	  This is a bitmask (18 bits) with information of what bits in PD
@@ -567,7 +594,7 @@ config ETRAX_PD_CHANGEABLE_BITS
 
 config ETRAX_PE_CHANGEABLE_DIR
 	hex "PE user changeable dir mask"
-	depends on ETRAX_GPIO
+	depends on ETRAX_GPIO && ETRAXFS
 	default "0x00000"
 	help
 	  This is a bitmask (18 bits) with information of what bits in PE
@@ -577,20 +604,36 @@ config ETRAX_PE_CHANGEABLE_DIR
 
 config ETRAX_PE_CHANGEABLE_BITS
 	hex "PE user changeable bits mask"
-	depends on ETRAX_GPIO
+ 	depends on ETRAX_GPIO && ETRAXFS
 	default "0x00000"
 	help
 	  This is a bitmask (18 bits) with information of what bits in PE
 	  that a user can change the value on using ioctl's.
 	  Bit set = changeable.
 
+config ETRAX_PV_CHANGEABLE_DIR
+	hex "PV user changeable dir mask"
+	depends on ETRAX_VIRTUAL_GPIO
+	default "0x0000"
+	help
+	  This is a bitmask (16 bits) with information of what bits in PV
+	  that a user can change direction on using ioctl's.
+	  Bit set = changeable.
+	  You probably want 0x0000 here, but it depends on your hardware.
+
+config ETRAX_PV_CHANGEABLE_BITS
+	hex "PV user changeable bits mask"
+	depends on ETRAX_VIRTUAL_GPIO
+	default "0x0000"
+	help
+	  This is a bitmask (16 bits) with information of what bits in PV
+	  that a user can change the value on using ioctl's.
+	  Bit set = changeable.
+
 config ETRAX_CARDBUS
         bool "Cardbus support"
         depends on ETRAX_ARCH_V32
-        select PCCARD
-        select CARDBUS
         select HOTPLUG
-        select PCCARD_NONSTATIC
         help
 	 Enabled the ETRAX Cardbus driver.
 
@@ -613,4 +656,202 @@ config ETRAX_STREAMCOPROC
 	  This option enables a driver for the stream co-processor
 	  for cryptographic operations.
 
+source drivers/mmc/Kconfig
+
+config ETRAX_MMC_IOP
+	tristate "MMC/SD host driver using IO-processor"
+	depends on ETRAX_ARCH_V32 && MMC
+	help
+	  This option enables the SD/MMC host controller interface.
+	  The host controller is implemented using the built in
+	  IO-Processor. Only the SPU is used in this implementation.
+
+config ETRAX_SPI_MMC
+# Make this one of several "choices" (possible simultaneously but
+# suggested uniquely) when an IOP driver emerges for "real" MMC/SD
+# protocol support.
+	tristate
+	depends on !ETRAX_MMC_IOP
+	default MMC
+	select SPI
+	select MMC_SPI
+	select ETRAX_SPI_MMC_BOARD
+
+# For the parts that can't be a module (due to restrictions in
+# framework elsewhere).
+config ETRAX_SPI_MMC_BOARD
+       boolean
+       default n
+
+# While the board info is MMC_SPI only, the drivers are written to be
+# independent of MMC_SPI, so we'll keep SPI non-dependent on the
+# MMC_SPI config choices (well, except for a single depends-on-line
+# for the board-info file until a separate non-MMC SPI board file
+# emerges).
+# FIXME: When that happens, we'll need to be able to ask for and
+# configure non-MMC SPI ports together with MMC_SPI ports (if multiple
+# SPI ports are enabled).
+
+config SPI_ETRAX_SSER
+	tristate
+	depends on SPI_MASTER && ETRAX_ARCH_V32 && EXPERIMENTAL
+	select SPI_BITBANG
+	help
+	  This enables using an synchronous serial (sser) port as a
+	  SPI master controller on Axis ETRAX FS and later.  The
+	  driver can be configured to use any sser port.
+
+config SPI_ETRAX_GPIO
+	tristate
+	depends on SPI_MASTER && ETRAX_ARCH_V32 && EXPERIMENTAL
+	select SPI_BITBANG
+	help
+	  This enables using GPIO pins port as a SPI master controller
+	  on Axis ETRAX FS and later.  The driver can be configured to
+	  use any GPIO pins.
+
+config ETRAX_SPI_SSER0
+	tristate "SPI using synchronous serial port 0 (sser0)"
+	depends on ETRAX_SPI_MMC
+	default m if MMC_SPI=m
+	default y if MMC_SPI=y
+	default y if MMC_SPI=n
+	select SPI_ETRAX_SSER
+	help
+	  Say Y for an MMC/SD socket connected to synchronous serial port 0,
+	  or for devices using the SPI protocol on that port.  Say m if you
+	  want to build it as a module, which will be named spi_crisv32_sser.
+	  (You need to select MMC separately.)
+
+config ETRAX_SPI_SSER0_DMA
+	bool "DMA for SPI on sser0 enabled"
+	depends on ETRAX_SPI_SSER0
+	depends on !ETRAX_SERIAL_PORT1_DMA4_OUT && !ETRAX_SERIAL_PORT1_DMA5_IN
+	default y
+	help
+	  Say Y if using DMA (dma4/dma5) for SPI on synchronous serial port 0.
+
+config ETRAX_SPI_MMC_CD_SSER0_PIN
+	string "MMC/SD card detect pin for SPI on sser0"
+	depends on ETRAX_SPI_SSER0 && MMC_SPI
+	default "pd11"
+	help
+	  The pin to use for SD/MMC card detect.  This pin should be pulled up
+	  and grounded when a card is present.  If defined as " " (space), no
+	  pin is selected.  A card must then always be inserted for proper
+	  action.
+
+config ETRAX_SPI_MMC_WP_SSER0_PIN
+	string "MMC/SD card write-protect pin for SPI on sser0"
+	depends on ETRAX_SPI_SSER0 && MMC_SPI
+	default "pd10"
+	help
+	  The pin to use for the SD/MMC write-protect signal for a memory
+	  card.  If defined as " " (space), the card is considered writable.
+
+config ETRAX_SPI_SSER1
+	tristate "SPI using synchronous serial port 1 (sser1)"
+	depends on ETRAX_SPI_MMC
+	default m if MMC_SPI=m && ETRAX_SPI_SSER0=n
+	default y if MMC_SPI=y && ETRAX_SPI_SSER0=n
+	default y if MMC_SPI=n && ETRAX_SPI_SSER0=n
+	select SPI_ETRAX_SSER
+	help
+	  Say Y for an MMC/SD socket connected to synchronous serial port 1,
+	  or for devices using the SPI protocol on that port.  Say m if you
+	  want to build it as a module, which will be named spi_crisv32_sser.
+	  (You need to select MMC separately.)
+
+config ETRAX_SPI_SSER1_DMA
+	bool "DMA for SPI on sser1 enabled"
+	depends on ETRAX_SPI_SSER1 && !ETRAX_ETHERNET_IFACE1
+	depends on !ETRAX_SERIAL_PORT0_DMA6_OUT && !ETRAX_SERIAL_PORT0_DMA7_IN
+	default y
+	help
+	  Say Y if using DMA (dma6/dma7) for SPI on synchronous serial port 1.
+
+config ETRAX_SPI_MMC_CD_SSER1_PIN
+	string "MMC/SD card detect pin for SPI on sser1"
+	depends on ETRAX_SPI_SSER1 && MMC_SPI
+	default "pd12"
+	help
+	  The pin to use for SD/MMC card detect.  This pin should be pulled up
+	  and grounded when a card is present.  If defined as " " (space), no
+	  pin is selected.  A card must then always be inserted for proper
+	  action.
+
+config ETRAX_SPI_MMC_WP_SSER1_PIN
+	string "MMC/SD card write-protect pin for SPI on sser1"
+	depends on ETRAX_SPI_SSER1 && MMC_SPI
+	default "pd9"
+	help
+	  The pin to use for the SD/MMC write-protect signal for a memory
+	  card.  If defined as " " (space), the card is considered writable.
+
+config ETRAX_SPI_GPIO
+	tristate "Bitbanged SPI using gpio pins"
+	depends on ETRAX_SPI_MMC
+	select SPI_ETRAX_GPIO
+	default m if MMC_SPI=m && ETRAX_SPI_SSER0=n && ETRAX_SPI_SSER1=n
+	default y if MMC_SPI=y && ETRAX_SPI_SSER0=n && ETRAX_SPI_SSER1=n
+	default y if MMC_SPI=n && ETRAX_SPI_SSER0=n && ETRAX_SPI_SSER1=n
+	help
+	  Say Y for an MMC/SD socket connected to general I/O pins (but not
+	  a complete synchronous serial ports), or for devices using the SPI
+	  protocol on general I/O pins.  Slow and slows down the system.
+	  Say m to build it as a module, which will be called spi_crisv32_gpio.
+	  (You need to select MMC separately.)
+
+# The default match that of sser0, only because that's how it was tested.
+config ETRAX_SPI_CS_PIN
+	string "SPI chip select pin"
+	depends on ETRAX_SPI_GPIO
+	default "pc3"
+	help
+	  The pin to use for SPI chip select.
+
+config ETRAX_SPI_CLK_PIN
+	string "SPI clock pin"
+	depends on ETRAX_SPI_GPIO
+	default "pc1"
+	help
+	  The pin to use for the SPI clock.
+
+config ETRAX_SPI_DATAIN_PIN
+	string "SPI MISO (data in) pin"
+	depends on ETRAX_SPI_GPIO
+	default "pc16"
+	help
+	  The pin to use for SPI data in from the device.
+
+config ETRAX_SPI_DATAOUT_PIN
+	string "SPI MOSI (data out) pin"
+	depends on ETRAX_SPI_GPIO
+	default "pc0"
+	help
+	  The pin to use for SPI data out to the device.
+
+config ETRAX_SPI_MMC_CD_GPIO_PIN
+	string "MMC/SD card detect pin for SPI using gpio (space for none)"
+	depends on ETRAX_SPI_GPIO && MMC_SPI
+	default "pd11"
+	help
+	  The pin to use for SD/MMC card detect.  This pin should be pulled up
+	  and grounded when a card is present.  If defined as " " (space), no
+	  pin is selected.  A card must then always be inserted for proper
+	  action.
+
+config ETRAX_SPI_MMC_WP_GPIO_PIN
+	string "MMC/SD card write-protect pin for SPI using gpio (space for none)"
+	depends on ETRAX_SPI_GPIO && MMC_SPI
+	default "pd10"
+	help
+	  The pin to use for the SD/MMC write-protect signal for a memory
+	  card.  If defined as " " (space), the card is considered writable.
+
+# Avoid choices causing non-working configs by conditionalizing the inclusion.
+if ETRAX_SPI_MMC
+source drivers/spi/Kconfig
+endif
+
 endif
diff --git a/arch/cris/arch-v32/drivers/Makefile b/arch/cris/arch-v32/drivers/Makefile
index a359cd20ae75..e8c02437edaf 100644
--- a/arch/cris/arch-v32/drivers/Makefile
+++ b/arch/cris/arch-v32/drivers/Makefile
@@ -4,10 +4,11 @@
 
 obj-$(CONFIG_ETRAX_STREAMCOPROC)        += cryptocop.o
 obj-$(CONFIG_ETRAX_AXISFLASHMAP)        += axisflashmap.o
-obj-$(CONFIG_ETRAX_NANDFLASH)           += nandflash.o
-obj-$(CONFIG_ETRAX_GPIO) 	        += gpio.o
+obj-$(CONFIG_ETRAXFS)                   += mach-fs/
+obj-$(CONFIG_CRIS_MACH_ARTPEC3)         += mach-a3/
 obj-$(CONFIG_ETRAX_IOP_FW_LOAD)         += iop_fw_load.o
 obj-$(CONFIG_ETRAX_PCF8563)		+= pcf8563.o
 obj-$(CONFIG_ETRAX_I2C)			+= i2c.o
 obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL)	+= sync_serial.o
 obj-$(CONFIG_PCI)			+= pci/
+obj-$(CONFIG_ETRAX_SPI_MMC_BOARD)	+= board_mmcspi.o
diff --git a/arch/cris/arch-v32/drivers/axisflashmap.c b/arch/cris/arch-v32/drivers/axisflashmap.c
index c5ff95e18269..51e1e85df96d 100644
--- a/arch/cris/arch-v32/drivers/axisflashmap.c
+++ b/arch/cris/arch-v32/drivers/axisflashmap.c
@@ -1,7 +1,7 @@
 /*
  * Physical mapping layer for MTD using the Axis partitiontable format
  *
- * Copyright (c) 2001, 2002, 2003 Axis Communications AB
+ * Copyright (c) 2001-2007 Axis Communications AB
  *
  * This file is under the GPL.
  *
@@ -10,9 +10,6 @@
  * tells us what other partitions to define. If there isn't, we use a default
  * partition split defined below.
  *
- * Copy of os/lx25/arch/cris/arch-v10/drivers/axisflashmap.c 1.5
- * with minor changes.
- *
  */
 
 #include <linux/module.h>
@@ -27,7 +24,8 @@
 #include <linux/mtd/mtdram.h>
 #include <linux/mtd/partitions.h>
 
-#include <asm/arch/hwregs/config_defs.h>
+#include <linux/cramfs_fs.h>
+
 #include <asm/axisflashmap.h>
 #include <asm/mmu.h>
 
@@ -37,16 +35,24 @@
 #define FLASH_UNCACHED_ADDR  KSEG_E
 #define FLASH_CACHED_ADDR    KSEG_F
 
+#define PAGESIZE (512)
+
 #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
+#define flash_data __u32
 #endif
 
 /* From head.S */
-extern unsigned long romfs_start, romfs_length, romfs_in_flash;
+extern unsigned long romfs_in_flash; /* 1 when romfs_start, _length in flash */
+extern unsigned long romfs_start, romfs_length;
+extern unsigned long nand_boot; /* 1 when booted from nand flash */
+
+struct partition_name {
+	char name[6];
+};
 
 /* The master mtd for the entire flash. */
 struct mtd_info* axisflash_mtd = NULL;
@@ -112,32 +118,20 @@ static struct map_info map_cse1 = {
 	.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
+#define MAX_PARTITIONS			7
+#ifdef CONFIG_ETRAX_NANDBOOT
+#define NUM_DEFAULT_PARTITIONS		4
+#define DEFAULT_ROOTFS_PARTITION_NO	2
+#define DEFAULT_MEDIA_SIZE              0x2000000 /* 32 megs */
+#else
+#define NUM_DEFAULT_PARTITIONS		3
+#define DEFAULT_ROOTFS_PARTITION_NO	(-1)
+#define DEFAULT_MEDIA_SIZE              0x800000 /* 8 megs */
+#endif
 
-/*
- * 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)
-	}
-};
+#if (MAX_PARTITIONS < NUM_DEFAULT_PARTITIONS)
+#error MAX_PARTITIONS must be >= than NUM_DEFAULT_PARTITIONS
+#endif
 
 /* Initialize the ones normally used. */
 static struct mtd_partition axis_partitions[MAX_PARTITIONS] = {
@@ -178,6 +172,56 @@ static struct mtd_partition axis_partitions[MAX_PARTITIONS] = {
 	},
 };
 
+
+/* If no partition-table was found, we use this default-set.
+ * Default flash size is 8MB (NOR). CONFIG_ETRAX_PTABLE_SECTOR is most
+ * likely the size of one flash block and "filesystem"-partition needs
+ * to be >=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 = 10 * CONFIG_ETRAX_PTABLE_SECTOR,
+		.offset = CONFIG_ETRAX_PTABLE_SECTOR
+	},
+#define FILESYSTEM_SECTOR (11 * CONFIG_ETRAX_PTABLE_SECTOR)
+#ifdef CONFIG_ETRAX_NANDBOOT
+	{
+		.name = "rootfs",
+		.size = 10 * CONFIG_ETRAX_PTABLE_SECTOR,
+		.offset = FILESYSTEM_SECTOR
+	},
+#undef FILESYSTEM_SECTOR
+#define FILESYSTEM_SECTOR (21 * CONFIG_ETRAX_PTABLE_SECTOR)
+#endif
+	{
+		.name = "rwfs",
+		.size = DEFAULT_MEDIA_SIZE - FILESYSTEM_SECTOR,
+		.offset = FILESYSTEM_SECTOR
+	}
+};
+
+#ifdef CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE
+/* Main flash device */
+static struct mtd_partition main_partition = {
+	.name = "main",
+	.size = 0,
+	.offset = 0
+};
+#endif
+
+/* Auxilliary partition if we find another flash */
+static struct mtd_partition aux_partition = {
+	.name = "aux",
+	.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).
@@ -191,7 +235,7 @@ static struct mtd_info *probe_cs(struct map_info *map_cs)
 	       map_cs->name, map_cs->size, map_cs->map_priv_1);
 
 #ifdef CONFIG_MTD_CFI
-		mtd_cs = do_map_probe("cfi_probe", map_cs);
+	mtd_cs = do_map_probe("cfi_probe", map_cs);
 #endif
 #ifdef CONFIG_MTD_JEDECPROBE
 	if (!mtd_cs)
@@ -204,7 +248,7 @@ static struct mtd_info *probe_cs(struct map_info *map_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 boundaries.
+ * 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
@@ -216,9 +260,8 @@ static struct mtd_info *flash_probe(void)
 {
 	struct mtd_info *mtd_cse0;
 	struct mtd_info *mtd_cse1;
-	struct mtd_info *mtd_nand = NULL;
 	struct mtd_info *mtd_total;
-	struct mtd_info *mtds[3];
+	struct mtd_info *mtds[2];
 	int count = 0;
 
 	if ((mtd_cse0 = probe_cs(&map_cse0)) != NULL)
@@ -226,12 +269,7 @@ static struct mtd_info *flash_probe(void)
 	if ((mtd_cse1 = probe_cs(&map_cse1)) != NULL)
 		mtds[count++] = mtd_cse1;
 
-#ifdef CONFIG_ETRAX_NANDFLASH
-	if ((mtd_nand = crisv32_nand_flash_probe()) != NULL)
-		mtds[count++] = mtd_nand;
-#endif
-
-	if (!mtd_cse0 && !mtd_cse1 && !mtd_nand) {
+	if (!mtd_cse0 && !mtd_cse1) {
 		/* No chip found. */
 		return NULL;
 	}
@@ -245,9 +283,7 @@ static struct mtd_info *flash_probe(void)
 		 * So we use the MTD concatenation layer instead of further
 		 * complicating the probing procedure.
 		 */
-		mtd_total = mtd_concat_create(mtds,
-		                              count,
-		                              "cse0+cse1+nand");
+		mtd_total = mtd_concat_create(mtds, count, "cse0+cse1");
 #else
 		printk(KERN_ERR "%s and %s: Cannot concatenate due to kernel "
 		       "(mis)configuration!\n", map_cse0.name, map_cse1.name);
@@ -255,61 +291,162 @@ static struct mtd_info *flash_probe(void)
 #endif
 		if (!mtd_total) {
 			printk(KERN_ERR "%s and %s: Concatenation failed!\n",
-			       map_cse0.name, map_cse1.name);
+				map_cse0.name, map_cse1.name);
 
 			/* The best we can do now is to only use what we found
-			 * at cse0.
-			 */
+			 * at cse0. */
 			mtd_total = mtd_cse0;
 			map_destroy(mtd_cse1);
 		}
-	} else {
-		mtd_total = mtd_cse0? mtd_cse0 : mtd_cse1 ? mtd_cse1 : mtd_nand;
-
-	}
+	} else
+		mtd_total = mtd_cse0 ? mtd_cse0 : mtd_cse1;
 
 	return mtd_total;
 }
 
-extern unsigned long crisv32_nand_boot;
-extern unsigned long crisv32_nand_cramfs_offset;
-
 /*
  * 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;
+	struct mtd_info *main_mtd;
+	struct mtd_info *aux_mtd = NULL;
 	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 = KERN_INFO "  /dev/flash%d at 0x%08x, size 0x%08x\n";
-	static char page[512];
+	int ptable_ok = 0;
+	static char page[PAGESIZE];
 	size_t len;
+	int ram_rootfs_partition = -1; /* -1 => no RAM rootfs partition */
+	int part;
+
+	/* We need a root fs. If it resides in RAM, we need to use an
+	 * MTDRAM device, so it must be enabled in the kernel config,
+	 * but its size must be configured as 0 so as not to conflict
+	 * with our usage.
+	 */
+#if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0)
+	if (!romfs_in_flash && !nand_boot) {
+		printk(KERN_EMERG "axisflashmap: Cannot create an MTD RAM "
+		       "device; configure CONFIG_MTD_MTDRAM with size = 0!\n");
+		panic("This kernel cannot boot from RAM!\n");
+	}
+#endif
+
+#ifndef CONFIG_ETRAX_VCS_SIM
+	main_mtd = flash_probe();
+	if (main_mtd)
+		printk(KERN_INFO "%s: 0x%08x bytes of NOR flash memory.\n",
+		       main_mtd->name, main_mtd->size);
+
+#ifdef CONFIG_ETRAX_NANDFLASH
+	aux_mtd = crisv32_nand_flash_probe();
+	if (aux_mtd)
+		printk(KERN_INFO "%s: 0x%08x bytes of NAND flash memory.\n",
+			aux_mtd->name, aux_mtd->size);
+
+#ifdef CONFIG_ETRAX_NANDBOOT
+	{
+		struct mtd_info *tmp_mtd;
 
-#ifndef CONFIG_ETRAXFS_SIM
-	mymtd = flash_probe();
-	mymtd->read(mymtd, CONFIG_ETRAX_PTABLE_SECTOR, 512, &len, page);
-	ptable_head = (struct partitiontable_head *)(page + PARTITION_TABLE_OFFSET);
+		printk(KERN_INFO "axisflashmap: Set to boot from NAND flash, "
+		       "making NAND flash primary device.\n");
+		tmp_mtd = main_mtd;
+		main_mtd = aux_mtd;
+		aux_mtd = tmp_mtd;
+	}
+#endif /* CONFIG_ETRAX_NANDBOOT */
+#endif /* CONFIG_ETRAX_NANDFLASH */
 
-	if (!mymtd) {
+	if (!main_mtd && !aux_mtd) {
 		/* 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;
+#if 0 /* Dump flash memory so we can see what is going on */
+	if (main_mtd) {
+		int sectoraddr, i;
+		for (sectoraddr = 0; sectoraddr < 2*65536+4096;
+				sectoraddr += PAGESIZE) {
+			main_mtd->read(main_mtd, sectoraddr, PAGESIZE, &len,
+				page);
+			printk(KERN_INFO
+			       "Sector at %d (length %d):\n",
+			       sectoraddr, len);
+			for (i = 0; i < PAGESIZE; i += 16) {
+				printk(KERN_INFO
+				       "%02x %02x %02x %02x "
+				       "%02x %02x %02x %02x "
+				       "%02x %02x %02x %02x "
+				       "%02x %02x %02x %02x\n",
+				       page[i] & 255, page[i+1] & 255,
+				       page[i+2] & 255, page[i+3] & 255,
+				       page[i+4] & 255, page[i+5] & 255,
+				       page[i+6] & 255, page[i+7] & 255,
+				       page[i+8] & 255, page[i+9] & 255,
+				       page[i+10] & 255, page[i+11] & 255,
+				       page[i+12] & 255, page[i+13] & 255,
+				       page[i+14] & 255, page[i+15] & 255);
+			}
+		}
+	}
+#endif
+
+	if (main_mtd) {
+		main_mtd->owner = THIS_MODULE;
+		axisflash_mtd = main_mtd;
+
+		loff_t ptable_sector = CONFIG_ETRAX_PTABLE_SECTOR;
+
+		/* First partition (rescue) is always set to the default. */
+		pidx++;
+#ifdef CONFIG_ETRAX_NANDBOOT
+		/* We know where the partition table should be located,
+		 * it will be in first good block after that.
+		 */
+		int blockstat;
+		do {
+			blockstat = main_mtd->block_isbad(main_mtd,
+				ptable_sector);
+			if (blockstat < 0)
+				ptable_sector = 0; /* read error */
+			else if (blockstat)
+				ptable_sector += main_mtd->erasesize;
+		} while (blockstat && ptable_sector);
+#endif
+		if (ptable_sector) {
+			main_mtd->read(main_mtd, ptable_sector, PAGESIZE,
+				&len, page);
+			ptable_head = &((struct partitiontable *) page)->head;
+		}
+
+#if 0 /* Dump partition table so we can see what is going on */
+		printk(KERN_INFO
+		       "axisflashmap: flash read %d bytes at 0x%08x, data: "
+		       "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+		       len, CONFIG_ETRAX_PTABLE_SECTOR,
+		       page[0] & 255, page[1] & 255,
+		       page[2] & 255, page[3] & 255,
+		       page[4] & 255, page[5] & 255,
+		       page[6] & 255, page[7] & 255);
+		printk(KERN_INFO
+		       "axisflashmap: partition table offset %d, data: "
+		       "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+		       PARTITION_TABLE_OFFSET,
+		       page[PARTITION_TABLE_OFFSET+0] & 255,
+		       page[PARTITION_TABLE_OFFSET+1] & 255,
+		       page[PARTITION_TABLE_OFFSET+2] & 255,
+		       page[PARTITION_TABLE_OFFSET+3] & 255,
+		       page[PARTITION_TABLE_OFFSET+4] & 255,
+		       page[PARTITION_TABLE_OFFSET+5] & 255,
+		       page[PARTITION_TABLE_OFFSET+6] & 255,
+		       page[PARTITION_TABLE_OFFSET+7] & 255);
+#endif
 	}
-	pidx++;  /* First partition is always set to the default. */
 
 	if (ptable_head && (ptable_head->magic == PARTITION_TABLE_MAGIC)
 	    && (ptable_head->size <
@@ -322,7 +459,6 @@ static int __init init_axis_flash(void)
 		/* 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) +
@@ -346,104 +482,170 @@ static int __init init_axis_flash(void)
 		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",
+		printk(KERN_INFO "axisflashmap: "
+		       "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.
+		 * partition table.  Scan the table.  It ends with 0xffffffff.
 		 */
 		while (ptable_ok
-		       && ptable->offset != 0xffffffff
+		       && ptable->offset != PARTITIONTABLE_END_MARKER
 		       && ptable < max_addr
-		       && pidx < MAX_PARTITIONS) {
+		       && pidx < MAX_PARTITIONS - 1) {
 
-			axis_partitions[pidx].offset = offset + ptable->offset + (crisv32_nand_boot ? 16384 : 0);
-			axis_partitions[pidx].size = ptable->size;
-
-			printk(pmsg, pidx, axis_partitions[pidx].offset,
-			       axis_partitions[pidx].size);
+			axis_partitions[pidx].offset = offset + ptable->offset;
+#ifdef CONFIG_ETRAX_NANDFLASH
+			if (main_mtd->type == MTD_NANDFLASH) {
+				axis_partitions[pidx].size =
+					(((ptable+1)->offset ==
+					  PARTITIONTABLE_END_MARKER) ?
+					  main_mtd->size :
+					  ((ptable+1)->offset + offset)) -
+					(ptable->offset + offset);
+
+			} else
+#endif /* CONFIG_ETRAX_NANDFLASH */
+				axis_partitions[pidx].size = ptable->size;
+#ifdef CONFIG_ETRAX_NANDBOOT
+			/* Save partition number of jffs2 ro partition.
+			 * Needed if RAM booting or root file system in RAM.
+			 */
+			if (!nand_boot &&
+			    ram_rootfs_partition < 0 && /* not already set */
+			    ptable->type == PARTITION_TYPE_JFFS2 &&
+			    (ptable->flags & PARTITION_FLAGS_READONLY_MASK) ==
+				PARTITION_FLAGS_READONLY)
+				ram_rootfs_partition = pidx;
+#endif /* CONFIG_ETRAX_NANDBOOT */
 			pidx++;
 			ptable++;
 		}
-		use_default_ptable = !ptable_ok;
 	}
 
-	if (romfs_in_flash) {
-		/* Add an overlapping device for the root partition (romfs). */
+	/* Decide whether to use default partition table. */
+	/* Only use default table if we actually have a device (main_mtd) */
 
-		axis_partitions[pidx].name = "romfs";
-		if (crisv32_nand_boot) {
-			char* data = kmalloc(1024, GFP_KERNEL);
-			int len;
-			int offset = crisv32_nand_cramfs_offset & ~(1024-1);
-			char* tmp;
-
-			mymtd->read(mymtd, offset, 1024, &len, data);
-			tmp = &data[crisv32_nand_cramfs_offset % 512];
-			axis_partitions[pidx].size = *(unsigned*)(tmp + 4);
-			axis_partitions[pidx].offset = crisv32_nand_cramfs_offset;
-			kfree(data);
-		} else {
-			axis_partitions[pidx].size = romfs_length;
-			axis_partitions[pidx].offset = romfs_start - FLASH_CACHED_ADDR;
-		}
+	struct mtd_partition *partition = &axis_partitions[0];
+	if (main_mtd && !ptable_ok) {
+		memcpy(axis_partitions, axis_default_partitions,
+		       sizeof(axis_default_partitions));
+		pidx = NUM_DEFAULT_PARTITIONS;
+		ram_rootfs_partition = DEFAULT_ROOTFS_PARTITION_NO;
+	}
 
+	/* Add artificial partitions for rootfs if necessary */
+	if (romfs_in_flash) {
+		/* rootfs is in directly accessible flash memory = NOR flash.
+		   Add an overlapping device for the rootfs partition. */
+		printk(KERN_INFO "axisflashmap: Adding partition for "
+		       "overlapping root file system image\n");
+		axis_partitions[pidx].size = romfs_length;
+		axis_partitions[pidx].offset = romfs_start - FLASH_CACHED_ADDR;
+		axis_partitions[pidx].name = "romfs";
 		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);
+		ram_rootfs_partition = -1;
 		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);
+	} else if (romfs_length && !nand_boot) {
+		/* romfs exists in memory, but not in flash, so must be in RAM.
+		 * Configure an MTDRAM partition. */
+		if (ram_rootfs_partition < 0) {
+			/* None set yet, put it at the end */
+			ram_rootfs_partition = pidx;
+			pidx++;
 		}
+		printk(KERN_INFO "axisflashmap: Adding partition for "
+		       "root file system image in RAM\n");
+		axis_partitions[ram_rootfs_partition].size = romfs_length;
+		axis_partitions[ram_rootfs_partition].offset = romfs_start;
+		axis_partitions[ram_rootfs_partition].name = "romfs";
+		axis_partitions[ram_rootfs_partition].mask_flags |=
+			MTD_WRITEABLE;
+	}
 
-		if (err) {
-			panic("axisflashmap could not add MTD partitions!\n");
-		}
+#ifdef CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE
+	if (main_mtd) {
+		main_partition.size = main_mtd->size;
+		err = add_mtd_partitions(main_mtd, &main_partition, 1);
+		if (err)
+			panic("axisflashmap: Could not initialize "
+			      "partition for whole main mtd device!\n");
 	}
-/* CONFIG_EXTRAXFS_SIM */
 #endif
 
-	if (!romfs_in_flash) {
-		/* Create an RAM device for the root partition (romfs). */
+	/* Now, register all partitions with mtd.
+	 * We do this one at a time so we can slip in an MTDRAM device
+	 * in the proper place if required. */
+
+	for (part = 0; part < pidx; part++) {
+		if (part == ram_rootfs_partition) {
+			/* add MTDRAM partition here */
+			struct mtd_info *mtd_ram;
+
+			mtd_ram = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+			if (!mtd_ram)
+				panic("axisflashmap: Couldn't allocate memory "
+				      "for mtd_info!\n");
+			printk(KERN_INFO "axisflashmap: Adding RAM partition "
+			       "for rootfs image.\n");
+			err = mtdram_init_device(mtd_ram,
+						 (void *)partition[part].offset,
+						 partition[part].size,
+						 partition[part].name);
+			if (err)
+				panic("axisflashmap: Could not initialize "
+				      "MTD RAM device!\n");
+			/* JFFS2 likes to have an erasesize. Keep potential
+			 * JFFS2 rootfs happy by providing one. Since image
+			 * was most likely created for main mtd, use that
+			 * erasesize, if available. Otherwise, make a guess. */
+			mtd_ram->erasesize = (main_mtd ? main_mtd->erasesize :
+				CONFIG_ETRAX_PTABLE_SECTOR);
+		} else {
+			err = add_mtd_partitions(main_mtd, &partition[part], 1);
+			if (err)
+				panic("axisflashmap: Could not add mtd "
+					"partition %d\n", part);
+		}
+	}
+#endif /* CONFIG_EXTRAX_VCS_SIM */
+
+#ifdef CONFIG_ETRAX_VCS_SIM
+	/* For simulator, always use a RAM partition.
+	 * The rootfs will be found after the kernel in RAM,
+	 * with romfs_start and romfs_end indicating location and size.
+	 */
+	struct mtd_info *mtd_ram;
+
+	mtd_ram = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+	if (!mtd_ram) {
+		panic("axisflashmap: Couldn't allocate memory for "
+		      "mtd_info!\n");
+	}
 
-#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;
+	printk(KERN_INFO "axisflashmap: Adding RAM partition for romfs, "
+	       "at %u, size %u\n",
+	       (unsigned) romfs_start, (unsigned) romfs_length);
 
-		mtd_ram = kmalloc(sizeof(struct mtd_info),
-						     GFP_KERNEL);
-		if (!mtd_ram) {
-			panic("axisflashmap couldn't allocate memory for "
-			      "mtd_info!\n");
-		}
+	err = mtdram_init_device(mtd_ram, (void *)romfs_start,
+				 romfs_length, "romfs");
+	if (err) {
+		panic("axisflashmap: Could not initialize MTD RAM "
+		      "device!\n");
+	}
+#endif /* CONFIG_EXTRAX_VCS_SIM */
 
-		printk(KERN_INFO " Adding RAM partition for romfs image:\n");
-		printk(pmsg, pidx, romfs_start, romfs_length);
+#ifndef CONFIG_ETRAX_VCS_SIM
+	if (aux_mtd) {
+		aux_partition.size = aux_mtd->size;
+		err = add_mtd_partitions(aux_mtd, &aux_partition, 1);
+		if (err)
+			panic("axisflashmap: Could not initialize "
+			      "aux mtd device!\n");
 
-		err = mtdram_init_device(mtd_ram, (void*)romfs_start,
-		                         romfs_length, "romfs");
-		if (err) {
-			panic("axisflashmap could not initialize MTD RAM "
-			      "device!\n");
-		}
-#endif
 	}
+#endif /* CONFIG_EXTRAX_VCS_SIM */
 
 	return err;
 }
diff --git a/arch/cris/arch-v32/drivers/cryptocop.c b/arch/cris/arch-v32/drivers/cryptocop.c
index e8914d401696..9fb58202be99 100644
--- a/arch/cris/arch-v32/drivers/cryptocop.c
+++ b/arch/cris/arch-v32/drivers/cryptocop.c
@@ -1,8 +1,7 @@
-/* $Id: cryptocop.c,v 1.13 2005/04/21 17:27:55 henriken Exp $
- *
+/*
  * Stream co-processor driver for the ETRAX FS
  *
- *    Copyright (C) 2003-2005  Axis Communications AB
+ *    Copyright (C) 2003-2007  Axis Communications AB
  */
 
 #include <linux/init.h>
@@ -25,17 +24,29 @@
 #include <asm/signal.h>
 #include <asm/irq.h>
 
-#include <asm/arch/dma.h>
-#include <asm/arch/hwregs/dma.h>
-#include <asm/arch/hwregs/reg_map.h>
-#include <asm/arch/hwregs/reg_rdwr.h>
-#include <asm/arch/hwregs/intr_vect_defs.h>
-
-#include <asm/arch/hwregs/strcop.h>
-#include <asm/arch/hwregs/strcop_defs.h>
-#include <asm/arch/cryptocop.h>
-
-
+#include <dma.h>
+#include <hwregs/dma.h>
+#include <hwregs/reg_map.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/intr_vect_defs.h>
+
+#include <hwregs/strcop.h>
+#include <hwregs/strcop_defs.h>
+#include <cryptocop.h>
+
+#ifdef CONFIG_ETRAXFS
+#define IN_DMA 9
+#define OUT_DMA 8
+#define IN_DMA_INST regi_dma9
+#define OUT_DMA_INST regi_dma8
+#define DMA_IRQ DMA9_INTR_VECT
+#else
+#define IN_DMA 3
+#define OUT_DMA 2
+#define IN_DMA_INST regi_dma3
+#define OUT_DMA_INST regi_dma2
+#define DMA_IRQ DMA3_INTR_VECT
+#endif
 
 #define DESCR_ALLOC_PAD  (31)
 
@@ -1886,14 +1897,14 @@ static void cryptocop_do_tasklet(unsigned long unused)
 }
 
 static irqreturn_t
-dma_done_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+dma_done_interrupt(int irq, void *dev_id)
 {
 	struct cryptocop_prio_job *done_job;
 	reg_dma_rw_ack_intr ack_intr = {
 		.data = 1,
 	};
 
-	REG_WR (dma, regi_dma9, rw_ack_intr, ack_intr);
+	REG_WR(dma, IN_DMA_INST, rw_ack_intr, ack_intr);
 
 	DEBUG(printk("cryptocop DMA done\n"));
 
@@ -1937,7 +1948,6 @@ dma_done_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 static int init_cryptocop(void)
 {
 	unsigned long          flags;
-	reg_intr_vect_rw_mask  intr_mask;
 	reg_dma_rw_cfg         dma_cfg = {.en = 1};
 	reg_dma_rw_intr_mask   intr_mask_in = {.data = regk_dma_yes}; /* Only want descriptor interrupts from the DMA in channel. */
 	reg_dma_rw_ack_intr    ack_intr = {.data = 1,.in_eop = 1 };
@@ -1950,10 +1960,14 @@ static int init_cryptocop(void)
 		.en = 1
 	};
 
-	if (request_irq(DMA9_INTR_VECT, dma_done_interrupt, 0, "stream co-processor DMA", NULL)) panic("request_irq stream co-processor irq dma9");
+	if (request_irq(DMA_IRQ, dma_done_interrupt, 0,
+			"stream co-processor DMA", NULL))
+		panic("request_irq stream co-processor irq dma9");
 
-	(void)crisv32_request_dma(8, "strcop", DMA_PANIC_ON_ERROR, 0, dma_strp);
-	(void)crisv32_request_dma(9, "strcop", DMA_PANIC_ON_ERROR, 0, dma_strp);
+	(void)crisv32_request_dma(OUT_DMA, "strcop", DMA_PANIC_ON_ERROR,
+		0, dma_strp);
+	(void)crisv32_request_dma(IN_DMA, "strcop", DMA_PANIC_ON_ERROR,
+		0, dma_strp);
 
 	local_irq_save(flags);
 
@@ -1963,24 +1977,19 @@ static int init_cryptocop(void)
 	strcop_cfg.en = 1;
 	REG_WR(strcop, regi_strcop, rw_cfg, strcop_cfg);
 
-	/* Enable DMA9 interrupt */
-	intr_mask = REG_RD(intr_vect, regi_irq, rw_mask);
-	intr_mask.dma9 = 1;
-	REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
-
 	/* Enable DMAs. */
-	REG_WR(dma, regi_dma9, rw_cfg, dma_cfg); /* input DMA */
-	REG_WR(dma, regi_dma8, rw_cfg, dma_cfg); /* output DMA */
+	REG_WR(dma, IN_DMA_INST, rw_cfg, dma_cfg); /* input DMA */
+	REG_WR(dma, OUT_DMA_INST, rw_cfg, dma_cfg); /* output DMA */
 
 	/* Set up wordsize = 4 for DMAs. */
-	DMA_WR_CMD (regi_dma8, regk_dma_set_w_size4);
-	DMA_WR_CMD (regi_dma9, regk_dma_set_w_size4);
+	DMA_WR_CMD(OUT_DMA_INST, regk_dma_set_w_size4);
+	DMA_WR_CMD(IN_DMA_INST, regk_dma_set_w_size4);
 
 	/* Enable interrupts. */
-	REG_WR(dma, regi_dma9, rw_intr_mask, intr_mask_in);
+	REG_WR(dma, IN_DMA_INST, rw_intr_mask, intr_mask_in);
 
 	/* Clear intr ack. */
-	REG_WR(dma, regi_dma9, rw_ack_intr, ack_intr);
+	REG_WR(dma, IN_DMA_INST, rw_ack_intr, ack_intr);
 
 	local_irq_restore(flags);
 
@@ -1991,7 +2000,6 @@ static int init_cryptocop(void)
 static void release_cryptocop(void)
 {
 	unsigned long          flags;
-	reg_intr_vect_rw_mask  intr_mask;
 	reg_dma_rw_cfg         dma_cfg = {.en = 0};
 	reg_dma_rw_intr_mask   intr_mask_in = {0};
 	reg_dma_rw_ack_intr    ack_intr = {.data = 1,.in_eop = 1 };
@@ -1999,26 +2007,21 @@ static void release_cryptocop(void)
 	local_irq_save(flags);
 
 	/* Clear intr ack. */
-	REG_WR(dma, regi_dma9, rw_ack_intr, ack_intr);
-
-	/* Disable DMA9 interrupt */
-	intr_mask = REG_RD(intr_vect, regi_irq, rw_mask);
-	intr_mask.dma9 = 0;
-	REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
+	REG_WR(dma, IN_DMA_INST, rw_ack_intr, ack_intr);
 
 	/* Disable DMAs. */
-	REG_WR(dma, regi_dma9, rw_cfg, dma_cfg); /* input DMA */
-	REG_WR(dma, regi_dma8, rw_cfg, dma_cfg); /* output DMA */
+	REG_WR(dma, IN_DMA_INST, rw_cfg, dma_cfg); /* input DMA */
+	REG_WR(dma, OUT_DMA_INST, rw_cfg, dma_cfg); /* output DMA */
 
 	/* Disable interrupts. */
-	REG_WR(dma, regi_dma9, rw_intr_mask, intr_mask_in);
+	REG_WR(dma, IN_DMA_INST, rw_intr_mask, intr_mask_in);
 
 	local_irq_restore(flags);
 
-	free_irq(DMA9_INTR_VECT, NULL);
+	free_irq(DMA_IRQ, NULL);
 
-	(void)crisv32_free_dma(8);
-	(void)crisv32_free_dma(9);
+	(void)crisv32_free_dma(OUT_DMA);
+	(void)crisv32_free_dma(IN_DMA);
 }
 
 
@@ -2076,13 +2079,13 @@ static void cryptocop_job_queue_close(void)
 		reg_dma_rw_cfg    dma_out_cfg, dma_in_cfg;
 
 		/* Stop DMA. */
-		dma_out_cfg = REG_RD(dma, regi_dma8, rw_cfg);
+		dma_out_cfg = REG_RD(dma, OUT_DMA_INST, rw_cfg);
 		dma_out_cfg.en = regk_dma_no;
-		REG_WR(dma, regi_dma8, rw_cfg, dma_out_cfg);
+		REG_WR(dma, OUT_DMA_INST, rw_cfg, dma_out_cfg);
 
-		dma_in_cfg = REG_RD(dma, regi_dma9, rw_cfg);
+		dma_in_cfg = REG_RD(dma, IN_DMA_INST, rw_cfg);
 		dma_in_cfg.en = regk_dma_no;
-		REG_WR(dma, regi_dma9, rw_cfg, dma_in_cfg);
+		REG_WR(dma, IN_DMA_INST, rw_cfg, dma_in_cfg);
 
 		/* Disble the cryptocop. */
 		rw_cfg = REG_RD(strcop, regi_strcop, rw_cfg);
@@ -2226,10 +2229,11 @@ static void cryptocop_start_job(void)
 		     &pj->iop->ctx_out, (char*)virt_to_phys(&pj->iop->ctx_out)));
 
 	/* Start input DMA. */
-	DMA_START_CONTEXT(regi_dma9, virt_to_phys(&pj->iop->ctx_in));
+	flush_dma_context(&pj->iop->ctx_in);
+	DMA_START_CONTEXT(IN_DMA_INST, virt_to_phys(&pj->iop->ctx_in));
 
 	/* Start output DMA. */
-	DMA_START_CONTEXT(regi_dma8, virt_to_phys(&pj->iop->ctx_out));
+	DMA_START_CONTEXT(OUT_DMA_INST, virt_to_phys(&pj->iop->ctx_out));
 
 	spin_unlock_irqrestore(&running_job_lock, running_job_flags);
 	DEBUG(printk("cryptocop_start_job: exiting\n"));
diff --git a/arch/cris/arch-v32/drivers/i2c.c b/arch/cris/arch-v32/drivers/i2c.c
index f1edd2e359b2..c2fb7a5c1396 100644
--- a/arch/cris/arch-v32/drivers/i2c.c
+++ b/arch/cris/arch-v32/drivers/i2c.c
@@ -19,10 +19,10 @@
 *!
 *! ---------------------------------------------------------------------------
 *!
-*! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN
+*! (C) Copyright 1999-2007 Axis Communications AB, LUND, SWEDEN
 *!
 *!***************************************************************************/
-/* $Id: i2c.c,v 1.2 2005/05/09 15:29:49 starvik Exp $ */
+
 /****************** INCLUDE FILES SECTION ***********************************/
 
 #include <linux/module.h>
@@ -79,6 +79,8 @@ static const char i2c_name[] = "i2c";
 
 #define i2c_delay(usecs) udelay(usecs)
 
+static DEFINE_SPINLOCK(i2c_lock); /* Protect directions etc */
+
 /****************** VARIABLE SECTION ************************************/
 
 static struct crisv32_iopin cris_i2c_clk;
@@ -252,6 +254,7 @@ i2c_getack(void)
 	 * generate ACK clock pulse
 	 */
 	i2c_clk(I2C_CLOCK_HIGH);
+#if 0
 	/*
 	 * Use PORT PB instead of I2C
 	 * for input. (I2C not working)
@@ -264,6 +267,8 @@ i2c_getack(void)
 	i2c_data(1);
 	i2c_disable();
 	i2c_dir_in();
+#endif
+
 	/*
 	 * now wait for ack
 	 */
@@ -271,11 +276,11 @@ i2c_getack(void)
 	/*
 	 * check for ack
 	 */
-	if(i2c_getbit())
+	if (i2c_getbit())
 		ack = 0;
 	i2c_delay(CLOCK_HIGH_TIME/2);
-	if(!ack){
-		if(!i2c_getbit()) /* receiver pulled SDA low */
+	if (!ack) {
+		if (!i2c_getbit()) /* receiver pulld SDA low */
 			ack = 1;
 		i2c_delay(CLOCK_HIGH_TIME/2);
 	}
@@ -285,6 +290,7 @@ i2c_getack(void)
     * before we enable our output. If we keep data high
     * and enable output, we would generate a stop condition.
     */
+#if 0
    i2c_data(I2C_DATA_LOW);
 
 	/*
@@ -292,6 +298,7 @@ i2c_getack(void)
 	 */
 	i2c_enable();
 	i2c_dir_out();
+#endif
 	i2c_clk(I2C_CLOCK_LOW);
 	i2c_delay(CLOCK_HIGH_TIME/4);
 	/*
@@ -375,6 +382,121 @@ i2c_sendnack(void)
 
 /*#---------------------------------------------------------------------------
 *#
+*# FUNCTION NAME: i2c_write
+*#
+*# DESCRIPTION  : Writes a value to an I2C device
+*#
+*#--------------------------------------------------------------------------*/
+int
+i2c_write(unsigned char theSlave, void *data, size_t nbytes)
+{
+	int error, cntr = 3;
+	unsigned char bytes_wrote = 0;
+	unsigned char value;
+	unsigned long flags;
+
+	spin_lock_irqsave(&i2c_lock, flags);
+
+	do {
+		error = 0;
+
+		i2c_start();
+		/*
+		 * send slave address
+		 */
+		i2c_outbyte((theSlave & 0xfe));
+		/*
+		 * wait for ack
+		 */
+		if (!i2c_getack())
+			error = 1;
+		/*
+		 * send data
+		 */
+		for (bytes_wrote = 0; bytes_wrote < nbytes; bytes_wrote++) {
+			memcpy(&value, data + bytes_wrote, sizeof value);
+			i2c_outbyte(value);
+			/*
+			 * now it's time to wait for ack
+			 */
+			if (!i2c_getack())
+				error |= 4;
+		}
+		/*
+		 * end byte stream
+		 */
+		i2c_stop();
+
+	} while (error && cntr--);
+
+	i2c_delay(CLOCK_LOW_TIME);
+
+	spin_unlock_irqrestore(&i2c_lock, flags);
+
+	return -error;
+}
+
+/*#---------------------------------------------------------------------------
+*#
+*# FUNCTION NAME: i2c_read
+*#
+*# DESCRIPTION  : Reads a value from an I2C device
+*#
+*#--------------------------------------------------------------------------*/
+int
+i2c_read(unsigned char theSlave, void *data, size_t nbytes)
+{
+	unsigned char b = 0;
+	unsigned char bytes_read = 0;
+	int error, cntr = 3;
+	unsigned long flags;
+
+	spin_lock_irqsave(&i2c_lock, flags);
+
+	do {
+		error = 0;
+		memset(data, 0, nbytes);
+		/*
+		 * generate start condition
+		 */
+		i2c_start();
+		/*
+		 * send slave address
+		 */
+		i2c_outbyte((theSlave | 0x01));
+		/*
+		 * wait for ack
+		 */
+		if (!i2c_getack())
+			error = 1;
+		/*
+		 * fetch data
+		 */
+		for (bytes_read = 0; bytes_read < nbytes; bytes_read++) {
+			b = i2c_inbyte();
+			memcpy(data + bytes_read, &b, sizeof b);
+
+			if (bytes_read < (nbytes - 1))
+				i2c_sendack();
+		}
+		/*
+		 * last received byte needs to be nacked
+		 * instead of acked
+		 */
+		i2c_sendnack();
+		/*
+		 * end sequence
+		 */
+		i2c_stop();
+	} while (error && cntr--);
+
+	spin_unlock_irqrestore(&i2c_lock, flags);
+
+	return -error;
+}
+
+/*#---------------------------------------------------------------------------
+*#
 *# FUNCTION NAME: i2c_writereg
 *#
 *# DESCRIPTION  : Writes a value to an I2C device
@@ -387,12 +509,10 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg,
 	int error, cntr = 3;
 	unsigned long flags;
 
+	spin_lock_irqsave(&i2c_lock, flags);
+
 	do {
 		error = 0;
-		/*
-		 * we don't like to be interrupted
-		 */
-                local_irq_save(flags);
 
 		i2c_start();
 		/*
@@ -427,15 +547,12 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg,
 		 * end byte stream
 		 */
 		i2c_stop();
-		/*
-		 * enable interrupt again
-		 */
-		local_irq_restore(flags);
-
 	} while(error && cntr--);
 
 	i2c_delay(CLOCK_LOW_TIME);
 
+	spin_unlock_irqrestore(&i2c_lock, flags);
+
 	return -error;
 }
 
@@ -453,13 +570,11 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg)
 	int error, cntr = 3;
 	unsigned long flags;
 
+	spin_lock_irqsave(&i2c_lock, flags);
+
 	do {
 		error = 0;
 		/*
-		 * we don't like to be interrupted
-		 */
-                local_irq_save(flags);
-		/*
 		 * generate start condition
 		 */
 		i2c_start();
@@ -482,7 +597,7 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg)
 		 * now it's time to wait for ack
 		 */
 		if(!i2c_getack())
-			error = 1;
+			error |= 2;
 		/*
 		 * repeat start condition
 		 */
@@ -496,7 +611,7 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg)
 		 * wait for ack
 		 */
 		if(!i2c_getack())
-			error = 1;
+			error |= 4;
 		/*
 		 * fetch register
 		 */
@@ -510,13 +625,11 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg)
 		 * end sequence
 		 */
 		i2c_stop();
-		/*
-		 * enable interrupt again
-		 */
-		local_irq_restore(flags);
 
 	} while(error && cntr--);
 
+	spin_unlock_irqrestore(&i2c_lock, flags);
+
 	return b;
 }
 
@@ -540,7 +653,7 @@ i2c_ioctl(struct inode *inode, struct file *file,
 	  unsigned int cmd, unsigned long arg)
 {
 	if(_IOC_TYPE(cmd) != ETRAXI2C_IOCTYPE) {
-		return -EINVAL;
+		return -ENOTTY;
 	}
 
 	switch (_IOC_NR(cmd)) {
@@ -580,31 +693,52 @@ static const struct file_operations i2c_fops = {
 	.release =  i2c_release,
 };
 
-int __init
-i2c_init(void)
+static int __init i2c_init(void)
 {
-	int res;
+	static int res;
+	static int first = 1;
 
-	/* Setup and enable the Port B I2C interface */
+	if (!first)
+		return res;
 
-        crisv32_io_get_name(&cris_i2c_data, CONFIG_ETRAX_I2C_DATA_PORT);
-        crisv32_io_get_name(&cris_i2c_clk, CONFIG_ETRAX_I2C_CLK_PORT);
+	first = 0;
+
+	/* Setup and enable the DATA and CLK pins */
+
+	res = crisv32_io_get_name(&cris_i2c_data,
+		CONFIG_ETRAX_V32_I2C_DATA_PORT);
+	if (res < 0)
+		return res;
+
+	res = crisv32_io_get_name(&cris_i2c_clk, CONFIG_ETRAX_V32_I2C_CLK_PORT);
+	crisv32_io_set_dir(&cris_i2c_clk, crisv32_io_dir_out);
+
+	return res;
+}
+
+
+static int __init i2c_register(void)
+{
+	int res;
+
+	res = i2c_init();
+	if (res < 0)
+		return res;
 
 	/* register char device */
 
 	res = register_chrdev(I2C_MAJOR, i2c_name, &i2c_fops);
-	if(res < 0) {
+	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");
+	printk(KERN_INFO
+		"I2C driver v2.2, (c) 1999-2007 Axis Communications AB\n");
 
 	return 0;
 }
-
 /* this makes sure that i2c_init is called during boot */
-
-module_init(i2c_init);
+module_init(i2c_register);
 
 /****************** END OF FILE i2c.c ********************************/
diff --git a/arch/cris/arch-v32/drivers/i2c.h b/arch/cris/arch-v32/drivers/i2c.h
index bfe1a13f9f35..c073cf4ba016 100644
--- a/arch/cris/arch-v32/drivers/i2c.h
+++ b/arch/cris/arch-v32/drivers/i2c.h
@@ -3,6 +3,8 @@
 
 /* High level I2C actions */
 int __init i2c_init(void);
+int i2c_write(unsigned char theSlave, void *data, size_t nbytes);
+int i2c_read(unsigned char theSlave, void *data, size_t nbytes);
 int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue);
 unsigned char i2c_readreg(unsigned char theSlave, unsigned char theReg);
 
diff --git a/arch/cris/arch-v32/drivers/iop_fw_load.c b/arch/cris/arch-v32/drivers/iop_fw_load.c
index f4bdc1dfa320..3b3857ec1f15 100644
--- a/arch/cris/arch-v32/drivers/iop_fw_load.c
+++ b/arch/cris/arch-v32/drivers/iop_fw_load.c
@@ -1,5 +1,4 @@
-/* $Id: iop_fw_load.c,v 1.4 2005/04/07 09:27:46 larsv Exp $
- *
+/*
  * Firmware loader for ETRAX FS IO-Processor
  *
  * Copyright (C) 2004  Axis Communications AB
@@ -11,12 +10,13 @@
 #include <linux/device.h>
 #include <linux/firmware.h>
 
-#include <asm/arch/hwregs/reg_map.h>
-#include <asm/arch/hwregs/iop/iop_reg_space.h>
-#include <asm/arch/hwregs/iop/iop_mpu_macros.h>
-#include <asm/arch/hwregs/iop/iop_mpu_defs.h>
-#include <asm/arch/hwregs/iop/iop_spu_defs.h>
-#include <asm/arch/hwregs/iop/iop_sw_cpu_defs.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/reg_map.h>
+#include <hwregs/iop/iop_reg_space.h>
+#include <hwregs/iop/iop_mpu_macros.h>
+#include <hwregs/iop/iop_mpu_defs.h>
+#include <hwregs/iop/iop_spu_defs.h>
+#include <hwregs/iop/iop_sw_cpu_defs.h>
 
 #define IOP_TIMEOUT 100
 
diff --git a/arch/cris/arch-v32/drivers/mach-a3/Makefile b/arch/cris/arch-v32/drivers/mach-a3/Makefile
new file mode 100644
index 000000000000..5c6d2a2a080e
--- /dev/null
+++ b/arch/cris/arch-v32/drivers/mach-a3/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for Etrax-specific drivers
+#
+
+obj-$(CONFIG_ETRAX_NANDFLASH)   += nandflash.o
+obj-$(CONFIG_ETRAX_GPIO)        += gpio.o
diff --git a/arch/cris/arch-v32/drivers/mach-a3/gpio.c b/arch/cris/arch-v32/drivers/mach-a3/gpio.c
new file mode 100644
index 000000000000..de107dad9f4f
--- /dev/null
+++ b/arch/cris/arch-v32/drivers/mach-a3/gpio.c
@@ -0,0 +1,984 @@
+/*
+ * Artec-3 general port I/O device
+ *
+ * Copyright (c) 2007 Axis Communications AB
+ *
+ * Authors:    Bjorn Wesen      (initial version)
+ *             Ola Knutsson     (LED handling)
+ *             Johan Adolfsson  (read/set directions, write, port G,
+ *                               port to ETRAX FS.
+ *             Ricard Wanderlof (PWM for Artpec-3)
+ *
+ */
+
+#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 <linux/spinlock.h>
+
+#include <asm/etraxgpio.h>
+#include <hwregs/reg_map.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/gio_defs.h>
+#include <hwregs/intr_vect_defs.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/arch/mach/pinmux.h>
+
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+#include "../i2c.h"
+
+#define VIRT_I2C_ADDR 0x40
+#endif
+
+/* The following gio ports on ARTPEC-3 is available:
+ * pa 32 bits
+ * pb 32 bits
+ * pc 16 bits
+ * each port has a rw_px_dout, r_px_din and rw_px_oe register.
+ */
+
+#define GPIO_MAJOR 120  /* experimental MAJOR number */
+
+#define I2C_INTERRUPT_BITS 0x300 /* i2c0_done and i2c1_done bits */
+
+#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";
+
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+static int virtual_gpio_ioctl(struct file *file, unsigned int cmd,
+			      unsigned long arg);
+#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 __user *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;
+	/* The IO_CFG_WRITE_MODE_VALUE only support 8 bits: */
+	unsigned char clk_mask;
+	unsigned char data_mask;
+	unsigned char write_msb;
+	unsigned char pad1;
+	/* These fields are generic */
+	unsigned long highalarm, lowalarm;
+	wait_queue_head_t alarm_wq;
+	int minor;
+};
+
+static void gpio_set_alarm(struct gpio_private *priv);
+static int gpio_leds_ioctl(unsigned int cmd, unsigned long arg);
+static int gpio_pwm_ioctl(struct gpio_private *priv, unsigned int cmd,
+	unsigned long arg);
+
+
+/* linked list of alarms to check for */
+
+static struct gpio_private *alarmlist;
+
+static int wanted_interrupts;
+
+static DEFINE_SPINLOCK(gpio_lock);
+
+#define NUM_PORTS (GPIO_MINOR_LAST+1)
+#define GIO_REG_RD_ADDR(reg) \
+	(unsigned long *)(regi_gio + REG_RD_ADDR_gio_##reg)
+#define GIO_REG_WR_ADDR(reg) \
+	(unsigned long *)(regi_gio + REG_WR_ADDR_gio_##reg)
+static unsigned long led_dummy;
+static unsigned long port_d_dummy;	/* Only input on Artpec-3 */
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+static unsigned long port_e_dummy;	/* Non existent on Artpec-3 */
+static unsigned long virtual_dummy;
+static unsigned long virtual_rw_pv_oe = CONFIG_ETRAX_DEF_GIO_PV_OE;
+static unsigned short cached_virtual_gpio_read;
+#endif
+
+static unsigned long *data_out[NUM_PORTS] = {
+	GIO_REG_WR_ADDR(rw_pa_dout),
+	GIO_REG_WR_ADDR(rw_pb_dout),
+	&led_dummy,
+	GIO_REG_WR_ADDR(rw_pc_dout),
+	&port_d_dummy,
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	&port_e_dummy,
+	&virtual_dummy,
+#endif
+};
+
+static unsigned long *data_in[NUM_PORTS] = {
+	GIO_REG_RD_ADDR(r_pa_din),
+	GIO_REG_RD_ADDR(r_pb_din),
+	&led_dummy,
+	GIO_REG_RD_ADDR(r_pc_din),
+	GIO_REG_RD_ADDR(r_pd_din),
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	&port_e_dummy,
+	&virtual_dummy,
+#endif
+};
+
+static unsigned long changeable_dir[NUM_PORTS] = {
+	CONFIG_ETRAX_PA_CHANGEABLE_DIR,
+	CONFIG_ETRAX_PB_CHANGEABLE_DIR,
+	0,
+	CONFIG_ETRAX_PC_CHANGEABLE_DIR,
+	0,
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	0,
+	CONFIG_ETRAX_PV_CHANGEABLE_DIR,
+#endif
+};
+
+static unsigned long changeable_bits[NUM_PORTS] = {
+	CONFIG_ETRAX_PA_CHANGEABLE_BITS,
+	CONFIG_ETRAX_PB_CHANGEABLE_BITS,
+	0,
+	CONFIG_ETRAX_PC_CHANGEABLE_BITS,
+	0,
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	0,
+	CONFIG_ETRAX_PV_CHANGEABLE_BITS,
+#endif
+};
+
+static unsigned long *dir_oe[NUM_PORTS] = {
+	GIO_REG_WR_ADDR(rw_pa_oe),
+	GIO_REG_WR_ADDR(rw_pb_oe),
+	&led_dummy,
+	GIO_REG_WR_ADDR(rw_pc_oe),
+	&port_d_dummy,
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	&port_e_dummy,
+	&virtual_rw_pv_oe,
+#endif
+};
+
+static void gpio_set_alarm(struct gpio_private *priv)
+{
+	int bit;
+	int intr_cfg;
+	int mask;
+	int pins;
+	unsigned long flags;
+
+	spin_lock_irqsave(&gpio_lock, flags);
+	intr_cfg = REG_RD_INT(gio, regi_gio, rw_intr_cfg);
+	pins = REG_RD_INT(gio, regi_gio, rw_intr_pins);
+	mask = REG_RD_INT(gio, regi_gio, rw_intr_mask) & I2C_INTERRUPT_BITS;
+
+	for (bit = 0; bit < 32; bit++) {
+		int intr = bit % 8;
+		int pin = bit / 8;
+		if (priv->minor < GPIO_MINOR_LEDS)
+			pin += priv->minor * 4;
+		else
+			pin += (priv->minor - 1) * 4;
+
+		if (priv->highalarm & (1<<bit)) {
+			intr_cfg |= (regk_gio_hi << (intr * 3));
+			mask |= 1 << intr;
+			wanted_interrupts = mask & 0xff;
+			pins |= pin << (intr * 4);
+		} else if (priv->lowalarm & (1<<bit)) {
+			intr_cfg |= (regk_gio_lo << (intr * 3));
+			mask |= 1 << intr;
+			wanted_interrupts = mask & 0xff;
+			pins |= pin << (intr * 4);
+		}
+	}
+
+	REG_WR_INT(gio, regi_gio, rw_intr_cfg, intr_cfg);
+	REG_WR_INT(gio, regi_gio, rw_intr_pins, pins);
+	REG_WR_INT(gio, regi_gio, rw_intr_mask, mask);
+
+	spin_unlock_irqrestore(&gpio_lock, flags);
+}
+
+static unsigned int gpio_poll(struct file *file, struct poll_table_struct *wait)
+{
+	unsigned int mask = 0;
+	struct gpio_private *priv = file->private_data;
+	unsigned long data;
+	unsigned long tmp;
+
+	if (priv->minor >= GPIO_MINOR_PWM0 &&
+	    priv->minor <= GPIO_MINOR_LAST_PWM)
+		return 0;
+
+	poll_wait(file, &priv->alarm_wq, wait);
+	if (priv->minor <= GPIO_MINOR_D) {
+		data = readl(data_in[priv->minor]);
+		REG_WR_INT(gio, regi_gio, rw_ack_intr, wanted_interrupts);
+		tmp = REG_RD_INT(gio, regi_gio, rw_intr_mask);
+		tmp &= I2C_INTERRUPT_BITS;
+		tmp |= wanted_interrupts;
+		REG_WR_INT(gio, regi_gio, rw_intr_mask, tmp);
+	} else
+		return 0;
+
+	if ((data & priv->highalarm) || (~data & priv->lowalarm))
+		mask = POLLIN|POLLRDNORM;
+
+	DP(printk(KERN_DEBUG "gpio_poll ready: mask 0x%08X\n", mask));
+	return mask;
+}
+
+static irqreturn_t gpio_interrupt(int irq, void *dev_id)
+{
+	reg_gio_rw_intr_mask intr_mask;
+	reg_gio_r_masked_intr masked_intr;
+	reg_gio_rw_ack_intr ack_intr;
+	unsigned long flags;
+	unsigned long tmp;
+	unsigned long tmp2;
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	unsigned char enable_gpiov_ack = 0;
+#endif
+
+	/* Find what PA interrupts are active */
+	masked_intr = REG_RD(gio, regi_gio, r_masked_intr);
+	tmp = REG_TYPE_CONV(unsigned long, reg_gio_r_masked_intr, masked_intr);
+
+	/* Find those that we have enabled */
+	spin_lock_irqsave(&gpio_lock, flags);
+	tmp &= wanted_interrupts;
+	spin_unlock_irqrestore(&gpio_lock, flags);
+
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	/* Something changed on virtual GPIO. Interrupt is acked by
+	 * reading the device.
+	 */
+	if (tmp & (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN)) {
+		i2c_read(VIRT_I2C_ADDR, (void *)&cached_virtual_gpio_read,
+			sizeof(cached_virtual_gpio_read));
+		enable_gpiov_ack = 1;
+	}
+#endif
+
+	/* Ack them */
+	ack_intr = REG_TYPE_CONV(reg_gio_rw_ack_intr, unsigned long, tmp);
+	REG_WR(gio, regi_gio, rw_ack_intr, ack_intr);
+
+	/* Disable those interrupts.. */
+	intr_mask = REG_RD(gio, regi_gio, rw_intr_mask);
+	tmp2 = REG_TYPE_CONV(unsigned long, reg_gio_rw_intr_mask, intr_mask);
+	tmp2 &= ~tmp;
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	/* Do not disable interrupt on virtual GPIO. Changes on virtual
+	 * pins are only noticed by an interrupt.
+	 */
+	if (enable_gpiov_ack)
+		tmp2 |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);
+#endif
+	intr_mask = REG_TYPE_CONV(reg_gio_rw_intr_mask, unsigned long, tmp2);
+	REG_WR(gio, regi_gio, rw_intr_mask, intr_mask);
+
+	return IRQ_RETVAL(tmp);
+}
+
+static void gpio_write_bit(unsigned long *port, unsigned char data, int bit,
+	unsigned char clk_mask, unsigned char data_mask)
+{
+	unsigned long shadow = readl(port) & ~clk_mask;
+	writel(shadow, port);
+	if (data & 1 << bit)
+		shadow |= data_mask;
+	else
+		shadow &= ~data_mask;
+	writel(shadow, port);
+	/* For FPGA: min 5.0ns (DCC) before CCLK high */
+	shadow |= clk_mask;
+	writel(shadow, port);
+}
+
+static void gpio_write_byte(struct gpio_private *priv, unsigned long *port,
+		unsigned char data)
+{
+	int i;
+
+	if (priv->write_msb)
+		for (i = 7; i >= 0; i--)
+			gpio_write_bit(port, data, i, priv->clk_mask,
+				priv->data_mask);
+	else
+		for (i = 0; i <= 7; i++)
+			gpio_write_bit(port, data, i, priv->clk_mask,
+				priv->data_mask);
+}
+
+
+static ssize_t gpio_write(struct file *file, const char __user *buf,
+	size_t count, loff_t *off)
+{
+	struct gpio_private *priv = file->private_data;
+	unsigned long flags;
+	ssize_t retval = count;
+	/* Only bits 0-7 may be used for write operations but allow all
+	   devices except leds... */
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	if (priv->minor == GPIO_MINOR_V)
+		return -EFAULT;
+#endif
+	if (priv->minor == GPIO_MINOR_LEDS)
+		return -EFAULT;
+
+	if (priv->minor >= GPIO_MINOR_PWM0 &&
+	    priv->minor <= GPIO_MINOR_LAST_PWM)
+		return -EFAULT;
+
+	if (!access_ok(VERIFY_READ, buf, count))
+		return -EFAULT;
+
+	/* It must have been configured using the IO_CFG_WRITE_MODE */
+	/* Perhaps a better error code? */
+	if (priv->clk_mask == 0 || priv->data_mask == 0)
+		return -EPERM;
+
+	D(printk(KERN_DEBUG "gpio_write: %lu to data 0x%02X clk 0x%02X "
+		"msb: %i\n",
+		count, priv->data_mask, priv->clk_mask, priv->write_msb));
+
+	spin_lock_irqsave(&gpio_lock, flags);
+
+	while (count--)
+		gpio_write_byte(priv, data_out[priv->minor], *buf++);
+
+	spin_unlock_irqrestore(&gpio_lock, flags);
+	return retval;
+}
+
+static int gpio_open(struct inode *inode, struct file *filp)
+{
+	struct gpio_private *priv;
+	int p = iminor(inode);
+
+	if (p > GPIO_MINOR_LAST_PWM ||
+	    (p > GPIO_MINOR_LAST && p < GPIO_MINOR_PWM0))
+		return -EINVAL;
+
+	priv = kmalloc(sizeof(struct gpio_private), GFP_KERNEL);
+
+	if (!priv)
+		return -ENOMEM;
+	memset(priv, 0, sizeof(*priv));
+
+	priv->minor = p;
+	filp->private_data = priv;
+
+	/* initialize the io/alarm struct, not for PWM ports though  */
+	if (p <= GPIO_MINOR_LAST) {
+
+		priv->clk_mask = 0;
+		priv->data_mask = 0;
+		priv->highalarm = 0;
+		priv->lowalarm = 0;
+
+		init_waitqueue_head(&priv->alarm_wq);
+
+		/* link it into our alarmlist */
+		spin_lock_irq(&gpio_lock);
+		priv->next = alarmlist;
+		alarmlist = priv;
+		spin_unlock_irq(&gpio_lock);
+	}
+
+	return 0;
+}
+
+static int gpio_release(struct inode *inode, struct file *filp)
+{
+	struct gpio_private *p;
+	struct gpio_private *todel;
+	/* local copies while updating them: */
+	unsigned long a_high, a_low;
+
+	/* prepare to free private structure */
+	todel = filp->private_data;
+
+	/* unlink from alarmlist - only for non-PWM ports though */
+	if (todel->minor <= GPIO_MINOR_LAST) {
+		spin_lock_irq(&gpio_lock);
+		p = alarmlist;
+
+		if (p == todel)
+			alarmlist = todel->next;
+		 else {
+			while (p->next != todel)
+				p = p->next;
+			p->next = todel->next;
+		}
+
+		/* Check if there are still any alarms set */
+		p = alarmlist;
+		a_high = 0;
+		a_low = 0;
+		while (p) {
+			if (p->minor == GPIO_MINOR_A) {
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+				p->lowalarm |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);
+#endif
+				a_high |= p->highalarm;
+				a_low |= p->lowalarm;
+			}
+
+			p = p->next;
+		}
+
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	/* Variable 'a_low' needs to be set here again
+	 * to ensure that interrupt for virtual GPIO is handled.
+	 */
+		a_low |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);
+#endif
+
+		spin_unlock_irq(&gpio_lock);
+	}
+	kfree(todel);
+
+	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().
+ */
+
+inline unsigned long setget_input(struct gpio_private *priv, unsigned long arg)
+{
+	/* Set direction 0=unchanged 1=input,
+	 * return mask with 1=input
+	 */
+	unsigned long flags;
+	unsigned long dir_shadow;
+
+	spin_lock_irqsave(&gpio_lock, flags);
+
+	dir_shadow = readl(dir_oe[priv->minor]) &
+		~(arg & changeable_dir[priv->minor]);
+	writel(dir_shadow, dir_oe[priv->minor]);
+
+	spin_unlock_irqrestore(&gpio_lock, flags);
+
+	if (priv->minor == GPIO_MINOR_C)
+		dir_shadow ^= 0xFFFF;		/* Only 16 bits */
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	else if (priv->minor == GPIO_MINOR_V)
+		dir_shadow ^= 0xFFFF;		/* Only 16 bits */
+#endif
+	else
+		dir_shadow ^= 0xFFFFFFFF;	/* PA, PB and PD 32 bits */
+
+	return dir_shadow;
+
+} /* setget_input */
+
+static inline unsigned long setget_output(struct gpio_private *priv,
+	unsigned long arg)
+{
+	unsigned long flags;
+	unsigned long dir_shadow;
+
+	spin_lock_irqsave(&gpio_lock, flags);
+
+	dir_shadow = readl(dir_oe[priv->minor]) |
+		(arg & changeable_dir[priv->minor]);
+	writel(dir_shadow, dir_oe[priv->minor]);
+
+	spin_unlock_irqrestore(&gpio_lock, flags);
+	return dir_shadow;
+} /* setget_output */
+
+static int gpio_ioctl(struct inode *inode, struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	unsigned long flags;
+	unsigned long val;
+	unsigned long shadow;
+	struct gpio_private *priv = file->private_data;
+
+	if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE)
+		return -ENOTTY;
+
+	/* Check for special ioctl handlers first */
+
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	if (priv->minor == GPIO_MINOR_V)
+		return virtual_gpio_ioctl(file, cmd, arg);
+#endif
+
+	if (priv->minor == GPIO_MINOR_LEDS)
+		return gpio_leds_ioctl(cmd, arg);
+
+	if (priv->minor >= GPIO_MINOR_PWM0 &&
+	    priv->minor <= GPIO_MINOR_LAST_PWM)
+		return gpio_pwm_ioctl(priv, cmd, arg);
+
+	switch (_IOC_NR(cmd)) {
+	case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */
+		/* Read the port. */
+		return readl(data_in[priv->minor]);
+	case IO_SETBITS:
+		spin_lock_irqsave(&gpio_lock, flags);
+		/* Set changeable bits with a 1 in arg. */
+		shadow = readl(data_out[priv->minor]) |
+			(arg & changeable_bits[priv->minor]);
+		writel(shadow, data_out[priv->minor]);
+		spin_unlock_irqrestore(&gpio_lock, flags);
+		break;
+	case IO_CLRBITS:
+		spin_lock_irqsave(&gpio_lock, flags);
+		/* Clear changeable bits with a 1 in arg. */
+		shadow = readl(data_out[priv->minor]) &
+			~(arg & changeable_bits[priv->minor]);
+		writel(shadow, data_out[priv->minor]);
+		spin_unlock_irqrestore(&gpio_lock, flags);
+		break;
+	case IO_HIGHALARM:
+		/* Set alarm when bits with 1 in arg go high. */
+		priv->highalarm |= arg;
+		gpio_set_alarm(priv);
+		break;
+	case IO_LOWALARM:
+		/* Set alarm when bits with 1 in arg go low. */
+		priv->lowalarm |= arg;
+		gpio_set_alarm(priv);
+		break;
+	case IO_CLRALARM:
+		/* Clear alarm for bits with 1 in arg. */
+		priv->highalarm &= ~arg;
+		priv->lowalarm  &= ~arg;
+		gpio_set_alarm(priv);
+		break;
+	case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */
+		/* Read direction 0=input 1=output */
+		return readl(dir_oe[priv->minor]);
+
+	case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */
+		/* Set direction 0=unchanged 1=input,
+		 * return mask with 1=input
+		 */
+		return setget_input(priv, arg);
+
+	case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */
+		/* Set direction 0=unchanged 1=output,
+		 * return mask with 1=output
+		 */
+		return setget_output(priv, arg);
+
+	case IO_CFG_WRITE_MODE:
+	{
+		int res = -EPERM;
+		unsigned long dir_shadow, clk_mask, data_mask, write_msb;
+
+		clk_mask = arg & 0xFF;
+		data_mask = (arg >> 8) & 0xFF;
+		write_msb = (arg >> 16) & 0x01;
+
+		/* Check if we're allowed to change the bits and
+		 * the direction is correct
+		 */
+		spin_lock_irqsave(&gpio_lock, flags);
+		dir_shadow = readl(dir_oe[priv->minor]);
+		if ((clk_mask & changeable_bits[priv->minor]) &&
+		    (data_mask & changeable_bits[priv->minor]) &&
+		    (clk_mask & dir_shadow) &&
+		    (data_mask & dir_shadow)) {
+			priv->clk_mask = clk_mask;
+			priv->data_mask = data_mask;
+			priv->write_msb = write_msb;
+			res = 0;
+		}
+		spin_unlock_irqrestore(&gpio_lock, flags);
+
+		return res;
+	}
+	case IO_READ_INBITS:
+		/* *arg is result of reading the input pins */
+		val = readl(data_in[priv->minor]);
+		if (copy_to_user((void __user *)arg, &val, sizeof(val)))
+			return -EFAULT;
+		return 0;
+	case IO_READ_OUTBITS:
+		 /* *arg is result of reading the output shadow */
+		val = *data_out[priv->minor];
+		if (copy_to_user((void __user *)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, (void __user *)arg, sizeof(val)))
+			return -EFAULT;
+		val = setget_input(priv, val);
+		if (copy_to_user((void __user *)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, (void __user *)arg, sizeof(val)))
+			return -EFAULT;
+		val = setget_output(priv, val);
+		if (copy_to_user((void __user *)arg, &val, sizeof(val)))
+			return -EFAULT;
+		break;
+	default:
+		return -EINVAL;
+	} /* switch */
+
+	return 0;
+}
+
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+static int virtual_gpio_ioctl(struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	unsigned long flags;
+	unsigned short val;
+	unsigned short shadow;
+	struct gpio_private *priv = file->private_data;
+
+	switch (_IOC_NR(cmd)) {
+	case IO_SETBITS:
+		spin_lock_irqsave(&gpio_lock, flags);
+		/* Set changeable bits with a 1 in arg. */
+		i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));
+		shadow |= ~readl(dir_oe[priv->minor]) |
+			(arg & changeable_bits[priv->minor]);
+		i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));
+		spin_lock_irqrestore(&gpio_lock, flags);
+		break;
+	case IO_CLRBITS:
+		spin_lock_irqsave(&gpio_lock, flags);
+		/* Clear changeable bits with a 1 in arg. */
+		i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));
+		shadow |= ~readl(dir_oe[priv->minor]) &
+			~(arg & changeable_bits[priv->minor]);
+		i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));
+		spin_lock_irqrestore(&gpio_lock, flags);
+		break;
+	case IO_HIGHALARM:
+		/* Set alarm when bits with 1 in arg go high. */
+		priv->highalarm |= arg;
+		break;
+	case IO_LOWALARM:
+		/* Set alarm when bits with 1 in arg go low. */
+		priv->lowalarm |= arg;
+		break;
+	case IO_CLRALARM:
+		/* Clear alarm for bits with 1 in arg. */
+		priv->highalarm &= ~arg;
+		priv->lowalarm  &= ~arg;
+		break;
+	case IO_CFG_WRITE_MODE:
+	{
+		unsigned long dir_shadow;
+		dir_shadow = readl(dir_oe[priv->minor]);
+
+		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 & changeable_bits[priv->minor]) &&
+		      (priv->data_mask & changeable_bits[priv->minor]) &&
+		      (priv->clk_mask & dir_shadow) &&
+		      (priv->data_mask & 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 */
+		val = cached_virtual_gpio_read & ~readl(dir_oe[priv->minor]);
+		if (copy_to_user((void __user *)arg, &val, sizeof(val)))
+			return -EFAULT;
+		return 0;
+
+	case IO_READ_OUTBITS:
+		 /* *arg is result of reading the output shadow */
+		i2c_read(VIRT_I2C_ADDR, (void *)&val, sizeof(val));
+		val &= readl(dir_oe[priv->minor]);
+		if (copy_to_user((void __user *)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.
+		 */
+		unsigned short input_mask = ~readl(dir_oe[priv->minor]);
+		if (copy_from_user(&val, (void __user *)arg, sizeof(val)))
+			return -EFAULT;
+		val = setget_input(priv, val);
+		if (copy_to_user((void __user *)arg, &val, sizeof(val)))
+			return -EFAULT;
+		if ((input_mask & val) != input_mask) {
+			/* Input pins changed. All ports desired as input
+			 * should be set to logic 1.
+			 */
+			unsigned short change = input_mask ^ val;
+			i2c_read(VIRT_I2C_ADDR, (void *)&shadow,
+				sizeof(shadow));
+			shadow &= ~change;
+			shadow |= val;
+			i2c_write(VIRT_I2C_ADDR, (void *)&shadow,
+				sizeof(shadow));
+		}
+		break;
+	}
+	case IO_SETGET_OUTPUT:
+		/* bits set in *arg is set to output,
+		 * *arg updated with current output pins.
+		 */
+		if (copy_from_user(&val, (void __user *)arg, sizeof(val)))
+			return -EFAULT;
+		val = setget_output(priv, val);
+		if (copy_to_user((void __user *)arg, &val, sizeof(val)))
+			return -EFAULT;
+		break;
+	default:
+		return -EINVAL;
+	} /* switch */
+	return 0;
+}
+#endif /* CONFIG_ETRAX_VIRTUAL_GPIO */
+
+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;
+		CRIS_LED_ACTIVE_SET_G(green);
+		CRIS_LED_ACTIVE_SET_R(red);
+		break;
+
+	default:
+		return -EINVAL;
+	} /* switch */
+
+	return 0;
+}
+
+static int gpio_pwm_set_mode(unsigned long arg, int pwm_port)
+{
+	int pinmux_pwm = pinmux_pwm0 + pwm_port;
+	int mode;
+	reg_gio_rw_pwm0_ctrl rw_pwm_ctrl = {
+		.ccd_val = 0,
+		.ccd_override = regk_gio_no,
+		.mode = regk_gio_no
+	};
+	int allocstatus;
+
+	if (get_user(mode, &((struct io_pwm_set_mode *) arg)->mode))
+		return -EFAULT;
+	rw_pwm_ctrl.mode = mode;
+	if (mode != PWM_OFF)
+		allocstatus = crisv32_pinmux_alloc_fixed(pinmux_pwm);
+	else
+		allocstatus = crisv32_pinmux_dealloc_fixed(pinmux_pwm);
+	if (allocstatus)
+		return allocstatus;
+	REG_WRITE(reg_gio_rw_pwm0_ctrl, REG_ADDR(gio, regi_gio, rw_pwm0_ctrl) +
+		12 * pwm_port, rw_pwm_ctrl);
+	return 0;
+}
+
+static int gpio_pwm_set_period(unsigned long arg, int pwm_port)
+{
+	struct io_pwm_set_period periods;
+	reg_gio_rw_pwm0_var rw_pwm_widths;
+
+	if (copy_from_user(&periods, (void __user *)arg, sizeof(periods)))
+		return -EFAULT;
+	if (periods.lo > 8191 || periods.hi > 8191)
+		return -EINVAL;
+	rw_pwm_widths.lo = periods.lo;
+	rw_pwm_widths.hi = periods.hi;
+	REG_WRITE(reg_gio_rw_pwm0_var, REG_ADDR(gio, regi_gio, rw_pwm0_var) +
+		12 * pwm_port, rw_pwm_widths);
+	return 0;
+}
+
+static int gpio_pwm_set_duty(unsigned long arg, int pwm_port)
+{
+	unsigned int duty;
+	reg_gio_rw_pwm0_data rw_pwm_duty;
+
+	if (get_user(duty, &((struct io_pwm_set_duty *) arg)->duty))
+		return -EFAULT;
+	if (duty > 255)
+		return -EINVAL;
+	rw_pwm_duty.data = duty;
+	REG_WRITE(reg_gio_rw_pwm0_data, REG_ADDR(gio, regi_gio, rw_pwm0_data) +
+		12 * pwm_port, rw_pwm_duty);
+	return 0;
+}
+
+static int gpio_pwm_ioctl(struct gpio_private *priv, unsigned int cmd,
+	unsigned long arg)
+{
+	int pwm_port = priv->minor - GPIO_MINOR_PWM0;
+
+	switch (_IOC_NR(cmd)) {
+	case IO_PWM_SET_MODE:
+		return gpio_pwm_set_mode(arg, pwm_port);
+	case IO_PWM_SET_PERIOD:
+		return gpio_pwm_set_period(arg, pwm_port);
+	case IO_PWM_SET_DUTY:
+		return gpio_pwm_set_duty(arg, pwm_port);
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static const struct file_operations gpio_fops = {
+	.owner       = THIS_MODULE,
+	.poll        = gpio_poll,
+	.ioctl       = gpio_ioctl,
+	.write       = gpio_write,
+	.open        = gpio_open,
+	.release     = gpio_release,
+};
+
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+static void __init virtual_gpio_init(void)
+{
+	reg_gio_rw_intr_cfg intr_cfg;
+	reg_gio_rw_intr_mask intr_mask;
+	unsigned short shadow;
+
+	shadow = ~virtual_rw_pv_oe; /* Input ports should be set to logic 1 */
+	shadow |= CONFIG_ETRAX_DEF_GIO_PV_OUT;
+	i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));
+
+	/* Set interrupt mask and on what state the interrupt shall trigger.
+	 * For virtual gpio the interrupt shall trigger on logic '0'.
+	 */
+	intr_cfg = REG_RD(gio, regi_gio, rw_intr_cfg);
+	intr_mask = REG_RD(gio, regi_gio, rw_intr_mask);
+
+	switch (CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN) {
+	case 0:
+		intr_cfg.pa0 = regk_gio_lo;
+		intr_mask.pa0 = regk_gio_yes;
+		break;
+	case 1:
+		intr_cfg.pa1 = regk_gio_lo;
+		intr_mask.pa1 = regk_gio_yes;
+		break;
+	case 2:
+		intr_cfg.pa2 = regk_gio_lo;
+		intr_mask.pa2 = regk_gio_yes;
+		break;
+	case 3:
+		intr_cfg.pa3 = regk_gio_lo;
+		intr_mask.pa3 = regk_gio_yes;
+		break;
+	case 4:
+		intr_cfg.pa4 = regk_gio_lo;
+		intr_mask.pa4 = regk_gio_yes;
+		break;
+	case 5:
+		intr_cfg.pa5 = regk_gio_lo;
+		intr_mask.pa5 = regk_gio_yes;
+		break;
+	case 6:
+		intr_cfg.pa6 = regk_gio_lo;
+		intr_mask.pa6 = regk_gio_yes;
+		break;
+	case 7:
+		intr_cfg.pa7 = regk_gio_lo;
+		intr_mask.pa7 = regk_gio_yes;
+		break;
+	}
+
+	REG_WR(gio, regi_gio, rw_intr_cfg, intr_cfg);
+	REG_WR(gio, regi_gio, rw_intr_mask, intr_mask);
+}
+#endif
+
+/* main driver initialization routine, called from mem.c */
+
+static int __init gpio_init(void)
+{
+	int res;
+
+	printk(KERN_INFO "ETRAX FS GPIO driver v2.7, (c) 2003-2008 "
+		"Axis Communications AB\n");
+
+	/* 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 */
+	CRIS_LED_NETWORK_GRP0_SET(0);
+	CRIS_LED_NETWORK_GRP1_SET(0);
+	CRIS_LED_ACTIVE_SET(0);
+	CRIS_LED_DISK_READ(0);
+	CRIS_LED_DISK_WRITE(0);
+
+	int res2 = request_irq(GIO_INTR_VECT, gpio_interrupt,
+		IRQF_SHARED | IRQF_DISABLED, "gpio", &alarmlist);
+	if (res2) {
+		printk(KERN_ERR "err: irq for gpio\n");
+		return res2;
+	}
+
+	/* No IRQs by default. */
+	REG_WR_INT(gio, regi_gio, rw_intr_pins, 0);
+
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	virtual_gpio_init();
+#endif
+
+	return res;
+}
+
+/* this makes sure that gpio_init is called during kernel boot */
+
+module_init(gpio_init);
diff --git a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c
new file mode 100644
index 000000000000..01ed0be2d0d1
--- /dev/null
+++ b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c
@@ -0,0 +1,180 @@
+/*
+ *  arch/cris/arch-v32/drivers/nandflash.c
+ *
+ *  Copyright (c) 2007
+ *
+ *  Derived from drivers/mtd/nand/spia.c
+ *	  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <asm/arch/memmap.h>
+#include <hwregs/reg_map.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/pio_defs.h>
+#include <pinmux.h>
+#include <asm/io.h>
+
+#define MANUAL_ALE_CLE_CONTROL 1
+
+#define regf_ALE	a0
+#define regf_CLE	a1
+#define regf_NCE	ce0_n
+
+#define CLE_BIT 10
+#define ALE_BIT 11
+#define CE_BIT 12
+
+struct mtd_info_wrapper {
+	struct mtd_info info;
+	struct nand_chip chip;
+};
+
+/* Bitmask for control pins */
+#define PIN_BITMASK ((1 << CE_BIT) | (1 << CLE_BIT) | (1 << ALE_BIT))
+
+static struct mtd_info *crisv32_mtd;
+/*
+ *	hardware specific access to control-lines
+ */
+static void crisv32_hwcontrol(struct mtd_info *mtd, int cmd,
+			      unsigned int ctrl)
+{
+	unsigned long flags;
+	reg_pio_rw_dout dout;
+	struct nand_chip *this = mtd->priv;
+
+	local_irq_save(flags);
+
+	/* control bits change */
+	if (ctrl & NAND_CTRL_CHANGE) {
+		dout = REG_RD(pio, regi_pio, rw_dout);
+		dout.regf_NCE = (ctrl & NAND_NCE) ? 0 : 1;
+
+#if !MANUAL_ALE_CLE_CONTROL
+		if (ctrl & NAND_ALE) {
+			/* A0 = ALE high */
+			this->IO_ADDR_W = (void __iomem *)REG_ADDR(pio,
+				regi_pio, rw_io_access1);
+		} else if (ctrl & NAND_CLE) {
+			/* A1 = CLE high */
+			this->IO_ADDR_W = (void __iomem *)REG_ADDR(pio,
+				regi_pio, rw_io_access2);
+		} else {
+			/* A1 = CLE and A0 = ALE low */
+			this->IO_ADDR_W = (void __iomem *)REG_ADDR(pio,
+				regi_pio, rw_io_access0);
+		}
+#else
+
+		dout.regf_CLE = (ctrl & NAND_CLE) ? 1 : 0;
+		dout.regf_ALE = (ctrl & NAND_ALE) ? 1 : 0;
+#endif
+		REG_WR(pio, regi_pio, rw_dout, dout);
+	}
+
+	/* command to chip */
+	if (cmd != NAND_CMD_NONE)
+		writeb(cmd, this->IO_ADDR_W);
+
+	local_irq_restore(flags);
+}
+
+/*
+*	read device ready pin
+*/
+static int crisv32_device_ready(struct mtd_info *mtd)
+{
+	reg_pio_r_din din = REG_RD(pio, regi_pio, r_din);
+	return din.rdy;
+}
+
+/*
+ * Main initialization routine
+ */
+struct mtd_info *__init crisv32_nand_flash_probe(void)
+{
+	void __iomem *read_cs;
+	void __iomem *write_cs;
+
+	struct mtd_info_wrapper *wrapper;
+	struct nand_chip *this;
+	int err = 0;
+
+	reg_pio_rw_man_ctrl man_ctrl = {
+		.regf_NCE = regk_pio_yes,
+#if MANUAL_ALE_CLE_CONTROL
+		.regf_ALE = regk_pio_yes,
+		.regf_CLE = regk_pio_yes
+#endif
+	};
+	reg_pio_rw_oe oe = {
+		.regf_NCE = regk_pio_yes,
+#if MANUAL_ALE_CLE_CONTROL
+		.regf_ALE = regk_pio_yes,
+		.regf_CLE = regk_pio_yes
+#endif
+	};
+	reg_pio_rw_dout dout = { .regf_NCE = 1 };
+
+	/* Allocate pio pins to pio */
+	crisv32_pinmux_alloc_fixed(pinmux_pio);
+	/* Set up CE, ALE, CLE (ce0_n, a0, a1) for manual control and output */
+	REG_WR(pio, regi_pio, rw_man_ctrl, man_ctrl);
+	REG_WR(pio, regi_pio, rw_dout, dout);
+	REG_WR(pio, regi_pio, rw_oe, oe);
+
+	/* Allocate memory for MTD device structure and private data */
+	wrapper = kzalloc(sizeof(struct mtd_info_wrapper), GFP_KERNEL);
+	if (!wrapper) {
+		printk(KERN_ERR "Unable to allocate CRISv32 NAND MTD "
+			"device structure.\n");
+		err = -ENOMEM;
+		return NULL;
+	}
+
+	read_cs = write_cs = (void __iomem *)REG_ADDR(pio, regi_pio,
+		rw_io_access0);
+
+	/* Get pointer to private data */
+	this = &wrapper->chip;
+	crisv32_mtd = &wrapper->info;
+
+	/* Link the private data with the MTD structure */
+	crisv32_mtd->priv = this;
+
+	/* Set address of NAND IO lines */
+	this->IO_ADDR_R = read_cs;
+	this->IO_ADDR_W = write_cs;
+	this->cmd_ctrl = crisv32_hwcontrol;
+	this->dev_ready = crisv32_device_ready;
+	/* 20 us command delay time */
+	this->chip_delay = 20;
+	this->ecc.mode = NAND_ECC_SOFT;
+
+	/* Enable the following for a flash based bad block table */
+	/* this->options = NAND_USE_FLASH_BBT; */
+
+	/* Scan to find existance of the device */
+	if (nand_scan(crisv32_mtd, 1)) {
+		err = -ENXIO;
+		goto out_mtd;
+	}
+
+	return crisv32_mtd;
+
+out_mtd:
+	kfree(wrapper);
+	return NULL;
+}
+
diff --git a/arch/cris/arch-v32/drivers/mach-fs/Makefile b/arch/cris/arch-v32/drivers/mach-fs/Makefile
new file mode 100644
index 000000000000..5c6d2a2a080e
--- /dev/null
+++ b/arch/cris/arch-v32/drivers/mach-fs/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for Etrax-specific drivers
+#
+
+obj-$(CONFIG_ETRAX_NANDFLASH)   += nandflash.o
+obj-$(CONFIG_ETRAX_GPIO)        += gpio.o
diff --git a/arch/cris/arch-v32/drivers/gpio.c b/arch/cris/arch-v32/drivers/mach-fs/gpio.c
index d82c5c561135..7863fd4efc2b 100644
--- a/arch/cris/arch-v32/drivers/gpio.c
+++ b/arch/cris/arch-v32/drivers/mach-fs/gpio.c
@@ -1,68 +1,15 @@
-/* $Id: gpio.c,v 1.16 2005/06/19 17:06:49 starvik Exp $
- *
+/*
  * ETRAX CRISv32 general port I/O device
  *
- * Copyright (c) 1999, 2000, 2001, 2002, 2003 Axis Communications AB
+ * Copyright (c) 1999-2006 Axis Communications AB
  *
  * Authors:    Bjorn Wesen      (initial version)
  *             Ola Knutsson     (LED handling)
  *             Johan Adolfsson  (read/set directions, write, port G,
  *                               port to ETRAX FS.
  *
- * $Log: gpio.c,v $
- * Revision 1.16  2005/06/19 17:06:49  starvik
- * Merge of Linux 2.6.12.
- *
- * Revision 1.15  2005/05/25 08:22:20  starvik
- * Changed GPIO port order to fit packages/devices/axis-2.4.
- *
- * Revision 1.14  2005/04/24 18:35:08  starvik
- * Updated with final register headers.
- *
- * Revision 1.13  2005/03/15 15:43:00  starvik
- * dev_id needs to be supplied for shared IRQs.
- *
- * Revision 1.12  2005/03/10 17:12:00  starvik
- * Protect alarm list with spinlock.
- *
- * Revision 1.11  2005/01/05 06:08:59  starvik
- * No need to do local_irq_disable after local_irq_save.
- *
- * Revision 1.10  2004/11/19 08:38:31  starvik
- * Removed old crap.
- *
- * Revision 1.9  2004/05/14 07:58:02  starvik
- * Merge of changes from 2.4
- *
- * Revision 1.8  2003/09/11 07:29:50  starvik
- * Merge of Linux 2.6.0-test5
- *
- * Revision 1.7  2003/07/10 13:25:46  starvik
- * Compiles for 2.5.74
- * Lindented ethernet.c
- *
- * Revision 1.6  2003/07/04 08:27:46  starvik
- * Merge of Linux 2.5.74
- *
- * Revision 1.5  2003/06/10 08:26:37  johana
- * Etrax -> ETRAX CRISv32
- *
- * Revision 1.4  2003/06/05 14:22:48  johana
- * Initialise some_alarms.
- *
- * Revision 1.3  2003/06/05 10:15:46  johana
- * New INTR_VECT macros.
- * Enable interrupts in global config.
- *
- * Revision 1.2  2003/06/03 15:52:50  johana
- * Initial CRIS v32 version.
- *
- * Revision 1.1  2003/06/03 08:53:15  johana
- * Copy of os/lx25/arch/cris/arch-v10/drivers/gpio.c version 1.7.
- *
  */
 
-
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
@@ -77,14 +24,20 @@
 #include <linux/spinlock.h>
 
 #include <asm/etraxgpio.h>
-#include <asm/arch/hwregs/reg_map.h>
-#include <asm/arch/hwregs/reg_rdwr.h>
-#include <asm/arch/hwregs/gio_defs.h>
-#include <asm/arch/hwregs/intr_vect_defs.h>
+#include <hwregs/reg_map.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/gio_defs.h>
+#include <hwregs/intr_vect_defs.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/irq.h>
 
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+#include "../i2c.h"
+
+#define VIRT_I2C_ADDR 0x40
+#endif
+
 /* The following gio ports on ETRAX FS is available:
  * pa  8 bits, supports interrupts off, hi, low, set, posedge, negedge anyedge
  * pb 18 bits
@@ -100,7 +53,12 @@
 
 #if 0
 static int dp_cnt;
-#define DP(x) do { dp_cnt++; if (dp_cnt % 1000 == 0) x; }while(0)
+#define DP(x) \
+	do { \
+		dp_cnt++; \
+		if (dp_cnt % 1000 == 0) \
+			x; \
+	} while (0)
 #else
 #define DP(x)
 #endif
@@ -111,13 +69,18 @@ static char gpio_name[] = "etrax gpio";
 static wait_queue_head_t *gpio_wq;
 #endif
 
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+static int virtual_gpio_ioctl(struct file *file, unsigned int cmd,
+	unsigned long arg);
+#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);
+	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);
+static unsigned int gpio_poll(struct file *filp,
+	struct poll_table_struct *wait);
 
 /* private data per open() of this driver */
 
@@ -136,18 +99,25 @@ struct gpio_private {
 
 /* linked list of alarms to check for */
 
-static struct gpio_private *alarmlist = 0;
+static struct gpio_private *alarmlist;
 
-static int gpio_some_alarms = 0; /* Set if someone uses alarm */
-static unsigned long gpio_pa_high_alarms = 0;
-static unsigned long gpio_pa_low_alarms = 0;
+static int gpio_some_alarms; /* Set if someone uses alarm */
+static unsigned long gpio_pa_high_alarms;
+static unsigned long gpio_pa_low_alarms;
 
 static DEFINE_SPINLOCK(alarm_lock);
 
 #define NUM_PORTS (GPIO_MINOR_LAST+1)
-#define GIO_REG_RD_ADDR(reg) (volatile unsigned long*) (regi_gio + REG_RD_ADDR_gio_##reg )
-#define GIO_REG_WR_ADDR(reg) (volatile unsigned long*) (regi_gio + REG_RD_ADDR_gio_##reg )
+#define GIO_REG_RD_ADDR(reg) \
+	(volatile unsigned long *)(regi_gio + REG_RD_ADDR_gio_##reg)
+#define GIO_REG_WR_ADDR(reg) \
+	(volatile unsigned long *)(regi_gio + REG_RD_ADDR_gio_##reg)
 unsigned long led_dummy;
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+static unsigned long virtual_dummy;
+static unsigned long virtual_rw_pv_oe = CONFIG_ETRAX_DEF_GIO_PV_OE;
+static unsigned short cached_virtual_gpio_read;
+#endif
 
 static volatile unsigned long *data_out[NUM_PORTS] = {
 	GIO_REG_WR_ADDR(rw_pa_dout),
@@ -156,6 +126,9 @@ static volatile unsigned long *data_out[NUM_PORTS] = {
 	GIO_REG_WR_ADDR(rw_pc_dout),
 	GIO_REG_WR_ADDR(rw_pd_dout),
 	GIO_REG_WR_ADDR(rw_pe_dout),
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	&virtual_dummy,
+#endif
 };
 
 static volatile unsigned long *data_in[NUM_PORTS] = {
@@ -165,6 +138,9 @@ static volatile unsigned long *data_in[NUM_PORTS] = {
 	GIO_REG_RD_ADDR(r_pc_din),
 	GIO_REG_RD_ADDR(r_pd_din),
 	GIO_REG_RD_ADDR(r_pe_din),
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	&virtual_dummy,
+#endif
 };
 
 static unsigned long changeable_dir[NUM_PORTS] = {
@@ -174,6 +150,9 @@ static unsigned long changeable_dir[NUM_PORTS] = {
 	CONFIG_ETRAX_PC_CHANGEABLE_DIR,
 	CONFIG_ETRAX_PD_CHANGEABLE_DIR,
 	CONFIG_ETRAX_PE_CHANGEABLE_DIR,
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	CONFIG_ETRAX_PV_CHANGEABLE_DIR,
+#endif
 };
 
 static unsigned long changeable_bits[NUM_PORTS] = {
@@ -183,6 +162,9 @@ static unsigned long changeable_bits[NUM_PORTS] = {
 	CONFIG_ETRAX_PC_CHANGEABLE_BITS,
 	CONFIG_ETRAX_PD_CHANGEABLE_BITS,
 	CONFIG_ETRAX_PE_CHANGEABLE_BITS,
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	CONFIG_ETRAX_PV_CHANGEABLE_BITS,
+#endif
 };
 
 static volatile unsigned long *dir_oe[NUM_PORTS] = {
@@ -192,13 +174,14 @@ static volatile unsigned long *dir_oe[NUM_PORTS] = {
 	GIO_REG_WR_ADDR(rw_pc_oe),
 	GIO_REG_WR_ADDR(rw_pd_oe),
 	GIO_REG_WR_ADDR(rw_pe_oe),
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	&virtual_rw_pv_oe,
+#endif
 };
 
 
 
-static unsigned int
-gpio_poll(struct file *file,
-	  poll_table *wait)
+static unsigned int gpio_poll(struct file *file, struct poll_table_struct *wait)
 {
 	unsigned int mask = 0;
 	struct gpio_private *priv = (struct gpio_private *)file->private_data;
@@ -210,65 +193,50 @@ gpio_poll(struct file *file,
 		unsigned long flags;
 
 		local_irq_save(flags);
-		data = REG_TYPE_CONV(unsigned long, reg_gio_r_pa_din, REG_RD(gio, regi_gio, r_pa_din));
+		data = REG_TYPE_CONV(unsigned long, reg_gio_r_pa_din,
+			REG_RD(gio, regi_gio, r_pa_din));
 		/* PA has support for interrupt
 		 * lets activate high for those low and with highalarm set
 		 */
 		intr_cfg = REG_RD(gio, regi_gio, rw_intr_cfg);
 
 		tmp = ~data & priv->highalarm & 0xFF;
-                if (tmp & (1 << 0)) {
+		if (tmp & (1 << 0))
 			intr_cfg.pa0 = regk_gio_hi;
-		}
-                if (tmp & (1 << 1)) {
+		if (tmp & (1 << 1))
 			intr_cfg.pa1 = regk_gio_hi;
-		}
-                if (tmp & (1 << 2)) {
+		if (tmp & (1 << 2))
 			intr_cfg.pa2 = regk_gio_hi;
-		}
-                if (tmp & (1 << 3)) {
+		if (tmp & (1 << 3))
 			intr_cfg.pa3 = regk_gio_hi;
-		}
-                if (tmp & (1 << 4)) {
+		if (tmp & (1 << 4))
 			intr_cfg.pa4 = regk_gio_hi;
-		}
-                if (tmp & (1 << 5)) {
+		if (tmp & (1 << 5))
 			intr_cfg.pa5 = regk_gio_hi;
-		}
-                if (tmp & (1 << 6)) {
+		if (tmp & (1 << 6))
 			intr_cfg.pa6 = regk_gio_hi;
-		}
-                if (tmp & (1 << 7)) {
+		if (tmp & (1 << 7))
 			intr_cfg.pa7 = regk_gio_hi;
-		}
 		/*
 		 * lets activate low for those high and with lowalarm set
 		 */
 		tmp = data & priv->lowalarm & 0xFF;
-                if (tmp & (1 << 0)) {
+		if (tmp & (1 << 0))
 			intr_cfg.pa0 = regk_gio_lo;
-		}
-                if (tmp & (1 << 1)) {
+		if (tmp & (1 << 1))
 			intr_cfg.pa1 = regk_gio_lo;
-		}
-                if (tmp & (1 << 2)) {
+		if (tmp & (1 << 2))
 			intr_cfg.pa2 = regk_gio_lo;
-		}
-                if (tmp & (1 << 3)) {
+		if (tmp & (1 << 3))
 			intr_cfg.pa3 = regk_gio_lo;
-		}
-                if (tmp & (1 << 4)) {
+		if (tmp & (1 << 4))
 			intr_cfg.pa4 = regk_gio_lo;
-		}
-                if (tmp & (1 << 5)) {
+		if (tmp & (1 << 5))
 			intr_cfg.pa5 = regk_gio_lo;
-		}
-                if (tmp & (1 << 6)) {
+		if (tmp & (1 << 6))
 			intr_cfg.pa6 = regk_gio_lo;
-		}
-                if (tmp & (1 << 7)) {
+		if (tmp & (1 << 7))
 			intr_cfg.pa7 = regk_gio_lo;
-		}
 
 		REG_WR(gio, regi_gio, rw_intr_cfg, intr_cfg);
 		local_irq_restore(flags);
@@ -277,50 +245,65 @@ gpio_poll(struct file *file,
 	else
 		return 0;
 
-	if ((data & priv->highalarm) ||
-	    (~data & priv->lowalarm)) {
+	if ((data & priv->highalarm) || (~data & priv->lowalarm))
 		mask = POLLIN|POLLRDNORM;
-	}
 
-	DP(printk("gpio_poll ready: mask 0x%08X\n", mask));
+	DP(printk(KERN_DEBUG "gpio_poll ready: mask 0x%08X\n", mask));
 	return mask;
 }
 
 int etrax_gpio_wake_up_check(void)
 {
-	struct gpio_private *priv = alarmlist;
+	struct gpio_private *priv;
 	unsigned long data = 0;
-        int ret = 0;
+	unsigned long flags;
+	int ret = 0;
+	spin_lock_irqsave(&alarm_lock, flags);
+	priv = alarmlist;
 	while (priv) {
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+		if (priv->minor == GPIO_MINOR_V)
+			data = (unsigned long)cached_virtual_gpio_read;
+		else {
+			data = *data_in[priv->minor];
+			if (priv->minor == GPIO_MINOR_A)
+				priv->lowalarm |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);
+		}
+#else
 		data = *data_in[priv->minor];
+#endif
 		if ((data & priv->highalarm) ||
 		    (~data & priv->lowalarm)) {
-			DP(printk("etrax_gpio_wake_up_check %i\n",priv->minor));
+			DP(printk(KERN_DEBUG
+				"etrax_gpio_wake_up_check %i\n", priv->minor));
 			wake_up_interruptible(&priv->alarm_wq);
-                        ret = 1;
+			ret = 1;
 		}
 		priv = priv->next;
 	}
-        return ret;
+	spin_unlock_irqrestore(&alarm_lock, flags);
+	return ret;
 }
 
 static irqreturn_t
-gpio_poll_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+gpio_poll_timer_interrupt(int irq, void *dev_id)
 {
-	if (gpio_some_alarms) {
+	if (gpio_some_alarms)
 		return IRQ_RETVAL(etrax_gpio_wake_up_check());
-	}
-        return IRQ_NONE;
+	return IRQ_NONE;
 }
 
 static irqreturn_t
-gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+gpio_pa_interrupt(int irq, void *dev_id)
 {
 	reg_gio_rw_intr_mask intr_mask;
 	reg_gio_r_masked_intr masked_intr;
 	reg_gio_rw_ack_intr ack_intr;
 	unsigned long tmp;
 	unsigned long tmp2;
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	unsigned char enable_gpiov_ack = 0;
+#endif
 
 	/* Find what PA interrupts are active */
 	masked_intr = REG_RD(gio, regi_gio, r_masked_intr);
@@ -331,6 +314,17 @@ gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 	tmp &= (gpio_pa_high_alarms | gpio_pa_low_alarms);
 	spin_unlock(&alarm_lock);
 
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	/* Something changed on virtual GPIO. Interrupt is acked by
+	 * reading the device.
+	 */
+	if (tmp & (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN)) {
+		i2c_read(VIRT_I2C_ADDR, (void *)&cached_virtual_gpio_read,
+			sizeof(cached_virtual_gpio_read));
+		enable_gpiov_ack = 1;
+	}
+#endif
+
 	/* Ack them */
 	ack_intr = REG_TYPE_CONV(reg_gio_rw_ack_intr, unsigned long, tmp);
 	REG_WR(gio, regi_gio, rw_ack_intr, ack_intr);
@@ -339,18 +333,24 @@ gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 	intr_mask = REG_RD(gio, regi_gio, rw_intr_mask);
 	tmp2 = REG_TYPE_CONV(unsigned long, reg_gio_rw_intr_mask, intr_mask);
 	tmp2 &= ~tmp;
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	/* Do not disable interrupt on virtual GPIO. Changes on virtual
+	 * pins are only noticed by an interrupt.
+	 */
+	if (enable_gpiov_ack)
+		tmp2 |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);
+#endif
 	intr_mask = REG_TYPE_CONV(reg_gio_rw_intr_mask, unsigned long, tmp2);
 	REG_WR(gio, regi_gio, rw_intr_mask, intr_mask);
 
-	if (gpio_some_alarms) {
+	if (gpio_some_alarms)
 		return IRQ_RETVAL(etrax_gpio_wake_up_check());
-	}
-        return IRQ_NONE;
+	return IRQ_NONE;
 }
 
 
-static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
-                          loff_t *off)
+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;
@@ -360,29 +360,31 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
 	ssize_t retval = count;
 	/* Only bits 0-7 may be used for write operations but allow all
 	   devices except leds... */
-	if (priv->minor == GPIO_MINOR_LEDS) {
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	if (priv->minor == GPIO_MINOR_V)
+		return -EFAULT;
+#endif
+	if (priv->minor == GPIO_MINOR_LEDS)
 		return -EFAULT;
-	}
 
-	if (!access_ok(VERIFY_READ, buf, count)) {
+	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) {
+	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));
+	D(printk(KERN_DEBUG "gpio_write: %lu to data 0x%02X clk 0x%02X "
+		"msb: %i\n", count, data_mask, clk_mask, write_msb));
 	port = data_out[priv->minor];
 
 	while (count--) {
 		int i;
 		data = *buf++;
 		if (priv->write_msb) {
-			for (i = 7; i >= 0;i--) {
+			for (i = 7; i >= 0; i--) {
 				local_irq_save(flags);
 				shadow = *port;
 				*port = shadow &= ~clk_mask;
@@ -395,7 +397,7 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
 				local_irq_restore(flags);
 			}
 		} else {
-			for (i = 0; i <= 7;i++) {
+			for (i = 0; i <= 7; i++) {
 				local_irq_save(flags);
 				shadow = *port;
 				*port = shadow &= ~clk_mask;
@@ -423,18 +425,16 @@ gpio_open(struct inode *inode, struct file *filp)
 	if (p > GPIO_MINOR_LAST)
 		return -EINVAL;
 
-	priv = kmalloc(sizeof(struct gpio_private),
-					      GFP_KERNEL);
+	priv = kmalloc(sizeof(struct gpio_private), GFP_KERNEL);
 
 	if (!priv)
 		return -ENOMEM;
+	memset(priv, 0, sizeof(*priv));
 
 	priv->minor = p;
 
-	/* initialize the io/alarm struct and link it into our alarmlist */
+	/* initialize the io/alarm struct */
 
-	priv->next = alarmlist;
-	alarmlist = priv;
 	priv->clk_mask = 0;
 	priv->data_mask = 0;
 	priv->highalarm = 0;
@@ -443,20 +443,30 @@ gpio_open(struct inode *inode, struct file *filp)
 
 	filp->private_data = (void *)priv;
 
+	/* link it into our alarmlist */
+	spin_lock_irq(&alarm_lock);
+	priv->next = alarmlist;
+	alarmlist = priv;
+	spin_unlock_irq(&alarm_lock);
+
 	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;
+	struct gpio_private *p;
+	struct gpio_private *todel;
 	/* local copies while updating them: */
 	unsigned long a_high, a_low;
 	unsigned long some_alarms;
 
 	/* unlink from alarmlist and free the private structure */
 
+	spin_lock_irq(&alarm_lock);
+	p = alarmlist;
+	todel = (struct gpio_private *)filp->private_data;
+
 	if (p == todel) {
 		alarmlist = todel->next;
 	} else {
@@ -468,26 +478,35 @@ gpio_release(struct inode *inode, struct file *filp)
 	kfree(todel);
 	/* Check if there are still any alarms set */
 	p = alarmlist;
-        some_alarms = 0;
+	some_alarms = 0;
 	a_high = 0;
 	a_low = 0;
 	while (p) {
 		if (p->minor == GPIO_MINOR_A) {
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+			p->lowalarm |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);
+#endif
 			a_high |= p->highalarm;
 			a_low |= p->lowalarm;
 		}
 
-		if (p->highalarm | p->lowalarm) {
+		if (p->highalarm | p->lowalarm)
 			some_alarms = 1;
-		}
 		p = p->next;
 	}
 
-	spin_lock(&alarm_lock);
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	/* Variables 'some_alarms' and 'a_low' needs to be set here again
+	 * to ensure that interrupt for virtual GPIO is handled.
+	 */
+	some_alarms = 1;
+	a_low |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);
+#endif
+
 	gpio_some_alarms = some_alarms;
 	gpio_pa_high_alarms = a_high;
 	gpio_pa_low_alarms = a_low;
-	spin_unlock(&alarm_lock);
+	spin_unlock_irq(&alarm_lock);
 
 	return 0;
 }
@@ -496,7 +515,7 @@ gpio_release(struct inode *inode, struct file *filp)
  * set alarms to wait for using a subsequent select().
  */
 
-unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg)
+inline unsigned long setget_input(struct gpio_private *priv, unsigned long arg)
 {
 	/* Set direction 0=unchanged 1=input,
 	 * return mask with 1=input
@@ -512,13 +531,17 @@ unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg)
 
 	if (priv->minor == GPIO_MINOR_A)
 		dir_shadow ^= 0xFF;    /* Only 8 bits */
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	else if (priv->minor == GPIO_MINOR_V)
+		dir_shadow ^= 0xFFFF;  /* Only 16 bits */
+#endif
 	else
 		dir_shadow ^= 0x3FFFF; /* Only 18 bits */
 	return dir_shadow;
 
 } /* setget_input */
 
-unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg)
+inline unsigned long setget_output(struct gpio_private *priv, unsigned long arg)
 {
 	unsigned long flags;
 	unsigned long dir_shadow;
@@ -542,20 +565,22 @@ gpio_ioctl(struct inode *inode, struct file *file,
 	unsigned long val;
 	unsigned long shadow;
 	struct gpio_private *priv = (struct gpio_private *)file->private_data;
-	if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) {
+	if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE)
 		return -EINVAL;
-	}
+
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	if (priv->minor == GPIO_MINOR_V)
+		return virtual_gpio_ioctl(file, cmd, arg);
+#endif
 
 	switch (_IOC_NR(cmd)) {
 	case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */
-		// read the port
+		/* Read the port. */
 		return *data_in[priv->minor];
 		break;
 	case IO_SETBITS:
 		local_irq_save(flags);
-                if (arg & 0x04)
-                  printk("GPIO SET 2\n");
-		// set changeable bits with a 1 in arg
+		/* Set changeable bits with a 1 in arg. */
 		shadow = *data_out[priv->minor];
 		shadow |=  (arg & changeable_bits[priv->minor]);
 		*data_out[priv->minor] = shadow;
@@ -563,46 +588,42 @@ gpio_ioctl(struct inode *inode, struct file *file,
 		break;
 	case IO_CLRBITS:
 		local_irq_save(flags);
-                if (arg & 0x04)
-                  printk("GPIO CLR 2\n");
-		// clear changeable bits with a 1 in arg
+		/* Clear changeable bits with a 1 in arg. */
 		shadow = *data_out[priv->minor];
 		shadow &=  ~(arg & changeable_bits[priv->minor]);
 		*data_out[priv->minor] = shadow;
 		local_irq_restore(flags);
 		break;
 	case IO_HIGHALARM:
-		// set alarm when bits with 1 in arg go high
+		/* Set alarm when bits with 1 in arg go high. */
 		priv->highalarm |= arg;
-		spin_lock(&alarm_lock);
+		spin_lock_irqsave(&alarm_lock, flags);
 		gpio_some_alarms = 1;
-		if (priv->minor == GPIO_MINOR_A) {
+		if (priv->minor == GPIO_MINOR_A)
 			gpio_pa_high_alarms |= arg;
-		}
-		spin_unlock(&alarm_lock);
+		spin_unlock_irqrestore(&alarm_lock, flags);
 		break;
 	case IO_LOWALARM:
-		// set alarm when bits with 1 in arg go low
+		/* Set alarm when bits with 1 in arg go low. */
 		priv->lowalarm |= arg;
-		spin_lock(&alarm_lock);
+		spin_lock_irqsave(&alarm_lock, flags);
 		gpio_some_alarms = 1;
-		if (priv->minor == GPIO_MINOR_A) {
+		if (priv->minor == GPIO_MINOR_A)
 			gpio_pa_low_alarms |= arg;
-		}
-		spin_unlock(&alarm_lock);
+		spin_unlock_irqrestore(&alarm_lock, flags);
 		break;
 	case IO_CLRALARM:
-		// clear alarm for bits with 1 in arg
+		/* Clear alarm for bits with 1 in arg. */
 		priv->highalarm &= ~arg;
 		priv->lowalarm  &= ~arg;
-		spin_lock(&alarm_lock);
+		spin_lock_irqsave(&alarm_lock, flags);
 		if (priv->minor == GPIO_MINOR_A) {
 			if (gpio_pa_high_alarms & arg ||
-			    gpio_pa_low_alarms & arg) {
+			    gpio_pa_low_alarms & arg)
 				/* Must update the gpio_pa_*alarms masks */
-			}
+				;
 		}
-		spin_unlock(&alarm_lock);
+		spin_unlock_irqrestore(&alarm_lock, flags);
 		break;
 	case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */
 		/* Read direction 0=input 1=output */
@@ -633,8 +654,7 @@ gpio_ioctl(struct inode *inode, struct file *file,
 		if (!((priv->clk_mask & changeable_bits[priv->minor]) &&
 		      (priv->data_mask & changeable_bits[priv->minor]) &&
 		      (priv->clk_mask & dir_shadow) &&
-		      (priv->data_mask & dir_shadow)))
-		{
+		      (priv->data_mask & dir_shadow))) {
 			priv->clk_mask = 0;
 			priv->data_mask = 0;
 			return -EPERM;
@@ -644,34 +664,34 @@ gpio_ioctl(struct inode *inode, struct file *file,
 	case IO_READ_INBITS:
 		/* *arg is result of reading the input pins */
 		val = *data_in[priv->minor];
-		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
+		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 */
 		val = *data_out[priv->minor];
-		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
+		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)))
+		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)))
+		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)))
+		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)))
+		if (copy_to_user((unsigned long *)arg, &val, sizeof(val)))
 			return -EFAULT;
 		break;
 	default:
@@ -684,6 +704,133 @@ gpio_ioctl(struct inode *inode, struct file *file,
 	return 0;
 }
 
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+static int
+virtual_gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	unsigned long flags;
+	unsigned short val;
+	unsigned short shadow;
+	struct gpio_private *priv = (struct gpio_private *)file->private_data;
+
+	switch (_IOC_NR(cmd)) {
+	case IO_SETBITS:
+		local_irq_save(flags);
+		/* Set changeable bits with a 1 in arg. */
+		i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));
+		shadow |= ~*dir_oe[priv->minor];
+		shadow |= (arg & changeable_bits[priv->minor]);
+		i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));
+		local_irq_restore(flags);
+		break;
+	case IO_CLRBITS:
+		local_irq_save(flags);
+		/* Clear changeable bits with a 1 in arg. */
+		i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));
+		shadow |= ~*dir_oe[priv->minor];
+		shadow &= ~(arg & changeable_bits[priv->minor]);
+		i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));
+		local_irq_restore(flags);
+		break;
+	case IO_HIGHALARM:
+		/* Set alarm when bits with 1 in arg go high. */
+		priv->highalarm |= arg;
+		spin_lock(&alarm_lock);
+		gpio_some_alarms = 1;
+		spin_unlock(&alarm_lock);
+		break;
+	case IO_LOWALARM:
+		/* Set alarm when bits with 1 in arg go low. */
+		priv->lowalarm |= arg;
+		spin_lock(&alarm_lock);
+		gpio_some_alarms = 1;
+		spin_unlock(&alarm_lock);
+		break;
+	case IO_CLRALARM:
+		/* Clear alarm for bits with 1 in arg. */
+		priv->highalarm &= ~arg;
+		priv->lowalarm  &= ~arg;
+		spin_lock(&alarm_lock);
+		spin_unlock(&alarm_lock);
+		break;
+	case IO_CFG_WRITE_MODE:
+	{
+		unsigned long dir_shadow;
+		dir_shadow = *dir_oe[priv->minor];
+
+		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 & changeable_bits[priv->minor]) &&
+		      (priv->data_mask & changeable_bits[priv->minor]) &&
+		      (priv->clk_mask & dir_shadow) &&
+		      (priv->data_mask & 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 */
+		val = cached_virtual_gpio_read;
+		val &= ~*dir_oe[priv->minor];
+		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 */
+		i2c_read(VIRT_I2C_ADDR, (void *)&val, sizeof(val));
+		val &= *dir_oe[priv->minor];
+		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.
+		 */
+		unsigned short input_mask = ~*dir_oe[priv->minor];
+		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;
+		if ((input_mask & val) != input_mask) {
+			/* Input pins changed. All ports desired as input
+			 * should be set to logic 1.
+			 */
+			unsigned short change = input_mask ^ val;
+			i2c_read(VIRT_I2C_ADDR, (void *)&shadow,
+				sizeof(shadow));
+			shadow &= ~change;
+			shadow |= val;
+			i2c_write(VIRT_I2C_ADDR, (void *)&shadow,
+				sizeof(shadow));
+		}
+		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:
+		return -EINVAL;
+	} /* switch */
+  return 0;
+}
+#endif /* CONFIG_ETRAX_VIRTUAL_GPIO */
+
 static int
 gpio_leds_ioctl(unsigned int cmd, unsigned long arg)
 {
@@ -694,8 +841,8 @@ gpio_leds_ioctl(unsigned int cmd, unsigned long arg)
 	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);
+		CRIS_LED_ACTIVE_SET_G(green);
+		CRIS_LED_ACTIVE_SET_R(red);
 		break;
 
 	default:
@@ -705,7 +852,7 @@ gpio_leds_ioctl(unsigned int cmd, unsigned long arg)
 	return 0;
 }
 
-const struct file_operations gpio_fops = {
+struct file_operations gpio_fops = {
 	.owner       = THIS_MODULE,
 	.poll        = gpio_poll,
 	.ioctl       = gpio_ioctl,
@@ -714,6 +861,66 @@ const struct file_operations gpio_fops = {
 	.release     = gpio_release,
 };
 
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+static void
+virtual_gpio_init(void)
+{
+	reg_gio_rw_intr_cfg intr_cfg;
+	reg_gio_rw_intr_mask intr_mask;
+	unsigned short shadow;
+
+	shadow = ~virtual_rw_pv_oe; /* Input ports should be set to logic 1 */
+	shadow |= CONFIG_ETRAX_DEF_GIO_PV_OUT;
+	i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));
+
+	/* Set interrupt mask and on what state the interrupt shall trigger.
+	 * For virtual gpio the interrupt shall trigger on logic '0'.
+	 */
+	intr_cfg = REG_RD(gio, regi_gio, rw_intr_cfg);
+	intr_mask = REG_RD(gio, regi_gio, rw_intr_mask);
+
+	switch (CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN) {
+	case 0:
+		intr_cfg.pa0 = regk_gio_lo;
+		intr_mask.pa0 = regk_gio_yes;
+		break;
+	case 1:
+		intr_cfg.pa1 = regk_gio_lo;
+		intr_mask.pa1 = regk_gio_yes;
+		break;
+	case 2:
+		intr_cfg.pa2 = regk_gio_lo;
+		intr_mask.pa2 = regk_gio_yes;
+		break;
+	case 3:
+		intr_cfg.pa3 = regk_gio_lo;
+		intr_mask.pa3 = regk_gio_yes;
+		break;
+	case 4:
+		intr_cfg.pa4 = regk_gio_lo;
+		intr_mask.pa4 = regk_gio_yes;
+		break;
+	case 5:
+		intr_cfg.pa5 = regk_gio_lo;
+		intr_mask.pa5 = regk_gio_yes;
+		break;
+	case 6:
+		intr_cfg.pa6 = regk_gio_lo;
+		intr_mask.pa6 = regk_gio_yes;
+		break;
+	case 7:
+		intr_cfg.pa7 = regk_gio_lo;
+		intr_mask.pa7 = regk_gio_yes;
+	break;
+	}
+
+	REG_WR(gio, regi_gio, rw_intr_cfg, intr_cfg);
+	REG_WR(gio, regi_gio, rw_intr_mask, intr_mask);
+
+	gpio_pa_low_alarms |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);
+	gpio_some_alarms = 1;
+}
+#endif
 
 /* main driver initialization routine, called from mem.c */
 
@@ -721,7 +928,6 @@ static __init int
 gpio_init(void)
 {
 	int res;
-	reg_intr_vect_rw_mask intr_mask;
 
 	/* do the formalities */
 
@@ -732,30 +938,30 @@ gpio_init(void)
 	}
 
 	/* Clear all leds */
-	LED_NETWORK_SET(0);
-	LED_ACTIVE_SET(0);
-	LED_DISK_READ(0);
-	LED_DISK_WRITE(0);
-
-	printk("ETRAX FS GPIO driver v2.5, (c) 2003-2005 Axis Communications AB\n");
+	CRIS_LED_NETWORK_GRP0_SET(0);
+	CRIS_LED_NETWORK_GRP1_SET(0);
+	CRIS_LED_ACTIVE_SET(0);
+	CRIS_LED_DISK_READ(0);
+	CRIS_LED_DISK_WRITE(0);
+
+	printk(KERN_INFO "ETRAX FS GPIO driver v2.5, (c) 2003-2007 "
+		"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(TIMER_INTR_VECT, gpio_poll_timer_interrupt,
-			IRQF_SHARED | IRQF_DISABLED,"gpio poll", &alarmlist)) {
-		printk("err: timer0 irq for gpio\n");
-	}
-	if (request_irq(GEN_IO_INTR_VECT, gpio_pa_interrupt,
-			IRQF_SHARED | IRQF_DISABLED,"gpio PA", &alarmlist)) {
-		printk("err: PA irq for gpio\n");
-	}
-	/* enable the gio and timer irq in global config */
-	intr_mask = REG_RD(intr_vect, regi_irq, rw_mask);
-	intr_mask.timer = 1;
-	intr_mask.gen_io = 1;
-	REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
+	if (request_irq(TIMER0_INTR_VECT, gpio_poll_timer_interrupt,
+			IRQF_SHARED | IRQF_DISABLED, "gpio poll", &alarmlist))
+		printk(KERN_ERR "timer0 irq for gpio\n");
+
+	if (request_irq(GIO_INTR_VECT, gpio_pa_interrupt,
+			IRQF_SHARED | IRQF_DISABLED, "gpio PA", &alarmlist))
+		printk(KERN_ERR "PA irq for gpio\n");
+
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+	virtual_gpio_init();
+#endif
 
 	return res;
 }
diff --git a/arch/cris/arch-v32/drivers/nandflash.c b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c
index 5ce015c6bb0d..aa01b134458a 100644
--- a/arch/cris/arch-v32/drivers/nandflash.c
+++ b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c
@@ -4,9 +4,7 @@
  *  Copyright (c) 2004
  *
  *  Derived from drivers/mtd/nand/spia.c
- * 	  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
- *
- * $Id: nandflash.c,v 1.3 2005/06/01 10:57:12 starvik Exp $
+ *	  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -21,10 +19,10 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <asm/arch/memmap.h>
-#include <asm/arch/hwregs/reg_map.h>
-#include <asm/arch/hwregs/reg_rdwr.h>
-#include <asm/arch/hwregs/gio_defs.h>
-#include <asm/arch/hwregs/bif_core_defs.h>
+#include <hwregs/reg_map.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/gio_defs.h>
+#include <hwregs/bif_core_defs.h>
 #include <asm/io.h>
 
 #define CE_BIT 4
@@ -32,44 +30,65 @@
 #define ALE_BIT 6
 #define BY_BIT 7
 
-static struct mtd_info *crisv32_mtd = NULL;
+struct mtd_info_wrapper {
+	struct mtd_info info;
+	struct nand_chip chip;
+};
+
+/* Bitmask for control pins */
+#define PIN_BITMASK ((1 << CE_BIT) | (1 << CLE_BIT) | (1 << ALE_BIT))
+
+/* Bitmask for mtd nand control bits */
+#define CTRL_BITMASK (NAND_NCE | NAND_CLE | NAND_ALE)
+
+
+static struct mtd_info *crisv32_mtd;
 /*
  *	hardware specific access to control-lines
-*/
-static void crisv32_hwcontrol(struct mtd_info *mtd, int cmd)
+ */
+static void crisv32_hwcontrol(struct mtd_info *mtd, int cmd,
+			      unsigned int ctrl)
 {
 	unsigned long flags;
-	reg_gio_rw_pa_dout dout = REG_RD(gio, regi_gio, rw_pa_dout);
+	reg_gio_rw_pa_dout dout;
+	struct nand_chip *this = mtd->priv;
 
 	local_irq_save(flags);
-	switch(cmd){
-		case NAND_CTL_SETCLE:
-		     dout.data |= (1<<CLE_BIT);
-		     break;
-		case NAND_CTL_CLRCLE:
-		     dout.data &= ~(1<<CLE_BIT);
-		     break;
-		case NAND_CTL_SETALE:
-		     dout.data |= (1<<ALE_BIT);
-		     break;
-		case NAND_CTL_CLRALE:
-		     dout.data &= ~(1<<ALE_BIT);
-		     break;
-		case NAND_CTL_SETNCE:
-		     dout.data |= (1<<CE_BIT);
-		     break;
-		case NAND_CTL_CLRNCE:
-		     dout.data &= ~(1<<CE_BIT);
-		     break;
+
+	/* control bits change */
+	if (ctrl & NAND_CTRL_CHANGE) {
+		dout = REG_RD(gio, regi_gio, rw_pa_dout);
+		dout.data &= ~PIN_BITMASK;
+
+#if (CE_BIT == 4 && NAND_NCE == 1 &&  \
+     CLE_BIT == 5 && NAND_CLE == 2 && \
+     ALE_BIT == 6 && NAND_ALE == 4)
+		/* Pins in same order as control bits, but shifted.
+		 * Optimize for this case; works for 2.6.18 */
+		dout.data |= ((ctrl & CTRL_BITMASK) ^ NAND_NCE) << CE_BIT;
+#else
+		/* the slow way */
+		if (!(ctrl & NAND_NCE))
+			dout.data |= (1 << CE_BIT);
+		if (ctrl & NAND_CLE)
+			dout.data |= (1 << CLE_BIT);
+		if (ctrl & NAND_ALE)
+			dout.data |= (1 << ALE_BIT);
+#endif
+		REG_WR(gio, regi_gio, rw_pa_dout, dout);
 	}
-	REG_WR(gio, regi_gio, rw_pa_dout, dout);
+
+	/* command to chip */
+	if (cmd != NAND_CMD_NONE)
+		writeb(cmd, this->IO_ADDR_W);
+
 	local_irq_restore(flags);
 }
 
 /*
 *	read device ready pin
 */
-int crisv32_device_ready(struct mtd_info *mtd)
+static int crisv32_device_ready(struct mtd_info *mtd)
 {
 	reg_gio_r_pa_din din = REG_RD(gio, regi_gio, r_pa_din);
 	return ((din.data & (1 << BY_BIT)) >> BY_BIT);
@@ -78,21 +97,23 @@ int crisv32_device_ready(struct mtd_info *mtd)
 /*
  * Main initialization routine
  */
-struct mtd_info* __init crisv32_nand_flash_probe (void)
+struct mtd_info *__init crisv32_nand_flash_probe(void)
 {
 	void __iomem *read_cs;
 	void __iomem *write_cs;
 
-	reg_bif_core_rw_grp3_cfg bif_cfg = REG_RD(bif_core, regi_bif_core, rw_grp3_cfg);
+	reg_bif_core_rw_grp3_cfg bif_cfg = REG_RD(bif_core, regi_bif_core,
+		rw_grp3_cfg);
 	reg_gio_rw_pa_oe pa_oe = REG_RD(gio, regi_gio, rw_pa_oe);
+	struct mtd_info_wrapper *wrapper;
 	struct nand_chip *this;
 	int err = 0;
 
 	/* Allocate memory for MTD device structure and private data */
-	crisv32_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
-				GFP_KERNEL);
-	if (!crisv32_mtd) {
-		printk ("Unable to allocate CRISv32 NAND MTD device structure.\n");
+	wrapper = kzalloc(sizeof(struct mtd_info_wrapper), GFP_KERNEL);
+	if (!wrapper) {
+		printk(KERN_ERR "Unable to allocate CRISv32 NAND MTD "
+			"device structure.\n");
 		err = -ENOMEM;
 		return NULL;
 	}
@@ -101,45 +122,42 @@ struct mtd_info* __init crisv32_nand_flash_probe (void)
 	write_cs = ioremap(MEM_CSP1_START | MEM_NON_CACHEABLE, 8192);
 
 	if (!read_cs || !write_cs) {
-		printk("CRISv32 NAND ioremap failed\n");
+		printk(KERN_ERR "CRISv32 NAND ioremap failed\n");
 		err = -EIO;
 		goto out_mtd;
 	}
 
 	/* Get pointer to private data */
-	this = (struct nand_chip *) (&crisv32_mtd[1]);
+	this = &wrapper->chip;
+	crisv32_mtd = &wrapper->info;
 
 	pa_oe.oe |= 1 << CE_BIT;
 	pa_oe.oe |= 1 << ALE_BIT;
 	pa_oe.oe |= 1 << CLE_BIT;
-	pa_oe.oe &= ~ (1 << BY_BIT);
+	pa_oe.oe &= ~(1 << BY_BIT);
 	REG_WR(gio, regi_gio, rw_pa_oe, pa_oe);
 
 	bif_cfg.gated_csp0 = regk_bif_core_rd;
 	bif_cfg.gated_csp1 = regk_bif_core_wr;
 	REG_WR(bif_core, regi_bif_core, rw_grp3_cfg, bif_cfg);
 
-	/* Initialize structures */
-	memset((char *) crisv32_mtd, 0, sizeof(struct mtd_info));
-	memset((char *) this, 0, sizeof(struct nand_chip));
-
 	/* Link the private data with the MTD structure */
 	crisv32_mtd->priv = this;
 
 	/* Set address of NAND IO lines */
 	this->IO_ADDR_R = read_cs;
 	this->IO_ADDR_W = write_cs;
-	this->hwcontrol = crisv32_hwcontrol;
+	this->cmd_ctrl = crisv32_hwcontrol;
 	this->dev_ready = crisv32_device_ready;
 	/* 20 us command delay time */
 	this->chip_delay = 20;
-	this->eccmode = NAND_ECC_SOFT;
+	this->ecc.mode = NAND_ECC_SOFT;
 
 	/* Enable the following for a flash based bad block table */
-	this->options = NAND_USE_FLASH_BBT;
+	/* this->options = NAND_USE_FLASH_BBT; */
 
-	/* Scan to find existence of the device */
-	if (nand_scan (crisv32_mtd, 1)) {
+	/* Scan to find existance of the device */
+	if (nand_scan(crisv32_mtd, 1)) {
 		err = -ENXIO;
 		goto out_ior;
 	}
@@ -150,7 +168,7 @@ out_ior:
 	iounmap((void *)read_cs);
 	iounmap((void *)write_cs);
 out_mtd:
-	kfree (crisv32_mtd);
-        return NULL;
+	kfree(wrapper);
+	return NULL;
 }
 
diff --git a/arch/cris/arch-v32/drivers/pcf8563.c b/arch/cris/arch-v32/drivers/pcf8563.c
index 6dbd700d3d66..53db3870ba04 100644
--- a/arch/cris/arch-v32/drivers/pcf8563.c
+++ b/arch/cris/arch-v32/drivers/pcf8563.c
@@ -10,7 +10,7 @@
  * 400 kbits/s. The built-in word address register is incremented
  * automatically after each written or read byte.
  *
- * Copyright (c) 2002-2003, Axis Communications AB
+ * Copyright (c) 2002-2007, Axis Communications AB
  * All rights reserved.
  *
  * Author: Tobias Anderberg <tobiasa@axis.com>.
@@ -26,6 +26,7 @@
 #include <linux/ioctl.h>
 #include <linux/delay.h>
 #include <linux/bcd.h>
+#include <linux/mutex.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -37,24 +38,27 @@
 #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.1 $"
+#define DRIVER_VERSION	"$Revision: 1.17 $"
 
 /* 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 DEFINE_MUTEX(rtc_lock); /* Protect state etc */
+
 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);
-int pcf8563_open(struct inode *, struct file *);
-int pcf8563_release(struct inode *, struct file *);
+
+/* Cache VL bit value read at driver init since writing the RTC_SECOND
+ * register clears the VL status.
+ */
+static int voltage_low;
 
 static const struct file_operations pcf8563_fops = {
 	.owner =	THIS_MODULE,
-	.ioctl =	pcf8563_ioctl,
-	.open =		pcf8563_open,
-	.release =	pcf8563_release,
+	.ioctl =	pcf8563_ioctl
 };
 
 unsigned char
@@ -62,7 +66,7 @@ pcf8563_readreg(int reg)
 {
 	unsigned char res = rtc_read(reg);
 
-	/* The PCF8563 does not return 0 for unimplemented bits */
+	/* The PCF8563 does not return 0 for unimplemented bits. */
 	switch (reg) {
 		case RTC_SECONDS:
 		case RTC_MINUTES:
@@ -95,11 +99,6 @@ pcf8563_readreg(int reg)
 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);
 }
 
@@ -114,11 +113,13 @@ get_rtc_time(struct rtc_time *tm)
 	tm->tm_mon  = rtc_read(RTC_MONTH);
 	tm->tm_year = rtc_read(RTC_YEAR);
 
-	if (tm->tm_sec & 0x80)
-		printk(KERN_WARNING "%s: RTC Voltage Low - reliable date/time "
+	if (tm->tm_sec & 0x80) {
+		printk(KERN_ERR "%s: RTC Voltage Low - reliable date/time "
 		       "information is no longer guaranteed!\n", PCF8563_NAME);
+	}
 
-	tm->tm_year  = BCD_TO_BIN(tm->tm_year) + ((tm->tm_mon & 0x80) ? 100 : 0);
+	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;
@@ -137,8 +138,19 @@ get_rtc_time(struct rtc_time *tm)
 int __init
 pcf8563_init(void)
 {
+	static int res;
+	static int first = 1;
+
+	if (!first)
+		return res;
+	first = 0;
+
 	/* Initiate the i2c protocol. */
-	i2c_init();
+	res = i2c_init();
+	if (res < 0) {
+		printk(KERN_CRIT "pcf8563_init: Failed to init i2c.\n");
+		return res;
+	}
 
 	/*
 	 * First of all we need to reset the chip. This is done by
@@ -170,24 +182,20 @@ pcf8563_init(void)
 	if (rtc_write(RTC_WEEKDAY_ALARM, 0x80) < 0)
 		goto err;
 
-	if (register_chrdev(PCF8563_MAJOR, DEVICE_NAME, &pcf8563_fops) < 0) {
-		printk(KERN_INFO "%s: Unable to get major number %d for RTC device.\n",
-		       PCF8563_NAME, PCF8563_MAJOR);
-		return -1;
+	/* Check for low voltage, and warn about it. */
+	if (rtc_read(RTC_SECONDS) & 0x80) {
+		voltage_low = 1;
+		printk(KERN_WARNING "%s: RTC Voltage Low - reliable "
+		       "date/time information is no longer guaranteed!\n",
+		       PCF8563_NAME);
 	}
 
-	printk(KERN_INFO "%s Real-Time Clock Driver, %s\n", PCF8563_NAME, DRIVER_VERSION);
-
-	/* Check for low voltage, and warn about it.. */
-	if (rtc_read(RTC_SECONDS) & 0x80)
-		printk(KERN_WARNING "%s: RTC Voltage Low - reliable date/time "
-		       "information is no longer guaranteed!\n", PCF8563_NAME);
-
-	return 0;
+	return res;
 
 err:
 	printk(KERN_INFO "%s: Error initializing chip.\n", PCF8563_NAME);
-	return -1;
+	res = -1;
+	return res;
 }
 
 void __exit
@@ -200,8 +208,8 @@ pcf8563_exit(void)
  * 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)
+int pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+	unsigned long arg)
 {
 	/* Some sanity checks. */
 	if (_IOC_TYPE(cmd) != RTC_MAGIC)
@@ -211,125 +219,147 @@ pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned
 		return -ENOTTY;
 
 	switch (cmd) {
-		case RTC_RD_TIME:
-		{
-			struct rtc_time tm;
-
-			memset(&tm, 0, sizeof (struct rtc_time));
-			get_rtc_time(&tm);
-
-			if (copy_to_user((struct rtc_time *) arg, &tm, sizeof tm)) {
-				return -EFAULT;
-			}
-
-			return 0;
+	case RTC_RD_TIME:
+	{
+		struct rtc_time tm;
+
+		mutex_lock(&rtc_lock);
+		memset(&tm, 0, sizeof tm);
+		get_rtc_time(&tm);
+
+		if (copy_to_user((struct rtc_time *) arg, &tm,
+				 sizeof tm)) {
+			spin_unlock(&rtc_lock);
+			return -EFAULT;
 		}
 
-		case RTC_SET_TIME:
-		{
-#ifdef CONFIG_ETRAX_RTC_READONLY
+		mutex_unlock(&rtc_lock);
+
+		return 0;
+	}
+	case RTC_SET_TIME:
+	{
+		int leap;
+		int year;
+		int century;
+		struct rtc_time tm;
+
+		memset(&tm, 0, sizeof tm);
+		if (!capable(CAP_SYS_TIME))
 			return -EPERM;
-#else
-			int leap;
-			int year;
-			int century;
-			struct rtc_time tm;
-
-			if (!capable(CAP_SYS_TIME))
-				return -EPERM;
-
-			if (copy_from_user(&tm, (struct rtc_time *) arg, sizeof tm))
-				return -EFAULT;
-
-			/* Convert from struct tm to struct rtc_time. */
-			tm.tm_year += 1900;
-			tm.tm_mon += 1;
-
-			/*
-			 * Check if tm.tm_year is a leap year. A year is a leap
-			 * year if it is divisible by 4 but not 100, except
-			 * that years divisible by 400 _are_ leap years.
-			 */
-			year = tm.tm_year;
-			leap = (tm.tm_mon == 2) && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 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_wday >= 7) ||
-			    (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_WEEKDAY, tm.tm_wday); /* Not coded in BCD. */
-			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 (copy_from_user(&tm, (struct rtc_time *) arg,
+				   sizeof tm))
+			return -EFAULT;
+
+		/* Convert from struct tm to struct rtc_time. */
+		tm.tm_year += 1900;
+		tm.tm_mon += 1;
+
+		/*
+		 * Check if tm.tm_year is a leap year. A year is a leap
+		 * year if it is divisible by 4 but not 100, except
+		 * that years divisible by 400 _are_ leap years.
+		 */
+		year = tm.tm_year;
+		leap = (tm.tm_mon == 2) &&
+			((year % 4 == 0 && year % 100 != 0) || year % 400 == 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_wday >= 7) ||
+		    (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_mon);
+		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;
+
+		mutex_lock(&rtc_lock);
+
+		rtc_write(RTC_YEAR, tm.tm_year);
+		rtc_write(RTC_MONTH, tm.tm_mon);
+		rtc_write(RTC_WEEKDAY, tm.tm_wday); /* Not coded in BCD. */
+		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);
+
+		mutex_unlock(&rtc_lock);
+
+		return 0;
+	}
+	case RTC_VL_READ:
+		if (voltage_low)
+			printk(KERN_ERR "%s: RTC Voltage Low - "
+			       "reliable date/time information is no "
+			       "longer guaranteed!\n", PCF8563_NAME);
 
-			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;
+		if (copy_to_user((int *) arg, &voltage_low, sizeof(int)))
+			return -EFAULT;
+		return 0;
 
-			return 0;
-		}
+	case RTC_VL_CLR:
+	{
+		/* Clear the VL bit in the seconds register in case
+		 * the time has not been set already (which would
+		 * have cleared it). This does not really matter
+		 * because of the cached voltage_low value but do it
+		 * anyway for consistency. */
 
-		case RTC_VLOW_SET:
-		{
-			/* Clear the VL bit in the seconds register */
-			int ret = rtc_read(RTC_SECONDS);
+		int ret = rtc_read(RTC_SECONDS);
 
-			rtc_write(RTC_SECONDS, (ret & 0x7F));
+		rtc_write(RTC_SECONDS, (ret & 0x7F));
 
-			return 0;
-		}
+		/* Clear the cached value. */
+		voltage_low = 0;
 
-		default:
-			return -ENOTTY;
+		return 0;
+	}
+	default:
+		return -ENOTTY;
 	}
 
 	return 0;
 }
 
-int
-pcf8563_open(struct inode *inode, struct file *filp)
+static int __init pcf8563_register(void)
 {
-	return 0;
-}
+	if (pcf8563_init() < 0) {
+		printk(KERN_INFO "%s: Unable to initialize Real-Time Clock "
+		       "Driver, %s\n", PCF8563_NAME, DRIVER_VERSION);
+		return -1;
+	}
+
+	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);
+
+	/* Check for low voltage, and warn about it. */
+	if (voltage_low) {
+		printk(KERN_WARNING "%s: RTC Voltage Low - reliable date/time "
+		       "information is no longer guaranteed!\n", PCF8563_NAME);
+	}
 
-int
-pcf8563_release(struct inode *inode, struct file *filp)
-{
 	return 0;
 }
 
-module_init(pcf8563_init);
+module_init(pcf8563_register);
 module_exit(pcf8563_exit);
diff --git a/arch/cris/arch-v32/drivers/sync_serial.c b/arch/cris/arch-v32/drivers/sync_serial.c
index d581b0a92a3f..47c377df6fb3 100644
--- a/arch/cris/arch-v32/drivers/sync_serial.c
+++ b/arch/cris/arch-v32/drivers/sync_serial.c
@@ -1,5 +1,5 @@
 /*
- * Simple synchronous serial port driver for ETRAX FS.
+ * Simple synchronous serial port driver for ETRAX FS and Artpec-3.
  *
  * Copyright (c) 2005 Axis Communications AB
  *
@@ -21,17 +21,18 @@
 #include <linux/spinlock.h>
 
 #include <asm/io.h>
-#include <asm/arch/dma.h>
-#include <asm/arch/pinmux.h>
-#include <asm/arch/hwregs/reg_rdwr.h>
-#include <asm/arch/hwregs/sser_defs.h>
-#include <asm/arch/hwregs/dma_defs.h>
-#include <asm/arch/hwregs/dma.h>
-#include <asm/arch/hwregs/intr_vect_defs.h>
-#include <asm/arch/hwregs/intr_vect.h>
-#include <asm/arch/hwregs/reg_map.h>
+#include <dma.h>
+#include <pinmux.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/sser_defs.h>
+#include <hwregs/dma_defs.h>
+#include <hwregs/dma.h>
+#include <hwregs/intr_vect_defs.h>
+#include <hwregs/intr_vect.h>
+#include <hwregs/reg_map.h>
 #include <asm/sync_serial.h>
 
+
 /* The receiver is a bit tricky beacuse of the continuous stream of data.*/
 /*                                                                       */
 /* Three DMA descriptors are linked together. Each DMA descriptor is     */
@@ -63,8 +64,10 @@
 /* words can be handled */
 #define IN_BUFFER_SIZE 12288
 #define IN_DESCR_SIZE 256
-#define NUM_IN_DESCR (IN_BUFFER_SIZE/IN_DESCR_SIZE)
-#define OUT_BUFFER_SIZE 4096
+#define NBR_IN_DESCR (IN_BUFFER_SIZE/IN_DESCR_SIZE)
+
+#define OUT_BUFFER_SIZE 1024*8
+#define NBR_OUT_DESCR 8
 
 #define DEFAULT_FRAME_RATE 0
 #define DEFAULT_WORD_RATE 7
@@ -78,6 +81,8 @@
 #define DEBUGPOLL(x)
 #define DEBUGRXINT(x)
 #define DEBUGTXINT(x)
+#define DEBUGTRDMA(x)
+#define DEBUGOUTBUF(x)
 
 typedef struct sync_port
 {
@@ -97,10 +102,11 @@ typedef struct sync_port
 	int output;
 	int input;
 
-	volatile unsigned int out_count; /* Remaining bytes for current transfer */
-	unsigned char* outp; /* Current position in out_buffer */
-	volatile unsigned char* volatile readp;  /* Next byte to be read by application */
-	volatile unsigned char* volatile writep; /* Next byte to be written by etrax */
+	/* Next byte to be read by application */
+	volatile unsigned char *volatile readp;
+	/* Next byte to be written by etrax */
+	volatile unsigned char *volatile writep;
+
 	unsigned int in_buffer_size;
 	unsigned int inbufchunk;
 	unsigned char out_buffer[OUT_BUFFER_SIZE] __attribute__ ((aligned(32)));
@@ -108,11 +114,30 @@ typedef struct sync_port
 	unsigned char flip[IN_BUFFER_SIZE] __attribute__ ((aligned(32)));
 	struct dma_descr_data* next_rx_desc;
 	struct dma_descr_data* prev_rx_desc;
+
+	/* Pointer to the first available descriptor in the ring,
+	 * unless active_tr_descr == catch_tr_descr and a dma
+	 * transfer is active */
+	struct dma_descr_data *active_tr_descr;
+
+	/* Pointer to the first allocated descriptor in the ring */
+	struct dma_descr_data *catch_tr_descr;
+
+	/* Pointer to the descriptor with the current end-of-list */
+	struct dma_descr_data *prev_tr_descr;
 	int full;
 
-	dma_descr_data in_descr[NUM_IN_DESCR] __attribute__ ((__aligned__(16)));
+	/* Pointer to the first byte being read by DMA
+	 * or current position in out_buffer if not using DMA. */
+	unsigned char *out_rd_ptr;
+
+	/* Number of bytes currently locked for being read by DMA */
+	int out_buf_count;
+
+	dma_descr_data in_descr[NBR_IN_DESCR] __attribute__ ((__aligned__(16)));
 	dma_descr_context in_context __attribute__ ((__aligned__(32)));
-	dma_descr_data out_descr __attribute__ ((__aligned__(16)));
+	dma_descr_data out_descr[NBR_OUT_DESCR]
+		__attribute__ ((__aligned__(16)));
 	dma_descr_context out_context __attribute__ ((__aligned__(32)));
 	wait_queue_head_t out_wait_q;
 	wait_queue_head_t in_wait_q;
@@ -143,11 +168,11 @@ static ssize_t sync_serial_read(struct file *file, char *buf,
 #endif
 
 static void send_word(sync_port* port);
-static void start_dma(struct sync_port *port, const char* data, int count);
+static void start_dma_out(struct sync_port *port, const char *data, int count);
 static void start_dma_in(sync_port* port);
 #ifdef SYNC_SER_DMA
-static irqreturn_t tr_interrupt(int irq, void *dev_id, struct pt_regs * regs);
-static irqreturn_t rx_interrupt(int irq, void *dev_id, struct pt_regs * regs);
+static irqreturn_t tr_interrupt(int irq, void *dev_id);
+static irqreturn_t rx_interrupt(int irq, void *dev_id);
 #endif
 
 #if (defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) && \
@@ -157,22 +182,49 @@ static irqreturn_t rx_interrupt(int irq, void *dev_id, struct pt_regs * regs);
 #define SYNC_SER_MANUAL
 #endif
 #ifdef SYNC_SER_MANUAL
-static irqreturn_t manual_interrupt(int irq, void *dev_id, struct pt_regs * regs);
+static irqreturn_t manual_interrupt(int irq, void *dev_id);
+#endif
+
+#ifdef CONFIG_ETRAXFS	/* ETRAX FS */
+#define OUT_DMA_NBR 4
+#define IN_DMA_NBR 5
+#define PINMUX_SSER pinmux_sser0
+#define SYNCSER_INST regi_sser0
+#define SYNCSER_INTR_VECT SSER0_INTR_VECT
+#define OUT_DMA_INST regi_dma4
+#define IN_DMA_INST regi_dma5
+#define DMA_OUT_INTR_VECT DMA4_INTR_VECT
+#define DMA_IN_INTR_VECT DMA5_INTR_VECT
+#define REQ_DMA_SYNCSER dma_sser0
+#else			/* Artpec-3 */
+#define OUT_DMA_NBR 6
+#define IN_DMA_NBR 7
+#define PINMUX_SSER pinmux_sser
+#define SYNCSER_INST regi_sser
+#define SYNCSER_INTR_VECT SSER_INTR_VECT
+#define OUT_DMA_INST regi_dma6
+#define IN_DMA_INST regi_dma7
+#define DMA_OUT_INTR_VECT DMA6_INTR_VECT
+#define DMA_IN_INTR_VECT DMA7_INTR_VECT
+#define REQ_DMA_SYNCSER dma_sser
 #endif
 
 /* The ports */
 static struct sync_port ports[]=
 {
 	{
-		.regi_sser             = regi_sser0,
-		.regi_dmaout           = regi_dma4,
-		.regi_dmain            = regi_dma5,
+		.regi_sser             = SYNCSER_INST,
+		.regi_dmaout           = OUT_DMA_INST,
+		.regi_dmain            = IN_DMA_INST,
 #if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)
                 .use_dma               = 1,
 #else
                 .use_dma               = 0,
 #endif
-	},
+	}
+#ifdef CONFIG_ETRAXFS
+	,
+
 	{
 		.regi_sser             = regi_sser1,
 		.regi_dmaout           = regi_dma6,
@@ -183,9 +235,10 @@ static struct sync_port ports[]=
                 .use_dma               = 0,
 #endif
 	}
+#endif
 };
 
-#define NUMBER_OF_PORTS ARRAY_SIZE(ports)
+#define NBR_PORTS ARRAY_SIZE(ports)
 
 static const struct file_operations sync_serial_fops = {
 	.owner   = THIS_MODULE,
@@ -200,19 +253,21 @@ static const struct file_operations sync_serial_fops = {
 static int __init etrax_sync_serial_init(void)
 {
 	ports[0].enabled = 0;
+#ifdef CONFIG_ETRAXFS
 	ports[1].enabled = 0;
-
-	if (register_chrdev(SYNC_SERIAL_MAJOR,"sync serial", &sync_serial_fops) <0 )
-	{
-		printk("unable to get major for synchronous serial port\n");
+#endif
+	if (register_chrdev(SYNC_SERIAL_MAJOR, "sync serial",
+			&sync_serial_fops) < 0) {
+		printk(KERN_WARNING
+			"Unable to get major for synchronous serial port\n");
 		return -EBUSY;
 	}
 
 	/* Initialize Ports */
 #if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0)
-	if (crisv32_pinmux_alloc_fixed(pinmux_sser0))
-	{
-		printk("Unable to allocate pins for syncrhronous serial port 0\n");
+	if (crisv32_pinmux_alloc_fixed(PINMUX_SSER)) {
+		printk(KERN_WARNING
+			"Unable to alloc pins for synchronous serial port 0\n");
 		return -EIO;
 	}
 	ports[0].enabled = 1;
@@ -220,33 +275,40 @@ static int __init etrax_sync_serial_init(void)
 #endif
 
 #if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1)
-	if (crisv32_pinmux_alloc_fixed(pinmux_sser1))
-	{
-		printk("Unable to allocate pins for syncrhronous serial port 0\n");
+	if (crisv32_pinmux_alloc_fixed(pinmux_sser1)) {
+		printk(KERN_WARNING
+			"Unable to alloc pins for synchronous serial port 0\n");
 		return -EIO;
 	}
 	ports[1].enabled = 1;
 	initialize_port(1);
 #endif
 
-	printk("ETRAX FS synchronous serial port driver\n");
+#ifdef CONFIG_ETRAXFS
+	printk(KERN_INFO "ETRAX FS synchronous serial port driver\n");
+#else
+	printk(KERN_INFO "Artpec-3 synchronous serial port driver\n");
+#endif
 	return 0;
 }
 
 static void __init initialize_port(int portnbr)
 {
-	struct sync_port* port = &ports[portnbr];
+	int __attribute__((unused)) i;
+	struct sync_port *port = &ports[portnbr];
 	reg_sser_rw_cfg cfg = {0};
 	reg_sser_rw_frm_cfg frm_cfg = {0};
 	reg_sser_rw_tr_cfg tr_cfg = {0};
 	reg_sser_rw_rec_cfg rec_cfg = {0};
 
-	DEBUG(printk("Init sync serial port %d\n", portnbr));
+	DEBUG(printk(KERN_DEBUG "Init sync serial port %d\n", portnbr));
 
 	port->port_nbr = portnbr;
 	port->init_irqs = 1;
 
-	port->outp = port->out_buffer;
+	port->out_rd_ptr = port->out_buffer;
+	port->out_buf_count = 0;
+
 	port->output = 1;
 	port->input = 0;
 
@@ -255,7 +317,7 @@ static void __init initialize_port(int portnbr)
 	port->in_buffer_size = IN_BUFFER_SIZE;
 	port->inbufchunk = IN_DESCR_SIZE;
 	port->next_rx_desc = &port->in_descr[0];
-	port->prev_rx_desc = &port->in_descr[NUM_IN_DESCR-1];
+	port->prev_rx_desc = &port->in_descr[NBR_IN_DESCR-1];
 	port->prev_rx_desc->eol = 1;
 
 	init_waitqueue_head(&port->out_wait_q);
@@ -286,8 +348,13 @@ static void __init initialize_port(int portnbr)
 	tr_cfg.sample_size = 7;
 	tr_cfg.sh_dir = regk_sser_msbfirst;
 	tr_cfg.use_dma = port->use_dma ? regk_sser_yes : regk_sser_no;
+#if 0
 	tr_cfg.rate_ctrl = regk_sser_bulk;
 	tr_cfg.data_pin_use = regk_sser_dout;
+#else
+	tr_cfg.rate_ctrl = regk_sser_iso;
+	tr_cfg.data_pin_use = regk_sser_dout;
+#endif
 	tr_cfg.bulk_wspace = 1;
 	REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg);
 
@@ -296,6 +363,27 @@ static void __init initialize_port(int portnbr)
 	rec_cfg.use_dma = port->use_dma ? regk_sser_yes : regk_sser_no;
 	rec_cfg.fifo_thr = regk_sser_inf;
 	REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg);
+
+#ifdef SYNC_SER_DMA
+	/* Setup the descriptor ring for dma out/transmit. */
+	for (i = 0; i < NBR_OUT_DESCR; i++) {
+		port->out_descr[i].wait = 0;
+		port->out_descr[i].intr = 1;
+		port->out_descr[i].eol = 0;
+		port->out_descr[i].out_eop = 0;
+		port->out_descr[i].next =
+			(dma_descr_data *)virt_to_phys(&port->out_descr[i+1]);
+	}
+
+	/* Create a ring from the list. */
+	port->out_descr[NBR_OUT_DESCR-1].next =
+		(dma_descr_data *)virt_to_phys(&port->out_descr[0]);
+
+	/* Setup context for traversing the ring. */
+	port->active_tr_descr = &port->out_descr[0];
+	port->prev_tr_descr = &port->out_descr[NBR_OUT_DESCR-1];
+	port->catch_tr_descr = &port->out_descr[0];
+#endif
 }
 
 static inline int sync_data_avail(struct sync_port *port)
@@ -311,7 +399,7 @@ static inline int sync_data_avail(struct sync_port *port)
 	 *  ^rp  ^wp    ^wp ^rp
 	 */
 
-  	if (end >= start)
+	if (end >= start)
 		avail = end - start;
 	else
 		avail = port->in_buffer_size - (start - end);
@@ -331,7 +419,7 @@ static inline int sync_data_avail_to_end(struct sync_port *port)
 	 *  ^rp  ^wp    ^wp ^rp
 	 */
 
-  	if (end >= start)
+	if (end >= start)
 		avail = end - start;
 	else
 		avail = port->flip + port->in_buffer_size - start;
@@ -341,66 +429,69 @@ static inline int sync_data_avail_to_end(struct sync_port *port)
 static int sync_serial_open(struct inode *inode, struct file *file)
 {
 	int dev = iminor(inode);
-	sync_port* port;
+	sync_port *port;
 	reg_dma_rw_cfg cfg = {.en = regk_dma_yes};
 	reg_dma_rw_intr_mask intr_mask = {.data = regk_dma_yes};
 
-	DEBUG(printk("Open sync serial port %d\n", dev));
+	DEBUG(printk(KERN_DEBUG "Open sync serial port %d\n", dev));
 
-	if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled)
+	if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled)
 	{
-		DEBUG(printk("Invalid minor %d\n", dev));
+		DEBUG(printk(KERN_DEBUG "Invalid minor %d\n", dev));
 		return -ENODEV;
 	}
 	port = &ports[dev];
 	/* Allow open this device twice (assuming one reader and one writer) */
 	if (port->busy == 2)
 	{
-		DEBUG(printk("Device is busy.. \n"));
+		DEBUG(printk(KERN_DEBUG "Device is busy.. \n"));
 		return -EBUSY;
 	}
+
+
 	if (port->init_irqs) {
 		if (port->use_dma) {
-			if (port == &ports[0]){
+			if (port == &ports[0]) {
 #ifdef SYNC_SER_DMA
-				if(request_irq(DMA4_INTR_VECT,
-					       tr_interrupt,
-					       0,
-					       "synchronous serial 0 dma tr",
-					       &ports[0])) {
+				if (request_irq(DMA_OUT_INTR_VECT,
+						tr_interrupt,
+						0,
+						"synchronous serial 0 dma tr",
+						&ports[0])) {
 					printk(KERN_CRIT "Can't allocate sync serial port 0 IRQ");
 					return -EBUSY;
-				} else if(request_irq(DMA5_INTR_VECT,
-						      rx_interrupt,
-						      0,
-						      "synchronous serial 1 dma rx",
-						      &ports[0])) {
-					free_irq(DMA4_INTR_VECT, &port[0]);
+				} else if (request_irq(DMA_IN_INTR_VECT,
+						rx_interrupt,
+						0,
+						"synchronous serial 1 dma rx",
+						&ports[0])) {
+					free_irq(DMA_OUT_INTR_VECT, &port[0]);
 					printk(KERN_CRIT "Can't allocate sync serial port 0 IRQ");
 					return -EBUSY;
-				} else if (crisv32_request_dma(SYNC_SER0_TX_DMA_NBR,
-                                                               "synchronous serial 0 dma tr",
-                                                               DMA_VERBOSE_ON_ERROR,
-                                                               0,
-                                                               dma_sser0)) {
-					free_irq(DMA4_INTR_VECT, &port[0]);
-					free_irq(DMA5_INTR_VECT, &port[0]);
+				} else if (crisv32_request_dma(OUT_DMA_NBR,
+						"synchronous serial 0 dma tr",
+						DMA_VERBOSE_ON_ERROR,
+						0,
+						REQ_DMA_SYNCSER)) {
+					free_irq(DMA_OUT_INTR_VECT, &port[0]);
+					free_irq(DMA_IN_INTR_VECT, &port[0]);
 					printk(KERN_CRIT "Can't allocate sync serial port 0 TX DMA channel");
 					return -EBUSY;
-				} else if (crisv32_request_dma(SYNC_SER0_RX_DMA_NBR,
-                                                               "synchronous serial 0 dma rec",
-                                                               DMA_VERBOSE_ON_ERROR,
-                                                               0,
-                                                               dma_sser0)) {
-					crisv32_free_dma(SYNC_SER0_TX_DMA_NBR);
-					free_irq(DMA4_INTR_VECT, &port[0]);
-					free_irq(DMA5_INTR_VECT, &port[0]);
+				} else if (crisv32_request_dma(IN_DMA_NBR,
+						"synchronous serial 0 dma rec",
+						DMA_VERBOSE_ON_ERROR,
+						0,
+						REQ_DMA_SYNCSER)) {
+					crisv32_free_dma(OUT_DMA_NBR);
+					free_irq(DMA_OUT_INTR_VECT, &port[0]);
+					free_irq(DMA_IN_INTR_VECT, &port[0]);
 					printk(KERN_CRIT "Can't allocate sync serial port 1 RX DMA channel");
 					return -EBUSY;
 				}
 #endif
 			}
-			else if (port == &ports[1]){
+#ifdef CONFIG_ETRAXFS
+			else if (port == &ports[1]) {
 #ifdef SYNC_SER_DMA
 				if (request_irq(DMA6_INTR_VECT,
 						tr_interrupt,
@@ -417,20 +508,22 @@ static int sync_serial_open(struct inode *inode, struct file *file)
 					free_irq(DMA6_INTR_VECT, &ports[1]);
 					printk(KERN_CRIT "Can't allocate sync serial port 3 IRQ");
 					return -EBUSY;
-				} else if (crisv32_request_dma(SYNC_SER1_TX_DMA_NBR,
-                                                               "synchronous serial 1 dma tr",
-                                                               DMA_VERBOSE_ON_ERROR,
-                                                               0,
-                                                               dma_sser1)) {
-					free_irq(21, &ports[1]);
-					free_irq(20, &ports[1]);
+				} else if (crisv32_request_dma(
+						SYNC_SER1_TX_DMA_NBR,
+						"synchronous serial 1 dma tr",
+						DMA_VERBOSE_ON_ERROR,
+						0,
+						dma_sser1)) {
+					free_irq(DMA6_INTR_VECT, &ports[1]);
+					free_irq(DMA7_INTR_VECT, &ports[1]);
 					printk(KERN_CRIT "Can't allocate sync serial port 3 TX DMA channel");
 					return -EBUSY;
-				} else if (crisv32_request_dma(SYNC_SER1_RX_DMA_NBR,
-							    "synchronous serial 3 dma rec",
-							    DMA_VERBOSE_ON_ERROR,
-							    0,
-							    dma_sser1)) {
+				} else if (crisv32_request_dma(
+						SYNC_SER1_RX_DMA_NBR,
+						"synchronous serial 3 dma rec",
+						DMA_VERBOSE_ON_ERROR,
+						0,
+						dma_sser1)) {
 					crisv32_free_dma(SYNC_SER1_TX_DMA_NBR);
 					free_irq(DMA6_INTR_VECT, &ports[1]);
 					free_irq(DMA7_INTR_VECT, &ports[1]);
@@ -439,14 +532,14 @@ static int sync_serial_open(struct inode *inode, struct file *file)
 				}
 #endif
 			}
-
+#endif
                         /* Enable DMAs */
 			REG_WR(dma, port->regi_dmain, rw_cfg, cfg);
 			REG_WR(dma, port->regi_dmaout, rw_cfg, cfg);
 			/* Enable DMA IRQs */
 			REG_WR(dma, port->regi_dmain, rw_intr_mask, intr_mask);
 			REG_WR(dma, port->regi_dmaout, rw_intr_mask, intr_mask);
-			/* Set up wordsize = 2 for DMAs. */
+			/* Set up wordsize = 1 for DMAs. */
 			DMA_WR_CMD (port->regi_dmain, regk_dma_set_w_size1);
 			DMA_WR_CMD (port->regi_dmaout, regk_dma_set_w_size1);
 
@@ -455,7 +548,7 @@ static int sync_serial_open(struct inode *inode, struct file *file)
 		} else { /* !port->use_dma */
 #ifdef SYNC_SER_MANUAL
 			if (port == &ports[0]) {
-				if (request_irq(SSER0_INTR_VECT,
+				if (request_irq(SYNCSER_INTR_VECT,
 						manual_interrupt,
 						0,
 						"synchronous serial manual irq",
@@ -463,7 +556,9 @@ static int sync_serial_open(struct inode *inode, struct file *file)
 					printk("Can't allocate sync serial manual irq");
 					return -EBUSY;
 				}
-			} else if (port == &ports[1]) {
+			}
+#ifdef CONFIG_ETRAXFS
+			else if (port == &ports[1]) {
 				if (request_irq(SSER1_INTR_VECT,
 						manual_interrupt,
 						0,
@@ -473,11 +568,13 @@ static int sync_serial_open(struct inode *inode, struct file *file)
 					return -EBUSY;
 				}
 			}
+#endif
 			port->init_irqs = 0;
 #else
 			panic("sync_serial: Manual mode not supported.\n");
 #endif /* SYNC_SER_MANUAL */
 		}
+
 	} /* port->init_irqs */
 
 	port->busy++;
@@ -487,9 +584,9 @@ static int sync_serial_open(struct inode *inode, struct file *file)
 static int sync_serial_release(struct inode *inode, struct file *file)
 {
 	int dev = iminor(inode);
-	sync_port* port;
+	sync_port *port;
 
-	if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled)
+	if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled)
 	{
 		DEBUG(printk("Invalid minor %d\n", dev));
 		return -ENODEV;
@@ -506,17 +603,37 @@ static unsigned int sync_serial_poll(struct file *file, poll_table *wait)
 {
 	int dev = iminor(file->f_path.dentry->d_inode);
 	unsigned int mask = 0;
-	sync_port* port;
+	sync_port *port;
 	DEBUGPOLL( static unsigned int prev_mask = 0; );
 
 	port = &ports[dev];
+
+	if (!port->started) {
+		reg_sser_rw_cfg cfg = REG_RD(sser, port->regi_sser, rw_cfg);
+		reg_sser_rw_rec_cfg rec_cfg =
+			REG_RD(sser, port->regi_sser, rw_rec_cfg);
+		cfg.en = regk_sser_yes;
+		rec_cfg.rec_en = port->input;
+		REG_WR(sser, port->regi_sser, rw_cfg, cfg);
+		REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg);
+		port->started = 1;
+	}
+
 	poll_wait(file, &port->out_wait_q, wait);
 	poll_wait(file, &port->in_wait_q, wait);
-	/* Some room to write */
-	if (port->out_count < OUT_BUFFER_SIZE)
+
+	/* No active transfer, descriptors are available */
+	if (port->output && !port->tr_running)
+		mask |= POLLOUT | POLLWRNORM;
+
+	/* Descriptor and buffer space available. */
+	if (port->output &&
+	    port->active_tr_descr != port->catch_tr_descr &&
+	    port->out_buf_count < OUT_BUFFER_SIZE)
 		mask |=  POLLOUT | POLLWRNORM;
+
 	/* At least an inbufchunk of data */
-	if (sync_data_avail(port) >= port->inbufchunk)
+	if (port->input && sync_data_avail(port) >= port->inbufchunk)
 		mask |= POLLIN | POLLRDNORM;
 
 	DEBUGPOLL(if (mask != prev_mask)
@@ -531,15 +648,16 @@ static int sync_serial_ioctl(struct inode *inode, struct file *file,
 		  unsigned int cmd, unsigned long arg)
 {
 	int return_val = 0;
+	int dma_w_size = regk_dma_set_w_size1;
 	int dev = iminor(file->f_path.dentry->d_inode);
-	sync_port* port;
+	sync_port *port;
 	reg_sser_rw_tr_cfg tr_cfg;
 	reg_sser_rw_rec_cfg rec_cfg;
 	reg_sser_rw_frm_cfg frm_cfg;
 	reg_sser_rw_cfg gen_cfg;
 	reg_sser_rw_intr_mask intr_mask;
 
-	if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled)
+	if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled)
 	{
 		DEBUG(printk("Invalid minor %d\n", dev));
 		return -1;
@@ -558,61 +676,81 @@ static int sync_serial_ioctl(struct inode *inode, struct file *file,
 	case SSP_SPEED:
 		if (GET_SPEED(arg) == CODEC)
 		{
+			unsigned int freq;
+
 			gen_cfg.base_freq = regk_sser_f32;
-			/* FREQ = 0 => 4 MHz => clk_div = 7*/
-			gen_cfg.clk_div = 6 + (1 << GET_FREQ(arg));
-		}
-		else
-		{
+
+			/* Clock divider will internally be
+			 * gen_cfg.clk_div + 1.
+			 */
+
+			freq = GET_FREQ(arg);
+			switch (freq) {
+			case FREQ_32kHz:
+			case FREQ_64kHz:
+			case FREQ_128kHz:
+			case FREQ_256kHz:
+				gen_cfg.clk_div = 125 *
+					(1 << (freq - FREQ_256kHz)) - 1;
+			break;
+			case FREQ_512kHz:
+				gen_cfg.clk_div = 62;
+			break;
+			case FREQ_1MHz:
+			case FREQ_2MHz:
+			case FREQ_4MHz:
+				gen_cfg.clk_div = 8 * (1 << freq) - 1;
+			break;
+			}
+		} else {
 			gen_cfg.base_freq = regk_sser_f29_493;
-			switch (GET_SPEED(arg))
-			{
-				case SSP150:
-					gen_cfg.clk_div = 29493000 / (150 * 8) - 1;
-					break;
-				case SSP300:
-					gen_cfg.clk_div = 29493000 / (300 * 8) - 1;
-					break;
-				case SSP600:
-					gen_cfg.clk_div = 29493000 / (600 * 8) - 1;
-					break;
-				case SSP1200:
-					gen_cfg.clk_div = 29493000 / (1200 * 8) - 1;
-					break;
-				case SSP2400:
-					gen_cfg.clk_div = 29493000 / (2400 * 8) - 1;
-					break;
-				case SSP4800:
-					gen_cfg.clk_div = 29493000 / (4800 * 8) - 1;
-					break;
-				case SSP9600:
-					gen_cfg.clk_div = 29493000 / (9600 * 8) - 1;
-					break;
-				case SSP19200:
-					gen_cfg.clk_div = 29493000 / (19200 * 8) - 1;
-					break;
-				case SSP28800:
-					gen_cfg.clk_div = 29493000 / (28800 * 8) - 1;
-					break;
-				case SSP57600:
-					gen_cfg.clk_div = 29493000 / (57600 * 8) - 1;
-					break;
-				case SSP115200:
-					gen_cfg.clk_div = 29493000 / (115200 * 8) - 1;
-					break;
-				case SSP230400:
-					gen_cfg.clk_div = 29493000 / (230400 * 8) - 1;
-					break;
-				case SSP460800:
-					gen_cfg.clk_div = 29493000 / (460800 * 8) - 1;
-					break;
-				case SSP921600:
-					gen_cfg.clk_div = 29493000 / (921600 * 8) - 1;
-					break;
-				case SSP3125000:
-					gen_cfg.base_freq = regk_sser_f100;
-					gen_cfg.clk_div = 100000000 / (3125000 * 8) - 1;
-					break;
+			switch (GET_SPEED(arg)) {
+			case SSP150:
+				gen_cfg.clk_div = 29493000 / (150 * 8) - 1;
+				break;
+			case SSP300:
+				gen_cfg.clk_div = 29493000 / (300 * 8) - 1;
+				break;
+			case SSP600:
+				gen_cfg.clk_div = 29493000 / (600 * 8) - 1;
+				break;
+			case SSP1200:
+				gen_cfg.clk_div = 29493000 / (1200 * 8) - 1;
+				break;
+			case SSP2400:
+				gen_cfg.clk_div = 29493000 / (2400 * 8) - 1;
+				break;
+			case SSP4800:
+				gen_cfg.clk_div = 29493000 / (4800 * 8) - 1;
+				break;
+			case SSP9600:
+				gen_cfg.clk_div = 29493000 / (9600 * 8) - 1;
+				break;
+			case SSP19200:
+				gen_cfg.clk_div = 29493000 / (19200 * 8) - 1;
+				break;
+			case SSP28800:
+				gen_cfg.clk_div = 29493000 / (28800 * 8) - 1;
+				break;
+			case SSP57600:
+				gen_cfg.clk_div = 29493000 / (57600 * 8) - 1;
+				break;
+			case SSP115200:
+				gen_cfg.clk_div = 29493000 / (115200 * 8) - 1;
+				break;
+			case SSP230400:
+				gen_cfg.clk_div = 29493000 / (230400 * 8) - 1;
+				break;
+			case SSP460800:
+				gen_cfg.clk_div = 29493000 / (460800 * 8) - 1;
+				break;
+			case SSP921600:
+				gen_cfg.clk_div = 29493000 / (921600 * 8) - 1;
+				break;
+			case SSP3125000:
+				gen_cfg.base_freq = regk_sser_f100;
+				gen_cfg.clk_div = 100000000 / (3125000 * 8) - 1;
+				break;
 
 			}
 		}
@@ -625,46 +763,60 @@ static int sync_serial_ioctl(struct inode *inode, struct file *file,
 			case MASTER_OUTPUT:
 				port->output = 1;
 				port->input = 0;
+				frm_cfg.out_on = regk_sser_tr;
+				frm_cfg.frame_pin_dir = regk_sser_out;
 				gen_cfg.clk_dir = regk_sser_out;
 				break;
 			case SLAVE_OUTPUT:
 				port->output = 1;
 				port->input = 0;
+				frm_cfg.frame_pin_dir = regk_sser_in;
 				gen_cfg.clk_dir = regk_sser_in;
 				break;
 			case MASTER_INPUT:
 				port->output = 0;
 				port->input = 1;
+				frm_cfg.frame_pin_dir = regk_sser_out;
+				frm_cfg.out_on = regk_sser_intern_tb;
 				gen_cfg.clk_dir = regk_sser_out;
 				break;
 			case SLAVE_INPUT:
 				port->output = 0;
 				port->input = 1;
+				frm_cfg.frame_pin_dir = regk_sser_in;
 				gen_cfg.clk_dir = regk_sser_in;
 				break;
 			case MASTER_BIDIR:
 				port->output = 1;
 				port->input = 1;
+				frm_cfg.frame_pin_dir = regk_sser_out;
+				frm_cfg.out_on = regk_sser_intern_tb;
 				gen_cfg.clk_dir = regk_sser_out;
 				break;
 			case SLAVE_BIDIR:
 				port->output = 1;
 				port->input = 1;
+				frm_cfg.frame_pin_dir = regk_sser_in;
 				gen_cfg.clk_dir = regk_sser_in;
 				break;
 			default:
 				spin_unlock_irq(&port->lock);
 				return -EINVAL;
-
 		}
 		if (!port->use_dma || (arg == MASTER_OUTPUT || arg == SLAVE_OUTPUT))
 			intr_mask.rdav = regk_sser_yes;
 		break;
 	case SSP_FRAME_SYNC:
-		if (arg & NORMAL_SYNC)
+		if (arg & NORMAL_SYNC) {
+			frm_cfg.rec_delay = 1;
 			frm_cfg.tr_delay = 1;
+		}
 		else if (arg & EARLY_SYNC)
-			frm_cfg.tr_delay = 0;
+			frm_cfg.rec_delay = frm_cfg.tr_delay = 0;
+		else if (arg & SECOND_WORD_SYNC) {
+			frm_cfg.rec_delay = 7;
+			frm_cfg.tr_delay = 1;
+		}
 
 		tr_cfg.bulk_wspace = frm_cfg.tr_delay;
 		frm_cfg.early_wend = regk_sser_yes;
@@ -680,9 +832,11 @@ static int sync_serial_ioctl(struct inode *inode, struct file *file,
 		else if (arg & SYNC_OFF)
 			frm_cfg.frame_pin_use = regk_sser_gio0;
 
-		if (arg & WORD_SIZE_8)
+		dma_w_size = regk_dma_set_w_size2;
+		if (arg & WORD_SIZE_8) {
 			rec_cfg.sample_size = tr_cfg.sample_size = 7;
-		else if (arg & WORD_SIZE_12)
+			dma_w_size = regk_dma_set_w_size1;
+		} else if (arg & WORD_SIZE_12)
 			rec_cfg.sample_size = tr_cfg.sample_size = 11;
 		else if (arg & WORD_SIZE_16)
 			rec_cfg.sample_size = tr_cfg.sample_size = 15;
@@ -696,10 +850,13 @@ static int sync_serial_ioctl(struct inode *inode, struct file *file,
 		else if (arg & BIT_ORDER_LSB)
 			rec_cfg.sh_dir = tr_cfg.sh_dir = regk_sser_lsbfirst;
 
-		if (arg & FLOW_CONTROL_ENABLE)
+		if (arg & FLOW_CONTROL_ENABLE) {
+			frm_cfg.status_pin_use = regk_sser_frm;
 			rec_cfg.fifo_thr = regk_sser_thr16;
-		else if (arg & FLOW_CONTROL_DISABLE)
+		} else if (arg & FLOW_CONTROL_DISABLE) {
+			frm_cfg.status_pin_use = regk_sser_gio0;
 			rec_cfg.fifo_thr = regk_sser_inf;
+		}
 
 		if (arg & CLOCK_NOT_GATED)
 			gen_cfg.gate_clk = regk_sser_no;
@@ -726,9 +883,9 @@ static int sync_serial_ioctl(struct inode *inode, struct file *file,
 		break;
 	case SSP_OPOLARITY:
 		if (arg & CLOCK_NORMAL)
-			gen_cfg.out_clk_pol = regk_sser_neg;
-		else if (arg & CLOCK_INVERT)
 			gen_cfg.out_clk_pol = regk_sser_pos;
+		else if (arg & CLOCK_INVERT)
+			gen_cfg.out_clk_pol = regk_sser_neg;
 
 		if (arg & FRAME_NORMAL)
 			frm_cfg.level = regk_sser_pos_hi;
@@ -770,10 +927,9 @@ static int sync_serial_ioctl(struct inode *inode, struct file *file,
 	}
 
 
-	if (port->started)
-	{
-		tr_cfg.tr_en = port->output;
+	if (port->started) {
 		rec_cfg.rec_en = port->input;
+		gen_cfg.en = (port->output | port->input);
 	}
 
 	REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg);
@@ -782,138 +938,145 @@ static int sync_serial_ioctl(struct inode *inode, struct file *file,
 	REG_WR(sser, port->regi_sser, rw_intr_mask, intr_mask);
 	REG_WR(sser, port->regi_sser, rw_cfg, gen_cfg);
 
+
+	if (cmd == SSP_FRAME_SYNC && (arg & (WORD_SIZE_8 | WORD_SIZE_12 |
+			WORD_SIZE_16 | WORD_SIZE_24 | WORD_SIZE_32))) {
+		int en = gen_cfg.en;
+		gen_cfg.en = 0;
+		REG_WR(sser, port->regi_sser, rw_cfg, gen_cfg);
+		/* ##### Should DMA be stoped before we change dma size? */
+		DMA_WR_CMD(port->regi_dmain, dma_w_size);
+		DMA_WR_CMD(port->regi_dmaout, dma_w_size);
+		gen_cfg.en = en;
+		REG_WR(sser, port->regi_sser, rw_cfg, gen_cfg);
+	}
+
 	spin_unlock_irq(&port->lock);
 	return return_val;
 }
 
-static ssize_t sync_serial_write(struct file * file, const char * buf,
-                                 size_t count, loff_t *ppos)
+/* NOTE: sync_serial_write does not support concurrency */
+static ssize_t sync_serial_write(struct file *file, const char *buf,
+				 size_t count, loff_t *ppos)
 {
 	int dev = iminor(file->f_path.dentry->d_inode);
 	DECLARE_WAITQUEUE(wait, current);
-	sync_port *port;
-	unsigned long c, c1;
-	unsigned long free_outp;
-	unsigned long outp;
-	unsigned long out_buffer;
+	struct sync_port *port;
+	int trunc_count;
 	unsigned long flags;
+	int bytes_free;
+	int out_buf_count;
 
-	if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled)
-	{
+	unsigned char *rd_ptr;       /* First allocated byte in the buffer */
+	unsigned char *wr_ptr;       /* First free byte in the buffer */
+	unsigned char *buf_stop_ptr; /* Last byte + 1 */
+
+	if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) {
 		DEBUG(printk("Invalid minor %d\n", dev));
 		return -ENODEV;
 	}
 	port = &ports[dev];
 
-	DEBUGWRITE(printk("W d%d c %lu (%d/%d)\n", port->port_nbr, count, port->out_count, OUT_BUFFER_SIZE));
-	/* Space to end of buffer */
-	/*
-	 * out_buffer <c1>012345<-   c    ->OUT_BUFFER_SIZE
-	 *            outp^    +out_count
-	                        ^free_outp
-	 * out_buffer 45<-     c      ->0123OUT_BUFFER_SIZE
-	 *             +out_count   outp^
-	 *              free_outp
-	 *
+	/* |<-         OUT_BUFFER_SIZE                          ->|
+	 *           |<- out_buf_count ->|
+	 *                               |<- trunc_count ->| ...->|
+	 *  ______________________________________________________
+	 * |  free   |   data            | free                   |
+	 * |_________|___________________|________________________|
+	 *           ^ rd_ptr            ^ wr_ptr
 	 */
+	DEBUGWRITE(printk(KERN_DEBUG "W d%d c %lu a: %p c: %p\n",
+			  port->port_nbr, count, port->active_tr_descr,
+			  port->catch_tr_descr));
 
 	/* Read variables that may be updated by interrupts */
 	spin_lock_irqsave(&port->lock, flags);
-	count = count > OUT_BUFFER_SIZE - port->out_count ? OUT_BUFFER_SIZE  - port->out_count : count;
-	outp = (unsigned long)port->outp;
-	free_outp = outp + port->out_count;
+	rd_ptr = port->out_rd_ptr;
+	out_buf_count = port->out_buf_count;
 	spin_unlock_irqrestore(&port->lock, flags);
-	out_buffer = (unsigned long)port->out_buffer;
 
-	/* Find out where and how much to write */
-	if (free_outp >= out_buffer + OUT_BUFFER_SIZE)
-		free_outp -= OUT_BUFFER_SIZE;
-	if (free_outp >= outp)
-		c = out_buffer + OUT_BUFFER_SIZE - free_outp;
-	else
-		c = outp - free_outp;
-	if (c > count)
-		c = count;
+	/* Check if resources are available */
+	if (port->tr_running &&
+	    ((port->use_dma && port->active_tr_descr == port->catch_tr_descr) ||
+	     out_buf_count >= OUT_BUFFER_SIZE)) {
+		DEBUGWRITE(printk(KERN_DEBUG "sser%d full\n", dev));
+		return -EAGAIN;
+	}
+
+	buf_stop_ptr = port->out_buffer + OUT_BUFFER_SIZE;
+
+	/* Determine pointer to the first free byte, before copying. */
+	wr_ptr = rd_ptr + out_buf_count;
+	if (wr_ptr >= buf_stop_ptr)
+		wr_ptr -= OUT_BUFFER_SIZE;
 
-//	DEBUGWRITE(printk("w op %08lX fop %08lX c %lu\n", outp, free_outp, c));
-	if (copy_from_user((void*)free_outp, buf, c))
+	/* If we wrap the ring buffer, let the user space program handle it by
+	 * truncating the data. This could be more elegant, small buffer
+	 * fragments may occur.
+	 */
+	bytes_free = OUT_BUFFER_SIZE - out_buf_count;
+	if (wr_ptr + bytes_free > buf_stop_ptr)
+		bytes_free = buf_stop_ptr - wr_ptr;
+	trunc_count = (count < bytes_free) ? count : bytes_free;
+
+	if (copy_from_user(wr_ptr, buf, trunc_count))
 		return -EFAULT;
 
-	if (c != count) {
-		buf += c;
-		c1 = count - c;
-		DEBUGWRITE(printk("w2 fi %lu c %lu c1 %lu\n", free_outp-out_buffer, c, c1));
-		if (copy_from_user((void*)out_buffer, buf, c1))
-			return -EFAULT;
-	}
-	spin_lock_irqsave(&port->lock, flags);
-	port->out_count += count;
-	spin_unlock_irqrestore(&port->lock, flags);
+	DEBUGOUTBUF(printk(KERN_DEBUG "%-4d + %-4d = %-4d     %p %p %p\n",
+			   out_buf_count, trunc_count,
+			   port->out_buf_count, port->out_buffer,
+			   wr_ptr, buf_stop_ptr));
 
 	/* Make sure transmitter/receiver is running */
-	if (!port->started)
-	{
+	if (!port->started) {
 		reg_sser_rw_cfg cfg = REG_RD(sser, port->regi_sser, rw_cfg);
-		reg_sser_rw_tr_cfg tr_cfg = REG_RD(sser, port->regi_sser, rw_tr_cfg);
 		reg_sser_rw_rec_cfg rec_cfg = REG_RD(sser, port->regi_sser, rw_rec_cfg);
 		cfg.en = regk_sser_yes;
-		tr_cfg.tr_en = port->output;
 		rec_cfg.rec_en = port->input;
 		REG_WR(sser, port->regi_sser, rw_cfg, cfg);
-		REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg);
 		REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg);
 		port->started = 1;
 	}
 
-	if (file->f_flags & O_NONBLOCK)	{
-		spin_lock_irqsave(&port->lock, flags);
-		if (!port->tr_running) {
-			if (!port->use_dma) {
-				reg_sser_rw_intr_mask intr_mask;
-				intr_mask = REG_RD(sser, port->regi_sser, rw_intr_mask);
-				/* Start sender by writing data */
-				send_word(port);
-				/* and enable transmitter ready IRQ */
-				intr_mask.trdy = 1;
-				REG_WR(sser, port->regi_sser, rw_intr_mask, intr_mask);
-			} else {
-				start_dma(port, (unsigned char* volatile )port->outp, c);
-			}
-		}
-		spin_unlock_irqrestore(&port->lock, flags);
-		DEBUGWRITE(printk("w d%d c %lu NB\n",
-				  port->port_nbr, count));
-		return count;
+	/* Setup wait if blocking */
+	if (!(file->f_flags & O_NONBLOCK)) {
+		add_wait_queue(&port->out_wait_q, &wait);
+		set_current_state(TASK_INTERRUPTIBLE);
 	}
 
-	/* Sleep until all sent */
-
-	add_wait_queue(&port->out_wait_q, &wait);
-	set_current_state(TASK_INTERRUPTIBLE);
 	spin_lock_irqsave(&port->lock, flags);
-	if (!port->tr_running) {
-		if (!port->use_dma) {
-			reg_sser_rw_intr_mask intr_mask;
-			intr_mask = REG_RD(sser, port->regi_sser, rw_intr_mask);
-			/* Start sender by writing data */
-			send_word(port);
-			/* and enable transmitter ready IRQ */
-			intr_mask.trdy = 1;
-			REG_WR(sser, port->regi_sser, rw_intr_mask, intr_mask);
-		} else {
-			start_dma(port, port->outp, c);
-		}
+	port->out_buf_count += trunc_count;
+	if (port->use_dma) {
+		start_dma_out(port, wr_ptr, trunc_count);
+	} else if (!port->tr_running) {
+		reg_sser_rw_intr_mask intr_mask;
+		intr_mask = REG_RD(sser, port->regi_sser, rw_intr_mask);
+		/* Start sender by writing data */
+		send_word(port);
+		/* and enable transmitter ready IRQ */
+		intr_mask.trdy = 1;
+		REG_WR(sser, port->regi_sser, rw_intr_mask, intr_mask);
 	}
 	spin_unlock_irqrestore(&port->lock, flags);
+
+	/* Exit if non blocking */
+	if (file->f_flags & O_NONBLOCK) {
+		DEBUGWRITE(printk(KERN_DEBUG "w d%d c %lu  %08x\n",
+				  port->port_nbr, trunc_count,
+				  REG_RD_INT(dma, port->regi_dmaout, r_intr)));
+		return trunc_count;
+	}
+
 	schedule();
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&port->out_wait_q, &wait);
+
 	if (signal_pending(current))
-	{
 		return -EINTR;
-	}
-	DEBUGWRITE(printk("w d%d c %lu\n", port->port_nbr, count));
-	return count;
+
+	DEBUGWRITE(printk(KERN_DEBUG "w d%d c %lu\n",
+			  port->port_nbr, trunc_count));
+	return trunc_count;
 }
 
 static ssize_t sync_serial_read(struct file * file, char * buf,
@@ -926,7 +1089,7 @@ static ssize_t sync_serial_read(struct file * file, char * buf,
 	unsigned char* end;
 	unsigned long flags;
 
-	if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled)
+	if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled)
 	{
 		DEBUG(printk("Invalid minor %d\n", dev));
 		return -ENODEV;
@@ -949,7 +1112,6 @@ static ssize_t sync_serial_read(struct file * file, char * buf,
 		port->started = 1;
 	}
 
-
 	/* Calculate number of available bytes */
 	/* Save pointers to avoid that they are modified by interrupt */
 	spin_lock_irqsave(&port->lock, flags);
@@ -958,16 +1120,14 @@ static ssize_t sync_serial_read(struct file * file, char * buf,
 	spin_unlock_irqrestore(&port->lock, flags);
 	while ((start == end) && !port->full) /* No data */
 	{
+		DEBUGREAD(printk(KERN_DEBUG "&"));
 		if (file->f_flags & O_NONBLOCK)
-		{
 			return -EAGAIN;
-		}
 
 		interruptible_sleep_on(&port->in_wait_q);
 		if (signal_pending(current))
-		{
 			return -EINTR;
-		}
+
 		spin_lock_irqsave(&port->lock, flags);
 		start = (unsigned char*)port->readp; /* cast away volatile */
 		end = (unsigned char*)port->writep;  /* cast away volatile */
@@ -1004,83 +1164,105 @@ static void send_word(sync_port* port)
 	switch(tr_cfg.sample_size)
 	{
 	 case 8:
-		 port->out_count--;
-		 tr_data.data = *port->outp++;
+		 port->out_buf_count--;
+		 tr_data.data = *port->out_rd_ptr++;
 		 REG_WR(sser, port->regi_sser, rw_tr_data, tr_data);
-		 if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE)
-			 port->outp = port->out_buffer;
+		 if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE)
+			 port->out_rd_ptr = port->out_buffer;
 		 break;
 	 case 12:
 	 {
-		int data = (*port->outp++) << 8;
-		data |= *port->outp++;
-		port->out_count-=2;
+		int data = (*port->out_rd_ptr++) << 8;
+		data |= *port->out_rd_ptr++;
+		port->out_buf_count -= 2;
 		tr_data.data = data;
 		REG_WR(sser, port->regi_sser, rw_tr_data, tr_data);
-		if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE)
-			port->outp = port->out_buffer;
+		if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE)
+			port->out_rd_ptr = port->out_buffer;
 	}
 	break;
 	case 16:
-		port->out_count-=2;
-		tr_data.data = *(unsigned short *)port->outp;
+		port->out_buf_count -= 2;
+		tr_data.data = *(unsigned short *)port->out_rd_ptr;
 		REG_WR(sser, port->regi_sser, rw_tr_data, tr_data);
-		port->outp+=2;
-		if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE)
-			port->outp = port->out_buffer;
+		port->out_rd_ptr += 2;
+		if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE)
+			port->out_rd_ptr = port->out_buffer;
 		break;
 	case 24:
-		port->out_count-=3;
-		tr_data.data = *(unsigned short *)port->outp;
+		port->out_buf_count -= 3;
+		tr_data.data = *(unsigned short *)port->out_rd_ptr;
 		REG_WR(sser, port->regi_sser, rw_tr_data, tr_data);
-		port->outp+=2;
-		tr_data.data = *port->outp++;
+		port->out_rd_ptr += 2;
+		tr_data.data = *port->out_rd_ptr++;
 		REG_WR(sser, port->regi_sser, rw_tr_data, tr_data);
-		if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE)
-			port->outp = port->out_buffer;
+		if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE)
+			port->out_rd_ptr = port->out_buffer;
 		break;
 	case 32:
-		port->out_count-=4;
-		tr_data.data = *(unsigned short *)port->outp;
+		port->out_buf_count -= 4;
+		tr_data.data = *(unsigned short *)port->out_rd_ptr;
 		REG_WR(sser, port->regi_sser, rw_tr_data, tr_data);
-		port->outp+=2;
-		tr_data.data = *(unsigned short *)port->outp;
+		port->out_rd_ptr += 2;
+		tr_data.data = *(unsigned short *)port->out_rd_ptr;
 		REG_WR(sser, port->regi_sser, rw_tr_data, tr_data);
-		port->outp+=2;
-		if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE)
-			port->outp = port->out_buffer;
+		port->out_rd_ptr += 2;
+		if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE)
+			port->out_rd_ptr = port->out_buffer;
 		break;
 	}
 }
 
-
-static void start_dma(struct sync_port* port, const char* data, int count)
+static void start_dma_out(struct sync_port *port,
+			  const char *data, int count)
 {
-	port->tr_running = 1;
-	port->out_descr.buf = (char*)virt_to_phys((char*)data);
-	port->out_descr.after = port->out_descr.buf + count;
-	port->out_descr.eol = port->out_descr.intr = 1;
+	port->active_tr_descr->buf = (char *) virt_to_phys((char *) data);
+	port->active_tr_descr->after = port->active_tr_descr->buf + count;
+	port->active_tr_descr->intr = 1;
+
+	port->active_tr_descr->eol = 1;
+	port->prev_tr_descr->eol = 0;
+
+	DEBUGTRDMA(printk(KERN_DEBUG "Inserting eolr:%p eol@:%p\n",
+		port->prev_tr_descr, port->active_tr_descr));
+	port->prev_tr_descr = port->active_tr_descr;
+	port->active_tr_descr = phys_to_virt((int) port->active_tr_descr->next);
+
+	if (!port->tr_running) {
+		reg_sser_rw_tr_cfg tr_cfg = REG_RD(sser, port->regi_sser,
+			rw_tr_cfg);
 
-	port->out_context.saved_data = (dma_descr_data*)virt_to_phys(&port->out_descr);
-	port->out_context.saved_data_buf = port->out_descr.buf;
+		port->out_context.next = 0;
+		port->out_context.saved_data =
+			(dma_descr_data *)virt_to_phys(port->prev_tr_descr);
+		port->out_context.saved_data_buf = port->prev_tr_descr->buf;
+
+		DMA_START_CONTEXT(port->regi_dmaout,
+			virt_to_phys((char *)&port->out_context));
+
+		tr_cfg.tr_en = regk_sser_yes;
+		REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg);
+		DEBUGTRDMA(printk(KERN_DEBUG "dma s\n"););
+	} else {
+		DMA_CONTINUE_DATA(port->regi_dmaout);
+		DEBUGTRDMA(printk(KERN_DEBUG "dma c\n"););
+	}
 
-	DMA_START_CONTEXT(port->regi_dmaout, virt_to_phys((char*)&port->out_context));
-	DEBUGTXINT(printk("dma %08lX c %d\n", (unsigned long)data, count));
+	port->tr_running = 1;
 }
 
-static void start_dma_in(sync_port* port)
+static void start_dma_in(sync_port *port)
 {
 	int i;
-	char* buf;
+	char *buf;
 	port->writep = port->flip;
 
-	if (port->writep > port->flip + port->in_buffer_size)
-	{
+	if (port->writep > port->flip + port->in_buffer_size) {
 		panic("Offset too large in sync serial driver\n");
 		return;
 	}
 	buf = (char*)virt_to_phys(port->in_buffer);
-	for (i = 0; i < NUM_IN_DESCR; i++) {
+	for (i = 0; i < NBR_IN_DESCR; i++) {
 		port->in_descr[i].buf = buf;
 		port->in_descr[i].after = buf + port->inbufchunk;
 		port->in_descr[i].intr = 1;
@@ -1092,59 +1274,126 @@ static void start_dma_in(sync_port* port)
 	port->in_descr[i-1].next = (dma_descr_data*)virt_to_phys(&port->in_descr[0]);
 	port->in_descr[i-1].eol = regk_sser_yes;
 	port->next_rx_desc = &port->in_descr[0];
-	port->prev_rx_desc = &port->in_descr[NUM_IN_DESCR - 1];
+	port->prev_rx_desc = &port->in_descr[NBR_IN_DESCR - 1];
 	port->in_context.saved_data = (dma_descr_data*)virt_to_phys(&port->in_descr[0]);
 	port->in_context.saved_data_buf = port->in_descr[0].buf;
 	DMA_START_CONTEXT(port->regi_dmain, virt_to_phys(&port->in_context));
 }
 
 #ifdef SYNC_SER_DMA
-static irqreturn_t tr_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t tr_interrupt(int irq, void *dev_id)
 {
 	reg_dma_r_masked_intr masked;
 	reg_dma_rw_ack_intr ack_intr = {.data = regk_dma_yes};
+	reg_dma_rw_stat stat;
 	int i;
-	struct dma_descr_data *descr;
-	unsigned int sentl;
 	int found = 0;
+	int stop_sser = 0;
 
-	for (i = 0; i < NUMBER_OF_PORTS; i++)
-	{
+	for (i = 0; i < NBR_PORTS; i++) {
 		sync_port *port = &ports[i];
-		if (!port->enabled  || !port->use_dma )
+		if (!port->enabled  || !port->use_dma)
 			continue;
 
+		/* IRQ active for the port? */
 		masked = REG_RD(dma, port->regi_dmaout, r_masked_intr);
+		if (!masked.data)
+			continue;
 
-		if (masked.data) /* IRQ active for the port? */
-		{
-			found = 1;
-			/* Clear IRQ */
-			REG_WR(dma, port->regi_dmaout, rw_ack_intr, ack_intr);
-			descr = &port->out_descr;
-			sentl = descr->after - descr->buf;
-			port->out_count -= sentl;
-			port->outp += sentl;
-			if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE)
-				port->outp = port->out_buffer;
-			if (port->out_count)  {
-				int c;
-				c = port->out_buffer + OUT_BUFFER_SIZE - port->outp;
-				if (c > port->out_count)
-					c = port->out_count;
-				DEBUGTXINT(printk("tx_int DMAWRITE %i %i\n", sentl, c));
-				start_dma(port, port->outp, c);
-			} else  {
-				DEBUGTXINT(printk("tx_int DMA stop %i\n", sentl));
-				port->tr_running = 0;
+		found = 1;
+
+		/* Check if we should stop the DMA transfer */
+		stat = REG_RD(dma, port->regi_dmaout, rw_stat);
+		if (stat.list_state == regk_dma_data_at_eol)
+			stop_sser = 1;
+
+		/* Clear IRQ */
+		REG_WR(dma, port->regi_dmaout, rw_ack_intr, ack_intr);
+
+		if (!stop_sser) {
+			/* The DMA has completed a descriptor, EOL was not
+			 * encountered, so step relevant descriptor and
+			 * datapointers forward. */
+			int sent;
+			sent = port->catch_tr_descr->after -
+				port->catch_tr_descr->buf;
+			DEBUGTXINT(printk(KERN_DEBUG "%-4d - %-4d = %-4d\t"
+					  "in descr %p (ac: %p)\n",
+					  port->out_buf_count, sent,
+					  port->out_buf_count - sent,
+					  port->catch_tr_descr,
+					  port->active_tr_descr););
+			port->out_buf_count -= sent;
+			port->catch_tr_descr =
+				phys_to_virt((int) port->catch_tr_descr->next);
+			port->out_rd_ptr =
+				phys_to_virt((int) port->catch_tr_descr->buf);
+		} else {
+			int i, sent;
+			/* EOL handler.
+			 * Note that if an EOL was encountered during the irq
+			 * locked section of sync_ser_write the DMA will be
+			 * restarted and the eol flag will be cleared.
+			 * The remaining descriptors will be traversed by
+			 * the descriptor interrupts as usual.
+			 */
+			i = 0;
+			while (!port->catch_tr_descr->eol) {
+				sent = port->catch_tr_descr->after -
+					port->catch_tr_descr->buf;
+				DEBUGOUTBUF(printk(KERN_DEBUG
+					"traversing descr %p -%d (%d)\n",
+					port->catch_tr_descr,
+					sent,
+					port->out_buf_count));
+				port->out_buf_count -= sent;
+				port->catch_tr_descr = phys_to_virt(
+					(int)port->catch_tr_descr->next);
+				i++;
+				if (i >= NBR_OUT_DESCR) {
+					/* TODO: Reset and recover */
+					panic("sync_serial: missing eol");
+				}
 			}
-			wake_up_interruptible(&port->out_wait_q); /* wake up the waiting process */
+			sent = port->catch_tr_descr->after -
+				port->catch_tr_descr->buf;
+			DEBUGOUTBUF(printk(KERN_DEBUG
+				"eol at descr %p -%d (%d)\n",
+				port->catch_tr_descr,
+				sent,
+				port->out_buf_count));
+
+			port->out_buf_count -= sent;
+
+			/* Update read pointer to first free byte, we
+			 * may already be writing data there. */
+			port->out_rd_ptr =
+				phys_to_virt((int) port->catch_tr_descr->after);
+			if (port->out_rd_ptr > port->out_buffer +
+					OUT_BUFFER_SIZE)
+				port->out_rd_ptr = port->out_buffer;
+
+			reg_sser_rw_tr_cfg tr_cfg =
+				REG_RD(sser, port->regi_sser, rw_tr_cfg);
+			DEBUGTXINT(printk(KERN_DEBUG
+				"tr_int DMA stop %d, set catch @ %p\n",
+				port->out_buf_count,
+				port->active_tr_descr));
+			if (port->out_buf_count != 0)
+				printk(KERN_CRIT "sync_ser: buffer not "
+					"empty after eol.\n");
+			port->catch_tr_descr = port->active_tr_descr;
+			port->tr_running = 0;
+			tr_cfg.tr_en = regk_sser_no;
+			REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg);
 		}
+		/* wake up the waiting process */
+		wake_up_interruptible(&port->out_wait_q);
 	}
 	return IRQ_RETVAL(found);
 } /* tr_interrupt */
 
-static irqreturn_t rx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t rx_interrupt(int irq, void *dev_id)
 {
 	reg_dma_r_masked_intr masked;
 	reg_dma_rw_ack_intr ack_intr = {.data = regk_dma_yes};
@@ -1152,7 +1401,7 @@ static irqreturn_t rx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 	int i;
 	int found = 0;
 
-	for (i = 0; i < NUMBER_OF_PORTS; i++)
+	for (i = 0; i < NBR_PORTS; i++)
 	{
 		sync_port *port = &ports[i];
 
@@ -1166,7 +1415,7 @@ static irqreturn_t rx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 			found = 1;
 			while (REG_RD(dma, port->regi_dmain, rw_data) !=
 			       virt_to_phys(port->next_rx_desc)) {
-
+				DEBUGRXINT(printk(KERN_DEBUG "!"));
 				if (port->writep + port->inbufchunk > port->flip + port->in_buffer_size) {
 					int first_size = port->flip + port->in_buffer_size - port->writep;
 					memcpy((char*)port->writep, phys_to_virt((unsigned)port->next_rx_desc->buf), first_size);
@@ -1185,11 +1434,16 @@ static irqreturn_t rx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 				  port->full = 1;
                                 }
 
-				port->next_rx_desc->eol = 0;
-				port->prev_rx_desc->eol = 1;
-				port->prev_rx_desc = phys_to_virt((unsigned)port->next_rx_desc);
+				port->next_rx_desc->eol = 1;
+				port->prev_rx_desc->eol = 0;
+				/* Cache bug workaround */
+				flush_dma_descr(port->prev_rx_desc, 0);
+				port->prev_rx_desc = port->next_rx_desc;
 				port->next_rx_desc = phys_to_virt((unsigned)port->next_rx_desc->next);
-				wake_up_interruptible(&port->in_wait_q); /* wake up the waiting process */
+				/* Cache bug workaround */
+				flush_dma_descr(port->prev_rx_desc, 1);
+				/* wake up the waiting process */
+				wake_up_interruptible(&port->in_wait_q);
 				DMA_CONTINUE(port->regi_dmain);
 				REG_WR(dma, port->regi_dmain, rw_ack_intr, ack_intr);
 
@@ -1201,15 +1455,15 @@ static irqreturn_t rx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 #endif /* SYNC_SER_DMA */
 
 #ifdef SYNC_SER_MANUAL
-static irqreturn_t manual_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t manual_interrupt(int irq, void *dev_id)
 {
 	int i;
 	int found = 0;
 	reg_sser_r_masked_intr masked;
 
-	for (i = 0; i < NUMBER_OF_PORTS; i++)
+	for (i = 0; i < NBR_PORTS; i++)
 	{
-		sync_port* port = &ports[i];
+		sync_port *port = &ports[i];
 
 		if (!port->enabled || port->use_dma)
 		{
@@ -1263,7 +1517,7 @@ static irqreturn_t manual_interrupt(int irq, void *dev_id, struct pt_regs * regs
 		if (masked.trdy) /* Transmitter ready? */
 		{
 			found = 1;
-			if (port->out_count > 0) /* More data to send */
+			if (port->out_buf_count > 0) /* More data to send */
 				send_word(port);
 			else /* transmission finished */
 			{
diff --git a/arch/cris/arch-v32/kernel/Makefile b/arch/cris/arch-v32/kernel/Makefile
index 5d5b613cde8c..993d987b0078 100644
--- a/arch/cris/arch-v32/kernel/Makefile
+++ b/arch/cris/arch-v32/kernel/Makefile
@@ -1,4 +1,3 @@
-# $Id: Makefile,v 1.11 2004/12/17 10:16:13 starvik Exp $
 #
 # Makefile for the linux kernel.
 #
@@ -6,9 +5,9 @@
 extra-y	:= head.o
 
 
-obj-y   := entry.o traps.o irq.o debugport.o dma.o pinmux.o \
+obj-y   := entry.o traps.o irq.o debugport.o \
 	   process.o ptrace.o setup.o signal.o traps.o time.o \
-	   arbiter.o io.o
+	   cache.o cacheflush.o
 
 obj-$(CONFIG_ETRAXFS_SIM) += vcs_hook.o
 
diff --git a/arch/cris/arch-v32/kernel/arbiter.c b/arch/cris/arch-v32/kernel/arbiter.c
deleted file mode 100644
index 420a5312ed03..000000000000
--- a/arch/cris/arch-v32/kernel/arbiter.c
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * Memory arbiter functions. Allocates bandwidth through the
- * arbiter and sets up arbiter breakpoints.
- *
- * The algorithm first assigns slots to the clients that has specified
- * bandwidth (e.g. ethernet) and then the remaining slots are divided
- * on all the active clients.
- *
- * Copyright (c) 2004, 2005 Axis Communications AB.
- */
-
-#include <asm/arch/hwregs/reg_map.h>
-#include <asm/arch/hwregs/reg_rdwr.h>
-#include <asm/arch/hwregs/marb_defs.h>
-#include <asm/arch/arbiter.h>
-#include <asm/arch/hwregs/intr_vect.h>
-#include <linux/interrupt.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/spinlock.h>
-#include <asm/io.h>
-
-struct crisv32_watch_entry
-{
-  unsigned long instance;
-  watch_callback* cb;
-  unsigned long start;
-  unsigned long end;
-  int used;
-};
-
-#define NUMBER_OF_BP 4
-#define NBR_OF_CLIENTS 14
-#define NBR_OF_SLOTS 64
-#define SDRAM_BANDWIDTH 100000000 /* Some kind of expected value */
-#define INTMEM_BANDWIDTH 400000000
-#define NBR_OF_REGIONS 2
-
-static struct crisv32_watch_entry watches[NUMBER_OF_BP] =
-{
-  {regi_marb_bp0},
-  {regi_marb_bp1},
-  {regi_marb_bp2},
-  {regi_marb_bp3}
-};
-
-static int requested_slots[NBR_OF_REGIONS][NBR_OF_CLIENTS];
-static int active_clients[NBR_OF_REGIONS][NBR_OF_CLIENTS];
-static int max_bandwidth[NBR_OF_REGIONS] = {SDRAM_BANDWIDTH, INTMEM_BANDWIDTH};
-
-DEFINE_SPINLOCK(arbiter_lock);
-
-static irqreturn_t
-crisv32_arbiter_irq(int irq, void* dev_id, struct pt_regs* regs);
-
-static void crisv32_arbiter_config(int region)
-{
-	int slot;
-	int client;
-	int interval = 0;
-	int val[NBR_OF_SLOTS];
-
-	for (slot = 0; slot < NBR_OF_SLOTS; slot++)
-	    val[slot] = NBR_OF_CLIENTS + 1;
-
-	for (client = 0; client < NBR_OF_CLIENTS; client++)
-	{
-	    int pos;
-	    if (!requested_slots[region][client])
-	       continue;
-	    interval = NBR_OF_SLOTS / requested_slots[region][client];
-	    pos = 0;
-	    while (pos < NBR_OF_SLOTS)
-	    {
-		if (val[pos] != NBR_OF_CLIENTS + 1)
-		   pos++;
-		else
-		{
-			val[pos] = client;
-			pos += interval;
-		}
-	    }
-	}
-
-	client = 0;
-	for (slot = 0; slot < NBR_OF_SLOTS; slot++)
-	{
-		if (val[slot] == NBR_OF_CLIENTS + 1)
-		{
-			int first = client;
-			while(!active_clients[region][client]) {
-				client = (client + 1) % NBR_OF_CLIENTS;
-				if (client == first)
-				   break;
-			}
-			val[slot] = client;
-			client = (client + 1) % NBR_OF_CLIENTS;
-		}
-		if (region == EXT_REGION)
-		   REG_WR_INT_VECT(marb, regi_marb, rw_ext_slots, slot, val[slot]);
-		else if (region == INT_REGION)
-		   REG_WR_INT_VECT(marb, regi_marb, rw_int_slots, slot, val[slot]);
-	}
-}
-
-extern char _stext, _etext;
-
-static void crisv32_arbiter_init(void)
-{
-	static int initialized = 0;
-
-	if (initialized)
-		return;
-
-	initialized = 1;
-
-	/* CPU caches are active. */
-	active_clients[EXT_REGION][10] = active_clients[EXT_REGION][11] = 1;
-        crisv32_arbiter_config(EXT_REGION);
-        crisv32_arbiter_config(INT_REGION);
-
-	if (request_irq(MEMARB_INTR_VECT, crisv32_arbiter_irq, IRQF_DISABLED,
-                        "arbiter", NULL))
-		printk(KERN_ERR "Couldn't allocate arbiter IRQ\n");
-
-#ifndef CONFIG_ETRAX_KGDB
-        /* Global watch for writes to kernel text segment. */
-        crisv32_arbiter_watch(virt_to_phys(&_stext), &_etext - &_stext,
-                              arbiter_all_clients, arbiter_all_write, NULL);
-#endif
-}
-
-
-
-int crisv32_arbiter_allocate_bandwidth(int client, int region,
-				       unsigned long bandwidth)
-{
-	int i;
-	int total_assigned = 0;
-	int total_clients = 0;
-	int req;
-
-	crisv32_arbiter_init();
-
-	for (i = 0; i < NBR_OF_CLIENTS; i++)
-	{
-		total_assigned += requested_slots[region][i];
-		total_clients += active_clients[region][i];
-	}
-	req = NBR_OF_SLOTS / (max_bandwidth[region] / bandwidth);
-
-	if (total_assigned + total_clients + req + 1 > NBR_OF_SLOTS)
-	   return -ENOMEM;
-
-	active_clients[region][client] = 1;
-	requested_slots[region][client] = req;
-	crisv32_arbiter_config(region);
-
-	return 0;
-}
-
-int crisv32_arbiter_watch(unsigned long start, unsigned long size,
-                          unsigned long clients, unsigned long accesses,
-                          watch_callback* cb)
-{
-	int i;
-
-	crisv32_arbiter_init();
-
-	if (start > 0x80000000) {
-		printk("Arbiter: %lX doesn't look like a physical address", start);
-		return -EFAULT;
-	}
-
-	spin_lock(&arbiter_lock);
-
-	for (i = 0; i < NUMBER_OF_BP; i++) {
-		if (!watches[i].used) {
-			reg_marb_rw_intr_mask intr_mask = REG_RD(marb, regi_marb, rw_intr_mask);
-
-			watches[i].used = 1;
-			watches[i].start = start;
-			watches[i].end = start + size;
-			watches[i].cb = cb;
-
-			REG_WR_INT(marb_bp, watches[i].instance, rw_first_addr, watches[i].start);
-			REG_WR_INT(marb_bp, watches[i].instance, rw_last_addr, watches[i].end);
-			REG_WR_INT(marb_bp, watches[i].instance, rw_op, accesses);
-			REG_WR_INT(marb_bp, watches[i].instance, rw_clients, clients);
-
-			if (i == 0)
-				intr_mask.bp0 = regk_marb_yes;
-			else if (i == 1)
-				intr_mask.bp1 = regk_marb_yes;
-			else if (i == 2)
-				intr_mask.bp2 = regk_marb_yes;
-			else if (i == 3)
-				intr_mask.bp3 = regk_marb_yes;
-
-			REG_WR(marb, regi_marb, rw_intr_mask, intr_mask);
-			spin_unlock(&arbiter_lock);
-
-			return i;
-		}
-	}
-	spin_unlock(&arbiter_lock);
-	return -ENOMEM;
-}
-
-int crisv32_arbiter_unwatch(int id)
-{
-	reg_marb_rw_intr_mask intr_mask = REG_RD(marb, regi_marb, rw_intr_mask);
-
-	crisv32_arbiter_init();
-
-	spin_lock(&arbiter_lock);
-
-	if ((id < 0) || (id >= NUMBER_OF_BP) || (!watches[id].used)) {
-		spin_unlock(&arbiter_lock);
-		return -EINVAL;
-	}
-
-	memset(&watches[id], 0, sizeof(struct crisv32_watch_entry));
-
-	if (id == 0)
-		intr_mask.bp0 = regk_marb_no;
-	else if (id == 1)
-		intr_mask.bp2 = regk_marb_no;
-	else if (id == 2)
-		intr_mask.bp2 = regk_marb_no;
-	else if (id == 3)
-		intr_mask.bp3 = regk_marb_no;
-
-	REG_WR(marb, regi_marb, rw_intr_mask, intr_mask);
-
-	spin_unlock(&arbiter_lock);
-	return 0;
-}
-
-extern void show_registers(struct pt_regs *regs);
-
-static irqreturn_t
-crisv32_arbiter_irq(int irq, void* dev_id, struct pt_regs* regs)
-{
-	reg_marb_r_masked_intr masked_intr = REG_RD(marb, regi_marb, r_masked_intr);
-	reg_marb_bp_r_brk_clients r_clients;
-	reg_marb_bp_r_brk_addr r_addr;
-	reg_marb_bp_r_brk_op r_op;
-	reg_marb_bp_r_brk_first_client r_first;
-	reg_marb_bp_r_brk_size r_size;
-	reg_marb_bp_rw_ack ack = {0};
-	reg_marb_rw_ack_intr ack_intr = {.bp0=1,.bp1=1,.bp2=1,.bp3=1};
-	struct crisv32_watch_entry* watch;
-
-	if (masked_intr.bp0) {
-		watch = &watches[0];
-		ack_intr.bp0 = regk_marb_yes;
-	} else if (masked_intr.bp1) {
-		watch = &watches[1];
-		ack_intr.bp1 = regk_marb_yes;
-	} else if (masked_intr.bp2) {
-		watch = &watches[2];
-		ack_intr.bp2 = regk_marb_yes;
-	} else if (masked_intr.bp3) {
-		watch = &watches[3];
-		ack_intr.bp3 = regk_marb_yes;
-	} else {
-		return IRQ_NONE;
-	}
-
-	/* Retrieve all useful information and print it. */
-	r_clients = REG_RD(marb_bp, watch->instance, r_brk_clients);
-	r_addr = REG_RD(marb_bp, watch->instance, r_brk_addr);
-	r_op = REG_RD(marb_bp, watch->instance, r_brk_op);
-	r_first = REG_RD(marb_bp, watch->instance, r_brk_first_client);
-	r_size = REG_RD(marb_bp, watch->instance, r_brk_size);
-
-	printk("Arbiter IRQ\n");
-	printk("Clients %X addr %X op %X first %X size %X\n",
-	       REG_TYPE_CONV(int, reg_marb_bp_r_brk_clients, r_clients),
-	       REG_TYPE_CONV(int, reg_marb_bp_r_brk_addr, r_addr),
-	       REG_TYPE_CONV(int, reg_marb_bp_r_brk_op, r_op),
-	       REG_TYPE_CONV(int, reg_marb_bp_r_brk_first_client, r_first),
-	       REG_TYPE_CONV(int, reg_marb_bp_r_brk_size, r_size));
-
-	REG_WR(marb_bp, watch->instance, rw_ack, ack);
-	REG_WR(marb, regi_marb, rw_ack_intr, ack_intr);
-
-	printk("IRQ occured at %lX\n", regs->erp);
-
-	if (watch->cb)
-		watch->cb();
-
-
-	return IRQ_HANDLED;
-}
diff --git a/arch/cris/arch-v32/kernel/crisksyms.c b/arch/cris/arch-v32/kernel/crisksyms.c
index e513da711245..77d02c15a7fc 100644
--- a/arch/cris/arch-v32/kernel/crisksyms.c
+++ b/arch/cris/arch-v32/kernel/crisksyms.c
@@ -2,7 +2,8 @@
 #include <linux/irq.h>
 #include <asm/arch/dma.h>
 #include <asm/arch/intmem.h>
-#include <asm/arch/pinmux.h>
+#include <asm/arch/mach/pinmux.h>
+#include <asm/arch/io.h>
 
 /* Functions for allocating DMA channels */
 EXPORT_SYMBOL(crisv32_request_dma);
@@ -16,7 +17,11 @@ EXPORT_SYMBOL(crisv32_intmem_virt_to_phys);
 
 /* Functions for handling pinmux */
 EXPORT_SYMBOL(crisv32_pinmux_alloc);
+EXPORT_SYMBOL(crisv32_pinmux_alloc_fixed);
 EXPORT_SYMBOL(crisv32_pinmux_dealloc);
+EXPORT_SYMBOL(crisv32_pinmux_dealloc_fixed);
+EXPORT_SYMBOL(crisv32_io_get_name);
+EXPORT_SYMBOL(crisv32_io_get);
 
 /* Functions masking/unmasking interrupts */
 EXPORT_SYMBOL(mask_irq);
diff --git a/arch/cris/arch-v32/kernel/debugport.c b/arch/cris/arch-v32/kernel/debugport.c
index d1272ad92153..15af4c293157 100644
--- a/arch/cris/arch-v32/kernel/debugport.c
+++ b/arch/cris/arch-v32/kernel/debugport.c
@@ -4,17 +4,12 @@
 
 #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/io.h>
-#include <asm/arch/hwregs/ser_defs.h>
-#include <asm/arch/hwregs/dma_defs.h>
-#include <asm/arch/pinmux.h>
-
-#include <asm/irq.h>
-#include <asm/arch/hwregs/intr_vect_defs.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/reg_map.h>
+#include <hwregs/ser_defs.h>
+#include <hwregs/dma_defs.h>
+#include <asm/arch/mach/pinmux.h>
 
 struct dbg_port
 {
@@ -59,45 +54,50 @@ struct dbg_port ports[] =
     115200,
     'N',
     8
-  }
+  },
+#if CONFIG_ETRAX_SERIAL_PORTS == 5
+  {
+    4,
+    regi_ser4,
+    0,
+    115200,
+    'N',
+    8
+  },
+#endif
 };
 static struct dbg_port *port =
 #if defined(CONFIG_ETRAX_DEBUG_PORT0)
-&ports[0];
+	&ports[0];
 #elif defined(CONFIG_ETRAX_DEBUG_PORT1)
-&ports[1];
+	&ports[1];
 #elif defined(CONFIG_ETRAX_DEBUG_PORT2)
-&ports[2];
+	&ports[2];
 #elif defined(CONFIG_ETRAX_DEBUG_PORT3)
-&ports[3];
+	&ports[3];
+#elif defined(CONFIG_ETRAX_DEBUG_PORT4)
+	&ports[4];
 #else
-NULL;
+	NULL;
 #endif
 
 #ifdef CONFIG_ETRAX_KGDB
 static struct dbg_port *kgdb_port =
 #if defined(CONFIG_ETRAX_KGDB_PORT0)
-&ports[0];
+	&ports[0];
 #elif defined(CONFIG_ETRAX_KGDB_PORT1)
-&ports[1];
+	&ports[1];
 #elif defined(CONFIG_ETRAX_KGDB_PORT2)
-&ports[2];
+	&ports[2];
 #elif defined(CONFIG_ETRAX_KGDB_PORT3)
-&ports[3];
+	&ports[3];
+#elif defined(CONFIG_ETRAX_KGDB_PORT4)
+	&ports[4];
 #else
-NULL;
+	NULL;
 #endif
 #endif
 
-#ifdef CONFIG_ETRAXFS_SIM
-extern void print_str( const char *str );
-static char buffer[1024];
-static char msg[] = "Debug: ";
-static int buffer_pos = sizeof(msg) - 1;
-#endif
-
-extern struct tty_driver *serial_driver;
-
 static void
 start_port(struct dbg_port* p)
 {
@@ -114,6 +114,10 @@ start_port(struct dbg_port* p)
 		crisv32_pinmux_alloc_fixed(pinmux_ser2);
 	else if (p->nbr == 3)
 		crisv32_pinmux_alloc_fixed(pinmux_ser3);
+#if CONFIG_ETRAX_SERIAL_PORTS == 5
+	else if (p->nbr == 4)
+		crisv32_pinmux_alloc_fixed(pinmux_ser4);
+#endif
 
 	/* Set up serial port registers */
 	reg_ser_rw_tr_ctrl tr_ctrl = {0};
@@ -156,124 +160,21 @@ start_port(struct dbg_port* p)
 	REG_WR (ser, p->instance, rw_rec_ctrl, rec_ctrl);
 }
 
-/* No debug */
-#ifdef CONFIG_ETRAX_DEBUG_PORT_NULL
-
-static void
-console_write(struct console *co, const char *buf, unsigned int len)
-{
-	return;
-}
-
-/* Target debug */
-#elif !defined(CONFIG_ETRAXFS_SIM)
-
-static void
-console_write_direct(struct console *co, const char *buf, unsigned int len)
-{
-	int i;
-	reg_ser_r_stat_din stat;
-	reg_ser_rw_tr_dma_en tr_dma_en, old;
-
-	/* Switch to manual mode */
-	tr_dma_en = old = REG_RD (ser, port->instance, rw_tr_dma_en);
-	if (tr_dma_en.en == regk_ser_yes) {
-		tr_dma_en.en = regk_ser_no;
-		REG_WR(ser, port->instance, rw_tr_dma_en, tr_dma_en);
-	}
-
-	/* Send data */
-	for (i = 0; i < len; i++) {
-		/* LF -> CRLF */
-		if (buf[i] == '\n') {
-			do {
-				stat = REG_RD (ser, port->instance, r_stat_din);
-			} while (!stat.tr_rdy);
-			REG_WR_INT (ser, port->instance, rw_dout, '\r');
-		}
-		/* Wait until transmitter is ready and send.*/
-		do {
-			stat = REG_RD (ser, port->instance, r_stat_din);
-		} while (!stat.tr_rdy);
-		REG_WR_INT (ser, port->instance, rw_dout, buf[i]);
-	}
-
-	/* Restore mode */
-	if (tr_dma_en.en != old.en)
-		REG_WR(ser, port->instance, rw_tr_dma_en, old);
-}
-
-static void
-console_write(struct console *co, const char *buf, unsigned int len)
-{
-	if (!port)
-		return;
-        console_write_direct(co, buf, len);
-}
-
-
-
-#else
-
-/* VCS debug */
-
-static void
-console_write(struct console *co, const char *buf, unsigned int len)
-{
-	char* pos;
-	pos = memchr(buf, '\n', len);
-	if (pos) {
-		int l = ++pos - buf;
-		memcpy(buffer + buffer_pos, buf, l);
-		memcpy(buffer, msg, sizeof(msg) - 1);
-		buffer[buffer_pos + l] = '\0';
-		print_str(buffer);
-		buffer_pos = sizeof(msg) - 1;
-		if (pos - buf != len) {
-			memcpy(buffer + buffer_pos, pos, len - l);
-			buffer_pos += len - l;
-		}
-	} else {
-		memcpy(buffer + buffer_pos, buf, len);
-		buffer_pos += len;
-	}
-}
-
-#endif
-
-int raw_printk(const char *fmt, ...)
-{
-	static char buf[1024];
-	int printed_len;
-	va_list args;
-	va_start(args, fmt);
-	printed_len = vsnprintf(buf, sizeof(buf), fmt, args);
-	va_end(args);
-	console_write(NULL, buf, strlen(buf));
-	return printed_len;
-}
-
-void
-stupid_debug(char* buf)
-{
-  console_write(NULL, buf, strlen(buf));
-}
-
 #ifdef CONFIG_ETRAX_KGDB
 /* Use polling to get a single character from the kernel debug port */
 int
 getDebugChar(void)
 {
-	reg_ser_rs_status_data stat;
+	reg_ser_rs_stat_din stat;
 	reg_ser_rw_ack_intr ack_intr = { 0 };
 
 	do {
-		stat = REG_RD(ser, kgdb_instance, rs_status_data);
-	} while (!stat.data_avail);
+		stat = REG_RD(ser, kgdb_port->instance, rs_stat_din);
+	} while (!stat.dav);
 
 	/* Ack the data_avail interrupt. */
-	ack_intr.data_avail = 1;
-	REG_WR(ser, kgdb_instance, rw_ack_intr, ack_intr);
+	ack_intr.dav = 1;
+	REG_WR(ser, kgdb_port->instance, rw_ack_intr, ack_intr);
 
 	return stat.data;
 }
@@ -282,173 +183,18 @@ getDebugChar(void)
 void
 putDebugChar(int val)
 {
-	reg_ser_r_status_data stat;
+	reg_ser_r_stat_din stat;
 	do {
-		stat = REG_RD (ser, kgdb_instance, r_status_data);
-	} while (!stat.tr_ready);
-	REG_WR (ser, kgdb_instance, rw_data_out, REG_TYPE_CONV(reg_ser_rw_data_out, int, val));
+		stat = REG_RD(ser, kgdb_port->instance, r_stat_din);
+	} while (!stat.tr_rdy);
+	REG_WR_INT(ser, kgdb_port->instance, rw_dout, val);
 }
 #endif /* CONFIG_ETRAX_KGDB */
 
-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(port);
-	}
-	return 0;
-}
-
-/* This is a dummy serial device that throws away anything written to it.
- * This is used when no debug output is wanted.
- */
-static struct tty_driver dummy_driver;
-
-static int dummy_open(struct tty_struct *tty, struct file * filp)
-{
-	return 0;
-}
-
-static void dummy_close(struct tty_struct *tty, struct file * filp)
-{
-}
-
-static int dummy_write(struct tty_struct * tty,
-                       const unsigned char *buf, int count)
-{
-	return count;
-}
-
-static int
-dummy_write_room(struct tty_struct *tty)
-{
-	return 8192;
-}
-
-void __init
-init_dummy_console(void)
-{
-	memset(&dummy_driver, 0, sizeof(struct tty_driver));
-	dummy_driver.driver_name = "serial";
-	dummy_driver.name = "ttyS";
-	dummy_driver.major = TTY_MAJOR;
-	dummy_driver.minor_start = 68;
-	dummy_driver.num = 1;       /* etrax100 has 4 serial ports */
-	dummy_driver.type = TTY_DRIVER_TYPE_SERIAL;
-	dummy_driver.subtype = SERIAL_TYPE_NORMAL;
-	dummy_driver.init_termios = tty_std_termios;
-	dummy_driver.init_termios.c_cflag =
-		B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */
-	dummy_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
-
-	dummy_driver.open = dummy_open;
-	dummy_driver.close = dummy_close;
-	dummy_driver.write = dummy_write;
-	dummy_driver.write_room = dummy_write_room;
-	if (tty_register_driver(&dummy_driver))
-		panic("Couldn't register dummy serial driver\n");
-}
-
-static struct tty_driver*
-crisv32_console_device(struct console* co, int *index)
-{
-	if (port)
-		*index = port->nbr;
-        return port ? serial_driver : &dummy_driver;
-}
-
-static struct console sercons = {
-	name : "ttyS",
-	write: console_write,
-	read : NULL,
-	device : crisv32_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 : crisv32_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 : crisv32_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 : crisv32_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 : crisv32_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) {
-		unregister_console(&sercons);
-		register_console(&sercons0);
-		register_console(&sercons1);
-		register_console(&sercons2);
-		register_console(&sercons3);
-		init_dummy_console();
-		return 0;
-	}
-	first = 0;
-        register_console(&sercons);
         start_port(port);
 
 #ifdef CONFIG_ETRAX_KGDB
@@ -456,5 +202,3 @@ init_etrax_debug(void)
 #endif /* CONFIG_ETRAX_KGDB */
 	return 0;
 }
-
-__initcall(init_etrax_debug);
diff --git a/arch/cris/arch-v32/kernel/entry.S b/arch/cris/arch-v32/kernel/entry.S
index f9d27807b914..eebbaba45430 100644
--- a/arch/cris/arch-v32/kernel/entry.S
+++ b/arch/cris/arch-v32/kernel/entry.S
@@ -10,7 +10,7 @@
  * 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.
+ *	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
@@ -281,12 +281,10 @@ _work_notifysig:
 	;; Deal with pending signals and notify-resume requests.
 
 	addoq	+TI_flags, $r0, $acr
-	move.d	[$acr], $r13		; The thread_info_flags parameter.
-	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	[$acr], $r12		; The thread_info_flags parameter.
+	move.d	$sp, $r11		; The regs param.
 	jsr	do_notify_resume
-	nop
+	move.d	$r9, $r10		; do_notify_resume syscall/irq param.
 
 	ba _Rexit
 	nop
@@ -396,7 +394,7 @@ nmi_interrupt:
 	btstq	REG_BIT(intr_vect, r_nmi, watchdog), $r0
 	bpl     1f
 	nop
-	jsr 	handle_watchdog_bite	; In time.c.
+	jsr	handle_watchdog_bite	; In time.c.
         move.d	$sp, $r10		; Pointer to registers
 1:	btstq	REG_BIT(intr_vect, r_nmi, ext), $r0
 	bpl     1f
@@ -515,6 +513,13 @@ _ugdb_handle_exception:
 	ba	do_sigtrap		; SIGTRAP the offending process.
 	move.d	[$sp+], $r0		; Restore R0 in delay slot.
 
+	.global kernel_execve
+kernel_execve:
+	move.d __NR_execve, $r9
+	break 13
+	ret
+	nop
+
 	.data
 
 	.section .rodata,"a"
@@ -778,21 +783,21 @@ sys_call_table:
 	.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_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_fadvise64_64
 	.long sys_ni_syscall	/* sys_vserver */
 	.long sys_ni_syscall	/* sys_mbind */
 	.long sys_ni_syscall	/* 275 sys_get_mempolicy */
@@ -805,6 +810,48 @@ sys_call_table:
 	.long sys_mq_getsetattr
 	.long sys_ni_syscall		/* reserved for kexec */
 	.long sys_waitid
+	.long sys_ni_syscall		/* 285 */ /* available */
+	.long sys_add_key
+	.long sys_request_key
+	.long sys_keyctl
+	.long sys_ioprio_set
+	.long sys_ioprio_get		/* 290 */
+	.long sys_inotify_init
+	.long sys_inotify_add_watch
+	.long sys_inotify_rm_watch
+	.long sys_migrate_pages
+	.long sys_openat		/* 295 */
+	.long sys_mkdirat
+	.long sys_mknodat
+	.long sys_fchownat
+	.long sys_futimesat
+	.long sys_fstatat64		/* 300 */
+	.long sys_unlinkat
+	.long sys_renameat
+	.long sys_linkat
+	.long sys_symlinkat
+	.long sys_readlinkat		/* 305 */
+	.long sys_fchmodat
+	.long sys_faccessat
+	.long sys_pselect6
+	.long sys_ppoll
+	.long sys_unshare		/* 310 */
+	.long sys_set_robust_list
+	.long sys_get_robust_list
+	.long sys_splice
+	.long sys_sync_file_range
+	.long sys_tee			/* 315 */
+	.long sys_vmsplice
+	.long sys_move_pages
+	.long sys_getcpu
+	.long sys_epoll_pwait
+	.long sys_utimensat		/* 320 */
+	.long sys_signalfd
+	.long sys_timerfd_create
+	.long sys_eventfd
+	.long sys_fallocate
+	.long sys_timerfd_settime       /* 325 */
+	.long sys_timerfd_gettime
 
         /*
          * NOTE!! This doesn't have to be exact - we just have
diff --git a/arch/cris/arch-v32/kernel/fasttimer.c b/arch/cris/arch-v32/kernel/fasttimer.c
index b40551f9f40d..2de9d5849ef0 100644
--- a/arch/cris/arch-v32/kernel/fasttimer.c
+++ b/arch/cris/arch-v32/kernel/fasttimer.c
@@ -1,110 +1,9 @@
-/* $Id: fasttimer.c,v 1.11 2005/01/04 11:15:46 starvik Exp $
+/*
  * linux/arch/cris/kernel/fasttimer.c
  *
  * Fast timers for ETRAX FS
- * This may be useful in other OS than Linux so use 2 space indentation...
- *
- * $Log: fasttimer.c,v $
- * Revision 1.11  2005/01/04 11:15:46  starvik
- * Don't share timer IRQ.
- *
- * Revision 1.10  2004/12/07 09:19:38  starvik
- * Corrected includes.
- * Use correct interrupt macros.
- *
- * Revision 1.9  2004/05/14 10:18:58  starvik
- * Export fast_timer_list
- *
- * Revision 1.8  2004/05/14 07:58:03  starvik
- * Merge of changes from 2.4
- *
- * Revision 1.7  2003/07/10 12:06:14  starvik
- * Return IRQ_NONE if irq wasn't handled
- *
- * Revision 1.6  2003/07/04 08:27:49  starvik
- * Merge of Linux 2.5.74
- *
- * Revision 1.5  2003/06/05 10:16:22  johana
- * New INTR_VECT macros.
- *
- * Revision 1.4  2003/06/03 08:49:45  johana
- * Fixed typo.
- *
- * Revision 1.3  2003/06/02 12:51:27  johana
- * Now compiles.
- * Commented some include files that probably can be removed.
- *
- * Revision 1.2  2003/06/02 12:09:41  johana
- * Ported to ETRAX FS using the trig interrupt instead of timer1.
- *
- * 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
- * want to use the true time - we want 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, 2003 Axis Communications AB, Lund, Sweden
+ * Copyright (C) 2000-2006 Axis Communications AB, Lund, Sweden
  */
 
 #include <linux/errno.h>
@@ -122,9 +21,9 @@
 
 #include <linux/version.h>
 
-#include <asm/arch/hwregs/reg_map.h>
-#include <asm/arch/hwregs/reg_rdwr.h>
-#include <asm/arch/hwregs/timer_defs.h>
+#include <hwregs/reg_map.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/timer_defs.h>
 #include <asm/fasttimer.h>
 #include <linux/proc_fs.h>
 
@@ -140,30 +39,25 @@
 
 #define DEBUG_LOG_INCLUDED
 #define FAST_TIMER_LOG
-//#define FAST_TIMER_TEST
+/* #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)
+static int sanity_failed;
 #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;
+static unsigned int fast_timer_running;
+static unsigned int fast_timers_added;
+static unsigned int fast_timers_started;
+static unsigned int fast_timers_expired;
+static unsigned int fast_timers_deleted;
+static unsigned int fast_timer_is_init;
+static unsigned int fast_timer_ints;
 
 struct fast_timer *fast_timer_list = NULL;
 
@@ -171,8 +65,8 @@ struct fast_timer *fast_timer_list = NULL;
 #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;
+static unsigned int debug_log_cnt;
+static unsigned int debug_log_cnt_wrapped;
 
 #define DEBUG_LOG(string, value) \
 { \
@@ -202,103 +96,92 @@ struct fast_timer timer_expired_log[NUM_TIMER_STATS];
 int timer_div_settings[NUM_TIMER_STATS];
 int timer_delay_settings[NUM_TIMER_STATS];
 
+struct work_struct fast_work;
 
 static void
-timer_trig_handler(void);
+timer_trig_handler(struct work_struct *work);
 
 
 
 /* Not true gettimeofday, only checks the jiffies (uptime) + useconds */
-void __INLINE__ do_gettimeofday_fast(struct timeval *tv)
+inline void do_gettimeofday_fast(struct fasttime_t *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;
+	tv->tv_jiff = jiffies;
+	tv->tv_usec = GET_JIFFIES_USEC();
 }
 
-int __INLINE__ timeval_cmp(struct timeval *t0, struct timeval *t1)
+inline int fasttime_cmp(struct fasttime_t *t0, struct fasttime_t *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;
+	/* Compare jiffies. Takes care of wrapping */
+	if (time_before(t0->tv_jiff, t1->tv_jiff))
+		return -1;
+	else if (time_after(t0->tv_jiff, t1->tv_jiff))
+		return 1;
+
+	/* Compare us */
+	if (t0->tv_usec < t1->tv_usec)
+		return -1;
+	else if (t0->tv_usec > t1->tv_usec)
+		return 1;
+	return 0;
 }
 
 /* Called with ints off */
-void __INLINE__ start_timer_trig(unsigned long delay_us)
+inline void start_timer_trig(unsigned long delay_us)
 {
   reg_timer_rw_ack_intr ack_intr = { 0 };
   reg_timer_rw_intr_mask intr_mask;
   reg_timer_rw_trig trig;
   reg_timer_rw_trig_cfg trig_cfg = { 0 };
-  reg_timer_r_time r_time;
+	reg_timer_r_time r_time0;
+	reg_timer_r_time r_time1;
+	unsigned char trig_wrap;
+	unsigned char time_wrap;
 
-  r_time = REG_RD(timer, regi_timer, r_time);
+	r_time0 = REG_RD(timer, regi_timer0, r_time);
 
   D1(printk("start_timer_trig : %d us freq: %i div: %i\n",
             delay_us, freq_index, div));
   /* Clear trig irq */
-  intr_mask = REG_RD(timer, regi_timer, rw_intr_mask);
+	intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask);
   intr_mask.trig = 0;
-  REG_WR(timer, regi_timer, rw_intr_mask, intr_mask);
+	REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask);
 
-  /* Set timer values */
-  /* r_time is 100MHz (10 ns resolution) */
-  trig = r_time + delay_us*(1000/10);
+	/* Set timer values and check if trigger wraps. */
+	/* r_time is 100MHz (10 ns resolution) */
+	trig_wrap = (trig = r_time0 + delay_us*(1000/10)) < r_time0;
 
   timer_div_settings[fast_timers_started % NUM_TIMER_STATS] = trig;
   timer_delay_settings[fast_timers_started % NUM_TIMER_STATS] = delay_us;
 
   /* Ack interrupt */
   ack_intr.trig = 1;
-  REG_WR(timer, regi_timer, rw_ack_intr, ack_intr);
+	REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr);
 
   /* Start timer */
-  REG_WR(timer, regi_timer, rw_trig, trig);
+	REG_WR(timer, regi_timer0, rw_trig, trig);
   trig_cfg.tmr = regk_timer_time;
-  REG_WR(timer, regi_timer, rw_trig_cfg, trig_cfg);
+	REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg);
 
   /* Check if we have already passed the trig time */
-  r_time = REG_RD(timer, regi_timer, r_time);
-  if (r_time < trig) {
+	r_time1 = REG_RD(timer, regi_timer0, r_time);
+	time_wrap = r_time1 < r_time0;
+
+	if ((trig_wrap && !time_wrap) || (r_time1 < trig)) {
     /* No, Enable trig irq */
-    intr_mask = REG_RD(timer, regi_timer, rw_intr_mask);
+		intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask);
     intr_mask.trig = 1;
-    REG_WR(timer, regi_timer, rw_intr_mask, intr_mask);
+		REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask);
     fast_timers_started++;
     fast_timer_running = 1;
-  }
-  else
-  {
+	} else {
     /* We have passed the time, disable trig point, ack intr */
     trig_cfg.tmr = regk_timer_off;
-    REG_WR(timer, regi_timer, rw_trig_cfg, trig_cfg);
-    REG_WR(timer, regi_timer, rw_ack_intr, ack_intr);
-    /* call the int routine directly */
-    timer_trig_handler();
+		REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg);
+		REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr);
+		/* call the int routine */
+		INIT_WORK(&fast_work, timer_trig_handler);
+		schedule_work(&fast_work);
   }
 
 }
@@ -320,22 +203,20 @@ void start_one_shot_timer(struct fast_timer *t,
   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("timer name: %s data: 0x%08lX already in list!\n", name, data);
-        sanity_failed++;
-        return;
-      }
-      else
-      {
-        tmp = tmp->next;
-      }
-    }
-    tmp = fast_timer_list;
-  });
+#ifdef FAST_TIMER_SANITY_CHECKS
+	/* Check so this is not in the list already... */
+	while (tmp != NULL) {
+		if (tmp == t) {
+			printk(KERN_DEBUG
+				"timer name: %s data: 0x%08lX already "
+				"in list!\n", name, data);
+			sanity_failed++;
+			goto done;
+		} else
+			tmp = tmp->next;
+	}
+	tmp = fast_timer_list;
+#endif
 
   t->delay_us = delay_us;
   t->function = function;
@@ -343,11 +224,10 @@ void start_one_shot_timer(struct fast_timer *t,
   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_jiff = t->tv_set.tv_jiff + delay_us / 1000000 / HZ;
+	if (t->tv_expires.tv_usec > 1000000) {
     t->tv_expires.tv_usec -= 1000000;
-    t->tv_expires.tv_sec++;
+		t->tv_expires.tv_jiff += HZ;
   }
 #ifdef FAST_TIMER_LOG
   timer_added_log[fast_timers_added % NUM_TIMER_STATS] = *t;
@@ -355,15 +235,12 @@ void start_one_shot_timer(struct fast_timer *t,
   fast_timers_added++;
 
   /* Check if this should timeout before anything else */
-  if (tmp == NULL || timeval_cmp(&t->tv_expires, &tmp->tv_expires) < 0)
-  {
+  if (tmp == NULL || fasttime_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;
@@ -372,10 +249,8 @@ void start_one_shot_timer(struct fast_timer *t,
   } else {
     /* Put in correct place in list */
     while (tmp->next &&
-           timeval_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0)
-    {
+        fasttime_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0)
       tmp = tmp->next;
-    }
     /* Insert t after tmp */
     t->prev = tmp;
     t->next = tmp->next;
@@ -388,6 +263,7 @@ void start_one_shot_timer(struct fast_timer *t,
 
   D2(printk("start_one_shot_timer: %d us done\n", delay_us));
 
+done:
   local_irq_restore(flags);
 } /* start_one_shot_timer */
 
@@ -431,19 +307,18 @@ int del_fast_timer(struct fast_timer * t)
 /* Timer interrupt handler for trig interrupts */
 
 static irqreturn_t
-timer_trig_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+timer_trig_interrupt(int irq, void *dev_id)
 {
   reg_timer_r_masked_intr masked_intr;
-
   /* Check if the timer interrupt is for us (a trig int) */
-  masked_intr = REG_RD(timer, regi_timer, r_masked_intr);
+	masked_intr = REG_RD(timer, regi_timer0, r_masked_intr);
   if (!masked_intr.trig)
     return IRQ_NONE;
-  timer_trig_handler();
+	timer_trig_handler(NULL);
   return IRQ_HANDLED;
 }
 
-static void timer_trig_handler(void)
+static void timer_trig_handler(struct work_struct *work)
 {
   reg_timer_rw_ack_intr ack_intr = { 0 };
   reg_timer_rw_intr_mask intr_mask;
@@ -451,38 +326,45 @@ static void timer_trig_handler(void)
   struct fast_timer *t;
   unsigned long flags;
 
+	/* We keep interrupts disabled not only when we modify the
+	 * fast timer list, but any time we hold a reference to a
+	 * timer in the list, since del_fast_timer may be called
+	 * from (another) interrupt context.  Thus, the only time
+	 * when interrupts are enabled is when calling the timer
+	 * callback function.
+	 */
   local_irq_save(flags);
 
   /* Clear timer trig interrupt */
-  intr_mask = REG_RD(timer, regi_timer, rw_intr_mask);
+	intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask);
   intr_mask.trig = 0;
-  REG_WR(timer, regi_timer, rw_intr_mask, intr_mask);
+  REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask);
 
   /* First stop timer, then ack interrupt */
   /* Stop timer */
   trig_cfg.tmr = regk_timer_off;
-  REG_WR(timer, regi_timer, rw_trig_cfg, trig_cfg);
+	REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg);
 
   /* Ack interrupt */
   ack_intr.trig = 1;
-  REG_WR(timer, regi_timer, rw_ack_intr, ack_intr);
+	REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr);
 
   fast_timer_running = 0;
   fast_timer_ints++;
 
-  local_irq_restore(flags);
+	fast_timer_function_type *f;
+	unsigned long d;
 
   t = fast_timer_list;
-  while (t)
-  {
-    struct timeval tv;
+	while (t) {
+		struct fasttime_t tv;
 
     /* Has it really expired? */
     do_gettimeofday_fast(&tv);
-    D1(printk("t: %is %06ius\n", tv.tv_sec, tv.tv_usec));
+		D1(printk(KERN_DEBUG
+			"t: %is %06ius\n", tv.tv_jiff, tv.tv_usec));
 
-    if (timeval_cmp(&t->tv_expires, &tv) <= 0)
-    {
+		if (fasttime_cmp(&t->tv_expires, &tv) <= 0) {
       /* Yes it has expired */
 #ifdef FAST_TIMER_LOG
       timer_expired_log[fast_timers_expired % NUM_TIMER_STATS] = *t;
@@ -490,84 +372,77 @@ static void timer_trig_handler(void)
       fast_timers_expired++;
 
       /* Remove this timer before call, since it may reuse the timer */
-      local_irq_save(flags);
       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;
-      local_irq_restore(flags);
 
-      if (t->function != NULL)
-      {
-        t->function(t->data);
-      }
-      else
-      {
+			/* Save function callback data before enabling
+			 * interrupts, since the timer may be removed and we
+			 * don't know how it was allocated (e.g. ->function
+			 * and ->data may become overwritten after deletion
+			 * if the timer was stack-allocated).
+			 */
+			f = t->function;
+			d = t->data;
+
+			if (f != NULL) {
+				/* Run the callback function with interrupts
+				 * enabled. */
+				local_irq_restore(flags);
+				f(d);
+				local_irq_save(flags);
+			} else
         DEBUG_LOG("!trimertrig %i function==NULL!\n", fast_timer_ints);
-      }
-    }
-    else
-    {
+		} else {
       /* Timer is to early, let's set it again using the normal routines */
       D1(printk(".\n"));
     }
 
-    local_irq_save(flags);
-    if ((t = fast_timer_list) != NULL)
-    {
+		t = fast_timer_list;
+		if (t != NULL) {
       /* Start next timer.. */
-      long us;
-      struct timeval tv;
+			long us = 0;
+			struct fasttime_t 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)
-        {
+
+			/* time_after_eq takes care of wrapping */
+			if (time_after_eq(t->tv_expires.tv_jiff, tv.tv_jiff))
+				us = ((t->tv_expires.tv_jiff - tv.tv_jiff) *
+					1000000 / HZ + 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_timer_trig(us);
         }
-        local_irq_restore(flags);
         break;
-      }
-      else
-      {
+			} else {
         /* Timer already expired, let's handle it better late than never.
          * The normal loop handles it
          */
         D1(printk("e! %d\n", us));
       }
     }
-    local_irq_restore(flags);
   }
 
-  if (!t)
-  {
+	local_irq_restore(flags);
+
+	if (!t)
     D1(printk("ttrig stop!\n"));
-  }
 }
 
 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);
 }
 
@@ -577,28 +452,17 @@ static void wake_up_func(unsigned long data)
 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);
+	/* Uninterruptible sleep on the fast timer. (The condition is
+	 * somewhat redundant since the timer is what wakes us up.) */
+	wait_event(sleep_wait, !fast_timer_pending(&t));
+
   D1(printk("done schedule_usleep(%d)\n", us));
-#ifdef DECLARE_WAITQUEUE
-  }
-#endif
 }
 
 #ifdef CONFIG_PROC_FS
@@ -618,20 +482,22 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
   unsigned long flags;
   int i = 0;
   int num_to_show;
-  struct timeval tv;
+	struct fasttime_t 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)
-  {
+	if (!bigbuf) {
+		bigbuf = vmalloc(BIG_BUF_SIZE);
+		if (!bigbuf) {
+			used = 0;
+			if (buf)
+				buf[0] = '\0';
+			return 0;
+		}
+	}
+
+	if (!offset || !used) {
     do_gettimeofday_fast(&tv);
 
     used = 0;
@@ -648,7 +514,7 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
     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_jiff,
                     (unsigned long)tv.tv_usec);
 #ifdef FAST_TIMER_SANITY_CHECKS
     used += sprintf(bigbuf + used, "Sanity failed:         %i\n",
@@ -661,10 +527,8 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
       int end_i = debug_log_cnt;
       i = 0;
 
-      if (debug_log_cnt_wrapped)
-      {
+			if (debug_log_cnt_wrapped)
         i = debug_log_cnt;
-      }
 
       while ((i != end_i || (debug_log_cnt_wrapped && !used)) &&
              used+100 < BIG_BUF_SIZE)
@@ -697,9 +561,9 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
                       "d: %6li us data: 0x%08lX"
                       "\n",
                       t->name,
-                      (unsigned long)t->tv_set.tv_sec,
+				(unsigned long)t->tv_set.tv_jiff,
                       (unsigned long)t->tv_set.tv_usec,
-                      (unsigned long)t->tv_expires.tv_sec,
+				(unsigned long)t->tv_expires.tv_jiff,
                       (unsigned long)t->tv_expires.tv_usec,
                       t->delay_us,
                       t->data
@@ -719,9 +583,9 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
                       "d: %6li us data: 0x%08lX"
                       "\n",
                       t->name,
-                      (unsigned long)t->tv_set.tv_sec,
+				(unsigned long)t->tv_set.tv_jiff,
                       (unsigned long)t->tv_set.tv_usec,
-                      (unsigned long)t->tv_expires.tv_sec,
+				(unsigned long)t->tv_expires.tv_jiff,
                       (unsigned long)t->tv_expires.tv_usec,
                       t->delay_us,
                       t->data
@@ -739,9 +603,9 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
                       "d: %6li us data: 0x%08lX"
                       "\n",
                       t->name,
-                      (unsigned long)t->tv_set.tv_sec,
+				(unsigned long)t->tv_set.tv_jiff,
                       (unsigned long)t->tv_set.tv_usec,
-                      (unsigned long)t->tv_expires.tv_sec,
+				(unsigned long)t->tv_expires.tv_jiff,
                       (unsigned long)t->tv_expires.tv_usec,
                       t->delay_us,
                       t->data
@@ -752,26 +616,25 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
 
     used += sprintf(bigbuf + used, "Active timers:\n");
     local_irq_save(flags);
-    local_irq_save(flags);
     t = fast_timer_list;
     while (t != NULL && (used+100 < BIG_BUF_SIZE))
     {
       nextt = t->next;
       local_irq_restore(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,
+			"d: %6li us data: 0x%08lX"
+/*			" func: 0x%08lX" */
+			"\n",
+			t->name,
+			(unsigned long)t->tv_set.tv_jiff,
+			(unsigned long)t->tv_set.tv_usec,
+			(unsigned long)t->tv_expires.tv_jiff,
+			(unsigned long)t->tv_expires.tv_usec,
                       t->delay_us,
                       t->data
 /*                      , t->function */
                       );
-      local_irq_disable();
+			local_irq_save(flags);
       if (t->next != nextt)
       {
         printk("timer removed!\n");
@@ -800,7 +663,7 @@ 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 struct fasttime_t tv_exp[100];
 
 static void test_timeout(unsigned long data)
 {
@@ -838,7 +701,7 @@ static void fast_timer_test(void)
   int prev_num;
   int j;
 
-  struct timeval tv, tv0, tv1, tv2;
+	struct fasttime_t tv, tv0, tv1, tv2;
 
   printk("fast_timer_test() start\n");
   do_gettimeofday_fast(&tv);
@@ -851,21 +714,22 @@ static void fast_timer_test(void)
   {
     do_gettimeofday_fast(&tv_exp[j]);
   }
-  printk("fast_timer_test() %is %06i\n", tv.tv_sec, tv.tv_usec);
+  printk(KERN_DEBUG "fast_timer_test() %is %06i\n", tv.tv_jiff, 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]);
+    printk(KERN_DEBUG "%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);
+    printk(KERN_DEBUG "%i.%i %i.%i %i.%i %i.%i %i.%i\n",
+			tv_exp[j].tv_jiff, tv_exp[j].tv_usec,
+			tv_exp[j+1].tv_jiff, tv_exp[j+1].tv_usec,
+			tv_exp[j+2].tv_jiff, tv_exp[j+2].tv_usec,
+			tv_exp[j+3].tv_jiff, tv_exp[j+3].tv_usec,
+			tv_exp[j+4].tv_jiff, tv_exp[j+4].tv_usec);
     j += 4;
   }
   do_gettimeofday_fast(&tv0);
@@ -892,14 +756,15 @@ static void fast_timer_test(void)
   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);
+	printk(KERN_INFO "Timers started    %is %06i\n",
+		tv0.tv_jiff, tv0.tv_usec);
+	printk(KERN_INFO "Timers started at %is %06i\n",
+		tv1.tv_jiff, tv1.tv_usec);
+	printk(KERN_INFO "Timers done       %is %06i\n",
+		tv2.tv_jiff, tv2.tv_usec);
   DP(printk("buf0:\n");
      printk(buf0);
      printk("buf1:\n");
@@ -921,9 +786,9 @@ static void fast_timer_test(void)
     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_jiff,
            t->tv_set.tv_usec,
-           t->tv_expires.tv_sec,
+			t->tv_expires.tv_jiff,
            t->tv_expires.tv_usec,
            t->data,
            t->function
@@ -931,10 +796,12 @@ static void fast_timer_test(void)
 
     printk("           del: %6ius     did exp: %6is %06ius as #%i error: %6li\n",
            t->delay_us,
-           tv_exp[j].tv_sec,
+			tv_exp[j].tv_jiff,
            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);
+			(tv_exp[j].tv_jiff - t->tv_expires.tv_jiff) *
+				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");
@@ -944,7 +811,7 @@ static void fast_timer_test(void)
 #endif
 
 
-void fast_timer_init(void)
+int fast_timer_init(void)
 {
   /* For some reason, request_irq() hangs when called froom time_init() */
   if (!fast_timer_is_init)
@@ -952,18 +819,20 @@ void fast_timer_init(void)
     printk("fast_timer_init()\n");
 
 #ifdef CONFIG_PROC_FS
-   if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 )))
-     fasttimer_proc_entry->read_proc = proc_fasttimer_read;
+    fasttimer_proc_entry = create_proc_entry("fasttimer", 0, 0);
+    if (fasttimer_proc_entry)
+      fasttimer_proc_entry->read_proc = proc_fasttimer_read;
 #endif /* PROC_FS */
-    if(request_irq(TIMER_INTR_VECT, timer_trig_interrupt, IRQF_DISABLED,
-                   "fast timer int", NULL))
-    {
-      printk("err: timer1 irq\n");
-    }
+		if (request_irq(TIMER0_INTR_VECT, timer_trig_interrupt,
+				IRQF_SHARED | IRQF_DISABLED,
+				"fast timer int", &fast_timer_list))
+			printk(KERN_ERR "err: fasttimer irq\n");
     fast_timer_is_init = 1;
 #ifdef FAST_TIMER_TEST
     printk("do test\n");
     fast_timer_test();
 #endif
   }
+	return 0;
 }
+__initcall(fast_timer_init);
diff --git a/arch/cris/arch-v32/kernel/head.S b/arch/cris/arch-v32/kernel/head.S
index 20bd80a84e48..2d66a7c320e1 100644
--- a/arch/cris/arch-v32/kernel/head.S
+++ b/arch/cris/arch-v32/kernel/head.S
@@ -4,22 +4,25 @@
  * Copyright (C) 2003, Axis Communications AB
  */
 
-
 #define ASSEMBLER_MACROS_ONLY
 
 /*
  * The macros found in mmu_defs_asm.h uses the ## concatenation operator, so
  * -traditional must not be used when assembling this file.
  */
-#include <asm/arch/hwregs/reg_rdwr.h>
-#include <asm/arch/hwregs/asm/mmu_defs_asm.h>
-#include <asm/arch/hwregs/asm/reg_map_asm.h>
-#include <asm/arch/hwregs/asm/config_defs_asm.h>
-#include <asm/arch/hwregs/asm/bif_core_defs_asm.h>
+#include <hwregs/reg_rdwr.h>
+#include <asm/arch/memmap.h>
+#include <hwregs/intr_vect.h>
+#include <hwregs/asm/mmu_defs_asm.h>
+#include <hwregs/asm/reg_map_asm.h>
+#include <asm/arch/mach/startup.inc>
 
 #define CRAMFS_MAGIC 0x28cd3d45
+#define JHEAD_MAGIC 0x1FF528A6
+#define JHEAD_SIZE 8
 #define RAM_INIT_MAGIC 0x56902387
 #define COMMAND_LINE_MAGIC 0x87109563
+#define NAND_BOOT_MAGIC 0x9a9db001
 
 	;; NOTE: R8 and R9 carry information from the decompressor (if the
 	;; kernel was compressed). They must not be used in the code below
@@ -30,12 +33,11 @@
 	.global romfs_start
 	.global romfs_length
 	.global romfs_in_flash
+	.global nand_boot
 	.global swapper_pg_dir
-	.global crisv32_nand_boot
-	.global crisv32_nand_cramfs_offset
 
 	;; Dummy section to make it bootable with current VCS simulator
-#ifdef CONFIG_ETRAXFS_SIM
+#ifdef CONFIG_ETRAX_VCS_SIM
 	.section ".boot", "ax"
 	ba tstart
 	nop
@@ -51,33 +53,15 @@ tstart:
 	;;
 	di
 
-	;; Start clocks for used blocks.
-	move.d REG_ADDR(config, regi_config, rw_clk_ctrl), $r1
-	move.d [$r1], $r0
-	or.d   REG_STATE(config, rw_clk_ctrl, cpu, yes) | \
-	       REG_STATE(config, rw_clk_ctrl, bif, yes) | \
-	       REG_STATE(config, rw_clk_ctrl, fix_io, yes), $r0
-	move.d $r0, [$r1]
-
-	;; Set up waitstates etc
-	move.d   REG_ADDR(bif_core, regi_bif_core, rw_grp1_cfg), $r0
-	move.d   CONFIG_ETRAX_MEM_GRP1_CONFIG, $r1
-	move.d   $r1, [$r0]
-	move.d   REG_ADDR(bif_core, regi_bif_core, rw_grp2_cfg), $r0
-	move.d   CONFIG_ETRAX_MEM_GRP2_CONFIG, $r1
-	move.d   $r1, [$r0]
-	move.d   REG_ADDR(bif_core, regi_bif_core, rw_grp3_cfg), $r0
-	move.d   CONFIG_ETRAX_MEM_GRP3_CONFIG, $r1
-	move.d   $r1, [$r0]
-	move.d   REG_ADDR(bif_core, regi_bif_core, rw_grp4_cfg), $r0
-	move.d   CONFIG_ETRAX_MEM_GRP4_CONFIG, $r1
-	move.d   $r1, [$r0]
-
-#ifdef CONFIG_ETRAXFS_SIM
-	;; Set up minimal flash waitstates
-	move.d 0, $r10
-	move.d REG_ADDR(bif_core, regi_bif_core, rw_grp1_cfg), $r11
-	move.d $r10, [$r11]
+	START_CLOCKS
+
+	SETUP_WAIT_STATES
+
+	GIO_INIT
+
+#ifdef CONFIG_SMP
+secondary_cpu_entry: /* Entry point for secondary CPUs */
+	di
 #endif
 
 	;; Setup and enable the MMU. Use same configuration for both the data
@@ -85,7 +69,7 @@ tstart:
 	;;
 	;; Note; 3 cycles is needed for a bank-select to take effect. Further;
 	;; bank 1 is the instruction MMU, bank 2 is the data MMU.
-#ifndef CONFIG_ETRAXFS_SIM
+#ifndef CONFIG_ETRAX_VCS_SIM
 	move.d	REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8)	\
 		| REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4)	\
 		| REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb), $r0
@@ -93,7 +77,7 @@ tstart:
 	;; Map the virtual DRAM to the RW eprom area at address 0.
 	;; Also map 0xa for the hook calls,
 	move.d	REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8)	\
-		| REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 0)	\
+		| REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4)	\
 		| REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb)   \
 		| REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0xa), $r0
 #endif
@@ -104,7 +88,7 @@ tstart:
 
 	;; Enable certain page protections and setup linear mapping
 	;; for f,e,c,b,4,0.
-#ifndef CONFIG_ETRAXFS_SIM
+#ifndef CONFIG_ETRAX_VCS_SIM
 	move.d	REG_STATE(mmu, rw_mm_cfg, we, on)		\
 		| REG_STATE(mmu, rw_mm_cfg, acc, on)		\
 		| REG_STATE(mmu, rw_mm_cfg, ex, on)		\
@@ -183,17 +167,11 @@ tstart:
 	nop
 	nop
 	nop
-	move    $s10, $r0
+	move    $s12, $r0
 	cmpq    0, $r0
 	beq	master_cpu
 	nop
 slave_cpu:
-	; A slave waits for cpu_now_booting to be equal to CPU ID.
-	move.d	cpu_now_booting, $r1
-slave_wait:
-	cmp.d	[$r1], $r0
-	bne	slave_wait
-	nop
 	; Time to boot-up. Get stack location provided by master CPU.
 	move.d  smp_init_current_idle_thread, $r1
 	move.d  [$r1], $sp
@@ -203,9 +181,16 @@ slave_wait:
 	jsr	smp_callin
 	nop
 master_cpu:
+	/* Set up entry point for secondary CPUs. The boot ROM has set up
+	 * EBP at start of internal memory. The CPU will get there
+	 * later when we issue an IPI to them... */
+	move.d MEM_INTMEM_START + IPI_INTR_VECT * 4, $r0
+	move.d secondary_cpu_entry, $r1
+	move.d $r1, [$r0]
 #endif
-#ifndef CONFIG_ETRAXFS_SIM
-	;; Check if starting from DRAM or flash.
+#ifndef CONFIG_ETRAX_VCS_SIM
+	; Check if starting from DRAM (network->RAM boot or unpacked
+	; compressed kernel), or directly from flash.
 	lapcq	., $r0
 	and.d	0x7fffffff, $r0 ; Mask off the non-cache bit.
 	cmp.d	0x10000, $r0	; Arbitrary, something above this code.
@@ -232,12 +217,13 @@ _inflash:
 	beq	_dram_initialized
 	nop
 
-#include "../lib/dram_init.S"
+#include "../mach/dram_init.S"
 
 _dram_initialized:
 	;; Copy the text and data section to DRAM. This depends on that the
 	;; variables used below are correctly set up by the linker script.
 	;; The calculated value stored in R4 is used below.
+	;; Leave the cramfs file system (piggybacked after the kernel) in flash.
 	moveq	0, $r0		; Source.
 	move.d	text_start, $r1	; Destination.
 	move.d	__vmlinux_end, $r2
@@ -249,7 +235,7 @@ _dram_initialized:
 	blo	1b
 	nop
 
-	;; Keep CRAMFS in flash.
+	;; Check for cramfs.
 	moveq	0, $r0
 	move.d	romfs_length, $r1
 	move.d	$r0, [$r1]
@@ -258,6 +244,7 @@ _dram_initialized:
 	bne 1f
 	nop
 
+	;; Set length and start of cramfs, set romfs_in_flash flag
 	addoq	+4, $r4, $acr
 	move.d	[$acr], $r0
 	move.d	romfs_length, $r1
@@ -273,35 +260,32 @@ _dram_initialized:
 	nop
 
 _inram:
-	;; Check if booting from NAND flash (in that case we just remember the offset
-	;; into the flash where cramfs should be).
-	move.d	REG_ADDR(config, regi_config, r_bootsel), $r0
-	move.d	[$r0], $r0
-	and.d	REG_MASK(config, r_bootsel, boot_mode), $r0
-	cmp.d	REG_STATE(config, r_bootsel, boot_mode, nand), $r0
-	bne	move_cramfs
-	moveq	1,$r0
-	move.d	crisv32_nand_boot, $r1
-	move.d	$r0, [$r1]
-	move.d	crisv32_nand_cramfs_offset, $r1
-	move.d	$r9, [$r1]
+	;; Check if booting from NAND flash; if so, set appropriate flags
+	;; and move on.
+	cmp.d	NAND_BOOT_MAGIC, $r12
+	bne	move_cramfs	; not nand, jump
 	moveq	1, $r0
-	move.d	romfs_in_flash, $r1
+	move.d	nand_boot, $r1	; tell axisflashmap we're booting from NAND
+	move.d	$r0, [$r1]
+	moveq	0, $r0		; tell axisflashmap romfs is not in
+	move.d	romfs_in_flash, $r1 ; (directly accessed) flash
 	move.d	$r0, [$r1]
-	jump	_start_it
+	jump	_start_it	; continue with boot
 	nop
 
 move_cramfs:
-	;; Move the cramfs after BSS.
+	;; kernel is in DRAM.
+	;; Must figure out if there is a piggybacked rootfs image or not.
+	;; Set romfs_length to 0 => no rootfs image available by default.
 	moveq	0, $r0
 	move.d	romfs_length, $r1
 	move.d	$r0, [$r1]
 
-#ifndef CONFIG_ETRAXFS_SIM
+#ifndef CONFIG_ETRAX_VCS_SIM
 	;; The kernel could have been unpacked to DRAM by the loader, but
-	;; the cramfs image could still be inte the flash immediately
-	;; following the compressed kernel image. The loaded passes the address
-	;; of the bute succeeding the last compressed byte in the flash in
+	;; the cramfs image could still be in the flash immediately
+	;; following the compressed kernel image. The loader passes the address
+	;; of the byte succeeding the last compressed byte in the flash in
 	;; register R9 when starting the kernel.
 	cmp.d	0x0ffffff8, $r9
 	bhs	_no_romfs_in_flash ; R9 points outside the flash area.
@@ -310,11 +294,13 @@ move_cramfs:
 	ba _no_romfs_in_flash
 	nop
 #endif
+	;; cramfs rootfs might to be in flash. Check for it.
 	move.d	[$r9], $r0	; cramfs_super.magic
 	cmp.d	CRAMFS_MAGIC, $r0
 	bne	_no_romfs_in_flash
 	nop
 
+	;; found cramfs in flash. set address and size, and romfs_in_flash flag.
 	addoq	+4, $r9, $acr
 	move.d	[$acr], $r0
 	move.d	romfs_length, $r1
@@ -330,27 +316,43 @@ move_cramfs:
 	nop
 
 _no_romfs_in_flash:
-	;; Look for cramfs.
+	;; No romfs in flash, so look for cramfs, or jffs2 with jhead,
+	;; after kernel in RAM, as is the case with network->RAM boot.
+	;; For cramfs, partition starts with magic and length.
+	;; For jffs2, a jhead is prepended which contains with magic and length.
+	;; The jhead is not part of the jffs2 partition however.
 #ifndef CONFIG_ETRAXFS_SIM
 	move.d	__vmlinux_end, $r0
 #else
 	move.d	__end, $r0
 #endif
 	move.d	[$r0], $r1
-	cmp.d	CRAMFS_MAGIC, $r1
-	bne	2f
+	cmp.d	CRAMFS_MAGIC, $r1 ; cramfs magic?
+	beq	2f		  ; yes, jump
+	nop
+	cmp.d	JHEAD_MAGIC, $r1 ; jffs2 (jhead) magic?
+	bne	4f		; no, skip copy
 	nop
+	addq	4, $r0		; location of jffs2 size
+	move.d	[$r0+], $r2	; fetch jffs2 size -> r2
+				; r0 now points to start of jffs2
+	ba	3f
+	nop
+2:
+	addoq	+4, $r0, $acr	; location of cramfs size
+	move.d	[$acr], $r2	; fetch cramfs size -> r2
+				; r0 still points to start of cramfs
+3:
+	;; Now, move the root fs to after kernel's BSS
 
-	addoq	+4, $r0, $acr
-	move.d	[$acr], $r2
-	move.d	_end, $r1
+	move.d	_end, $r1	; start of cramfs -> r1
 	move.d	romfs_start, $r3
-	move.d	$r1, [$r3]
+	move.d	$r1, [$r3]	; store at romfs_start (for axisflashmap)
 	move.d	romfs_length, $r3
-	move.d	$r2, [$r3]
+	move.d	$r2, [$r3]	; store size at romfs_length
 
-#ifndef CONFIG_ETRAXFS_SIM
-	add.d	$r2, $r0
+#ifndef CONFIG_ETRAX_VCS_SIM
+	add.d	$r2, $r0	; copy from end and downwards
 	add.d	$r2, $r1
 
 	lsrq	1, $r2		; Size is in bytes, we copy words.
@@ -365,10 +367,17 @@ _no_romfs_in_flash:
 	nop
 #endif
 
-2:
+4:
+	;; BSS move done.
+	;; Clear romfs_in_flash flag, as we now know romfs is in DRAM
+	;; Also clear nand_boot flag; if we got here, we know we've not
+	;; booted from NAND flash.
 	moveq	0, $r0
 	move.d	romfs_in_flash, $r1
 	move.d	$r0, [$r1]
+	moveq	0, $r0
+	move.d	nand_boot, $r1
+	move.d	$r0, [$r1]
 
 	jump	_start_it	; Jump to cached code.
 	nop
@@ -384,8 +393,8 @@ _start_it:
 	move.d  cris_command_line, $r10
 	or.d	0x80000000, $r11 ; Make it virtual
 1:
-	move.b  [$r11+], $r12
-	move.b  $r12, [$r10+]
+	move.b  [$r11+], $r1
+	move.b  $r1, [$r10+]
 	subq	1, $r13
 	bne	1b
 	nop
@@ -401,7 +410,7 @@ no_command_line:
 	move.d	etrax_irv, $r1	; Set the exception base register and pointer.
 	move.d	$r0, [$r1]
 
-#ifndef CONFIG_ETRAXFS_SIM
+#ifndef CONFIG_ETRAX_VCS_SIM
 	;; Clear the BSS region from _bss_start to _end.
 	move.d	__bss_start, $r0
 	move.d	_end, $r1
@@ -411,7 +420,7 @@ no_command_line:
 	nop
 #endif
 
-#ifdef CONFIG_ETRAXFS_SIM
+#ifdef CONFIG_ETRAX_VCS_SIM
 	/* Set the watchdog timeout to something big. Will be removed when */
 	/* watchdog can be disabled with command line option */
 	move.d  0x7fffffff, $r10
@@ -423,25 +432,44 @@ no_command_line:
 	move.d __bss_start, $r0
 	movem [$r0], $r13
 
+#ifdef CONFIG_ETRAX_L2CACHE
+	jsr	l2cache_init
+	nop
+#endif
+
 	jump	start_kernel	; Jump to start_kernel() in init/main.c.
 	nop
 
 	.data
 etrax_irv:
 	.dword 0
+
+; Variables for communication with the Axis flash map driver (axisflashmap),
+; and for setting up memory in arch/cris/kernel/setup.c .
+
+; romfs_start is set to the start of the root file system, if it exists
+; in directly accessible memory (i.e. NOR Flash when booting from Flash,
+; or RAM when booting directly from a network-downloaded RAM image)
 romfs_start:
 	.dword 0
+
+; romfs_length is set to the size of the root file system image, if it exists
+; in directly accessible memory (see romfs_start). Otherwise it is set to 0.
 romfs_length:
 	.dword 0
+
+; romfs_in_flash is set to 1 if the root file system resides in directly
+; accessible flash memory (i.e. NOR flash). It is set to 0 for RAM boot
+; or NAND flash boot.
 romfs_in_flash:
 	.dword 0
-crisv32_nand_boot:
-	.dword 0
-crisv32_nand_cramfs_offset:
+
+; nand_boot is set to 1 when the kernel has been booted from NAND flash
+nand_boot:
 	.dword 0
 
 swapper_pg_dir = 0xc0002000
 
 	.section ".init.data", "aw"
 
-#include "../lib/hw_settings.S"
+#include "../mach/hw_settings.S"
diff --git a/arch/cris/arch-v32/kernel/io.c b/arch/cris/arch-v32/kernel/io.c
deleted file mode 100644
index a22a9e02e093..000000000000
--- a/arch/cris/arch-v32/kernel/io.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Helper functions for I/O pins.
- *
- * Copyright (c) 2004 Axis Communications AB.
- */
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <asm/io.h>
-#include <asm/arch/pinmux.h>
-#include <asm/arch/hwregs/gio_defs.h>
-
-struct crisv32_ioport crisv32_ioports[] =
-{
-	{
-		(unsigned long*)REG_ADDR(gio, regi_gio, rw_pa_oe),
-		(unsigned long*)REG_ADDR(gio, regi_gio, rw_pa_dout),
-		(unsigned long*)REG_ADDR(gio, regi_gio, r_pa_din),
-		8
-	},
-	{
-		(unsigned long*)REG_ADDR(gio, regi_gio, rw_pb_oe),
-		(unsigned long*)REG_ADDR(gio, regi_gio, rw_pb_dout),
-		(unsigned long*)REG_ADDR(gio, regi_gio, r_pb_din),
-		18
-	},
-	{
-		(unsigned long*)REG_ADDR(gio, regi_gio, rw_pc_oe),
-		(unsigned long*)REG_ADDR(gio, regi_gio, rw_pc_dout),
-		(unsigned long*)REG_ADDR(gio, regi_gio, r_pc_din),
-		18
-	},
-	{
-		(unsigned long*)REG_ADDR(gio, regi_gio, rw_pd_oe),
-		(unsigned long*)REG_ADDR(gio, regi_gio, rw_pd_dout),
-		(unsigned long*)REG_ADDR(gio, regi_gio, r_pd_din),
-		18
-	},
-	{
-		(unsigned long*)REG_ADDR(gio, regi_gio, rw_pe_oe),
-		(unsigned long*)REG_ADDR(gio, regi_gio, rw_pe_dout),
-		(unsigned long*)REG_ADDR(gio, regi_gio, r_pe_din),
-		18
-	}
-};
-
-#define NBR_OF_PORTS ARRAY_SIZE(crisv32_ioports)
-
-struct crisv32_iopin crisv32_led1_green;
-struct crisv32_iopin crisv32_led1_red;
-struct crisv32_iopin crisv32_led2_green;
-struct crisv32_iopin crisv32_led2_red;
-struct crisv32_iopin crisv32_led3_green;
-struct crisv32_iopin crisv32_led3_red;
-
-/* Dummy port used when green LED and red LED is on the same bit */
-static unsigned long io_dummy;
-static struct crisv32_ioport dummy_port =
-{
-	&io_dummy,
-	&io_dummy,
-	&io_dummy,
-	18
-};
-static struct crisv32_iopin dummy_led =
-{
-	&dummy_port,
-	0
-};
-
-static int __init crisv32_io_init(void)
-{
-	int ret = 0;
-	/* Initialize LEDs */
-	ret += crisv32_io_get_name(&crisv32_led1_green, CONFIG_ETRAX_LED1G);
-	ret += crisv32_io_get_name(&crisv32_led1_red, CONFIG_ETRAX_LED1R);
-	ret += crisv32_io_get_name(&crisv32_led2_green, CONFIG_ETRAX_LED2G);
-	ret += crisv32_io_get_name(&crisv32_led2_red, CONFIG_ETRAX_LED2R);
-	ret += crisv32_io_get_name(&crisv32_led3_green, CONFIG_ETRAX_LED3G);
-	ret += crisv32_io_get_name(&crisv32_led3_red, CONFIG_ETRAX_LED3R);
-	crisv32_io_set_dir(&crisv32_led1_green, crisv32_io_dir_out);
-	crisv32_io_set_dir(&crisv32_led1_red, crisv32_io_dir_out);
-	crisv32_io_set_dir(&crisv32_led2_green, crisv32_io_dir_out);
-	crisv32_io_set_dir(&crisv32_led2_red, crisv32_io_dir_out);
-	crisv32_io_set_dir(&crisv32_led3_green, crisv32_io_dir_out);
-	crisv32_io_set_dir(&crisv32_led3_red, crisv32_io_dir_out);
-
-	if (!strcmp(CONFIG_ETRAX_LED1G, CONFIG_ETRAX_LED1R))
-		crisv32_led1_red = dummy_led;
-	if (!strcmp(CONFIG_ETRAX_LED2G, CONFIG_ETRAX_LED2R))
-		crisv32_led2_red = dummy_led;
-
-	return ret;
-}
-
-__initcall(crisv32_io_init);
-
-int crisv32_io_get(struct crisv32_iopin* iopin,
-                   unsigned int port, unsigned int pin)
-{
-	if (port > NBR_OF_PORTS)
-		return -EINVAL;
-	if (port > crisv32_ioports[port].pin_count)
-		return -EINVAL;
-
-	iopin->bit = 1 << pin;
-	iopin->port = &crisv32_ioports[port];
-
-	if (crisv32_pinmux_alloc(port, pin, pin, pinmux_gpio))
-		return -EIO;
-
-	return 0;
-}
-
-int crisv32_io_get_name(struct crisv32_iopin* iopin,
-                         char* name)
-{
-	int port;
-	int pin;
-
-	if (toupper(*name) == 'P')
-		name++;
-
-	if (toupper(*name) < 'A' || toupper(*name) > 'E')
-		return -EINVAL;
-
-	port = toupper(*name) - 'A';
-	name++;
-	pin = simple_strtoul(name, NULL, 10);
-
-	if (pin < 0 || pin > crisv32_ioports[port].pin_count)
-		return -EINVAL;
-
-	iopin->bit = 1 << pin;
-	iopin->port = &crisv32_ioports[port];
-
-	if (crisv32_pinmux_alloc(port, pin, pin, pinmux_gpio))
-		return -EIO;
-
-	return 0;
-}
-
-#ifdef CONFIG_PCI
-/* PCI I/O access stuff */
-struct cris_io_operations* cris_iops = NULL;
-EXPORT_SYMBOL(cris_iops);
-#endif
-
diff --git a/arch/cris/arch-v32/kernel/irq.c b/arch/cris/arch-v32/kernel/irq.c
index a9acaa270243..173c141ac9ba 100644
--- a/arch/cris/arch-v32/kernel/irq.c
+++ b/arch/cris/arch-v32/kernel/irq.c
@@ -15,15 +15,21 @@
 #include <linux/threads.h>
 #include <linux/spinlock.h>
 #include <linux/kernel_stat.h>
-#include <asm/arch/hwregs/reg_map.h>
-#include <asm/arch/hwregs/reg_rdwr.h>
-#include <asm/arch/hwregs/intr_vect.h>
-#include <asm/arch/hwregs/intr_vect_defs.h>
+#include <hwregs/reg_map.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/intr_vect.h>
+#include <hwregs/intr_vect_defs.h>
 
 #define CPU_FIXED -1
 
 /* IRQ masks (refer to comment for crisv32_do_multiple) */
-#define TIMER_MASK (1 << (TIMER_INTR_VECT - FIRST_IRQ))
+#if TIMER0_INTR_VECT - FIRST_IRQ < 32
+#define TIMER_MASK (1 << (TIMER0_INTR_VECT - FIRST_IRQ))
+#undef TIMER_VECT1
+#else
+#define TIMER_MASK (1 << (TIMER0_INTR_VECT - FIRST_IRQ - 32))
+#define TIMER_VECT1
+#endif
 #ifdef CONFIG_ETRAX_KGDB
 #if defined(CONFIG_ETRAX_KGDB_PORT0)
 #define IGNOREMASK (1 << (SER0_INTR_VECT - FIRST_IRQ))
@@ -44,8 +50,8 @@ struct cris_irq_allocation
   cpumask_t mask; /* The CPUs to which the IRQ may be allocated. */
 };
 
-struct cris_irq_allocation irq_allocations[NR_IRQS] =
-  {[0 ... NR_IRQS - 1] = {0, CPU_MASK_ALL}};
+struct cris_irq_allocation irq_allocations[NR_REAL_IRQS] =
+  { [0 ... NR_REAL_IRQS - 1] = {0, CPU_MASK_ALL} };
 
 static unsigned long irq_regs[NR_CPUS] =
 {
@@ -55,6 +61,12 @@ static unsigned long irq_regs[NR_CPUS] =
 #endif
 };
 
+#if NR_REAL_IRQS > 32
+#define NBR_REGS 2
+#else
+#define NBR_REGS 1
+#endif
+
 unsigned long cpu_irq_counters[NR_CPUS];
 unsigned long irq_counters[NR_REAL_IRQS];
 
@@ -79,45 +91,81 @@ extern void d_mmu_write(void);
 extern void kgdb_init(void);
 extern void breakpoint(void);
 
+/* From traps.c.  */
+extern void breakh_BUG(void);
+
 /*
- * Build the IRQ handler stubs using macros from irq.h. First argument is the
- * IRQ number, the second argument is the corresponding bit in
- * intr_rw_vect_mask found in asm/arch/hwregs/intr_vect_defs.h.
+ * Build the IRQ handler stubs using macros from irq.h.
  */
-BUILD_IRQ(0x31, (1 << 0))	/* memarb */
-BUILD_IRQ(0x32, (1 << 1))	/* gen_io */
-BUILD_IRQ(0x33, (1 << 2))	/* iop0 */
-BUILD_IRQ(0x34, (1 << 3))	/* iop1 */
-BUILD_IRQ(0x35, (1 << 4))	/* iop2 */
-BUILD_IRQ(0x36, (1 << 5))	/* iop3 */
-BUILD_IRQ(0x37, (1 << 6))	/* dma0 */
-BUILD_IRQ(0x38, (1 << 7))	/* dma1 */
-BUILD_IRQ(0x39, (1 << 8))	/* dma2 */
-BUILD_IRQ(0x3a, (1 << 9))	/* dma3 */
-BUILD_IRQ(0x3b, (1 << 10))	/* dma4 */
-BUILD_IRQ(0x3c, (1 << 11))	/* dma5 */
-BUILD_IRQ(0x3d, (1 << 12))	/* dma6 */
-BUILD_IRQ(0x3e, (1 << 13))	/* dma7 */
-BUILD_IRQ(0x3f, (1 << 14))	/* dma8 */
-BUILD_IRQ(0x40, (1 << 15))	/* dma9 */
-BUILD_IRQ(0x41, (1 << 16))	/* ata */
-BUILD_IRQ(0x42, (1 << 17))	/* sser0 */
-BUILD_IRQ(0x43, (1 << 18))	/* sser1 */
-BUILD_IRQ(0x44, (1 << 19))	/* ser0 */
-BUILD_IRQ(0x45, (1 << 20))	/* ser1 */
-BUILD_IRQ(0x46, (1 << 21))	/* ser2 */
-BUILD_IRQ(0x47, (1 << 22))	/* ser3 */
-BUILD_IRQ(0x48, (1 << 23))
-BUILD_IRQ(0x49, (1 << 24))	/* eth0 */
-BUILD_IRQ(0x4a, (1 << 25))	/* eth1 */
-BUILD_TIMER_IRQ(0x4b, (1 << 26))/* timer */
-BUILD_IRQ(0x4c, (1 << 27))	/* bif_arb */
-BUILD_IRQ(0x4d, (1 << 28))	/* bif_dma */
-BUILD_IRQ(0x4e, (1 << 29))	/* ext */
-BUILD_IRQ(0x4f, (1 << 29))	/* ipi */
+BUILD_IRQ(0x31)
+BUILD_IRQ(0x32)
+BUILD_IRQ(0x33)
+BUILD_IRQ(0x34)
+BUILD_IRQ(0x35)
+BUILD_IRQ(0x36)
+BUILD_IRQ(0x37)
+BUILD_IRQ(0x38)
+BUILD_IRQ(0x39)
+BUILD_IRQ(0x3a)
+BUILD_IRQ(0x3b)
+BUILD_IRQ(0x3c)
+BUILD_IRQ(0x3d)
+BUILD_IRQ(0x3e)
+BUILD_IRQ(0x3f)
+BUILD_IRQ(0x40)
+BUILD_IRQ(0x41)
+BUILD_IRQ(0x42)
+BUILD_IRQ(0x43)
+BUILD_IRQ(0x44)
+BUILD_IRQ(0x45)
+BUILD_IRQ(0x46)
+BUILD_IRQ(0x47)
+BUILD_IRQ(0x48)
+BUILD_IRQ(0x49)
+BUILD_IRQ(0x4a)
+BUILD_IRQ(0x4b)
+BUILD_IRQ(0x4c)
+BUILD_IRQ(0x4d)
+BUILD_IRQ(0x4e)
+BUILD_IRQ(0x4f)
+BUILD_IRQ(0x50)
+#if MACH_IRQS > 32
+BUILD_IRQ(0x51)
+BUILD_IRQ(0x52)
+BUILD_IRQ(0x53)
+BUILD_IRQ(0x54)
+BUILD_IRQ(0x55)
+BUILD_IRQ(0x56)
+BUILD_IRQ(0x57)
+BUILD_IRQ(0x58)
+BUILD_IRQ(0x59)
+BUILD_IRQ(0x5a)
+BUILD_IRQ(0x5b)
+BUILD_IRQ(0x5c)
+BUILD_IRQ(0x5d)
+BUILD_IRQ(0x5e)
+BUILD_IRQ(0x5f)
+BUILD_IRQ(0x60)
+BUILD_IRQ(0x61)
+BUILD_IRQ(0x62)
+BUILD_IRQ(0x63)
+BUILD_IRQ(0x64)
+BUILD_IRQ(0x65)
+BUILD_IRQ(0x66)
+BUILD_IRQ(0x67)
+BUILD_IRQ(0x68)
+BUILD_IRQ(0x69)
+BUILD_IRQ(0x6a)
+BUILD_IRQ(0x6b)
+BUILD_IRQ(0x6c)
+BUILD_IRQ(0x6d)
+BUILD_IRQ(0x6e)
+BUILD_IRQ(0x6f)
+BUILD_IRQ(0x70)
+#endif
 
 /* Pointers to the low-level handlers. */
-static void (*interrupt[NR_IRQS])(void) = {
+static void (*interrupt[MACH_IRQS])(void) = {
 	IRQ0x31_interrupt, IRQ0x32_interrupt, IRQ0x33_interrupt,
 	IRQ0x34_interrupt, IRQ0x35_interrupt, IRQ0x36_interrupt,
 	IRQ0x37_interrupt, IRQ0x38_interrupt, IRQ0x39_interrupt,
@@ -128,7 +176,20 @@ static void (*interrupt[NR_IRQS])(void) = {
 	IRQ0x46_interrupt, IRQ0x47_interrupt, IRQ0x48_interrupt,
 	IRQ0x49_interrupt, IRQ0x4a_interrupt, IRQ0x4b_interrupt,
 	IRQ0x4c_interrupt, IRQ0x4d_interrupt, IRQ0x4e_interrupt,
-	IRQ0x4f_interrupt
+	IRQ0x4f_interrupt, IRQ0x50_interrupt,
+#if MACH_IRQS > 32
+	IRQ0x51_interrupt, IRQ0x52_interrupt, IRQ0x53_interrupt,
+	IRQ0x54_interrupt, IRQ0x55_interrupt, IRQ0x56_interrupt,
+	IRQ0x57_interrupt, IRQ0x58_interrupt, IRQ0x59_interrupt,
+	IRQ0x5a_interrupt, IRQ0x5b_interrupt, IRQ0x5c_interrupt,
+	IRQ0x5d_interrupt, IRQ0x5e_interrupt, IRQ0x5f_interrupt,
+	IRQ0x60_interrupt, IRQ0x61_interrupt, IRQ0x62_interrupt,
+	IRQ0x63_interrupt, IRQ0x64_interrupt, IRQ0x65_interrupt,
+	IRQ0x66_interrupt, IRQ0x67_interrupt, IRQ0x68_interrupt,
+	IRQ0x69_interrupt, IRQ0x6a_interrupt, IRQ0x6b_interrupt,
+	IRQ0x6c_interrupt, IRQ0x6d_interrupt, IRQ0x6e_interrupt,
+	IRQ0x6f_interrupt, IRQ0x70_interrupt,
+#endif
 };
 
 void
@@ -137,13 +198,26 @@ block_irq(int irq, int cpu)
 	int intr_mask;
         unsigned long flags;
 
-        spin_lock_irqsave(&irq_lock, flags);
-        intr_mask = REG_RD_INT(intr_vect, irq_regs[cpu], rw_mask);
-
-	/* Remember; 1 let through, 0 block. */
-	intr_mask &= ~(1 << (irq - FIRST_IRQ));
-
-	REG_WR_INT(intr_vect, irq_regs[cpu], rw_mask, intr_mask);
+	spin_lock_irqsave(&irq_lock, flags);
+	if (irq - FIRST_IRQ < 32)
+		intr_mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu],
+			rw_mask, 0);
+	else
+		intr_mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu],
+			rw_mask, 1);
+
+	/* Remember; 1 let thru, 0 block. */
+	if (irq - FIRST_IRQ < 32)
+		intr_mask &= ~(1 << (irq - FIRST_IRQ));
+	else
+		intr_mask &= ~(1 << (irq - FIRST_IRQ - 32));
+
+	if (irq - FIRST_IRQ < 32)
+		REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask,
+			0, intr_mask);
+	else
+		REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask,
+			1, intr_mask);
         spin_unlock_irqrestore(&irq_lock, flags);
 }
 
@@ -154,12 +228,26 @@ unblock_irq(int irq, int cpu)
         unsigned long flags;
 
         spin_lock_irqsave(&irq_lock, flags);
-        intr_mask = REG_RD_INT(intr_vect, irq_regs[cpu], rw_mask);
-
-	/* Remember; 1 let through, 0 block. */
-	intr_mask |= (1 << (irq - FIRST_IRQ));
+	if (irq - FIRST_IRQ < 32)
+		intr_mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu],
+			rw_mask, 0);
+	else
+		intr_mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu],
+			rw_mask, 1);
+
+	/* Remember; 1 let thru, 0 block. */
+	if (irq - FIRST_IRQ < 32)
+		intr_mask |= (1 << (irq - FIRST_IRQ));
+	else
+		intr_mask |= (1 << (irq - FIRST_IRQ - 32));
+
+	if (irq - FIRST_IRQ < 32)
+		REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask,
+			0, intr_mask);
+	else
+		REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask,
+			1, intr_mask);
 
-	REG_WR_INT(intr_vect, irq_regs[cpu], rw_mask, intr_mask);
         spin_unlock_irqrestore(&irq_lock, flags);
 }
 
@@ -298,8 +386,9 @@ crisv32_do_multiple(struct pt_regs* regs)
 {
 	int cpu;
 	int mask;
-	int masked;
+	int masked[NBR_REGS];
 	int bit;
+	int i;
 
 	cpu = smp_processor_id();
 
@@ -308,42 +397,59 @@ crisv32_do_multiple(struct pt_regs* regs)
 	 */
 	irq_enter();
 
-	/* Get which IRQs that happened. */
-	masked = REG_RD_INT(intr_vect, irq_regs[cpu], r_masked_vect);
+	for (i = 0; i < NBR_REGS; i++) {
+		/* Get which IRQs that happend. */
+		masked[i] = REG_RD_INT_VECT(intr_vect, irq_regs[cpu],
+			r_masked_vect, i);
 
-	/* Calculate new IRQ mask with these IRQs disabled. */
-	mask = REG_RD_INT(intr_vect, irq_regs[cpu], rw_mask);
-	mask &= ~masked;
+		/* Calculate new IRQ mask with these IRQs disabled. */
+		mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, i);
+		mask &= ~masked[i];
 
 	/* Timer IRQ is never masked */
-	if (masked & TIMER_MASK)
-		mask |= TIMER_MASK;
-
-	/* Block all the IRQs */
-	REG_WR_INT(intr_vect, irq_regs[cpu], rw_mask, mask);
+#ifdef TIMER_VECT1
+		if ((i == 1) && (masked[0] & TIMER_MASK))
+			mask |= TIMER_MASK;
+#else
+		if ((i == 0) && (masked[0] & TIMER_MASK))
+			mask |= TIMER_MASK;
+#endif
+		/* Block all the IRQs */
+		REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, i, mask);
 
 	/* Check for timer IRQ and handle it special. */
-	if (masked & TIMER_MASK) {
-	        masked &= ~TIMER_MASK;
-		do_IRQ(TIMER_INTR_VECT, regs);
+#ifdef TIMER_VECT1
+		if ((i == 1) && (masked[i] & TIMER_MASK)) {
+			masked[i] &= ~TIMER_MASK;
+			do_IRQ(TIMER0_INTR_VECT, regs);
+		}
+#else
+		if ((i == 0) && (masked[i] & TIMER_MASK)) {
+			 masked[i] &= ~TIMER_MASK;
+			 do_IRQ(TIMER0_INTR_VECT, regs);
+		}
 	}
+#endif
 
 #ifdef IGNORE_MASK
 	/* Remove IRQs that can't be handled as multiple. */
-	masked &= ~IGNORE_MASK;
+	masked[0] &= ~IGNORE_MASK;
 #endif
 
 	/* Handle the rest of the IRQs. */
-	for (bit = 0; bit < 32; bit++)
-	{
-		if (masked & (1 << bit))
-			do_IRQ(bit + FIRST_IRQ, regs);
+	for (i = 0; i < NBR_REGS; i++) {
+		for (bit = 0; bit < 32; bit++) {
+			if (masked[i] & (1 << bit))
+				do_IRQ(bit + FIRST_IRQ + i*32, regs);
+		}
 	}
 
 	/* Unblock all the IRQs. */
-	mask = REG_RD_INT(intr_vect, irq_regs[cpu], rw_mask);
-	mask |= masked;
-	REG_WR_INT(intr_vect, irq_regs[cpu], rw_mask, mask);
+	for (i = 0; i < NBR_REGS; i++) {
+		mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, i);
+		mask |= masked[i];
+		REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, i, mask);
+	}
 
 	/* This irq_exit() will trigger the soft IRQs. */
 	irq_exit();
@@ -361,20 +467,21 @@ init_IRQ(void)
 	reg_intr_vect_rw_mask vect_mask = {0};
 
 	/* Clear all interrupts masks. */
-	REG_WR(intr_vect, regi_irq, rw_mask, vect_mask);
+	for (i = 0; i < NBR_REGS; i++)
+		REG_WR_VECT(intr_vect, regi_irq, rw_mask, i, vect_mask);
 
 	for (i = 0; i < 256; i++)
 		etrax_irv->v[i] = weird_irq;
 
-	/* Point all IRQs to bad handlers. */
+	/* Point all IRQ's to bad handlers. */
 	for (i = FIRST_IRQ, j = 0; j < NR_IRQS; i++, j++) {
 		irq_desc[j].chip = &crisv32_irq_type;
 		set_exception_vector(i, interrupt[j]);
 	}
 
         /* Mark Timer and IPI IRQs as CPU local */
-	irq_allocations[TIMER_INTR_VECT - FIRST_IRQ].cpu = CPU_FIXED;
-	irq_desc[TIMER_INTR_VECT].status |= IRQ_PER_CPU;
+	irq_allocations[TIMER0_INTR_VECT - FIRST_IRQ].cpu = CPU_FIXED;
+	irq_desc[TIMER0_INTR_VECT].status |= IRQ_PER_CPU;
 	irq_allocations[IPI_INTR_VECT - FIRST_IRQ].cpu = CPU_FIXED;
 	irq_desc[IPI_INTR_VECT].status |= IRQ_PER_CPU;
 
@@ -391,6 +498,11 @@ init_IRQ(void)
 	set_exception_vector(0x0a, d_mmu_access);
 	set_exception_vector(0x0b, d_mmu_write);
 
+#ifdef CONFIG_BUG
+	/* Break 14 handler, used to implement cheap BUG().  */
+	set_exception_vector(0x1e, breakh_BUG);
+#endif
+
 	/* The system-call trap is reached by "break 13". */
 	set_exception_vector(0x1d, system_call);
 
diff --git a/arch/cris/arch-v32/kernel/kgdb.c b/arch/cris/arch-v32/kernel/kgdb.c
index 480e56348be2..4e2e2e271efb 100644
--- a/arch/cris/arch-v32/kernel/kgdb.c
+++ b/arch/cris/arch-v32/kernel/kgdb.c
@@ -381,7 +381,7 @@ static int read_register(char regno, unsigned int *valptr);
 /* Serial port, reads one character. ETRAX 100 specific. from debugport.c */
 int getDebugChar(void);
 
-#ifdef CONFIG_ETRAXFS_SIM
+#ifdef CONFIG_ETRAX_VCS_SIM
 int getDebugChar(void)
 {
   return socketread();
@@ -391,7 +391,7 @@ int getDebugChar(void)
 /* Serial port, writes one character. ETRAX 100 specific. from debugport.c */
 void putDebugChar(int val);
 
-#ifdef CONFIG_ETRAXFS_SIM
+#ifdef CONFIG_ETRAX_VCS_SIM
 void putDebugChar(int val)
 {
   socketwrite((char *)&val, 1);
@@ -1599,7 +1599,7 @@ kgdb_init(void)
 	REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
 
 	ser_intr_mask = REG_RD(ser, regi_ser0, rw_intr_mask);
-	ser_intr_mask.data_avail = regk_ser_yes;
+	ser_intr_mask.dav = regk_ser_yes;
 	REG_WR(ser, regi_ser0, rw_intr_mask, ser_intr_mask);
 #elif defined(CONFIG_ETRAX_KGDB_PORT1)
 	/* Note: no shortcut registered (not handled by multiple_interrupt).
@@ -1611,7 +1611,7 @@ kgdb_init(void)
 	REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
 
 	ser_intr_mask = REG_RD(ser, regi_ser1, rw_intr_mask);
-	ser_intr_mask.data_avail = regk_ser_yes;
+	ser_intr_mask.dav = regk_ser_yes;
 	REG_WR(ser, regi_ser1, rw_intr_mask, ser_intr_mask);
 #elif defined(CONFIG_ETRAX_KGDB_PORT2)
 	/* Note: no shortcut registered (not handled by multiple_interrupt).
@@ -1623,7 +1623,7 @@ kgdb_init(void)
 	REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
 
 	ser_intr_mask = REG_RD(ser, regi_ser2, rw_intr_mask);
-	ser_intr_mask.data_avail = regk_ser_yes;
+	ser_intr_mask.dav = regk_ser_yes;
 	REG_WR(ser, regi_ser2, rw_intr_mask, ser_intr_mask);
 #elif defined(CONFIG_ETRAX_KGDB_PORT3)
 	/* Note: no shortcut registered (not handled by multiple_interrupt).
@@ -1635,7 +1635,7 @@ kgdb_init(void)
 	REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
 
 	ser_intr_mask = REG_RD(ser, regi_ser3, rw_intr_mask);
-	ser_intr_mask.data_avail = regk_ser_yes;
+	ser_intr_mask.dav = regk_ser_yes;
 	REG_WR(ser, regi_ser3, rw_intr_mask, ser_intr_mask);
 #endif
 
diff --git a/arch/cris/arch-v32/kernel/process.c b/arch/cris/arch-v32/kernel/process.c
index b72a15580dc7..ced5b725d9bd 100644
--- a/arch/cris/arch-v32/kernel/process.c
+++ b/arch/cris/arch-v32/kernel/process.c
@@ -12,17 +12,13 @@
 #include <linux/err.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
-#include <asm/arch/hwregs/reg_rdwr.h>
-#include <asm/arch/hwregs/reg_map.h>
-#include <asm/arch/hwregs/timer_defs.h>
-#include <asm/arch/hwregs/intr_vect_defs.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/reg_map.h>
+#include <hwregs/timer_defs.h>
+#include <hwregs/intr_vect_defs.h>
 
 extern void stop_watchdog(void);
 
-#ifdef CONFIG_ETRAX_GPIO
-extern void etrax_gpio_wake_up_check(void); /* Defined in drivers/gpio.c. */
-#endif
-
 extern int cris_hlt_counter;
 
 /* We use this if we don't have any better idle routine. */
@@ -82,7 +78,7 @@ hard_reset_now(void)
 	wd_ctrl.cmd = regk_timer_start;
 
         arch_enable_nmi();
-	REG_WR(timer, regi_timer, rw_wd_ctrl, wd_ctrl);
+	REG_WR(timer, regi_timer0, rw_wd_ctrl, wd_ctrl);
 }
 #endif
 
diff --git a/arch/cris/arch-v32/kernel/ptrace.c b/arch/cris/arch-v32/kernel/ptrace.c
index 2df60529a8af..e27f4670e88e 100644
--- a/arch/cris/arch-v32/kernel/ptrace.c
+++ b/arch/cris/arch-v32/kernel/ptrace.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2000-2003, Axis Communications AB.
+ * Copyright (C) 2000-2007, Axis Communications AB.
  */
 
 #include <linux/kernel.h>
@@ -149,7 +149,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 			ret = generic_ptrace_pokedata(child, addr, data);
 			break;
 
- 		/* Write the word at location address in the USER area. */
+		/* Write the word at location address in the USER area. */
 		case PTRACE_POKEUSR:
 			ret = -EIO;
 			if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
@@ -201,7 +201,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 
 			break;
 
- 		/* Make the child exit by sending it a sigkill. */
+		/* Make the child exit by sending it a sigkill. */
 		case PTRACE_KILL:
 			ret = 0;
 
@@ -245,9 +245,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 			break;
 
 		}
+
 		/* Get all GP registers from the child. */
 		case PTRACE_GETREGS: {
-		  	int i;
+			int i;
 			unsigned long tmp;
 
 			for (i = 0; i <= PT_MAX; i++) {
@@ -294,6 +295,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 			break;
 	}
 
+out_tsk:
 	return ret;
 }
 
diff --git a/arch/cris/arch-v32/kernel/signal.c b/arch/cris/arch-v32/kernel/signal.c
index 024cc6901974..58c1866804e3 100644
--- a/arch/cris/arch-v32/kernel/signal.c
+++ b/arch/cris/arch-v32/kernel/signal.c
@@ -50,7 +50,7 @@ struct rt_signal_frame {
 	unsigned char retcode[8];	/* Trampoline code. */
 };
 
-int do_signal(int restart, sigset_t *oldset, struct pt_regs *regs);
+void do_signal(int restart, struct pt_regs *regs);
 void keep_debug_flags(unsigned long oldccs, unsigned long oldspc,
 		      struct pt_regs *regs);
 /*
@@ -61,74 +61,16 @@ 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;
-
+	current->saved_sigmask = 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)) {
-			/*
-			 * This point is reached twice: once to call
-			 * the signal handler, then again to return
-			 * from the sigsuspend system call. When
-			 * calling the signal handler, R10 hold the
-			 * signal number as set by do_signal(). The
-			 * sigsuspend  call will always return with
-			 * the restored value above; -EINTR.
-			 */
-			return regs->r10;
-		}
-	}
-}
-
-/* Define some dummy arguments to be able to reach the regs argument. */
-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;
-	sigset_t newset;
-
-	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)) {
-			/* See comment in function above. */
-			return regs->r10;
-		}
-	}
+	current->state = TASK_INTERRUPTIBLE;
+	schedule();
+	set_thread_flag(TIF_RESTORE_SIGMASK);
+	return -ERESTARTNOHAND;
 }
 
 int
@@ -290,7 +232,7 @@ sys_rt_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp,
 		goto badframe;
 
 	if (do_sigaltstack(&frame->uc.uc_stack, NULL, rdusp()) == -EFAULT)
- 		goto badframe;
+		goto badframe;
 
 	keep_debug_flags(oldccs, oldspc, regs);
 
@@ -347,11 +289,11 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
 /* Grab and setup a signal frame.
  *
  * Basically a lot of state-info is stacked, and arranged for the
- * user-mode program to return to the kernel using either a trampoline
+ * user-mode program to return to the kernel using either a trampiline
  * which performs the syscall sigreturn(), or a provided user-mode
  * trampoline.
   */
-static void
+static int
 setup_frame(int sig, struct k_sigaction *ka,  sigset_t *set,
 	    struct pt_regs * regs)
 {
@@ -417,16 +359,17 @@ setup_frame(int sig, struct k_sigaction *ka,  sigset_t *set,
 	/* Actually move the USP to reflect the stacked frame. */
 	wrusp((unsigned long)frame);
 
-	return;
+	return 0;
 
 give_sigsegv:
 	if (sig == SIGSEGV)
 		ka->sa.sa_handler = SIG_DFL;
 
 	force_sig(SIGSEGV, current);
+	return -EFAULT;
 }
 
-static void
+static int
 setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 	       sigset_t *set, struct pt_regs * regs)
 {
@@ -503,21 +446,24 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 	/* Actually move the usp to reflect the stacked frame. */
 	wrusp((unsigned long)frame);
 
-	return;
+	return 0;
 
 give_sigsegv:
 	if (sig == SIGSEGV)
 		ka->sa.sa_handler = SIG_DFL;
 
 	force_sig(SIGSEGV, current);
+	return -EFAULT;
 }
 
 /* Invoke a singal handler to, well, handle the signal. */
-static inline void
+static inline int
 handle_signal(int canrestart, unsigned long sig,
 	      siginfo_t *info, struct k_sigaction *ka,
               sigset_t *oldset, struct pt_regs * regs)
 {
+	int ret;
+
 	/* Check if this got called from a system call. */
 	if (canrestart) {
 		/* If so, check system call restarting. */
@@ -561,19 +507,24 @@ handle_signal(int canrestart, unsigned long sig,
 
 	/* Set up the stack frame. */
 	if (ka->sa.sa_flags & SA_SIGINFO)
-		setup_rt_frame(sig, ka, info, oldset, regs);
+		ret = setup_rt_frame(sig, ka, info, oldset, regs);
 	else
-		setup_frame(sig, ka, oldset, regs);
+		ret = setup_frame(sig, ka, oldset, regs);
 
 	if (ka->sa.sa_flags & SA_ONESHOT)
 		ka->sa.sa_handler = SIG_DFL;
 
-	spin_lock_irq(&current->sighand->siglock);
-	sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-	if (!(ka->sa.sa_flags & SA_NODEFER))
-		sigaddset(&current->blocked,sig);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	if (ret == 0) {
+		spin_lock_irq(&current->sighand->siglock);
+		sigorsets(&current->blocked, &current->blocked,
+			&ka->sa.sa_mask);
+		if (!(ka->sa.sa_flags & SA_NODEFER))
+			sigaddset(&current->blocked, sig);
+		recalc_sigpending();
+		spin_unlock_irq(&current->sighand->siglock);
+	}
+
+	return ret;
 }
 
 /*
@@ -587,12 +538,13 @@ handle_signal(int canrestart, unsigned long sig,
  * 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)
+void
+do_signal(int canrestart, struct pt_regs *regs)
 {
 	int signr;
 	siginfo_t info;
         struct k_sigaction ka;
+	sigset_t *oldset;
 
 	/*
 	 * The common case should go fast, which is why this point is
@@ -600,17 +552,28 @@ do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
 	 * without doing anything.
 	 */
 	if (!user_mode(regs))
-		return 1;
+		return;
 
-	if (!oldset)
+	if (test_thread_flag(TIF_RESTORE_SIGMASK))
+		oldset = &current->saved_sigmask;
+	else
 		oldset = &current->blocked;
 
 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 
 	if (signr > 0) {
-		/* Deliver the signal. */
-		handle_signal(canrestart, signr, &info, &ka, oldset, regs);
-		return 1;
+		/* Whee!  Actually deliver the signal.  */
+		if (handle_signal(canrestart, signr, &info, &ka,
+				oldset, regs)) {
+			/* a signal was successfully delivered; the saved
+			 * sigmask will have been stored in the signal frame,
+			 * and will be restored by sigreturn, so we can simply
+			 * clear the TIF_RESTORE_SIGMASK flag */
+			if (test_thread_flag(TIF_RESTORE_SIGMASK))
+				clear_thread_flag(TIF_RESTORE_SIGMASK);
+		}
+
+		return;
 	}
 
 	/* Got here from a system call? */
@@ -628,7 +591,12 @@ do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
 		}
 	}
 
-	return 0;
+	/* if there's no signal to deliver, we just put the saved sigmask
+	 * back */
+	if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+		clear_thread_flag(TIF_RESTORE_SIGMASK);
+		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+	}
 }
 
 asmlinkage void
@@ -641,7 +609,7 @@ ugdb_trap_user(struct thread_info *ti, int sig)
 		user_regs(ti)->spc = 0;
 	}
 	/* FIXME: Filter out false h/w breakpoint hits (i.e. EDA
-	   not within any configured h/w breakpoint range). Synchronize with
+	   not withing any configured h/w breakpoint range). Synchronize with
 	   what already exists for kernel debugging.  */
 	if (((user_regs(ti)->exs & 0xff00) >> 8) == BREAK_8_INTR_VECT) {
 		/* Break 8: subtract 2 from ERP unless in a delay slot. */
diff --git a/arch/cris/arch-v32/kernel/smp.c b/arch/cris/arch-v32/kernel/smp.c
index 171c96e0a5d3..a9c3334e46c9 100644
--- a/arch/cris/arch-v32/kernel/smp.c
+++ b/arch/cris/arch-v32/kernel/smp.c
@@ -1,11 +1,12 @@
+#include <linux/types.h>
 #include <asm/delay.h>
-#include <asm/arch/irq.h>
-#include <asm/arch/hwregs/intr_vect.h>
-#include <asm/arch/hwregs/intr_vect_defs.h>
+#include <irq.h>
+#include <hwregs/intr_vect.h>
+#include <hwregs/intr_vect_defs.h>
 #include <asm/tlbflush.h>
 #include <asm/mmu_context.h>
-#include <asm/arch/hwregs/mmu_defs_asm.h>
-#include <asm/arch/hwregs/supp_reg.h>
+#include <hwregs/asm/mmu_defs_asm.h>
+#include <hwregs/supp_reg.h>
 #include <asm/atomic.h>
 
 #include <linux/err.h>
@@ -20,6 +21,7 @@
 #define IPI_SCHEDULE 1
 #define IPI_CALL 2
 #define IPI_FLUSH_TLB 4
+#define IPI_BOOT 8
 
 #define FLUSH_ALL (void*)0xffffffff
 
@@ -30,6 +32,8 @@ spinlock_t cris_atomic_locks[] = { [0 ... LOCK_COUNT - 1] = SPIN_LOCK_UNLOCKED};
 cpumask_t cpu_online_map = CPU_MASK_NONE;
 EXPORT_SYMBOL(cpu_online_map);
 cpumask_t phys_cpu_present_map = CPU_MASK_NONE;
+cpumask_t cpu_possible_map;
+EXPORT_SYMBOL(cpu_possible_map);
 EXPORT_SYMBOL(phys_cpu_present_map);
 
 /* Variables used during SMP boot */
@@ -55,13 +59,12 @@ static unsigned long flush_addr;
 extern int setup_irq(int, struct irqaction *);
 
 /* Mode registers */
-static unsigned long irq_regs[NR_CPUS] =
-{
+static unsigned long irq_regs[NR_CPUS] = {
   regi_irq,
   regi_irq2
 };
 
-static irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id);
 static int send_ipi(int vector, int wait, cpumask_t cpu_mask);
 static struct irqaction irq_ipi  = {
 	.handler = crisv32_ipi_interrupt,
@@ -101,6 +104,7 @@ void __devinit smp_prepare_boot_cpu(void)
 
 	cpu_set(0, cpu_online_map);
 	cpu_set(0, phys_cpu_present_map);
+	cpu_set(0, cpu_possible_map);
 }
 
 void __init smp_cpus_done(unsigned int max_cpus)
@@ -113,6 +117,7 @@ smp_boot_one_cpu(int cpuid)
 {
 	unsigned timeout;
 	struct task_struct *idle;
+	cpumask_t cpu_mask = CPU_MASK_NONE;
 
 	idle = fork_idle(cpuid);
 	if (IS_ERR(idle))
@@ -124,6 +129,12 @@ smp_boot_one_cpu(int cpuid)
 	smp_init_current_idle_thread = task_thread_info(idle);
 	cpu_now_booting = cpuid;
 
+	/* Kick it */
+	cpu_set(cpuid, cpu_online_map);
+	cpu_set(cpuid, cpu_mask);
+	send_ipi(IPI_BOOT, 0, cpu_mask);
+	cpu_clear(cpuid, cpu_online_map);
+
 	/* Wait for CPU to come online */
 	for (timeout = 0; timeout < 10000; timeout++) {
 		if(cpu_online(cpuid)) {
@@ -165,7 +176,7 @@ void __init smp_callin(void)
 	/* Enable IRQ and idle */
 	REG_WR(intr_vect, irq_regs[cpu], rw_mask, vect_mask);
 	unmask_irq(IPI_INTR_VECT);
-	unmask_irq(TIMER_INTR_VECT);
+	unmask_irq(TIMER0_INTR_VECT);
 	preempt_disable();
 	local_irq_enable();
 
@@ -328,7 +339,7 @@ int smp_call_function(void (*func)(void *info), void *info,
 	return ret;
 }
 
-irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id)
 {
 	void (*func) (void *info) = call_data->func;
 	void *info = call_data->info;
diff --git a/arch/cris/arch-v32/kernel/time.c b/arch/cris/arch-v32/kernel/time.c
index 2f7e8e200f2c..3a13dd6e0a9a 100644
--- a/arch/cris/arch-v32/kernel/time.c
+++ b/arch/cris/arch-v32/kernel/time.c
@@ -1,8 +1,7 @@
-/* $Id: time.c,v 1.19 2005/04/29 05:40:09 starvik Exp $
- *
+/*
  *  linux/arch/cris/arch-v32/kernel/time.c
  *
- *  Copyright (C) 2003 Axis Communications AB
+ *  Copyright (C) 2003-2007 Axis Communications AB
  *
  */
 
@@ -14,28 +13,34 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/threads.h>
+#include <linux/cpufreq.h>
 #include <asm/types.h>
 #include <asm/signal.h>
 #include <asm/io.h>
 #include <asm/delay.h>
 #include <asm/rtc.h>
 #include <asm/irq.h>
-
-#include <asm/arch/hwregs/reg_map.h>
-#include <asm/arch/hwregs/reg_rdwr.h>
-#include <asm/arch/hwregs/timer_defs.h>
-#include <asm/arch/hwregs/intr_vect_defs.h>
+#include <asm/irq_regs.h>
+
+#include <hwregs/reg_map.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/timer_defs.h>
+#include <hwregs/intr_vect_defs.h>
+#ifdef CONFIG_CRIS_MACH_ARTPEC3
+#include <hwregs/clkgen_defs.h>
+#endif
 
 /* Watchdog defines */
-#define ETRAX_WD_KEY_MASK 0x7F /* key is 7 bit */
-#define ETRAX_WD_HZ       763 /* watchdog counts at 763 Hz */
-#define ETRAX_WD_CNT      ((2*ETRAX_WD_HZ)/HZ + 1) /* Number of 763 counts before watchdog bites */
+#define ETRAX_WD_KEY_MASK	0x7F /* key is 7 bit */
+#define ETRAX_WD_HZ		763 /* watchdog counts at 763 Hz */
+/* Number of 763 counts before watchdog bites */
+#define ETRAX_WD_CNT		((2*ETRAX_WD_HZ)/HZ + 1)
 
 unsigned long timer_regs[NR_CPUS] =
 {
-  regi_timer,
+	regi_timer0,
 #ifdef CONFIG_SMP
-  regi_timer2
+	regi_timer2
 #endif
 };
 
@@ -44,12 +49,22 @@ extern int set_rtc_mmss(unsigned long nowtime);
 extern int setup_irq(int, struct irqaction *);
 extern int have_rtc;
 
+#ifdef CONFIG_CPU_FREQ
+static int
+cris_time_freq_notifier(struct notifier_block *nb, unsigned long val,
+			void *data);
+
+static struct notifier_block cris_time_freq_notifier_block = {
+	.notifier_call = cris_time_freq_notifier,
+};
+#endif
+
 unsigned long get_ns_in_jiffie(void)
 {
 	reg_timer_r_tmr0_data data;
 	unsigned long ns;
 
-	data = REG_RD(timer, regi_timer, r_tmr0_data);
+	data = REG_RD(timer, regi_timer0, r_tmr0_data);
 	ns = (TIMER0_DIV - data) * 10;
 	return ns;
 }
@@ -59,31 +74,27 @@ unsigned long do_slow_gettimeoffset(void)
 	unsigned long count;
 	unsigned long usec_count = 0;
 
-	static unsigned long count_p = TIMER0_DIV;/* for the first call after boot */
+	/* For the first call after boot */
+	static unsigned long count_p = TIMER0_DIV;
 	static unsigned long jiffies_p = 0;
 
-	/*
-	 * cache volatile jiffies temporarily; we have IRQs turned off.
-	 */
+	/* 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.
-	 */
+	 * underflowed already though. */
+	count = REG_RD(timer, regi_timer0, r_tmr0_data);
+	jiffies_t = jiffies;
 
-	count = REG_RD(timer, regi_timer, r_tmr0_data);
- 	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
+	/* Avoiding timer inconsistencies (they are rare, but they happen)
+	 * There is 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
+			/* Timer wrapped, use new count and prescale.
+			 * Increase the time corresponding to one jiffy.
 			 */
 			usec_count = 1000000/HZ;
 		}
@@ -106,17 +117,15 @@ unsigned long do_slow_gettimeoffset(void)
  */
 /* This gives us 1.3 ms to do something useful when the NMI comes */
 
-/* right now, starting the watchdog is the same as resetting it */
+/* Right now, starting the watchdog is the same as resetting it */
 #define start_watchdog reset_watchdog
 
 #if defined(CONFIG_ETRAX_WATCHDOG)
 static short int watchdog_key = 42;  /* arbitrary 7 bit number */
 #endif
 
-/* number of pages to consider "out of memory". it is normal that the memory
- * is used though, so put this really low.
- */
-
+/* Number of pages to consider "out of memory". It is normal that the memory
+ * is used though, so set this really low. */
 #define WATCHDOG_MIN_FREE_PAGES 8
 
 void
@@ -125,14 +134,15 @@ reset_watchdog(void)
 #if defined(CONFIG_ETRAX_WATCHDOG)
 	reg_timer_rw_wd_ctrl wd_ctrl = { 0 };
 
-	/* only keep watchdog happy as long as we have memory left! */
+	/* 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 ^= ETRAX_WD_KEY_MASK; /* invert key, which is 7 bits */
+		/* Reset the watchdog with the inverse of the old key */
+		/* Invert key, which is 7 bits */
+		watchdog_key ^= ETRAX_WD_KEY_MASK;
 		wd_ctrl.cnt = ETRAX_WD_CNT;
 		wd_ctrl.cmd = regk_timer_start;
 		wd_ctrl.key = watchdog_key;
-		REG_WR(timer, regi_timer, rw_wd_ctrl, wd_ctrl);
+		REG_WR(timer, regi_timer0, rw_wd_ctrl, wd_ctrl);
 	}
 #endif
 }
@@ -148,7 +158,7 @@ stop_watchdog(void)
 	wd_ctrl.cnt = ETRAX_WD_CNT;
 	wd_ctrl.cmd = regk_timer_stop;
 	wd_ctrl.key = watchdog_key;
-	REG_WR(timer, regi_timer, rw_wd_ctrl, wd_ctrl);
+	REG_WR(timer, regi_timer0, rw_wd_ctrl, wd_ctrl);
 #endif
 }
 
@@ -160,17 +170,28 @@ handle_watchdog_bite(struct pt_regs* regs)
 #if defined(CONFIG_ETRAX_WATCHDOG)
 	extern int cause_of_death;
 
-	raw_printk("Watchdog bite\n");
+	oops_in_progress = 1;
+	printk(KERN_WARNING "Watchdog bite\n");
 
 	/* Check if forced restart or unexpected watchdog */
 	if (cause_of_death == 0xbedead) {
+#ifdef CONFIG_CRIS_MACH_ARTPEC3
+		/* There is a bug in Artpec-3 (voodoo TR 78) that requires
+		 * us to go to lower frequency for the reset to be reliable
+		 */
+		reg_clkgen_rw_clk_ctrl ctrl =
+			REG_RD(clkgen, regi_clkgen, rw_clk_ctrl);
+		ctrl.pll = 0;
+		REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, ctrl);
+#endif
 		while(1);
 	}
 
-	/* Unexpected watchdog, stop the watchdog and dump registers*/
+	/* Unexpected watchdog, stop the watchdog and dump registers. */
 	stop_watchdog();
-	raw_printk("Oops: bitten by watchdog\n");
-        show_registers(regs);
+	printk(KERN_WARNING "Oops: bitten by watchdog\n");
+	show_registers(regs);
+	oops_in_progress = 0;
 #ifndef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
 	reset_watchdog();
 #endif
@@ -178,21 +199,19 @@ handle_watchdog_bite(struct pt_regs* regs)
 #endif
 }
 
-/* last time the cmos clock got updated */
+/* 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
+ * 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)
+timer_interrupt(int irq, void *dev_id)
 {
+	struct pt_regs *regs = get_irq_regs();
 	int cpu = smp_processor_id();
 	reg_timer_r_masked_intr masked_intr;
 	reg_timer_rw_ack_intr ack_intr = { 0 };
@@ -202,11 +221,11 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 	if (!masked_intr.tmr0)
 		return IRQ_NONE;
 
-	/* acknowledge the timer irq */
+	/* Acknowledge the timer irq. */
 	ack_intr.tmr0 = 1;
 	REG_WR(timer, timer_regs[cpu], rw_ack_intr, ack_intr);
 
-	/* reset watchdog otherwise it resets us! */
+	/* Reset watchdog otherwise it resets us! */
 	reset_watchdog();
 
         /* Update statistics. */
@@ -218,7 +237,7 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 	if (cpu != 0)
 		return IRQ_HANDLED;
 
-	/* call the real timer interrupt handler */
+	/* Call the real timer interrupt handler */
 	do_timer(1);
 
 	/*
@@ -236,17 +255,17 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 		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 */
+			/* Do it again in 60 s */
+			last_rtc_update = xtime.tv_sec - 600;
 	}
         return IRQ_HANDLED;
 }
 
-/* timer is IRQF_SHARED so drivers can add stuff to the timer irq chain
- * it needs to be IRQF_DISABLED to make the jiffies update work properly
+/* Timer is IRQF_SHARED so drivers can add stuff to the timer irq chain.
+ * It needs to be IRQF_DISABLED to make the jiffies update work properly.
  */
-
-static struct irqaction irq_timer  = {
-	.mask = timer_interrupt,
+static struct irqaction irq_timer = {
+	.handler = timer_interrupt,
 	.flags = IRQF_SHARED | IRQF_DISABLED,
 	.mask = CPU_MASK_NONE,
 	.name = "timer"
@@ -256,27 +275,27 @@ void __init
 cris_timer_init(void)
 {
 	int cpu = smp_processor_id();
-  	reg_timer_rw_tmr0_ctrl tmr0_ctrl = { 0 };
-       	reg_timer_rw_tmr0_div tmr0_div = TIMER0_DIV;
+	reg_timer_rw_tmr0_ctrl tmr0_ctrl = { 0 };
+	reg_timer_rw_tmr0_div tmr0_div = TIMER0_DIV;
 	reg_timer_rw_intr_mask timer_intr_mask;
 
-	/* Setup the etrax timers
+	/* Setup the etrax timers.
 	 * Base frequency is 100MHz, divider 1000000 -> 100 HZ
 	 * We use timer0, so timer1 is free.
 	 * The trig timer is used by the fasttimer API if enabled.
 	 */
 
-       	tmr0_ctrl.op = regk_timer_ld;
+	tmr0_ctrl.op = regk_timer_ld;
 	tmr0_ctrl.freq = regk_timer_f100;
-       	REG_WR(timer, timer_regs[cpu], rw_tmr0_div, tmr0_div);
-       	REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Load */
-       	tmr0_ctrl.op = regk_timer_run;
-       	REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Start */
-
-       	/* enable the timer irq */
-       	timer_intr_mask = REG_RD(timer, timer_regs[cpu], rw_intr_mask);
-       	timer_intr_mask.tmr0 = 1;
-       	REG_WR(timer, timer_regs[cpu], rw_intr_mask, timer_intr_mask);
+	REG_WR(timer, timer_regs[cpu], rw_tmr0_div, tmr0_div);
+	REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Load */
+	tmr0_ctrl.op = regk_timer_run;
+	REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Start */
+
+	/* Enable the timer irq. */
+	timer_intr_mask = REG_RD(timer, timer_regs[cpu], rw_intr_mask);
+	timer_intr_mask.tmr0 = 1;
+	REG_WR(timer, timer_regs[cpu], rw_intr_mask, timer_intr_mask);
 }
 
 void __init
@@ -284,7 +303,7 @@ time_init(void)
 {
 	reg_intr_vect_rw_mask intr_mask;
 
-	/* probe for the RTC and read it if it exists
+	/* 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
@@ -293,52 +312,74 @@ time_init(void)
 	loops_per_usec = 50;
 
 	if(RTC_INIT() < 0) {
-		/* no RTC, start at 1980 */
+		/* No RTC, start at 1980 */
 		xtime.tv_sec = 0;
 		xtime.tv_nsec = 0;
 		have_rtc = 0;
 	} else {
-		/* get the current time */
+		/* 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).
+	 * 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);
 
-	/* Start CPU local timer */
+	/* Start CPU local timer. */
 	cris_timer_init();
 
-	/* enable the timer irq in global config */
-	intr_mask = REG_RD(intr_vect, regi_irq, rw_mask);
-	intr_mask.timer = 1;
-	REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
-
-	/* now actually register the timer irq handler that calls timer_interrupt() */
+	/* Enable the timer irq in global config. */
+	intr_mask = REG_RD_VECT(intr_vect, regi_irq, rw_mask, 1);
+	intr_mask.timer0 = 1;
+	REG_WR_VECT(intr_vect, regi_irq, rw_mask, 1, intr_mask);
 
-	setup_irq(TIMER_INTR_VECT, &irq_timer);
+	/* Now actually register the timer irq handler that calls
+	 * timer_interrupt(). */
+	setup_irq(TIMER0_INTR_VECT, &irq_timer);
 
-	/* enable watchdog if we should use one */
+	/* Enable watchdog if we should use one. */
 
 #if defined(CONFIG_ETRAX_WATCHDOG)
-	printk("Enabling watchdog...\n");
+	printk(KERN_INFO "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.  */
-        {
-          unsigned long flags;
-          local_save_flags(flags);
-          flags |= (1<<30); /* NMI M flag is at bit 30 */
-          local_irq_restore(flags);
-        }
+	 * 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). */
+	{
+		unsigned long flags;
+		local_save_flags(flags);
+		flags |= (1<<30); /* NMI M flag is at bit 30 */
+		local_irq_restore(flags);
+	}
+#endif
+
+#ifdef CONFIG_CPU_FREQ
+	cpufreq_register_notifier(&cris_time_freq_notifier_block,
+		CPUFREQ_TRANSITION_NOTIFIER);
 #endif
 }
+
+#ifdef CONFIG_CPU_FREQ
+static int
+cris_time_freq_notifier(struct notifier_block *nb, unsigned long val,
+			void *data)
+{
+	struct cpufreq_freqs *freqs = data;
+	if (val == CPUFREQ_POSTCHANGE) {
+		reg_timer_r_tmr0_data data;
+		reg_timer_rw_tmr0_div div = (freqs->new * 500) / HZ;
+		do {
+			data = REG_RD(timer, timer_regs[freqs->cpu],
+				r_tmr0_data);
+		} while (data > 20);
+		REG_WR(timer, timer_regs[freqs->cpu], rw_tmr0_div, div);
+	}
+	return 0;
+}
+#endif
diff --git a/arch/cris/arch-v32/kernel/traps.c b/arch/cris/arch-v32/kernel/traps.c
index 17fd3dbd1c80..9003e382cada 100644
--- a/arch/cris/arch-v32/kernel/traps.c
+++ b/arch/cris/arch-v32/kernel/traps.c
@@ -1,50 +1,45 @@
 /*
- * Copyright (C) 2003, Axis Communications AB.
+ * Copyright (C) 2003-2006, Axis Communications AB.
  */
 
 #include <linux/ptrace.h>
+#include <linux/module.h>
 #include <asm/uaccess.h>
-
-#include <asm/arch/hwregs/supp_reg.h>
-
-extern void reset_watchdog(void);
-extern void stop_watchdog(void);
-
-extern int raw_printk(const char *fmt, ...);
+#include <hwregs/supp_reg.h>
+#include <hwregs/intr_vect_defs.h>
+#include <asm/irq.h>
 
 void
 show_registers(struct pt_regs *regs)
 {
 	/*
 	 * It's possible to use either the USP register or current->thread.usp.
-	 * USP might not correspond to the current proccess for all cases this
+	 * USP might not correspond to the current process for all cases this
 	 * function is called, and current->thread.usp isn't up to date for the
-	 * current proccess. Experience shows that using USP is the way to go.
+	 * current process. Experience shows that using USP is the way to go.
 	 */
-	unsigned long usp;
+	unsigned long usp = rdusp();
 	unsigned long d_mmu_cause;
 	unsigned long i_mmu_cause;
 
-	usp = rdusp();
+	printk("CPU: %d\n", smp_processor_id());
 
-	raw_printk("CPU: %d\n", smp_processor_id());
+	printk("ERP: %08lx SRP: %08lx  CCS: %08lx USP: %08lx MOF: %08lx\n",
+	       regs->erp, regs->srp, regs->ccs, usp, regs->mof);
 
-	raw_printk("ERP: %08lx SRP: %08lx  CCS: %08lx USP: %08lx MOF: %08lx\n",
-		regs->erp, regs->srp, regs->ccs, usp, regs->mof);
+	printk(" r0: %08lx  r1: %08lx   r2: %08lx  r3: %08lx\n",
+	       regs->r0, regs->r1, regs->r2, regs->r3);
 
-	raw_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);
 
-	raw_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);
 
-	raw_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 acr: %08lx\n",
+	       regs->r12, regs->r13, regs->orig_r10, regs->acr);
 
-	raw_printk("r12: %08lx r13: %08lx oR10: %08lx acr: %08lx\n",
-		regs->r12, regs->r13, regs->orig_r10, regs->acr);
-
-	raw_printk("sp: %08lx\n", regs);
+	printk(" sp: %08lx\n", (unsigned long)regs);
 
 	SUPP_BANK_SEL(BANK_IM);
 	SUPP_REG_RD(RW_MM_CAUSE, i_mmu_cause);
@@ -52,18 +47,20 @@ show_registers(struct pt_regs *regs)
 	SUPP_BANK_SEL(BANK_DM);
 	SUPP_REG_RD(RW_MM_CAUSE, d_mmu_cause);
 
-	raw_printk("       Data MMU Cause: %08lx\n", d_mmu_cause);
-	raw_printk("Instruction MMU Cause: %08lx\n", i_mmu_cause);
+	printk("       Data MMU Cause: %08lx\n", d_mmu_cause);
+	printk("Instruction MMU Cause: %08lx\n", i_mmu_cause);
 
-	raw_printk("Process %s (pid: %d, stackpage: %08lx)\n",
-		current->comm, current->pid, (unsigned long) current);
+	printk("Process %s (pid: %d, stackpage=%08lx)\n",
+	       current->comm, current->pid, (unsigned long)current);
 
-	/* Show additional info if in kernel-mode. */
+	/*
+	 * When in-kernel, we also print out the stack and code at the
+	 * time of the fault..
+	 */
 	if (!user_mode(regs)) {
 		int i;
-		unsigned char c;
 
-		show_stack(NULL, (unsigned long *) usp);
+		show_stack(NULL, (unsigned long *)usp);
 
 		/*
 		 * If the previous stack-dump wasn't a kernel one, dump the
@@ -72,7 +69,7 @@ show_registers(struct pt_regs *regs)
 		if (usp != 0)
 			show_stack(NULL, NULL);
 
-		raw_printk("\nCode: ");
+		printk("\nCode: ");
 
 		if (regs->erp < PAGE_OFFSET)
 			goto bad_value;
@@ -84,76 +81,115 @@ show_registers(struct pt_regs *regs)
 		 * instruction decoding should be in sync at the interesting
 		 * point, but small enough to fit on a row. The regs->erp
 		 * location is pointed out in a ksymoops-friendly way by
-		 * wrapping the byte for that address in parenthesis.
+		 * wrapping the byte for that address in parenthesises.
 		 */
 		for (i = -12; i < 12; i++) {
-			if (__get_user(c, &((unsigned char *) regs->erp)[i])) {
+			unsigned char c;
+
+			if (__get_user(c, &((unsigned char *)regs->erp)[i])) {
 bad_value:
-				raw_printk(" Bad IP value.");
+				printk(" Bad IP value.");
 				break;
 			}
 
 			if (i == 0)
-				raw_printk("(%02x) ", c);
+				printk("(%02x) ", c);
 			else
-				raw_printk("%02x ", c);
+				printk("%02x ", c);
 		}
-
-		raw_printk("\n");
+		printk("\n");
 	}
 }
 
-/*
- * This gets called from entry.S when the watchdog has bitten. Show something
- * similar to an Oops dump, and if the kernel is configured to be a nice doggy;
- * halt instead of reboot.
- */
 void
-watchdog_bite_hook(struct pt_regs *regs)
+arch_enable_nmi(void)
 {
-#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
-	local_irq_disable();
-	stop_watchdog();
-	show_registers(regs);
+	unsigned long flags;
 
-	while (1)
-		; /* Do nothing. */
-#else
-	show_registers(regs);
-#endif
+	local_save_flags(flags);
+	flags |= (1 << 30); /* NMI M flag is at bit 30 */
+	local_irq_restore(flags);
 }
 
-/* This is normally the Oops function. */
-void
-die_if_kernel(const char *str, struct pt_regs *regs, long err)
+extern void (*nmi_handler)(struct pt_regs *);
+void handle_nmi(struct pt_regs *regs)
 {
-	if (user_mode(regs))
-		return;
+#ifdef CONFIG_ETRAXFS
+	reg_intr_vect_r_nmi r;
+#endif
 
-#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
-	/*
-	 * This printout might take too long and could trigger
-	 * the watchdog normally. If NICE_DOGGY is set, simply
-	 * stop the watchdog during the printout.
-	 */
-	stop_watchdog();
+	if (nmi_handler)
+		nmi_handler(regs);
+
+#ifdef CONFIG_ETRAXFS
+	/* Wait until nmi is no longer active. */
+	do {
+		r = REG_RD(intr_vect, regi_irq, r_nmi);
+	} while (r.ext == regk_intr_vect_on);
 #endif
+}
 
-	raw_printk("%s: %04lx\n", str, err & 0xffff);
 
-	show_registers(regs);
+#ifdef CONFIG_BUG
+extern void die_if_kernel(const char *str, struct pt_regs *regs, long err);
 
-#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
-	reset_watchdog();
-#endif
+/* Copy of the regs at BUG() time.  */
+struct pt_regs BUG_regs;
 
-	do_exit(SIGSEGV);
+void do_BUG(char *file, unsigned int line)
+{
+	printk("kernel BUG at %s:%d!\n", file, line);
+	die_if_kernel("Oops", &BUG_regs, 0);
 }
+EXPORT_SYMBOL(do_BUG);
 
-void arch_enable_nmi(void)
+void fixup_BUG(struct pt_regs *regs)
 {
-	unsigned long flags;
-	local_save_flags(flags);
-	flags |= (1<<30); /* NMI M flag is at bit 30 */
-	local_irq_restore(flags);
+	BUG_regs = *regs;
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+	/*
+	 * Fixup the BUG arguments through exception handlers.
+	 */
+	{
+		const struct exception_table_entry *fixup;
+
+		/*
+		 * ERP points at the "break 14" + 2, compensate for the 2
+		 * bytes.
+		 */
+		fixup = search_exception_tables(instruction_pointer(regs) - 2);
+		if (fixup) {
+			/* Adjust the instruction pointer in the stackframe. */
+			instruction_pointer(regs) = fixup->fixup;
+			arch_fixup(regs);
+		}
+	}
+#else
+	/* Dont try to lookup the filename + line, just dump regs.  */
+	do_BUG("unknown", 0);
+#endif
 }
+
+/*
+ * Break 14 handler. Save regs and jump into the fixup_BUG.
+ */
+__asm__  ( ".text\n\t"
+	   ".global breakh_BUG\n\t"
+	   "breakh_BUG:\n\t"
+	   SAVE_ALL
+	   KGDB_FIXUP
+	   "move.d $sp, $r10\n\t"
+	   "jsr fixup_BUG\n\t"
+	   "nop\n\t"
+	   "jump ret_from_intr\n\t"
+	   "nop\n\t");
+
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+void
+handle_BUG(struct pt_regs *regs)
+{
+}
+#endif
+#endif
diff --git a/arch/cris/arch-v32/kernel/vcs_hook.c b/arch/cris/arch-v32/kernel/vcs_hook.c
deleted file mode 100644
index 64d71c54c22c..000000000000
--- a/arch/cris/arch-v32/kernel/vcs_hook.c
+++ /dev/null
@@ -1,96 +0,0 @@
-// $Id: vcs_hook.c,v 1.2 2003/08/12 12:01:06 starvik Exp $
-//
-// Call simulator hook. This is the part running in the
-// simulated program.
-//
-
-#include "vcs_hook.h"
-#include <stdarg.h>
-#include <asm/arch-v32/hwregs/reg_map.h>
-#include <asm/arch-v32/hwregs/intr_vect_defs.h>
-
-#define HOOK_TRIG_ADDR     0xb7000000   /* hook cvlog model reg address */
-#define HOOK_MEM_BASE_ADDR 0xa0000000   /* csp4 (shared mem) base addr */
-
-#define HOOK_DATA(offset) ((unsigned*) HOOK_MEM_BASE_ADDR)[offset]
-#define VHOOK_DATA(offset) ((volatile unsigned*) HOOK_MEM_BASE_ADDR)[offset]
-#define HOOK_TRIG(funcid) do { *((unsigned *) HOOK_TRIG_ADDR) = funcid; } while(0)
-#define HOOK_DATA_BYTE(offset) ((unsigned char*) HOOK_MEM_BASE_ADDR)[offset]
-
-
-// ------------------------------------------------------------------ hook_call
-int hook_call( unsigned id, unsigned pcnt, ...) {
-  va_list ap;
-  unsigned i;
-  unsigned ret;
-#ifdef USING_SOS
-  PREEMPT_OFF_SAVE();
-#endif
-
-  // pass parameters
-  HOOK_DATA(0) = id;
-
-  /* Have to make hook_print_str a special case since we call with a
-     parameter of byte type. Should perhaps be a separate
-     hook_call. */
-
-  if (id == hook_print_str) {
-    int i;
-    char *str;
-
-    HOOK_DATA(1) = pcnt;
-
-    va_start(ap, pcnt);
-    str = (char*)va_arg(ap,unsigned);
-
-    for (i=0; i!=pcnt; i++) {
-      HOOK_DATA_BYTE(8+i) = str[i];
-    }
-    HOOK_DATA_BYTE(8+i) = 0;	/* null byte */
-  }
-  else {
-    va_start(ap, pcnt);
-    for( i = 1; i <= pcnt; i++ ) HOOK_DATA(i) = va_arg(ap,unsigned);
-    va_end(ap);
-  }
-
-  // read from mem to make sure data has propagated to memory before trigging
-  *((volatile unsigned*) HOOK_MEM_BASE_ADDR);
-
-  // trigger hook
-  HOOK_TRIG(id);
-
-  // wait for call to finish
-  while( VHOOK_DATA(0) > 0 ) {}
-
-  // extract return value
-
-  ret = VHOOK_DATA(1);
-
-#ifdef USING_SOS
-  PREEMPT_RESTORE();
-#endif
-  return ret;
-}
-
-unsigned
-hook_buf(unsigned i)
-{
-  return (HOOK_DATA(i));
-}
-
-void print_str( const char *str ) {
-  int i;
-  for (i=1; str[i]; i++);         /* find null at end of string */
-  hook_call(hook_print_str, i, str);
-}
-
-// --------------------------------------------------------------- CPU_KICK_DOG
-void CPU_KICK_DOG(void) {
-  (void) hook_call( hook_kick_dog, 0 );
-}
-
-// ------------------------------------------------------- CPU_WATCHDOG_TIMEOUT
-void CPU_WATCHDOG_TIMEOUT( unsigned t ) {
-  (void) hook_call( hook_dog_timeout, 1, t );
-}
diff --git a/arch/cris/arch-v32/lib/Makefile b/arch/cris/arch-v32/lib/Makefile
index 05b3ec6978d6..eb4aad1f1158 100644
--- a/arch/cris/arch-v32/lib/Makefile
+++ b/arch/cris/arch-v32/lib/Makefile
@@ -2,5 +2,6 @@
 # Makefile for Etrax-specific library files..
 #
 
-lib-y  = checksum.o checksumcopy.o string.o usercopy.o memset.o csumcpfruser.o spinlock.o
+lib-y  = checksum.o checksumcopy.o string.o usercopy.o memset.o \
+	csumcpfruser.o spinlock.o delay.o
 
diff --git a/arch/cris/arch-v32/lib/checksum.S b/arch/cris/arch-v32/lib/checksum.S
index 32e66181b826..87f3fd71ab10 100644
--- a/arch/cris/arch-v32/lib/checksum.S
+++ b/arch/cris/arch-v32/lib/checksum.S
@@ -1,6 +1,6 @@
 /*
  * A fast checksum routine using movem
- * Copyright (c) 1998-2001, 2003 Axis Communications AB
+ * Copyright (c) 1998-2007 Axis Communications AB
  *
  * csum_partial(const unsigned char * buff, int len, unsigned int sum)
  */
@@ -12,30 +12,23 @@ csum_partial:
 	;; 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
+	;; Optimized for large packets
+	subq	10*4, $r11
+	blt	_word_loop
+	move.d	$r11, $acr
 
 	subq	9*4,$sp
-	subq	10*4,$r11	; update length for the first loop
+	clearf	c
 	movem	$r8,[$sp]
 
 	;; do a movem checksum
 
 _mloop:	movem	[$r10+],$r9	; read 10 longwords
-
+	;; Loop count without touching the c flag.
+	addoq	-10*4, $acr, $acr
 	;; perform dword checksumming on the 10 longwords
 
-	add.d	$r0,$r12
+	addc	$r0,$r12
 	addc	$r1,$r12
 	addc	$r2,$r12
 	addc	$r3,$r12
@@ -46,60 +39,41 @@ _mloop:	movem	[$r10+],$r9	; read 10 longwords
 	addc	$r8,$r12
 	addc	$r9,$r12
 
-	;; fold the carry into the checksum, to avoid having to loop the carry
-	;; back into the top
-
-	addc	0,$r12
-	addc	0,$r12		; do it again, since we might have generated a carry
-
-	subq	10*4,$r11
-	bge	_mloop
-	nop
-
-	addq	10*4,$r11	; compensate for last loop underflowing length
+	;; test $acr without trashing carry.
+	move.d	$acr, $acr
+	bpl	_mloop
+	;; r11 <= acr  is not really needed in the mloop, just using the dslot
+	;; to prepare for what is needed after mloop.
+	move.d	$acr, $r11
 
+	;; fold the last carry into r13
+	addc	0, $r12
 	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.
+	addq	10*4,$r11	; compensate for last loop underflowing length
 
 	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
+	and.d	$r9,$r12	; checksum = checksum & 0xffff
 
 _no_fold:
-	cmpq	2,$r11
+	subq	2,$r11
 	blt	_no_words
-	nop
+	add.d	$r13,$r12	; checksum += r13
 
 	;; checksum the rest of the words
-
-	subq	2,$r11
-
 _wloop:	subq	2,$r11
 	bge	_wloop
 	addu.w	[$r10+],$r12
 
-	addq	2,$r11
-
 _no_words:
+	addq	2,$r11
 	;; see if we have one odd byte more
-	cmpq	1,$r11
-	beq	_do_byte
+	bne	_do_byte
 	nop
 	ret
 	move.d	$r12,$r10
diff --git a/arch/cris/arch-v32/lib/checksumcopy.S b/arch/cris/arch-v32/lib/checksumcopy.S
index 9303ccbadc6d..21aabe91489b 100644
--- a/arch/cris/arch-v32/lib/checksumcopy.S
+++ b/arch/cris/arch-v32/lib/checksumcopy.S
@@ -1,6 +1,6 @@
 /*
  * A fast checksum+copy routine using movem
- * Copyright (c) 1998, 2001, 2003 Axis Communications AB
+ * Copyright (c) 1998-2007 Axis Communications AB
  *
  * Authors:	Bjorn Wesen
  *
@@ -16,32 +16,23 @@ csum_partial_copy_nocheck:
 	;; 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
+	;; Optimized for large packets
+	subq	10*4, $r12
+	blt	_word_loop
+	move.d	$r12, $acr
 
 	subq	9*4,$sp
-	subq	10*4,$r12	; update length for the first loop
+	clearf	c
 	movem	$r8,[$sp]
 
 	;; do a movem copy and checksum
-
 1:	;; A failing userspace access (the read) will have this as PC.
 _mloop:	movem	[$r10+],$r9	; read 10 longwords
+	addoq	-10*4, $acr, $acr ; loop counter in latency cycle
 	movem	$r9,[$r11+]	; write 10 longwords
 
 	;; perform dword checksumming on the 10 longwords
-
-	add.d	$r0,$r13
+	addc	$r0,$r13
 	addc	$r1,$r13
 	addc	$r2,$r13
 	addc	$r3,$r13
@@ -52,47 +43,30 @@ _mloop:	movem	[$r10+],$r9	; read 10 longwords
 	addc	$r8,$r13
 	addc	$r9,$r13
 
-	;; fold the carry into the checksum, to avoid having to loop the carry
-	;; back into the top
-
-	addc	0,$r13
-	addc	0,$r13		; do it again, since we might have generated a carry
-
-	subq	10*4,$r12
-	bge	_mloop
-	nop
-
-	addq	10*4,$r12	; compensate for last loop underflowing length
+	;; test $acr, without trashing carry.
+	move.d	$acr, $acr
+	bpl	_mloop
+	;; r12 <= acr  is needed after mloop and in the exception handlers.
+	move.d	$acr, $r12
 
+	;; fold the last carry into r13
+	addc	0, $r13
 	movem	[$sp+],$r8	; restore regs
 
 _word_loop:
-	;; only fold if there is anything to fold.
-
-	cmpq	0,$r13
-	beq	_no_fold
+	addq	10*4,$r12	; compensate for last loop underflowing length
 
 	;; 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
+	subq	2, $r12
 	blt	_no_words
-	nop
+	add.d	$r9,$r13	; checksum += r0
 
 	;; copy and checksum the rest of the words
-
-	subq	2,$r12
-
 2:	;; A failing userspace access for the read below will have this as PC.
 _wloop:	move.w	[$r10+],$r9
 	addu.w	$r9,$r13
@@ -100,12 +74,9 @@ _wloop:	move.w	[$r10+],$r9
 	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
+	addq	2,$r12
+	bne	_do_byte
 	nop
 	ret
 	move.d	$r13,$r10
diff --git a/arch/cris/arch-v32/lib/delay.c b/arch/cris/arch-v32/lib/delay.c
new file mode 100644
index 000000000000..39f1ac9995b4
--- /dev/null
+++ b/arch/cris/arch-v32/lib/delay.c
@@ -0,0 +1,28 @@
+/*
+ * Precise Delay Loops for ETRAX FS
+ *
+ * Copyright (C) 2006 Axis Communications AB.
+ *
+ */
+
+#include <hwregs/reg_map.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/timer_defs.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+/*
+ * On ETRAX FS, we can check the free-running read-only 100MHz timer
+ * getting 32-bit 10ns precision, theoretically good for 42.94967295
+ * seconds.  Unsigned arithmetic and careful expression handles
+ * wrapping.
+ */
+
+void cris_delay10ns(u32 n10ns)
+{
+	u32 t0 = REG_RD(timer, regi_timer0, r_time);
+	while (REG_RD(timer, regi_timer0, r_time) - t0 < n10ns)
+		;
+}
+EXPORT_SYMBOL(cris_delay10ns);
diff --git a/arch/cris/arch-v32/lib/spinlock.S b/arch/cris/arch-v32/lib/spinlock.S
index 2437ae7f6ed2..79087ef59a1c 100644
--- a/arch/cris/arch-v32/lib/spinlock.S
+++ b/arch/cris/arch-v32/lib/spinlock.S
@@ -12,11 +12,11 @@
 
 cris_spin_lock:
 	clearf	p
-1:	test.d	[$r10]
+1:	test.b	[$r10]
 	beq	1b
 	clearf	p
 	ax
-	clear.d [$r10]
+	clear.b [$r10]
 	bcs     1b
 	clearf	p
 	ret
@@ -24,10 +24,10 @@ cris_spin_lock:
 
 cris_spin_trylock:
 	clearf	p
-1:	move.d	[$r10], $r11
+1:	move.b	[$r10], $r11
 	ax
-	clear.d [$r10]
+	clear.b [$r10]
         bcs	1b
         clearf	p
 	ret
-	move.d	$r11,$r10
+	movu.b	$r11,$r10
diff --git a/arch/cris/arch-v32/mach-a3/Kconfig b/arch/cris/arch-v32/mach-a3/Kconfig
new file mode 100644
index 000000000000..a4df06d5997a
--- /dev/null
+++ b/arch/cris/arch-v32/mach-a3/Kconfig
@@ -0,0 +1,110 @@
+if CRIS_MACH_ARTPEC3
+
+menu "Artpec-3 options"
+       depends on CRIS_MACH_ARTPEC3
+
+config ETRAX_DRAM_VIRTUAL_BASE
+	hex
+	default "c0000000"
+
+config ETRAX_L2CACHE
+       bool
+       default y
+
+config ETRAX_SERIAL_PORTS
+       int
+       default 5
+
+config ETRAX_DDR
+       bool
+       default y
+
+config ETRAX_DDR2_MRS
+	hex "DDR2 MRS"
+	default "0"
+
+config ETRAX_DDR2_TIMING
+	hex "DDR2 SDRAM timing"
+	default "0"
+	help
+	  SDRAM timing parameters.
+
+config ETRAX_DDR2_CONFIG
+	hex "DDR2 config"
+	default "0"
+
+config ETRAX_PIO_CE0_CFG
+       hex "PIO CE0 configuration"
+       default "0"
+
+config ETRAX_PIO_CE1_CFG
+       hex "PIO CE1 configuration"
+       default "0"
+
+config ETRAX_PIO_CE2_CFG
+       hex "PIO CE2 configuration"
+       default "0"
+
+config ETRAX_DEF_GIO_PA_OE
+	hex "GIO_PA_OE"
+	default "00000000"
+	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_GIO_PA_OUT
+	hex "GIO_PA_OUT"
+	default "00000000"
+	help
+	  Configures the initial data for the general port A bits.  Most
+	  products should use 00 here.
+
+config ETRAX_DEF_GIO_PB_OE
+	hex "GIO_PB_OE"
+	default "000000000"
+	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.
+	  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_GIO_PB_OUT
+	hex "GIO_PB_OUT"
+	default "000000000"
+	help
+	  Configures the initial data for the general port B bits.  Most
+	  products should use 00000 here.
+
+config ETRAX_DEF_GIO_PC_OE
+	hex "GIO_PC_OE"
+	default "00000"
+	help
+	  Configures the direction of general port C 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_GIO_PC_OUT
+	hex "GIO_PC_OUT"
+	default "00000"
+	help
+	  Configures the initial data for the general port C bits.  Most
+	  products should use 00000 here.
+
+endmenu
+
+endif
diff --git a/arch/cris/arch-v32/mach-a3/Makefile b/arch/cris/arch-v32/mach-a3/Makefile
new file mode 100644
index 000000000000..41fa6a6893a9
--- /dev/null
+++ b/arch/cris/arch-v32/mach-a3/Makefile
@@ -0,0 +1,11 @@
+# $Id: Makefile,v 1.3 2007/03/13 11:57:46 starvik Exp $
+#
+# Makefile for the linux kernel.
+#
+
+obj-y   := dma.o pinmux.o io.o arbiter.o
+obj-$(CONFIG_ETRAX_VCS_SIM) += vcs_hook.o
+obj-$(CONFIG_CPU_FREQ)   += cpufreq.o
+
+clean:
+
diff --git a/arch/cris/arch-v32/mach-a3/arbiter.c b/arch/cris/arch-v32/mach-a3/arbiter.c
new file mode 100644
index 000000000000..8b924db71c9a
--- /dev/null
+++ b/arch/cris/arch-v32/mach-a3/arbiter.c
@@ -0,0 +1,634 @@
+/*
+ * Memory arbiter functions. Allocates bandwidth through the
+ * arbiter and sets up arbiter breakpoints.
+ *
+ * The algorithm first assigns slots to the clients that has specified
+ * bandwidth (e.g. ethernet) and then the remaining slots are divided
+ * on all the active clients.
+ *
+ * Copyright (c) 2004-2007 Axis Communications AB.
+ *
+ * The artpec-3 has two arbiters. The memory hierarchy looks like this:
+ *
+ *
+ * CPU DMAs
+ *  |   |
+ *  |   |
+ * --------------    ------------------
+ * | foo arbiter|----| Internal memory|
+ * --------------    ------------------
+ *      |
+ * --------------
+ * | L2 cache   |
+ * --------------
+ *             |
+ * h264 etc    |
+ *    |        |
+ *    |        |
+ * --------------
+ * | bar arbiter|
+ * --------------
+ *       |
+ * ---------
+ * | SDRAM |
+ * ---------
+ *
+ */
+
+#include <hwregs/reg_map.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/marb_foo_defs.h>
+#include <hwregs/marb_bar_defs.h>
+#include <arbiter.h>
+#include <hwregs/intr_vect.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
+#include <asm/irq_regs.h>
+
+#define D(x)
+
+struct crisv32_watch_entry {
+  unsigned long instance;
+  watch_callback *cb;
+  unsigned long start;
+  unsigned long end;
+  int used;
+};
+
+#define NUMBER_OF_BP 4
+#define SDRAM_BANDWIDTH 400000000
+#define INTMEM_BANDWIDTH 400000000
+#define NBR_OF_SLOTS 64
+#define NBR_OF_REGIONS 2
+#define NBR_OF_CLIENTS 15
+#define ARBITERS 2
+#define UNASSIGNED 100
+
+struct arbiter {
+  unsigned long instance;
+  int nbr_regions;
+  int nbr_clients;
+  int requested_slots[NBR_OF_REGIONS][NBR_OF_CLIENTS];
+  int active_clients[NBR_OF_REGIONS][NBR_OF_CLIENTS];
+};
+
+static struct crisv32_watch_entry watches[ARBITERS][NUMBER_OF_BP] =
+{
+  {
+  {regi_marb_foo_bp0},
+  {regi_marb_foo_bp1},
+  {regi_marb_foo_bp2},
+  {regi_marb_foo_bp3}
+  },
+  {
+  {regi_marb_bar_bp0},
+  {regi_marb_bar_bp1},
+  {regi_marb_bar_bp2},
+  {regi_marb_bar_bp3}
+  }
+};
+
+struct arbiter arbiters[ARBITERS] =
+{
+  { /* L2 cache arbiter */
+    .instance = regi_marb_foo,
+    .nbr_regions = 2,
+    .nbr_clients = 15
+  },
+  { /* DDR2 arbiter */
+    .instance = regi_marb_bar,
+    .nbr_regions = 1,
+    .nbr_clients = 9
+  }
+};
+
+static int max_bandwidth[NBR_OF_REGIONS] = {SDRAM_BANDWIDTH, INTMEM_BANDWIDTH};
+
+DEFINE_SPINLOCK(arbiter_lock);
+
+static irqreturn_t
+crisv32_foo_arbiter_irq(int irq, void *dev_id);
+static irqreturn_t
+crisv32_bar_arbiter_irq(int irq, void *dev_id);
+
+/*
+ * "I'm the arbiter, I know the score.
+ *  From square one I'll be watching all 64."
+ * (memory arbiter slots, that is)
+ *
+ *  Or in other words:
+ * Program the memory arbiter slots for "region" according to what's
+ * in requested_slots[] and active_clients[], while minimizing
+ * latency. A caller may pass a non-zero positive amount for
+ * "unused_slots", which must then be the unallocated, remaining
+ * number of slots, free to hand out to any client.
+ */
+
+static void crisv32_arbiter_config(int arbiter, int region, int unused_slots)
+{
+	int slot;
+	int client;
+	int interval = 0;
+
+	/*
+	 * This vector corresponds to the hardware arbiter slots (see
+	 * the hardware documentation for semantics). We initialize
+	 * each slot with a suitable sentinel value outside the valid
+	 * range {0 .. NBR_OF_CLIENTS - 1} and replace them with
+	 * client indexes. Then it's fed to the hardware.
+	 */
+	s8 val[NBR_OF_SLOTS];
+
+	for (slot = 0; slot < NBR_OF_SLOTS; slot++)
+	    val[slot] = -1;
+
+	for (client = 0; client < arbiters[arbiter].nbr_clients; client++) {
+	    int pos;
+	    /* Allocate the requested non-zero number of slots, but
+	     * also give clients with zero-requests one slot each
+	     * while stocks last. We do the latter here, in client
+	     * order. This makes sure zero-request clients are the
+	     * first to get to any spare slots, else those slots
+	     * could, when bandwidth is allocated close to the limit,
+	     * all be allocated to low-index non-zero-request clients
+	     * in the default-fill loop below. Another positive but
+	     * secondary effect is a somewhat better spread of the
+	     * zero-bandwidth clients in the vector, avoiding some of
+	     * the latency that could otherwise be caused by the
+	     * partitioning of non-zero-bandwidth clients at low
+	     * indexes and zero-bandwidth clients at high
+	     * indexes. (Note that this spreading can only affect the
+	     * unallocated bandwidth.)  All the above only matters for
+	     * memory-intensive situations, of course.
+	     */
+	    if (!arbiters[arbiter].requested_slots[region][client]) {
+		/*
+		 * Skip inactive clients. Also skip zero-slot
+		 * allocations in this pass when there are no known
+		 * free slots.
+		 */
+		if (!arbiters[arbiter].active_clients[region][client] ||
+				unused_slots <= 0)
+			continue;
+
+		unused_slots--;
+
+		/* Only allocate one slot for this client. */
+		interval = NBR_OF_SLOTS;
+	    } else
+		interval = NBR_OF_SLOTS /
+			arbiters[arbiter].requested_slots[region][client];
+
+	    pos = 0;
+	    while (pos < NBR_OF_SLOTS) {
+		if (val[pos] >= 0)
+		   pos++;
+		else {
+			val[pos] = client;
+			pos += interval;
+		}
+	    }
+	}
+
+	client = 0;
+	for (slot = 0; slot < NBR_OF_SLOTS; slot++) {
+		/*
+		 * Allocate remaining slots in round-robin
+		 * client-number order for active clients. For this
+		 * pass, we ignore requested bandwidth and previous
+		 * allocations.
+		 */
+		if (val[slot] < 0) {
+			int first = client;
+			while (!arbiters[arbiter].active_clients[region][client]) {
+				client = (client + 1) %
+					arbiters[arbiter].nbr_clients;
+				if (client == first)
+				   break;
+			}
+			val[slot] = client;
+			client = (client + 1) % arbiters[arbiter].nbr_clients;
+		}
+		if (arbiter == 0) {
+			if (region == EXT_REGION)
+				REG_WR_INT_VECT(marb_foo, regi_marb_foo,
+					rw_l2_slots, slot, val[slot]);
+			else if (region == INT_REGION)
+				REG_WR_INT_VECT(marb_foo, regi_marb_foo,
+					rw_intm_slots, slot, val[slot]);
+		} else {
+			REG_WR_INT_VECT(marb_bar, regi_marb_bar,
+				rw_ddr2_slots, slot, val[slot]);
+		}
+	}
+}
+
+extern char _stext, _etext;
+
+static void crisv32_arbiter_init(void)
+{
+	static int initialized;
+
+	if (initialized)
+		return;
+
+	initialized = 1;
+
+	/*
+	 * CPU caches are always set to active, but with zero
+	 * bandwidth allocated. It should be ok to allocate zero
+	 * bandwidth for the caches, because DMA for other channels
+	 * will supposedly finish, once their programmed amount is
+	 * done, and then the caches will get access according to the
+	 * "fixed scheme" for unclaimed slots. Though, if for some
+	 * use-case somewhere, there's a maximum CPU latency for
+	 * e.g. some interrupt, we have to start allocating specific
+	 * bandwidth for the CPU caches too.
+	 */
+	arbiters[0].active_clients[EXT_REGION][11] = 1;
+	arbiters[0].active_clients[EXT_REGION][12] = 1;
+	crisv32_arbiter_config(0, EXT_REGION, 0);
+	crisv32_arbiter_config(0, INT_REGION, 0);
+	crisv32_arbiter_config(1, EXT_REGION, 0);
+
+	if (request_irq(MEMARB_FOO_INTR_VECT, crisv32_foo_arbiter_irq,
+			IRQF_DISABLED, "arbiter", NULL))
+		printk(KERN_ERR "Couldn't allocate arbiter IRQ\n");
+
+	if (request_irq(MEMARB_BAR_INTR_VECT, crisv32_bar_arbiter_irq,
+			IRQF_DISABLED, "arbiter", NULL))
+		printk(KERN_ERR "Couldn't allocate arbiter IRQ\n");
+
+#ifndef CONFIG_ETRAX_KGDB
+	/* Global watch for writes to kernel text segment. */
+	crisv32_arbiter_watch(virt_to_phys(&_stext), &_etext - &_stext,
+		MARB_CLIENTS(arbiter_all_clients, arbiter_bar_all_clients),
+			      arbiter_all_write, NULL);
+#endif
+
+	/* Set up max burst sizes by default */
+	REG_WR_INT(marb_bar, regi_marb_bar, rw_h264_rd_burst, 3);
+	REG_WR_INT(marb_bar, regi_marb_bar, rw_h264_wr_burst, 3);
+	REG_WR_INT(marb_bar, regi_marb_bar, rw_ccd_burst, 3);
+	REG_WR_INT(marb_bar, regi_marb_bar, rw_vin_wr_burst, 3);
+	REG_WR_INT(marb_bar, regi_marb_bar, rw_vin_rd_burst, 3);
+	REG_WR_INT(marb_bar, regi_marb_bar, rw_sclr_rd_burst, 3);
+	REG_WR_INT(marb_bar, regi_marb_bar, rw_vout_burst, 3);
+	REG_WR_INT(marb_bar, regi_marb_bar, rw_sclr_fifo_burst, 3);
+	REG_WR_INT(marb_bar, regi_marb_bar, rw_l2cache_burst, 3);
+}
+
+int crisv32_arbiter_allocate_bandwidth(int client, int region,
+				      unsigned long bandwidth)
+{
+	int i;
+	int total_assigned = 0;
+	int total_clients = 0;
+	int req;
+	int arbiter = 0;
+
+	crisv32_arbiter_init();
+
+	if (client & 0xffff0000) {
+		arbiter = 1;
+		client >>= 16;
+	}
+
+	for (i = 0; i < arbiters[arbiter].nbr_clients; i++) {
+		total_assigned += arbiters[arbiter].requested_slots[region][i];
+		total_clients += arbiters[arbiter].active_clients[region][i];
+	}
+
+	/* Avoid division by 0 for 0-bandwidth requests. */
+	req = bandwidth == 0
+		? 0 : NBR_OF_SLOTS / (max_bandwidth[region] / bandwidth);
+
+	/*
+	 * We make sure that there are enough slots only for non-zero
+	 * requests. Requesting 0 bandwidth *may* allocate slots,
+	 * though if all bandwidth is allocated, such a client won't
+	 * get any and will have to rely on getting memory access
+	 * according to the fixed scheme that's the default when one
+	 * of the slot-allocated clients doesn't claim their slot.
+	 */
+	if (total_assigned + req > NBR_OF_SLOTS)
+	   return -ENOMEM;
+
+	arbiters[arbiter].active_clients[region][client] = 1;
+	arbiters[arbiter].requested_slots[region][client] = req;
+	crisv32_arbiter_config(arbiter, region, NBR_OF_SLOTS - total_assigned);
+
+	/* Propagate allocation from foo to bar */
+	if (arbiter == 0)
+		crisv32_arbiter_allocate_bandwidth(8 << 16,
+			EXT_REGION, bandwidth);
+	return 0;
+}
+
+/*
+ * Main entry for bandwidth deallocation.
+ *
+ * Strictly speaking, for a somewhat constant set of clients where
+ * each client gets a constant bandwidth and is just enabled or
+ * disabled (somewhat dynamically), no action is necessary here to
+ * avoid starvation for non-zero-allocation clients, as the allocated
+ * slots will just be unused. However, handing out those unused slots
+ * to active clients avoids needless latency if the "fixed scheme"
+ * would give unclaimed slots to an eager low-index client.
+ */
+
+void crisv32_arbiter_deallocate_bandwidth(int client, int region)
+{
+	int i;
+	int total_assigned = 0;
+	int arbiter = 0;
+
+	if (client & 0xffff0000)
+		arbiter = 1;
+
+	arbiters[arbiter].requested_slots[region][client] = 0;
+	arbiters[arbiter].active_clients[region][client] = 0;
+
+	for (i = 0; i < arbiters[arbiter].nbr_clients; i++)
+		total_assigned += arbiters[arbiter].requested_slots[region][i];
+
+	crisv32_arbiter_config(arbiter, region, NBR_OF_SLOTS - total_assigned);
+}
+
+int crisv32_arbiter_watch(unsigned long start, unsigned long size,
+			  unsigned long clients, unsigned long accesses,
+			  watch_callback *cb)
+{
+	int i;
+	int arbiter;
+	int used[2];
+	int ret = 0;
+
+	crisv32_arbiter_init();
+
+	if (start > 0x80000000) {
+		printk(KERN_ERR "Arbiter: %lX doesn't look like a "
+			"physical address", start);
+		return -EFAULT;
+	}
+
+	spin_lock(&arbiter_lock);
+
+	if (clients & 0xffff)
+		used[0] = 1;
+	if (clients & 0xffff0000)
+		used[1] = 1;
+
+	for (arbiter = 0; arbiter < ARBITERS; arbiter++) {
+		if (!used[arbiter])
+			continue;
+
+		for (i = 0; i < NUMBER_OF_BP; i++) {
+			if (!watches[arbiter][i].used) {
+				unsigned intr_mask;
+				if (arbiter)
+					intr_mask = REG_RD_INT(marb_bar,
+						regi_marb_bar, rw_intr_mask);
+				else
+					intr_mask = REG_RD_INT(marb_foo,
+						regi_marb_foo, rw_intr_mask);
+
+				watches[arbiter][i].used = 1;
+				watches[arbiter][i].start = start;
+				watches[arbiter][i].end = start + size;
+				watches[arbiter][i].cb = cb;
+
+				ret |= (i + 1) << (arbiter + 8);
+				if (arbiter) {
+					REG_WR_INT(marb_bar_bp,
+						watches[arbiter][i].instance,
+						rw_first_addr,
+						watches[arbiter][i].start);
+					REG_WR_INT(marb_bar_bp,
+						watches[arbiter][i].instance,
+						rw_last_addr,
+						watches[arbiter][i].end);
+					REG_WR_INT(marb_bar_bp,
+						watches[arbiter][i].instance,
+						rw_op, accesses);
+					REG_WR_INT(marb_bar_bp,
+						watches[arbiter][i].instance,
+						rw_clients,
+						clients & 0xffff);
+				} else {
+					REG_WR_INT(marb_foo_bp,
+						watches[arbiter][i].instance,
+						rw_first_addr,
+						watches[arbiter][i].start);
+					REG_WR_INT(marb_foo_bp,
+						watches[arbiter][i].instance,
+						rw_last_addr,
+						watches[arbiter][i].end);
+					REG_WR_INT(marb_foo_bp,
+						watches[arbiter][i].instance,
+						rw_op, accesses);
+					REG_WR_INT(marb_foo_bp,
+						watches[arbiter][i].instance,
+						rw_clients, clients >> 16);
+				}
+
+				if (i == 0)
+					intr_mask |= 1;
+				else if (i == 1)
+					intr_mask |= 2;
+				else if (i == 2)
+					intr_mask |= 4;
+				else if (i == 3)
+					intr_mask |= 8;
+
+				if (arbiter)
+					REG_WR_INT(marb_bar, regi_marb_bar,
+						rw_intr_mask, intr_mask);
+				else
+					REG_WR_INT(marb_foo, regi_marb_foo,
+						rw_intr_mask, intr_mask);
+
+				spin_unlock(&arbiter_lock);
+
+				break;
+			}
+		}
+	}
+	spin_unlock(&arbiter_lock);
+	if (ret)
+		return ret;
+	else
+		return -ENOMEM;
+}
+
+int crisv32_arbiter_unwatch(int id)
+{
+	int arbiter;
+	int intr_mask;
+
+	crisv32_arbiter_init();
+
+	spin_lock(&arbiter_lock);
+
+	for (arbiter = 0; arbiter < ARBITERS; arbiter++) {
+		int id2;
+
+		if (arbiter)
+			intr_mask = REG_RD_INT(marb_bar, regi_marb_bar,
+				rw_intr_mask);
+		else
+			intr_mask = REG_RD_INT(marb_foo, regi_marb_foo,
+				rw_intr_mask);
+
+		id2 = (id & (0xff << (arbiter + 8))) >> (arbiter + 8);
+		if (id2 == 0)
+			continue;
+		id2--;
+		if ((id2 >= NUMBER_OF_BP) || (!watches[arbiter][id2].used)) {
+			spin_unlock(&arbiter_lock);
+			return -EINVAL;
+		}
+
+		memset(&watches[arbiter][id2], 0,
+			sizeof(struct crisv32_watch_entry));
+
+		if (id2 == 0)
+			intr_mask &= ~1;
+		else if (id2 == 1)
+			intr_mask &= ~2;
+		else if (id2 == 2)
+			intr_mask &= ~4;
+		else if (id2 == 3)
+			intr_mask &= ~8;
+
+		if (arbiter)
+			REG_WR_INT(marb_bar, regi_marb_bar, rw_intr_mask,
+				intr_mask);
+		else
+			REG_WR_INT(marb_foo, regi_marb_foo, rw_intr_mask,
+				intr_mask);
+	}
+
+	spin_unlock(&arbiter_lock);
+	return 0;
+}
+
+extern void show_registers(struct pt_regs *regs);
+
+
+static irqreturn_t
+crisv32_foo_arbiter_irq(int irq, void *dev_id)
+{
+	reg_marb_foo_r_masked_intr masked_intr =
+		REG_RD(marb_foo, regi_marb_foo, r_masked_intr);
+	reg_marb_foo_bp_r_brk_clients r_clients;
+	reg_marb_foo_bp_r_brk_addr r_addr;
+	reg_marb_foo_bp_r_brk_op r_op;
+	reg_marb_foo_bp_r_brk_first_client r_first;
+	reg_marb_foo_bp_r_brk_size r_size;
+	reg_marb_foo_bp_rw_ack ack = {0};
+	reg_marb_foo_rw_ack_intr ack_intr = {
+		.bp0 = 1, .bp1 = 1, .bp2 = 1, .bp3 = 1
+	};
+	struct crisv32_watch_entry *watch;
+	unsigned arbiter = (unsigned)dev_id;
+
+	masked_intr = REG_RD(marb_foo, regi_marb_foo, r_masked_intr);
+
+	if (masked_intr.bp0)
+		watch = &watches[arbiter][0];
+	else if (masked_intr.bp1)
+		watch = &watches[arbiter][1];
+	else if (masked_intr.bp2)
+		watch = &watches[arbiter][2];
+	else if (masked_intr.bp3)
+		watch = &watches[arbiter][3];
+	else
+		return IRQ_NONE;
+
+	/* Retrieve all useful information and print it. */
+	r_clients = REG_RD(marb_foo_bp, watch->instance, r_brk_clients);
+	r_addr = REG_RD(marb_foo_bp, watch->instance, r_brk_addr);
+	r_op = REG_RD(marb_foo_bp, watch->instance, r_brk_op);
+	r_first = REG_RD(marb_foo_bp, watch->instance, r_brk_first_client);
+	r_size = REG_RD(marb_foo_bp, watch->instance, r_brk_size);
+
+	printk(KERN_DEBUG "Arbiter IRQ\n");
+	printk(KERN_DEBUG "Clients %X addr %X op %X first %X size %X\n",
+	       REG_TYPE_CONV(int, reg_marb_foo_bp_r_brk_clients, r_clients),
+	       REG_TYPE_CONV(int, reg_marb_foo_bp_r_brk_addr, r_addr),
+	       REG_TYPE_CONV(int, reg_marb_foo_bp_r_brk_op, r_op),
+	       REG_TYPE_CONV(int, reg_marb_foo_bp_r_brk_first_client, r_first),
+	       REG_TYPE_CONV(int, reg_marb_foo_bp_r_brk_size, r_size));
+
+	REG_WR(marb_foo_bp, watch->instance, rw_ack, ack);
+	REG_WR(marb_foo, regi_marb_foo, rw_ack_intr, ack_intr);
+
+	printk(KERN_DEBUG "IRQ occured at %X\n", (unsigned)get_irq_regs());
+
+	if (watch->cb)
+		watch->cb();
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t
+crisv32_bar_arbiter_irq(int irq, void *dev_id)
+{
+	reg_marb_bar_r_masked_intr masked_intr =
+		REG_RD(marb_bar, regi_marb_bar, r_masked_intr);
+	reg_marb_bar_bp_r_brk_clients r_clients;
+	reg_marb_bar_bp_r_brk_addr r_addr;
+	reg_marb_bar_bp_r_brk_op r_op;
+	reg_marb_bar_bp_r_brk_first_client r_first;
+	reg_marb_bar_bp_r_brk_size r_size;
+	reg_marb_bar_bp_rw_ack ack = {0};
+	reg_marb_bar_rw_ack_intr ack_intr = {
+		.bp0 = 1, .bp1 = 1, .bp2 = 1, .bp3 = 1
+	};
+	struct crisv32_watch_entry *watch;
+	unsigned arbiter = (unsigned)dev_id;
+
+	masked_intr = REG_RD(marb_bar, regi_marb_bar, r_masked_intr);
+
+	if (masked_intr.bp0)
+		watch = &watches[arbiter][0];
+	else if (masked_intr.bp1)
+		watch = &watches[arbiter][1];
+	else if (masked_intr.bp2)
+		watch = &watches[arbiter][2];
+	else if (masked_intr.bp3)
+		watch = &watches[arbiter][3];
+	else
+		return IRQ_NONE;
+
+	/* Retrieve all useful information and print it. */
+	r_clients = REG_RD(marb_bar_bp, watch->instance, r_brk_clients);
+	r_addr = REG_RD(marb_bar_bp, watch->instance, r_brk_addr);
+	r_op = REG_RD(marb_bar_bp, watch->instance, r_brk_op);
+	r_first = REG_RD(marb_bar_bp, watch->instance, r_brk_first_client);
+	r_size = REG_RD(marb_bar_bp, watch->instance, r_brk_size);
+
+	printk(KERN_DEBUG "Arbiter IRQ\n");
+	printk(KERN_DEBUG "Clients %X addr %X op %X first %X size %X\n",
+	       REG_TYPE_CONV(int, reg_marb_bar_bp_r_brk_clients, r_clients),
+	       REG_TYPE_CONV(int, reg_marb_bar_bp_r_brk_addr, r_addr),
+	       REG_TYPE_CONV(int, reg_marb_bar_bp_r_brk_op, r_op),
+	       REG_TYPE_CONV(int, reg_marb_bar_bp_r_brk_first_client, r_first),
+	       REG_TYPE_CONV(int, reg_marb_bar_bp_r_brk_size, r_size));
+
+	REG_WR(marb_bar_bp, watch->instance, rw_ack, ack);
+	REG_WR(marb_bar, regi_marb_bar, rw_ack_intr, ack_intr);
+
+	printk(KERN_DEBUG "IRQ occured at %X\n", (unsigned)get_irq_regs()->erp);
+
+	if (watch->cb)
+		watch->cb();
+
+	return IRQ_HANDLED;
+}
+
diff --git a/arch/cris/arch-v32/mach-a3/cpufreq.c b/arch/cris/arch-v32/mach-a3/cpufreq.c
new file mode 100644
index 000000000000..8e5a3cab8ad7
--- /dev/null
+++ b/arch/cris/arch-v32/mach-a3/cpufreq.c
@@ -0,0 +1,153 @@
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/cpufreq.h>
+#include <hwregs/reg_map.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/clkgen_defs.h>
+#include <hwregs/ddr2_defs.h>
+
+static int
+cris_sdram_freq_notifier(struct notifier_block *nb, unsigned long val,
+	void *data);
+
+static struct notifier_block cris_sdram_freq_notifier_block = {
+	.notifier_call = cris_sdram_freq_notifier
+};
+
+static struct cpufreq_frequency_table cris_freq_table[] = {
+	{0x01,	6000},
+	{0x02,	200000},
+	{0,	CPUFREQ_TABLE_END},
+};
+
+static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu)
+{
+	reg_clkgen_rw_clk_ctrl clk_ctrl;
+	clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl);
+	return clk_ctrl.pll ? 200000 : 6000;
+}
+
+static void cris_freq_set_cpu_state(unsigned int state)
+{
+	int i = 0;
+	struct cpufreq_freqs freqs;
+	reg_clkgen_rw_clk_ctrl clk_ctrl;
+	clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl);
+
+#ifdef CONFIG_SMP
+	for_each_present_cpu(i)
+#endif
+	{
+		freqs.old = cris_freq_get_cpu_frequency(i);
+		freqs.new = cris_freq_table[state].frequency;
+		freqs.cpu = i;
+	}
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	local_irq_disable();
+
+	/* Even though we may be SMP they will share the same clock
+	 * so all settings are made on CPU0. */
+	if (cris_freq_table[state].frequency == 200000)
+		clk_ctrl.pll = 1;
+	else
+		clk_ctrl.pll = 0;
+	REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, clk_ctrl);
+
+	local_irq_enable();
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+};
+
+static int cris_freq_verify(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, &cris_freq_table[0]);
+}
+
+static int cris_freq_target(struct cpufreq_policy *policy,
+			    unsigned int target_freq,
+			    unsigned int relation)
+{
+	unsigned int newstate = 0;
+
+	if (cpufreq_frequency_table_target(policy, cris_freq_table,
+			target_freq, relation, &newstate))
+		return -EINVAL;
+
+	cris_freq_set_cpu_state(newstate);
+
+	return 0;
+}
+
+static int cris_freq_cpu_init(struct cpufreq_policy *policy)
+{
+	int result;
+
+	/* cpuinfo and default policy values */
+	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+	policy->cpuinfo.transition_latency = 1000000; /* 1ms */
+	policy->cur = cris_freq_get_cpu_frequency(0);
+
+	result = cpufreq_frequency_table_cpuinfo(policy, cris_freq_table);
+	if (result)
+		return (result);
+
+	cpufreq_frequency_table_get_attr(cris_freq_table, policy->cpu);
+
+	return 0;
+}
+
+
+static int cris_freq_cpu_exit(struct cpufreq_policy *policy)
+{
+	cpufreq_frequency_table_put_attr(policy->cpu);
+	return 0;
+}
+
+
+static struct freq_attr *cris_freq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver cris_freq_driver = {
+	.get	= cris_freq_get_cpu_frequency,
+	.verify	= cris_freq_verify,
+	.target	= cris_freq_target,
+	.init	= cris_freq_cpu_init,
+	.exit	= cris_freq_cpu_exit,
+	.name	= "cris_freq",
+	.owner	= THIS_MODULE,
+	.attr	= cris_freq_attr,
+};
+
+static int __init cris_freq_init(void)
+{
+	int ret;
+	ret = cpufreq_register_driver(&cris_freq_driver);
+	cpufreq_register_notifier(&cris_sdram_freq_notifier_block,
+		CPUFREQ_TRANSITION_NOTIFIER);
+	return ret;
+}
+
+static int
+cris_sdram_freq_notifier(struct notifier_block *nb, unsigned long val,
+	void *data)
+{
+	int i;
+	struct cpufreq_freqs *freqs = data;
+	if (val == CPUFREQ_PRECHANGE) {
+		reg_ddr2_rw_cfg cfg =
+		  REG_RD(ddr2, regi_ddr2_ctrl, rw_cfg);
+		cfg.ref_interval = (freqs->new == 200000 ? 1560 : 46);
+
+		if (freqs->new == 200000)
+			for (i = 0; i < 50000; i++);
+		REG_WR(bif_core, regi_bif_core, rw_sdram_timing, timing);
+	}
+	return 0;
+}
+
+
+module_init(cris_freq_init);
diff --git a/arch/cris/arch-v32/mach-a3/dma.c b/arch/cris/arch-v32/mach-a3/dma.c
new file mode 100644
index 000000000000..25f236ef0b81
--- /dev/null
+++ b/arch/cris/arch-v32/mach-a3/dma.c
@@ -0,0 +1,185 @@
+/* Wrapper for DMA channel allocator that starts clocks etc */
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <asm/arch/mach/dma.h>
+#include <hwregs/reg_map.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/marb_defs.h>
+#include <hwregs/clkgen_defs.h>
+#include <hwregs/strmux_defs.h>
+#include <linux/errno.h>
+#include <asm/system.h>
+#include <arbiter.h>
+
+static char used_dma_channels[MAX_DMA_CHANNELS];
+static const char *used_dma_channels_users[MAX_DMA_CHANNELS];
+
+static DEFINE_SPINLOCK(dma_lock);
+
+int crisv32_request_dma(unsigned int dmanr, const char *device_id,
+	unsigned options, unsigned int bandwidth, enum dma_owner owner)
+{
+	unsigned long flags;
+	reg_clkgen_rw_clk_ctrl clk_ctrl;
+	reg_strmux_rw_cfg strmux_cfg;
+
+	if (crisv32_arbiter_allocate_bandwidth(dmanr,
+			options & DMA_INT_MEM ? INT_REGION : EXT_REGION,
+			bandwidth))
+		return -ENOMEM;
+
+	spin_lock_irqsave(&dma_lock, flags);
+
+	if (used_dma_channels[dmanr]) {
+		spin_unlock_irqrestore(&dma_lock, flags);
+		if (options & DMA_VERBOSE_ON_ERROR)
+			printk(KERN_ERR "Failed to request DMA %i for %s, "
+				"already allocated by %s\n",
+				dmanr,
+				device_id,
+				used_dma_channels_users[dmanr]);
+
+		if (options & DMA_PANIC_ON_ERROR)
+			panic("request_dma error!");
+		spin_unlock_irqrestore(&dma_lock, flags);
+		return -EBUSY;
+	}
+	clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl);
+	strmux_cfg = REG_RD(strmux, regi_strmux, rw_cfg);
+
+	switch (dmanr) {
+	case 0:
+	case 1:
+		clk_ctrl.dma0_1_eth = 1;
+		break;
+	case 2:
+	case 3:
+		clk_ctrl.dma2_3_strcop = 1;
+		break;
+	case 4:
+	case 5:
+		clk_ctrl.dma4_5_iop = 1;
+		break;
+	case 6:
+	case 7:
+		clk_ctrl.sser_ser_dma6_7 = 1;
+		break;
+	case 9:
+	case 11:
+		clk_ctrl.dma9_11 = 1;
+		break;
+#if MAX_DMA_CHANNELS-1 != 11
+#error Check dma.c
+#endif
+	default:
+		spin_unlock_irqrestore(&dma_lock, flags);
+		if (options & DMA_VERBOSE_ON_ERROR)
+			printk(KERN_ERR "Failed to request DMA %i for %s, "
+				"only 0-%i valid)\n",
+				dmanr, device_id, MAX_DMA_CHANNELS-1);
+
+		if (options & DMA_PANIC_ON_ERROR)
+			panic("request_dma error!");
+		return -EINVAL;
+	}
+
+	switch (owner) {
+	case dma_eth:
+		if (dmanr == 0)
+			strmux_cfg.dma0 = regk_strmux_eth;
+		else if (dmanr == 1)
+			strmux_cfg.dma1 = regk_strmux_eth;
+		else
+			panic("Invalid DMA channel for eth\n");
+		break;
+	case dma_ser0:
+		if (dmanr == 0)
+			strmux_cfg.dma0 = regk_strmux_ser0;
+		else if (dmanr == 1)
+			strmux_cfg.dma1 = regk_strmux_ser0;
+		else
+			panic("Invalid DMA channel for ser0\n");
+		break;
+	case dma_ser3:
+		if (dmanr == 2)
+			strmux_cfg.dma2 = regk_strmux_ser3;
+		else if (dmanr == 3)
+			strmux_cfg.dma3 = regk_strmux_ser3;
+		else
+			panic("Invalid DMA channel for ser3\n");
+		break;
+	case dma_strp:
+		if (dmanr == 2)
+			strmux_cfg.dma2 = regk_strmux_strcop;
+		else if (dmanr == 3)
+			strmux_cfg.dma3 = regk_strmux_strcop;
+		else
+			panic("Invalid DMA channel for strp\n");
+		break;
+	case dma_ser1:
+		if (dmanr == 4)
+			strmux_cfg.dma4 = regk_strmux_ser1;
+		else if (dmanr == 5)
+			strmux_cfg.dma5 = regk_strmux_ser1;
+		else
+			panic("Invalid DMA channel for ser1\n");
+		break;
+	case dma_iop:
+		if (dmanr == 4)
+			strmux_cfg.dma4 = regk_strmux_iop;
+		else if (dmanr == 5)
+			strmux_cfg.dma5 = regk_strmux_iop;
+		else
+			panic("Invalid DMA channel for iop\n");
+		break;
+	case dma_ser2:
+		if (dmanr == 6)
+			strmux_cfg.dma6 = regk_strmux_ser2;
+		else if (dmanr == 7)
+			strmux_cfg.dma7 = regk_strmux_ser2;
+		else
+			panic("Invalid DMA channel for ser2\n");
+		break;
+	case dma_sser:
+		if (dmanr == 6)
+			strmux_cfg.dma6 = regk_strmux_sser;
+		else if (dmanr == 7)
+			strmux_cfg.dma7 = regk_strmux_sser;
+		else
+			panic("Invalid DMA channel for sser\n");
+		break;
+	case dma_ser4:
+		if (dmanr == 9)
+			strmux_cfg.dma9 = regk_strmux_ser4;
+		else
+			panic("Invalid DMA channel for ser4\n");
+		break;
+	case dma_jpeg:
+		if (dmanr == 9)
+			strmux_cfg.dma9 = regk_strmux_jpeg;
+		else
+			panic("Invalid DMA channel for JPEG\n");
+		break;
+	case dma_h264:
+		if (dmanr == 11)
+			strmux_cfg.dma11 = regk_strmux_h264;
+		else
+			panic("Invalid DMA channel for H264\n");
+		break;
+	}
+
+	used_dma_channels[dmanr] = 1;
+	used_dma_channels_users[dmanr] = device_id;
+	REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, clk_ctrl);
+	REG_WR(strmux, regi_strmux, rw_cfg, strmux_cfg);
+	spin_unlock_irqrestore(&dma_lock, flags);
+	return 0;
+}
+
+void crisv32_free_dma(unsigned int dmanr)
+{
+	spin_lock(&dma_lock);
+	used_dma_channels[dmanr] = 0;
+	spin_unlock(&dma_lock);
+}
diff --git a/arch/cris/arch-v32/mach-a3/dram_init.S b/arch/cris/arch-v32/mach-a3/dram_init.S
new file mode 100644
index 000000000000..94d6b41cb299
--- /dev/null
+++ b/arch/cris/arch-v32/mach-a3/dram_init.S
@@ -0,0 +1,104 @@
+/*
+ * DDR SDRAM initialization - alter with care
+ * This file is intended to be included from other assembler files
+ *
+ * Note: This file may not modify r8 or r9 because they are used to
+ * carry information from the decompresser to the kernel
+ *
+ * Copyright (C) 2005-2007 Axis Communications AB
+ *
+ * Authors:  Mikael Starvik <starvik@axis.com>
+ */
+
+/* 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 <hwregs/asm/reg_map_asm.h>
+#include <hwregs/asm/ddr2_defs_asm.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.
+
+	;; Refer to ddr2 MDS for initialization sequence
+
+	; Start clock
+	move.d   REG_ADDR(ddr2, regi_ddr2_ctrl, rw_phy_cfg), $r0
+	move.d   REG_STATE(ddr2, rw_phy_cfg, en, yes), $r1
+	move.d   $r1, [$r0]
+
+	; Reset phy and start calibration
+	move.d   REG_ADDR(ddr2, regi_ddr2_ctrl, rw_phy_ctrl), $r0
+	move.d   REG_STATE(ddr2, rw_phy_ctrl, rst, yes) | \
+		 REG_STATE(ddr2, rw_phy_ctrl, cal_rst, yes), $r1
+	move.d   $r1, [$r0]
+	move.d	 REG_STATE(ddr2, rw_phy_ctrl, cal_start, yes), $r1
+	move.d   $r1, [$r0]
+
+	; 2. Wait 200us
+	move.d   10000, $r2
+1:	bne      1b
+	subq     1, $r2
+
+	; Issue commands
+	move.d   REG_ADDR(ddr2, regi_ddr2_ctrl, rw_ctrl), $r0
+	move.d   sdram_commands_start, $r2
+command_loop:
+	movu.b  [$r2+], $r1
+	movu.w  [$r2+], $r3
+do_cmd:
+	lslq     16, $r1
+	or.d     $r3, $r1
+	move.d   $r1, [$r0]
+	cmp.d    sdram_commands_end, $r2
+	blo      command_loop
+	nop
+
+	; Set timing
+	move.d   REG_ADDR(ddr2, regi_ddr2_ctrl, rw_timing), $r0
+	move.d   CONFIG_ETRAX_DDR2_TIMING, $r1
+	move.d   $r1, [$r0]
+
+	; Set latency
+	move.d   REG_ADDR(ddr2, regi_ddr2_ctrl, rw_latency), $r0
+	move.d   0x13, $r1
+	move.d   $r1, [$r0]
+
+	; Set configuration
+	move.d   REG_ADDR(ddr2, regi_ddr2_ctrl, rw_cfg), $r0
+	move.d   CONFIG_ETRAX_DDR2_CONFIG, $r1
+	move.d   $r1, [$r0]
+
+	ba after_sdram_commands
+	nop
+
+sdram_commands_start:
+	.byte regk_ddr2_deselect
+	.word 0
+	.byte regk_ddr2_pre
+	.word regk_ddr2_pre_all
+	.byte regk_ddr2_emrs2
+	.word 0
+	.byte regk_ddr2_emrs3
+	.word 0
+	.byte regk_ddr2_emrs
+	.word regk_ddr2_dll_en
+	.byte regk_ddr2_mrs
+	.word regk_ddr2_dll_rst
+	.byte regk_ddr2_pre
+	.word regk_ddr2_pre_all
+	.byte regk_ddr2_ref
+	.word 0
+	.byte regk_ddr2_ref
+	.word 0
+	.byte regk_ddr2_mrs
+	.word CONFIG_ETRAX_DDR2_MRS & 0xffff
+	.byte regk_ddr2_emrs
+	.word regk_ddr2_ocd_default | regk_ddr2_dll_en
+	.byte regk_ddr2_emrs
+	.word regk_ddr2_ocd_exit | regk_ddr2_dll_en | (CONFIG_ETRAX_DDR2_MRS >> 16)
+sdram_commands_end:
+	.align 1
+after_sdram_commands:
diff --git a/arch/cris/arch-v32/mach-a3/hw_settings.S b/arch/cris/arch-v32/mach-a3/hw_settings.S
new file mode 100644
index 000000000000..258a6329cd4a
--- /dev/null
+++ b/arch/cris/arch-v32/mach-a3/hw_settings.S
@@ -0,0 +1,51 @@
+/*
+ * 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-2007 Axis Communications AB
+ *
+ * Authors:  Mikael Starvik <starvik@axis.com>
+ */
+
+#include <hwregs/asm/reg_map_asm.h>
+#include <hwregs/asm/ddr2_defs_asm.h>
+#include <hwregs/asm/gio_defs_asm.h>
+
+	.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
+
+	; Register values
+	.dword REG_ADDR(ddr2, regi_ddr2_ctrl, rw_cfg)
+	.dword CONFIG_ETRAX_DDR2_CONFIG
+	.dword REG_ADDR(ddr2, regi_ddr2_ctrl, rw_timing)
+	.dword CONFIG_ETRAX_DDR2_TIMING
+	.dword CONFIG_ETRAX_DDR2_MRS
+
+	.dword REG_ADDR(gio, regi_gio, rw_pa_dout)
+	.dword CONFIG_ETRAX_DEF_GIO_PA_OUT
+	.dword REG_ADDR(gio, regi_gio, rw_pa_oe)
+	.dword CONFIG_ETRAX_DEF_GIO_PA_OE
+	.dword REG_ADDR(gio, regi_gio, rw_pb_dout)
+	.dword CONFIG_ETRAX_DEF_GIO_PB_OUT
+	.dword REG_ADDR(gio, regi_gio, rw_pb_oe)
+	.dword CONFIG_ETRAX_DEF_GIO_PB_OE
+	.dword REG_ADDR(gio, regi_gio, rw_pc_dout)
+	.dword CONFIG_ETRAX_DEF_GIO_PC_OUT
+	.dword REG_ADDR(gio, regi_gio, rw_pc_oe)
+	.dword CONFIG_ETRAX_DEF_GIO_PC_OE
+
+	.dword 0 ; No more register values
diff --git a/arch/cris/arch-v32/mach-a3/io.c b/arch/cris/arch-v32/mach-a3/io.c
new file mode 100644
index 000000000000..9eeaf3eca474
--- /dev/null
+++ b/arch/cris/arch-v32/mach-a3/io.c
@@ -0,0 +1,149 @@
+/*
+ * Helper functions for I/O pins.
+ *
+ * Copyright (c) 2005-2007 Axis Communications AB.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/io.h>
+#include <asm/arch/mach/pinmux.h>
+#include <hwregs/gio_defs.h>
+
+struct crisv32_ioport crisv32_ioports[] = {
+	{
+		(unsigned long *)REG_ADDR(gio, regi_gio, rw_pa_oe),
+		(unsigned long *)REG_ADDR(gio, regi_gio, rw_pa_dout),
+		(unsigned long *)REG_ADDR(gio, regi_gio, r_pa_din),
+		32
+	},
+	{
+		(unsigned long *)REG_ADDR(gio, regi_gio, rw_pb_oe),
+		(unsigned long *)REG_ADDR(gio, regi_gio, rw_pb_dout),
+		(unsigned long *)REG_ADDR(gio, regi_gio, r_pb_din),
+		32
+	},
+	{
+		(unsigned long *)REG_ADDR(gio, regi_gio, rw_pc_oe),
+		(unsigned long *)REG_ADDR(gio, regi_gio, rw_pc_dout),
+		(unsigned long *)REG_ADDR(gio, regi_gio, r_pc_din),
+		16
+	},
+};
+
+#define NBR_OF_PORTS sizeof(crisv32_ioports)/sizeof(struct crisv32_ioport)
+
+struct crisv32_iopin crisv32_led_net0_green;
+struct crisv32_iopin crisv32_led_net0_red;
+struct crisv32_iopin crisv32_led2_green;
+struct crisv32_iopin crisv32_led2_red;
+struct crisv32_iopin crisv32_led3_green;
+struct crisv32_iopin crisv32_led3_red;
+
+/* Dummy port used when green LED and red LED is on the same bit */
+static unsigned long io_dummy;
+static struct crisv32_ioport dummy_port = {
+	&io_dummy,
+	&io_dummy,
+	&io_dummy,
+	32
+};
+static struct crisv32_iopin dummy_led = {
+	&dummy_port,
+	0
+};
+
+static int __init crisv32_io_init(void)
+{
+	int ret = 0;
+
+	u32 i;
+
+	/* Locks *should* be dynamically initialized. */
+	for (i = 0; i < ARRAY_SIZE(crisv32_ioports); i++)
+		spin_lock_init(&crisv32_ioports[i].lock);
+	spin_lock_init(&dummy_port.lock);
+
+	/* Initialize LEDs */
+#if (defined(CONFIG_ETRAX_NBR_LED_GRP_ONE) || defined(CONFIG_ETRAX_NBR_LED_GRP_TWO))
+	ret += crisv32_io_get_name(&crisv32_led_net0_green,
+		CONFIG_ETRAX_LED_G_NET0);
+	crisv32_io_set_dir(&crisv32_led_net0_green, crisv32_io_dir_out);
+	if (strcmp(CONFIG_ETRAX_LED_G_NET0, CONFIG_ETRAX_LED_R_NET0)) {
+		ret += crisv32_io_get_name(&crisv32_led_net0_red,
+			CONFIG_ETRAX_LED_R_NET0);
+		crisv32_io_set_dir(&crisv32_led_net0_red, crisv32_io_dir_out);
+	} else
+		crisv32_led_net0_red = dummy_led;
+#endif
+
+	ret += crisv32_io_get_name(&crisv32_led2_green, CONFIG_ETRAX_V32_LED2G);
+	ret += crisv32_io_get_name(&crisv32_led2_red, CONFIG_ETRAX_V32_LED2R);
+	ret += crisv32_io_get_name(&crisv32_led3_green, CONFIG_ETRAX_V32_LED3G);
+	ret += crisv32_io_get_name(&crisv32_led3_red, CONFIG_ETRAX_V32_LED3R);
+
+	crisv32_io_set_dir(&crisv32_led2_green, crisv32_io_dir_out);
+	crisv32_io_set_dir(&crisv32_led2_red, crisv32_io_dir_out);
+	crisv32_io_set_dir(&crisv32_led3_green, crisv32_io_dir_out);
+	crisv32_io_set_dir(&crisv32_led3_red, crisv32_io_dir_out);
+
+	return ret;
+}
+
+__initcall(crisv32_io_init);
+
+int crisv32_io_get(struct crisv32_iopin *iopin,
+	unsigned int port, unsigned int pin)
+{
+	if (port > NBR_OF_PORTS)
+		return -EINVAL;
+	if (port > crisv32_ioports[port].pin_count)
+		return -EINVAL;
+
+	iopin->bit = 1 << pin;
+	iopin->port = &crisv32_ioports[port];
+
+	if (crisv32_pinmux_alloc(port, pin, pin, pinmux_gpio))
+		return -EIO;
+
+	return 0;
+}
+
+int crisv32_io_get_name(struct crisv32_iopin *iopin, const char *name)
+{
+	int port;
+	int pin;
+
+	if (toupper(*name) == 'P')
+		name++;
+
+	if (toupper(*name) < 'A' || toupper(*name) > 'E')
+		return -EINVAL;
+
+	port = toupper(*name) - 'A';
+	name++;
+	pin = simple_strtoul(name, NULL, 10);
+
+	if (pin < 0 || pin > crisv32_ioports[port].pin_count)
+		return -EINVAL;
+
+	iopin->bit = 1 << pin;
+	iopin->port = &crisv32_ioports[port];
+
+	if (crisv32_pinmux_alloc(port, pin, pin, pinmux_gpio))
+		return -EIO;
+
+	return 0;
+}
+
+#ifdef CONFIG_PCI
+/* PCI I/O access stuff */
+struct cris_io_operations *cris_iops = NULL;
+EXPORT_SYMBOL(cris_iops);
+#endif
+
diff --git a/arch/cris/arch-v32/mach-a3/pinmux.c b/arch/cris/arch-v32/mach-a3/pinmux.c
new file mode 100644
index 000000000000..0a28c9bedfb7
--- /dev/null
+++ b/arch/cris/arch-v32/mach-a3/pinmux.c
@@ -0,0 +1,386 @@
+/*
+ * Allocator for I/O pins. All pins are allocated to GPIO at bootup.
+ * Unassigned pins and GPIO pins can be allocated to a fixed interface
+ * or the I/O processor instead.
+ *
+ * Copyright (c) 2005-2007 Axis Communications AB.
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <hwregs/reg_map.h>
+#include <hwregs/reg_rdwr.h>
+#include <pinmux.h>
+#include <hwregs/pinmux_defs.h>
+#include <hwregs/clkgen_defs.h>
+
+#undef DEBUG
+
+#define PINS 80
+#define PORT_PINS 32
+#define PORTS 3
+
+static char pins[PINS];
+static DEFINE_SPINLOCK(pinmux_lock);
+
+static void crisv32_pinmux_set(int port);
+
+int
+crisv32_pinmux_init(void)
+{
+	static int initialized;
+
+	if (!initialized) {
+		initialized = 1;
+		REG_WR_INT(pinmux, regi_pinmux, rw_hwprot, 0);
+		crisv32_pinmux_alloc(PORT_A, 0, 31, pinmux_gpio);
+		crisv32_pinmux_alloc(PORT_B, 0, 31, pinmux_gpio);
+		crisv32_pinmux_alloc(PORT_C, 0, 15, pinmux_gpio);
+	}
+
+	return 0;
+}
+
+int
+crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode mode)
+{
+	int i;
+	unsigned long flags;
+
+	crisv32_pinmux_init();
+
+	if (port >= PORTS)
+		return -EINVAL;
+
+	spin_lock_irqsave(&pinmux_lock, flags);
+
+	for (i = first_pin; i <= last_pin; i++) {
+		if ((pins[port * PORT_PINS + i] != pinmux_none) &&
+		    (pins[port * PORT_PINS + i] != pinmux_gpio) &&
+		    (pins[port * PORT_PINS + i] != mode)) {
+			spin_unlock_irqrestore(&pinmux_lock, flags);
+#ifdef DEBUG
+			panic("Pinmux alloc failed!\n");
+#endif
+			return -EPERM;
+		}
+	}
+
+	for (i = first_pin; i <= last_pin; i++)
+		pins[port * PORT_PINS + i] = mode;
+
+	crisv32_pinmux_set(port);
+
+	spin_unlock_irqrestore(&pinmux_lock, flags);
+
+	return 0;
+}
+
+int
+crisv32_pinmux_alloc_fixed(enum fixed_function function)
+{
+	int ret = -EINVAL;
+	char saved[sizeof pins];
+	unsigned long flags;
+
+	spin_lock_irqsave(&pinmux_lock, flags);
+
+	/* Save internal data for recovery */
+	memcpy(saved, pins, sizeof pins);
+
+	crisv32_pinmux_init(); /* must be done before we read rw_hwprot */
+
+	reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot);
+	reg_clkgen_rw_clk_ctrl clk_ctrl = REG_RD(clkgen, regi_clkgen,
+		rw_clk_ctrl);
+
+	switch (function) {
+	case pinmux_eth:
+		clk_ctrl.eth = regk_clkgen_yes;
+		clk_ctrl.dma0_1_eth = regk_clkgen_yes;
+		ret = crisv32_pinmux_alloc(PORT_B, 8, 23, pinmux_fixed);
+		ret |= crisv32_pinmux_alloc(PORT_B, 24, 25, pinmux_fixed);
+		hwprot.eth = hwprot.eth_mdio = regk_pinmux_yes;
+		break;
+	case pinmux_geth:
+		ret = crisv32_pinmux_alloc(PORT_B, 0, 7, pinmux_fixed);
+		hwprot.geth = regk_pinmux_yes;
+		break;
+	case pinmux_tg_cmos:
+		clk_ctrl.ccd_tg_100 = clk_ctrl.ccd_tg_200 = regk_clkgen_yes;
+		ret = crisv32_pinmux_alloc(PORT_B, 27, 29, pinmux_fixed);
+		hwprot.tg_clk = regk_pinmux_yes;
+		break;
+	case pinmux_tg_ccd:
+		clk_ctrl.ccd_tg_100 = clk_ctrl.ccd_tg_200 = regk_clkgen_yes;
+		ret = crisv32_pinmux_alloc(PORT_B, 27, 31, pinmux_fixed);
+		ret |= crisv32_pinmux_alloc(PORT_C, 0, 15, pinmux_fixed);
+		hwprot.tg = hwprot.tg_clk = regk_pinmux_yes;
+		break;
+	case pinmux_vout:
+		clk_ctrl.strdma0_2_video = regk_clkgen_yes;
+		ret = crisv32_pinmux_alloc(PORT_A, 8, 18, pinmux_fixed);
+		hwprot.vout = hwprot.vout_sync = regk_pinmux_yes;
+		break;
+	case pinmux_ser1:
+		clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes;
+		ret = crisv32_pinmux_alloc(PORT_A, 24, 25, pinmux_fixed);
+		hwprot.ser1 = regk_pinmux_yes;
+		break;
+	case pinmux_ser2:
+		clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes;
+		ret = crisv32_pinmux_alloc(PORT_A, 26, 27, pinmux_fixed);
+		hwprot.ser2 = regk_pinmux_yes;
+		break;
+	case pinmux_ser3:
+		clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes;
+		ret = crisv32_pinmux_alloc(PORT_A, 28, 29, pinmux_fixed);
+		hwprot.ser3 = regk_pinmux_yes;
+		break;
+	case pinmux_ser4:
+		clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes;
+		ret = crisv32_pinmux_alloc(PORT_A, 30, 31, pinmux_fixed);
+		hwprot.ser4 = regk_pinmux_yes;
+		break;
+	case pinmux_sser:
+		clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes;
+		ret = crisv32_pinmux_alloc(PORT_A, 19, 23, pinmux_fixed);
+		hwprot.sser = regk_pinmux_yes;
+		break;
+	case pinmux_pio:
+		hwprot.pio = regk_pinmux_yes;
+		ret = 0;
+		break;
+	case pinmux_pwm0:
+		ret = crisv32_pinmux_alloc(PORT_A, 30, 30, pinmux_fixed);
+		hwprot.pwm0 = regk_pinmux_yes;
+		break;
+	case pinmux_pwm1:
+		ret = crisv32_pinmux_alloc(PORT_A, 31, 31, pinmux_fixed);
+		hwprot.pwm1 = regk_pinmux_yes;
+		break;
+	case pinmux_pwm2:
+		ret = crisv32_pinmux_alloc(PORT_B, 26, 26, pinmux_fixed);
+		hwprot.pwm2 = regk_pinmux_yes;
+		break;
+	case pinmux_i2c0:
+		ret = crisv32_pinmux_alloc(PORT_A, 0, 1, pinmux_fixed);
+		hwprot.i2c0 = regk_pinmux_yes;
+		break;
+	case pinmux_i2c1:
+		ret = crisv32_pinmux_alloc(PORT_A, 2, 3, pinmux_fixed);
+		hwprot.i2c1 = regk_pinmux_yes;
+		break;
+	case pinmux_i2c1_3wire:
+		ret = crisv32_pinmux_alloc(PORT_A, 2, 3, pinmux_fixed);
+		ret |= crisv32_pinmux_alloc(PORT_A, 7, 7, pinmux_fixed);
+		hwprot.i2c1 = hwprot.i2c1_sen = regk_pinmux_yes;
+		break;
+	case pinmux_i2c1_sda1:
+		ret = crisv32_pinmux_alloc(PORT_A, 2, 4, pinmux_fixed);
+		hwprot.i2c1 = hwprot.i2c1_sda1 = regk_pinmux_yes;
+		break;
+	case pinmux_i2c1_sda2:
+		ret = crisv32_pinmux_alloc(PORT_A, 2, 3, pinmux_fixed);
+		ret |= crisv32_pinmux_alloc(PORT_A, 5, 5, pinmux_fixed);
+		hwprot.i2c1 = hwprot.i2c1_sda2 = regk_pinmux_yes;
+		break;
+	case pinmux_i2c1_sda3:
+		ret = crisv32_pinmux_alloc(PORT_A, 2, 3, pinmux_fixed);
+		ret |= crisv32_pinmux_alloc(PORT_A, 6, 6, pinmux_fixed);
+		hwprot.i2c1 = hwprot.i2c1_sda3 = regk_pinmux_yes;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (!ret) {
+		REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot);
+		REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, clk_ctrl);
+	} else
+		memcpy(pins, saved, sizeof pins);
+
+  spin_unlock_irqrestore(&pinmux_lock, flags);
+
+  return ret;
+}
+
+void
+crisv32_pinmux_set(int port)
+{
+	int i;
+	int gpio_val = 0;
+	int iop_val = 0;
+	int pin = port * PORT_PINS;
+
+	for (i = 0; (i < PORT_PINS) && (pin < PINS); i++, pin++) {
+		if (pins[pin] == pinmux_gpio)
+			gpio_val |= (1 << i);
+		else if (pins[pin] == pinmux_iop)
+			iop_val |= (1 << i);
+	}
+
+	REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_gio_pa + 4 * port,
+		gpio_val);
+	REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_iop_pa + 4 * port,
+		iop_val);
+
+#ifdef DEBUG
+       crisv32_pinmux_dump();
+#endif
+}
+
+int
+crisv32_pinmux_dealloc(int port, int first_pin, int last_pin)
+{
+	int i;
+	unsigned long flags;
+
+	crisv32_pinmux_init();
+
+	if (port > PORTS)
+		return -EINVAL;
+
+	spin_lock_irqsave(&pinmux_lock, flags);
+
+	for (i = first_pin; i <= last_pin; i++)
+		pins[port * PORT_PINS + i] = pinmux_none;
+
+	crisv32_pinmux_set(port);
+	spin_unlock_irqrestore(&pinmux_lock, flags);
+
+	return 0;
+}
+
+int
+crisv32_pinmux_dealloc_fixed(enum fixed_function function)
+{
+	int ret = -EINVAL;
+	char saved[sizeof pins];
+	unsigned long flags;
+
+	spin_lock_irqsave(&pinmux_lock, flags);
+
+	/* Save internal data for recovery */
+	memcpy(saved, pins, sizeof pins);
+
+	crisv32_pinmux_init(); /* must be done before we read rw_hwprot */
+
+	reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot);
+
+	switch (function) {
+	case pinmux_eth:
+		ret = crisv32_pinmux_dealloc(PORT_B, 8, 23);
+		ret |= crisv32_pinmux_dealloc(PORT_B, 24, 25);
+		ret |= crisv32_pinmux_dealloc(PORT_B, 0, 7);
+		hwprot.eth = hwprot.eth_mdio = hwprot.geth = regk_pinmux_no;
+		break;
+	case pinmux_tg_cmos:
+		ret = crisv32_pinmux_dealloc(PORT_B, 27, 29);
+		hwprot.tg_clk = regk_pinmux_no;
+		break;
+	case pinmux_tg_ccd:
+		ret = crisv32_pinmux_dealloc(PORT_B, 27, 31);
+		ret |= crisv32_pinmux_dealloc(PORT_C, 0, 15);
+		hwprot.tg = hwprot.tg_clk = regk_pinmux_no;
+		break;
+	case pinmux_vout:
+		ret = crisv32_pinmux_dealloc(PORT_A, 8, 18);
+		hwprot.vout = hwprot.vout_sync = regk_pinmux_no;
+		break;
+	case pinmux_ser1:
+		ret = crisv32_pinmux_dealloc(PORT_A, 24, 25);
+		hwprot.ser1 = regk_pinmux_no;
+		break;
+	case pinmux_ser2:
+		ret = crisv32_pinmux_dealloc(PORT_A, 26, 27);
+		hwprot.ser2 = regk_pinmux_no;
+		break;
+	case pinmux_ser3:
+		ret = crisv32_pinmux_dealloc(PORT_A, 28, 29);
+		hwprot.ser3 = regk_pinmux_no;
+		break;
+	case pinmux_ser4:
+		ret = crisv32_pinmux_dealloc(PORT_A, 30, 31);
+		hwprot.ser4 = regk_pinmux_no;
+		break;
+	case pinmux_sser:
+		ret = crisv32_pinmux_dealloc(PORT_A, 19, 23);
+		hwprot.sser = regk_pinmux_no;
+		break;
+	case pinmux_pwm0:
+		ret = crisv32_pinmux_dealloc(PORT_A, 30, 30);
+		hwprot.pwm0 = regk_pinmux_no;
+		break;
+	case pinmux_pwm1:
+		ret = crisv32_pinmux_dealloc(PORT_A, 31, 31);
+		hwprot.pwm1 = regk_pinmux_no;
+		break;
+	case pinmux_pwm2:
+		ret = crisv32_pinmux_dealloc(PORT_B, 26, 26);
+		hwprot.pwm2 = regk_pinmux_no;
+		break;
+	case pinmux_i2c0:
+		ret = crisv32_pinmux_dealloc(PORT_A, 0, 1);
+		hwprot.i2c0 = regk_pinmux_no;
+		break;
+	case pinmux_i2c1:
+		ret = crisv32_pinmux_dealloc(PORT_A, 2, 3);
+		hwprot.i2c1 = regk_pinmux_no;
+		break;
+	case pinmux_i2c1_3wire:
+		ret = crisv32_pinmux_dealloc(PORT_A, 2, 3);
+		ret |= crisv32_pinmux_dealloc(PORT_A, 7, 7);
+		hwprot.i2c1 = hwprot.i2c1_sen = regk_pinmux_no;
+		break;
+	case pinmux_i2c1_sda1:
+		ret = crisv32_pinmux_dealloc(PORT_A, 2, 4);
+		hwprot.i2c1_sda1 = regk_pinmux_no;
+		break;
+	case pinmux_i2c1_sda2:
+		ret = crisv32_pinmux_dealloc(PORT_A, 2, 3);
+		ret |= crisv32_pinmux_dealloc(PORT_A, 5, 5);
+		hwprot.i2c1_sda2 = regk_pinmux_no;
+		break;
+	case pinmux_i2c1_sda3:
+		ret = crisv32_pinmux_dealloc(PORT_A, 2, 3);
+		ret |= crisv32_pinmux_dealloc(PORT_A, 6, 6);
+		hwprot.i2c1_sda3 = regk_pinmux_no;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (!ret)
+		REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot);
+	else
+		memcpy(pins, saved, sizeof pins);
+
+  spin_unlock_irqrestore(&pinmux_lock, flags);
+
+  return ret;
+}
+
+void
+crisv32_pinmux_dump(void)
+{
+	int i, j;
+	int pin = 0;
+
+	crisv32_pinmux_init();
+
+	for (i = 0; i < PORTS; i++) {
+		pin++;
+		printk(KERN_DEBUG "Port %c\n", 'A'+i);
+		for (j = 0; (j < PORT_PINS) && (pin < PINS); j++, pin++)
+			printk(KERN_DEBUG
+				"  Pin %d = %d\n", j, pins[i * PORT_PINS + j]);
+	}
+}
+
+__initcall(crisv32_pinmux_init);
diff --git a/arch/cris/arch-v32/mach-a3/vcs_hook.c b/arch/cris/arch-v32/mach-a3/vcs_hook.c
new file mode 100644
index 000000000000..58b1a5469fd7
--- /dev/null
+++ b/arch/cris/arch-v32/mach-a3/vcs_hook.c
@@ -0,0 +1,103 @@
+/*
+ * Simulator hook mechanism
+ */
+
+#include "vcs_hook.h"
+#include <asm/io.h>
+#include <stdarg.h>
+
+#define HOOK_TRIG_ADDR      0xb7000000
+#define HOOK_MEM_BASE_ADDR  0xce000000
+
+static volatile unsigned *hook_base;
+
+#define HOOK_DATA(offset) hook_base[offset]
+#define VHOOK_DATA(offset) hook_base[offset]
+#define HOOK_TRIG(funcid) \
+	do { \
+		*((unsigned *) HOOK_TRIG_ADDR) = funcid; \
+	} while (0)
+#define HOOK_DATA_BYTE(offset) ((unsigned char *)hook_base)[offset]
+
+static void hook_init(void)
+{
+	static int first = 1;
+	if (first) {
+		first = 0;
+		hook_base = ioremap(HOOK_MEM_BASE_ADDR, 8192);
+	}
+}
+
+static unsigned hook_trig(unsigned id)
+{
+	unsigned ret;
+
+	/* preempt_disable(); */
+
+	/* Dummy read from mem to make sure data has propagated to memory
+	 * before trigging */
+	ret = *hook_base;
+
+	/* trigger hook */
+	HOOK_TRIG(id);
+
+	/* wait for call to finish */
+	while (VHOOK_DATA(0) > 0) ;
+
+	/* extract return value */
+
+	ret = VHOOK_DATA(1);
+
+	return ret;
+}
+
+int hook_call(unsigned id, unsigned pcnt, ...)
+{
+	va_list ap;
+	int i;
+	unsigned ret;
+
+	hook_init();
+
+	HOOK_DATA(0) = id;
+
+	va_start(ap, pcnt);
+	for (i = 1; i <= pcnt; i++)
+		HOOK_DATA(i) = va_arg(ap, unsigned);
+	va_end(ap);
+
+	ret = hook_trig(id);
+
+	return ret;
+}
+
+int hook_call_str(unsigned id, unsigned size, const char *str)
+{
+	int i;
+	unsigned ret;
+
+	hook_init();
+
+	HOOK_DATA(0) = id;
+	HOOK_DATA(1) = size;
+
+	for (i = 0; i < size; i++)
+		HOOK_DATA_BYTE(8 + i) = str[i];
+	HOOK_DATA_BYTE(8 + i) = 0;
+
+	ret = hook_trig(id);
+
+	return ret;
+}
+
+void print_str(const char *str)
+{
+	int i;
+	/* find null at end of string */
+	for (i = 1; str[i]; i++) ;
+	hook_call(hook_print_str, i, str);
+}
+
+void CPU_WATCHDOG_TIMEOUT(unsigned t)
+{
+}
diff --git a/arch/cris/arch-v32/mach-a3/vcs_hook.h b/arch/cris/arch-v32/mach-a3/vcs_hook.h
new file mode 100644
index 000000000000..8b73d0e8392d
--- /dev/null
+++ b/arch/cris/arch-v32/mach-a3/vcs_hook.h
@@ -0,0 +1,58 @@
+/*
+ * Simulator hook call mechanism
+ */
+
+#ifndef __hook_h__
+#define __hook_h__
+
+int hook_call(unsigned id, unsigned pcnt, ...);
+int hook_call_str(unsigned id, unsigned size, const char *str);
+
+enum hook_ids {
+  hook_debug_on = 1,
+  hook_debug_off,
+  hook_stop_sim_ok,
+  hook_stop_sim_fail,
+  hook_alloc_shared,
+  hook_ptr_shared,
+  hook_free_shared,
+  hook_file2shared,
+  hook_cmp_shared,
+  hook_print_params,
+  hook_sim_time,
+  hook_stop_sim,
+  hook_kick_dog,
+  hook_dog_timeout,
+  hook_rand,
+  hook_srand,
+  hook_rand_range,
+  hook_print_str,
+  hook_print_hex,
+  hook_cmp_offset_shared,
+  hook_fill_random_shared,
+  hook_alloc_random_data,
+  hook_calloc_random_data,
+  hook_print_int,
+  hook_print_uint,
+  hook_fputc,
+  hook_init_fd,
+  hook_sbrk,
+  hook_print_context_descr,
+  hook_print_data_descr,
+  hook_print_group_descr,
+  hook_fill_shared,
+  hook_sl_srand,
+  hook_sl_rand_irange,
+  hook_sl_rand_urange,
+  hook_sl_sh_malloc_aligned,
+  hook_sl_sh_calloc_aligned,
+  hook_sl_sh_alloc_random_data,
+  hook_sl_sh_file2mem,
+  hook_sl_vera_mbox_handle,
+  hook_sl_vera_mbox_put,
+  hook_sl_vera_mbox_get,
+  hook_sl_system,
+  hook_sl_sh_hexdump
+};
+
+#endif
diff --git a/arch/cris/arch-v32/mach-fs/Kconfig b/arch/cris/arch-v32/mach-fs/Kconfig
new file mode 100644
index 000000000000..f6d74475f1c6
--- /dev/null
+++ b/arch/cris/arch-v32/mach-fs/Kconfig
@@ -0,0 +1,216 @@
+if ETRAXFS
+
+menu "ETRAX FS options"
+       depends on ETRAXFS
+
+config ETRAX_DRAM_VIRTUAL_BASE
+	hex
+	depends on ETRAX_ARCH_V32
+	default "c0000000"
+
+config ETRAX_SERIAL_PORTS
+       int
+       default 4
+
+config ETRAX_MEM_GRP1_CONFIG
+	hex "MEM_GRP1_CONFIG"
+	depends on ETRAX_ARCH_V32
+	default "4044a"
+	help
+	  Waitstates for flash. The default value is suitable for the
+	  standard flashes used in axis products (120 ns).
+
+config ETRAX_MEM_GRP2_CONFIG
+	hex "MEM_GRP2_CONFIG"
+	depends on ETRAX_ARCH_V32
+	default "0"
+	help
+	  Waitstates for SRAM. 0 is a good choice for most Axis products.
+
+config ETRAX_MEM_GRP3_CONFIG
+	hex "MEM_GRP3_CONFIG"
+	depends on ETRAX_ARCH_V32
+	default "0"
+	help
+	  Waitstates for CSP0-3. 0 is a good choice for most Axis products.
+	  It may need to be changed if external devices such as extra
+	  register-mapped LEDs are used.
+
+config ETRAX_MEM_GRP4_CONFIG
+	hex "MEM_GRP4_CONFIG"
+	depends on ETRAX_ARCH_V32
+	default "0"
+	help
+	  Waitstates for CSP4-6. 0 is a good choice for most Axis products.
+
+config ETRAX_SDRAM_GRP0_CONFIG
+	hex "SDRAM_GRP0_CONFIG"
+	depends on ETRAX_ARCH_V32
+	default "336"
+	help
+	  SDRAM configuration for group 0. The value depends on the
+	  hardware configuration. The default value is suitable
+	  for 32 MB organized as two 16 bits chips (e.g. Axis
+	  part number 18550) connected as one 32 bit device (i.e. in
+	  the same group).
+
+config ETRAX_SDRAM_GRP1_CONFIG
+	hex "SDRAM_GRP1_CONFIG"
+	depends on ETRAX_ARCH_V32
+	default "0"
+	help
+	  SDRAM configuration for group 1. The defult value is 0
+	  because group 1 is not used in the default configuration,
+	  described in the help for SDRAM_GRP0_CONFIG.
+
+config ETRAX_SDRAM_TIMING
+	hex "SDRAM_TIMING"
+	depends on ETRAX_ARCH_V32
+	default "104a"
+	help
+	  SDRAM timing parameters. The default value is ok for
+	  most hardwares but large SDRAMs may require a faster
+	  refresh (a.k.a 8K refresh). The default value implies
+	  100MHz clock and SDR mode.
+
+config ETRAX_SDRAM_COMMAND
+	hex "SDRAM_COMMAND"
+	depends on ETRAX_ARCH_V32
+	default "0"
+	help
+	  SDRAM command. Should be 0 unless you really know what
+	  you are doing (may be != 0 for unusual address line
+	  mappings such as in a MCM)..
+
+config ETRAX_DEF_GIO_PA_OE
+	hex "GIO_PA_OE"
+	depends on ETRAX_ARCH_V32
+	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_GIO_PA_OUT
+	hex "GIO_PA_OUT"
+	depends on ETRAX_ARCH_V32
+	default "00"
+	help
+	  Configures the initial data for the general port A bits.  Most
+	  products should use 00 here.
+
+config ETRAX_DEF_GIO_PB_OE
+	hex "GIO_PB_OE"
+	depends on ETRAX_ARCH_V32
+	default "00000"
+	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.
+	  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_GIO_PB_OUT
+	hex "GIO_PB_OUT"
+	depends on ETRAX_ARCH_V32
+	default "00000"
+	help
+	  Configures the initial data for the general port B bits.  Most
+	  products should use 00000 here.
+
+config ETRAX_DEF_GIO_PC_OE
+	hex "GIO_PC_OE"
+	depends on ETRAX_ARCH_V32
+	default "00000"
+	help
+	  Configures the direction of general port C 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_GIO_PC_OUT
+	hex "GIO_PC_OUT"
+	depends on ETRAX_ARCH_V32
+	default "00000"
+	help
+	  Configures the initial data for the general port C bits.  Most
+	  products should use 00000 here.
+
+config ETRAX_DEF_GIO_PD_OE
+	hex "GIO_PD_OE"
+	depends on ETRAX_ARCH_V32
+	default "00000"
+	help
+	  Configures the direction of general port D 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_GIO_PD_OUT
+	hex "GIO_PD_OUT"
+	depends on ETRAX_ARCH_V32
+	default "00000"
+	help
+	  Configures the initial data for the general port D bits.  Most
+	  products should use 00000 here.
+
+config ETRAX_DEF_GIO_PE_OE
+	hex "GIO_PE_OE"
+	depends on ETRAX_ARCH_V32
+	default "00000"
+	help
+	  Configures the direction of general port E 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_GIO_PE_OUT
+	hex "GIO_PE_OUT"
+	depends on ETRAX_ARCH_V32
+	default "00000"
+	help
+	  Configures the initial data for the general port E bits.  Most
+	  products should use 00000 here.
+
+config ETRAX_DEF_GIO_PV_OE
+	hex "GIO_PV_OE"
+	depends on ETRAX_VIRTUAL_GPIO
+	default "0000"
+	help
+	  Configures the direction of virtual general port V bits. 1 is out,
+	  0 is in. This is often totally different depending on the product
+	  used. 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_GIO_PV_OUT
+	hex "GIO_PV_OUT"
+	depends on ETRAX_VIRTUAL_GPIO
+	default "0000"
+	help
+	  Configures the initial data for the virtual general port V bits.
+	  Most products should use 0000 here.
+
+endmenu
+
+endif
diff --git a/arch/cris/arch-v32/mach-fs/Makefile b/arch/cris/arch-v32/mach-fs/Makefile
new file mode 100644
index 000000000000..4ff407a1b931
--- /dev/null
+++ b/arch/cris/arch-v32/mach-fs/Makefile
@@ -0,0 +1,11 @@
+# $Id: Makefile,v 1.3 2007/03/13 11:57:46 starvik Exp $
+#
+# Makefile for the linux kernel.
+#
+
+obj-y   := dma.o pinmux.o io.o arbiter.o
+bj-$(CONFIG_ETRAX_VCS_SIM) += vcs_hook.o
+obj-$(CONFIG_CPU_FREQ)   += cpufreq.o
+
+clean:
+
diff --git a/arch/cris/arch-v32/mach-fs/arbiter.c b/arch/cris/arch-v32/mach-fs/arbiter.c
new file mode 100644
index 000000000000..84d31bd7b692
--- /dev/null
+++ b/arch/cris/arch-v32/mach-fs/arbiter.c
@@ -0,0 +1,404 @@
+/*
+ * Memory arbiter functions. Allocates bandwidth through the
+ * arbiter and sets up arbiter breakpoints.
+ *
+ * The algorithm first assigns slots to the clients that has specified
+ * bandwidth (e.g. ethernet) and then the remaining slots are divided
+ * on all the active clients.
+ *
+ * Copyright (c) 2004-2007 Axis Communications AB.
+ */
+
+#include <hwregs/reg_map.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/marb_defs.h>
+#include <arbiter.h>
+#include <hwregs/intr_vect.h>
+#include <linux/interrupt.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
+#include <asm/irq_regs.h>
+
+struct crisv32_watch_entry {
+	unsigned long instance;
+	watch_callback *cb;
+	unsigned long start;
+	unsigned long end;
+	int used;
+};
+
+#define NUMBER_OF_BP 4
+#define NBR_OF_CLIENTS 14
+#define NBR_OF_SLOTS 64
+#define SDRAM_BANDWIDTH 100000000	/* Some kind of expected value */
+#define INTMEM_BANDWIDTH 400000000
+#define NBR_OF_REGIONS 2
+
+static struct crisv32_watch_entry watches[NUMBER_OF_BP] = {
+	{regi_marb_bp0},
+	{regi_marb_bp1},
+	{regi_marb_bp2},
+	{regi_marb_bp3}
+};
+
+static u8 requested_slots[NBR_OF_REGIONS][NBR_OF_CLIENTS];
+static u8 active_clients[NBR_OF_REGIONS][NBR_OF_CLIENTS];
+static int max_bandwidth[NBR_OF_REGIONS] =
+    { SDRAM_BANDWIDTH, INTMEM_BANDWIDTH };
+
+DEFINE_SPINLOCK(arbiter_lock);
+
+static irqreturn_t crisv32_arbiter_irq(int irq, void *dev_id);
+
+/*
+ * "I'm the arbiter, I know the score.
+ *  From square one I'll be watching all 64."
+ * (memory arbiter slots, that is)
+ *
+ *  Or in other words:
+ * Program the memory arbiter slots for "region" according to what's
+ * in requested_slots[] and active_clients[], while minimizing
+ * latency. A caller may pass a non-zero positive amount for
+ * "unused_slots", which must then be the unallocated, remaining
+ * number of slots, free to hand out to any client.
+ */
+
+static void crisv32_arbiter_config(int region, int unused_slots)
+{
+	int slot;
+	int client;
+	int interval = 0;
+
+	/*
+	 * This vector corresponds to the hardware arbiter slots (see
+	 * the hardware documentation for semantics). We initialize
+	 * each slot with a suitable sentinel value outside the valid
+	 * range {0 .. NBR_OF_CLIENTS - 1} and replace them with
+	 * client indexes. Then it's fed to the hardware.
+	 */
+	s8 val[NBR_OF_SLOTS];
+
+	for (slot = 0; slot < NBR_OF_SLOTS; slot++)
+		val[slot] = -1;
+
+	for (client = 0; client < NBR_OF_CLIENTS; client++) {
+		int pos;
+		/* Allocate the requested non-zero number of slots, but
+		 * also give clients with zero-requests one slot each
+		 * while stocks last. We do the latter here, in client
+		 * order. This makes sure zero-request clients are the
+		 * first to get to any spare slots, else those slots
+		 * could, when bandwidth is allocated close to the limit,
+		 * all be allocated to low-index non-zero-request clients
+		 * in the default-fill loop below. Another positive but
+		 * secondary effect is a somewhat better spread of the
+		 * zero-bandwidth clients in the vector, avoiding some of
+		 * the latency that could otherwise be caused by the
+		 * partitioning of non-zero-bandwidth clients at low
+		 * indexes and zero-bandwidth clients at high
+		 * indexes. (Note that this spreading can only affect the
+		 * unallocated bandwidth.)  All the above only matters for
+		 * memory-intensive situations, of course.
+		 */
+		if (!requested_slots[region][client]) {
+			/*
+			 * Skip inactive clients. Also skip zero-slot
+			 * allocations in this pass when there are no known
+			 * free slots.
+			 */
+			if (!active_clients[region][client]
+			    || unused_slots <= 0)
+				continue;
+
+			unused_slots--;
+
+			/* Only allocate one slot for this client. */
+			interval = NBR_OF_SLOTS;
+		} else
+			interval =
+			    NBR_OF_SLOTS / requested_slots[region][client];
+
+		pos = 0;
+		while (pos < NBR_OF_SLOTS) {
+			if (val[pos] >= 0)
+				pos++;
+			else {
+				val[pos] = client;
+				pos += interval;
+			}
+		}
+	}
+
+	client = 0;
+	for (slot = 0; slot < NBR_OF_SLOTS; slot++) {
+		/*
+		 * Allocate remaining slots in round-robin
+		 * client-number order for active clients. For this
+		 * pass, we ignore requested bandwidth and previous
+		 * allocations.
+		 */
+		if (val[slot] < 0) {
+			int first = client;
+			while (!active_clients[region][client]) {
+				client = (client + 1) % NBR_OF_CLIENTS;
+				if (client == first)
+					break;
+			}
+			val[slot] = client;
+			client = (client + 1) % NBR_OF_CLIENTS;
+		}
+		if (region == EXT_REGION)
+			REG_WR_INT_VECT(marb, regi_marb, rw_ext_slots, slot,
+					val[slot]);
+		else if (region == INT_REGION)
+			REG_WR_INT_VECT(marb, regi_marb, rw_int_slots, slot,
+					val[slot]);
+	}
+}
+
+extern char _stext, _etext;
+
+static void crisv32_arbiter_init(void)
+{
+	static int initialized;
+
+	if (initialized)
+		return;
+
+	initialized = 1;
+
+	/*
+	 * CPU caches are always set to active, but with zero
+	 * bandwidth allocated. It should be ok to allocate zero
+	 * bandwidth for the caches, because DMA for other channels
+	 * will supposedly finish, once their programmed amount is
+	 * done, and then the caches will get access according to the
+	 * "fixed scheme" for unclaimed slots. Though, if for some
+	 * use-case somewhere, there's a maximum CPU latency for
+	 * e.g. some interrupt, we have to start allocating specific
+	 * bandwidth for the CPU caches too.
+	 */
+	active_clients[EXT_REGION][10] = active_clients[EXT_REGION][11] = 1;
+	crisv32_arbiter_config(EXT_REGION, 0);
+	crisv32_arbiter_config(INT_REGION, 0);
+
+	if (request_irq(MEMARB_INTR_VECT, crisv32_arbiter_irq, IRQF_DISABLED,
+			"arbiter", NULL))
+		printk(KERN_ERR "Couldn't allocate arbiter IRQ\n");
+
+#ifndef CONFIG_ETRAX_KGDB
+	/* Global watch for writes to kernel text segment. */
+	crisv32_arbiter_watch(virt_to_phys(&_stext), &_etext - &_stext,
+			      arbiter_all_clients, arbiter_all_write, NULL);
+#endif
+}
+
+/* Main entry for bandwidth allocation. */
+
+int crisv32_arbiter_allocate_bandwidth(int client, int region,
+				       unsigned long bandwidth)
+{
+	int i;
+	int total_assigned = 0;
+	int total_clients = 0;
+	int req;
+
+	crisv32_arbiter_init();
+
+	for (i = 0; i < NBR_OF_CLIENTS; i++) {
+		total_assigned += requested_slots[region][i];
+		total_clients += active_clients[region][i];
+	}
+
+	/* Avoid division by 0 for 0-bandwidth requests. */
+	req = bandwidth == 0
+	    ? 0 : NBR_OF_SLOTS / (max_bandwidth[region] / bandwidth);
+
+	/*
+	 * We make sure that there are enough slots only for non-zero
+	 * requests. Requesting 0 bandwidth *may* allocate slots,
+	 * though if all bandwidth is allocated, such a client won't
+	 * get any and will have to rely on getting memory access
+	 * according to the fixed scheme that's the default when one
+	 * of the slot-allocated clients doesn't claim their slot.
+	 */
+	if (total_assigned + req > NBR_OF_SLOTS)
+		return -ENOMEM;
+
+	active_clients[region][client] = 1;
+	requested_slots[region][client] = req;
+	crisv32_arbiter_config(region, NBR_OF_SLOTS - total_assigned);
+
+	return 0;
+}
+
+/*
+ * Main entry for bandwidth deallocation.
+ *
+ * Strictly speaking, for a somewhat constant set of clients where
+ * each client gets a constant bandwidth and is just enabled or
+ * disabled (somewhat dynamically), no action is necessary here to
+ * avoid starvation for non-zero-allocation clients, as the allocated
+ * slots will just be unused. However, handing out those unused slots
+ * to active clients avoids needless latency if the "fixed scheme"
+ * would give unclaimed slots to an eager low-index client.
+ */
+
+void crisv32_arbiter_deallocate_bandwidth(int client, int region)
+{
+	int i;
+	int total_assigned = 0;
+
+	requested_slots[region][client] = 0;
+	active_clients[region][client] = 0;
+
+	for (i = 0; i < NBR_OF_CLIENTS; i++)
+		total_assigned += requested_slots[region][i];
+
+	crisv32_arbiter_config(region, NBR_OF_SLOTS - total_assigned);
+}
+
+int crisv32_arbiter_watch(unsigned long start, unsigned long size,
+			  unsigned long clients, unsigned long accesses,
+			  watch_callback *cb)
+{
+	int i;
+
+	crisv32_arbiter_init();
+
+	if (start > 0x80000000) {
+		printk(KERN_ERR "Arbiter: %lX doesn't look like a "
+			"physical address", start);
+		return -EFAULT;
+	}
+
+	spin_lock(&arbiter_lock);
+
+	for (i = 0; i < NUMBER_OF_BP; i++) {
+		if (!watches[i].used) {
+			reg_marb_rw_intr_mask intr_mask =
+			    REG_RD(marb, regi_marb, rw_intr_mask);
+
+			watches[i].used = 1;
+			watches[i].start = start;
+			watches[i].end = start + size;
+			watches[i].cb = cb;
+
+			REG_WR_INT(marb_bp, watches[i].instance, rw_first_addr,
+				   watches[i].start);
+			REG_WR_INT(marb_bp, watches[i].instance, rw_last_addr,
+				   watches[i].end);
+			REG_WR_INT(marb_bp, watches[i].instance, rw_op,
+				   accesses);
+			REG_WR_INT(marb_bp, watches[i].instance, rw_clients,
+				   clients);
+
+			if (i == 0)
+				intr_mask.bp0 = regk_marb_yes;
+			else if (i == 1)
+				intr_mask.bp1 = regk_marb_yes;
+			else if (i == 2)
+				intr_mask.bp2 = regk_marb_yes;
+			else if (i == 3)
+				intr_mask.bp3 = regk_marb_yes;
+
+			REG_WR(marb, regi_marb, rw_intr_mask, intr_mask);
+			spin_unlock(&arbiter_lock);
+
+			return i;
+		}
+	}
+	spin_unlock(&arbiter_lock);
+	return -ENOMEM;
+}
+
+int crisv32_arbiter_unwatch(int id)
+{
+	reg_marb_rw_intr_mask intr_mask = REG_RD(marb, regi_marb, rw_intr_mask);
+
+	crisv32_arbiter_init();
+
+	spin_lock(&arbiter_lock);
+
+	if ((id < 0) || (id >= NUMBER_OF_BP) || (!watches[id].used)) {
+		spin_unlock(&arbiter_lock);
+		return -EINVAL;
+	}
+
+	memset(&watches[id], 0, sizeof(struct crisv32_watch_entry));
+
+	if (id == 0)
+		intr_mask.bp0 = regk_marb_no;
+	else if (id == 1)
+		intr_mask.bp2 = regk_marb_no;
+	else if (id == 2)
+		intr_mask.bp2 = regk_marb_no;
+	else if (id == 3)
+		intr_mask.bp3 = regk_marb_no;
+
+	REG_WR(marb, regi_marb, rw_intr_mask, intr_mask);
+
+	spin_unlock(&arbiter_lock);
+	return 0;
+}
+
+extern void show_registers(struct pt_regs *regs);
+
+static irqreturn_t crisv32_arbiter_irq(int irq, void *dev_id)
+{
+	reg_marb_r_masked_intr masked_intr =
+	    REG_RD(marb, regi_marb, r_masked_intr);
+	reg_marb_bp_r_brk_clients r_clients;
+	reg_marb_bp_r_brk_addr r_addr;
+	reg_marb_bp_r_brk_op r_op;
+	reg_marb_bp_r_brk_first_client r_first;
+	reg_marb_bp_r_brk_size r_size;
+	reg_marb_bp_rw_ack ack = { 0 };
+	reg_marb_rw_ack_intr ack_intr = {
+		.bp0 = 1, .bp1 = 1, .bp2 = 1, .bp3 = 1
+	};
+	struct crisv32_watch_entry *watch;
+
+	if (masked_intr.bp0) {
+		watch = &watches[0];
+		ack_intr.bp0 = regk_marb_yes;
+	} else if (masked_intr.bp1) {
+		watch = &watches[1];
+		ack_intr.bp1 = regk_marb_yes;
+	} else if (masked_intr.bp2) {
+		watch = &watches[2];
+		ack_intr.bp2 = regk_marb_yes;
+	} else if (masked_intr.bp3) {
+		watch = &watches[3];
+		ack_intr.bp3 = regk_marb_yes;
+	} else {
+		return IRQ_NONE;
+	}
+
+	/* Retrieve all useful information and print it. */
+	r_clients = REG_RD(marb_bp, watch->instance, r_brk_clients);
+	r_addr = REG_RD(marb_bp, watch->instance, r_brk_addr);
+	r_op = REG_RD(marb_bp, watch->instance, r_brk_op);
+	r_first = REG_RD(marb_bp, watch->instance, r_brk_first_client);
+	r_size = REG_RD(marb_bp, watch->instance, r_brk_size);
+
+	printk(KERN_INFO "Arbiter IRQ\n");
+	printk(KERN_INFO "Clients %X addr %X op %X first %X size %X\n",
+	       REG_TYPE_CONV(int, reg_marb_bp_r_brk_clients, r_clients),
+	       REG_TYPE_CONV(int, reg_marb_bp_r_brk_addr, r_addr),
+	       REG_TYPE_CONV(int, reg_marb_bp_r_brk_op, r_op),
+	       REG_TYPE_CONV(int, reg_marb_bp_r_brk_first_client, r_first),
+	       REG_TYPE_CONV(int, reg_marb_bp_r_brk_size, r_size));
+
+	REG_WR(marb_bp, watch->instance, rw_ack, ack);
+	REG_WR(marb, regi_marb, rw_ack_intr, ack_intr);
+
+	printk(KERN_INFO "IRQ occured at %lX\n", get_irq_regs()->erp);
+
+	if (watch->cb)
+		watch->cb();
+
+	return IRQ_HANDLED;
+}
diff --git a/arch/cris/arch-v32/mach-fs/cpufreq.c b/arch/cris/arch-v32/mach-fs/cpufreq.c
new file mode 100644
index 000000000000..d57631c0d8d1
--- /dev/null
+++ b/arch/cris/arch-v32/mach-fs/cpufreq.c
@@ -0,0 +1,146 @@
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/cpufreq.h>
+#include <hwregs/reg_map.h>
+#include <asm/arch/hwregs/reg_rdwr.h>
+#include <asm/arch/hwregs/config_defs.h>
+#include <asm/arch/hwregs/bif_core_defs.h>
+
+static int
+cris_sdram_freq_notifier(struct notifier_block *nb, unsigned long val,
+			 void *data);
+
+static struct notifier_block cris_sdram_freq_notifier_block = {
+	.notifier_call = cris_sdram_freq_notifier
+};
+
+static struct cpufreq_frequency_table cris_freq_table[] = {
+	{0x01, 6000},
+	{0x02, 200000},
+	{0, CPUFREQ_TABLE_END},
+};
+
+static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu)
+{
+	reg_config_rw_clk_ctrl clk_ctrl;
+	clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl);
+	return clk_ctrl.pll ? 200000 : 6000;
+}
+
+static void cris_freq_set_cpu_state(unsigned int state)
+{
+	int i;
+	struct cpufreq_freqs freqs;
+	reg_config_rw_clk_ctrl clk_ctrl;
+	clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl);
+
+	for_each_possible_cpu(i) {
+		freqs.old = cris_freq_get_cpu_frequency(i);
+		freqs.new = cris_freq_table[state].frequency;
+		freqs.cpu = i;
+	}
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	local_irq_disable();
+
+	/* Even though we may be SMP they will share the same clock
+	 * so all settings are made on CPU0. */
+	if (cris_freq_table[state].frequency == 200000)
+		clk_ctrl.pll = 1;
+	else
+		clk_ctrl.pll = 0;
+	REG_WR(config, regi_config, rw_clk_ctrl, clk_ctrl);
+
+	local_irq_enable();
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+};
+
+static int cris_freq_verify(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, &cris_freq_table[0]);
+}
+
+static int cris_freq_target(struct cpufreq_policy *policy,
+			    unsigned int target_freq, unsigned int relation)
+{
+	unsigned int newstate = 0;
+
+	if (cpufreq_frequency_table_target
+	    (policy, cris_freq_table, target_freq, relation, &newstate))
+		return -EINVAL;
+
+	cris_freq_set_cpu_state(newstate);
+
+	return 0;
+}
+
+static int cris_freq_cpu_init(struct cpufreq_policy *policy)
+{
+	int result;
+
+	/* cpuinfo and default policy values */
+	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+	policy->cpuinfo.transition_latency = 1000000;	/* 1ms */
+	policy->cur = cris_freq_get_cpu_frequency(0);
+
+	result = cpufreq_frequency_table_cpuinfo(policy, cris_freq_table);
+	if (result)
+		return (result);
+
+	cpufreq_frequency_table_get_attr(cris_freq_table, policy->cpu);
+
+	return 0;
+}
+
+static int cris_freq_cpu_exit(struct cpufreq_policy *policy)
+{
+	cpufreq_frequency_table_put_attr(policy->cpu);
+	return 0;
+}
+
+static struct freq_attr *cris_freq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver cris_freq_driver = {
+	.get = cris_freq_get_cpu_frequency,
+	.verify = cris_freq_verify,
+	.target = cris_freq_target,
+	.init = cris_freq_cpu_init,
+	.exit = cris_freq_cpu_exit,
+	.name = "cris_freq",
+	.owner = THIS_MODULE,
+	.attr = cris_freq_attr,
+};
+
+static int __init cris_freq_init(void)
+{
+	int ret;
+	ret = cpufreq_register_driver(&cris_freq_driver);
+	cpufreq_register_notifier(&cris_sdram_freq_notifier_block,
+				  CPUFREQ_TRANSITION_NOTIFIER);
+	return ret;
+}
+
+static int
+cris_sdram_freq_notifier(struct notifier_block *nb, unsigned long val,
+			 void *data)
+{
+	int i;
+	struct cpufreq_freqs *freqs = data;
+	if (val == CPUFREQ_PRECHANGE) {
+		reg_bif_core_rw_sdram_timing timing =
+		    REG_RD(bif_core, regi_bif_core, rw_sdram_timing);
+		timing.cpd = (freqs->new == 200000 ? 0 : 1);
+
+		if (freqs->new == 200000)
+			for (i = 0; i < 50000; i++) ;
+		REG_WR(bif_core, regi_bif_core, rw_sdram_timing, timing);
+	}
+	return 0;
+}
+
+module_init(cris_freq_init);
diff --git a/arch/cris/arch-v32/kernel/dma.c b/arch/cris/arch-v32/mach-fs/dma.c
index 570e19128ffd..a6acf4e6345c 100644
--- a/arch/cris/arch-v32/kernel/dma.c
+++ b/arch/cris/arch-v32/mach-fs/dma.c
@@ -3,49 +3,54 @@
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
 #include <asm/dma.h>
-#include <asm/arch/hwregs/reg_map.h>
-#include <asm/arch/hwregs/reg_rdwr.h>
-#include <asm/arch/hwregs/marb_defs.h>
-#include <asm/arch/hwregs/config_defs.h>
-#include <asm/arch/hwregs/strmux_defs.h>
+#include <hwregs/reg_map.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/marb_defs.h>
+#include <hwregs/config_defs.h>
+#include <hwregs/strmux_defs.h>
 #include <linux/errno.h>
 #include <asm/system.h>
-#include <asm/arch/arbiter.h>
+#include <asm/arch/mach/arbiter.h>
 
 static char used_dma_channels[MAX_DMA_CHANNELS];
-static const char * used_dma_channels_users[MAX_DMA_CHANNELS];
+static const char *used_dma_channels_users[MAX_DMA_CHANNELS];
 
 static DEFINE_SPINLOCK(dma_lock);
 
-int crisv32_request_dma(unsigned int dmanr, const char * device_id,
-                        unsigned options, unsigned int bandwidth,
+int crisv32_request_dma(unsigned int dmanr, const char *device_id,
+			unsigned options, unsigned int bandwidth,
 			enum dma_owner owner)
 {
 	unsigned long flags;
 	reg_config_rw_clk_ctrl clk_ctrl;
 	reg_strmux_rw_cfg strmux_cfg;
 
-        if (crisv32_arbiter_allocate_bandwidth(dmanr,
-					       options & DMA_INT_MEM ? INT_REGION : EXT_REGION,
-                                              bandwidth))
-          return -ENOMEM;
+	if (crisv32_arbiter_allocate_bandwidth(dmanr,
+					       options & DMA_INT_MEM ?
+					       INT_REGION : EXT_REGION,
+					       bandwidth))
+		return -ENOMEM;
 
 	spin_lock_irqsave(&dma_lock, flags);
 
 	if (used_dma_channels[dmanr]) {
 		spin_unlock_irqrestore(&dma_lock, flags);
 		if (options & DMA_VERBOSE_ON_ERROR) {
-			printk("Failed to request DMA %i for %s, already allocated by %s\n", dmanr, device_id, used_dma_channels_users[dmanr]);
+			printk(KERN_ERR "Failed to request DMA %i for %s, "
+				"already allocated by %s\n",
+				dmanr,
+				device_id,
+				used_dma_channels_users[dmanr]);
 		}
 		if (options & DMA_PANIC_ON_ERROR)
 			panic("request_dma error!");
+		spin_unlock_irqrestore(&dma_lock, flags);
 		return -EBUSY;
 	}
 	clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl);
 	strmux_cfg = REG_RD(strmux, regi_strmux, rw_cfg);
 
-	switch(dmanr)
-	{
+	switch (dmanr) {
 	case 0:
 	case 1:
 		clk_ctrl.dma01_eth0 = 1;
@@ -72,7 +77,9 @@ int crisv32_request_dma(unsigned int dmanr, const char * device_id,
 	default:
 		spin_unlock_irqrestore(&dma_lock, flags);
 		if (options & DMA_VERBOSE_ON_ERROR) {
-			printk("Failed to request DMA %i for %s, only 0-%i valid)\n", dmanr, device_id, MAX_DMA_CHANNELS-1);
+			printk(KERN_ERR "Failed to request DMA %i for %s, "
+				"only 0-%i valid)\n",
+				dmanr, device_id, MAX_DMA_CHANNELS - 1);
 		}
 
 		if (options & DMA_PANIC_ON_ERROR)
@@ -80,8 +87,7 @@ int crisv32_request_dma(unsigned int dmanr, const char * device_id,
 		return -EINVAL;
 	}
 
-	switch(owner)
-	{
+	switch (owner) {
 	case dma_eth0:
 		if (dmanr == 0)
 			strmux_cfg.dma0 = regk_strmux_eth0;
@@ -212,7 +218,7 @@ int crisv32_request_dma(unsigned int dmanr, const char * device_id,
 	used_dma_channels_users[dmanr] = device_id;
 	REG_WR(config, regi_config, rw_clk_ctrl, clk_ctrl);
 	REG_WR(strmux, regi_strmux, rw_cfg, strmux_cfg);
-	spin_unlock_irqrestore(&dma_lock,flags);
+	spin_unlock_irqrestore(&dma_lock, flags);
 	return 0;
 }
 
diff --git a/arch/cris/arch-v32/lib/dram_init.S b/arch/cris/arch-v32/mach-fs/dram_init.S
index 218fbe259ee5..6fbad336527b 100644
--- a/arch/cris/arch-v32/lib/dram_init.S
+++ b/arch/cris/arch-v32/mach-fs/dram_init.S
@@ -1,23 +1,22 @@
-/* $Id: dram_init.S,v 1.4 2005/04/24 18:48:32 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 r8 or r9 because they are used to
  * carry information from the decompresser to the kernel
  *
- * Copyright (C) 2000-2003 Axis Communications AB
+ * Copyright (C) 2000-2007 Axis Communications AB
  *
- * Authors:  Mikael Starvik (starvik@axis.com)
+ * Authors:  Mikael Starvik <starvik@axis.com>
  */
 
 /* Just to be certain the config file is included, we include it here
- * explicitly instead of depending on it being included in the file that
+ * explicitely instead of depending on it being included in the file that
  * uses this code.
  */
 
-#include <asm/arch/hwregs/asm/reg_map_asm.h>
-#include <asm/arch/hwregs/asm/bif_core_defs_asm.h>
+#include <hwregs/asm/reg_map_asm.h>
+#include <hwregs/asm/bif_core_defs_asm.h>
 
 	;; WARNING! The registers r8 and r9 are used as parameters carrying
 	;; information from the decompressor (if the kernel was compressed).
@@ -46,7 +45,7 @@
 
 	move.d   0x40, $r4       ; Assume 32 bits and CAS latency = 2
 	move.d   CONFIG_ETRAX_SDRAM_TIMING, $r1
- 	and.d    0x07, $r1       ; Get CAS latency
+	and.d    0x07, $r1       ; Get CAS latency
 	cmpq	 2, $r1		 ; CL = 2 ?
 	beq	 _bw_check
 	nop
@@ -80,12 +79,10 @@ _set_timing:
 	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
+	lapc     _sdram_commands_start, $r2
+	lapc     _sdram_commands_end,  $r3
 1:	clear.d  $r6
-	move.b   [$r2+], $r6 	; Load command
+	move.b   [$r2+], $r6	; Load command
 	or.d     $r4, $r6	; Add calculated mrs
 	move.d   $r6, [$r5]	; Write rw_sdram_cmd
 	; Wait 80 ns between each command
diff --git a/arch/cris/arch-v32/lib/hw_settings.S b/arch/cris/arch-v32/mach-fs/hw_settings.S
index fff9443513d1..8bde93c36214 100644
--- a/arch/cris/arch-v32/lib/hw_settings.S
+++ b/arch/cris/arch-v32/mach-fs/hw_settings.S
@@ -1,18 +1,16 @@
 /*
- * $Id: hw_settings.S,v 1.3 2005/04/24 18:36:57 starvik 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
+ * Copyright (C) 2001-2007 Axis Communications AB
  *
- * Authors:  Mikael Starvik (starvik@axis.com)
+ * Authors:  Mikael Starvik <starvik@axis.com>
  */
 
-#include <asm/arch/hwregs/asm/reg_map_asm.h>
-#include <asm/arch/hwregs/asm/bif_core_defs_asm.h>
-#include <asm/arch/hwregs/asm/gio_defs_asm.h>
+#include <hwregs/asm/reg_map_asm.h>
+#include <hwregs/asm/bif_core_defs_asm.h>
+#include <hwregs/asm/gio_defs_asm.h>
 
 	.ascii "HW_PARAM_MAGIC" ; Magic number
 	.dword 0xc0004000	; Kernel start address
diff --git a/arch/cris/arch-v32/mach-fs/io.c b/arch/cris/arch-v32/mach-fs/io.c
new file mode 100644
index 000000000000..a03a3ad3a188
--- /dev/null
+++ b/arch/cris/arch-v32/mach-fs/io.c
@@ -0,0 +1,191 @@
+/*
+ * Helper functions for I/O pins.
+ *
+ * Copyright (c) 2004-2007 Axis Communications AB.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/io.h>
+#include <asm/arch/pinmux.h>
+#include <asm/arch/hwregs/gio_defs.h>
+
+#ifndef DEBUG
+#define DEBUG(x)
+#endif
+
+struct crisv32_ioport crisv32_ioports[] = {
+	{
+		(unsigned long *)REG_ADDR(gio, regi_gio, rw_pa_oe),
+		(unsigned long *)REG_ADDR(gio, regi_gio, rw_pa_dout),
+		(unsigned long *)REG_ADDR(gio, regi_gio, r_pa_din),
+		8
+	},
+	{
+		(unsigned long *)REG_ADDR(gio, regi_gio, rw_pb_oe),
+		(unsigned long *)REG_ADDR(gio, regi_gio, rw_pb_dout),
+		(unsigned long *)REG_ADDR(gio, regi_gio, r_pb_din),
+		18
+	},
+	{
+		(unsigned long *)REG_ADDR(gio, regi_gio, rw_pc_oe),
+		(unsigned long *)REG_ADDR(gio, regi_gio, rw_pc_dout),
+		(unsigned long *)REG_ADDR(gio, regi_gio, r_pc_din),
+		18
+	},
+	{
+		(unsigned long *)REG_ADDR(gio, regi_gio, rw_pd_oe),
+		(unsigned long *)REG_ADDR(gio, regi_gio, rw_pd_dout),
+		(unsigned long *)REG_ADDR(gio, regi_gio, r_pd_din),
+		18
+	},
+	{
+		(unsigned long *)REG_ADDR(gio, regi_gio, rw_pe_oe),
+		(unsigned long *)REG_ADDR(gio, regi_gio, rw_pe_dout),
+		(unsigned long *)REG_ADDR(gio, regi_gio, r_pe_din),
+		18
+	}
+};
+
+#define NBR_OF_PORTS sizeof(crisv32_ioports)/sizeof(struct crisv32_ioport)
+
+struct crisv32_iopin crisv32_led_net0_green;
+struct crisv32_iopin crisv32_led_net0_red;
+struct crisv32_iopin crisv32_led_net1_green;
+struct crisv32_iopin crisv32_led_net1_red;
+struct crisv32_iopin crisv32_led2_green;
+struct crisv32_iopin crisv32_led2_red;
+struct crisv32_iopin crisv32_led3_green;
+struct crisv32_iopin crisv32_led3_red;
+
+/* Dummy port used when green LED and red LED is on the same bit */
+static unsigned long io_dummy;
+static struct crisv32_ioport dummy_port = {
+	&io_dummy,
+	&io_dummy,
+	&io_dummy,
+	18
+};
+static struct crisv32_iopin dummy_led = {
+	&dummy_port,
+	0
+};
+
+static int __init crisv32_io_init(void)
+{
+	int ret = 0;
+
+	u32 i;
+
+	/* Locks *should* be dynamically initialized. */
+	for (i = 0; i < ARRAY_SIZE(crisv32_ioports); i++)
+		spin_lock_init(&crisv32_ioports[i].lock);
+	spin_lock_init(&dummy_port.lock);
+
+	/* Initialize LEDs */
+#if (defined(CONFIG_ETRAX_NBR_LED_GRP_ONE) || defined(CONFIG_ETRAX_NBR_LED_GRP_TWO))
+	ret +=
+	    crisv32_io_get_name(&crisv32_led_net0_green,
+				CONFIG_ETRAX_LED_G_NET0);
+	crisv32_io_set_dir(&crisv32_led_net0_green, crisv32_io_dir_out);
+	if (strcmp(CONFIG_ETRAX_LED_G_NET0, CONFIG_ETRAX_LED_R_NET0)) {
+		ret +=
+		    crisv32_io_get_name(&crisv32_led_net0_red,
+					CONFIG_ETRAX_LED_R_NET0);
+		crisv32_io_set_dir(&crisv32_led_net0_red, crisv32_io_dir_out);
+	} else
+		crisv32_led_net0_red = dummy_led;
+#endif
+
+#ifdef CONFIG_ETRAX_NBR_LED_GRP_TWO
+	ret +=
+	    crisv32_io_get_name(&crisv32_led_net1_green,
+				CONFIG_ETRAX_LED_G_NET1);
+	crisv32_io_set_dir(&crisv32_led_net1_green, crisv32_io_dir_out);
+	if (strcmp(CONFIG_ETRAX_LED_G_NET1, CONFIG_ETRAX_LED_R_NET1)) {
+		crisv32_io_get_name(&crisv32_led_net1_red,
+				    CONFIG_ETRAX_LED_R_NET1);
+		crisv32_io_set_dir(&crisv32_led_net1_red, crisv32_io_dir_out);
+	} else
+		crisv32_led_net1_red = dummy_led;
+#endif
+
+	ret += crisv32_io_get_name(&crisv32_led2_green, CONFIG_ETRAX_V32_LED2G);
+	ret += crisv32_io_get_name(&crisv32_led2_red, CONFIG_ETRAX_V32_LED2R);
+	ret += crisv32_io_get_name(&crisv32_led3_green, CONFIG_ETRAX_V32_LED3G);
+	ret += crisv32_io_get_name(&crisv32_led3_red, CONFIG_ETRAX_V32_LED3R);
+
+	crisv32_io_set_dir(&crisv32_led2_green, crisv32_io_dir_out);
+	crisv32_io_set_dir(&crisv32_led2_red, crisv32_io_dir_out);
+	crisv32_io_set_dir(&crisv32_led3_green, crisv32_io_dir_out);
+	crisv32_io_set_dir(&crisv32_led3_red, crisv32_io_dir_out);
+
+	return ret;
+}
+
+__initcall(crisv32_io_init);
+
+int crisv32_io_get(struct crisv32_iopin *iopin,
+		   unsigned int port, unsigned int pin)
+{
+	if (port > NBR_OF_PORTS)
+		return -EINVAL;
+	if (port > crisv32_ioports[port].pin_count)
+		return -EINVAL;
+
+	iopin->bit = 1 << pin;
+	iopin->port = &crisv32_ioports[port];
+
+	/* Only allocate pinmux gpiopins if port != PORT_A (port 0) */
+	/* NOTE! crisv32_pinmux_alloc thinks PORT_B is port 0 */
+	if (port != 0 && crisv32_pinmux_alloc(port - 1, pin, pin, pinmux_gpio))
+		return -EIO;
+	DEBUG(printk(KERN_DEBUG "crisv32_io_get: Allocated pin %d on port %d\n",
+		pin, port));
+
+	return 0;
+}
+
+int crisv32_io_get_name(struct crisv32_iopin *iopin, const char *name)
+{
+	int port;
+	int pin;
+
+	if (toupper(*name) == 'P')
+		name++;
+
+	if (toupper(*name) < 'A' || toupper(*name) > 'E')
+		return -EINVAL;
+
+	port = toupper(*name) - 'A';
+	name++;
+	pin = simple_strtoul(name, NULL, 10);
+
+	if (pin < 0 || pin > crisv32_ioports[port].pin_count)
+		return -EINVAL;
+
+	iopin->bit = 1 << pin;
+	iopin->port = &crisv32_ioports[port];
+
+	/* Only allocate pinmux gpiopins if port != PORT_A (port 0) */
+	/* NOTE! crisv32_pinmux_alloc thinks PORT_B is port 0 */
+	if (port != 0 && crisv32_pinmux_alloc(port - 1, pin, pin, pinmux_gpio))
+		return -EIO;
+
+	DEBUG(printk(KERN_DEBUG
+		"crisv32_io_get_name: Allocated pin %d on port %d\n",
+		pin, port));
+
+	return 0;
+}
+
+#ifdef CONFIG_PCI
+/* PCI I/O access stuff */
+struct cris_io_operations *cris_iops = NULL;
+EXPORT_SYMBOL(cris_iops);
+#endif
diff --git a/arch/cris/arch-v32/mach-fs/pinmux.c b/arch/cris/arch-v32/mach-fs/pinmux.c
new file mode 100644
index 000000000000..d722ad9ae626
--- /dev/null
+++ b/arch/cris/arch-v32/mach-fs/pinmux.c
@@ -0,0 +1,309 @@
+/*
+ * Allocator for I/O pins. All pins are allocated to GPIO at bootup.
+ * Unassigned pins and GPIO pins can be allocated to a fixed interface
+ * or the I/O processor instead.
+ *
+ * Copyright (c) 2004-2007 Axis Communications AB.
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <hwregs/reg_map.h>
+#include <hwregs/reg_rdwr.h>
+#include <pinmux.h>
+#include <hwregs/pinmux_defs.h>
+
+#undef DEBUG
+
+#define PORT_PINS 18
+#define PORTS 4
+
+static char pins[PORTS][PORT_PINS];
+static DEFINE_SPINLOCK(pinmux_lock);
+
+static void crisv32_pinmux_set(int port);
+
+int crisv32_pinmux_init(void)
+{
+	static int initialized;
+
+	if (!initialized) {
+		reg_pinmux_rw_pa pa = REG_RD(pinmux, regi_pinmux, rw_pa);
+		initialized = 1;
+		REG_WR_INT(pinmux, regi_pinmux, rw_hwprot, 0);
+		pa.pa0 = pa.pa1 = pa.pa2 = pa.pa3 =
+		    pa.pa4 = pa.pa5 = pa.pa6 = pa.pa7 = regk_pinmux_yes;
+		REG_WR(pinmux, regi_pinmux, rw_pa, pa);
+		crisv32_pinmux_alloc(PORT_B, 0, PORT_PINS - 1, pinmux_gpio);
+		crisv32_pinmux_alloc(PORT_C, 0, PORT_PINS - 1, pinmux_gpio);
+		crisv32_pinmux_alloc(PORT_D, 0, PORT_PINS - 1, pinmux_gpio);
+		crisv32_pinmux_alloc(PORT_E, 0, PORT_PINS - 1, pinmux_gpio);
+	}
+
+	return 0;
+}
+
+int
+crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode mode)
+{
+	int i;
+	unsigned long flags;
+
+	crisv32_pinmux_init();
+
+	if (port > PORTS)
+		return -EINVAL;
+
+	spin_lock_irqsave(&pinmux_lock, flags);
+
+	for (i = first_pin; i <= last_pin; i++) {
+		if ((pins[port][i] != pinmux_none)
+		    && (pins[port][i] != pinmux_gpio)
+		    && (pins[port][i] != mode)) {
+			spin_unlock_irqrestore(&pinmux_lock, flags);
+#ifdef DEBUG
+			panic("Pinmux alloc failed!\n");
+#endif
+			return -EPERM;
+		}
+	}
+
+	for (i = first_pin; i <= last_pin; i++)
+		pins[port][i] = mode;
+
+	crisv32_pinmux_set(port);
+
+	spin_unlock_irqrestore(&pinmux_lock, flags);
+
+	return 0;
+}
+
+int crisv32_pinmux_alloc_fixed(enum fixed_function function)
+{
+	int ret = -EINVAL;
+	char saved[sizeof pins];
+	unsigned long flags;
+
+	spin_lock_irqsave(&pinmux_lock, flags);
+
+	/* Save internal data for recovery */
+	memcpy(saved, pins, sizeof pins);
+
+	crisv32_pinmux_init();	/* Must be done before we read rw_hwprot */
+
+	reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot);
+
+	switch (function) {
+	case pinmux_ser1:
+		ret = crisv32_pinmux_alloc(PORT_C, 4, 7, pinmux_fixed);
+		hwprot.ser1 = regk_pinmux_yes;
+		break;
+	case pinmux_ser2:
+		ret = crisv32_pinmux_alloc(PORT_C, 8, 11, pinmux_fixed);
+		hwprot.ser2 = regk_pinmux_yes;
+		break;
+	case pinmux_ser3:
+		ret = crisv32_pinmux_alloc(PORT_C, 12, 15, pinmux_fixed);
+		hwprot.ser3 = regk_pinmux_yes;
+		break;
+	case pinmux_sser0:
+		ret = crisv32_pinmux_alloc(PORT_C, 0, 3, pinmux_fixed);
+		ret |= crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed);
+		hwprot.sser0 = regk_pinmux_yes;
+		break;
+	case pinmux_sser1:
+		ret = crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed);
+		hwprot.sser1 = regk_pinmux_yes;
+		break;
+	case pinmux_ata0:
+		ret = crisv32_pinmux_alloc(PORT_D, 5, 7, pinmux_fixed);
+		ret |= crisv32_pinmux_alloc(PORT_D, 15, 17, pinmux_fixed);
+		hwprot.ata0 = regk_pinmux_yes;
+		break;
+	case pinmux_ata1:
+		ret = crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed);
+		ret |= crisv32_pinmux_alloc(PORT_E, 17, 17, pinmux_fixed);
+		hwprot.ata1 = regk_pinmux_yes;
+		break;
+	case pinmux_ata2:
+		ret = crisv32_pinmux_alloc(PORT_C, 11, 15, pinmux_fixed);
+		ret |= crisv32_pinmux_alloc(PORT_E, 3, 3, pinmux_fixed);
+		hwprot.ata2 = regk_pinmux_yes;
+		break;
+	case pinmux_ata3:
+		ret = crisv32_pinmux_alloc(PORT_C, 8, 10, pinmux_fixed);
+		ret |= crisv32_pinmux_alloc(PORT_C, 0, 2, pinmux_fixed);
+		hwprot.ata2 = regk_pinmux_yes;
+		break;
+	case pinmux_ata:
+		ret = crisv32_pinmux_alloc(PORT_B, 0, 15, pinmux_fixed);
+		ret |= crisv32_pinmux_alloc(PORT_D, 8, 15, pinmux_fixed);
+		hwprot.ata = regk_pinmux_yes;
+		break;
+	case pinmux_eth1:
+		ret = crisv32_pinmux_alloc(PORT_E, 0, 17, pinmux_fixed);
+		hwprot.eth1 = regk_pinmux_yes;
+		hwprot.eth1_mgm = regk_pinmux_yes;
+		break;
+	case pinmux_timer:
+		ret = crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed);
+		hwprot.timer = regk_pinmux_yes;
+		spin_unlock_irqrestore(&pinmux_lock, flags);
+		return ret;
+	}
+
+	if (!ret)
+		REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot);
+	else
+		memcpy(pins, saved, sizeof pins);
+
+	spin_unlock_irqrestore(&pinmux_lock, flags);
+
+	return ret;
+}
+
+void crisv32_pinmux_set(int port)
+{
+	int i;
+	int gpio_val = 0;
+	int iop_val = 0;
+
+	for (i = 0; i < PORT_PINS; i++) {
+		if (pins[port][i] == pinmux_gpio)
+			gpio_val |= (1 << i);
+		else if (pins[port][i] == pinmux_iop)
+			iop_val |= (1 << i);
+	}
+
+	REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_pb_gio + 8 * port,
+		  gpio_val);
+	REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_pb_iop + 8 * port,
+		  iop_val);
+
+#ifdef DEBUG
+	crisv32_pinmux_dump();
+#endif
+}
+
+int crisv32_pinmux_dealloc(int port, int first_pin, int last_pin)
+{
+	int i;
+	unsigned long flags;
+
+	crisv32_pinmux_init();
+
+	if (port > PORTS)
+		return -EINVAL;
+
+	spin_lock_irqsave(&pinmux_lock, flags);
+
+	for (i = first_pin; i <= last_pin; i++)
+		pins[port][i] = pinmux_none;
+
+	crisv32_pinmux_set(port);
+	spin_unlock_irqrestore(&pinmux_lock, flags);
+
+	return 0;
+}
+
+int crisv32_pinmux_dealloc_fixed(enum fixed_function function)
+{
+	int ret = -EINVAL;
+	char saved[sizeof pins];
+	unsigned long flags;
+
+	spin_lock_irqsave(&pinmux_lock, flags);
+
+	/* Save internal data for recovery */
+	memcpy(saved, pins, sizeof pins);
+
+	crisv32_pinmux_init();	/* Must be done before we read rw_hwprot */
+
+	reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot);
+
+	switch (function) {
+	case pinmux_ser1:
+		ret = crisv32_pinmux_dealloc(PORT_C, 4, 7);
+		hwprot.ser1 = regk_pinmux_no;
+		break;
+	case pinmux_ser2:
+		ret = crisv32_pinmux_dealloc(PORT_C, 8, 11);
+		hwprot.ser2 = regk_pinmux_no;
+		break;
+	case pinmux_ser3:
+		ret = crisv32_pinmux_dealloc(PORT_C, 12, 15);
+		hwprot.ser3 = regk_pinmux_no;
+		break;
+	case pinmux_sser0:
+		ret = crisv32_pinmux_dealloc(PORT_C, 0, 3);
+		ret |= crisv32_pinmux_dealloc(PORT_C, 16, 16);
+		hwprot.sser0 = regk_pinmux_no;
+		break;
+	case pinmux_sser1:
+		ret = crisv32_pinmux_dealloc(PORT_D, 0, 4);
+		hwprot.sser1 = regk_pinmux_no;
+		break;
+	case pinmux_ata0:
+		ret = crisv32_pinmux_dealloc(PORT_D, 5, 7);
+		ret |= crisv32_pinmux_dealloc(PORT_D, 15, 17);
+		hwprot.ata0 = regk_pinmux_no;
+		break;
+	case pinmux_ata1:
+		ret = crisv32_pinmux_dealloc(PORT_D, 0, 4);
+		ret |= crisv32_pinmux_dealloc(PORT_E, 17, 17);
+		hwprot.ata1 = regk_pinmux_no;
+		break;
+	case pinmux_ata2:
+		ret = crisv32_pinmux_dealloc(PORT_C, 11, 15);
+		ret |= crisv32_pinmux_dealloc(PORT_E, 3, 3);
+		hwprot.ata2 = regk_pinmux_no;
+		break;
+	case pinmux_ata3:
+		ret = crisv32_pinmux_dealloc(PORT_C, 8, 10);
+		ret |= crisv32_pinmux_dealloc(PORT_C, 0, 2);
+		hwprot.ata2 = regk_pinmux_no;
+		break;
+	case pinmux_ata:
+		ret = crisv32_pinmux_dealloc(PORT_B, 0, 15);
+		ret |= crisv32_pinmux_dealloc(PORT_D, 8, 15);
+		hwprot.ata = regk_pinmux_no;
+		break;
+	case pinmux_eth1:
+		ret = crisv32_pinmux_dealloc(PORT_E, 0, 17);
+		hwprot.eth1 = regk_pinmux_no;
+		hwprot.eth1_mgm = regk_pinmux_no;
+		break;
+	case pinmux_timer:
+		ret = crisv32_pinmux_dealloc(PORT_C, 16, 16);
+		hwprot.timer = regk_pinmux_no;
+		spin_unlock_irqrestore(&pinmux_lock, flags);
+		return ret;
+	}
+
+	if (!ret)
+		REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot);
+	else
+		memcpy(pins, saved, sizeof pins);
+
+	spin_unlock_irqrestore(&pinmux_lock, flags);
+
+	return ret;
+}
+
+void crisv32_pinmux_dump(void)
+{
+	int i, j;
+
+	crisv32_pinmux_init();
+
+	for (i = 0; i < PORTS; i++) {
+		printk(KERN_DEBUG "Port %c\n", 'B' + i);
+		for (j = 0; j < PORT_PINS; j++)
+			printk(KERN_DEBUG "  Pin %d = %d\n", j, pins[i][j]);
+	}
+}
+
+__initcall(crisv32_pinmux_init);
diff --git a/arch/cris/arch-v32/mach-fs/vcs_hook.c b/arch/cris/arch-v32/mach-fs/vcs_hook.c
new file mode 100644
index 000000000000..593b10f07ef1
--- /dev/null
+++ b/arch/cris/arch-v32/mach-fs/vcs_hook.c
@@ -0,0 +1,100 @@
+/*
+ * Call simulator hook. This is the part running in the
+ * simulated program.
+ */
+
+#include "vcs_hook.h"
+#include <stdarg.h>
+#include <asm/arch-v32/hwregs/reg_map.h>
+#include <asm/arch-v32/hwregs/intr_vect_defs.h>
+
+#define HOOK_TRIG_ADDR     0xb7000000	/* hook cvlog model reg address */
+#define HOOK_MEM_BASE_ADDR 0xa0000000	/* csp4 (shared mem) base addr */
+
+#define HOOK_DATA(offset) ((unsigned *)HOOK_MEM_BASE_ADDR)[offset]
+#define VHOOK_DATA(offset) ((volatile unsigned *)HOOK_MEM_BASE_ADDR)[offset]
+#define HOOK_TRIG(funcid) \
+	do { \
+		*((unsigned *) HOOK_TRIG_ADDR) = funcid; \
+	} while (0)
+#define HOOK_DATA_BYTE(offset) ((unsigned char *)HOOK_MEM_BASE_ADDR)[offset]
+
+int hook_call(unsigned id, unsigned pcnt, ...)
+{
+	va_list ap;
+	unsigned i;
+	unsigned ret;
+#ifdef USING_SOS
+	PREEMPT_OFF_SAVE();
+#endif
+
+	/* pass parameters */
+	HOOK_DATA(0) = id;
+
+	/* Have to make hook_print_str a special case since we call with a
+	 * parameter of byte type. Should perhaps be a separate
+	 * hook_call. */
+
+	if (id == hook_print_str) {
+		int i;
+		char *str;
+
+		HOOK_DATA(1) = pcnt;
+
+		va_start(ap, pcnt);
+		str = (char *)va_arg(ap, unsigned);
+
+		for (i = 0; i != pcnt; i++)
+			HOOK_DATA_BYTE(8 + i) = str[i];
+
+		HOOK_DATA_BYTE(8 + i) = 0;	/* null byte */
+	} else {
+		va_start(ap, pcnt);
+		for (i = 1; i <= pcnt; i++)
+			HOOK_DATA(i) = va_arg(ap, unsigned);
+		va_end(ap);
+	}
+
+	/* read from mem to make sure data has propagated to memory before
+	 * trigging */
+	ret = *((volatile unsigned *)HOOK_MEM_BASE_ADDR);
+
+	/* trigger hook */
+	HOOK_TRIG(id);
+
+	/* wait for call to finish */
+	while (VHOOK_DATA(0) > 0) ;
+
+	/* extract return value */
+
+	ret = VHOOK_DATA(1);
+
+#ifdef USING_SOS
+	PREEMPT_RESTORE();
+#endif
+	return ret;
+}
+
+unsigned hook_buf(unsigned i)
+{
+	return (HOOK_DATA(i));
+}
+
+void print_str(const char *str)
+{
+	int i;
+	/* find null at end of string */
+	for (i = 1; str[i]; i++) ;
+	hook_call(hook_print_str, i, str);
+}
+
+void CPU_KICK_DOG(void)
+{
+	(void)hook_call(hook_kick_dog, 0);
+}
+
+void CPU_WATCHDOG_TIMEOUT(unsigned t)
+{
+	(void)hook_call(hook_dog_timeout, 1, t);
+}
+
diff --git a/arch/cris/arch-v32/kernel/vcs_hook.h b/arch/cris/arch-v32/mach-fs/vcs_hook.h
index 7d73709e3cc6..c000b9fece41 100644
--- a/arch/cris/arch-v32/kernel/vcs_hook.h
+++ b/arch/cris/arch-v32/mach-fs/vcs_hook.h
@@ -1,11 +1,11 @@
-// $Id: vcs_hook.h,v 1.1 2003/08/12 12:01:06 starvik Exp $
-//
-// Call simulator hook functions
+/*
+ * Call simulator hook functions
+ */
 
 #ifndef HOOK_H
 #define HOOK_H
 
-int hook_call( unsigned id, unsigned pcnt, ...);
+int hook_call(unsigned id, unsigned pcnt, ...);
 
 enum hook_ids {
   hook_debug_on = 1,
diff --git a/arch/cris/arch-v32/mm/Makefile b/arch/cris/arch-v32/mm/Makefile
index 9146f88484b1..0b801f2964ac 100644
--- a/arch/cris/arch-v32/mm/Makefile
+++ b/arch/cris/arch-v32/mm/Makefile
@@ -1,3 +1,4 @@
 # Makefile for the Linux/cris parts of the memory manager.
 
-obj-y	 := mmu.o init.o tlb.o intmem.o
+obj-y	 += mmu.o init.o tlb.o intmem.o
+obj-$(CONFIG_ETRAX_L2CACHE)    += l2cache.o
diff --git a/arch/cris/arch-v32/mm/init.c b/arch/cris/arch-v32/mm/init.c
index a84ba7ff22d2..5a9ac5834647 100644
--- a/arch/cris/arch-v32/mm/init.c
+++ b/arch/cris/arch-v32/mm/init.c
@@ -65,7 +65,7 @@ cris_mmu_init(void)
 		       REG_STATE(mmu, rw_mm_cfg, seg_d, page)   |
 		       REG_STATE(mmu, rw_mm_cfg, seg_c, linear) |
 		       REG_STATE(mmu, rw_mm_cfg, seg_b, linear) |
-#ifndef CONFIG_ETRAXFS_SIM
+#ifndef CONFIG_ETRAX_VCS_SIM
                        REG_STATE(mmu, rw_mm_cfg, seg_a, page)   |
 #else
 		       REG_STATE(mmu, rw_mm_cfg, seg_a, linear) |
@@ -84,13 +84,9 @@ cris_mmu_init(void)
 	mmu_kbase_hi = ( REG_FIELD(mmu, rw_mm_kbase_hi, base_f, 0x0) |
 			 REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 0x8) |
 			 REG_FIELD(mmu, rw_mm_kbase_hi, base_d, 0x0) |
-#ifndef CONFIG_ETRAXFS_SIM
                          REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 0x4) |
-#else
-			 REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 0x0) |
-#endif
 			 REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb) |
-#ifndef CONFIG_ETRAXFS_SIM
+#ifndef CONFIG_ETRAX_VCS_SIM
 			 REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0x0) |
 #else
                          REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0xa) |
diff --git a/arch/cris/arch-v32/mm/intmem.c b/arch/cris/arch-v32/mm/intmem.c
index 41ee7f7997fd..9e8b69cdf19e 100644
--- a/arch/cris/arch-v32/mm/intmem.c
+++ b/arch/cris/arch-v32/mm/intmem.c
@@ -7,11 +7,17 @@
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <asm/io.h>
-#include <asm/arch/memmap.h>
+#include <memmap.h>
 
 #define STATUS_FREE 0
 #define STATUS_ALLOCATED 1
 
+#ifdef CONFIG_ETRAX_L2CACHE
+#define RESERVED_SIZE 66*1024
+#else
+#define RESERVED_SIZE 0
+#endif
+
 struct intmem_allocation {
 	struct list_head entry;
 	unsigned int size;
@@ -30,9 +36,10 @@ static void crisv32_intmem_init(void)
 		struct intmem_allocation* alloc =
 		  (struct intmem_allocation*)kmalloc(sizeof *alloc, GFP_KERNEL);
 		INIT_LIST_HEAD(&intmem_allocations);
-		intmem_virtual = ioremap(MEM_INTMEM_START, MEM_INTMEM_SIZE);
+		intmem_virtual = ioremap(MEM_INTMEM_START + RESERVED_SIZE,
+					 MEM_INTMEM_SIZE - RESERVED_SIZE);
 		initiated = 1;
-		alloc->size = MEM_INTMEM_SIZE;
+		alloc->size = MEM_INTMEM_SIZE - RESERVED_SIZE;
 		alloc->offset = 0;
 		alloc->status = STATUS_FREE;
 		list_add_tail(&alloc->entry, &intmem_allocations);
@@ -59,19 +66,23 @@ void* crisv32_intmem_alloc(unsigned size, unsigned align)
 					(struct intmem_allocation*)
 					kmalloc(sizeof *alloc, GFP_ATOMIC);
 				alloc->status = STATUS_FREE;
-				alloc->size = allocation->size - size - alignment;
-				alloc->offset = allocation->offset + size;
+				alloc->size = allocation->size - size -
+					alignment;
+				alloc->offset = allocation->offset + size +
+					alignment;
 				list_add(&alloc->entry, &allocation->entry);
 
 				if (alignment) {
-					struct intmem_allocation* tmp;
-					tmp = (struct intmem_allocation*)
-						kmalloc(sizeof *tmp, GFP_ATOMIC);
+					struct intmem_allocation *tmp;
+					tmp = (struct intmem_allocation *)
+						kmalloc(sizeof *tmp,
+							GFP_ATOMIC);
 					tmp->offset = allocation->offset;
 					tmp->size = alignment;
 					tmp->status = STATUS_FREE;
 					allocation->offset += alignment;
-					list_add_tail(&tmp->entry, &allocation->entry);
+					list_add_tail(&tmp->entry,
+						&allocation->entry);
 				}
 			}
 			allocation->status = STATUS_ALLOCATED;
@@ -96,22 +107,24 @@ void crisv32_intmem_free(void* addr)
 
 	list_for_each_entry_safe(allocation, tmp, &intmem_allocations, entry) {
 		if (allocation->offset == (int)(addr - intmem_virtual)) {
-			struct intmem_allocation* prev =
+			struct intmem_allocation *prev =
 			  list_entry(allocation->entry.prev,
 			             struct intmem_allocation, entry);
-			struct intmem_allocation* next =
+			struct intmem_allocation *next =
 			  list_entry(allocation->entry.next,
 				     struct intmem_allocation, entry);
 
 			allocation->status = STATUS_FREE;
 			/* Join with prev and/or next if also free */
-			if (prev->status == STATUS_FREE) {
+			if ((prev != &intmem_allocations) &&
+					(prev->status == STATUS_FREE)) {
 				prev->size += allocation->size;
 				list_del(&allocation->entry);
 				kfree(allocation);
 				allocation = prev;
 			}
-			if (next->status == STATUS_FREE) {
+			if ((next != &intmem_allocations) &&
+					(next->status == STATUS_FREE)) {
 				allocation->size += next->size;
 				list_del(&next->entry);
 				kfree(next);
@@ -125,15 +138,16 @@ void crisv32_intmem_free(void* addr)
 
 void* crisv32_intmem_phys_to_virt(unsigned long addr)
 {
-	return (void*)(addr - MEM_INTMEM_START+
-	               (unsigned long)intmem_virtual);
+	return (void *)(addr - (MEM_INTMEM_START + RESERVED_SIZE) +
+		(unsigned long)intmem_virtual);
 }
 
 unsigned long crisv32_intmem_virt_to_phys(void* addr)
 {
 	return (unsigned long)((unsigned long )addr -
-	  (unsigned long)intmem_virtual + MEM_INTMEM_START);
+		(unsigned long)intmem_virtual + MEM_INTMEM_START +
+		RESERVED_SIZE);
 }
 
-
+module_init(crisv32_intmem_init);
 
diff --git a/arch/cris/arch-v32/mm/l2cache.c b/arch/cris/arch-v32/mm/l2cache.c
new file mode 100644
index 000000000000..332ff10dcc6b
--- /dev/null
+++ b/arch/cris/arch-v32/mm/l2cache.c
@@ -0,0 +1,29 @@
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <memmap.h>
+#include <hwregs/reg_map.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/l2cache_defs.h>
+#include <asm/io.h>
+
+#define L2CACHE_SIZE 64
+
+int __init l2cache_init(void)
+{
+	reg_l2cache_rw_ctrl ctrl = {0};
+	reg_l2cache_rw_cfg cfg = {.en = regk_l2cache_yes};
+
+	ctrl.csize = L2CACHE_SIZE;
+	ctrl.cbase = L2CACHE_SIZE / 4 + (L2CACHE_SIZE % 4 ? 1 : 0);
+	REG_WR(l2cache, regi_l2cache, rw_ctrl, ctrl);
+
+	/* Flush the tag memory */
+	memset((void *)(MEM_INTMEM_START | MEM_NON_CACHEABLE), 0, 2*1024);
+
+	/* Enable the cache */
+	REG_WR(l2cache, regi_l2cache, rw_cfg, cfg);
+
+	return 0;
+}
+
diff --git a/arch/cris/arch-v32/mm/mmu.S b/arch/cris/arch-v32/mm/mmu.S
index 27b70e5006af..2238d154bde3 100644
--- a/arch/cris/arch-v32/mm/mmu.S
+++ b/arch/cris/arch-v32/mm/mmu.S
@@ -1,3 +1,5 @@
+; WARNING : The refill handler has been modified, see below !!!
+
 /*
  *  Copyright (C) 2003 Axis Communications AB
  *
@@ -61,6 +63,14 @@
 ; Note that the code is optimized to minimize stalls (makes the code harder
 ; to read).
 ;
+; WARNING !!!
+; Modified by Mikael Asker 060725: added a workaround for strange TLB
+; behavior. If the same PTE is present in more than one set, the TLB
+; doesn't recognize it and we get stuck in a loop of refill exceptions.
+; The workaround detects such loops and exits them by flushing
+; the TLB contents. The problem and workaround were verified
+; in VCS by Mikael Starvik.
+;
 ; Each page is 8 KB. Each PMD holds 8192/4 PTEs (each PTE is 4 bytes) so each
 ; PMD holds 16 MB of virtual memory.
 ;   Bits  0-12 : Offset within a page
@@ -68,6 +78,11 @@
 ;   Bits 24-31 : PMD offset within the PGD
 
 .macro MMU_REFILL_HANDLER handler, mmu
+	.data
+1:	.dword	0		; refill_count
+                                ;   == 0 <=> last_refill_cause is invalid
+2:	.dword	0		; last_refill_cause
+	.text
 	.globl \handler
 \handler:
 	subq	4, $sp
@@ -76,42 +91,96 @@
 	subq	4, $sp
 	move	\mmu, $srs	; Select MMU support register bank
 	move.d	$acr, [$sp]
-	subq	4, $sp
-	move.d	$r0, [$sp]
+	subq	12, $sp
+	move.d	1b, $acr        ; Point to refill_count
+	movem	$r2, [$sp]
+
+	test.d	[$acr]	        ; refill_count == 0 ?
+	beq	5f		;   yes, last_refill_cause is invalid
+        move.d	$acr, $r1
+
+	; last_refill_cause is valid, investigate cause
+        addq    4, $r1          ; Point to last_refill_cause
+	move	$s3, $r0	; Get rw_mm_cause
+	move.d	[$r1], $r2	; Get last_refill_cause
+	cmp.d	$r0, $r2	; rw_mm_cause == last_refill_cause ?
+	beq	6f		;   yes, increment count
+	moveq	1, $r2
+
+        ; rw_mm_cause != last_refill_cause
+	move.d	$r2, [$acr]	; refill_count = 1
+	move.d	$r0, [$r1]	; last_refill_cause = rw_mm_cause
+
+3:	; Probably not in a loop, continue normal processing
 #ifdef CONFIG_SMP
 	move    $s7, $acr	; PGD
 #else
 	move.d  per_cpu__current_pgd, $acr ; PGD
 #endif
 	; Look up PMD in PGD
-	move	$s3, $r0	; rw_mm_cause
 	lsrq	24, $r0	; Get PMD index into PGD (bit 24-31)
 	move.d  [$acr], $acr	; PGD for the current process
 	addi	$r0.d, $acr, $acr
 	move	$s3, $r0	; rw_mm_cause
 	move.d  [$acr], $acr	; Get PMD
-	beq	1f
+	beq	8f
 	; Look up PTE in PMD
 	lsrq	PAGE_SHIFT, $r0
 	and.w	PAGE_MASK, $acr	; Remove PMD flags
 	and.d	0x7ff, $r0	; Get PTE index into PMD (bit 13-23)
 	addi    $r0.d, $acr, $acr
 	move.d  [$acr], $acr	; Get PTE
-	beq	2f
-	move.d  [$sp+], $r0	; Pop r0 in delayslot
+	beq	9f
+	movem	[$sp], $r2	; Restore r0-r2 in delay slot
+	addq	12, $sp
 	; Store in TLB
 	move	$acr, $s5
-	; Return
+4:	; Return
 	move.d	[$sp+], $acr
-	move  	[$sp], $srs
+	move	[$sp], $srs
 	addq	4, $sp
 	rete
 	rfe
-1:	; PMD missing, let the mm subsystem fix it up.
-	move.d  [$sp+], $r0	; Pop r0
-2:      ; PTE missing, let the mm subsystem fix it up.
+
+5:      ; last_refill_cause is invalid
+	moveq	1, $r2
+        addq    4, $r1          ; Point to last_refill_cause
+	move.d	$r2, [$acr]	; refill_count = 1
+	move	$s3, $r0	; Get rw_mm_cause
+        ba      3b		; Continue normal processing
+	move.d	$r0,[$r1]	; last_refill_cause = rw_mm_cause
+
+6:      ; rw_mm_cause == last_refill_cause
+        move.d  [$acr], $r2     ; Get refill_count
+	cmpq	4, $r2		; refill_count > 4 ?
+	bhi	7f		;   yes
+	addq	1, $r2	        ; refill_count++
+	ba	3b		; Continue normal processing
+	move.d	$r2, [$acr]
+
+7:	; refill_count > 4, error
+	move.d	$acr, $r0       ; Save pointer to refill_count
+	clear.d	[$r0]		; refill_count = 0
+
+	;; rewind the short stack
+	movem	[$sp], $r2	; Restore r0-r2
+	addq	12, $sp
+	move.d	[$sp+], $acr
+	move	[$sp], $srs
+	addq	4, $sp
+	;; Keep it simple (slow), save all the regs.
+	SAVE_ALL
+	jsr	__flush_tlb_all
+	nop
+	ba	ret_from_intr	; Return
+	nop
+
+8:	; PMD missing, let the mm subsystem fix it up.
+	movem	[$sp], $r2	; Restore r0-r2
+9:      ; PTE missing, let the mm subsystem fix it up.
+	addq	12, $sp
 	move.d	[$sp+], $acr
-	move  	[$sp], $srs
+	move	[$sp], $srs
 	addq	4, $sp
 	SAVE_ALL
 	move    \mmu, $srs
diff --git a/arch/cris/arch-v32/mm/tlb.c b/arch/cris/arch-v32/mm/tlb.c
index a076ef6e9389..eda5ebcaea54 100644
--- a/arch/cris/arch-v32/mm/tlb.c
+++ b/arch/cris/arch-v32/mm/tlb.c
@@ -13,8 +13,8 @@
 #include <asm/arch/hwregs/supp_reg.h>
 
 #define UPDATE_TLB_SEL_IDX(val)					\
-do { 								\
-	unsigned long tlb_sel; 					\
+do {								\
+	unsigned long tlb_sel;					\
 								\
 	tlb_sel = REG_FIELD(mmu, rw_mm_tlb_sel, idx, val);	\
 	SUPP_REG_WR(RW_MM_TLB_SEL, tlb_sel);			\
@@ -30,8 +30,8 @@ do {						\
  * The TLB can host up to 256 different mm contexts at the same time. The running
  * context is found in the PID register. Each TLB entry contains a page_id that
  * has to match the PID register to give a hit. page_id_map keeps track of which
- * mm is assigned to which page_id, making sure it's known when to invalidate TLB
- * entries.
+ * mm's is assigned to which page_id's, making sure it's known when to
+ * invalidate TLB entries.
  *
  * The last page_id is never running, it is used as an invalid page_id so that
  * it's possible to make TLB entries that will nerver match.
@@ -179,29 +179,29 @@ void
 switch_mm(struct mm_struct *prev, struct mm_struct *next,
 	  struct task_struct *tsk)
 {
-	int cpu = smp_processor_id();
-
-	/* Make sure there is a MMU context. */
-	spin_lock(&mmu_context_lock);
-	get_mmu_context(next);
-	cpu_set(cpu, next->cpu_vm_mask);
-	spin_unlock(&mmu_context_lock);
-
-	/*
-	 * Remember the pgd for the fault handlers. Keep a separate copy of it
-	 * because current and active_mm might be invalid at points where
-	 * there's still a need to derefer the pgd.
-	 */
-	per_cpu(current_pgd, cpu) = next->pgd;
-
-	/* Switch context in the MMU. */
-        if (tsk && task_thread_info(tsk))
-        {
-          SPEC_REG_WR(SPEC_REG_PID, next->context.page_id | task_thread_info(tsk)->tls);
-        }
-        else
-        {
-          SPEC_REG_WR(SPEC_REG_PID, next->context.page_id);
-        }
+	if (prev != next) {
+		int cpu = smp_processor_id();
+
+		/* Make sure there is a MMU context. */
+		spin_lock(&mmu_context_lock);
+		get_mmu_context(next);
+		cpu_set(cpu, next->cpu_vm_mask);
+		spin_unlock(&mmu_context_lock);
+
+		/*
+		 * Remember the pgd for the fault handlers. Keep a seperate
+		 * copy of it because current and active_mm might be invalid
+		 * at points where * there's still a need to derefer the pgd.
+		 */
+		per_cpu(current_pgd, cpu) = next->pgd;
+
+		/* Switch context in the MMU. */
+		if (tsk && task_thread_info(tsk)) {
+			SPEC_REG_WR(SPEC_REG_PID, next->context.page_id |
+				task_thread_info(tsk)->tls);
+		} else {
+			SPEC_REG_WR(SPEC_REG_PID, next->context.page_id);
+		}
+	}
 }
 
diff --git a/arch/cris/arch-v32/vmlinux.lds.S b/arch/cris/arch-v32/vmlinux.lds.S
index fead8c59ea63..d5f28e40717c 100644
--- a/arch/cris/arch-v32/vmlinux.lds.S
+++ b/arch/cris/arch-v32/vmlinux.lds.S
@@ -9,6 +9,13 @@
  */
 
 #include <asm-generic/vmlinux.lds.h>
+#include <asm/page.h>
+
+#ifdef CONFIG_ETRAX_VMEM_SIZE
+#define __CONFIG_ETRAX_VMEM_SIZE CONFIG_ETRAX_VMEM_SIZE
+#else
+#define __CONFIG_ETRAX_VMEM_SIZE 0
+#endif
 
 jiffies = jiffies_64;
 SECTIONS
@@ -17,18 +24,19 @@ SECTIONS
 	dram_start = .;
 	ebp_start = .;
 
-	/* The boot section is only necessary until the VCS top level testbench */
-	/* includes both flash and DRAM. */
+	/* The boot section is only necessary until the VCS top */
+	/* level testbench includes both flash and DRAM. */
 	.boot : { *(.boot) }
 
-	. = DRAM_VIRTUAL_BASE + 0x4000;		/* See head.S and pages reserved at the start. */
+	/* See head.S and pages reserved at the start. */
+	. = DRAM_VIRTUAL_BASE + 0x4000;
 
 	_text = .;		/* Text and read-only data. */
 	text_start = .;		/* Lots of aliases. */
 	_stext = .;
 	__stext = .;
 	.text : {
-		*(.text)
+		TEXT_TEXT
 		SCHED_TEXT
 		LOCK_TEXT
 		*(.fixup)
@@ -39,9 +47,9 @@ SECTIONS
 	__etext = .;
 
 	. = ALIGN(4);		/* Exception table. */
-  	__start___ex_table = .;
-  	__ex_table : { *(__ex_table) }
-  	__stop___ex_table = .;
+	__start___ex_table = .;
+	__ex_table : { *(__ex_table) }
+	__stop___ex_table = .;
 
 	RODATA
 
@@ -54,33 +62,27 @@ SECTIONS
 	__edata = . ;		/* End of data section. */
 	_edata = . ;
 
-	. = ALIGN(8192);	/* init_task and stack, must be aligned. */
-  	.data.init_task : { *(.data.init_task) }
+	. = ALIGN(PAGE_SIZE);	/* init_task and stack, must be aligned. */
+	.data.init_task : { *(.data.init_task) }
 
-  	. = ALIGN(8192);	/* Init code and data. */
-  	__init_begin = .;
+	. = ALIGN(PAGE_SIZE);	/* 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 = .;
+	. = ALIGN(16);
+	__setup_start = .;
+	.init.setup : { *(.init.setup) }
+	__setup_end = .;
 	__start___param = .;
 	__param : { *(__param) }
 	__stop___param = .;
-  	.initcall.init : {
+	.initcall.init : {
 		__initcall_start = .;
-		*(.initcall1.init);
-		*(.initcall2.init);
-		*(.initcall3.init);
-		*(.initcall4.init);
-		*(.initcall5.init);
-		*(.initcall6.init);
-		*(.initcall7.init);
+		INITCALLS
 		__initcall_end = .;
 	}
 
@@ -91,25 +93,23 @@ SECTIONS
 	}
 	SECURITY_INIT
 
-	PERCPU(8192)
+	__vmlinux_end = .;	/* Last address of the physical file. */
+	PERCPU(PAGE_SIZE)
 
-#ifdef CONFIG_BLK_DEV_INITRD
 	.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);
 	}
-#endif
 
-	__vmlinux_end = .;	/* Last address of the physical file. */
-  	__init_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.
+	 */
+	. = ALIGN (PAGE_SIZE);
+
+	__init_end = .;
 
 	__data_end = . ;	/* Move to _edata? */
 	__bss_start = .;	/* BSS. */
@@ -123,11 +123,11 @@ SECTIONS
 	__end = .;
 
 	/* Sections to be discarded */
-  	/DISCARD/ : {
+	/DISCARD/ : {
 		EXIT_TEXT
 		EXIT_DATA
 		*(.exitcall.exit)
         }
 
-	dram_end = dram_start + CONFIG_ETRAX_DRAM_SIZE*1024*1024;
+	dram_end = dram_start + (CONFIG_ETRAX_DRAM_SIZE - __CONFIG_ETRAX_VMEM_SIZE)*1024*1024;
 }
diff --git a/arch/cris/artpec_3_defconfig b/arch/cris/artpec_3_defconfig
new file mode 100644
index 000000000000..41fe67409aab
--- /dev/null
+++ b/arch/cris/artpec_3_defconfig
@@ -0,0 +1,582 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.24-rc3
+# Mon Dec  3 11:18:54 2007
+#
+CONFIG_MMU=y
+CONFIG_ZONE_DMA=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_IOMAP=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NO_IOPORT=y
+CONFIG_FORCE_MAX_ZONEORDER=6
+CONFIG_CRIS=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+# CONFIG_SYSVIPC is not set
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_MODULES is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
+# General setup
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_ETRAX_CMDLINE="root=/dev/mtdblock3 init=/linuxrc"
+# CONFIG_ETRAX_WATCHDOG is not set
+CONFIG_ETRAX_FAST_TIMER=y
+# CONFIG_ETRAX_KMALLOCED_MODULES is not set
+# CONFIG_OOM_REBOOT is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+
+#
+# Hardware setup
+#
+# CONFIG_ETRAX100LX is not set
+# CONFIG_ETRAX100LX_V2 is not set
+# CONFIG_SVINTO_SIM is not set
+# CONFIG_ETRAXFS is not set
+CONFIG_CRIS_MACH_ARTPEC3=y
+# CONFIG_ETRAX_VCS_SIM is not set
+# CONFIG_ETRAX_ARCH_V10 is not set
+CONFIG_ETRAX_ARCH_V32=y
+CONFIG_ETRAX_DRAM_SIZE=32
+CONFIG_ETRAX_VMEM_SIZE=8
+CONFIG_ETRAX_FLASH_BUSWIDTH=2
+CONFIG_ETRAX_NANDFLASH_BUSWIDTH=1
+CONFIG_ETRAX_FLASH1_SIZE=4
+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_DEBUG_PORT_NULL is not set
+CONFIG_ETRAX_DRAM_VIRTUAL_BASE=c0000000
+CONFIG_ETRAX_SERIAL_PORTS=5
+CONFIG_ETRAX_DEF_GIO_PA_OE=1c
+CONFIG_ETRAX_DEF_GIO_PA_OUT=00
+CONFIG_ETRAX_DEF_GIO_PB_OE=00000
+CONFIG_ETRAX_DEF_GIO_PB_OUT=00000
+CONFIG_ETRAX_DEF_GIO_PC_OE=00000
+CONFIG_ETRAX_DEF_GIO_PC_OUT=00000
+
+#
+# Artpec-3 options
+#
+CONFIG_ETRAX_L2CACHE=y
+CONFIG_ETRAX_DDR=y
+CONFIG_ETRAX_DDR2_MRS=0
+CONFIG_ETRAX_DDR2_TIMING=0
+CONFIG_ETRAX_DDR2_CONFIG=0
+CONFIG_ETRAX_PIO_CE0_CFG=0
+CONFIG_ETRAX_PIO_CE1_CFG=0
+CONFIG_ETRAX_PIO_CE2_CFG=0
+# CONFIG_CPU_FREQ is not set
+# CONFIG_ETRAX_NBR_LED_GRP_ZERO is not set
+CONFIG_ETRAX_NBR_LED_GRP_ONE=y
+# CONFIG_ETRAX_NBR_LED_GRP_TWO is not set
+CONFIG_ETRAX_LED_G_NET0="PA3"
+CONFIG_ETRAX_LED_R_NET0="PA4"
+CONFIG_ETRAX_V32_LED2G="PA5"
+CONFIG_ETRAX_V32_LED2R="PA6"
+CONFIG_ETRAX_V32_LED3G="PA7"
+CONFIG_ETRAX_V32_LED3R="PA7"
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NF_CONNTRACK_ENABLED is not set
+# CONFIG_NF_CONNTRACK is not set
+# CONFIG_NETFILTER_XTABLES is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Drivers for built-in interfaces
+#
+CONFIG_ETRAX_ETHERNET=y
+# CONFIG_ETRAX_IDE is not set
+CONFIG_ETRAX_AXISFLASHMAP=y
+CONFIG_ETRAX_PTABLE_SECTOR=65536
+# CONFIG_ETRAX_I2C is not set
+# CONFIG_ETRAX_GPIO is not set
+# CONFIG_ETRAX_NO_PHY is not set
+# CONFIG_ETRAX_ETHERNET_IFACE0 is not set
+# CONFIG_ETRAX_ETHERNET_GBIT is not set
+# CONFIG_ETRAXFS_SERIAL is not set
+# CONFIG_ETRAX_SYNCHRONOUS_SERIAL is not set
+# CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE is not set
+# CONFIG_ETRAX_NANDFLASH is not set
+# CONFIG_ETRAX_CARDBUS is not set
+# CONFIG_ETRAX_IOP_FW_LOAD is not set
+# CONFIG_ETRAX_STREAMCOPROC is not set
+# CONFIG_ETRAX_SPI_MMC is not set
+# CONFIG_ETRAX_SPI_MMC_BOARD is not set
+# CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK is not set
+CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY=y
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_RAM=y
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+CONFIG_MTD_MTDRAM=y
+CONFIG_MTDRAM_TOTAL_SIZE=0
+CONFIG_MTDRAM_ERASE_SIZE=64
+CONFIG_MTDRAM_ABS_POS=0x0
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_RTC_CLASS is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+CONFIG_HW_RANDOM=y
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PROFILING is not set
+# CONFIG_SYSTEM_PROFILER is not set
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SAMPLES is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_DMA=y
diff --git a/arch/cris/defconfig b/arch/cris/defconfig
index 9c33ae659934..59f36a58f842 100644
--- a/arch/cris/defconfig
+++ b/arch/cris/defconfig
@@ -1,52 +1,91 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11
-# Mon Jun 20 13:42:02 2005
+# Linux kernel version: 2.6.24-rc3
+# Mon Dec  3 11:34:27 2007
 #
 CONFIG_MMU=y
-CONFIG_UID16=y
+CONFIG_ZONE_DMA=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_IOMAP=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NO_IOPORT=y
+CONFIG_FORCE_MAX_ZONEORDER=6
 CONFIG_CRIS=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
-
-#
-# General setup
-#
+CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
 # CONFIG_SWAP is not set
 # CONFIG_SYSVIPC is not set
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
 CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
 # CONFIG_KALLSYMS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_MODULES is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
 
 #
-# Loadable module support
+# IO Schedulers
 #
-# CONFIG_MODULES is not set
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
 
 #
 # General setup
@@ -54,12 +93,27 @@ CONFIG_CC_ALIGN_JUMPS=0
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 CONFIG_GENERIC_HARDIRQS=y
-# CONFIG_SMP is not set
 CONFIG_ETRAX_CMDLINE="root=/dev/mtdblock3 init=/linuxrc"
 # CONFIG_ETRAX_WATCHDOG is not set
 CONFIG_ETRAX_FAST_TIMER=y
-# CONFIG_PREEMPT is not set
+# CONFIG_ETRAX_KMALLOCED_MODULES is not set
 # CONFIG_OOM_REBOOT is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
 
 #
 # Hardware setup
@@ -68,127 +122,180 @@ CONFIG_ETRAX_FAST_TIMER=y
 CONFIG_ETRAX100LX_V2=y
 # CONFIG_SVINTO_SIM is not set
 # CONFIG_ETRAXFS is not set
-# CONFIG_ETRAXFS_SIM is not set
+# CONFIG_CRIS_MACH_ARTPEC3 is not set
+# CONFIG_ETRAX_VCS_SIM is not set
 CONFIG_ETRAX_ARCH_V10=y
 # CONFIG_ETRAX_ARCH_V32 is not set
 CONFIG_ETRAX_DRAM_SIZE=32
 CONFIG_ETRAX_FLASH_BUSWIDTH=2
+CONFIG_ETRAX_NANDFLASH_BUSWIDTH=1
 CONFIG_ETRAX_FLASH1_SIZE=4
+# CONFIG_ETRAX_DEBUG_PORT0 is not set
+# CONFIG_ETRAX_DEBUG_PORT1 is not set
+# CONFIG_ETRAX_DEBUG_PORT2 is not set
+# CONFIG_ETRAX_DEBUG_PORT3 is not set
+CONFIG_ETRAX_DEBUG_PORT_NULL=y
+
+#
+# CRIS v10 options
+#
 CONFIG_ETRAX_DRAM_VIRTUAL_BASE=c0000000
 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=3
-CONFIG_ETRAX_LED2R=3
+CONFIG_ETRAX_LED1R=3
+CONFIG_ETRAX_LED2G=4
+CONFIG_ETRAX_LED2R=5
 CONFIG_ETRAX_LED3G=2
 CONFIG_ETRAX_LED3R=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_DEBUG_PORT_NULL 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=0x95a6
-CONFIG_ETRAX_DEF_R_BUS_CONFIG=0x4
-CONFIG_ETRAX_SDRAM=y
-CONFIG_ETRAX_DEF_R_SDRAM_CONFIG=0x09e05757
-CONFIG_ETRAX_DEF_R_SDRAM_TIMING=0x80008002
-CONFIG_ETRAX_DEF_R_PORT_PA_DIR=0x1d
-CONFIG_ETRAX_DEF_R_PORT_PA_DATA=0x00
-CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG=0x00
-CONFIG_ETRAX_DEF_R_PORT_PB_DIR=0x1e
-CONFIG_ETRAX_DEF_R_PORT_PB_DATA=0xf3
+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=1c
+CONFIG_ETRAX_DEF_R_PORT_PA_DATA=00
+CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG=00
+CONFIG_ETRAX_DEF_R_PORT_PB_DIR=00
+CONFIG_ETRAX_DEF_R_PORT_PB_DATA=ff
 # CONFIG_ETRAX_SOFT_SHUTDOWN is not set
 
 #
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NF_CONNTRACK_ENABLED is not set
+# CONFIG_NF_CONNTRACK is not set
+# CONFIG_NETFILTER_XTABLES is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
 # Drivers for built-in interfaces
 #
 CONFIG_ETRAX_ETHERNET=y
-# CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK is not set
-CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY=y
 CONFIG_ETRAX_SERIAL=y
 # CONFIG_ETRAX_SERIAL_FAST_TIMER is not set
 # CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST is not set
 CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS=5
-CONFIG_ETRAX_SERIAL_PORT0=y
-# CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_OUT is not set
-CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT=y
-# CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_IN is not set
-CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN=y
-CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_NONE=y
-# CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PA is not set
-# CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB is not set
-# CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED is not set
-CONFIG_ETRAX_SER0_DTR_ON_PA_BIT=-1
-CONFIG_ETRAX_SER0_RI_ON_PA_BIT=-1
-CONFIG_ETRAX_SER0_DSR_ON_PA_BIT=-1
-CONFIG_ETRAX_SER0_CD_ON_PA_BIT=-1
-CONFIG_ETRAX_SER0_DTR_ON_PB_BIT=-1
-CONFIG_ETRAX_SER0_RI_ON_PB_BIT=-1
-CONFIG_ETRAX_SER0_DSR_ON_PB_BIT=-1
-CONFIG_ETRAX_SER0_CD_ON_PB_BIT=-1
+# CONFIG_ETRAX_SERIAL_PORT0 is not set
 # CONFIG_ETRAX_SERIAL_PORT1 is not set
-CONFIG_ETRAX_SERIAL_PORT2=y
-# CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_OUT is not set
-CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT=y
-# CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_IN is not set
-CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN=y
-CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_NONE=y
-# CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA is not set
-# CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PB is not set
-# CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED is not set
-CONFIG_ETRAX_SER2_DTR_ON_PA_BIT=-1
-CONFIG_ETRAX_SER2_RI_ON_PA_BIT=-1
-CONFIG_ETRAX_SER2_DSR_ON_PA_BIT=-1
-CONFIG_ETRAX_SER2_CD_ON_PA_BIT=-1
-CONFIG_ETRAX_SER2_DTR_ON_PB_BIT=-1
-CONFIG_ETRAX_SER2_RI_ON_PB_BIT=-1
-CONFIG_ETRAX_SER2_DSR_ON_PB_BIT=-1
-CONFIG_ETRAX_SER2_CD_ON_PB_BIT=-1
+# CONFIG_ETRAX_SERIAL_PORT2 is not set
 # CONFIG_ETRAX_SERIAL_PORT3 is not set
-CONFIG_ETRAX_RS485=y
-# CONFIG_ETRAX_RS485_ON_PA is not set
-# CONFIG_ETRAX_RS485_DISABLE_RECEIVER is not set
-CONFIG_ETRAX_IDE=y
-CONFIG_ETRAX_IDE_DELAY=15
-CONFIG_ETRAX_IDE_PB7_RESET=y
-# CONFIG_ETRAX_IDE_G27_RESET is not set
-CONFIG_ETRAX_USB_HOST=y
-CONFIG_ETRAX_USB_HOST_PORT1=y
-CONFIG_ETRAX_USB_HOST_PORT2=y
+# CONFIG_ETRAX_RS485 is not set
+# CONFIG_ETRAX_IDE is not set
+# CONFIG_ETRAX_USB_HOST is not set
 CONFIG_ETRAX_AXISFLASHMAP=y
 CONFIG_ETRAX_PTABLE_SECTOR=65536
 # CONFIG_ETRAX_I2C is not set
 # CONFIG_ETRAX_GPIO is not set
-CONFIG_ETRAX_RTC=y
-CONFIG_ETRAX_DS1302=y
-# CONFIG_ETRAX_PCF8563 is not set
-CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT=y
-CONFIG_ETRAX_DS1302_RSTBIT=0
-CONFIG_ETRAX_DS1302_SCLBIT=1
-CONFIG_ETRAX_DS1302_SDABIT=0
-CONFIG_ETRAX_DS1302_TRICKLE_CHARGE=0
+# CONFIG_ETRAX_RTC is not set
+# CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK is not set
+CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY=y
 
 #
 # Generic Driver Options
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
-
-#
-# Memory Technology Devices (MTD)
-#
+# CONFIG_SYS_HYPERVISOR is not set
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
 # CONFIG_MTD_CMDLINE_PARTS is not set
 
@@ -196,16 +303,20 @@ CONFIG_MTD_CONCAT=y
 # User Modules And Translation Layers
 #
 CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
 CONFIG_MTD_BLOCK=y
 # CONFIG_FTL is not set
 # CONFIG_NFTL is not set
 # CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
 
 #
 # RAM/ROM/Flash chip drivers
 #
 CONFIG_MTD_CFI=y
-# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_JEDECPROBE=y
 CONFIG_MTD_GEN_PROBE=y
 # CONFIG_MTD_CFI_ADV_OPTIONS is not set
 CONFIG_MTD_MAP_BANK_WIDTH_1=y
@@ -220,20 +331,18 @@ CONFIG_MTD_CFI_I2=y
 # CONFIG_MTD_CFI_I8 is not set
 # CONFIG_MTD_CFI_INTELEXT is not set
 CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_CFI_AMDSTD_RETRY=0
 # CONFIG_MTD_CFI_STAA is not set
 CONFIG_MTD_CFI_UTIL=y
 CONFIG_MTD_RAM=y
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_SHARP is not set
-# CONFIG_MTD_JEDEC is not set
 
 #
 # Mapping drivers for chip access
 #
 CONFIG_MTD_COMPLEX_MAPPINGS=y
 # CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PLATRAM is not set
 
 #
 # Self-contained MTD device drivers
@@ -244,7 +353,6 @@ CONFIG_MTD_MTDRAM=y
 CONFIG_MTDRAM_TOTAL_SIZE=0
 CONFIG_MTDRAM_ERASE_SIZE=64
 CONFIG_MTDRAM_ABS_POS=0x0
-# CONFIG_MTD_BLKMTD is not set
 # CONFIG_MTD_BLOCK2MTD is not set
 
 #
@@ -253,216 +361,54 @@ CONFIG_MTDRAM_ABS_POS=0x0
 # CONFIG_MTD_DOC2000 is not set
 # CONFIG_MTD_DOC2001 is not set
 # CONFIG_MTD_DOC2001PLUS is not set
-
-#
-# NAND Flash Device Drivers
-#
 # CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
 
 #
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
+# UBI - Unsorted block images
 #
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
+# CONFIG_MTD_UBI is not set
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_UB is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
-# CONFIG_BLK_DEV_INITRD is not set
-CONFIG_INITRAMFS_SOURCE=""
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 # CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-# CONFIG_IOSCHED_AS is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-CONFIG_IOSCHED_CFQ=y
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-# CONFIG_PARIDE is not set
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_IDE_SATA is not set
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_IDE_GENERIC is not set
-# CONFIG_IDE_ARM is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-# CONFIG_ISCSI_TCP is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-
-#
-# I2O device support
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-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_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-
-#
-# IP: Virtual Server Configuration
-#
-# CONFIG_IP_VS is not set
-# CONFIG_IPV6 is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-
-#
-# IP: Netfilter Configuration
-#
-# CONFIG_IP_NF_CONNTRACK is not set
-# CONFIG_IP_NF_CONNTRACK_MARK is not set
-# CONFIG_IP_NF_QUEUE is not set
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_ARPTABLES is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_AF_RXRPC is not set
-# CONFIG_AF_RXRPC_DEBUG is not set
-# CONFIG_BT is not set
-# CONFIG_I2C is not set
-
 CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
+# CONFIG_VETH is not set
+# CONFIG_PHYLIB is not set
 CONFIG_NET_ETHERNET=y
-# CONFIG_MII is not set
+CONFIG_MII=y
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
 
 #
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-
-#
-# Token Ring devices
-#
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Wan interfaces
+# Wireless LAN
 #
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
 # CONFIG_WAN is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
 # CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_RTC_CLASS is not set
 
 #
 # Input device support
@@ -470,7 +416,7 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_INPUT is not set
 
 #
-# Input I/O drivers
+# Hardware I/O ports
 #
 CONFIG_SERIO=y
 # CONFIG_SERIO_I8042 is not set
@@ -480,94 +426,39 @@ CONFIG_SERIO=y
 # CONFIG_GAMEPORT is not set
 
 #
-# Input Device Drivers
-#
-CONFIG_INPUT_KEYBOARD=y
-CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
-# CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
-# CONFIG_KEYBOARD_NEWTON is not set
-CONFIG_INPUT_MOUSE=y
-CONFIG_MOUSE_PS2=y
-# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_MOUSE_VSXXXAA is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TABLET is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
 # Character devices
 #
 # CONFIG_VT is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
 # CONFIG_RTC is not set
 # CONFIG_GEN_RTC is not set
-# CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
-# CONFIG_RTC_LIB is not set
-# CONFIG_RTC_CLASS is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
 #
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
 # File systems
 #
 # CONFIG_EXT2_FS is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
+# CONFIG_EXT4DEV_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
-
-#
-# XFS support
-#
+# CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
 # CONFIG_QUOTA is not set
 CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
 
 #
 # CD-ROM/DVD Filesystems
@@ -587,13 +478,12 @@ CONFIG_DNOTIFY=y
 #
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
-# CONFIG_TMPFS_XATTR is not set
+# CONFIG_TMPFS_POSIX_ACL is not set
 # CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -605,15 +495,15 @@ CONFIG_RAMFS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-CONFIG_JFFS_FS=y
-CONFIG_JFFS_FS_VERBOSE=0
-# CONFIG_JFFS_PROC_FS is not set
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
-# CONFIG_JFFS2_FS_NAND is not set
-# CONFIG_JFFS2_FS_NOR_ECC is not set
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
 # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
 CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
 CONFIG_CRAMFS=y
@@ -622,12 +512,10 @@ CONFIG_CRAMFS=y
 # CONFIG_QNX4FS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
+CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
 # CONFIG_NFS_V4 is not set
 # CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
@@ -649,181 +537,44 @@ CONFIG_SUNRPC=y
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
 # CONFIG_NLS is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Generic devices
-#
-# CONFIG_SND_MPU401_UART is not set
-# CONFIG_SND_DUMMY is not set
-# CONFIG_SND_VIRMIDI is not set
-# CONFIG_SND_MTPAV is not set
-# CONFIG_SND_SERIAL_U16550 is not set
-# CONFIG_SND_MPU401 is not set
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-# CONFIG_PCCARD is not set
-# CONFIG_PARPORT_PC_PCMCIA is not set
-# CONFIG_NET_PCMCIA is not set
-
-#
-# PC-card bridges
-#
-
-#
-# USB support
-#
-CONFIG_USB=y
-# CONFIG_USB_DEBUG is not set
-
-#
-# Miscellaneous USB options
-#
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_BANDWIDTH is not set
-# CONFIG_USB_DYNAMIC_MINORS is not set
-# CONFIG_USB_OTG is not set
-# CONFIG_USB_ARCH_HAS_HCD is not set
-# CONFIG_USB_ARCH_HAS_OHCI is not set
-
-#
-# USB Host Controller Drivers
-#
-# CONFIG_USB_SL811_HCD is not set
-
-#
-# USB Device Class drivers
-#
-
-#
-# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem
-#
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-# CONFIG_USB_STORAGE is not set
-
-#
-# USB Input Devices
-#
-# CONFIG_USB_HID is not set
-# HID_SUPPORT is not set
-
-#
-# USB HID Boot Protocol drivers
-#
-# CONFIG_USB_KBD is not set
-# CONFIG_USB_MOUSE is not set
-# CONFIG_USB_AIPTEK is not set
-# CONFIG_USB_WACOM is not set
-# CONFIG_USB_KBTAB is not set
-# CONFIG_USB_POWERMATE is not set
-# CONFIG_USB_MTOUCH is not set
-# CONFIG_USB_EGALAX is not set
-# CONFIG_USB_XPAD is not set
-# CONFIG_USB_ATI_REMOTE is not set
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_MDC800 is not set
-
-#
-# USB Multimedia devices
-#
-# CONFIG_USB_DABUSB is not set
-
-#
-# Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network Adapters
-#
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
-CONFIG_USB_RTL8150=y
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_EMI62 is not set
-# CONFIG_USB_EMI26 is not set
-# CONFIG_USB_AUERSWALD is not set
-# CONFIG_USB_RIO500 is not set
-# CONFIG_USB_LEGOTOWER is not set
-# CONFIG_USB_LCD is not set
-# CONFIG_USB_LED is not set
-# CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGETKIT is not set
-# CONFIG_USB_PHIDGETSERVO is not set
-# CONFIG_USB_IDMOUSE is not set
-# CONFIG_USB_TEST is not set
-
-#
-# USB ATM/DSL drivers
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
+# CONFIG_DLM is not set
 
 #
 # Kernel hacking
 #
 # CONFIG_PROFILING is not set
 # CONFIG_SYSTEM_PROFILER is not set
-# CONFIG_ETRAX_KGDB is not set
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_FRAME_POINTER is not set
-# CONFIG_DEBUG_NMI_OOPS is not set
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SAMPLES is not set
 
 #
 # Security options
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
 # CONFIG_CRYPTO is not set
 
 #
-# Hardware crypto devices
-# CONFIG_CRYPTO_HW is not set
-
-#
 # Library routines
 #
+CONFIG_BITREVERSE=y
 # CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_DMA=y
diff --git a/arch/cris/etraxfs_defconfig b/arch/cris/etraxfs_defconfig
new file mode 100644
index 000000000000..73c646a37255
--- /dev/null
+++ b/arch/cris/etraxfs_defconfig
@@ -0,0 +1,585 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.24-rc3
+# Fri Nov 30 14:24:26 2007
+#
+CONFIG_MMU=y
+CONFIG_ZONE_DMA=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_IOMAP=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NO_IOPORT=y
+CONFIG_FORCE_MAX_ZONEORDER=6
+CONFIG_CRIS=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+# CONFIG_SYSVIPC is not set
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_MODULES is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
+# General setup
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_ETRAX_CMDLINE="root=/dev/mtdblock3 init=/linuxrc"
+# CONFIG_ETRAX_WATCHDOG is not set
+CONFIG_ETRAX_FAST_TIMER=y
+# CONFIG_ETRAX_KMALLOCED_MODULES is not set
+# CONFIG_OOM_REBOOT is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+
+#
+# Hardware setup
+#
+# CONFIG_ETRAX100LX is not set
+# CONFIG_ETRAX100LX_V2 is not set
+# CONFIG_SVINTO_SIM is not set
+CONFIG_ETRAXFS=y
+# CONFIG_CRIS_MACH_ARTPEC3 is not set
+# CONFIG_ETRAX_VCS_SIM is not set
+# CONFIG_ETRAX_ARCH_V10 is not set
+CONFIG_ETRAX_ARCH_V32=y
+CONFIG_ETRAX_DRAM_SIZE=32
+CONFIG_ETRAX_FLASH_BUSWIDTH=2
+CONFIG_ETRAX_NANDFLASH_BUSWIDTH=1
+CONFIG_ETRAX_FLASH1_SIZE=4
+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_DEBUG_PORT_NULL is not set
+CONFIG_ETRAX_DRAM_VIRTUAL_BASE=c0000000
+
+#
+# ETRAX FS options
+#
+CONFIG_ETRAX_SERIAL_PORTS=4
+CONFIG_ETRAX_MEM_GRP1_CONFIG=4044a
+CONFIG_ETRAX_MEM_GRP2_CONFIG=0
+CONFIG_ETRAX_MEM_GRP3_CONFIG=0
+CONFIG_ETRAX_MEM_GRP4_CONFIG=0
+CONFIG_ETRAX_SDRAM_GRP0_CONFIG=336
+CONFIG_ETRAX_SDRAM_GRP1_CONFIG=0
+CONFIG_ETRAX_SDRAM_TIMING=104a
+CONFIG_ETRAX_SDRAM_COMMAND=0
+CONFIG_ETRAX_DEF_GIO_PA_OE=1c
+CONFIG_ETRAX_DEF_GIO_PA_OUT=00
+CONFIG_ETRAX_DEF_GIO_PB_OE=00000
+CONFIG_ETRAX_DEF_GIO_PB_OUT=00000
+CONFIG_ETRAX_DEF_GIO_PC_OE=00000
+CONFIG_ETRAX_DEF_GIO_PC_OUT=00000
+CONFIG_ETRAX_DEF_GIO_PD_OE=00000
+CONFIG_ETRAX_DEF_GIO_PD_OUT=00000
+CONFIG_ETRAX_DEF_GIO_PE_OE=00000
+CONFIG_ETRAX_DEF_GIO_PE_OUT=00000
+# CONFIG_CPU_FREQ is not set
+# CONFIG_ETRAX_NBR_LED_GRP_ZERO is not set
+CONFIG_ETRAX_NBR_LED_GRP_ONE=y
+# CONFIG_ETRAX_NBR_LED_GRP_TWO is not set
+CONFIG_ETRAX_LED_G_NET0="PA3"
+CONFIG_ETRAX_LED_R_NET0="PA4"
+CONFIG_ETRAX_V32_LED2G="PA5"
+CONFIG_ETRAX_V32_LED2R="PA6"
+CONFIG_ETRAX_V32_LED3G="PA7"
+CONFIG_ETRAX_V32_LED3R="PA7"
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NF_CONNTRACK_ENABLED is not set
+# CONFIG_NF_CONNTRACK is not set
+# CONFIG_NETFILTER_XTABLES is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Drivers for built-in interfaces
+#
+CONFIG_ETRAX_ETHERNET=y
+# CONFIG_ETRAX_IDE is not set
+CONFIG_ETRAX_AXISFLASHMAP=y
+CONFIG_ETRAX_PTABLE_SECTOR=65536
+# CONFIG_ETRAX_I2C is not set
+# CONFIG_ETRAX_GPIO is not set
+# CONFIG_ETRAX_NO_PHY is not set
+# CONFIG_ETRAX_ETHERNET_IFACE0 is not set
+# CONFIG_ETRAX_ETHERNET_IFACE1 is not set
+# CONFIG_ETRAXFS_SERIAL is not set
+# CONFIG_ETRAX_SYNCHRONOUS_SERIAL is not set
+# CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE is not set
+# CONFIG_ETRAX_NANDFLASH is not set
+# CONFIG_ETRAX_CARDBUS is not set
+# CONFIG_ETRAX_IOP_FW_LOAD is not set
+# CONFIG_ETRAX_STREAMCOPROC is not set
+# CONFIG_ETRAX_SPI_MMC is not set
+# CONFIG_ETRAX_SPI_MMC_BOARD is not set
+# CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK is not set
+CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY=y
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_RAM=y
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+CONFIG_MTD_MTDRAM=y
+CONFIG_MTDRAM_TOTAL_SIZE=0
+CONFIG_MTDRAM_ERASE_SIZE=64
+CONFIG_MTDRAM_ABS_POS=0x0
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_RTC_CLASS is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+CONFIG_HW_RANDOM=y
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PROFILING is not set
+# CONFIG_SYSTEM_PROFILER is not set
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SAMPLES is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_DMA=y
diff --git a/arch/cris/kernel/module.c b/arch/cris/kernel/module.c
index 11b867df8617..a187833febc8 100644
--- a/arch/cris/kernel/module.c
+++ b/arch/cris/kernel/module.c
@@ -28,20 +28,28 @@
 #define DEBUGP(fmt , ...)
 #endif
 
+#ifdef CONFIG_ETRAX_KMALLOCED_MODULES
+#define MALLOC_MODULE(size) kmalloc(size, GFP_KERNEL)
+#define FREE_MODULE(region) kfree(region)
+#else
+#define MALLOC_MODULE(size) vmalloc_exec(size)
+#define FREE_MODULE(region) vfree(region)
+#endif
+
 void *module_alloc(unsigned long size)
 {
 	if (size == 0)
 		return NULL;
-	return vmalloc_exec(size);
+	return MALLOC_MODULE(size);
 }
 
 
 /* Free memory returned from module_alloc */
 void module_free(struct module *mod, void *module_region)
 {
-	vfree(module_region);
+	FREE_MODULE(module_region);
 	/* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
+	   table entries. */
 }
 
 /* We don't need anything special. */
diff --git a/arch/cris/kernel/process.c b/arch/cris/kernel/process.c
index 9ca558fc5bc8..ef2db8fd102a 100644
--- a/arch/cris/kernel/process.c
+++ b/arch/cris/kernel/process.c
@@ -1,5 +1,4 @@
-/* $Id: process.c,v 1.21 2005/03/04 08:16:17 starvik Exp $
- * 
+/*
  *  linux/arch/cris/kernel/process.c
  *
  *  Copyright (C) 1995  Linus Torvalds
@@ -7,105 +6,6 @@
  *
  *  Authors:   Bjorn Wesen (bjornw@axis.com)
  *
- *  $Log: process.c,v $
- *  Revision 1.21  2005/03/04 08:16:17  starvik
- *  Merge of Linux 2.6.11.
- *
- *  Revision 1.20  2005/01/18 05:57:22  starvik
- *  Renamed hlt_counter to cris_hlt_counter and made it global.
- *
- *  Revision 1.19  2004/10/19 13:07:43  starvik
- *  Merge of Linux 2.6.9
- *
- *  Revision 1.18  2004/08/16 12:37:23  starvik
- *  Merge of Linux 2.6.8
- *
- *  Revision 1.17  2004/04/05 13:53:48  starvik
- *  Merge of Linux 2.6.5
- *
- *  Revision 1.16  2003/10/27 08:04:33  starvik
- *  Merge of Linux 2.6.0-test9
- *
- *  Revision 1.15  2003/09/11 07:29:52  starvik
- *  Merge of Linux 2.6.0-test5
- *
- *  Revision 1.14  2003/06/10 10:21:12  johana
- *  Moved thread_saved_pc() from arch/cris/kernel/process.c to
- *  subarch specific process.c. arch-v32 has an erp, no irp.
- *
- *  Revision 1.13  2003/04/09 05:20:47  starvik
- *  Merge of Linux 2.5.67
- *
- *  Revision 1.12  2002/12/11 15:41:11  starvik
- *  Extracted v10 (ETRAX 100LX) specific stuff to arch/cris/arch-v10/kernel
- *
- *  Revision 1.11  2002/12/10 09:00:10  starvik
- *  Merge of Linux 2.5.51
- *
- *  Revision 1.10  2002/11/27 08:42:34  starvik
- *  Argument to user_regs() is thread_info*
- *
- *  Revision 1.9  2002/11/26 09:44:21  starvik
- *  New threads exits through ret_from_fork (necessary for preemptive scheduling)
- *
- *  Revision 1.8  2002/11/19 14:35:24  starvik
- *  Changes from linux 2.4
- *  Changed struct initializer syntax to the currently prefered notation
- *
- *  Revision 1.7  2002/11/18 07:39:42  starvik
- *  thread_saved_pc moved here from processor.h
- *
- *  Revision 1.6  2002/11/14 06:51:27  starvik
- *  Made cpu_idle more similar with other archs
- *  init_task_union -> init_thread_union
- *  Updated for new interrupt macros
- *  sys_clone and do_fork have a new argument, user_tid
- *
- *  Revision 1.5  2002/11/05 06:45:11  starvik
- *  Merge of Linux 2.5.45
- *
- *  Revision 1.4  2002/02/05 15:37:44  bjornw
- *  Need init_task.h
- *
- *  Revision 1.3  2002/01/21 15:22:49  bjornw
- *  current->counter is gone
- *
- *  Revision 1.22  2001/11/13 09:40:43  orjanf
- *  Added dump_fpu (needed for core dumps).
- *
- *  Revision 1.21  2001/11/12 18:26:21  pkj
- *  Fixed compiler warnings.
- *
- *  Revision 1.20  2001/10/03 08:21:39  jonashg
- *  cause_of_death does not exist if CONFIG_SVINTO_SIM is defined.
- *
- *  Revision 1.19  2001/09/26 11:52:54  bjornw
- *  INIT_MMAP is gone in 2.4.10
- *
- *  Revision 1.18  2001/08/21 21:43:51  hp
- *  Move last watchdog fix inside #ifdef CONFIG_ETRAX_WATCHDOG
- *
- *  Revision 1.17  2001/08/21 13:48:01  jonashg
- *  Added fix by HP to avoid oops when doing a hard_reset_now.
- *
- *  Revision 1.16  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.15  2001/06/20 16:31:57  hp
- *  Add comments to describe empty functions according to review.
- *
- *  Revision 1.14  2001/05/29 11:27:59  markusl
- *  Fixed so that hard_reset_now will do reset even if watchdog wasn't enabled
- *
- *  Revision 1.13  2001/03/20 19:44:06  bjornw
- *  Use the 7th syscall argument for regs instead of current_regs
- *
  */
 
 /*
@@ -206,6 +106,7 @@ EXPORT_SYMBOL(pm_power_off);
  * low exit latency (ie sit in a loop waiting for
  * somebody to say that they'd like to reschedule)
  */
+
 void cpu_idle (void)
 {
 	/* endless idle loop with no priority at all */
diff --git a/arch/cris/kernel/ptrace.c b/arch/cris/kernel/ptrace.c
index 3ccd20e85dce..b326023baab2 100644
--- a/arch/cris/kernel/ptrace.c
+++ b/arch/cris/kernel/ptrace.c
@@ -2,65 +2,11 @@
  *  linux/arch/cris/kernel/ptrace.c
  *
  * Parts taken from the m68k port.
- * 
+ *
  * Copyright (c) 2000, 2001, 2002 Axis Communications AB
  *
  * Authors:   Bjorn Wesen
  *
- * $Log: ptrace.c,v $
- * Revision 1.10  2004/09/22 11:50:01  orjanf
- * * Moved get_reg/put_reg to arch-specific files.
- * * Added functions to access debug registers (CRISv32).
- * * Added support for PTRACE_SINGLESTEP (CRISv32).
- * * Added S flag to CCS_MASK (CRISv32).
- *
- * Revision 1.9  2003/07/04 12:56:11  tobiasa
- * Moved arch-specific code to arch-specific files.
- *
- * Revision 1.8  2003/04/09 05:20:47  starvik
- * Merge of Linux 2.5.67
- *
- * Revision 1.7  2002/11/27 08:42:34  starvik
- * Argument to user_regs() is thread_info*
- *
- * Revision 1.6  2002/11/20 11:56:11  starvik
- * Merge of Linux 2.5.48
- *
- * Revision 1.5  2002/11/18 07:41:19  starvik
- * Removed warning
- *
- * Revision 1.4  2002/11/11 12:47:28  starvik
- * SYSCALL_TRACE has been moved to thread flags
- *
- * Revision 1.3  2002/02/05 15:37:18  bjornw
- * * Add do_notify_resume (replaces do_signal in the callchain)
- * * syscall_trace is now do_syscall_trace
- * * current->ptrace flag PT_TRACESYS -> PT_SYSCALLTRACE
- * * Keep track of the current->work.syscall_trace counter
- *
- * Revision 1.2  2001/12/18 13:35:20  bjornw
- * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15).
- *
- * Revision 1.8  2001/11/12 18:26:21  pkj
- * Fixed compiler warnings.
- *
- * Revision 1.7  2001/09/26 11:53:49  bjornw
- * PTRACE_DETACH works more simple in 2.4.10
- *
- * Revision 1.6  2001/07/25 16:08:47  bjornw
- * PTRACE_ATTACH bulk moved into arch-independent code in 2.4.7
- *
- * Revision 1.5  2001/03/26 14:24:28  orjanf
- * * Changed loop condition.
- * * Added comment documenting non-standard ptrace behaviour.
- *
- * Revision 1.4  2001/03/20 19:44:41  bjornw
- * Use the user_regs macro instead of thread.esp0
- *
- * Revision 1.3  2000/12/18 23:45:25  bjornw
- * Linux/CRIS first version
- *
- *
  */
 
 #include <linux/kernel.h>
@@ -85,7 +31,7 @@ extern int do_signal(int canrestart, struct pt_regs *regs);
 
 
 void do_notify_resume(int canrestart, struct pt_regs *regs,
-		      __u32 thread_info_flags  )
+		      __u32 thread_info_flags)
 {
 	/* deal with pending signal delivery */
 	if (thread_info_flags & _TIF_SIGPENDING)
diff --git a/arch/cris/kernel/semaphore.c b/arch/cris/kernel/semaphore.c
index b884263d3cd4..f137a439041f 100644
--- a/arch/cris/kernel/semaphore.c
+++ b/arch/cris/kernel/semaphore.c
@@ -4,7 +4,6 @@
  */
 
 #include <linux/sched.h>
-#include <linux/init.h>
 #include <asm/semaphore-helper.h>
 
 /*
diff --git a/arch/cris/kernel/setup.c b/arch/cris/kernel/setup.c
index c34fb235b09f..04d48dd91ddf 100644
--- a/arch/cris/kernel/setup.c
+++ b/arch/cris/kernel/setup.c
@@ -18,7 +18,7 @@
 #include <linux/screen_info.h>
 #include <linux/utsname.h>
 #include <linux/pfn.h>
-
+#include <linux/cpu.h>
 #include <asm/setup.h>
 
 /*
@@ -36,6 +36,8 @@ extern unsigned long dram_start, dram_end;
 
 extern unsigned long romfs_start, romfs_length, romfs_in_flash; /* from head.S */
 
+static struct cpu cpu_devices[NR_CPUS];
+
 extern void show_etrax_copyright(void);		/* arch-vX/kernel/setup.c */
 
 /* This mainly sets up the memory area, and can be really confusing.
@@ -45,24 +47,23 @@ extern void show_etrax_copyright(void);		/* arch-vX/kernel/setup.c */
  * given by the macro __pa().
  *
  * In this DRAM, the kernel code and data is loaded, in the beginning.
- * It really starts at c0004000 to make room for some special pages - 
+ * It really starts at c0004000 to make room for some special pages -
  * the start address is text_start. The kernel data ends at _end. After
  * this the ROM filesystem is appended (if there is any).
- * 
+ *
  * Between this address and dram_end, we have RAM pages usable to the
  * boot code and the system.
  *
  */
 
-void __init 
-setup_arch(char **cmdline_p)
+void __init setup_arch(char **cmdline_p)
 {
 	extern void init_etrax_debug(void);
 	unsigned long bootmap_size;
 	unsigned long start_pfn, max_pfn;
 	unsigned long memory_start;
 
- 	/* register an initial console printing routine for printk's */
+	/* register an initial console printing routine for printk's */
 
 	init_etrax_debug();
 
@@ -121,7 +122,7 @@ setup_arch(char **cmdline_p)
 	min_low_pfn = PAGE_OFFSET >> PAGE_SHIFT;
 
 	bootmap_size = init_bootmem_node(NODE_DATA(0), start_pfn,
-					 min_low_pfn, 
+					 min_low_pfn,
 					 max_low_pfn);
 
 	/* And free all memory not belonging to the kernel (addr, size) */
@@ -187,4 +188,16 @@ const struct seq_operations cpuinfo_op = {
 	.show  = show_cpuinfo,
 };
 
+static int __init topology_init(void)
+{
+	int i;
+
+	for_each_possible_cpu(i) {
+		 return register_cpu(&cpu_devices[i], i);
+	}
+
+	return 0;
+}
+
+subsys_initcall(topology_init);
 
diff --git a/arch/cris/kernel/time.c b/arch/cris/kernel/time.c
index 7a2cc7efbcf8..ff4c6aa75def 100644
--- a/arch/cris/kernel/time.c
+++ b/arch/cris/kernel/time.c
@@ -1,5 +1,4 @@
-/* $Id: time.c,v 1.18 2005/03/04 08:16:17 starvik Exp $
- *
+/*
  *  linux/arch/cris/kernel/time.c
  *
  *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
@@ -18,7 +17,7 @@
  * Linux/CRIS specific code:
  *
  * Authors:    Bjorn Wesen
- *             Johan Adolfsson  
+ *             Johan Adolfsson
  *
  */
 
@@ -208,10 +207,16 @@ cris_do_profile(struct pt_regs* regs)
 #endif
 
 #ifdef CONFIG_PROFILING
-        profile_tick(CPU_PROFILING);
+	profile_tick(CPU_PROFILING);
 #endif
 }
 
+unsigned long long sched_clock(void)
+{
+	return (unsigned long long)jiffies * (1000000000 / HZ) +
+		get_ns_in_jiffie();
+}
+
 static int
 __init init_udelay(void)
 {
diff --git a/arch/cris/kernel/traps.c b/arch/cris/kernel/traps.c
index 520d92205fed..541efbf09371 100644
--- a/arch/cris/kernel/traps.c
+++ b/arch/cris/kernel/traps.c
@@ -1,66 +1,78 @@
-/* $Id: traps.c,v 1.11 2005/01/24 16:03:19 orjanf Exp $
- *
+/*
  *  linux/arch/cris/traps.c
  *
- *  Here we handle the break vectors not used by the system call 
- *  mechanism, as well as some general stack/register dumping 
+ *  Here we handle the break vectors not used by the system call
+ *  mechanism, as well as some general stack/register dumping
  *  things.
- * 
- *  Copyright (C) 2000-2002 Axis Communications AB
+ *
+ *  Copyright (C) 2000-2007 Axis Communications AB
  *
  *  Authors:   Bjorn Wesen
- *  	       Hans-Peter Nilsson
+ *             Hans-Peter Nilsson
  *
  */
 
 #include <linux/init.h>
 #include <linux/module.h>
+
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 
+extern void arch_enable_nmi(void);
+extern void stop_watchdog(void);
+extern void reset_watchdog(void);
+extern void show_registers(struct pt_regs *regs);
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+extern void handle_BUG(struct pt_regs *regs);
+#else
+#define handle_BUG(regs)
+#endif
+
 static int kstack_depth_to_print = 24;
 
-extern int raw_printk(const char *fmt, ...);
+void (*nmi_handler)(struct pt_regs *);
 
-void show_trace(unsigned long * stack)
+void
+show_trace(unsigned long *stack)
 {
 	unsigned long addr, module_start, module_end;
 	extern char _stext, _etext;
 	int i;
 
-        raw_printk("\nCall Trace: ");
+	printk("\nCall Trace: ");
 
-        i = 1;
-        module_start = VMALLOC_START;
-        module_end = VMALLOC_END;
+	i = 1;
+	module_start = VMALLOC_START;
+	module_end = VMALLOC_END;
 
-        while (((long) stack & (THREAD_SIZE-1)) != 0) {
-		if (__get_user (addr, stack)) {
+	while (((long)stack & (THREAD_SIZE-1)) != 0) {
+		if (__get_user(addr, stack)) {
 			/* This message matches "failing address" marked
 			   s390 in ksymoops, so lines containing it will
 			   not be filtered out by ksymoops.  */
-			raw_printk ("Failing address 0x%lx\n", (unsigned long)stack);
+			printk("Failing address 0x%lx\n", (unsigned long)stack);
 			break;
 		}
 		stack++;
 
-                /*
-                 * If the address is either in the text segment of the
-                 * kernel, or in the region which contains vmalloc'ed
-                 * memory, it *may* be the address of a calling
-                 * routine; if so, print it so that someone tracing
-                 * down the cause of the crash will be able to figure
-                 * out the call path that was taken.
-                 */
-                if (((addr >= (unsigned long) &_stext) &&
-                     (addr <= (unsigned long) &_etext)) ||
-                    ((addr >= module_start) && (addr <= module_end))) {
-                        if (i && ((i % 8) == 0))
-                                raw_printk("\n       ");
-                        raw_printk("[<%08lx>] ", addr);
-                        i++;
-                }
-        }
+		/*
+		 * If the address is either in the text segment of the
+		 * kernel, or in the region which contains vmalloc'ed
+		 * memory, it *may* be the address of a calling
+		 * routine; if so, print it so that someone tracing
+		 * down the cause of the crash will be able to figure
+		 * out the call path that was taken.
+		 */
+		if (((addr >= (unsigned long)&_stext) &&
+		     (addr <= (unsigned long)&_etext)) ||
+		    ((addr >= module_start) && (addr <= module_end))) {
+			if (i && ((i % 8) == 0))
+				printk("\n       ");
+			printk("[<%08lx>] ", addr);
+			i++;
+		}
+	}
 }
 
 /*
@@ -78,109 +90,149 @@ void show_trace(unsigned long * stack)
  * with the ksymoops maintainer.
  */
 
-void 
+void
 show_stack(struct task_struct *task, unsigned long *sp)
 {
-        unsigned long *stack, addr;
-        int i;
+	unsigned long *stack, addr;
+	int i;
 
 	/*
 	 * debugging aid: "show_stack(NULL);" prints a
 	 * back trace.
 	 */
 
-        if(sp == NULL) {
+	if (sp == NULL) {
 		if (task)
 			sp = (unsigned long*)task->thread.ksp;
 		else
 			sp = (unsigned long*)rdsp();
 	}
 
-        stack = sp;
+	stack = sp;
 
-	raw_printk("\nStack from %08lx:\n       ", (unsigned long)stack);
-        for(i = 0; i < kstack_depth_to_print; i++) {
-                if (((long) stack & (THREAD_SIZE-1)) == 0)
-                        break;
-                if (i && ((i % 8) == 0))
-                        raw_printk("\n       ");
-		if (__get_user (addr, stack)) {
+	printk("\nStack from %08lx:\n       ", (unsigned long)stack);
+	for (i = 0; i < kstack_depth_to_print; i++) {
+		if (((long)stack & (THREAD_SIZE-1)) == 0)
+			break;
+		if (i && ((i % 8) == 0))
+			printk("\n       ");
+		if (__get_user(addr, stack)) {
 			/* This message matches "failing address" marked
 			   s390 in ksymoops, so lines containing it will
 			   not be filtered out by ksymoops.  */
-			raw_printk ("Failing address 0x%lx\n", (unsigned long)stack);
+			printk("Failing address 0x%lx\n", (unsigned long)stack);
 			break;
 		}
 		stack++;
-		raw_printk("%08lx ", addr);
-        }
+		printk("%08lx ", addr);
+	}
 	show_trace(sp);
 }
 
-static void (*nmi_handler)(struct pt_regs*);
-extern void arch_enable_nmi(void);
+#if 0
+/* displays a short stack trace */
 
-void set_nmi_handler(void (*handler)(struct pt_regs*))
+int
+show_stack(void)
 {
-  nmi_handler = handler;
-  arch_enable_nmi();
+	unsigned long *sp = (unsigned long *)rdusp();
+	int i;
+
+	printk("Stack dump [0x%08lx]:\n", (unsigned long)sp);
+	for (i = 0; i < 16; i++)
+		printk("sp + %d: 0x%08lx\n", i*4, sp[i]);
+	return 0;
 }
+#endif
 
-void handle_nmi(struct pt_regs* regs)
+void
+dump_stack(void)
 {
-  if (nmi_handler)
-    nmi_handler(regs);
+	show_stack(NULL, NULL);
+}
+EXPORT_SYMBOL(dump_stack);
+
+void
+set_nmi_handler(void (*handler)(struct pt_regs *))
+{
+	nmi_handler = handler;
+	arch_enable_nmi();
 }
 
 #ifdef CONFIG_DEBUG_NMI_OOPS
-void oops_nmi_handler(struct pt_regs* regs)
+void
+oops_nmi_handler(struct pt_regs *regs)
 {
-  stop_watchdog();
-  raw_printk("NMI!\n");
-  show_registers(regs);
+	stop_watchdog();
+	oops_in_progress = 1;
+	printk("NMI!\n");
+	show_registers(regs);
+	oops_in_progress = 0;
 }
 
-static int
-__init oops_nmi_register(void)
+static int __init
+oops_nmi_register(void)
 {
-  set_nmi_handler(oops_nmi_handler);
-  return 0;
+	set_nmi_handler(oops_nmi_handler);
+	return 0;
 }
 
 __initcall(oops_nmi_register);
 
 #endif
 
-#if 0
-/* displays a short stack trace */
-
-int 
-show_stack()
+/*
+ * This gets called from entry.S when the watchdog has bitten. Show something
+ * similiar to an Oops dump, and if the kernel is configured to be a nice
+ * doggy, then halt instead of reboot.
+ */
+void
+watchdog_bite_hook(struct pt_regs *regs)
 {
-	unsigned long *sp = (unsigned long *)rdusp();
-	int i;
-	raw_printk("Stack dump [0x%08lx]:\n", (unsigned long)sp);
-	for(i = 0; i < 16; i++)
-		raw_printk("sp + %d: 0x%08lx\n", i*4, sp[i]);
-	return 0;
-}
+#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
+	local_irq_disable();
+	stop_watchdog();
+	show_registers(regs);
+
+	while (1)
+		; /* Do nothing. */
+#else
+	show_registers(regs);
 #endif
+}
 
-void dump_stack(void)
+/* This is normally the Oops function. */
+void
+die_if_kernel(const char *str, struct pt_regs *regs, long err)
 {
-	show_stack(NULL, NULL);
-}
+	if (user_mode(regs))
+		return;
 
-EXPORT_SYMBOL(dump_stack);
+#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
+	/*
+	 * This printout might take too long and could trigger
+	 * the watchdog normally. If NICE_DOGGY is set, simply
+	 * stop the watchdog during the printout.
+	 */
+	stop_watchdog();
+#endif
 
-void __init 
-trap_init(void)
-{
-	/* Nothing needs to be done */
+	handle_BUG(regs);
+
+	printk("%s: %04lx\n", str, err & 0xffff);
+
+	show_registers(regs);
+
+	oops_in_progress = 0;
+
+#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
+	reset_watchdog();
+#endif
+	do_exit(SIGSEGV);
 }
 
-void spinning_cpu(void* addr)
+void __init
+trap_init(void)
 {
-  raw_printk("CPU %d spinning on %X\n", smp_processor_id(), addr);
-  dump_stack();
+	/* Nothing needs to be done */
 }
diff --git a/arch/cris/mm/fault.c b/arch/cris/mm/fault.c
index 3034f3ff950c..c4c76db90f9c 100644
--- a/arch/cris/mm/fault.c
+++ b/arch/cris/mm/fault.c
@@ -1,130 +1,9 @@
 /*
  *  linux/arch/cris/mm/fault.c
  *
- *  Copyright (C) 2000, 2001  Axis Communications AB
- *
- *  Authors:  Bjorn Wesen 
- * 
- *  $Log: fault.c,v $
- *  Revision 1.20  2005/03/04 08:16:18  starvik
- *  Merge of Linux 2.6.11.
- *
- *  Revision 1.19  2005/01/14 10:07:59  starvik
- *  Fixed warning.
- *
- *  Revision 1.18  2005/01/12 08:10:14  starvik
- *  Re-added the change of frametype when handling kernel page fault fixup
- *  for v10. This is necessary to avoid that the CPU remakes the faulting
- *  access.
- *
- *  Revision 1.17  2005/01/11 13:53:05  starvik
- *  Use raw_printk.
- *
- *  Revision 1.16  2004/12/17 11:39:41  starvik
- *  SMP support.
- *
- *  Revision 1.15  2004/11/23 18:36:18  starvik
- *  Stack is now non-executable.
- *  Signal handler trampolines are placed in a reserved page mapped into all
- *  processes.
- *
- *  Revision 1.14  2004/11/23 07:10:21  starvik
- *  Moved find_fixup_code to generic code.
- *
- *  Revision 1.13  2004/11/23 07:00:54  starvik
- *  Actually use the execute permission bit in the MMU. This makes it possible
- *  to prevent e.g. attacks where executable code is put on the stack.
- *
- *  Revision 1.12  2004/09/29 06:16:04  starvik
- *  Use instruction_pointer
- *
- *  Revision 1.11  2004/05/14 07:58:05  starvik
- *  Merge of changes from 2.4
- *
- *  Revision 1.10  2003/10/27 14:51:24  starvik
- *  Removed debugcode
- *
- *  Revision 1.9  2003/10/27 14:50:42  starvik
- *  Changed do_page_fault signature
- *
- *  Revision 1.8  2003/07/04 13:02:48  tobiasa
- *  Moved code snippet from arch/cris/mm/fault.c that searches for fixup code
- *  to separate function in arch-specific files.
- *
- *  Revision 1.7  2003/01/22 06:48:38  starvik
- *  Fixed warnings issued by GCC 3.2.1
- *
- *  Revision 1.6  2003/01/09 14:42:52  starvik
- *  Merge of Linux 2.5.55
- *
- *  Revision 1.5  2002/12/11 14:44:48  starvik
- *  Extracted v10 (ETRAX 100LX) specific stuff to arch/cris/arch-v10/mm
- *
- *  Revision 1.4  2002/11/13 15:10:28  starvik
- *  pte_offset has been renamed to pte_offset_kernel
- *
- *  Revision 1.3  2002/11/05 06:45:13  starvik
- *  Merge of Linux 2.5.45
- *
- *  Revision 1.2  2001/12/18 13:35:22  bjornw
- *  Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15).
- *
- *  Revision 1.20  2001/11/22 13:34:06  bjornw
- *  * Bug workaround (LX TR89): force a rerun of the whole of an interrupted
- *    unaligned write, because the second half of the write will be corrupted
- *    otherwise. Affected unaligned writes spanning not-yet mapped pages.
- *  * Optimization: use the wr_rd bit in R_MMU_CAUSE to know whether a miss
- *    was due to a read or a write (before we didn't know this until the next
- *    restart of the interrupted instruction, thus wasting one fault-irq)
- *
- *  Revision 1.19  2001/11/12 19:02:10  pkj
- *  Fixed compiler warnings.
- *
- *  Revision 1.18  2001/07/18 22:14:32  bjornw
- *  Enable interrupts in the bulk of do_page_fault
- *
- *  Revision 1.17  2001/07/18 13:07:23  bjornw
- *  * Detect non-existant PTE's in vmalloc pmd synchronization
- *  * Remove comment about fast-paths for VMALLOC_START etc, because all that
- *    was totally bogus anyway it turned out :)
- *  * Fix detection of vmalloc-area synchronization
- *  * Add some comments
- *
- *  Revision 1.16  2001/06/13 00:06:08  bjornw
- *  current_pgd should be volatile
- *
- *  Revision 1.15  2001/06/13 00:02:23  bjornw
- *  Use a separate variable to store the current pgd to avoid races in schedule
- *
- *  Revision 1.14  2001/05/16 17:41:07  hp
- *  Last comment tweak further tweaked.
- *
- *  Revision 1.13  2001/05/15 00:58:44  hp
- *  Expand a bit on the comment why we compare address >= TASK_SIZE rather
- *  than >= VMALLOC_START.
- *
- *  Revision 1.12  2001/04/04 10:51:14  bjornw
- *  mmap_sem is grabbed for reading
- *
- *  Revision 1.11  2001/03/23 07:36:07  starvik
- *  Corrected according to review remarks
- *
- *  Revision 1.10  2001/03/21 16:10:11  bjornw
- *  CRIS_FRAME_FIXUP not needed anymore, use FRAME_NORMAL
- *
- *  Revision 1.9  2001/03/05 13:22:20  bjornw
- *  Spell-fix and fix in vmalloc_fault handling
- *
- *  Revision 1.8  2000/11/22 14:45:31  bjornw
- *  * 2.4.0-test10 removed the set_pgdir instantaneous kernel global mapping
- *    into all processes. Instead we fill in the missing PTE entries on demand.
- *
- *  Revision 1.7  2000/11/21 16:39:09  bjornw
- *  fixup switches frametype
- *
- *  Revision 1.6  2000/11/17 16:54:08  bjornw
- *  More detailed siginfo reporting
+ *  Copyright (C) 2000-2006  Axis Communications AB
  *
+ *  Authors:  Bjorn Wesen
  *
  */
 
@@ -135,7 +14,6 @@
 
 extern int find_fixup_code(struct pt_regs *);
 extern void die_if_kernel(const char *, struct pt_regs *, long);
-extern int raw_printk(const char *fmt, ...);
 
 /* debug of low-level TLB reload */
 #undef DEBUG
@@ -164,8 +42,8 @@ unsigned long cris_signal_return_page;
  * address.
  *
  * error_code:
- *	bit 0 == 0 means no page found, 1 means protection fault
- *	bit 1 == 0 means read, 1 means write
+ *      bit 0 == 0 means no page found, 1 means protection fault
+ *      bit 1 == 0 means read, 1 means write
  *
  * If this routine detects a bad access, it returns 1, otherwise it
  * returns 0.
@@ -181,9 +59,10 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
 	siginfo_t info;
 	int fault;
 
-        D(printk("Page fault for %lX on %X at %lX, prot %d write %d\n",
-                 address, smp_processor_id(), instruction_pointer(regs),
-                 protection, writeaccess));
+	D(printk(KERN_DEBUG
+		 "Page fault for %lX on %X at %lX, prot %d write %d\n",
+		 address, smp_processor_id(), instruction_pointer(regs),
+		 protection, writeaccess));
 
 	tsk = current;
 
@@ -233,7 +112,7 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
 	 * context, we must not take the fault..
 	 */
 
-	if (in_atomic() || !mm)
+	if (in_interrupt() || !mm)
 		goto no_context;
 
 	down_read(&mm->mmap_sem);
@@ -319,6 +198,9 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
 		/* info.si_code has been set above */
 		info.si_addr = (void *)address;
 		force_sig_info(SIGSEGV, &info, tsk);
+		printk(KERN_NOTICE "%s (pid %d) segfaults for page "
+		       "address %08lx at pc %08lx\n",
+		       tsk->comm, tsk->pid, address, instruction_pointer(regs));
 		return;
 	}
 
@@ -326,7 +208,7 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
 
 	/* Are we prepared to handle this kernel fault?
 	 *
-	 * (The kernel has valid exception-points in the source 
+	 * (The kernel has valid exception-points in the source
 	 *  when it acesses user-memory. When it fails in one
 	 *  of those points, we find it in a table and do a jump
 	 *  to some fixup code that loads an appropriate error
@@ -341,13 +223,18 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
 	 * terminate things with extreme prejudice.
 	 */
 
-	if ((unsigned long) (address) < PAGE_SIZE)
-		raw_printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
-	else
-		raw_printk(KERN_ALERT "Unable to handle kernel access");
-	raw_printk(" at virtual address %08lx\n",address);
-
-	die_if_kernel("Oops", regs, (writeaccess << 1) | protection);
+	if (!oops_in_progress) {
+		oops_in_progress = 1;
+		if ((unsigned long) (address) < PAGE_SIZE)
+			printk(KERN_ALERT "Unable to handle kernel NULL "
+				"pointer dereference");
+		else
+			printk(KERN_ALERT "Unable to handle kernel access"
+				" at virtual address %08lx\n", address);
+
+		die_if_kernel("Oops", regs, (writeaccess << 1) | protection);
+		oops_in_progress = 0;
+	}
 
 	do_exit(SIGKILL);
 
@@ -360,7 +247,7 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
 	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", tsk->comm);
 	if (user_mode(regs))
-		do_group_exit(SIGKILL);
+		do_exit(SIGKILL);
 	goto no_context;
 
  do_sigbus:
@@ -406,8 +293,8 @@ vmalloc_fault:
 		/* Since we're two-level, we don't need to do both
 		 * set_pgd and set_pmd (they do the same thing). If
 		 * we go three-level at some point, do the right thing
-		 * with pgd_present and set_pgd here. 
-		 * 
+		 * with pgd_present and set_pgd here.
+		 *
 		 * Also, since the vmalloc area is global, we don't
 		 * need to copy individual PTE's, it is enough to
 		 * copy the pgd pointer into the pte page of the
diff --git a/arch/cris/mm/init.c b/arch/cris/mm/init.c
index 0c833d176226..4207a2b52750 100644
--- a/arch/cris/mm/init.c
+++ b/arch/cris/mm/init.c
@@ -6,117 +6,6 @@
  *
  *  Authors:  Bjorn Wesen (bjornw@axis.com)
  *
- *  $Log: init.c,v $
- *  Revision 1.11  2004/05/28 09:28:56  starvik
- *  Calculation of loops_per_usec moved because initialization order has changed
- *  in Linux 2.6.
- *
- *  Revision 1.10  2004/05/14 07:58:05  starvik
- *  Merge of changes from 2.4
- *
- *  Revision 1.9  2003/07/04 08:27:54  starvik
- *  Merge of Linux 2.5.74
- *
- *  Revision 1.8  2003/04/09 05:20:48  starvik
- *  Merge of Linux 2.5.67
- *
- *  Revision 1.7  2003/01/22 06:48:38  starvik
- *  Fixed warnings issued by GCC 3.2.1
- *
- *  Revision 1.6  2002/12/11 14:44:48  starvik
- *  Extracted v10 (ETRAX 100LX) specific stuff to arch/cris/arch-v10/mm
- *
- *  Revision 1.5  2002/11/18 07:37:37  starvik
- *  Added cache bug workaround (from Linux 2.4)
- *
- *  Revision 1.4  2002/11/13 15:40:24  starvik
- *  Removed the page table cache stuff (as done in other archs)
- *
- *  Revision 1.3  2002/11/05 06:45:13  starvik
- *  Merge of Linux 2.5.45
- *
- *  Revision 1.2  2001/12/18 13:35:22  bjornw
- *  Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15).
- *
- *  Revision 1.31  2001/11/13 16:22:00  bjornw
- *  Skip calculating totalram and sharedram in si_meminfo
- *
- *  Revision 1.30  2001/11/12 19:02:10  pkj
- *  Fixed compiler warnings.
- *
- *  Revision 1.29  2001/07/25 16:09:50  bjornw
- *  val->sharedram will stay 0
- *
- *  Revision 1.28  2001/06/28 16:30:17  bjornw
- *  Oops. This needs to wait until 2.4.6 is merged
- *
- *  Revision 1.27  2001/06/28 14:04:07  bjornw
- *  Fill in sharedram
- *
- *  Revision 1.26  2001/06/18 06:36:02  hp
- *  Enable free_initmem of __init-type pages
- *
- *  Revision 1.25  2001/06/13 00:02:23  bjornw
- *  Use a separate variable to store the current pgd to avoid races in schedule
- *
- *  Revision 1.24  2001/05/15 00:52:20  hp
- *  Only map segment 0xa as seg if CONFIG_JULIETTE
- *
- *  Revision 1.23  2001/04/04 14:35:40  bjornw
- *  * Removed get_pte_slow and friends (2.4.3 change)
- *  * Removed bad_pmd handling (2.4.3 change)
- *
- *  Revision 1.22  2001/04/04 13:38:04  matsfg
- *  Moved ioremap to a separate function instead
- *
- *  Revision 1.21  2001/03/27 09:28:33  bjornw
- *  ioremap used too early - lets try it in mem_init instead
- *
- *  Revision 1.20  2001/03/23 07:39:21  starvik
- *  Corrected according to review remarks
- *
- *  Revision 1.19  2001/03/15 14:25:17  bjornw
- *  More general shadow registers and ioremaped addresses for external I/O
- *
- *  Revision 1.18  2001/02/23 12:46:44  bjornw
- *  * 0xc was not CSE1; 0x8 is, same as uncached flash, so we move the uncached
- *    flash during CRIS_LOW_MAP from 0xe to 0x8 so both the flash and the I/O
- *    is mapped straight over (for !CRIS_LOW_MAP the uncached flash is still 0xe)
- *
- *  Revision 1.17  2001/02/22 15:05:21  bjornw
- *  Map 0x9 straight over during LOW_MAP to allow for memory mapped LEDs
- *
- *  Revision 1.16  2001/02/22 15:02:35  bjornw
- *  Map 0xc straight over during LOW_MAP to allow for memory mapped I/O
- *
- *  Revision 1.15  2001/01/10 21:12:10  bjornw
- *  loops_per_sec -> loops_per_jiffy
- *
- *  Revision 1.14  2000/11/22 16:23:20  bjornw
- *  Initialize totalhigh counters to 0 to make /proc/meminfo look nice.
- *
- *  Revision 1.13  2000/11/21 16:37:51  bjornw
- *  Temporarily disable initmem freeing
- *
- *  Revision 1.12  2000/11/21 13:55:07  bjornw
- *  Use CONFIG_CRIS_LOW_MAP for the low VM map instead of explicit CPU type
- *
- *  Revision 1.11  2000/10/06 12:38:22  bjornw
- *  Cast empty_bad_page correctly (should really be of * type from the start..
- *
- *  Revision 1.10  2000/10/04 16:53:57  bjornw
- *  Fix memory-map due to LX features
- *
- *  Revision 1.9  2000/09/13 15:47:49  bjornw
- *  Wrong count in reserved-pages loop
- *
- *  Revision 1.8  2000/09/13 14:35:10  bjornw
- *  2.4.0-test8 added a new arg to free_area_init_node
- *
- *  Revision 1.7  2000/08/17 15:35:55  bjornw
- *  2.4.0-test6 removed MAP_NR and inserted virt_to_page
- *
- *
  */
 
 #include <linux/init.h>