Mindspeed Comcerto 2000 patch from SDK 3.1-rc4

This patch comes from Mindspeed's SDK 3.1-rc4

sdk-comcerto-openwrt-c2k_3.1-rc4/target/linux/comcerto2000/patches-3.2/000-mspd-kernel_linux_3_2_3_01_3.patch

Change-Id: I30ff3ebaeb108bc9b4e3b94df9049c1ab45cba93
diff --git a/Makefile b/Makefile
index 89f46df..160e758 100644
--- a/Makefile
+++ b/Makefile
@@ -561,8 +561,12 @@
 ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
 KBUILD_CFLAGS	+= -Os -fno-caller-saves
 else
+ifdef CONFIG_COMCERTO_CC_OPTIMIZE_O3
+KBUILD_CFLAGS	+= -O3 -fno-reorder-blocks -fno-tree-ch -fno-caller-saves
+else
 KBUILD_CFLAGS	+= -O2 -fno-reorder-blocks -fno-tree-ch -fno-caller-saves
 endif
+endif
 
 include $(srctree)/arch/$(SRCARCH)/Makefile
 
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 987c72d..45d65c8 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -266,6 +266,16 @@
 	help
 	  Support for ARM's Integrator platform.
 
+config ARCH_COMCERTO
+	bool "Mindspeed Comcerto"
+	select ARCH_SUPPORTS_MSI
+	select NEED_MACH_MEMORY_H
+	select ARCH_REQUIRE_GPIOLIB
+	help
+	  This enables support for Mindspeed's Comcerto development boards.
+	  If you would like to build your kernel to run on one of these boards
+	  then you must say 'Y' here. Otherwise say 'N'    
+
 config ARCH_REALVIEW
 	bool "ARM Ltd. RealView family"
 	select ARM_AMBA
@@ -1099,6 +1109,8 @@
 
 source "arch/arm/mach-w90x900/Kconfig"
 
+source "arch/arm/mach-comcerto/Kconfig"
+
 # Definitions to make life easier
 config ARCH_ACORN
 	bool
@@ -1451,7 +1463,7 @@
 	depends on REALVIEW_EB_ARM11MP || REALVIEW_EB_A9MP || \
 		 MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX || ARCH_OMAP4 || \
 		 ARCH_EXYNOS4 || ARCH_TEGRA || ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || \
-		 ARCH_MSM_SCORPIONMP || ARCH_SHMOBILE || ARCH_HIGHBANK || SOC_IMX6Q
+		 ARCH_MSM_SCORPIONMP || ARCH_SHMOBILE || ARCH_HIGHBANK || SOC_IMX6Q || ARCH_COMCERTO
 	depends on MMU
 	select USE_GENERIC_SMP_HELPERS
 	select HAVE_ARM_SCU if !ARCH_MSM_SCORPIONMP
@@ -1515,6 +1527,11 @@
 	help
 	  This option enables support for the ARM system coherency unit
 
+config SCU_SPECULATIVE_LINE_FILLS
+	bool "SCU speculative line fills"
+	depends on HAVE_ARM_SCU && CACHE_PL310
+	default n
+
 config HAVE_ARM_TWD
 	bool
 	depends on SMP
@@ -1532,10 +1549,12 @@
 	  option alone!
 
 	config VMSPLIT_3G
+		depends on !COMCERTO_HW_KERNEL_PAGETABLE
 		bool "3G/1G user/kernel split"
 	config VMSPLIT_2G
 		bool "2G/2G user/kernel split"
 	config VMSPLIT_1G
+		depends on !COMCERTO_HW_KERNEL_PAGETABLE
 		bool "1G/3G user/kernel split"
 endchoice
 
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index dfcf3b0..c93d06c 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -26,7 +26,7 @@
 
 # Do not use arch/arm/defconfig - it's always outdated.
 # Select a platform tht is kept up-to-date
-KBUILD_DEFCONFIG := versatile_defconfig
+KBUILD_DEFCONFIG := c2krtsm_defconfig
 
 # defines filename extension depending memory management type.
 ifeq ($(CONFIG_MMU),)
@@ -138,6 +138,10 @@
 machine-$(CONFIG_ARCH_BCMRING)		:= bcmring
 machine-$(CONFIG_ARCH_CLPS711X)		:= clps711x
 machine-$(CONFIG_ARCH_CNS3XXX)		:= cns3xxx
+machine-$(CONFIG_ARCH_COMCERTO)         := comcerto
+ifeq ($(CONFIG_ARCH_COMCERTO),y)
+textofs-$(CONFIG_ZONE_DMA) := 0x04008000
+endif
 machine-$(CONFIG_ARCH_DAVINCI)		:= davinci
 machine-$(CONFIG_ARCH_DOVE)		:= dove
 machine-$(CONFIG_ARCH_EBSA110)		:= ebsa110
@@ -199,6 +203,8 @@
 machine-$(CONFIG_MACH_SPEAR600)		:= spear6xx
 machine-$(CONFIG_ARCH_ZYNQ)		:= zynq
 
+
+
 # Platform directory name.  This list is sorted alphanumerically
 # by CONFIG_* macro name.
 plat-$(CONFIG_ARCH_MXC)		:= mxc
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index 21f56ff..da01136 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -33,6 +33,11 @@
 #
 # Architecture dependencies
 #
+
+ifeq ($(CONFIG_ARCH_COMCERTO),y)
+OBJS		+= head-comcerto.o
+endif
+
 ifeq ($(CONFIG_ARCH_ACORN),y)
 OBJS		+= ll_char_wr.o font.o
 endif
diff --git a/arch/arm/boot/compressed/head-comcerto.S b/arch/arm/boot/compressed/head-comcerto.S
new file mode 100644
index 0000000..e48f6e6
--- /dev/null
+++ b/arch/arm/boot/compressed/head-comcerto.S
@@ -0,0 +1,6 @@
+#include <asm/mach-types.h>
+
+	.section	".start", "ax"
+	ldr	r7,mach_type
+
+mach_type:     .word    MACH_TYPE_COMCERTO
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 410a546..399302e 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -43,11 +43,12 @@
 #include <asm/mach/irq.h>
 #include <asm/hardware/gic.h>
 
+#include <mach/sema.h>
+
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
 
 /* Address of GIC 0 CPU interface */
 void __iomem *gic_cpu_base_addr __read_mostly;
-
 /*
  * Supported arch specific GIC irq extension.
  * Default make them NULL.
@@ -90,30 +91,48 @@
 static void gic_mask_irq(struct irq_data *d)
 {
 	u32 mask = 1 << (gic_irq(d) % 32);
+	unsigned long flags;
+
+	if ((gic_irq(d) == 87) || (gic_irq(d) == 66) || (gic_irq(d) == 33)) {
+		return;
+	}
 
 	raw_spin_lock(&irq_controller_lock);
+	flags = msp_lock_frqsave();
 	writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4);
 	if (gic_arch_extn.irq_mask)
 		gic_arch_extn.irq_mask(d);
+	msp_unlock_frqrestore(flags);
 	raw_spin_unlock(&irq_controller_lock);
 }
 
 static void gic_unmask_irq(struct irq_data *d)
 {
 	u32 mask = 1 << (gic_irq(d) % 32);
+	unsigned long flags;
+
+	if ((gic_irq(d) == 87) || (gic_irq(d) == 66) || (gic_irq(d) == 33)) {
+		return;
+	}
 
 	raw_spin_lock(&irq_controller_lock);
+	flags = msp_lock_frqsave();
 	if (gic_arch_extn.irq_unmask)
 		gic_arch_extn.irq_unmask(d);
 	writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
+	msp_unlock_frqrestore(flags);
 	raw_spin_unlock(&irq_controller_lock);
 }
 
 static void gic_eoi_irq(struct irq_data *d)
 {
 	if (gic_arch_extn.irq_eoi) {
+		unsigned long flags;
+
 		raw_spin_lock(&irq_controller_lock);
+		flags = msp_lock_frqsave();
 		gic_arch_extn.irq_eoi(d);
+		msp_unlock_frqrestore(flags);
 		raw_spin_unlock(&irq_controller_lock);
 	}
 
@@ -308,6 +327,14 @@
 	for (i = 32; i < gic_irqs; i += 32)
 		writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
 
+#ifdef CONFIG_COMCERTO_MSP
+	/*
+	 * Set SPI interrupts are nonSecure
+	 */
+	for (i = 32; i < gic_irqs; i += 32)
+		writel_relaxed(0xffffffff, base + GIC_DIST_SECURITY_BIT + i * 4 / 32);
+#endif  /* CONFIG_COMCERTO_MSP */
+
 	/*
 	 * Setup the Linux IRQ subsystem.
 	 */
@@ -325,7 +352,14 @@
 		irq_set_chip_data(irq, gic);
 	}
 
+#ifdef CONFIG_COMCERTO_MSP
+	/*
+	 * Enable NonSecure interrupts in Distributor
+	 */
+	writel_relaxed(3, base + GIC_DIST_CTRL);
+#else  /* !CONFIG_COMCERTO_MSP */
 	writel_relaxed(1, base + GIC_DIST_CTRL);
+#endif /* CONFIG_COMCERTO_MSP */
 }
 
 static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
@@ -348,9 +382,62 @@
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
 
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
+
+#ifdef CONFIG_COMCERTO_MSP
+	/*
+	 * Set PPI and SGI interrupts are nonSecure
+	 */
+	writel_relaxed(0xffffffff, dist_base + GIC_DIST_SECURITY_BIT);
+
+	/*
+	 * Enable NonSecure interrupts in CPU interface,
+	 * Secure interrupts go to FIQ line,
+	 * Secure read returns valid NonSecure interrupt ID
+	 */
+	writel_relaxed(0xf, base + GIC_CPU_CTRL);
+#else  /* !CONFIG_COMCERTO_MSP */
 	writel_relaxed(1, base + GIC_CPU_CTRL);
+#endif /* CONFIG_COMCERTO_MSP */
 }
 
+#ifdef CONFIG_COMCERTO_MSP
+
+static void __cpuinit gic_cpu_init_irq_only(struct gic_chip_data *gic)
+{
+	void __iomem *dist_base = gic->dist_base;
+	void __iomem *base = gic->cpu_base;
+	int i;
+
+	/*
+	 * Deal with the banked PPI and SGI interrupts - disable all
+	 * PPI interrupts, ensure all SGI interrupts are enabled.
+	 */
+	writel_relaxed(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR);
+	writel_relaxed(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET);
+
+	/*
+	 * Set priority on PPI and SGI interrupts
+	 */
+	for (i = 0; i < 32; i += 4)
+		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
+
+	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
+
+	/*
+	 * Set PPI and SGI interrupts are nonSecure
+	 */
+	writel_relaxed(0xffffffff, dist_base + GIC_DIST_SECURITY_BIT);
+
+	/*
+	 * Enable NonSecure interrupts in CPU interface,
+	 * Secure interrupts go to IRQ line,
+	 * Secure read returns valid NonSecure interrupt ID
+	 */
+	writel_relaxed(0x7, base + GIC_CPU_CTRL);
+}
+
+#endif /* CONFIG_COMCERTO_MSP */
+
 #ifdef CONFIG_CPU_PM
 /*
  * Saves the GIC distributor registers during suspend or idle.  Must be called
@@ -625,7 +712,12 @@
 {
 	BUG_ON(gic_nr >= MAX_GIC_NR);
 
+#ifdef CONFIG_COMCERTO_MSP
+	/* run alternative secondary_boot gic init */
+	gic_cpu_init_irq_only(&gic_data[gic_nr]);
+#else  /* !CONFIG_COMCERTO_MSP */
 	gic_cpu_init(&gic_data[gic_nr]);
+#endif  /* CONFIG_COMCERTO_MSP */
 }
 
 #ifdef CONFIG_SMP
@@ -645,7 +737,16 @@
 	dsb();
 
 	/* this always happens on GIC0 */
+
+#ifdef CONFIG_COMCERTO_MSP
+#define GIC_SGI_SATT (1 << 15)
+	/*
+	 * Send SGI from Secure write to NonSecure target
+	 */
+	writel_relaxed(map << 16 | GIC_SGI_SATT | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT);
+#else  /* !CONFIG_COMCERTO_MSP */
 	writel_relaxed(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT);
+#endif /* CONFIG_COMCERTO_MSP */
 }
 #endif
 
diff --git a/arch/arm/configs/c2kasic_defconfig b/arch/arm/configs/c2kasic_defconfig
new file mode 100644
index 0000000..21cf380
--- /dev/null
+++ b/arch/arm/configs/c2kasic_defconfig
@@ -0,0 +1,1046 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Linux/arm 3.2.2 Kernel Configuration
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_KTIME_SCALAR=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_ARM_PATCH_PHYS_VIRT=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_HAVE_IRQ_WORK=y
+CONFIG_IRQ_WORK=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+CONFIG_DEFAULT_HOSTNAME="(none)"
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+# CONFIG_FHANDLE is not set
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_HAVE_SPARSE_IRQ=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_IRQ_DOMAIN=y
+# CONFIG_SPARSE_IRQ is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+# CONFIG_CGROUP_FREEZER is not set
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_PROC_PID_CPUSET=y
+CONFIG_CGROUP_CPUACCT=y
+# CONFIG_RESOURCE_COUNTERS is not set
+# CONFIG_CGROUP_PERF is not set
+# CONFIG_CGROUP_SCHED is not set
+# CONFIG_BLK_CGROUP is not set
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+CONFIG_USER_NS=y
+CONFIG_PID_NS=y
+# CONFIG_SCHED_AUTOGROUP is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+# CONFIG_EXPERT is not set
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+# CONFIG_EMBEDDED is not set
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_PERF_EVENTS=y
+# CONFIG_PERF_COUNTERS is not set
+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_PROFILING is not set
+CONFIG_TRACEPOINTS=y
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_HW_BREAKPOINT=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_BSGLIB is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+# CONFIG_FREEZER is not set
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_INTEGRATOR is not set
+CONFIG_ARCH_COMCERTO=y
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_VEXPRESS is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCMRING is not set
+# CONFIG_ARCH_HIGHBANK is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_PRIMA2 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_MXS is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_DOVE is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LPC32XX is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_TEGRA is not set
+# CONFIG_ARCH_PICOXCELL is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_SHMOBILE is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5P64X0 is not set
+# CONFIG_ARCH_S5PC100 is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_EXYNOS is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_TCC_926 is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_U8500 is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_PLAT_SPEAR is not set
+# CONFIG_ARCH_VT8500 is not set
+# CONFIG_ARCH_ZYNQ is not set
+# CONFIG_ARCH_SUPPORTS_BIG_ENDIAN is not set
+
+#
+# System MMU
+#
+
+#
+# Comcerto Implementation Options
+#
+CONFIG_ARCH_M86XXX=y
+# CONFIG_C2K_EVM is not set
+CONFIG_C2K_ASIC=y
+# CONFIG_RTSM_C2K is not set
+CONFIG_MTD_COMCERTO_NOR=y
+CONFIG_COMCERTO_TDM_CLOCK=y
+# CONFIG_PCI is not set
+CONFIG_COMCERTO_NUM_PCIES=2
+CONFIG_COMCERTO_FP=y
+CONFIG_COMCERTO_UART0_SUPPORT=y
+CONFIG_COMCERTO_UART1_SUPPORT=y
+CONFIG_COMCERTO_USB0_SUPPORT=y
+# CONFIG_COMCERTO_USB1_SUPPORT is not set
+CONFIG_COMCERTO_IPSEC_SUPPORT=y
+CONFIG_COMCERTO_SPI_SUPPORT=y
+CONFIG_COMCERTO_FAST_SPI_SUPPORT=y
+CONFIG_COMCERTO_I2C_SUPPORT=y
+CONFIG_COMCERTO_DW_DMA_SUPPORT=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_SWP_EMULATE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_OUTER_CACHE=y
+CONFIG_OUTER_CACHE_SYNC=y
+CONFIG_CACHE_L2X0=y
+CONFIG_CACHE_PL310=y
+CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+CONFIG_CPU_HAS_PMU=y
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+CONFIG_ARM_ERRATA_742230=y
+CONFIG_ARM_ERRATA_742231=y
+CONFIG_PL310_ERRATA_588369=y
+CONFIG_ARM_ERRATA_720789=y
+CONFIG_PL310_ERRATA_727915=y
+CONFIG_ARM_ERRATA_743622=y
+CONFIG_ARM_ERRATA_751472=y
+CONFIG_PL310_ERRATA_753970=y
+CONFIG_ARM_ERRATA_754322=y
+# CONFIG_ARM_ERRATA_754327 is not set
+CONFIG_ARM_ERRATA_764369=y
+CONFIG_PL310_ERRATA_769419=y
+CONFIG_ARM_GIC=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+# CONFIG_NO_HZ is not set
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_SMP=y
+# CONFIG_SMP_ON_UP is not set
+CONFIG_ARM_CPU_TOPOLOGY=y
+# CONFIG_SCHED_MC is not set
+# CONFIG_SCHED_SMT is not set
+CONFIG_HAVE_ARM_SCU=y
+CONFIG_HAVE_ARM_TWD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_NR_CPUS=2
+# CONFIG_HOTPLUG_CPU is not set
+CONFIG_LOCAL_TIMERS=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+CONFIG_HAVE_ARCH_PFN_VALID=y
+# CONFIG_HIGHMEM is not set
+CONFIG_HW_PERF_EVENTS=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_COMPACTION is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_CLEANCACHE is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_CC_STACKPROTECTOR is not set
+# CONFIG_DEPRECATED_PARAM_STRUCT is not set
+
+#
+# Boot options
+#
+# CONFIG_USE_OF is not set
+CONFIG_ZBOOT_ROM_TEXT=0x00608000
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_ZBOOT_ROM=y
+CONFIG_CMDLINE=""
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+
+#
+# CPU Power Management
+#
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_SUSPEND is not set
+# CONFIG_PM_RUNTIME is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_ARM_CPU_SUSPEND is not set
+# CONFIG_NET is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_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_SM_FTL 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_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=y
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_RAM=y
+CONFIG_MTD_ROM=y
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT 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 is not set
+# 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_DOCG3 is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+# CONFIG_BLK_DEV is not set
+# CONFIG_SENSORS_LIS3LV02D is not set
+# CONFIG_MISC_DEVICES is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+# CONFIG_KEYBOARD_ADP5589 is not set
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_QT1070 is not set
+# CONFIG_KEYBOARD_QT2160 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_TCA6416 is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_MCS is not set
+# CONFIG_KEYBOARD_MPR121 is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+# CONFIG_MOUSE_PS2_SENTELIC is not set
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C 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
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_SERIO_PS2MULT is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_TRACE_SINK is not set
+CONFIG_DEVKMEM=y
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_XILINX_PS_UART is not set
+# CONFIG_HVC_DCC is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_RAMOOPS is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_COMPAT is not set
+# CONFIG_I2C_CHARDEV is not set
+# CONFIG_I2C_MUX is not set
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_I2C_SMBUS=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=m
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_ALGOPCA=m
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_COMCERTO=y
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_PCA_PLATFORM=m
+# CONFIG_I2C_PXA_PCI is not set
+CONFIG_I2C_SIMTEC=m
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+CONFIG_I2C_PARPORT_LIGHT=m
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_SPI is not set
+CONFIG_SPI_MSPD=y
+CONFIG_COMCERTO_SPI=y
+
+#
+# Miscellaneous I2C Chip support
+#
+CONFIG_EEPROM_AT=y
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+
+#
+# PPS generators support
+#
+
+#
+# PTP clock support
+#
+
+#
+# Enable Device Drivers -> PPS to see the PTP clock options.
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB=y
+# CONFIG_SSB_DEBUG is not set
+CONFIG_BCMA_POSSIBLE=y
+
+#
+# Broadcom specific AMBA
+#
+# CONFIG_BCMA is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS6105X is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_TC3589X is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8997 is not set
+# CONFIG_MFD_MAX8998 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_MFD_WL1273_CORE is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+CONFIG_DRM=m
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# CONFIG_FB is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
+# CONFIG_BACKLIGHT_ADP8860 is not set
+# CONFIG_BACKLIGHT_ADP8870 is not set
+
+#
+# Display device support
+#
+CONFIG_DISPLAY_SUPPORT=m
+
+#
+# Display hardware drivers
+#
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# Virtio drivers
+#
+# CONFIG_VIRTIO_BALLOON is not set
+# CONFIG_VIRTIO_MMIO is not set
+# CONFIG_STAGING is not set
+
+#
+# Hardware Spinlock drivers
+#
+CONFIG_IOMMU_SUPPORT=y
+# CONFIG_VIRT_DRIVERS is not set
+# CONFIG_PM_DEVFREQ is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_FSNOTIFY is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+# CONFIG_FANOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE 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_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# 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=1
+# CONFIG_JFFS2_FS_WRITEBUFFER 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_LOGFS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_PSTORE is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=2048
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_LOCKUP_DETECTOR is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+# CONFIG_DETECT_HUNG_TASK is not set
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_TEST_LIST_SORT is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_DEBUG_PER_CPU_MAPS is not set
+# CONFIG_LKDTM is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_RING_BUFFER=y
+CONFIG_EVENT_TRACING=y
+CONFIG_EVENT_POWER_TRACING_DEPRECATED=y
+CONFIG_CONTEXT_SWITCH_TRACER=y
+CONFIG_TRACING=y
+CONFIG_GENERIC_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+CONFIG_BLK_DEV_IO_TRACE=y
+# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_RING_BUFFER_BENCHMARK is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_TEST_KSTRTOX is not set
+# CONFIG_STRICT_DEVMEM is not set
+# CONFIG_ARM_UNWIND is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+# CONFIG_CRYPTO is not set
+CONFIG_BINARY_PRINTF=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+# CONFIG_CRC8 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+# CONFIG_XZ_DEC is not set
+# CONFIG_XZ_DEC_BCJ is not set
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+# CONFIG_AVERAGE is not set
+# CONFIG_CORDIC is not set
diff --git a/arch/arm/configs/c2kevm_defconfig b/arch/arm/configs/c2kevm_defconfig
new file mode 100644
index 0000000..caba88d
--- /dev/null
+++ b/arch/arm/configs/c2kevm_defconfig
@@ -0,0 +1,1046 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Linux/arm 3.2.2 Kernel Configuration
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_KTIME_SCALAR=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_ARM_PATCH_PHYS_VIRT=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_HAVE_IRQ_WORK=y
+CONFIG_IRQ_WORK=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+CONFIG_DEFAULT_HOSTNAME="(none)"
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+# CONFIG_FHANDLE is not set
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_HAVE_SPARSE_IRQ=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_IRQ_DOMAIN=y
+# CONFIG_SPARSE_IRQ is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+# CONFIG_CGROUP_FREEZER is not set
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_PROC_PID_CPUSET=y
+CONFIG_CGROUP_CPUACCT=y
+# CONFIG_RESOURCE_COUNTERS is not set
+# CONFIG_CGROUP_PERF is not set
+# CONFIG_CGROUP_SCHED is not set
+# CONFIG_BLK_CGROUP is not set
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+CONFIG_USER_NS=y
+CONFIG_PID_NS=y
+# CONFIG_SCHED_AUTOGROUP is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+# CONFIG_EXPERT is not set
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+# CONFIG_EMBEDDED is not set
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_PERF_EVENTS=y
+# CONFIG_PERF_COUNTERS is not set
+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_PROFILING is not set
+CONFIG_TRACEPOINTS=y
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_HW_BREAKPOINT=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_BSGLIB is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+# CONFIG_FREEZER is not set
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_INTEGRATOR is not set
+CONFIG_ARCH_COMCERTO=y
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_VEXPRESS is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCMRING is not set
+# CONFIG_ARCH_HIGHBANK is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_PRIMA2 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_MXS is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_DOVE is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LPC32XX is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_TEGRA is not set
+# CONFIG_ARCH_PICOXCELL is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_SHMOBILE is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5P64X0 is not set
+# CONFIG_ARCH_S5PC100 is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_EXYNOS is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_TCC_926 is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_U8500 is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_PLAT_SPEAR is not set
+# CONFIG_ARCH_VT8500 is not set
+# CONFIG_ARCH_ZYNQ is not set
+# CONFIG_ARCH_SUPPORTS_BIG_ENDIAN is not set
+
+#
+# System MMU
+#
+
+#
+# Comcerto Implementation Options
+#
+CONFIG_ARCH_M86XXX=y
+CONFIG_C2K_EVM=y
+# CONFIG_C2K_ASIC is not set
+# CONFIG_RTSM_C2K is not set
+CONFIG_MTD_COMCERTO_NOR=y
+CONFIG_COMCERTO_TDM_CLOCK=y
+# CONFIG_PCI is not set
+CONFIG_COMCERTO_NUM_PCIES=2
+CONFIG_COMCERTO_FP=y
+# CONFIG_COMCERTO_UART0_SUPPORT is not set
+CONFIG_COMCERTO_UART1_SUPPORT=y
+CONFIG_COMCERTO_USB0_SUPPORT=y
+# CONFIG_COMCERTO_USB1_SUPPORT is not set
+CONFIG_COMCERTO_IPSEC_SUPPORT=y
+CONFIG_COMCERTO_SPI_SUPPORT=y
+CONFIG_COMCERTO_FAST_SPI_SUPPORT=y
+CONFIG_COMCERTO_I2C_SUPPORT=y
+CONFIG_COMCERTO_DW_DMA_SUPPORT=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_SWP_EMULATE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_OUTER_CACHE=y
+CONFIG_OUTER_CACHE_SYNC=y
+CONFIG_CACHE_L2X0=y
+CONFIG_CACHE_PL310=y
+CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+CONFIG_CPU_HAS_PMU=y
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+CONFIG_ARM_ERRATA_742230=y
+CONFIG_ARM_ERRATA_742231=y
+CONFIG_PL310_ERRATA_588369=y
+CONFIG_ARM_ERRATA_720789=y
+CONFIG_PL310_ERRATA_727915=y
+CONFIG_ARM_ERRATA_743622=y
+CONFIG_ARM_ERRATA_751472=y
+CONFIG_PL310_ERRATA_753970=y
+CONFIG_ARM_ERRATA_754322=y
+# CONFIG_ARM_ERRATA_754327 is not set
+CONFIG_ARM_ERRATA_764369=y
+CONFIG_PL310_ERRATA_769419=y
+CONFIG_ARM_GIC=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+# CONFIG_NO_HZ is not set
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_SMP=y
+# CONFIG_SMP_ON_UP is not set
+CONFIG_ARM_CPU_TOPOLOGY=y
+# CONFIG_SCHED_MC is not set
+# CONFIG_SCHED_SMT is not set
+CONFIG_HAVE_ARM_SCU=y
+CONFIG_HAVE_ARM_TWD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_NR_CPUS=2
+# CONFIG_HOTPLUG_CPU is not set
+CONFIG_LOCAL_TIMERS=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+CONFIG_HAVE_ARCH_PFN_VALID=y
+# CONFIG_HIGHMEM is not set
+CONFIG_HW_PERF_EVENTS=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_COMPACTION is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_CLEANCACHE is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_CC_STACKPROTECTOR is not set
+# CONFIG_DEPRECATED_PARAM_STRUCT is not set
+
+#
+# Boot options
+#
+# CONFIG_USE_OF is not set
+CONFIG_ZBOOT_ROM_TEXT=0x00608000
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_ZBOOT_ROM=y
+CONFIG_CMDLINE=""
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+
+#
+# CPU Power Management
+#
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_SUSPEND is not set
+# CONFIG_PM_RUNTIME is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_ARM_CPU_SUSPEND is not set
+# CONFIG_NET is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_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_SM_FTL 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_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=y
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_RAM=y
+CONFIG_MTD_ROM=y
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT 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 is not set
+# 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_DOCG3 is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+# CONFIG_BLK_DEV is not set
+# CONFIG_SENSORS_LIS3LV02D is not set
+# CONFIG_MISC_DEVICES is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+# CONFIG_KEYBOARD_ADP5589 is not set
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_QT1070 is not set
+# CONFIG_KEYBOARD_QT2160 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_TCA6416 is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_MCS is not set
+# CONFIG_KEYBOARD_MPR121 is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+# CONFIG_MOUSE_PS2_SENTELIC is not set
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C 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
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_SERIO_PS2MULT is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_TRACE_SINK is not set
+CONFIG_DEVKMEM=y
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_XILINX_PS_UART is not set
+# CONFIG_HVC_DCC is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_RAMOOPS is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_COMPAT is not set
+# CONFIG_I2C_CHARDEV is not set
+# CONFIG_I2C_MUX is not set
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_I2C_SMBUS=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=m
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_ALGOPCA=m
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_COMCERTO=y
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_PCA_PLATFORM=m
+# CONFIG_I2C_PXA_PCI is not set
+CONFIG_I2C_SIMTEC=m
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+CONFIG_I2C_PARPORT_LIGHT=m
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_SPI is not set
+CONFIG_SPI_MSPD=y
+CONFIG_COMCERTO_SPI=y
+
+#
+# Miscellaneous I2C Chip support
+#
+CONFIG_EEPROM_AT=y
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+
+#
+# PPS generators support
+#
+
+#
+# PTP clock support
+#
+
+#
+# Enable Device Drivers -> PPS to see the PTP clock options.
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB=y
+# CONFIG_SSB_DEBUG is not set
+CONFIG_BCMA_POSSIBLE=y
+
+#
+# Broadcom specific AMBA
+#
+# CONFIG_BCMA is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS6105X is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_TC3589X is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8997 is not set
+# CONFIG_MFD_MAX8998 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_MFD_WL1273_CORE is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+CONFIG_DRM=m
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# CONFIG_FB is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
+# CONFIG_BACKLIGHT_ADP8860 is not set
+# CONFIG_BACKLIGHT_ADP8870 is not set
+
+#
+# Display device support
+#
+CONFIG_DISPLAY_SUPPORT=m
+
+#
+# Display hardware drivers
+#
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# Virtio drivers
+#
+# CONFIG_VIRTIO_BALLOON is not set
+# CONFIG_VIRTIO_MMIO is not set
+# CONFIG_STAGING is not set
+
+#
+# Hardware Spinlock drivers
+#
+CONFIG_IOMMU_SUPPORT=y
+# CONFIG_VIRT_DRIVERS is not set
+# CONFIG_PM_DEVFREQ is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_FSNOTIFY is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+# CONFIG_FANOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE 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_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# 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=1
+# CONFIG_JFFS2_FS_WRITEBUFFER 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_LOGFS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_PSTORE is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=2048
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_LOCKUP_DETECTOR is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+# CONFIG_DETECT_HUNG_TASK is not set
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_TEST_LIST_SORT is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_DEBUG_PER_CPU_MAPS is not set
+# CONFIG_LKDTM is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_RING_BUFFER=y
+CONFIG_EVENT_TRACING=y
+CONFIG_EVENT_POWER_TRACING_DEPRECATED=y
+CONFIG_CONTEXT_SWITCH_TRACER=y
+CONFIG_TRACING=y
+CONFIG_GENERIC_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+CONFIG_BLK_DEV_IO_TRACE=y
+# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_RING_BUFFER_BENCHMARK is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_TEST_KSTRTOX is not set
+# CONFIG_STRICT_DEVMEM is not set
+# CONFIG_ARM_UNWIND is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+# CONFIG_CRYPTO is not set
+CONFIG_BINARY_PRINTF=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+# CONFIG_CRC8 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+# CONFIG_XZ_DEC is not set
+# CONFIG_XZ_DEC_BCJ is not set
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+# CONFIG_AVERAGE is not set
+# CONFIG_CORDIC is not set
diff --git a/arch/arm/configs/c2klv_defconfig b/arch/arm/configs/c2klv_defconfig
new file mode 100644
index 0000000..79e3d9a
--- /dev/null
+++ b/arch/arm/configs/c2klv_defconfig
@@ -0,0 +1,924 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Linux/arm 3.2.2 Kernel Configuration
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_KTIME_SCALAR=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_ARM_PATCH_PHYS_VIRT=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_HAVE_IRQ_WORK=y
+CONFIG_IRQ_WORK=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+CONFIG_DEFAULT_HOSTNAME="(none)"
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+# CONFIG_FHANDLE is not set
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_HAVE_SPARSE_IRQ=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_IRQ_DOMAIN=y
+# CONFIG_SPARSE_IRQ is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+# CONFIG_CGROUP_FREEZER is not set
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_PROC_PID_CPUSET=y
+CONFIG_CGROUP_CPUACCT=y
+# CONFIG_RESOURCE_COUNTERS is not set
+# CONFIG_CGROUP_PERF is not set
+# CONFIG_CGROUP_SCHED is not set
+# CONFIG_BLK_CGROUP is not set
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+CONFIG_USER_NS=y
+CONFIG_PID_NS=y
+# CONFIG_SCHED_AUTOGROUP is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+# CONFIG_EXPERT is not set
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+# CONFIG_EMBEDDED is not set
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_PERF_EVENTS=y
+# CONFIG_PERF_COUNTERS is not set
+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_PROFILING is not set
+CONFIG_TRACEPOINTS=y
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_HW_BREAKPOINT=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_BSGLIB is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+# CONFIG_FREEZER is not set
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_INTEGRATOR is not set
+CONFIG_ARCH_COMCERTO=y
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_VEXPRESS is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCMRING is not set
+# CONFIG_ARCH_HIGHBANK is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_PRIMA2 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_MXS is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_DOVE is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LPC32XX is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_TEGRA is not set
+# CONFIG_ARCH_PICOXCELL is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_SHMOBILE is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5P64X0 is not set
+# CONFIG_ARCH_S5PC100 is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_EXYNOS is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_TCC_926 is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_U8500 is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_PLAT_SPEAR is not set
+# CONFIG_ARCH_VT8500 is not set
+# CONFIG_ARCH_ZYNQ is not set
+# CONFIG_ARCH_SUPPORTS_BIG_ENDIAN is not set
+
+#
+# System MMU
+#
+
+#
+# Comcerto Implementation Options
+#
+CONFIG_ARCH_M86XXX=y
+# CONFIG_C2K_EVM is not set
+# CONFIG_C2K_ASIC is not set
+CONFIG_RTSM_C2K=y
+CONFIG_MTD_COMCERTO_NOR=y
+CONFIG_COMCERTO_TDM_CLOCK=y
+CONFIG_COMCERTO_NUM_PCIES=2
+CONFIG_COMCERTO_FP=y
+# CONFIG_COMCERTO_UART0_SUPPORT is not set
+CONFIG_COMCERTO_UART1_SUPPORT=y
+CONFIG_COMCERTO_USB0_SUPPORT=y
+# CONFIG_COMCERTO_USB1_SUPPORT is not set
+CONFIG_COMCERTO_IPSEC_SUPPORT=y
+CONFIG_COMCERTO_SPI_SUPPORT=y
+CONFIG_COMCERTO_FAST_SPI_SUPPORT=y
+CONFIG_COMCERTO_I2C_SUPPORT=y
+CONFIG_COMCERTO_DW_DMA_SUPPORT=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+CONFIG_SWP_EMULATE=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_OUTER_CACHE=y
+CONFIG_OUTER_CACHE_SYNC=y
+CONFIG_CACHE_L2X0=y
+CONFIG_CACHE_PL310=y
+CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+CONFIG_CPU_HAS_PMU=y
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+# CONFIG_ARM_ERRATA_742230 is not set
+# CONFIG_ARM_ERRATA_742231 is not set
+CONFIG_PL310_ERRATA_588369=y
+CONFIG_ARM_ERRATA_720789=y
+CONFIG_PL310_ERRATA_727915=y
+# CONFIG_ARM_ERRATA_743622 is not set
+# CONFIG_ARM_ERRATA_751472 is not set
+CONFIG_PL310_ERRATA_753970=y
+# CONFIG_ARM_ERRATA_754322 is not set
+# CONFIG_ARM_ERRATA_754327 is not set
+# CONFIG_ARM_ERRATA_764369 is not set
+CONFIG_PL310_ERRATA_769419=y
+CONFIG_ARM_GIC=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+# CONFIG_NO_HZ is not set
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_SMP=y
+CONFIG_SMP_ON_UP=y
+CONFIG_ARM_CPU_TOPOLOGY=y
+# CONFIG_SCHED_MC is not set
+# CONFIG_SCHED_SMT is not set
+CONFIG_HAVE_ARM_SCU=y
+CONFIG_HAVE_ARM_TWD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_NR_CPUS=2
+# CONFIG_HOTPLUG_CPU is not set
+CONFIG_LOCAL_TIMERS=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+# CONFIG_THUMB2_KERNEL is not set
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+CONFIG_HAVE_ARCH_PFN_VALID=y
+# CONFIG_HIGHMEM is not set
+# CONFIG_HW_PERF_EVENTS is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_COMPACTION is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_CLEANCACHE is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_CC_STACKPROTECTOR is not set
+# CONFIG_DEPRECATED_PARAM_STRUCT is not set
+
+#
+# Boot options
+#
+# CONFIG_USE_OF is not set
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_AUTO_ZRELADDR is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_FPE_NWFPE is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_SUSPEND is not set
+# CONFIG_PM_RUNTIME is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_ARM_CPU_SUSPEND is not set
+# CONFIG_NET is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+# CONFIG_BLK_DEV is not set
+# CONFIG_SENSORS_LIS3LV02D is not set
+# CONFIG_MISC_DEVICES is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+# CONFIG_KEYBOARD_ADP5589 is not set
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_QT1070 is not set
+# CONFIG_KEYBOARD_QT2160 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_TCA6416 is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_MCS is not set
+# CONFIG_KEYBOARD_MPR121 is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+# CONFIG_MOUSE_PS2_SENTELIC is not set
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C 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
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_SERIO_PS2MULT is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_TRACE_SINK is not set
+CONFIG_DEVKMEM=y
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_XILINX_PS_UART is not set
+# CONFIG_HVC_DCC is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_RAMOOPS is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_COMPAT is not set
+# CONFIG_I2C_CHARDEV is not set
+# CONFIG_I2C_MUX is not set
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_I2C_SMBUS=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=m
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_ALGOPCA=m
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_PCA_PLATFORM=m
+# CONFIG_I2C_PXA_PCI is not set
+CONFIG_I2C_SIMTEC=m
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+CONFIG_I2C_PARPORT_LIGHT=m
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+
+#
+# PPS generators support
+#
+
+#
+# PTP clock support
+#
+
+#
+# Enable Device Drivers -> PPS to see the PTP clock options.
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB=y
+# CONFIG_SSB_DEBUG is not set
+CONFIG_BCMA_POSSIBLE=y
+
+#
+# Broadcom specific AMBA
+#
+# CONFIG_BCMA is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS6105X is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_TC3589X is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8997 is not set
+# CONFIG_MFD_MAX8998 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_MFD_WL1273_CORE is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+CONFIG_DRM=m
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# CONFIG_FB is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
+# CONFIG_BACKLIGHT_ADP8860 is not set
+# CONFIG_BACKLIGHT_ADP8870 is not set
+
+#
+# Display device support
+#
+CONFIG_DISPLAY_SUPPORT=m
+
+#
+# Display hardware drivers
+#
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# Virtio drivers
+#
+# CONFIG_VIRTIO_BALLOON is not set
+# CONFIG_VIRTIO_MMIO is not set
+# CONFIG_STAGING is not set
+
+#
+# Hardware Spinlock drivers
+#
+CONFIG_IOMMU_SUPPORT=y
+# CONFIG_VIRT_DRIVERS is not set
+# CONFIG_PM_DEVFREQ is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_FSNOTIFY is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+# CONFIG_FANOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE 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_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=2048
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_LOCKUP_DETECTOR is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+# CONFIG_DETECT_HUNG_TASK is not set
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_TEST_LIST_SORT is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_DEBUG_PER_CPU_MAPS is not set
+# CONFIG_LKDTM is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_RING_BUFFER=y
+CONFIG_EVENT_TRACING=y
+CONFIG_EVENT_POWER_TRACING_DEPRECATED=y
+CONFIG_CONTEXT_SWITCH_TRACER=y
+CONFIG_TRACING=y
+CONFIG_GENERIC_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+CONFIG_BLK_DEV_IO_TRACE=y
+# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_RING_BUFFER_BENCHMARK is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_TEST_KSTRTOX is not set
+# CONFIG_STRICT_DEVMEM is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+# CONFIG_CRYPTO is not set
+CONFIG_BINARY_PRINTF=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+# CONFIG_CRC8 is not set
+# CONFIG_XZ_DEC is not set
+# CONFIG_XZ_DEC_BCJ is not set
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_GENERIC_ATOMIC64=y
+# CONFIG_AVERAGE is not set
+# CONFIG_CORDIC is not set
diff --git a/arch/arm/configs/c2kmfcnevm_defconfig b/arch/arm/configs/c2kmfcnevm_defconfig
new file mode 100644
index 0000000..2e12bbf
--- /dev/null
+++ b/arch/arm/configs/c2kmfcnevm_defconfig
@@ -0,0 +1,1047 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Linux/arm 3.2.2 Kernel Configuration
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_KTIME_SCALAR=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_ARM_PATCH_PHYS_VIRT=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_HAVE_IRQ_WORK=y
+CONFIG_IRQ_WORK=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+CONFIG_DEFAULT_HOSTNAME="(none)"
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+# CONFIG_FHANDLE is not set
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_HAVE_SPARSE_IRQ=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_IRQ_DOMAIN=y
+# CONFIG_SPARSE_IRQ is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+# CONFIG_CGROUP_FREEZER is not set
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_PROC_PID_CPUSET=y
+CONFIG_CGROUP_CPUACCT=y
+# CONFIG_RESOURCE_COUNTERS is not set
+# CONFIG_CGROUP_PERF is not set
+# CONFIG_CGROUP_SCHED is not set
+# CONFIG_BLK_CGROUP is not set
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+CONFIG_USER_NS=y
+CONFIG_PID_NS=y
+# CONFIG_SCHED_AUTOGROUP is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+# CONFIG_EXPERT is not set
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+# CONFIG_EMBEDDED is not set
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_PERF_EVENTS=y
+# CONFIG_PERF_COUNTERS is not set
+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_PROFILING is not set
+CONFIG_TRACEPOINTS=y
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_HW_BREAKPOINT=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_BSGLIB is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+# CONFIG_FREEZER is not set
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_INTEGRATOR is not set
+CONFIG_ARCH_COMCERTO=y
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_VEXPRESS is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCMRING is not set
+# CONFIG_ARCH_HIGHBANK is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_PRIMA2 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_MXS is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_DOVE is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LPC32XX is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_TEGRA is not set
+# CONFIG_ARCH_PICOXCELL is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_SHMOBILE is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5P64X0 is not set
+# CONFIG_ARCH_S5PC100 is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_EXYNOS is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_TCC_926 is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_U8500 is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_PLAT_SPEAR is not set
+# CONFIG_ARCH_VT8500 is not set
+# CONFIG_ARCH_ZYNQ is not set
+# CONFIG_ARCH_SUPPORTS_BIG_ENDIAN is not set
+
+#
+# System MMU
+#
+
+#
+# Comcerto Implementation Options
+#
+CONFIG_ARCH_M86XXX=y
+# CONFIG_C2K_EVM is not set
+CONFIG_C2K_MFCN_EVM=y
+# CONFIG_C2K_ASIC is not set
+# CONFIG_RTSM_C2K is not set
+CONFIG_MTD_COMCERTO_NOR=y
+CONFIG_COMCERTO_TDM_CLOCK=y
+# CONFIG_PCI is not set
+CONFIG_COMCERTO_NUM_PCIES=2
+CONFIG_COMCERTO_FP=y
+# CONFIG_COMCERTO_UART0_SUPPORT is not set
+CONFIG_COMCERTO_UART1_SUPPORT=y
+CONFIG_COMCERTO_USB0_SUPPORT=y
+# CONFIG_COMCERTO_USB1_SUPPORT is not set
+CONFIG_COMCERTO_IPSEC_SUPPORT=y
+CONFIG_COMCERTO_SPI_SUPPORT=y
+CONFIG_COMCERTO_FAST_SPI_SUPPORT=y
+CONFIG_COMCERTO_I2C_SUPPORT=y
+CONFIG_COMCERTO_DW_DMA_SUPPORT=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_SWP_EMULATE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_OUTER_CACHE=y
+CONFIG_OUTER_CACHE_SYNC=y
+CONFIG_CACHE_L2X0=y
+CONFIG_CACHE_PL310=y
+CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+CONFIG_CPU_HAS_PMU=y
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+CONFIG_ARM_ERRATA_742230=y
+CONFIG_ARM_ERRATA_742231=y
+CONFIG_PL310_ERRATA_588369=y
+CONFIG_ARM_ERRATA_720789=y
+CONFIG_PL310_ERRATA_727915=y
+CONFIG_ARM_ERRATA_743622=y
+CONFIG_ARM_ERRATA_751472=y
+CONFIG_PL310_ERRATA_753970=y
+CONFIG_ARM_ERRATA_754322=y
+# CONFIG_ARM_ERRATA_754327 is not set
+CONFIG_ARM_ERRATA_764369=y
+CONFIG_PL310_ERRATA_769419=y
+CONFIG_ARM_GIC=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+# CONFIG_NO_HZ is not set
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_SMP=y
+# CONFIG_SMP_ON_UP is not set
+CONFIG_ARM_CPU_TOPOLOGY=y
+# CONFIG_SCHED_MC is not set
+# CONFIG_SCHED_SMT is not set
+CONFIG_HAVE_ARM_SCU=y
+CONFIG_HAVE_ARM_TWD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_NR_CPUS=2
+# CONFIG_HOTPLUG_CPU is not set
+CONFIG_LOCAL_TIMERS=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+CONFIG_HAVE_ARCH_PFN_VALID=y
+# CONFIG_HIGHMEM is not set
+CONFIG_HW_PERF_EVENTS=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_COMPACTION is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_CLEANCACHE is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_CC_STACKPROTECTOR is not set
+# CONFIG_DEPRECATED_PARAM_STRUCT is not set
+
+#
+# Boot options
+#
+# CONFIG_USE_OF is not set
+CONFIG_ZBOOT_ROM_TEXT=0x00608000
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_ZBOOT_ROM=y
+CONFIG_CMDLINE=""
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+
+#
+# CPU Power Management
+#
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_SUSPEND is not set
+# CONFIG_PM_RUNTIME is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_ARM_CPU_SUSPEND is not set
+# CONFIG_NET is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_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_SM_FTL 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_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=y
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_RAM=y
+CONFIG_MTD_ROM=y
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT 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 is not set
+# 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_DOCG3 is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+# CONFIG_BLK_DEV is not set
+# CONFIG_SENSORS_LIS3LV02D is not set
+# CONFIG_MISC_DEVICES is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+# CONFIG_KEYBOARD_ADP5589 is not set
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_QT1070 is not set
+# CONFIG_KEYBOARD_QT2160 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_TCA6416 is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_MCS is not set
+# CONFIG_KEYBOARD_MPR121 is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+# CONFIG_MOUSE_PS2_SENTELIC is not set
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C 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
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_SERIO_PS2MULT is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_TRACE_SINK is not set
+CONFIG_DEVKMEM=y
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_XILINX_PS_UART is not set
+# CONFIG_HVC_DCC is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_RAMOOPS is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_COMPAT is not set
+# CONFIG_I2C_CHARDEV is not set
+# CONFIG_I2C_MUX is not set
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_I2C_SMBUS=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=m
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_ALGOPCA=m
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_COMCERTO=y
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_PCA_PLATFORM=m
+# CONFIG_I2C_PXA_PCI is not set
+CONFIG_I2C_SIMTEC=m
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+CONFIG_I2C_PARPORT_LIGHT=m
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_SPI is not set
+CONFIG_SPI_MSPD=y
+CONFIG_COMCERTO_SPI=y
+
+#
+# Miscellaneous I2C Chip support
+#
+CONFIG_EEPROM_AT=y
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+
+#
+# PPS generators support
+#
+
+#
+# PTP clock support
+#
+
+#
+# Enable Device Drivers -> PPS to see the PTP clock options.
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB=y
+# CONFIG_SSB_DEBUG is not set
+CONFIG_BCMA_POSSIBLE=y
+
+#
+# Broadcom specific AMBA
+#
+# CONFIG_BCMA is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS6105X is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_TC3589X is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8997 is not set
+# CONFIG_MFD_MAX8998 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_MFD_WL1273_CORE is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+CONFIG_DRM=m
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# CONFIG_FB is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
+# CONFIG_BACKLIGHT_ADP8860 is not set
+# CONFIG_BACKLIGHT_ADP8870 is not set
+
+#
+# Display device support
+#
+CONFIG_DISPLAY_SUPPORT=m
+
+#
+# Display hardware drivers
+#
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# Virtio drivers
+#
+# CONFIG_VIRTIO_BALLOON is not set
+# CONFIG_VIRTIO_MMIO is not set
+# CONFIG_STAGING is not set
+
+#
+# Hardware Spinlock drivers
+#
+CONFIG_IOMMU_SUPPORT=y
+# CONFIG_VIRT_DRIVERS is not set
+# CONFIG_PM_DEVFREQ is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_FSNOTIFY is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+# CONFIG_FANOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE 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_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# 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=1
+# CONFIG_JFFS2_FS_WRITEBUFFER 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_LOGFS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_PSTORE is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=2048
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_LOCKUP_DETECTOR is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+# CONFIG_DETECT_HUNG_TASK is not set
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_TEST_LIST_SORT is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_DEBUG_PER_CPU_MAPS is not set
+# CONFIG_LKDTM is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_RING_BUFFER=y
+CONFIG_EVENT_TRACING=y
+CONFIG_EVENT_POWER_TRACING_DEPRECATED=y
+CONFIG_CONTEXT_SWITCH_TRACER=y
+CONFIG_TRACING=y
+CONFIG_GENERIC_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+CONFIG_BLK_DEV_IO_TRACE=y
+# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_RING_BUFFER_BENCHMARK is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_TEST_KSTRTOX is not set
+# CONFIG_STRICT_DEVMEM is not set
+# CONFIG_ARM_UNWIND is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+# CONFIG_CRYPTO is not set
+CONFIG_BINARY_PRINTF=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+# CONFIG_CRC8 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+# CONFIG_XZ_DEC is not set
+# CONFIG_XZ_DEC_BCJ is not set
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+# CONFIG_AVERAGE is not set
+# CONFIG_CORDIC is not set
diff --git a/arch/arm/configs/c2krtsm_defconfig b/arch/arm/configs/c2krtsm_defconfig
new file mode 100644
index 0000000..987f396
--- /dev/null
+++ b/arch/arm/configs/c2krtsm_defconfig
@@ -0,0 +1,1034 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Linux/arm 3.2.2 Kernel Configuration
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_KTIME_SCALAR=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_ARM_PATCH_PHYS_VIRT=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_HAVE_IRQ_WORK=y
+CONFIG_IRQ_WORK=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+CONFIG_DEFAULT_HOSTNAME="(none)"
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+# CONFIG_FHANDLE is not set
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_HAVE_SPARSE_IRQ=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_IRQ_DOMAIN=y
+# CONFIG_SPARSE_IRQ is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+# CONFIG_CGROUP_FREEZER is not set
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_PROC_PID_CPUSET=y
+CONFIG_CGROUP_CPUACCT=y
+# CONFIG_RESOURCE_COUNTERS is not set
+# CONFIG_CGROUP_PERF is not set
+# CONFIG_CGROUP_SCHED is not set
+# CONFIG_BLK_CGROUP is not set
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+CONFIG_USER_NS=y
+CONFIG_PID_NS=y
+# CONFIG_SCHED_AUTOGROUP is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+# CONFIG_EXPERT is not set
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+# CONFIG_EMBEDDED is not set
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_PERF_EVENTS=y
+# CONFIG_PERF_COUNTERS is not set
+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_PROFILING is not set
+CONFIG_TRACEPOINTS=y
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_HW_BREAKPOINT=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_BSGLIB is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+# CONFIG_FREEZER is not set
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_INTEGRATOR is not set
+CONFIG_ARCH_COMCERTO=y
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_VEXPRESS is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCMRING is not set
+# CONFIG_ARCH_HIGHBANK is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_PRIMA2 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_MXS is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_DOVE is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LPC32XX is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_TEGRA is not set
+# CONFIG_ARCH_PICOXCELL is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_SHMOBILE is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5P64X0 is not set
+# CONFIG_ARCH_S5PC100 is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_EXYNOS is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_TCC_926 is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_U8500 is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_PLAT_SPEAR is not set
+# CONFIG_ARCH_VT8500 is not set
+# CONFIG_ARCH_ZYNQ is not set
+# CONFIG_ARCH_SUPPORTS_BIG_ENDIAN is not set
+
+#
+# System MMU
+#
+
+#
+# Comcerto Implementation Options
+#
+CONFIG_ARCH_M86XXX=y
+# CONFIG_C2K_EVM is not set
+# CONFIG_C2K_ASIC is not set
+CONFIG_RTSM_C2K=y
+CONFIG_MTD_COMCERTO_NOR=y
+CONFIG_COMCERTO_TDM_CLOCK=y
+CONFIG_COMCERTO_NUM_PCIES=2
+CONFIG_COMCERTO_FP=y
+# CONFIG_COMCERTO_UART0_SUPPORT is not set
+CONFIG_COMCERTO_UART1_SUPPORT=y
+CONFIG_COMCERTO_USB0_SUPPORT=y
+# CONFIG_COMCERTO_USB1_SUPPORT is not set
+CONFIG_COMCERTO_IPSEC_SUPPORT=y
+CONFIG_COMCERTO_SPI_SUPPORT=y
+CONFIG_COMCERTO_FAST_SPI_SUPPORT=y
+CONFIG_COMCERTO_I2C_SUPPORT=y
+CONFIG_COMCERTO_DW_DMA_SUPPORT=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_SWP_EMULATE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_OUTER_CACHE=y
+CONFIG_OUTER_CACHE_SYNC=y
+CONFIG_CACHE_L2X0=y
+CONFIG_CACHE_PL310=y
+CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+CONFIG_CPU_HAS_PMU=y
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+CONFIG_ARM_ERRATA_742230=y
+CONFIG_ARM_ERRATA_742231=y
+CONFIG_PL310_ERRATA_588369=y
+CONFIG_ARM_ERRATA_720789=y
+CONFIG_PL310_ERRATA_727915=y
+CONFIG_ARM_ERRATA_743622=y
+CONFIG_ARM_ERRATA_751472=y
+CONFIG_PL310_ERRATA_753970=y
+CONFIG_ARM_ERRATA_754322=y
+# CONFIG_ARM_ERRATA_754327 is not set
+CONFIG_ARM_ERRATA_764369=y
+CONFIG_PL310_ERRATA_769419=y
+CONFIG_ARM_GIC=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+# CONFIG_NO_HZ is not set
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_SMP=y
+# CONFIG_SMP_ON_UP is not set
+CONFIG_ARM_CPU_TOPOLOGY=y
+# CONFIG_SCHED_MC is not set
+# CONFIG_SCHED_SMT is not set
+CONFIG_HAVE_ARM_SCU=y
+CONFIG_HAVE_ARM_TWD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_NR_CPUS=2
+# CONFIG_HOTPLUG_CPU is not set
+CONFIG_LOCAL_TIMERS=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+CONFIG_HAVE_ARCH_PFN_VALID=y
+# CONFIG_HIGHMEM is not set
+# CONFIG_HW_PERF_EVENTS is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_COMPACTION is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_CLEANCACHE is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_CC_STACKPROTECTOR is not set
+# CONFIG_DEPRECATED_PARAM_STRUCT is not set
+
+#
+# Boot options
+#
+# CONFIG_USE_OF is not set
+CONFIG_ZBOOT_ROM_TEXT=0x00608000
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_ZBOOT_ROM=y
+CONFIG_CMDLINE=""
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+
+#
+# CPU Power Management
+#
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_SUSPEND is not set
+# CONFIG_PM_RUNTIME is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_ARM_CPU_SUSPEND is not set
+# CONFIG_NET is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_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_SM_FTL 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_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=y
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_RAM=y
+CONFIG_MTD_ROM=y
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT 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 is not set
+# 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_DOCG3 is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+# CONFIG_BLK_DEV is not set
+# CONFIG_SENSORS_LIS3LV02D is not set
+# CONFIG_MISC_DEVICES is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+# CONFIG_KEYBOARD_ADP5589 is not set
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_QT1070 is not set
+# CONFIG_KEYBOARD_QT2160 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_TCA6416 is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_MCS is not set
+# CONFIG_KEYBOARD_MPR121 is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+# CONFIG_MOUSE_PS2_SENTELIC is not set
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C 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
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_SERIO_PS2MULT is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_TRACE_SINK is not set
+CONFIG_DEVKMEM=y
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_XILINX_PS_UART is not set
+# CONFIG_HVC_DCC is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_RAMOOPS is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_COMPAT is not set
+# CONFIG_I2C_CHARDEV is not set
+# CONFIG_I2C_MUX is not set
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_I2C_SMBUS=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=m
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_ALGOPCA=m
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_PCA_PLATFORM=m
+# CONFIG_I2C_PXA_PCI is not set
+CONFIG_I2C_SIMTEC=m
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+CONFIG_I2C_PARPORT_LIGHT=m
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+
+#
+# PPS generators support
+#
+
+#
+# PTP clock support
+#
+
+#
+# Enable Device Drivers -> PPS to see the PTP clock options.
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB=y
+# CONFIG_SSB_DEBUG is not set
+CONFIG_BCMA_POSSIBLE=y
+
+#
+# Broadcom specific AMBA
+#
+# CONFIG_BCMA is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS6105X is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_TC3589X is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8997 is not set
+# CONFIG_MFD_MAX8998 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_MFD_WL1273_CORE is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+CONFIG_DRM=m
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# CONFIG_FB is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
+# CONFIG_BACKLIGHT_ADP8860 is not set
+# CONFIG_BACKLIGHT_ADP8870 is not set
+
+#
+# Display device support
+#
+CONFIG_DISPLAY_SUPPORT=m
+
+#
+# Display hardware drivers
+#
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# Virtio drivers
+#
+# CONFIG_VIRTIO_BALLOON is not set
+# CONFIG_VIRTIO_MMIO is not set
+# CONFIG_STAGING is not set
+
+#
+# Hardware Spinlock drivers
+#
+CONFIG_IOMMU_SUPPORT=y
+# CONFIG_VIRT_DRIVERS is not set
+# CONFIG_PM_DEVFREQ is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_FSNOTIFY is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+# CONFIG_FANOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE 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_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# 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=1
+# CONFIG_JFFS2_FS_WRITEBUFFER 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_LOGFS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_PSTORE is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=2048
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_LOCKUP_DETECTOR is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+# CONFIG_DETECT_HUNG_TASK is not set
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_TEST_LIST_SORT is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_DEBUG_PER_CPU_MAPS is not set
+# CONFIG_LKDTM is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_RING_BUFFER=y
+CONFIG_EVENT_TRACING=y
+CONFIG_EVENT_POWER_TRACING_DEPRECATED=y
+CONFIG_CONTEXT_SWITCH_TRACER=y
+CONFIG_TRACING=y
+CONFIG_GENERIC_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+CONFIG_BLK_DEV_IO_TRACE=y
+# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_RING_BUFFER_BENCHMARK is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_TEST_KSTRTOX is not set
+# CONFIG_STRICT_DEVMEM is not set
+# CONFIG_ARM_UNWIND is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+# CONFIG_CRYPTO is not set
+CONFIG_BINARY_PRINTF=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+# CONFIG_CRC8 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+# CONFIG_XZ_DEC is not set
+# CONFIG_XZ_DEC_BCJ is not set
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+# CONFIG_AVERAGE is not set
+# CONFIG_CORDIC is not set
diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h
index 86976d0..293fabf 100644
--- a/arch/arm/include/asm/atomic.h
+++ b/arch/arm/include/asm/atomic.h
@@ -29,6 +29,27 @@
 
 #if __LINUX_ARM_ARCH__ >= 6
 
+#ifdef CONFIG_COMCERTO_ZONE_DMA_NCNB
+
+int comcerto_atomic_add(int i, atomic_t *v);
+int comcerto_atomic_cmpxchg(atomic_t *v, int old, int new);
+void comcerto_atomic_clear_mask(unsigned long mask, unsigned long *addr);
+
+
+struct virtual_zone {
+	void *start;
+	void *end;
+};
+
+extern struct virtual_zone arm_dma_zone;
+
+static inline bool is_dma_zone_virtual_address(void *addr)
+{
+	return ((addr < arm_dma_zone.end) && (addr >= arm_dma_zone.start));
+}
+
+#endif
+
 /*
  * ARMv6 UP and SMP safe atomic ops.  We use load exclusive and
  * store exclusive to ensure that these are atomic.  We may loop
@@ -39,6 +60,13 @@
 	unsigned long tmp;
 	int result;
 
+#ifdef CONFIG_COMCERTO_ZONE_DMA_NCNB
+	if (unlikely(is_dma_zone_virtual_address(v))) {
+		comcerto_atomic_add(i, v);
+		return;
+	}
+#endif
+
 	__asm__ __volatile__("@ atomic_add\n"
 "1:	ldrex	%0, [%3]\n"
 "	add	%0, %0, %4\n"
@@ -55,6 +83,11 @@
 	unsigned long tmp;
 	int result;
 
+#ifdef CONFIG_COMCERTO_ZONE_DMA_NCNB
+	if (unlikely(is_dma_zone_virtual_address(v)))
+		return comcerto_atomic_add(i, v);
+#endif
+
 	smp_mb();
 
 	__asm__ __volatile__("@ atomic_add_return\n"
@@ -77,6 +110,13 @@
 	unsigned long tmp;
 	int result;
 
+#ifdef CONFIG_COMCERTO_ZONE_DMA_NCNB
+	if (unlikely(is_dma_zone_virtual_address(v))) {
+		comcerto_atomic_add(-i, v);
+		return;
+	}
+#endif
+
 	__asm__ __volatile__("@ atomic_sub\n"
 "1:	ldrex	%0, [%3]\n"
 "	sub	%0, %0, %4\n"
@@ -93,6 +133,11 @@
 	unsigned long tmp;
 	int result;
 
+#ifdef CONFIG_COMCERTO_ZONE_DMA_NCNB
+	if (unlikely(is_dma_zone_virtual_address(v)))
+		return comcerto_atomic_add(-i, v);
+#endif
+
 	smp_mb();
 
 	__asm__ __volatile__("@ atomic_sub_return\n"
@@ -114,6 +159,11 @@
 {
 	unsigned long oldval, res;
 
+#ifdef CONFIG_COMCERTO_ZONE_DMA_NCNB
+	if (unlikely(is_dma_zone_virtual_address(ptr)))
+		return comcerto_atomic_cmpxchg(ptr, old, new);
+#endif
+
 	smp_mb();
 
 	do {
@@ -136,6 +186,13 @@
 {
 	unsigned long tmp, tmp2;
 
+#ifdef CONFIG_COMCERTO_ZONE_DMA_NCNB
+	if (unlikely(is_dma_zone_virtual_address(addr))) {
+		atomic_clear_mask(mask, addr);
+		return;
+	}
+#endif
+
 	__asm__ __volatile__("@ atomic_clear_mask\n"
 "1:	ldrex	%0, [%3]\n"
 "	bic	%0, %0, %4\n"
diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h
index 0e9ce8d..7f02c54 100644
--- a/arch/arm/include/asm/elf.h
+++ b/arch/arm/include/asm/elf.h
@@ -109,7 +109,7 @@
 #define ELF_CORE_COPY_TASK_REGS dump_task_regs
 
 #define CORE_DUMP_USE_REGSET
-#define ELF_EXEC_PAGESIZE	4096
+#define ELF_EXEC_PAGESIZE	(PAGE_SIZE)
 
 /* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
    use of this is to invoke "./ld.so someprog" to test out a new version of
diff --git a/arch/arm/include/asm/entry-macro-multi.S b/arch/arm/include/asm/entry-macro-multi.S
index 88d6181..f6546a9 100644
--- a/arch/arm/include/asm/entry-macro-multi.S
+++ b/arch/arm/include/asm/entry-macro-multi.S
@@ -4,8 +4,8 @@
  * Interrupt handling.  Preserves r7, r8, r9
  */
 	.macro	arch_irq_handler_default
-	get_irqnr_preamble r6, lr
-1:	get_irqnr_and_base r0, r2, r6, lr
+	get_irqnr_preamble r6, r3, lr
+1:	get_irqnr_and_base r0, r2, r6, r3, lr
 	movne	r1, sp
 	@
 	@ routine called with r0 = irq number, r1 = struct pt_regs *
diff --git a/arch/arm/include/asm/fixmap.h b/arch/arm/include/asm/fixmap.h
index bbae919..ac9fa8a 100644
--- a/arch/arm/include/asm/fixmap.h
+++ b/arch/arm/include/asm/fixmap.h
@@ -13,7 +13,7 @@
  * 0xfffe0000 and 0xfffeffff.
  */
 
-#define FIXADDR_START		0xfff00000UL
+#define FIXADDR_START		0xfff30000UL
 #define FIXADDR_TOP		0xfffe0000UL
 #define FIXADDR_SIZE		(FIXADDR_TOP - FIXADDR_START)
 
diff --git a/arch/arm/include/asm/glue-proc.h b/arch/arm/include/asm/glue-proc.h
index e2be7f1..6e94826 100644
--- a/arch/arm/include/asm/glue-proc.h
+++ b/arch/arm/include/asm/glue-proc.h
@@ -256,6 +256,7 @@
 #define cpu_dcache_clean_area		__glue(CPU_NAME,_dcache_clean_area)
 #define cpu_do_switch_mm		__glue(CPU_NAME,_switch_mm)
 #define cpu_set_pte_ext			__glue(CPU_NAME,_set_pte_ext)
+#define cpu_uncache_pte_ext		__glue(CPU_NAME,_uncache_pte_ext)
 #define cpu_suspend_size		__glue(CPU_NAME,_suspend_size)
 #define cpu_do_suspend			__glue(CPU_NAME,_do_suspend)
 #define cpu_do_resume			__glue(CPU_NAME,_do_resume)
diff --git a/arch/arm/include/asm/hardware/entry-macro-gic.S b/arch/arm/include/asm/hardware/entry-macro-gic.S
index 74ebc80..56daa10 100644
--- a/arch/arm/include/asm/hardware/entry-macro-gic.S
+++ b/arch/arm/include/asm/hardware/entry-macro-gic.S
@@ -11,7 +11,7 @@
 #include <asm/hardware/gic.h>
 
 #ifndef HAVE_GET_IRQNR_PREAMBLE
-	.macro	get_irqnr_preamble, base, tmp
+	.macro	get_irqnr_preamble, base, pending_intr, tmp
 	ldr	\base, =gic_cpu_base_addr
 	ldr	\base, [\base]
 	.endm
@@ -32,17 +32,61 @@
  * valid range for an IRQ (30-1020 inclusive).
  */
 
-	.macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
+	.macro  get_irqnr_and_base, irqnr, irqstat, base, pending_intr, tmp
+
+#ifdef CONFIG_COMCERTO_MSP
+	ldr     \irqstat, [\base, #GIC_CPU_HIGHPRI]
+	bic     \irqnr, \irqstat, #0x1c00
+	cmp     \irqnr, #33
+	cmpne   \irqnr, #66
+	cmpne   \irqnr, #87
+	cmpeq   \irqnr, \irqnr
+	bne 1001f
+
+	mov \irqnr, \irqnr /* breakpoint here */
+
+	beq 1002f
+
+1001:
+#endif /* CONFIG_COMCERTO_MSP */
 
 	ldr     \irqstat, [\base, #GIC_CPU_INTACK]
 	/* bits 12-10 = src CPU, 9-0 = int # */
 
-	ldr	\tmp, =1021
 	bic     \irqnr, \irqstat, #0x1c00
+	
+#ifdef CONFIG_COMCERTO_MSP
+	cmp     \irqnr, #33
+	streq	\irqstat, [\base, #GIC_CPU_EOI]
+	ldreq	\tmp, =0x2	//2 on bit1
+	ldreq	\pending_intr, =COMCERTO_DISTR_INT_SET_PENDING_OFFSET_4
+	streq	\tmp, [\pending_intr]
+	beq	1002f
+
+	cmpne   \irqnr, #66
+	streq	\irqstat, [\base, #GIC_CPU_EOI]
+	ldreq	\tmp, =0x4	//4 on bit 2
+	ldreq	\pending_intr, =COMCERTO_DISTR_INT_SET_PENDING_OFFSET_8
+	streq	\tmp, [\pending_intr]
+	beq	1002f
+
+	cmpne   \irqnr, #87
+	streq	\irqstat, [\base, #GIC_CPU_EOI]
+	ldreq	\tmp, =0x800000	//0x800000 on bit 23
+	ldreq	\pending_intr, =COMCERTO_DISTR_INT_SET_PENDING_OFFSET_8
+	streq	\tmp, [\pending_intr]
+	beq	1002f
+#endif /* CONFIG_COMCERTO_MSP */
+	ldr	\tmp, =1021
 	cmp     \irqnr, #15
 	cmpcc	\irqnr, \irqnr
 	cmpne	\irqnr, \tmp
 	cmpcs	\irqnr, \irqnr
+
+#ifdef CONFIG_COMCERTO_MSP
+1002:
+#endif /* CONFIG_COMCERTO_MSP */
+
 	.endm
 
 /* We assume that irqstat (the raw value of the IRQ acknowledge
diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h
index 3e91f22..7177ea1 100644
--- a/arch/arm/include/asm/hardware/gic.h
+++ b/arch/arm/include/asm/hardware/gic.h
@@ -22,6 +22,7 @@
 
 #define GIC_DIST_CTRL			0x000
 #define GIC_DIST_CTR			0x004
+#define GIC_DIST_SECURITY_BIT		0x080
 #define GIC_DIST_ENABLE_SET		0x100
 #define GIC_DIST_ENABLE_CLEAR		0x180
 #define GIC_DIST_PENDING_SET		0x200
diff --git a/arch/arm/include/asm/kexec.h b/arch/arm/include/asm/kexec.h
index c2b9b4b..ddd7fbc 100644
--- a/arch/arm/include/asm/kexec.h
+++ b/arch/arm/include/asm/kexec.h
@@ -10,7 +10,7 @@
 /* Maximum address we can use for the control code buffer */
 #define KEXEC_CONTROL_MEMORY_LIMIT (-1UL)
 
-#define KEXEC_CONTROL_PAGE_SIZE	4096
+#define KEXEC_CONTROL_PAGE_SIZE	(PAGE_SIZE)
 
 #define KEXEC_ARCH KEXEC_ARCH_ARM
 
diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h
index b36f365..520d5b6 100644
--- a/arch/arm/include/asm/mach/map.h
+++ b/arch/arm/include/asm/mach/map.h
@@ -30,6 +30,8 @@
 #define MT_MEMORY_DTCM		12
 #define MT_MEMORY_ITCM		13
 #define MT_MEMORY_SO		14
+#define MT_MSP				15
+#define MT_MSP_NCNB			16
 
 #ifdef CONFIG_MMU
 extern void iotable_init(struct map_desc *, int);
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index a8997d7..a8941af 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -35,28 +35,31 @@
  * TASK_SIZE - the maximum size of a user space task.
  * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area
  */
+#include <asm/pgtable-2level.h>
+#if !defined(CONFIG_COMCERTO_64K_PAGES)
 #define PAGE_OFFSET		UL(CONFIG_PAGE_OFFSET)
 #define TASK_SIZE		(UL(CONFIG_PAGE_OFFSET) - UL(0x01000000))
 #define TASK_UNMAPPED_BASE	(UL(CONFIG_PAGE_OFFSET) / 3)
-
+#else
+#define PAGE_OFFSET		UL(CONFIG_PAGE_OFFSET)
+#define TASK_SIZE		((UL(CONFIG_PAGE_OFFSET) - UL(0x01000000)) & ~(UL((1 << PMD_SHIFT)-1)))  // Must be aligned on PMD size (kernel/user space can share same PMD)
+#define TASK_UNMAPPED_BASE	(UL(CONFIG_PAGE_OFFSET) / 3)
+#endif
 /*
  * The maximum size of a 26-bit user space task.
  */
 #define TASK_SIZE_26		UL(0x04000000)
 
+#ifndef CONFIG_COMCERTO_ZONE_DMA_NCNB
 /*
  * The module space lives between the addresses given by TASK_SIZE
  * and PAGE_OFFSET - it must be within 32MB of the kernel text.
  */
 #ifndef CONFIG_THUMB2_KERNEL
-#define MODULES_VADDR		(PAGE_OFFSET - 16*1024*1024)
+#define MODULES_VADDR	(PAGE_OFFSET - 16*1024*1024)
 #else
 /* smaller range for Thumb-2 symbols relocation (2^24)*/
-#define MODULES_VADDR		(PAGE_OFFSET - 8*1024*1024)
-#endif
-
-#if TASK_SIZE > MODULES_VADDR
-#error Top of user space clashes with start of module space
+#define MODULES_VADDR	(PAGE_OFFSET - 8*1024*1024)
 #endif
 
 /*
@@ -68,6 +71,22 @@
 #define MODULES_END		(PAGE_OFFSET)
 #endif
 
+#else
+/* Move module space into the hole reserved for MSP/PFE so we can have a bigger DMA zone */
+#define MODULES_END		((COMCERTO_DDR_SHARED_BASE + COMCERTO_DDR_SHARED_SIZE - PLAT_PHYS_OFFSET + PAGE_OFFSET) & PMD_MASK) // convert SHARED_END to virt and align on lower PMD boundary
+
+#ifndef CONFIG_THUMB2_KERNEL
+#define MODULES_VADDR	(MODULES_END - 16*1024*1024)
+#else
+#define MODULES_VADDR	(MODULES_END - 10*1024*1024) // Relocations will be guaranteed to work as long as kernel size is less than 6MB
+#endif
+
+#endif
+
+#if TASK_SIZE > MODULES_VADDR
+#error Top of user space clashes with start of module space
+#endif
+
 /*
  * The XIP kernel gets mapped at the bottom of the module vm area.
  * Since we use sections to map it, this macro replaces the physical address
diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h
index ca94653..0cb69e04 100644
--- a/arch/arm/include/asm/page.h
+++ b/arch/arm/include/asm/page.h
@@ -11,7 +11,11 @@
 #define _ASMARM_PAGE_H
 
 /* PAGE_SHIFT determines the page size */
+#if !defined(CONFIG_COMCERTO_64K_PAGES)
 #define PAGE_SHIFT		12
+#else
+#define PAGE_SHIFT		16
+#endif
 #define PAGE_SIZE		(_AC(1,UL) << PAGE_SHIFT)
 #define PAGE_MASK		(~(PAGE_SIZE-1))
 
diff --git a/arch/arm/include/asm/param.h b/arch/arm/include/asm/param.h
index 8b24bf94..88367aa 100644
--- a/arch/arm/include/asm/param.h
+++ b/arch/arm/include/asm/param.h
@@ -18,7 +18,11 @@
 # define HZ		100
 #endif
 
+#if !defined(CONFIG_COMCERTO_64K_PAGES)
 #define EXEC_PAGESIZE	4096
+#else
+#define EXEC_PAGESIZE	65536
+#endif
 
 #ifndef NOGROUP
 #define NOGROUP         (-1)
diff --git a/arch/arm/include/asm/pgalloc.h b/arch/arm/include/asm/pgalloc.h
index 3e08fd3..1a9413a 100644
--- a/arch/arm/include/asm/pgalloc.h
+++ b/arch/arm/include/asm/pgalloc.h
@@ -108,8 +108,17 @@
 				  pmdval_t prot)
 {
 	pmdval_t pmdval = (pte + PTE_HWTABLE_OFF) | prot;
+#if !defined(CONFIG_COMCERTO_64K_PAGES)
 	pmdp[0] = __pmd(pmdval);
 	pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t));
+#else
+	int i, off = 0;
+	for (i = 0; i < LINKED_PMDS; i++) {
+		pmdp[i] = __pmd(pmdval + off);
+		off += 1024; // Each PMD points to a 1kB 2nd-level table
+	}
+
+#endif
 	flush_pmd_entry(pmdp);
 }
 
diff --git a/arch/arm/include/asm/pgtable-2level-hwdef.h b/arch/arm/include/asm/pgtable-2level-hwdef.h
index 5cfba15..01bbb91 100644
--- a/arch/arm/include/asm/pgtable-2level-hwdef.h
+++ b/arch/arm/include/asm/pgtable-2level-hwdef.h
@@ -65,7 +65,13 @@
 /*
  *   - extended small page/tiny page
  */
+#if !defined(CONFIG_COMCERTO_64K_PAGES)
 #define PTE_EXT_XN		(_AT(pteval_t, 1) << 0)		/* v6 */
+#define PTE_EXT_TEX(x)		(_AT(pteval_t, (x)) << 6)	/* v5 */
+#else
+#define PTE_EXT_XN		(_AT(pteval_t, 1) << 15)		/* v6 */
+#define PTE_EXT_TEX(x)		(_AT(pteval_t, (x)) << 12)	/* v5 */
+#endif
 #define PTE_EXT_AP_MASK		(_AT(pteval_t, 3) << 4)
 #define PTE_EXT_AP0		(_AT(pteval_t, 1) << 4)
 #define PTE_EXT_AP1		(_AT(pteval_t, 2) << 4)
@@ -73,7 +79,6 @@
 #define PTE_EXT_AP_UNO_SRW	(PTE_EXT_AP0)
 #define PTE_EXT_AP_URO_SRW	(PTE_EXT_AP1)
 #define PTE_EXT_AP_URW_SRW	(PTE_EXT_AP1|PTE_EXT_AP0)
-#define PTE_EXT_TEX(x)		(_AT(pteval_t, (x)) << 6)	/* v5 */
 #define PTE_EXT_APX		(_AT(pteval_t, 1) << 9)		/* v6 */
 #define PTE_EXT_COHERENT	(_AT(pteval_t, 1) << 9)		/* XScale3 */
 #define PTE_EXT_SHARED		(_AT(pteval_t, 1) << 10)	/* v6 */
diff --git a/arch/arm/include/asm/pgtable-2level-types.h b/arch/arm/include/asm/pgtable-2level-types.h
index 66cb5b0..ad48bf6 100644
--- a/arch/arm/include/asm/pgtable-2level-types.h
+++ b/arch/arm/include/asm/pgtable-2level-types.h
@@ -24,12 +24,17 @@
 typedef u32 pteval_t;
 typedef u32 pmdval_t;
 
+#if !defined(CONFIG_COMCERTO_64K_PAGES)
 #undef STRICT_MM_TYPECHECKS
+#else
+#define STRICT_MM_TYPECHECKS	1
+#endif
 
 #ifdef STRICT_MM_TYPECHECKS
 /*
  * These are used to make use of C type-checking..
  */
+#if !defined(CONFIG_COMCERTO_64K_PAGES)
 typedef struct { pteval_t pte; } pte_t;
 typedef struct { pmdval_t pmd; } pmd_t;
 typedef struct { pmdval_t pgd[2]; } pgd_t;
@@ -45,6 +50,23 @@
 #define __pgprot(x)     ((pgprot_t) { (x) } )
 
 #else
+#include <asm/pgtable-2level.h>
+typedef struct { pteval_t pte[16]; } pte_t;
+typedef struct { pmdval_t pmd; } pmd_t;
+typedef struct { pmdval_t pgd[LINKED_PMDS]; } pgd_t;
+typedef struct { pteval_t pgprot; } pgprot_t;
+
+#define pte_val(x)      ((x).pte[0])
+#define pmd_val(x)      ((x).pmd)
+#define pgd_val(x)	((x).pgd[0])
+#define pgprot_val(x)   ((x).pgprot)
+
+#define __pte(x)        ((pte_t) { {(x)} } )
+#define __pmd(x)        ((pmd_t) { (x) } )
+#define __pgprot(x)     ((pgprot_t) { (x) } )
+#endif
+
+#else
 /*
  * .. while these make it easier on the compiler
  */
diff --git a/arch/arm/include/asm/pgtable-2level.h b/arch/arm/include/asm/pgtable-2level.h
index 470457e..5feb89d 100644
--- a/arch/arm/include/asm/pgtable-2level.h
+++ b/arch/arm/include/asm/pgtable-2level.h
@@ -28,6 +28,15 @@
  * which contain the state information Linux needs.  We, therefore, end up
  * with 512 entries in the "PTE" level.
  *
+ * 64k pages support (Mindspeed COMCERTO):
+ * We cheat even more and tell Linux that we have 256 entries in the first
+ * level, each of which is 64 bytes (16 hardware pointers). The 2nd level
+ * contains 16 hardware PTE tables, or 4096 hardware entries. However,
+ * since 64kB pages are done by duplicating 4kB entries, there will only by
+ * 256 entries in the Linux "PTE" level (and the PTE entry will be larger).
+ * All defines are now also derived from the LINKED_PMDS_SHIFT macro, which
+ * determines how many PMDs point into a single 2nd-level table.
+ *
  * This leads to the page tables having the following layout:
  *
  *    pgd             pte
@@ -68,6 +77,7 @@
  * until either the TLB entry is evicted under pressure, or a context
  * switch which changes the user space mapping occurs.
  */
+#if !defined(CONFIG_COMCERTO_64K_PAGES)
 #define PTRS_PER_PTE		512
 #define PTRS_PER_PMD		1
 #define PTRS_PER_PGD		2048
@@ -82,6 +92,21 @@
  */
 #define PMD_SHIFT		21
 #define PGDIR_SHIFT		21
+#else
+#define LINKED_PMDS_SHIFT	4
+#define LINKED_PMDS			(1 << LINKED_PMDS_SHIFT)	/* number of PMDs pointing to the same 2nd-level page */
+#define PTRS_PER_PGD		(4096 / LINKED_PMDS)		/* one pgdir table contains 4096 entries */
+#define PGDIR_SHIFT			(20 + LINKED_PMDS_SHIFT)	/* one pgdir entry can map 1MB (2^20) */
+#define PMD_SHIFT			(PGDIR_SHIFT)
+#define PTET_SIZE_SHIFT		6							/* a HW PTE entry is 16*4bytes */
+#define PTE_HWTABLE_PTRS	(1 << (10 + LINKED_PMDS_SHIFT - PTET_SIZE_SHIFT)) /* one HW PTE table is 1kB (2^10) */
+
+#define PTRS_PER_PTE		(PTE_HWTABLE_PTRS)
+#define PTRS_PER_PMD		1
+
+#define PTE_HWTABLE_OFF		32768 //(PTRS_PER_PTE * sizeof(pte_t))
+#define PTE_HWTABLE_SIZE	(1 << (10 + LINKED_PMDS_SHIFT))
+#endif
 
 #define PMD_SIZE		(1UL << PMD_SHIFT)
 #define PMD_MASK		(~(PMD_SIZE-1))
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index 9451dce..ef333db 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -183,6 +183,7 @@
 #define pmd_present(pmd)	(pmd_val(pmd))
 #define pmd_bad(pmd)		(pmd_val(pmd) & 2)
 
+#if !defined(CONFIG_COMCERTO_64K_PAGES)
 #define copy_pmd(pmdpd,pmdps)		\
 	do {				\
 		pmdpd[0] = pmdps[0];	\
@@ -196,10 +197,29 @@
 		pmdp[1] = __pmd(0);	\
 		clean_pmd_entry(pmdp);	\
 	} while (0)
+#else
+#define copy_pmd(pmdpd,pmdps)	\
+	do {	\
+		int i;	\
+		for(i = 0; i < LINKED_PMDS; i++)	\
+			pmdpd[i] = pmdps[i];	\
+		flush_pmd_entry(pmdpd);	\
+	} while (0)
 
+#define pmd_clear(pmdp)	\
+	do {	\
+		int i;	\
+		for(i = 0; i < LINKED_PMDS; i++)	\
+			pmdp[i] = __pmd(0);	\
+		clean_pmd_entry(pmdp);	\
+	} while (0)
+
+#endif
+
+#define PMD_PAGE_ADDR_MASK		(~((1 << 10) - 1))
 static inline pte_t *pmd_page_vaddr(pmd_t pmd)
 {
-	return __va(pmd_val(pmd) & PHYS_MASK & (s32)PAGE_MASK);
+	return __va((pmd_val(pmd) & PHYS_MASK & (s32)PMD_PAGE_ADDR_MASK) - PTE_HWTABLE_OFF);
 }
 
 #define pmd_page(pmd)		pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK))
@@ -229,8 +249,17 @@
 #define pte_page(pte)		pfn_to_page(pte_pfn(pte))
 #define mk_pte(page,prot)	pfn_pte(page_to_pfn(page), prot)
 
-#define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext)
-#define pte_clear(mm,addr,ptep)	set_pte_ext(ptep, __pte(0), 0)
+#define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte_val(pte),ext)
+#define uncache_pte_ext(ptep) cpu_uncache_pte_ext(ptep)
+#define pte_clear(mm,addr,ptep)	do {__sync_outer_cache(ptep, __pte(0)); set_pte_ext(ptep, __pte(0), 0); } while (0)
+
+#if !defined(CONFIG_L2X0_INSTRUCTION_ONLY)
+static inline void __sync_outer_cache(pte_t *ptep, pte_t pteval)
+{
+}
+#else
+extern void __sync_outer_cache(pte_t *ptep, pte_t pteval);
+#endif
 
 #if __LINUX_ARM_ARCH__ < 6
 static inline void __sync_icache_dcache(pte_t pteval)
@@ -243,6 +272,8 @@
 static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
 			      pte_t *ptep, pte_t pteval)
 {
+	__sync_outer_cache(ptep, pteval);
+
 	if (addr >= TASK_SIZE)
 		set_pte_ext(ptep, pteval, 0);
 	else {
@@ -303,7 +334,7 @@
 #define __swp_entry(type,offset) ((swp_entry_t) { ((type) << __SWP_TYPE_SHIFT) | ((offset) << __SWP_OFFSET_SHIFT) })
 
 #define __pte_to_swp_entry(pte)	((swp_entry_t) { pte_val(pte) })
-#define __swp_entry_to_pte(swp)	((pte_t) { (swp).val })
+#define __swp_entry_to_pte(swp)	((pte_t) { { (swp).val } })
 
 /*
  * It is an error for the kernel to have more swap files than we can
diff --git a/arch/arm/include/asm/proc-fns.h b/arch/arm/include/asm/proc-fns.h
index 9e92cb20..bbb1d96 100644
--- a/arch/arm/include/asm/proc-fns.h
+++ b/arch/arm/include/asm/proc-fns.h
@@ -65,7 +65,7 @@
 	 * Set a possibly extended PTE.  Non-extended PTEs should
 	 * ignore 'ext'.
 	 */
-	void (*set_pte_ext)(pte_t *ptep, pte_t pte, unsigned int ext);
+	void (*set_pte_ext)(pte_t *ptep, pteval_t pte, unsigned int ext);
 
 	/* Suspend/resume */
 	unsigned int suspend_size;
@@ -79,7 +79,8 @@
 extern int cpu_do_idle(void);
 extern void cpu_dcache_clean_area(void *, int);
 extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm);
-extern void cpu_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext);
+extern void cpu_set_pte_ext(pte_t *ptep, pteval_t pte, unsigned int ext);
+extern void cpu_uncache_pte_ext(pte_t *ptep);
 extern void cpu_reset(unsigned long addr) __attribute__((noreturn));
 
 /* These three are private to arch/arm/kernel/suspend.c */
@@ -92,6 +93,7 @@
 #define cpu_do_idle			processor._do_idle
 #define cpu_dcache_clean_area		processor.dcache_clean_area
 #define cpu_set_pte_ext			processor.set_pte_ext
+#define cpu_uncache_pte_ext		processor.uncache_pte_ext
 #define cpu_do_switch_mm		processor.switch_mm
 
 /* These three are private to arch/arm/kernel/suspend.c */
diff --git a/arch/arm/include/asm/shmparam.h b/arch/arm/include/asm/shmparam.h
index a5223b3..73cdb5a 100644
--- a/arch/arm/include/asm/shmparam.h
+++ b/arch/arm/include/asm/shmparam.h
@@ -6,7 +6,12 @@
  * or page size, whichever is greater since the cache aliases
  * every size/ways bytes.
  */
+#if !defined(CONFIG_COMCERTO_64K_PAGES)
 #define	SHMLBA	(4 * PAGE_SIZE)		 /* attach addr a multiple of this */
+#else
+#define	SHMLBA	(PAGE_SIZE)		 /* attach addr a multiple of this */
+#endif
+
 
 /*
  * Enforce SHMLBA in shmat
diff --git a/arch/arm/include/asm/smp_twd.h b/arch/arm/include/asm/smp_twd.h
index ef9ffba9..d289c78 100644
--- a/arch/arm/include/asm/smp_twd.h
+++ b/arch/arm/include/asm/smp_twd.h
@@ -24,5 +24,8 @@
 
 void twd_timer_setup(struct clock_event_device *);
 void twd_timer_stop(struct clock_event_device *);
+#ifdef CONFIG_LOCAL_TIMERS
+int twd_timer_ack(void);
+#endif
 
 #endif
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
index 7b5cc8d..7d6a8ac 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -15,8 +15,13 @@
 #include <linux/compiler.h>
 #include <asm/fpstate.h>
 
+#if !defined(CONFIG_COMCERTO_64K_PAGES)
 #define THREAD_SIZE_ORDER	1
 #define THREAD_SIZE		8192
+#else
+#define THREAD_SIZE_ORDER	0
+#define THREAD_SIZE		65536
+#endif
 #define THREAD_START_SP		(THREAD_SIZE - 8)
 
 #ifndef __ASSEMBLY__
diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h
index 02b2f82..49ff231 100644
--- a/arch/arm/include/asm/tlbflush.h
+++ b/arch/arm/include/asm/tlbflush.h
@@ -471,6 +471,7 @@
  *	these operations.  This is typically used when we are removing
  *	PMD entries.
  */
+#if !defined(CONFIG_COMCERTO_64K_PAGES)
 static inline void flush_pmd_entry(void *pmd)
 {
 	const unsigned int __tlb_flag = __cpu_tlb_flags;
@@ -499,6 +500,39 @@
 		asm("mcr	p15, 1, %0, c15, c9, 1  @ L2 flush_pmd"
 			: : "r" (pmd) : "cc");
 }
+#else
+static inline void flush_pmd_entry(void *pmd)
+{
+	const unsigned int __tlb_flag = __cpu_tlb_flags;
+	char *p = (char *)pmd;
+
+	if (tlb_flag(TLB_DCLEAN)) {
+		while (p < ((char *)pmd + (LINKED_PMDS * sizeof(u32)))) { // A PMD contains LINKED_PMDS pointers to the 2nd-level table
+			asm("mcr	p15, 0, %0, c7, c10, 1	@ flush_pmd"
+					: : "r" (p) : "cc");
+			p += 32; //Next cache line
+		}
+	}
+
+	if (tlb_flag(TLB_WB))
+		dsb();
+}
+
+static inline void clean_pmd_entry(void *pmd)
+{
+	const unsigned int __tlb_flag = __cpu_tlb_flags;
+	char *p = (char *)pmd;
+
+	if (tlb_flag(TLB_DCLEAN)) {
+		while (p < ((char *)pmd + (LINKED_PMDS * sizeof(u32)))) { // A PMD contains LINKED_PMDS pointers to the 2nd-level table
+			asm("mcr	p15, 0, %0, c7, c10, 1	@ flush_pmd"
+					: : "r" (p) : "cc");
+			p += 32; //Next cache line
+		}
+	}
+}
+
+#endif
 
 #undef tlb_flag
 #undef always_tlb_flags
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index b145f16..ece0996 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -242,6 +242,19 @@
 	b	1b
 #endif
 
+__und_fault:
+	@ Correct the PC such that it is pointing at the instruction
+	@ which caused the fault.  If the faulting instruction was ARM
+	@ the PC will be pointing at the next instruction, and have to
+	@ subtract 4.  Otherwise, it is Thumb, and the PC will be
+	@ pointing at the second half of the Thumb instruction.  We
+	@ have to subtract 2.
+	ldr	r2, [r0, #S_PC]
+	sub	r2, r2, r1
+	str	r2, [r0, #S_PC]
+	b	do_undefinstr
+ENDPROC(__und_fault)
+
 	.align	5
 __und_svc:
 #ifdef CONFIG_KPROBES
@@ -259,25 +272,32 @@
 	@
 	@  r0 - instruction
 	@
-#ifndef	CONFIG_THUMB2_KERNEL
+#ifndef CONFIG_THUMB2_KERNEL
 	ldr	r0, [r4, #-4]
 #else
+	mov	r1, #2
 	ldrh	r0, [r4, #-2]			@ Thumb instruction at LR - 2
 	cmp	r0, #0xe800			@ 32-bit instruction if xx >= 0
-	ldrhhs	r9, [r4]			@ bottom 16 bits
-	orrhs	r0, r9, r0, lsl #16
+	blo	__und_svc_fault
+	ldrh	r9, [r4]			@ bottom 16 bits
+	add	r4, r4, #2
+	str	r4, [sp, #S_PC]
+	orr	r0, r9, r0, lsl #16
 #endif
-	adr	r9, BSYM(1f)
+	adr	r9, BSYM(__und_svc_finish)
 	mov	r2, r4
 	bl	call_fpe
 
+	mov	r1, #4				@ PC correction to apply
+__und_svc_fault:
 	mov	r0, sp				@ struct pt_regs *regs
-	bl	do_undefinstr
+	bl	__und_fault
 
 	@
 	@ IRQs off again before pulling preserved data off the stack
 	@
-1:	disable_irq_notrace
+__und_svc_finish:
+	disable_irq_notrace
 
 	@
 	@ restore SPSR and restart the instruction
@@ -421,25 +441,33 @@
 	mov	r2, r4
 	mov	r3, r5
 
+	@ r2 = regs->ARM_pc, which is either 2 or 4 bytes ahead of the
+	@      faulting instruction depending on Thumb mode.
+	@ r3 = regs->ARM_cpsr
 	@
-	@ fall through to the emulation code, which returns using r9 if
-	@ it has emulated the instruction, or the more conventional lr
-	@ if we are to treat this as a real undefined instruction
-	@
-	@  r0 - instruction
+	@ The emulation code returns using r9 if it has emulated the
+	@ instruction, or the more conventional lr if we are to treat
+	@ this as a real undefined instruction
 	@
 	adr	r9, BSYM(ret_from_exception)
-	adr	lr, BSYM(__und_usr_unknown)
+
 	tst	r3, #PSR_T_BIT			@ Thumb mode?
-	itet	eq				@ explicit IT needed for the 1f label
-	subeq	r4, r2, #4			@ ARM instr at LR - 4
-	subne	r4, r2, #2			@ Thumb instr at LR - 2
-1:	ldreqt	r0, [r4]
+	bne	__und_usr_thumb
+	sub	r4, r2, #4			@ ARM instr at LR - 4
+1:	ldrt	r0, [r4]
 #ifdef CONFIG_CPU_ENDIAN_BE8
-	reveq	r0, r0				@ little endian instruction
+	rev	r0, r0				@ little endian instruction
 #endif
-	beq	call_fpe
+	@ r0 = 32-bit ARM instruction which caused the exception
+	@ r2 = PC value for the following instruction (:= regs->ARM_pc)
+	@ r4 = PC value for the faulting instruction
+	@ lr = 32-bit undefined instruction function
+	adr	lr, BSYM(__und_usr_fault_32)
+	b	call_fpe
+
+__und_usr_thumb:
 	@ Thumb instruction
+	sub	r4, r2, #2			@ First half of thumb instr at LR - 2
 #if CONFIG_ARM_THUMB && __LINUX_ARM_ARCH__ >= 6 && CONFIG_CPU_V7
 /*
  * Thumb-2 instruction handling.  Note that because pre-v6 and >= v6 platforms
@@ -453,7 +481,7 @@
 	ldr	r5, .LCcpu_architecture
 	ldr	r5, [r5]
 	cmp	r5, #CPU_ARCH_ARMv7
-	blo	__und_usr_unknown
+	blo	__und_usr_fault_16		@ 16bit undefined instruction
 /*
  * The following code won't get run unless the running CPU really is v7, so
  * coding round the lack of ldrht on older arches is pointless.  Temporarily
@@ -461,15 +489,18 @@
  */
 	.arch	armv6t2
 #endif
-2:
- ARM(	ldrht	r5, [r4], #2	)
- THUMB(	ldrht	r5, [r4]	)
- THUMB(	add	r4, r4, #2	)
+2:	ldrht	r5, [r4]
 	cmp	r5, #0xe800			@ 32bit instruction if xx != 0
-	blo	__und_usr_unknown
-3:	ldrht	r0, [r4]
+	blo	__und_usr_fault_16		@ 16bit undefined instruction
+3:	ldrht	r0, [r2]
 	add	r2, r2, #2			@ r2 is PC + 2, make it PC + 4
+	str	r2, [sp, #S_PC]			@ it's a 2x16bit instr, update
 	orr	r0, r0, r5, lsl #16
+	adr	lr, BSYM(__und_usr_fault_32)
+	@ r0 = the two 16-bit Thumb instructions which caused the exception
+	@ r2 = PC value for the following Thumb instruction (:= regs->ARM_pc)
+	@ r4 = PC value for the first 16-bit Thumb instruction
+	@ lr = 32bit undefined instruction function
 
 #if __LINUX_ARM_ARCH__ < 7
 /* If the target arch was overridden, change it back: */
@@ -480,17 +511,13 @@
 #endif
 #endif /* __LINUX_ARM_ARCH__ < 7 */
 #else /* !(CONFIG_ARM_THUMB && __LINUX_ARM_ARCH__ >= 6 && CONFIG_CPU_V7) */
-	b	__und_usr_unknown
+	b	__und_usr_fault_16
 #endif
- UNWIND(.fnend		)
+ UNWIND(.fnend)
 ENDPROC(__und_usr)
 
-	@
-	@ fallthrough to call_fpe
-	@
-
 /*
- * The out of line fixup for the ldrt above.
+ * The out of line fixup for the ldrt instructions above.
  */
 	.pushsection .fixup, "ax"
 4:	mov	pc, r9
@@ -521,11 +548,12 @@
  * NEON handler code.
  *
  * Emulators may wish to make use of the following registers:
- *  r0  = instruction opcode.
- *  r2  = PC+4
+ *  r0  = instruction opcode (32-bit ARM or two 16-bit Thumb)
+ *  r2  = PC value to resume execution after successful emulation
  *  r9  = normal "successful" return address
- *  r10 = this threads thread_info structure.
+ *  r10 = this threads thread_info structure
  *  lr  = unrecognised instruction return address
+ * IRQs disabled, FIQs enabled.
  */
 	@
 	@ Fall-through from Thumb-2 __und_usr
@@ -660,12 +688,17 @@
 	mov	pc, lr
 ENDPROC(no_fp)
 
-__und_usr_unknown:
-	enable_irq
+__und_usr_fault_32:
+	mov	r1, #4
+	b	1f
+__und_usr_fault_16:
+	mov	r1, #2
+1:	enable_irq
 	mov	r0, sp
 	adr	lr, BSYM(ret_from_exception)
-	b	do_undefinstr
-ENDPROC(__und_usr_unknown)
+	b	__und_fault
+ENDPROC(__und_usr_fault_32)
+ENDPROC(__und_usr_fault_16)
 
 	.align	5
 __pabt_usr:
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index b2a27b6..aacae19 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -14,7 +14,7 @@
 #include <asm/unwind.h>
 
 #include "entry-header.S"
-
+#include <asm/page.h>
 
 	.align	5
 /*
@@ -583,6 +583,7 @@
  */
 sys_mmap2:
 #if PAGE_SHIFT > 12
+#define PGOFF_MASK ((1 << (PAGE_SHIFT - 12)) - 1)
 		tst	r5, #PGOFF_MASK
 		moveq	r5, r5, lsr #PAGE_SHIFT - 12
 		streq	r5, [sp, #4]
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 9a8531e..39b4bd6 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -108,11 +108,17 @@
 	movs	pc, lr				@ return & move spsr_svc into cpsr
 	.endm
 
+#if !defined(CONFIG_COMCERTO_64K_PAGES)
 	.macro	get_thread_info, rd
 	mov	\rd, sp, lsr #13
 	mov	\rd, \rd, lsl #13
 	.endm
-
+#else
+	.macro	get_thread_info, rd
+	mov	\rd, sp, lsr #16
+	mov	\rd, \rd, lsl #16
+	.endm
+#endif
 	@
 	@ 32-bit wide "mov pc, reg"
 	@
@@ -148,11 +154,18 @@
 	movs	pc, lr				@ return & move spsr_svc into cpsr
 	.endm
 
+#if !defined(CONFIG_COMCERTO_64K_PAGES)
 	.macro	get_thread_info, rd
 	mov	\rd, sp
 	lsr	\rd, \rd, #13
 	mov	\rd, \rd, lsl #13
 	.endm
+#else
+	.macro	get_thread_info, rd
+	mov	\rd, sp, lsr #16
+	mov	\rd, \rd, lsl #16
+	.endm
+#endif
 
 	@
 	@ 32-bit wide "mov pc, reg"
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 08c82fd..eeb4d84 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -44,9 +44,17 @@
 
 	.globl	swapper_pg_dir
 	.equ	swapper_pg_dir, KERNEL_RAM_VADDR - PG_DIR_SIZE
-
+/*
+*	Mindspeed:
+*   Need to break the function in case text offset is too big
+*   this is the case when using zone_dma
+*	There is probably a more elegant way to to that
+*	original code:
+*	add	\rd, \phys, #TEXT_OFFSET - PG_DIR_SIZE
+*/
 	.macro	pgtbl, rd, phys
-	add	\rd, \phys, #TEXT_OFFSET - PG_DIR_SIZE
+	ldr	\rd, =TEXT_OFFSET - PG_DIR_SIZE
+	add	\rd, \phys, \rd
 	.endm
 
 #ifdef CONFIG_XIP_KERNEL
diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S
index 020e99c..0a589b7 100644
--- a/arch/arm/kernel/sleep.S
+++ b/arch/arm/kernel/sleep.S
@@ -5,6 +5,13 @@
 #include <asm/glue-cache.h>
 #include <asm/glue-proc.h>
 #include <asm/system.h>
+
+#ifdef CONFIG_ARCH_M86XXX
+/* 
+ * IRAM Location to restore the banked registers
+ */
+#define SCRATCHPAD_CPU_CONTEXT_LOC_DBG	 (0xf0802570)
+#endif
 	.text
 
 /*
@@ -64,10 +71,66 @@
 ENDPROC(cpu_resume_mmu)
 cpu_resume_after_mmu:
 	bl	cpu_init		@ restore the und/abt/irq banked regs
+
+#ifdef CONFIG_ARCH_M86XXX
+	/* 
+	 * This code is added to restore the banked registers
+	 * This restore has to be kept here as it has to happen 
+	 * after MMU int.
+	 */
+
+	/* Restore cpsr and spsr */
+        ldr 	r7, scratchpad_cpu_context_loc_dbg
+
+	/* Restoring all the banked registers */
+        mrs     r0, cpsr
+
+        /* Restore the Undef mode reisters */
+        bic     r1, r0, #0x1f
+        orr     r1, r1, #0x1b
+        msr     cpsr_c, r1
+	ARM ( ldmia	r7!, {r13-r14} )
+	ldmia	r7!, {r6}
+	msr	spsr, r6
+
+        /* Restore the Abort mode reisters */
+        bic     r1, r0, #0x1f
+        orr     r1, r1, #0x17
+        msr     cpsr_c, r1
+	ARM ( ldmia	r7!, {r13-r14} )
+	ldmia	r7!, {r6}
+	msr	spsr, r6
+
+        /* Restore the IRQ mode reisters */
+        bic     r1, r0, #0x1f
+        orr     r1, r1, #0x12
+        msr     cpsr_c, r1
+	ARM ( ldmia	r7!, {r13-r14} )
+	ldmia	r7!, {r6}
+	msr	spsr, r6
+
+        /* Restore the FIQ mode reisters */
+        bic     r1, r0, #0x1f
+        orr     r1, r1, #0x11
+        msr     cpsr_c, r1
+	ARM ( ldmia	r7!, {r8-r14} )
+	THUMB ( ldmia	r7!, {r8-r12} )
+	ldmia	r7!, {r6}
+	msr	spsr, r6
+
+        /* Return to the original mode */
+        msr     cpsr_c, r0
+#endif
 	mov	r0, #0			@ return zero on success
 	ldmfd	sp!, {r4 - r11, pc}
 ENDPROC(cpu_resume_after_mmu)
 
+
+#ifdef CONFIG_ARCH_M86XXX
+scratchpad_cpu_context_loc_dbg:
+        .word   SCRATCHPAD_CPU_CONTEXT_LOC_DBG
+#endif
+
 /*
  * Note: Yes, part of the following code is located into the .data section.
  *       This is to allow sleep_save_sp to be accessed with a relative load
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 1d1710e..0f7a254 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -345,7 +345,10 @@
 	 * now.
 	 */
 	local_irq_enable();
+
+#ifndef CONFIG_COMCERTO_MSP
 	local_fiq_enable();
+#endif  /* !CONFIG_COMCERTO_MSP */
 
 	/*
 	 * OK, it's off to the idle thread for us
diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c
index 8f5dd79..ff84772 100644
--- a/arch/arm/kernel/smp_scu.c
+++ b/arch/arm/kernel/smp_scu.c
@@ -52,6 +52,10 @@
 	if (scu_ctrl & 1)
 		return;
 
+#ifdef CONFIG_SCU_SPECULATIVE_LINE_FILLS
+	scu_ctrl |= (1 << 3);
+#endif
+
 	scu_ctrl |= 1;
 	__raw_writel(scu_ctrl, scu_base + SCU_CTRL);
 
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 160cb16..8380bd1 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -362,18 +362,10 @@
 
 asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
 {
-	unsigned int correction = thumb_mode(regs) ? 2 : 4;
 	unsigned int instr;
 	siginfo_t info;
 	void __user *pc;
 
-	/*
-	 * According to the ARM ARM, PC is 2 or 4 bytes ahead,
-	 * depending whether we're in Thumb mode or not.
-	 * Correct this offset.
-	 */
-	regs->ARM_pc -= correction;
-
 	pc = (void __user *)instruction_pointer(regs);
 
 	if (processor_mode(regs) == SVC_MODE) {
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index cf73a7f..7c69deb 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -42,6 +42,7 @@
 
 lib-$(CONFIG_ARCH_RPC)		+= ecard.o io-acorn.o floppydma.o
 lib-$(CONFIG_ARCH_SHARK)	+= io-shark.o
+lib-$(CONFIG_COMCERTO_ZONE_DMA_NCNB) += atomic.o
 
 $(obj)/csumpartialcopy.o:	$(obj)/csumpartialcopygeneric.S
 $(obj)/csumpartialcopyuser.o:	$(obj)/csumpartialcopygeneric.S
diff --git a/arch/arm/lib/atomic.c b/arch/arm/lib/atomic.c
new file mode 100644
index 0000000..b460d00
--- /dev/null
+++ b/arch/arm/lib/atomic.c
@@ -0,0 +1,48 @@
+#include <linux/spinlock.h>
+#include <linux/export.h>
+#include <asm/atomic.h>
+
+static DEFINE_RAW_SPINLOCK(atomic_lock);
+
+struct virtual_zone arm_dma_zone; /* initialized in arch/arm/mm/mmu.c::map_lowmem() */
+EXPORT_SYMBOL(arm_dma_zone);
+
+int comcerto_atomic_add(int i, atomic_t *v)
+{
+	unsigned long flags;
+	int result;
+
+	raw_spin_lock_irqsave(&atomic_lock, flags);
+	v->counter += i;
+	result = v->counter;
+	raw_spin_unlock_irqrestore(&atomic_lock, flags);
+
+	return result;
+}
+EXPORT_SYMBOL(comcerto_atomic_add);
+
+int comcerto_atomic_cmpxchg(atomic_t *v, int old, int new)
+{
+	unsigned long flags;
+	int result;
+
+	raw_spin_lock_irqsave(&atomic_lock, flags);
+	result = v->counter;
+	if (likely(result == old))
+		v->counter = new;
+	raw_spin_unlock_irqrestore(&atomic_lock, flags);
+
+	return result;
+}
+EXPORT_SYMBOL(comcerto_atomic_cmpxchg);
+
+void comcerto_atomic_clear_mask(unsigned long mask, unsigned long *addr)
+{
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&atomic_lock, flags);
+	*addr &= ~mask;
+	raw_spin_unlock_irqrestore(&atomic_lock, flags);
+}
+EXPORT_SYMBOL(comcerto_atomic_clear_mask);
+
diff --git a/arch/arm/lib/copy_page.S b/arch/arm/lib/copy_page.S
index 6ee2f67..eb0f586 100644
--- a/arch/arm/lib/copy_page.S
+++ b/arch/arm/lib/copy_page.S
@@ -28,7 +28,7 @@
 		stmfd	sp!, {r4, lr}			@	2
 	PLD(	pld	[r1, #0]		)
 	PLD(	pld	[r1, #L1_CACHE_BYTES]		)
-		mov	r2, #COPY_COUNT			@	1
+		ldr	r2, =COPY_COUNT			@	1
 		ldmia	r1!, {r3, r4, ip, lr}		@	4+1
 1:	PLD(	pld	[r1, #2 * L1_CACHE_BYTES])
 	PLD(	pld	[r1, #3 * L1_CACHE_BYTES])
diff --git a/arch/arm/mach-comcerto/Kconfig b/arch/arm/mach-comcerto/Kconfig
new file mode 100644
index 0000000..3735479
--- /dev/null
+++ b/arch/arm/mach-comcerto/Kconfig
@@ -0,0 +1,289 @@
+if ARCH_COMCERTO
+
+menu "Comcerto Implementation Options"
+
+config ARCH_SUPPORTS_BIG_ENDIAN
+	bool "Architecture supports Big Endian"
+        default n
+
+choice
+	prompt "Comcerto System Type"
+	default CONFIG_ARCH_M86XXX
+
+config ARCH_M86XXX
+	bool "M86xxx"
+	select CPU_V7
+	select ARM_GIC
+	select ARM_ERRATA_743622
+	select ARM_ERRATA_751472
+	select ARM_ERRATA_754322
+	select ARM_ERRATA_764369 if SMP
+	select MTD_COMCERTO_NOR
+	select COMCERTO_UART1_SUPPORT
+	select COMCERTO_PFE_UART_SUPPORT
+	select COMCERTO_USB2_SUPPORT
+	select COMCERTO_USB3_SUPPORT
+ 	select COMCERTO_USB3_INTERNAL_CLK
+	select COMCERTO_IPSEC_SUPPORT
+	select COMCERTO_I2C_SUPPORT
+	select GENERIC_TIME
+	select GENERIC_CLOCKEVENTS
+	select HAVE_SCHED_CLOCK
+	select COMCERTO_DW_DMA_SUPPORT
+	select CLKDEV_LOOKUP
+	select ARCH_HAS_CPUFREQ
+	select ARCH_HAS_OPP
+	select MIGHT_HAVE_PCI if !RTSM_C2K
+	select PCI_MSI if PCI
+	help
+	  Say Y here if you intend to run this kernel with a Comcerto2000 device.
+
+endchoice
+
+
+
+choice
+	prompt "Comcerto Board type"
+	default RTSM_C2K
+
+config C2K_EVM
+	bool "EVM"
+	depends on ARCH_M86XXX
+	help
+	  Say Y here if you intend to run this kernel with a C2K EVM.
+
+config C2K_MFCN_EVM
+	bool "MFCN EVM"
+	depends on ARCH_M86XXX
+	help
+	  Say Y here if you intend to run this kernel with a C2K MFCN EVM.
+
+config C2K_ASIC
+	bool "ASIC"
+	depends on ARCH_M86XXX
+	select COMCERTO_UART0_SUPPORT
+	help
+	  Say Y here if you intend to run this kernel with a C2K ASIC.
+
+config RTSM_C2K
+	bool "RTSM"
+	depends on ARCH_M86XXX
+	help
+	  Say Y here if you intend to run this kernel with a C2K RTSM.
+	  
+endchoice
+
+
+config MTD_COMCERTO_NOR
+	bool
+	default y
+
+config COMCERTO_TDM_CLOCK
+        bool "Comcerto device TDM clock and frame sync control through sysfs"
+	default y
+	help
+	  Say Y if you intend to use the Comcerto TDM and be able to change
+	  different parameters through sysfs.
+
+config COMCERTO_CSYS_TPI_CLOCK
+        bool "Comcerto device TPI and CSYS clock control "
+	default n
+	help
+	  Say Y if you intend to use the Comcerto TPI (Cortex A9 JTAG interface) and CSYS clock (Cortex A9 CoreSight module).
+
+config COMCERTO_PCIE_OCC_CLOCK
+        bool "Comcerto device PCIE OCC clock control "
+	default n
+	help
+	  Say Y if you intend to use the Comcerto PCIE OCC clock.
+
+config COMCERTO_SATA_OCC_CLOCK
+        bool "Comcerto device SATA OCC clock control "
+	default n
+	help
+	  Say Y if you intend to use the Comcerto SATA OCC clock.
+
+config COMCERTO_SGMII_OCC_CLOCK
+        bool "Comcerto device SGMII OCC clock control "
+	default n
+	help
+	  Say Y if you intend to use the Comcerto SGMII OCC clock.
+
+config COMCERTO_MEMBUF
+	bool "Comcerto memory buffer driver"
+	default n
+	help
+	  Say Y if you intend to use the memory buffer driver. This driver helps
+	  Linux user space applications setup a physical scatter buffer that can be used
+	  directly by the PFE. Currently the PFE hold tone generation feature requires
+	  this driver to be enabled.
+
+config COMCERTO_NUM_PCIES
+	int "Number of PCIe controllers to be enabled (0-2)"
+	range 0 2
+	depends on ARCH_M86XXX 
+	default "2"
+
+config COMCERTO_FP
+	bool "Comcerto Fast Path Support"
+	depends on ARCH_M86XXX
+	default y
+
+config COMCERTO_UART0_SUPPORT
+	bool
+	default n
+
+config COMCERTO_UART1_SUPPORT
+	bool
+	default y
+
+config COMCERTO_USB2_SUPPORT
+	bool
+	default n
+
+config COMCERTO_USB3_SUPPORT
+	bool
+	default n
+
+config COMCERTO_IPSEC_SUPPORT
+	bool
+	default n
+
+config COMCERTO_EPAVIS
+	bool "DPI EPAVIS content inspection driver"
+	default n
+
+config COMCERTO_ELP_SUPPORT
+	bool "Elliptic EPN1802 SPAcc/PKA crypto driver"
+	default y
+
+config COMCERTO_I2C_SUPPORT
+        bool
+        default n
+
+config COMCERTO_DW_DMA_SUPPORT
+        bool
+        default n
+
+config COMCERTO_DDR_ECC_SUPPORT
+        bool "Fix for the Comcerto DDR ECC Support problem"
+        default n
+        help
+          There is a limitation with Denali DDRC Controller when ECC is enabled. It expects that the
+          burst writes of greater than or equal to 16 bytes must start and end at a 16-byte boundary.
+          Saying Y for this option will make the dma memory area to be non-writeable, apart from being
+          non-cacheable so that single write should happen instead of burst.
+
+config COMCERTO_MSP
+	bool "Mindspeed Comcerto VoIP"
+	depends on ARCH_M86XXX
+	select FIQ
+	default y
+
+config COMCERTO_SATA
+	bool "Comcerto SATA"
+	select ATA
+	select ATA_VERBOSE_ERROR
+	select SATA_AHCI_PLATFORM
+	select BLK_DEV_SD
+	select LBDAF
+
+config COMCERTO_IMPROVED_SPLICE
+	bool "Comcerto improved splice call"
+	default n
+	help
+	  Say Y if you intend to use the Comcerto improved splice call. When writing data to a file on an
+	  ext4 partition, re-organize the splice code to gather all the memcpy calls in one place, instead
+	  of allocating pages and releasing pipe buffers one by one. This improves performance and makes it
+	  possible to use a DMA engine with scatter-gather in-place of mempcy.
+
+config COMCERTO_SPLICE_USE_MDMA
+	bool "Comcerto splice using MDMA"
+	default n
+	depends on COMCERTO_IMPROVED_SPLICE
+	select COMCERTO_DMA_BASIC
+	help
+	  Say Y if you intend to use the Comcerto MDMA engine to replace memcpy calls inside the improved 
+	  splice call.
+
+config COMCERTO_ZONE_DMA_NCNB
+	bool "Comcerto Zone DMA"
+	select ZONE_DMA
+	default n
+
+config COMCERTO_CUSTOM_SKB_LAYOUT
+	bool "Mindspeed customized skb layout, to reduce NCNB access overhead, when NCNB buffer is used in skb"
+	depends on COMCERTO_ZONE_DMA_NCNB
+	default n
+
+config DSPG_DECT_CSS
+	bool "DSPG DECT CSS"
+	default n
+
+config COMCERTO_USB3_INTERNAL_CLK
+	bool "Comcerto internal clock for USB3"
+	default n
+
+config COMCERTO_AHCI_PROF
+	bool "Comcerto AHCI profiling"
+	bool
+	default n
+
+config COMCERTO_SPLICE_PROF
+	bool "Comcerto splice profiling"
+	depends on COMCERTO_IMPROVED_SPLICE
+	default n
+
+config COMCERTO_MDMA_PROF
+	bool "Comcerto MDMA profiling"
+	depends on COMCERTO_DMA_BASIC
+	default n
+
+config COMCERTO_64K_PAGES
+	bool "Comcerto 64kB pages"
+	default n
+	help
+	  Say Y to enable 64kB pages instead of the default 4kB. Memory usage will be increased, but
+          per-page operations will be reduced, and data transfers will become more efficient.
+
+config COMCERTO_CC_OPTIMIZE_O3
+	bool "Compile the kernel with -O3"
+	default n
+	depends on !CC_OPTIMIZE_FOR_SIZE
+	help
+	  Compile the kernel with -O3 instead of -O2 option. Resulting kernel can be a bit faster, but
+	  it will also be bigger.
+
+config COMCERTO_HW_KERNEL_PAGETABLE
+	bool "Use the 2nd HW page table for kernel memory space"
+	select VMSPLIT_2G
+	default n
+	help
+	  By default, Linux uses only one page table at a time, and switches page tables when switching
+	  between processes. Say Y to enable the 2nd hardware page table, which will be used to map kernel
+	  addresses.
+	  Note that because of the way the ARM MMU determines which page table to use, this option can
+	  only be enabled with a 2G/2G userspace/kernel memory split.
+
+config COMCERTO_UNCACHED_DMA
+	bool "Make pages uncacheable when doing DMA operations"
+	depends on COMCERTO_HW_KERNEL_PAGETABLE
+	default n
+	help
+	  When transferring ownership of a page to a device through the DMA API, make the page uncacheable
+	  for the duration of the transfer. This makes the 2nd cache invalidate (that was needed because
+	  of the possibility of speculative accesses by the A9 cores) unnecessary, which can increase
+	  performance during heavy IO workloads. The page tables will be more complex though, resulting in
+	  more TLB misses when a DMA transfer is going on.
+
+config COMCERTO_SPLICE_READ_NOCONTIG
+	bool "Use find_get_pages in splice read code"
+	default n
+	help
+	  The splice read code normally calls find_get_pages_contig to retrieve pages mapping the requested
+	  portion of the file to read. However, using find_get_pages works just as well, as the splice code
+	  is able to handle both situations.
+	  Say Y to use find_get_pages instead of find_get_pages_contig, which seems to yield a significant
+	  performance improvement in Samba read tests.
+endmenu
+endif
diff --git a/arch/arm/mach-comcerto/Makefile b/arch/arm/mach-comcerto/Makefile
new file mode 100644
index 0000000..9f5cfa0
--- /dev/null
+++ b/arch/arm/mach-comcerto/Makefile
@@ -0,0 +1,30 @@
+#
+# Makefile for the linux kernel.
+#
+
+# Object file lists.
+
+obj-y := gpio.o time.o dma.o clock.o reset.o pm.o sleep.o
+obj-m :=
+obj-n :=
+obj- :=
+
+obj-$(CONFIG_ARCH_M86XXX) 		    	+= comcerto-2000.o
+obj-$(CONFIG_ARCH_M86XXX) 		    	+= comcerto-vwd.o
+
+obj-$(CONFIG_ARCH_M86XXX)               	+= serdes-c2000.o
+
+ifeq ($(CONFIG_PCI),y)
+        obj-$(CONFIG_ARCH_M86XXX)               += pcie-c2000.o
+endif
+
+obj-$(CONFIG_COMCERTO_MEMBUF)                   += membuf.o
+obj-$(CONFIG_COMCERTO_TDM_CLOCK)                += sysfstdm.o
+obj-$(CONFIG_RTSM_C2K) 				+= board-c2krtsm.o
+obj-$(CONFIG_C2K_EVM) 				+= board-c2kevm.o
+obj-$(CONFIG_C2K_MFCN_EVM)			+= board-c2kmfcnevm.o
+obj-$(CONFIG_C2K_ASIC) 				+= board-c2kasic.o
+obj-$(CONFIG_SMP)				+= platsmp.o headsmp.o
+obj-$(CONFIG_COMCERTO_MSP)			+= msp/
+obj-$(CONFIG_HOTPLUG_CPU)			+= hotplug.o
+obj-$(CONFIG_COMCERTO_CSYS_TPI_CLOCK)		+= comcerto-tpicsys.o
diff --git a/arch/arm/mach-comcerto/Makefile.boot b/arch/arm/mach-comcerto/Makefile.boot
new file mode 100644
index 0000000..133025b
--- /dev/null
+++ b/arch/arm/mach-comcerto/Makefile.boot
@@ -0,0 +1,8 @@
+ifeq ($(CONFIG_ARCH_M86XXX),y)
+ifeq ($(CONFIG_COMCERTO_ZONE_DMA_NCNB),y)
+   zreladdr-y     := 0x04008000
+else
+   zreladdr-y     := 0x00008000
+endif
+   params_phys-y  := 0x00000100
+endif
diff --git a/arch/arm/mach-comcerto/board-c2kasic.c b/arch/arm/mach-comcerto/board-c2kasic.c
new file mode 100644
index 0000000..9097b28
--- /dev/null
+++ b/arch/arm/mach-comcerto/board-c2kasic.c
@@ -0,0 +1,757 @@
+/*
+ * arch/arm/mach-comcerto/board-c2kasic.c
+ *
+ *  Copyright (C) 2012 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/sched.h>
+#include <linux/device.h>
+#include <linux/serial_8250.h>
+#include <linux/memblock.h>
+#include <linux/phy.h>
+
+#include <linux/mtd/mtd.h>
+#if defined(CONFIG_MTD_NAND_COMCERTO) || defined(CONFIG_MTD_NAND_COMCERTO_MODULE)
+#include <linux/mtd/nand.h>
+#endif
+#include <linux/mtd/partitions.h>
+
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+#include <linux/spi/spi.h>
+#endif
+
+#include <asm/sizes.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/io.h>
+
+#include <asm/mach/flash.h>
+#include <asm/mach/arch.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/dma.h>
+#include <linux/dw_dmac.h>
+
+#include <linux/clockchips.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <asm/smp_twd.h>
+#include <asm/localtimer.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/time.h>
+#include <mach/gpio.h>
+
+extern void platform_reserve(void);
+extern void device_map_io (void);
+extern void device_irq_init(void);
+extern void device_init(void);
+extern void mac_addr_init(struct comcerto_pfe_platform_data *);
+extern struct sys_timer comcerto_timer;
+
+static void __init board_gpio_init(void)
+{
+#ifdef CONFIG_COMCERTO_PFE_UART_SUPPORT
+	writel((readl(COMCERTO_GPIO_PIN_SELECT_REG) & ~PFE_UART_GPIO) | PFE_UART_BUS, COMCERTO_GPIO_PIN_SELECT_REG);
+	c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= PFE_UART_GPIO_PIN; /* GPIOs 12 & 13 are used for PFE_UART */
+#endif
+
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI2_MSPD_LOW_SPEED)
+	/* enable SPI pins */
+	writel((readl(COMCERTO_GPIO_PIN_SELECT_REG1) & ~(SPI_MUX_GPIO_1)) | (SPI_MUX_BUS_1), COMCERTO_GPIO_PIN_SELECT_REG1);
+	writel((readl(COMCERTO_GPIO_63_32_PIN_SELECT) & ~(SPI_MUX_GPIO_2)) | (SPI_MUX_BUS_2), COMCERTO_GPIO_63_32_PIN_SELECT);
+	c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= SPI_MUX_GPIO_1_PIN; /* GPIOs 18,19, 21,22, 30,31 are used for SPI*/
+	c2k_gpio_pin_stat.c2k_gpio_pins_32_63 |= SPI_MUX_GPIO_2_PIN; /* GPIO 32 is used for SPI*/
+#endif
+
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+	/* enable SPI pins */
+	writel((readl(COMCERTO_GPIO_PIN_SELECT_REG1) & ~(SPI_2_MUX_GPIO_1)) | (SPI_2_MUX_BUS_1), COMCERTO_GPIO_PIN_SELECT_REG1);
+	writel((readl(COMCERTO_GPIO_63_32_PIN_SELECT) & ~(SPI_2_MUX_GPIO_2)) | (SPI_2_MUX_BUS_2), COMCERTO_GPIO_63_32_PIN_SELECT);
+	c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= SPI_2_MUX_GPIO_1_PIN;
+	c2k_gpio_pin_stat.c2k_gpio_pins_32_63 |= SPI_2_MUX_GPIO_2_PIN;
+#endif
+
+#if defined(CONFIG_COMCERTO_I2C_SUPPORT)
+	writel((readl(COMCERTO_GPIO_PIN_SELECT_REG1) & ~I2C_GPIO) | I2C_BUS, COMCERTO_GPIO_PIN_SELECT_REG1);
+	c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= I2C_GPIO_PIN;
+#endif
+
+#if defined(CONFIG_MTD_NAND_COMCERTO) || defined(CONFIG_MTD_NAND_COMCERTO_MODULE)
+	writel((readl(COMCERTO_GPIO_PIN_SELECT_REG1) & ~NAND_GPIO) | NAND_BUS, COMCERTO_GPIO_PIN_SELECT_REG1);
+	c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= NAND_GPIO_PIN;
+#endif
+
+#if defined(CONFIG_MTD_COMCERTO_NOR)
+	writel((readl(COMCERTO_GPIO_PIN_SELECT_REG1) & ~NOR_GPIO) | NOR_BUS, COMCERTO_GPIO_PIN_SELECT_REG1);
+	c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= NOR_GPIO_PIN;
+#endif
+
+        /* TDM bus configuration */
+        /* Fix for C2KASIC RevA. Correct/lower TDM bus strength to avoid noise distorting voice with si3227 */
+	/* TODO: Check on RevB. */
+        /* Setting TDM_CK strangth [7:6] equal X3 */
+        #define X1 0
+        #define X2 2
+        #define X3 1
+        #define X4 3
+        writel((X3 << 6) |(readl(COMCERTO_GPIO_PAD_CONFIG0) & ~(0x3 << 6)), COMCERTO_GPIO_PAD_CONFIG0);
+}
+
+
+/* --------------------------------------------------------------------
+ *  NOR device
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_MTD_COMCERTO_NOR)
+
+static struct resource comcerto_nor_resources[] = {
+	{
+		.start	= NORFLASH_MEMORY_PHY1,
+		.end	= NORFLASH_MEMORY_PHY1 + SZ_128M - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct flash_platform_data comcerto_nor_data = {
+	.map_name	= "cfi_probe",
+	.width	= 2,
+};
+
+static struct platform_device comcerto_nor = {
+	.name           = "comcertoflash",
+	.id             = 0,
+	.num_resources  = ARRAY_SIZE(comcerto_nor_resources),
+	.resource       = comcerto_nor_resources,
+	.dev = {
+		.platform_data	= &comcerto_nor_data,
+	},
+};
+#endif
+
+static struct resource rtc_res[] = {
+	{
+		.start = COMCERTO_APB_RTC_BASE,
+		.end = COMCERTO_APB_RTC_BASE + SZ_32 - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = IRQ_RTC_ALM,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = IRQ_RTC_PRI,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+static struct platform_device rtc_dev = {
+	.name = "c2k-rtc",
+	.id = -1,
+	.num_resources = ARRAY_SIZE(rtc_res),
+	.resource = rtc_res,
+};
+
+/* --------------------------------------------------------------------
+ *  DMAC controller
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_COMCERTO_DW_DMA_SUPPORT)
+static struct resource dw_dmac_resource[] = {
+	{
+		.start          = DW_DMA_DMAC_BASEADDR,
+		.end            = DW_DMA_DMAC_BASEADDR + 0x2C0,
+		.flags          = IORESOURCE_MEM,
+	},
+	{
+		.start          = IRQ_DMAC,
+		.flags          = IORESOURCE_IRQ,
+	}
+};
+
+static struct dw_dma_platform_data dw_dmac_data = {
+	.nr_channels    = 8,
+};
+
+static u64 dw_dmac_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device dw_dmac_device = {
+	.name           = "dw_dmac",
+	.id             = 0,
+	.dev            = {
+		.dma_mask = &dw_dmac_dma_mask,
+		.platform_data  = &dw_dmac_data,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+	.resource       = dw_dmac_resource,
+	.num_resources  = ARRAY_SIZE(dw_dmac_resource),
+};
+#endif
+
+/* --------------------------------------------------------------------
+ *  NAND device
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_MTD_NAND_COMCERTO) || defined(CONFIG_MTD_NAND_COMCERTO_MODULE)
+static struct resource comcerto_nand_resources[] = {
+	{
+		.start	= COMCERTO_NAND_FIO_ADDR,
+		.end	= COMCERTO_NAND_FIO_ADDR + COMCERTO_NAND_IO_SZ - 1,
+		.flags	= IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device comcerto_nand = {
+	.name		= "comcertonand",
+	.id		= -1,
+	.dev		= {
+				.platform_data	= NULL,
+	},
+	.resource	= comcerto_nand_resources,
+	.num_resources	= ARRAY_SIZE(comcerto_nand_resources),
+};
+#endif
+
+/* --------------------------------------------------------------------
+ *  SPI bus controller
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+
+#define	CLK_NAME	10
+struct spi_controller_pdata {
+	int use_dma;
+	int num_chipselects;
+	int bus_num;
+	u32 max_freq;
+	char clk_name[CLK_NAME];
+};
+
+struct spi_platform_data {
+	int type;
+	int dummy;
+};
+
+struct spi_controller_data {
+        u8 poll_mode;   /* 0 for contoller polling mode */
+        u8 type;        /* SPI/SSP/Micrwire */
+        u8 enable_dma;
+        void (*cs_control)(u32 command);
+};
+
+struct spi_platform_data spi_pdata = {
+	.type = 0,
+	.dummy = 0,
+};
+
+struct spi_controller_data spi_ctrl_data =  {
+        .poll_mode = 1,
+};
+
+static struct spi_board_info comcerto_spi_board_info[] = {
+	{
+		/* FIXME: for chipselect-0 */
+		.modalias = "comcerto_spi1",
+		.chip_select = 0,
+		.max_speed_hz = 4*1000*1000,
+		.bus_num = 0,
+		.irq = -1,
+		.mode = SPI_MODE_3,
+		.platform_data = &spi_pdata,
+                .controller_data = &spi_ctrl_data,
+	},
+	{
+		/* FIXME: for chipselect-1 */
+		.modalias = "proslic",
+		.max_speed_hz = 4*1000*1000,
+		.chip_select = 1,
+		.mode = SPI_MODE_3,
+		.bus_num = 0,
+		.irq = -1,
+		.platform_data = &spi_pdata,
+                .controller_data = &spi_ctrl_data,
+	},
+	{
+		.modalias = "comcerto_spi3",
+		.chip_select = 2,
+		.max_speed_hz = 4*1000*1000,
+		.bus_num = 0,
+		.irq = -1,
+		.mode = SPI_MODE_3,
+		.platform_data = &spi_pdata,
+                .controller_data = &spi_ctrl_data,
+	},
+
+#if 0 //MSIF
+
+	{
+		.modalias = "proslic",
+		.max_speed_hz = 2*1000*1000,
+		.chip_select = 3,
+                .mode = SPI_MODE_1,
+		.bus_num = 0,
+		.irq = -1,
+		.platform_data = &spi_pdata,
+                .controller_data = &spi_ctrl_data,
+	},
+#else
+	{
+		.modalias = "legerity",
+		.chip_select = 3,
+		.max_speed_hz = 4*1000*1000,
+		.bus_num = 0,
+		.irq = -1,
+		.mode = SPI_MODE_3,
+		.platform_data = &spi_pdata,
+                .controller_data = &spi_ctrl_data,
+	},
+#endif
+};
+#endif
+
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+struct spi_controller_pdata fast_spi_pdata = {
+	.use_dma = 0,
+	.num_chipselects = 2,
+	.bus_num = 1,
+	.max_freq = 60 * 1000 * 1000,
+	.clk_name = "DUS",
+};
+#endif
+
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED) || defined(CONFIG_SPI2_MSPD_HIGH_SPEED)
+static struct resource comcerto_fast_spi_resource[] = {
+	{
+		.start  = COMCERTO_AXI_SPI_BASE,
+		.end    = COMCERTO_AXI_SPI_BASE + SZ_4K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = IRQ_SPI,
+		.flags  = IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device comcerto_fast_spi = {
+	.name = "comcerto_spi",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(comcerto_fast_spi_resource),
+	.resource = comcerto_fast_spi_resource,
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+	.dev = {
+		.platform_data = &fast_spi_pdata,
+	},
+#endif
+};
+#endif
+
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED)
+struct spi_controller_pdata ls_spi_pdata = {
+	.use_dma = 0,
+	.num_chipselects = 4,
+	.bus_num = 0,
+	.max_freq = 20 * 1000 * 1000,
+	.clk_name = "spi_i2c",
+};
+#endif
+
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI2_MSPD_LOW_SPEED)
+static struct resource comcerto_spi_resource[] = {
+	{
+		.start  = COMCERTO_APB_SPI_BASE,
+		.end    = COMCERTO_APB_SPI_BASE + SZ_4K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = IRQ_SPI_LS,
+		.flags  = IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device comcerto_spi = {
+	.name = "comcerto_spi",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(comcerto_spi_resource),
+	.resource = comcerto_spi_resource,
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED)
+	.dev = {
+		.platform_data = &ls_spi_pdata,
+	},
+#endif
+};
+#endif
+
+/* --------------------------------------------------------------------
+ *  I2C bus controller
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_COMCERTO_I2C_SUPPORT)
+static struct resource comcerto_i2c_resources[] = {
+	{
+		.start	= COMCERTO_APB_I2C_BASE,
+		.end	= COMCERTO_APB_I2C_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IRQ_I2C,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device comcerto_i2c = {
+	.name           = "comcerto_i2c",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(comcerto_i2c_resources),
+	.resource       = comcerto_i2c_resources,
+};
+#endif
+
+/* --------------------------------------------------------------------
+*  Watchdog
+* -------------------------------------------------------------------- */
+#ifdef CONFIG_MPCORE_WATCHDOG
+static struct resource comcerto_a9wd_resources[] = {
+	{
+		.start	= COMCERTO_TWD_BASE,
+		.end	= COMCERTO_TWD_BASE + 0xFF,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "mpcore_wdt",
+		.start	= IRQ_LOCALWDOG,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device comcerto_a9wd = {
+	.name		= "mpcore_wdt",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(comcerto_a9wd_resources),
+	.resource       = comcerto_a9wd_resources,
+};
+#endif
+
+#ifdef CONFIG_COMCERTO_WATCHDOG
+static struct resource comcerto_wdt_resources[] = {
+	{
+		.start	= COMCERTO_APB_TIMER_BASE + 0xD0,
+		.end	= COMCERTO_APB_TIMER_BASE + 0xD8,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device comcerto_wdt = {
+        .name   = "comcerto_wdt",
+        .id     = -1,
+	.num_resources  = ARRAY_SIZE(comcerto_wdt_resources),
+	.resource       = comcerto_wdt_resources,
+};
+#endif
+
+#if defined(CONFIG_COMCERTO_ELP_SUPPORT)
+/* --------------------------------------------------------------------
+ *  IPsec
+ * -------------------------------------------------------------------- */
+static struct resource comcerto_elp_resources[] = {
+	{
+		.name   = "elp",
+		.start  = COMCERTO_AXI_SPACC_PDU_BASE,
+		.end    = COMCERTO_AXI_SPACC_PDU_BASE + SZ_16M  - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "irq_spacc",
+		.start  = IRQ_SPACC,
+		.end    = IRQ_SPACC,
+		.flags  = IORESOURCE_IRQ,
+	}
+};
+
+static u64 comcerto_elp_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device  comcerto_elp_device = {
+	.name                   = "Elliptic-EPN1802",
+	.id                     = 0,
+	.num_resources          = 2,
+	.resource               = comcerto_elp_resources,
+	.dev = {
+		.dma_mask               = &comcerto_elp_dma_mask,
+		.coherent_dma_mask      = DMA_BIT_MASK(32),
+	},
+};
+#endif
+
+
+static struct comcerto_tdm_data comcerto_tdm_pdata = {
+	.fsoutput = 1, /* Generic Pad Control and Version ID Register[2] */
+	.fspolarity = 0, /* 28 FSYNC_FALL(RISE)_EDGE */
+	.fshwidth = 1, /* High_Phase_Width[10:0] */
+	.fslwidth = 0xFF, /* Low_Phase_Width[10:0] */
+	.clockhz = 2048000, /* INC_VALUE[29:0] According to the desired TDM clock output 
+			frequency, this field should be configured */
+	.clockout = 1, /* 0 -> set bit 21, clear bit 20 in COMCERTO_GPIO_IOCTRL_REG
+			  (software control, clock input)
+			  1 -> set bit 21 and 20 in COMCERTO_GPIO_IOCTRL_REG
+			  (software control, clock output)
+			  2 -> clear bit 21 in COMCERTO_GPIO_IOCTRL_REG (hardware control) */
+	.tdmmux = 0x1, /* TDM interface Muxing:0x0 - TDM block, 0x1 - ZDS block,
+		0x2 - GPIO[63:60] signals and 0x3 - MSIF block is selected */
+#if 0
+	/* FIX ME - Need correct values for TDM_DR, TDM_DX, TDM_FS and TDM_CK */
+	.tdmck = 0x3F,
+	.tdmfs = 0x3F,
+	.tdmdx = 0x3F,
+	.tdmdr = 0x3F,
+#endif
+};
+
+static struct platform_device comcerto_tdm_device = {
+	.name	= "comcerto-tdm",
+	.id		= 0,
+	.dev.platform_data = &comcerto_tdm_pdata,
+	.num_resources	= 0,
+	.resource = NULL,
+};
+
+#if defined(CONFIG_DSPG_DECT_CSS)
+#define CSS_ITCM_BASE		COMCERTO_AXI_DECT_BASE
+#define CSS_ITCM_SIZE		(SZ_1M)
+
+#define CSS_DTCM_BASE		(CSS_ITCM_BASE + CSS_ITCM_SIZE)
+#define CSS_DTCM_SIZE		(SZ_1M)
+
+static struct resource comcerto_css_resources[] = {
+	{
+		.name	= "itcm",
+		.start	= CSS_ITCM_BASE,
+		.end	= CSS_ITCM_BASE + CSS_ITCM_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "dtcm",
+		.start	= CSS_DTCM_BASE,
+		.end	= CSS_DTCM_BASE + CSS_DTCM_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device comcerto_css_device = {
+	.name		= "css",
+	.id		= 0,
+	.dev		= {
+		.platform_data = 0,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+	.num_resources	= ARRAY_SIZE(comcerto_css_resources),
+	.resource	= comcerto_css_resources,
+};
+#endif
+
+static struct resource comcerto_pfe_resources[] = {
+	{
+		.name	= "apb",
+		.start  = COMCERTO_APB_PFE_BASE,
+		.end    = COMCERTO_APB_PFE_BASE + COMCERTO_APB_PFE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name	= "axi",
+		.start  = COMCERTO_AXI_PFE_BASE,
+		.end    = COMCERTO_AXI_PFE_BASE + COMCERTO_AXI_PFE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name	= "ddr",
+		.start  = COMCERTO_PFE_DDR_BASE,
+		.end	= COMCERTO_PFE_DDR_BASE + COMCERTO_PFE_DDR_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name	= "iram",
+		.start  = COMCERTO_PFE_IRAM_BASE,
+		.end	= COMCERTO_PFE_IRAM_BASE + COMCERTO_PFE_IRAM_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name	= "ipsec",
+		.start  = COMCERTO_AXI_IPSEC_BASE,
+		.end	= COMCERTO_AXI_IPSEC_BASE + COMCERTO_AXI_IPSEC_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name	= "hif",
+		.start  = IRQ_PFE_HIF,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct comcerto_pfe_platform_data comcerto_pfe_pdata = {
+	.comcerto_eth_pdata[0] = {
+		.name = GEM0_ITF_NAME,
+		.device_flags = CONFIG_COMCERTO_GEMAC,
+		.mii_config = CONFIG_COMCERTO_USE_RGMII,
+		.gemac_mode = GEMAC_SW_CONF | GEMAC_SW_FULL_DUPLEX | GEMAC_SW_SPEED_1G,
+		.phy_flags = GEMAC_PHY_RGMII_ADD_DELAY,
+		.bus_id = 0,
+		.phy_id = 4,
+		.gem_id = 0,
+		.mac_addr = (u8[])GEM0_MAC,
+	},
+
+	.comcerto_eth_pdata[1] = {
+		.name = GEM1_ITF_NAME,
+		.device_flags = CONFIG_COMCERTO_GEMAC,
+		.mii_config = CONFIG_COMCERTO_USE_RGMII,
+		.gemac_mode = GEMAC_SW_CONF | GEMAC_SW_FULL_DUPLEX | GEMAC_SW_SPEED_1G,
+		.phy_flags = GEMAC_PHY_RGMII_ADD_DELAY,
+		.bus_id = 0,
+		.phy_id = 5,
+		.gem_id = 1,
+		.mac_addr = (u8[])GEM1_MAC,
+	},
+
+	.comcerto_eth_pdata[2] = {
+		.name = GEM2_ITF_NAME,
+		.device_flags = CONFIG_COMCERTO_GEMAC,
+		.mii_config = CONFIG_COMCERTO_USE_RGMII,
+		.gemac_mode = GEMAC_SW_CONF | GEMAC_SW_FULL_DUPLEX | GEMAC_SW_SPEED_1G,
+		.phy_flags = GEMAC_PHY_RGMII_ADD_DELAY,
+		.bus_id = 0,
+		.phy_id = 6,
+		.gem_id = 2,
+		.mac_addr = (u8[])GEM2_MAC,
+	},
+
+	/**
+	 * There is a single mdio bus coming out of C2K.  And that's the one
+	 * connected to GEM0. All PHY's, switchs will be connected to the same
+	 * bus using different addresses. Typically .bus_id is always 0, only
+	 * .phy_id will change in the different comcerto_eth_pdata[] structures above.
+	 */
+	.comcerto_mdio_pdata[0] = {
+		.enabled = 1,
+		.phy_mask = 0xFFFFFF8F,
+		.mdc_div = 96,
+		.irq = {
+			[4] = PHY_POLL,
+			[5] = PHY_POLL,
+			[6] = PHY_POLL,
+		},
+	},
+};
+
+static u64 comcerto_pfe_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device comcerto_pfe_device = {
+	.name		= "pfe",
+	.id		= 0,
+	.dev		= {
+		.platform_data		= &comcerto_pfe_pdata,
+		.dma_mask		= &comcerto_pfe_dma_mask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.num_resources	= ARRAY_SIZE(comcerto_pfe_resources),
+	.resource	= comcerto_pfe_resources,
+};
+
+static struct platform_device *comcerto_devices[] __initdata = {
+#if defined(CONFIG_MTD_NAND_COMCERTO) || defined(CONFIG_MTD_NAND_COMCERTO_MODULE)
+		&comcerto_nand,
+#endif
+#if defined(CONFIG_MTD_COMCERTO_NOR)
+		&comcerto_nor,
+#endif
+#if defined(CONFIG_COMCERTO_I2C_SUPPORT)
+		&comcerto_i2c,
+#endif
+
+#if defined (CONFIG_MPCORE_WATCHDOG)
+		&comcerto_a9wd,
+#endif
+
+#if defined(CONFIG_COMCERTO_WATCHDOG)
+		&comcerto_wdt,
+#endif
+
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED) || defined(CONFIG_SPI2_MSPD_HIGH_SPEED)
+		&comcerto_fast_spi,
+#endif
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI2_MSPD_LOW_SPEED)
+		&comcerto_spi,
+#endif
+#if defined(CONFIG_COMCERTO_DW_DMA_SUPPORT)
+		&dw_dmac_device,
+#endif
+		&comcerto_tdm_device,
+		&comcerto_pfe_device,
+		&rtc_dev,
+#if defined(CONFIG_DSPG_DECT_CSS)
+		&comcerto_css_device,
+#endif
+#if defined(CONFIG_COMCERTO_ELP_SUPPORT)
+	&comcerto_elp_device,
+#endif
+};
+
+
+/************************************************************************
+ *  Expansion bus
+ *
+ ************************************************************************/
+/* This variable is used by comcerto-2000.c to initialize the expansion bus */
+int comcerto_exp_values[5][7]= {
+	/* ENABLE, BASE, SEG_SZ, CFG, TMG1, TMG2, TMG3 */
+	{1, (EXP_BUS_REG_BASE_CS0 >> 12), ((EXP_BUS_REG_BASE_CS0 + EXP_CS0_SEG_SIZE - 1) >> 12), EXP_MEM_BUS_SIZE_16, 0x1A1A401F, 0x06060A04, 0x00000002},		/*TODO Values to check*/
+	{0, (EXP_BUS_REG_BASE_CS1 >> 12), ((EXP_BUS_REG_BASE_CS1 + EXP_CS1_SEG_SIZE - 1) >> 12), EXP_RDY_EN|EXP_MEM_BUS_SIZE_32, 0x1A1A401F, 0x06060A04, 0x00000002},	/*TODO Values to check*/
+	{0, (EXP_BUS_REG_BASE_CS2 >> 12), ((EXP_BUS_REG_BASE_CS2 + EXP_CS2_SEG_SIZE - 1) >> 12), EXP_STRB_MODE|EXP_ALE_MODE|EXP_MEM_BUS_SIZE_8, 0x1A10201A, 0x03080403, 0x0000002},	/*TODO Values to check*/
+	{0, (EXP_BUS_REG_BASE_CS3 >> 12), ((EXP_BUS_REG_BASE_CS3 + EXP_CS3_SEG_SIZE - 1) >> 12), EXP_STRB_MODE|EXP_ALE_MODE|EXP_MEM_BUS_SIZE_8, 0x1A10201A, 0x03080403, 0x0000002},	/*BT8370*/
+	{0, (EXP_BUS_REG_BASE_CS4 >> 12), ((EXP_BUS_REG_BASE_CS4 + EXP_CS4_SEG_SIZE - 1) >> 12), EXP_NAND_MODE|EXP_MEM_BUS_SIZE_8, 0x1A1A401F, 0x06060A04, 0x00000002},	/* NAND: TODO Values to check */
+};
+
+/************************************************************************
+ *  Machine definition
+ *
+ ************************************************************************/
+static void __init platform_map_io(void)
+{
+	device_map_io();
+}
+
+static void __init platform_irq_init(void)
+{
+	device_irq_init();
+}
+
+static void __init platform_init(void)
+{
+	device_init();
+	board_gpio_init();
+
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED) || defined(CONFIG_SPI_MSPD_LOW_SPEED)
+	spi_register_board_info(comcerto_spi_board_info, ARRAY_SIZE(comcerto_spi_board_info));
+#endif
+	mac_addr_init(&comcerto_pfe_pdata);
+
+	platform_add_devices(comcerto_devices, ARRAY_SIZE(comcerto_devices));
+}
+
+MACHINE_START(COMCERTO, "Comcerto 2000 ASIC")
+	/* Mindspeed Technologies Inc. */
+	.atag_offset    = COMCERTO_AXI_DDR_BASE + 0x100,
+	.reserve	= platform_reserve,
+	.map_io		= platform_map_io,
+	.init_irq	= platform_irq_init,
+	.init_machine	= platform_init,
+	.timer		= &comcerto_timer,
+#ifdef CONFIG_ZONE_DMA
+	.dma_zone_size	= SZ_32M + 3*SZ_4M,  /* Up to start of memory reserved for PFE+MSP */
+#endif
+MACHINE_END
diff --git a/arch/arm/mach-comcerto/board-c2kevm.c b/arch/arm/mach-comcerto/board-c2kevm.c
new file mode 100644
index 0000000..d944636
--- /dev/null
+++ b/arch/arm/mach-comcerto/board-c2kevm.c
@@ -0,0 +1,743 @@
+/*
+ * arch/arm/mach-comcerto/board-c2kevm.c
+ *
+ *  Copyright (C) 2012 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/sched.h>
+#include <linux/device.h>
+#include <linux/serial_8250.h>
+#include <linux/memblock.h>
+#include <linux/phy.h>
+
+#include <linux/mtd/mtd.h>
+#if defined(CONFIG_MTD_NAND_COMCERTO) || defined(CONFIG_MTD_NAND_COMCERTO_MODULE)
+#include <linux/mtd/nand.h>
+#endif
+#include <linux/mtd/partitions.h>
+
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+#include <linux/spi/spi.h>
+#endif
+
+#include <asm/sizes.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/io.h>
+
+#include <asm/mach/flash.h>
+#include <asm/mach/arch.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/dma.h>
+#include <linux/dw_dmac.h>
+
+#include <linux/clockchips.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <asm/smp_twd.h>
+#include <asm/localtimer.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/time.h>
+#include <mach/gpio.h>
+
+
+extern void platform_reserve(void);
+extern void device_map_io (void);
+extern void device_irq_init(void);
+extern void device_init(void);
+extern void mac_addr_init(struct comcerto_pfe_platform_data *);
+extern struct sys_timer comcerto_timer;
+
+static void __init board_gpio_init(void)
+{
+#ifdef CONFIG_COMCERTO_PFE_UART_SUPPORT
+	writel((readl(COMCERTO_GPIO_PIN_SELECT_REG) & ~PFE_UART_GPIO) | PFE_UART_BUS, COMCERTO_GPIO_PIN_SELECT_REG);
+	c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= PFE_UART_GPIO_PIN; /* GPIOs 12 & 13 are used for PFE_UART */
+#endif
+
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI2_MSPD_LOW_SPEED)
+	/* enable SPI pins */
+	writel((readl(COMCERTO_GPIO_PIN_SELECT_REG1) & ~(SPI_MUX_GPIO_1)) | (SPI_MUX_BUS_1), COMCERTO_GPIO_PIN_SELECT_REG1);
+	writel((readl(COMCERTO_GPIO_63_32_PIN_SELECT) & ~(SPI_MUX_GPIO_2)) | (SPI_MUX_BUS_2), COMCERTO_GPIO_63_32_PIN_SELECT);
+	c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= SPI_MUX_GPIO_1_PIN; /* GPIOs 18,19, 21,22, 30,31 are used for SPI*/
+	c2k_gpio_pin_stat.c2k_gpio_pins_32_63 |= SPI_MUX_GPIO_2_PIN; /* GPIO 32 is used for SPI*/
+#endif
+
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+	/* enable SPI pins */
+	writel((readl(COMCERTO_GPIO_PIN_SELECT_REG1) & ~(SPI_2_MUX_GPIO_1)) | (SPI_2_MUX_BUS_1), COMCERTO_GPIO_PIN_SELECT_REG1);
+	writel((readl(COMCERTO_GPIO_63_32_PIN_SELECT) & ~(SPI_2_MUX_GPIO_2)) | (SPI_2_MUX_BUS_2), COMCERTO_GPIO_63_32_PIN_SELECT);
+	c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= SPI_2_MUX_GPIO_1_PIN;
+	c2k_gpio_pin_stat.c2k_gpio_pins_32_63 |= SPI_2_MUX_GPIO_2_PIN;
+#endif
+
+#if defined(CONFIG_COMCERTO_I2C_SUPPORT)
+	writel((readl(COMCERTO_GPIO_PIN_SELECT_REG1) & ~I2C_GPIO) | I2C_BUS, COMCERTO_GPIO_PIN_SELECT_REG1);
+	c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= I2C_GPIO_PIN;
+#endif
+
+#if defined(CONFIG_MTD_NAND_COMCERTO) || defined(CONFIG_MTD_NAND_COMCERTO_MODULE)
+	writel((readl(COMCERTO_GPIO_PIN_SELECT_REG1) & ~NAND_GPIO) | NAND_BUS, COMCERTO_GPIO_PIN_SELECT_REG1);
+	c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= NAND_GPIO_PIN;
+#endif
+
+#if defined(CONFIG_MTD_COMCERTO_NOR)
+	writel((readl(COMCERTO_GPIO_PIN_SELECT_REG1) & ~NOR_GPIO) | NOR_BUS, COMCERTO_GPIO_PIN_SELECT_REG1);
+	c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= NOR_GPIO_PIN;
+#endif
+}
+
+/* --------------------------------------------------------------------
+ *  NOR device
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_MTD_COMCERTO_NOR)
+
+static struct resource comcerto_nor_resources[] = {
+	{
+		.start	= NORFLASH_MEMORY_PHY1,
+		.end	= NORFLASH_MEMORY_PHY1 + SZ_64M - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct flash_platform_data comcerto_nor_data = {
+	.map_name	= "cfi_probe",
+	.width	= 2,
+};
+
+static struct platform_device comcerto_nor = {
+	.name           = "comcertoflash",
+	.id             = 0,
+	.num_resources  = ARRAY_SIZE(comcerto_nor_resources),
+	.resource       = comcerto_nor_resources,
+	.dev = {
+		.platform_data	= &comcerto_nor_data,
+	},
+};
+#endif
+
+static struct resource rtc_res[] = {
+       {
+               .start = COMCERTO_APB_RTC_BASE,
+               .end = COMCERTO_APB_RTC_BASE + SZ_32 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_RTC_ALM,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_RTC_PRI,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+static struct platform_device rtc_dev = {
+       .name = "c2k-rtc",
+       .id = -1,
+       .num_resources = ARRAY_SIZE(rtc_res),
+       .resource = rtc_res,
+};
+
+/* --------------------------------------------------------------------
+ *  DMAC controller
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_COMCERTO_DW_DMA_SUPPORT)
+static struct resource dw_dmac_resource[] = {
+	{
+		.start          = DW_DMA_DMAC_BASEADDR,
+		.end            = DW_DMA_DMAC_BASEADDR + 0x2C0,
+		.flags          = IORESOURCE_MEM,
+	},
+	{
+		.start          = IRQ_DMAC,
+		.flags          = IORESOURCE_IRQ,
+	}
+};
+
+static struct dw_dma_platform_data dw_dmac_data = {
+	.nr_channels    = 8,
+};
+
+static u64 dw_dmac_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device dw_dmac_device = {
+	.name           = "dw_dmac",
+	.id             = 0,
+	.dev            = {
+		.dma_mask = &dw_dmac_dma_mask,
+		.platform_data  = &dw_dmac_data,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+	.resource       = dw_dmac_resource,
+	.num_resources  = ARRAY_SIZE(dw_dmac_resource),
+};
+#endif
+
+/* --------------------------------------------------------------------
+ *  NAND device
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_MTD_NAND_COMCERTO) || defined(CONFIG_MTD_NAND_COMCERTO_MODULE)
+static struct resource comcerto_nand_resources[] = {
+	{
+		.start	= COMCERTO_NAND_FIO_ADDR,
+		.end	= COMCERTO_NAND_FIO_ADDR + COMCERTO_NAND_IO_SZ - 1,
+		.flags	= IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device comcerto_nand = {
+	.name		= "comcertonand",
+	.id		= -1,
+	.dev		= {
+				.platform_data	= NULL,
+	},
+	.resource	= comcerto_nand_resources,
+	.num_resources	= ARRAY_SIZE(comcerto_nand_resources),
+};
+#endif
+
+/* --------------------------------------------------------------------
+ *  SPI bus controller
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+
+#define	CLK_NAME	10
+struct spi_controller_pdata {
+	int use_dma;
+	int num_chipselects;
+	int bus_num;
+	u32 max_freq;
+	char clk_name[CLK_NAME];
+};
+
+struct spi_platform_data {
+	int type;
+	int dummy;
+};
+
+struct spi_controller_data {
+        u8 poll_mode;   /* 0 for contoller polling mode */
+        u8 type;        /* SPI/SSP/Micrwire */
+        u8 enable_dma;
+        void (*cs_control)(u32 command);
+};
+
+struct spi_platform_data spi_pdata = {
+	.type = 0,
+	.dummy = 0,
+};
+
+struct spi_controller_data spi_ctrl_data =  {
+        .poll_mode = 1,
+};
+
+static struct spi_board_info comcerto_spi_board_info[] = {
+	{
+		/* FIXME: for chipselect-0 */
+		.modalias = "s25fl256s0",
+		.chip_select = 0,
+		.max_speed_hz = 4*1000*1000,
+		.bus_num = 0,
+		.irq = -1,
+		.mode = SPI_MODE_3,
+		.platform_data = &spi_pdata,
+                .controller_data = &spi_ctrl_data,
+	},
+	{
+		/* FIXME: for chipselect-1 */
+		.modalias = "proslic",
+		.max_speed_hz = 4*1000*1000,
+		.chip_select = 1,
+		.mode = SPI_MODE_3,
+		.bus_num = 0,
+		.irq = -1,
+		.mode = SPI_MODE_3,
+		.platform_data = &spi_pdata,
+                .controller_data = &spi_ctrl_data,
+	},
+	{
+		.modalias = "comcerto_spi3",
+		.chip_select = 2,
+		.max_speed_hz = 4*1000*1000,
+		.bus_num = 0,
+		.irq = -1,
+		.mode = SPI_MODE_3,
+		.platform_data = &spi_pdata,
+                .controller_data = &spi_ctrl_data,
+	},
+
+#if 0 //MSIF
+
+	{
+		.modalias = "proslic",
+		.max_speed_hz = 2*1000*1000,
+		.chip_select = 3,
+		.mode = SPI_MODE_1,
+		.bus_num = 0,
+		.irq = -1,
+		.mode = SPI_MODE_3,
+		.platform_data = &spi_pdata,
+                .controller_data = &spi_ctrl_data,
+	},
+#else
+	{
+		.modalias = "legerity",
+		.chip_select = 3,
+		.max_speed_hz = 4*1000*1000,
+		.bus_num = 0,
+		.irq = -1,
+		.mode = SPI_MODE_3,
+		.platform_data = &spi_pdata,
+                .controller_data = &spi_ctrl_data,
+	},
+#endif
+};
+#endif
+
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+struct spi_controller_pdata fast_spi_pdata = {
+	.use_dma = 0,
+	.num_chipselects = 2,
+	.bus_num = 1,
+	.max_freq = 60 * 1000 * 1000,
+	.clk_name = "DUS",
+};
+#endif
+
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED) || defined(CONFIG_SPI2_MSPD_HIGH_SPEED)
+static struct resource comcerto_fast_spi_resource[] = {
+	{
+		.start  = COMCERTO_AXI_SPI_BASE,
+		.end    = COMCERTO_AXI_SPI_BASE + SZ_4K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = IRQ_SPI,
+		.flags  = IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device comcerto_fast_spi = {
+	.name = "comcerto_spi",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(comcerto_fast_spi_resource),
+	.resource = comcerto_fast_spi_resource,
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+	.dev = {
+		.platform_data = &fast_spi_pdata,
+	},
+#endif
+};
+#endif
+
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED)
+struct spi_controller_pdata ls_spi_pdata = {
+	.use_dma = 0,
+	.num_chipselects = 4,
+	.bus_num = 0,
+	.max_freq = 20 * 1000 * 1000,
+	.clk_name = "spi_i2c",
+};
+#endif
+
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI2_MSPD_LOW_SPEED)
+static struct resource comcerto_spi_resource[] = {
+	{
+		.start  = COMCERTO_APB_SPI_BASE,
+		.end    = COMCERTO_APB_SPI_BASE + SZ_4K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = IRQ_SPI_LS,
+		.flags  = IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device comcerto_spi = {
+	.name = "comcerto_spi",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(comcerto_spi_resource),
+	.resource = comcerto_spi_resource,
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED)
+	.dev = {
+		.platform_data = &ls_spi_pdata,
+	},
+#endif
+};
+#endif
+
+/* --------------------------------------------------------------------
+ *  I2C bus controller
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_COMCERTO_I2C_SUPPORT)
+static struct resource comcerto_i2c_resources[] = {
+	{
+		.start	= COMCERTO_APB_I2C_BASE,
+		.end	= COMCERTO_APB_I2C_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IRQ_I2C,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device comcerto_i2c = {
+	.name           = "comcerto_i2c",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(comcerto_i2c_resources),
+	.resource       = comcerto_i2c_resources,
+};
+#endif
+
+/* --------------------------------------------------------------------
+*  Watchdog
+* -------------------------------------------------------------------- */
+#ifdef CONFIG_MPCORE_WATCHDOG
+static struct resource comcerto_a9wd_resources[] = {
+	{
+		.start	= COMCERTO_TWD_BASE,
+		.end	= COMCERTO_TWD_BASE + 0xFF,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "mpcore_wdt",
+		.start	= IRQ_LOCALWDOG,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device comcerto_a9wd = {
+	.name		= "mpcore_wdt",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(comcerto_a9wd_resources),
+	.resource       = comcerto_a9wd_resources,
+};
+#endif
+
+#ifdef CONFIG_COMCERTO_WATCHDOG
+static struct resource comcerto_wdt_resources[] = {
+	{
+		.start	= COMCERTO_APB_TIMER_BASE + 0xD0,
+		.end	= COMCERTO_APB_TIMER_BASE + 0xD8,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device comcerto_wdt = {
+        .name   = "comcerto_wdt",
+        .id     = -1,
+	.num_resources  = ARRAY_SIZE(comcerto_wdt_resources),
+	.resource       = comcerto_wdt_resources,
+};
+#endif
+
+#if defined(CONFIG_COMCERTO_ELP_SUPPORT)
+/* --------------------------------------------------------------------
+ *  IPsec
+ * -------------------------------------------------------------------- */
+static struct resource comcerto_elp_resources[] = {
+	{
+		.name   = "elp",
+		.start  = COMCERTO_AXI_SPACC_PDU_BASE,
+		.end    = COMCERTO_AXI_SPACC_PDU_BASE + SZ_16M  - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "irq_spacc",
+		.start  = IRQ_SPACC,
+		.end    = IRQ_SPACC,
+		.flags  = IORESOURCE_IRQ,
+	}
+};
+
+static u64 comcerto_elp_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device  comcerto_elp_device = {
+	.name                   = "Elliptic-EPN1802",
+	.id                     = 0,
+	.num_resources          = 2,
+	.resource               = comcerto_elp_resources,
+	.dev = {
+		.dma_mask               = &comcerto_elp_dma_mask,
+		.coherent_dma_mask      = DMA_BIT_MASK(32),
+	},
+};
+#endif
+
+static struct comcerto_tdm_data comcerto_tdm_pdata = {
+	.fsoutput = 1, /* Generic Pad Control and Version ID Register[2] */
+	.fspolarity = 0, /* 28 FSYNC_FALL(RISE)_EDGE */
+	.fshwidth = 1, /* High_Phase_Width[10:0] */
+	.fslwidth = 0xFF, /* Low_Phase_Width[10:0] */
+	.clockhz = 2048000, /* INC_VALUE[29:0] According to the desired TDM clock output \
+			       frequency, this field should be configured */
+	.clockout = 1, /* 0 -> set bit 21, clear bit 20 in COMCERTO_GPIO_IOCTRL_REG
+			  (software control, clock input)
+			  1 -> set bit 21 and 20 in COMCERTO_GPIO_IOCTRL_REG
+			  (software control, clock output)
+			  2 -> clear bit 21 in COMCERTO_GPIO_IOCTRL_REG (hardware control) */
+	.tdmmux = 0x1, /* TDM interface Muxing:0x0 - TDM block, 0x1 - ZDS block,
+		0x2 - GPIO[63:60] signals and 0x3 - MSIF block is selected */
+#if 0
+	/* FIX ME - Need correct values for TDM_DR, TDM_DX, TDM_FS and TDM_CK */
+	.tdmck = 0x3F,
+	.tdmfs = 0x3F,
+	.tdmdx = 0x3F,
+	.tdmdr = 0x3F,
+#endif
+};
+
+static struct platform_device comcerto_tdm_device = {
+	.name	= "comcerto-tdm",
+	.id		= 0,
+	.dev.platform_data = &comcerto_tdm_pdata,
+	.num_resources	= 0,
+	.resource = NULL,
+};
+
+#if defined(CONFIG_DSPG_DECT_CSS)
+#define CSS_ITCM_BASE		COMCERTO_AXI_DECT_BASE
+#define CSS_ITCM_SIZE		(SZ_1M)
+
+#define CSS_DTCM_BASE		(CSS_ITCM_BASE + CSS_ITCM_SIZE)
+#define CSS_DTCM_SIZE		(SZ_1M)
+
+static struct resource comcerto_css_resources[] = {
+	{
+		.name	= "itcm",
+		.start	= CSS_ITCM_BASE,
+		.end	= CSS_ITCM_BASE + CSS_ITCM_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "dtcm",
+		.start	= CSS_DTCM_BASE,
+		.end	= CSS_DTCM_BASE + CSS_DTCM_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device comcerto_css_device = {
+	.name		= "css",
+	.id		= 0,
+	.dev		= {
+		.platform_data = 0,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+	.num_resources	= ARRAY_SIZE(comcerto_css_resources),
+	.resource	= comcerto_css_resources,
+};
+#endif
+
+static struct resource comcerto_pfe_resources[] = {
+	{
+		.name	= "apb",
+		.start  = COMCERTO_APB_PFE_BASE,
+		.end    = COMCERTO_APB_PFE_BASE + COMCERTO_APB_PFE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name	= "axi",
+		.start  = COMCERTO_AXI_PFE_BASE,
+		.end    = COMCERTO_AXI_PFE_BASE + COMCERTO_AXI_PFE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name	= "ddr",
+		.start  = COMCERTO_PFE_DDR_BASE,
+		.end	= COMCERTO_PFE_DDR_BASE + COMCERTO_PFE_DDR_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name	= "iram",
+		.start  = COMCERTO_PFE_IRAM_BASE,
+		.end	= COMCERTO_PFE_IRAM_BASE + COMCERTO_PFE_IRAM_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+        {
+                .name   = "ipsec",
+                .start  = COMCERTO_AXI_IPSEC_BASE,
+                .end    = COMCERTO_AXI_IPSEC_BASE + COMCERTO_AXI_IPSEC_SIZE - 1,
+                .flags  = IORESOURCE_MEM,
+        },
+
+	{
+		.name	= "hif",
+		.start  = IRQ_PFE_HIF,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct comcerto_pfe_platform_data comcerto_pfe_pdata = {
+	.comcerto_eth_pdata[0] = {
+		.name = GEM0_ITF_NAME,
+		.device_flags = CONFIG_COMCERTO_GEMAC,
+		.mii_config = CONFIG_COMCERTO_USE_RGMII,
+		.gemac_mode = GEMAC_SW_CONF | GEMAC_SW_FULL_DUPLEX | GEMAC_SW_SPEED_1G,
+		.phy_flags = GEMAC_PHY_RGMII_ADD_DELAY,
+		.bus_id = 0,
+		.phy_id = 4,
+		.gem_id = 0,
+		.mac_addr = (u8[])GEM0_MAC,
+	},
+
+	.comcerto_eth_pdata[1] = {
+		.name = GEM1_ITF_NAME,
+		.device_flags = CONFIG_COMCERTO_GEMAC,
+		.mii_config = CONFIG_COMCERTO_USE_RGMII,
+		.gemac_mode = GEMAC_SW_CONF | GEMAC_SW_FULL_DUPLEX | GEMAC_SW_SPEED_1G,
+		.phy_flags = GEMAC_NO_PHY,
+		.gem_id = 1,
+		.mac_addr = (u8[])GEM1_MAC,
+	},
+
+	.comcerto_eth_pdata[2] = {
+		.name = GEM2_ITF_NAME,
+		.device_flags = CONFIG_COMCERTO_GEMAC,
+		.mii_config = CONFIG_COMCERTO_USE_RGMII,
+		.gemac_mode = GEMAC_SW_CONF | GEMAC_SW_FULL_DUPLEX | GEMAC_SW_SPEED_1G,
+		.phy_flags = GEMAC_NO_PHY,
+		.gem_id = 2,
+		.mac_addr = (u8[])GEM2_MAC,
+	},
+
+	/**
+	 * There is a single mdio bus coming out of C2K.  And that's the one
+	 * connected to GEM0. All PHY's, switchs will be connected to the same
+	 * bus using different addresses. Typically .bus_id is always 0, only
+	 * .phy_id will change in the different comcerto_eth_pdata[] structures above.
+	 */
+	.comcerto_mdio_pdata[0] = {
+		.enabled = 1,
+		.phy_mask = 0xFFFFFFEF,
+		.mdc_div = 96,
+		.irq = {
+			[4] = PHY_POLL,
+		},
+	},
+};
+
+static u64 comcerto_pfe_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device comcerto_pfe_device = {
+	.name		= "pfe",
+	.id		= 0,
+	.dev		= {
+		.platform_data		= &comcerto_pfe_pdata,
+		.dma_mask		= &comcerto_pfe_dma_mask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.num_resources	= ARRAY_SIZE(comcerto_pfe_resources),
+	.resource	= comcerto_pfe_resources,
+};
+
+static struct platform_device *comcerto_devices[] __initdata = {
+#if defined(CONFIG_MTD_NAND_COMCERTO) || defined(CONFIG_MTD_NAND_COMCERTO_MODULE)
+		&comcerto_nand,
+#endif
+#if defined(CONFIG_MTD_COMCERTO_NOR)
+		&comcerto_nor,
+#endif
+#if defined(CONFIG_COMCERTO_I2C_SUPPORT)
+		&comcerto_i2c,
+#endif
+
+#if defined (CONFIG_MPCORE_WATCHDOG)
+		&comcerto_a9wd,
+#endif
+
+#if defined(CONFIG_COMCERTO_WATCHDOG)
+		&comcerto_wdt,
+#endif
+
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED) || defined(CONFIG_SPI2_MSPD_HIGH_SPEED)
+		&comcerto_fast_spi,
+#endif
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI2_MSPD_LOW_SPEED)
+		&comcerto_spi,
+#endif
+#if defined(CONFIG_COMCERTO_DW_DMA_SUPPORT)
+		&dw_dmac_device,
+#endif
+		&comcerto_tdm_device,
+		&comcerto_pfe_device,
+		&rtc_dev,
+#if defined(CONFIG_DSPG_DECT_CSS)
+		&comcerto_css_device,
+#endif
+#if defined(CONFIG_COMCERTO_ELP_SUPPORT)
+	&comcerto_elp_device,
+#endif
+};
+
+
+/************************************************************************
+ *  Expansion bus
+ *
+ ************************************************************************/
+/* This variable is used by comcerto-2000.c to initialize the expansion bus */
+int comcerto_exp_values[5][7]= {
+	/* ENABLE, BASE, SEG_SZ, CFG, TMG1, TMG2, TMG3 */
+	{1, (EXP_BUS_REG_BASE_CS0 >> 12), ((EXP_BUS_REG_BASE_CS0 + EXP_CS0_SEG_SIZE - 1) >> 12), EXP_MEM_BUS_SIZE_16, 0x03034007, 0x04040502, 0x00000002},		/*TODO Values to check*/
+	{0, (EXP_BUS_REG_BASE_CS1 >> 12), ((EXP_BUS_REG_BASE_CS1 + EXP_CS1_SEG_SIZE - 1) >> 12), EXP_RDY_EN|EXP_MEM_BUS_SIZE_32, 0x1A1A401F, 0x06060A04, 0x00000002},	/*TODO Values to check*/
+	{0, (EXP_BUS_REG_BASE_CS2 >> 12), ((EXP_BUS_REG_BASE_CS2 + EXP_CS2_SEG_SIZE - 1) >> 12), EXP_STRB_MODE|EXP_ALE_MODE|EXP_MEM_BUS_SIZE_8, 0x1A10201A, 0x03080403, 0x0000002},	/*TODO Values to check*/
+	{0, (EXP_BUS_REG_BASE_CS3 >> 12), ((EXP_BUS_REG_BASE_CS3 + EXP_CS3_SEG_SIZE - 1) >> 12), EXP_STRB_MODE|EXP_ALE_MODE|EXP_MEM_BUS_SIZE_8, 0x1A10201A, 0x03080403, 0x0000002},	/*BT8370*/
+	{1, (EXP_BUS_REG_BASE_CS4 >> 12), ((EXP_BUS_REG_BASE_CS4 + EXP_CS4_SEG_SIZE - 1) >> 12), EXP_NAND_MODE|EXP_MEM_BUS_SIZE_8, 0x00000001, 0x01010001, 0x00000002},	/* NAND: TODO Values to check */
+};
+
+/************************************************************************
+ *  Machine definition
+ *
+ ************************************************************************/
+static void __init platform_map_io(void)
+{
+	device_map_io();
+}
+
+static void __init platform_irq_init(void)
+{
+	device_irq_init();
+}
+
+static void __init platform_init(void)
+{
+	device_init();
+	board_gpio_init();
+
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+	spi_register_board_info(comcerto_spi_board_info, ARRAY_SIZE(comcerto_spi_board_info));
+#endif
+	mac_addr_init(&comcerto_pfe_pdata);
+
+	platform_add_devices(comcerto_devices, ARRAY_SIZE(comcerto_devices));
+}
+
+MACHINE_START(COMCERTO, "Comcerto 2000 EVM")
+	/* Mindspeed Technologies Inc. */
+	.atag_offset    = COMCERTO_AXI_DDR_BASE + 0x100,
+	.reserve	= platform_reserve,
+	.map_io		= platform_map_io,
+	.init_irq	= platform_irq_init,
+	.init_machine	= platform_init,
+	.timer		= &comcerto_timer,
+#ifdef CONFIG_ZONE_DMA
+	.dma_zone_size	= SZ_32M + 3*SZ_4M,
+#endif
+MACHINE_END
diff --git a/arch/arm/mach-comcerto/board-c2kmfcnevm.c b/arch/arm/mach-comcerto/board-c2kmfcnevm.c
new file mode 100644
index 0000000..c14cf44
--- /dev/null
+++ b/arch/arm/mach-comcerto/board-c2kmfcnevm.c
@@ -0,0 +1,743 @@
+/*
+ * arch/arm/mach-comcerto/board-c2kmfcnevm.c
+ *
+ *  Copyright (C) 2012 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/sched.h>
+#include <linux/device.h>
+#include <linux/serial_8250.h>
+#include <linux/memblock.h>
+#include <linux/phy.h>
+
+#include <linux/mtd/mtd.h>
+#if defined(CONFIG_MTD_NAND_COMCERTO) || defined(CONFIG_MTD_NAND_COMCERTO_MODULE)
+#include <linux/mtd/nand.h>
+#endif
+#include <linux/mtd/partitions.h>
+
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+#include <linux/spi/spi.h>
+#endif
+
+#include <asm/sizes.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/io.h>
+
+#include <asm/mach/flash.h>
+#include <asm/mach/arch.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/dma.h>
+#include <linux/dw_dmac.h>
+
+#include <linux/clockchips.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <asm/smp_twd.h>
+#include <asm/localtimer.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/time.h>
+#include <mach/gpio.h>
+
+
+extern void platform_reserve(void);
+extern void device_map_io (void);
+extern void device_irq_init(void);
+extern void device_init(void);
+extern void mac_addr_init(struct comcerto_pfe_platform_data *);
+extern struct sys_timer comcerto_timer;
+
+static void __init board_gpio_init(void)
+{
+#ifdef CONFIG_COMCERTO_PFE_UART_SUPPORT
+	writel((readl(COMCERTO_GPIO_PIN_SELECT_REG) & ~PFE_UART_GPIO) | PFE_UART_BUS, COMCERTO_GPIO_PIN_SELECT_REG);
+	c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= PFE_UART_GPIO_PIN; /* GPIOs 12 & 13 are used for PFE_UART */
+#endif
+
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI2_MSPD_LOW_SPEED)
+	/* enable SPI pins */
+	writel((readl(COMCERTO_GPIO_PIN_SELECT_REG1) & ~(SPI_MUX_GPIO_1)) | (SPI_MUX_BUS_1), COMCERTO_GPIO_PIN_SELECT_REG1);
+	writel((readl(COMCERTO_GPIO_63_32_PIN_SELECT) & ~(SPI_MUX_GPIO_2)) | (SPI_MUX_BUS_2), COMCERTO_GPIO_63_32_PIN_SELECT);
+	c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= SPI_MUX_GPIO_1_PIN; /* GPIOs 18,19, 21,22, 30,31 are used for SPI*/
+	c2k_gpio_pin_stat.c2k_gpio_pins_32_63 |= SPI_MUX_GPIO_2_PIN; /* GPIO 32 is used for SPI*/
+#endif
+
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+	/* enable SPI pins */
+	writel((readl(COMCERTO_GPIO_PIN_SELECT_REG1) & ~(SPI_2_MUX_GPIO_1)) | (SPI_2_MUX_BUS_1), COMCERTO_GPIO_PIN_SELECT_REG1);
+	writel((readl(COMCERTO_GPIO_63_32_PIN_SELECT) & ~(SPI_2_MUX_GPIO_2)) | (SPI_2_MUX_BUS_2), COMCERTO_GPIO_63_32_PIN_SELECT);
+	c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= SPI_2_MUX_GPIO_1_PIN;
+	c2k_gpio_pin_stat.c2k_gpio_pins_32_63 |= SPI_2_MUX_GPIO_2_PIN;
+#endif
+
+#if defined(CONFIG_COMCERTO_I2C_SUPPORT)
+	writel((readl(COMCERTO_GPIO_PIN_SELECT_REG1) & ~I2C_GPIO) | I2C_BUS, COMCERTO_GPIO_PIN_SELECT_REG1);
+	c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= I2C_GPIO_PIN;
+#endif
+
+#if defined(CONFIG_MTD_NAND_COMCERTO) || defined(CONFIG_MTD_NAND_COMCERTO_MODULE)
+	writel((readl(COMCERTO_GPIO_PIN_SELECT_REG1) & ~NAND_GPIO) | NAND_BUS, COMCERTO_GPIO_PIN_SELECT_REG1);
+	c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= NAND_GPIO_PIN;
+#endif
+
+#if defined(CONFIG_MTD_COMCERTO_NOR)
+	writel((readl(COMCERTO_GPIO_PIN_SELECT_REG1) & ~NOR_GPIO) | NOR_BUS, COMCERTO_GPIO_PIN_SELECT_REG1);
+	c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= NOR_GPIO_PIN;
+#endif
+}
+
+/* --------------------------------------------------------------------
+ *  NOR device
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_MTD_COMCERTO_NOR)
+
+static struct resource comcerto_nor_resources[] = {
+	{
+		.start	= NORFLASH_MEMORY_PHY1,
+		.end	= NORFLASH_MEMORY_PHY1 + SZ_64M - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct flash_platform_data comcerto_nor_data = {
+	.map_name	= "cfi_probe",
+	.width	= 2,
+};
+
+static struct platform_device comcerto_nor = {
+	.name           = "comcertoflash",
+	.id             = 0,
+	.num_resources  = ARRAY_SIZE(comcerto_nor_resources),
+	.resource       = comcerto_nor_resources,
+	.dev = {
+		.platform_data	= &comcerto_nor_data,
+	},
+};
+#endif
+
+static struct resource rtc_res[] = {
+       {
+               .start = COMCERTO_APB_RTC_BASE,
+               .end = COMCERTO_APB_RTC_BASE + SZ_32 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_RTC_ALM,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_RTC_PRI,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+static struct platform_device rtc_dev = {
+       .name = "c2k-rtc",
+       .id = -1,
+       .num_resources = ARRAY_SIZE(rtc_res),
+       .resource = rtc_res,
+};
+
+/* --------------------------------------------------------------------
+ *  DMAC controller
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_COMCERTO_DW_DMA_SUPPORT)
+static struct resource dw_dmac_resource[] = {
+	{
+		.start          = DW_DMA_DMAC_BASEADDR,
+		.end            = DW_DMA_DMAC_BASEADDR + 0x2C0,
+		.flags          = IORESOURCE_MEM,
+	},
+	{
+		.start          = IRQ_DMAC,
+		.flags          = IORESOURCE_IRQ,
+	}
+};
+
+static struct dw_dma_platform_data dw_dmac_data = {
+	.nr_channels    = 8,
+};
+
+static u64 dw_dmac_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device dw_dmac_device = {
+	.name           = "dw_dmac",
+	.id             = 0,
+	.dev            = {
+		.dma_mask = &dw_dmac_dma_mask,
+		.platform_data  = &dw_dmac_data,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+	.resource       = dw_dmac_resource,
+	.num_resources  = ARRAY_SIZE(dw_dmac_resource),
+};
+#endif
+
+/* --------------------------------------------------------------------
+ *  NAND device
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_MTD_NAND_COMCERTO) || defined(CONFIG_MTD_NAND_COMCERTO_MODULE)
+static struct resource comcerto_nand_resources[] = {
+	{
+		.start	= COMCERTO_NAND_FIO_ADDR,
+		.end	= COMCERTO_NAND_FIO_ADDR + COMCERTO_NAND_IO_SZ - 1,
+		.flags	= IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device comcerto_nand = {
+	.name		= "comcertonand",
+	.id		= -1,
+	.dev		= {
+				.platform_data	= NULL,
+	},
+	.resource	= comcerto_nand_resources,
+	.num_resources	= ARRAY_SIZE(comcerto_nand_resources),
+};
+#endif
+
+/* --------------------------------------------------------------------
+ *  SPI bus controller
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+
+#define	CLK_NAME	10
+struct spi_controller_pdata {
+	int use_dma;
+	int num_chipselects;
+	int bus_num;
+	u32 max_freq;
+	char clk_name[CLK_NAME];
+};
+
+struct spi_platform_data {
+	int type;
+	int dummy;
+};
+
+struct spi_controller_data {
+        u8 poll_mode;   /* 0 for contoller polling mode */
+        u8 type;        /* SPI/SSP/Micrwire */
+        u8 enable_dma;
+        void (*cs_control)(u32 command);
+};
+
+struct spi_platform_data spi_pdata = {
+	.type = 0,
+	.dummy = 0,
+};
+
+struct spi_controller_data spi_ctrl_data =  {
+        .poll_mode = 1,
+};
+
+static struct spi_board_info comcerto_spi_board_info[] = {
+	{
+		/* FIXME: for chipselect-0 */
+		.modalias = "s25fl256s0",
+		.chip_select = 0,
+		.max_speed_hz = 4*1000*1000,
+		.bus_num = 0,
+		.irq = -1,
+		.mode = SPI_MODE_3,
+		.platform_data = &spi_pdata,
+                .controller_data = &spi_ctrl_data,
+	},
+	{
+		/* FIXME: for chipselect-1 */
+		.modalias = "proslic",
+		.max_speed_hz = 4*1000*1000,
+		.chip_select = 1,
+		.mode = SPI_MODE_3,
+		.bus_num = 0,
+		.irq = -1,
+		.mode = SPI_MODE_3,
+		.platform_data = &spi_pdata,
+                .controller_data = &spi_ctrl_data,
+	},
+	{
+		.modalias = "comcerto_spi3",
+		.chip_select = 2,
+		.max_speed_hz = 4*1000*1000,
+		.bus_num = 0,
+		.irq = -1,
+		.mode = SPI_MODE_3,
+		.platform_data = &spi_pdata,
+                .controller_data = &spi_ctrl_data,
+	},
+
+#if 0 //MSIF
+
+	{
+		.modalias = "proslic",
+		.max_speed_hz = 2*1000*1000,
+		.chip_select = 3,
+		.mode = SPI_MODE_1,
+		.bus_num = 0,
+		.irq = -1,
+		.mode = SPI_MODE_3,
+		.platform_data = &spi_pdata,
+                .controller_data = &spi_ctrl_data,
+	},
+#else
+	{
+		.modalias = "legerity",
+		.chip_select = 3,
+		.max_speed_hz = 4*1000*1000,
+		.bus_num = 0,
+		.irq = -1,
+		.mode = SPI_MODE_3,
+		.platform_data = &spi_pdata,
+                .controller_data = &spi_ctrl_data,
+	},
+#endif
+};
+#endif
+
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+struct spi_controller_pdata fast_spi_pdata = {
+	.use_dma = 0,
+	.num_chipselects = 2,
+	.bus_num = 1,
+	.max_freq = 60 * 1000 * 1000,
+	.clk_name = "DUS",
+};
+#endif
+
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED) || defined(CONFIG_SPI2_MSPD_HIGH_SPEED)
+static struct resource comcerto_fast_spi_resource[] = {
+	{
+		.start  = COMCERTO_AXI_SPI_BASE,
+		.end    = COMCERTO_AXI_SPI_BASE + SZ_4K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = IRQ_SPI,
+		.flags  = IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device comcerto_fast_spi = {
+	.name = "comcerto_spi",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(comcerto_fast_spi_resource),
+	.resource = comcerto_fast_spi_resource,
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+	.dev = {
+		.platform_data = &fast_spi_pdata,
+	},
+#endif
+};
+#endif
+
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED)
+struct spi_controller_pdata ls_spi_pdata = {
+	.use_dma = 0,
+	.num_chipselects = 4,
+	.bus_num = 0,
+	.max_freq = 20 * 1000 * 1000,
+	.clk_name = "spi_i2c",
+};
+#endif
+
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI2_MSPD_LOW_SPEED)
+static struct resource comcerto_spi_resource[] = {
+	{
+		.start  = COMCERTO_APB_SPI_BASE,
+		.end    = COMCERTO_APB_SPI_BASE + SZ_4K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = IRQ_SPI_LS,
+		.flags  = IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device comcerto_spi = {
+	.name = "comcerto_spi",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(comcerto_spi_resource),
+	.resource = comcerto_spi_resource,
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED)
+	.dev = {
+		.platform_data = &ls_spi_pdata,
+	},
+#endif
+};
+#endif
+
+/* --------------------------------------------------------------------
+ *  I2C bus controller
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_COMCERTO_I2C_SUPPORT)
+static struct resource comcerto_i2c_resources[] = {
+	{
+		.start	= COMCERTO_APB_I2C_BASE,
+		.end	= COMCERTO_APB_I2C_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IRQ_I2C,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device comcerto_i2c = {
+	.name           = "comcerto_i2c",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(comcerto_i2c_resources),
+	.resource       = comcerto_i2c_resources,
+};
+#endif
+
+/* --------------------------------------------------------------------
+*  Watchdog
+* -------------------------------------------------------------------- */
+#ifdef CONFIG_MPCORE_WATCHDOG
+static struct resource comcerto_a9wd_resources[] = {
+	{
+		.start	= COMCERTO_TWD_BASE,
+		.end	= COMCERTO_TWD_BASE + 0xFF,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "mpcore_wdt",
+		.start	= IRQ_LOCALWDOG,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device comcerto_a9wd = {
+	.name		= "mpcore_wdt",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(comcerto_a9wd_resources),
+	.resource       = comcerto_a9wd_resources,
+};
+#endif
+
+#ifdef CONFIG_COMCERTO_WATCHDOG
+static struct resource comcerto_wdt_resources[] = {
+	{
+		.start	= COMCERTO_APB_TIMER_BASE + 0xD0,
+		.end	= COMCERTO_APB_TIMER_BASE + 0xD8,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device comcerto_wdt = {
+        .name   = "comcerto_wdt",
+        .id     = -1,
+	.num_resources  = ARRAY_SIZE(comcerto_wdt_resources),
+	.resource       = comcerto_wdt_resources,
+};
+#endif
+
+#if defined(CONFIG_COMCERTO_ELP_SUPPORT)
+/* --------------------------------------------------------------------
+ *  IPsec
+ * -------------------------------------------------------------------- */
+static struct resource comcerto_elp_resources[] = {
+	{
+		.name   = "elp",
+		.start  = COMCERTO_AXI_SPACC_PDU_BASE,
+		.end    = COMCERTO_AXI_SPACC_PDU_BASE + SZ_16M  - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "irq_spacc",
+		.start  = IRQ_SPACC,
+		.end    = IRQ_SPACC,
+		.flags  = IORESOURCE_IRQ,
+	}
+};
+
+static u64 comcerto_elp_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device  comcerto_elp_device = {
+	.name                   = "Elliptic-EPN1802",
+	.id                     = 0,
+	.num_resources          = 2,
+	.resource               = comcerto_elp_resources,
+	.dev = {
+		.dma_mask               = &comcerto_elp_dma_mask,
+		.coherent_dma_mask      = DMA_BIT_MASK(32),
+	},
+};
+#endif
+
+static struct comcerto_tdm_data comcerto_tdm_pdata = {
+	.fsoutput = 1, /* Generic Pad Control and Version ID Register[2] */
+	.fspolarity = 0, /* 28 FSYNC_FALL(RISE)_EDGE */
+	.fshwidth = 1, /* High_Phase_Width[10:0] */
+	.fslwidth = 0xFF, /* Low_Phase_Width[10:0] */
+	.clockhz = 2048000, /* INC_VALUE[29:0] According to the desired TDM clock output \
+			       frequency, this field should be configured */
+	.clockout = 1, /* 0 -> set bit 21, clear bit 20 in COMCERTO_GPIO_IOCTRL_REG
+			  (software control, clock input)
+			  1 -> set bit 21 and 20 in COMCERTO_GPIO_IOCTRL_REG
+			  (software control, clock output)
+			  2 -> clear bit 21 in COMCERTO_GPIO_IOCTRL_REG (hardware control) */
+	.tdmmux = 0x1, /* TDM interface Muxing:0x0 - TDM block, 0x1 - ZDS block,
+		0x2 - GPIO[63:60] signals and 0x3 - MSIF block is selected */
+#if 0
+	/* FIX ME - Need correct values for TDM_DR, TDM_DX, TDM_FS and TDM_CK */
+	.tdmck = 0x3F,
+	.tdmfs = 0x3F,
+	.tdmdx = 0x3F,
+	.tdmdr = 0x3F,
+#endif
+};
+
+static struct platform_device comcerto_tdm_device = {
+	.name	= "comcerto-tdm",
+	.id		= 0,
+	.dev.platform_data = &comcerto_tdm_pdata,
+	.num_resources	= 0,
+	.resource = NULL,
+};
+
+#if defined(CONFIG_DSPG_DECT_CSS)
+#define CSS_ITCM_BASE		COMCERTO_AXI_DECT_BASE
+#define CSS_ITCM_SIZE		(SZ_1M)
+
+#define CSS_DTCM_BASE		(CSS_ITCM_BASE + CSS_ITCM_SIZE)
+#define CSS_DTCM_SIZE		(SZ_1M)
+
+static struct resource comcerto_css_resources[] = {
+	{
+		.name	= "itcm",
+		.start	= CSS_ITCM_BASE,
+		.end	= CSS_ITCM_BASE + CSS_ITCM_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "dtcm",
+		.start	= CSS_DTCM_BASE,
+		.end	= CSS_DTCM_BASE + CSS_DTCM_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device comcerto_css_device = {
+	.name		= "css",
+	.id		= 0,
+	.dev		= {
+		.platform_data = 0,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+	.num_resources	= ARRAY_SIZE(comcerto_css_resources),
+	.resource	= comcerto_css_resources,
+};
+#endif
+
+static struct resource comcerto_pfe_resources[] = {
+	{
+		.name	= "apb",
+		.start  = COMCERTO_APB_PFE_BASE,
+		.end    = COMCERTO_APB_PFE_BASE + COMCERTO_APB_PFE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name	= "axi",
+		.start  = COMCERTO_AXI_PFE_BASE,
+		.end    = COMCERTO_AXI_PFE_BASE + COMCERTO_AXI_PFE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name	= "ddr",
+		.start  = COMCERTO_PFE_DDR_BASE,
+		.end	= COMCERTO_PFE_DDR_BASE + COMCERTO_PFE_DDR_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name	= "iram",
+		.start  = COMCERTO_PFE_IRAM_BASE,
+		.end	= COMCERTO_PFE_IRAM_BASE + COMCERTO_PFE_IRAM_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+        {
+                .name   = "ipsec",
+                .start  = COMCERTO_AXI_IPSEC_BASE,
+                .end    = COMCERTO_AXI_IPSEC_BASE + COMCERTO_AXI_IPSEC_SIZE - 1,
+                .flags  = IORESOURCE_MEM,
+        },
+
+	{
+		.name	= "hif",
+		.start  = IRQ_PFE_HIF,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct comcerto_pfe_platform_data comcerto_pfe_pdata = {
+	.comcerto_eth_pdata[0] = {
+		.name = GEM0_ITF_NAME,
+		.device_flags = CONFIG_COMCERTO_GEMAC,
+		.mii_config = CONFIG_COMCERTO_USE_RGMII,
+		.gemac_mode = GEMAC_SW_CONF | GEMAC_SW_FULL_DUPLEX | GEMAC_SW_SPEED_1G,
+		.phy_flags = GEMAC_PHY_RGMII_ADD_DELAY,
+		.bus_id = 0,
+		.phy_id = 4,
+		.gem_id = 0,
+		.mac_addr = (u8[])GEM0_MAC,
+	},
+
+	.comcerto_eth_pdata[1] = {
+		.name = GEM1_ITF_NAME,
+		.device_flags = CONFIG_COMCERTO_GEMAC,
+		.mii_config = CONFIG_COMCERTO_USE_RGMII,
+		.gemac_mode = GEMAC_SW_CONF | GEMAC_SW_FULL_DUPLEX | GEMAC_SW_SPEED_1G,
+		.phy_flags = GEMAC_NO_PHY,
+		.gem_id = 1,
+		.mac_addr = (u8[])GEM1_MAC,
+	},
+
+	.comcerto_eth_pdata[2] = {
+		.name = GEM2_ITF_NAME,
+		.device_flags = CONFIG_COMCERTO_GEMAC,
+		.mii_config = CONFIG_COMCERTO_USE_RGMII,
+		.gemac_mode = GEMAC_SW_CONF | GEMAC_SW_FULL_DUPLEX | GEMAC_SW_SPEED_1G,
+		.phy_flags = GEMAC_NO_PHY,
+		.gem_id = 2,
+		.mac_addr = (u8[])GEM2_MAC,
+	},
+
+	/**
+	 * There is a single mdio bus coming out of C2K.  And that's the one
+	 * connected to GEM0. All PHY's, switchs will be connected to the same
+	 * bus using different addresses. Typically .bus_id is always 0, only
+	 * .phy_id will change in the different comcerto_eth_pdata[] structures above.
+	 */
+	.comcerto_mdio_pdata[0] = {
+		.enabled = 1,
+		.phy_mask = 0xFFFFFFEF,
+		.mdc_div = 96,
+		.irq = {
+			[4] = PHY_POLL,
+		},
+	},
+};
+
+static u64 comcerto_pfe_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device comcerto_pfe_device = {
+	.name		= "pfe",
+	.id		= 0,
+	.dev		= {
+		.platform_data		= &comcerto_pfe_pdata,
+		.dma_mask		= &comcerto_pfe_dma_mask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.num_resources	= ARRAY_SIZE(comcerto_pfe_resources),
+	.resource	= comcerto_pfe_resources,
+};
+
+static struct platform_device *comcerto_devices[] __initdata = {
+#if defined(CONFIG_MTD_NAND_COMCERTO) || defined(CONFIG_MTD_NAND_COMCERTO_MODULE)
+		&comcerto_nand,
+#endif
+#if defined(CONFIG_MTD_COMCERTO_NOR)
+		&comcerto_nor,
+#endif
+#if defined(CONFIG_COMCERTO_I2C_SUPPORT)
+		&comcerto_i2c,
+#endif
+
+#if defined (CONFIG_MPCORE_WATCHDOG)
+		&comcerto_a9wd,
+#endif
+
+#if defined(CONFIG_COMCERTO_WATCHDOG)
+		&comcerto_wdt,
+#endif
+
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED) || defined(CONFIG_SPI2_MSPD_HIGH_SPEED)
+		&comcerto_fast_spi,
+#endif
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI2_MSPD_LOW_SPEED)
+		&comcerto_spi,
+#endif
+#if defined(CONFIG_COMCERTO_DW_DMA_SUPPORT)
+		&dw_dmac_device,
+#endif
+		&comcerto_tdm_device,
+		&comcerto_pfe_device,
+		&rtc_dev,
+#if defined(CONFIG_DSPG_DECT_CSS)
+		&comcerto_css_device,
+#endif
+#if defined(CONFIG_COMCERTO_ELP_SUPPORT)
+	&comcerto_elp_device,
+#endif
+};
+
+
+/************************************************************************
+ *  Expansion bus
+ *
+ ************************************************************************/
+/* This variable is used by comcerto-2000.c to initialize the expansion bus */
+int comcerto_exp_values[5][7]= {
+	/* ENABLE, BASE, SEG_SZ, CFG, TMG1, TMG2, TMG3 */
+	{1, (EXP_BUS_REG_BASE_CS0 >> 12), ((EXP_BUS_REG_BASE_CS0 + EXP_CS0_SEG_SIZE - 1) >> 12), EXP_MEM_BUS_SIZE_16, 0x03034007, 0x04040502, 0x00000002},		/*TODO Values to check*/
+	{0, (EXP_BUS_REG_BASE_CS1 >> 12), ((EXP_BUS_REG_BASE_CS1 + EXP_CS1_SEG_SIZE - 1) >> 12), EXP_RDY_EN|EXP_MEM_BUS_SIZE_32, 0x1A1A401F, 0x06060A04, 0x00000002},	/*TODO Values to check*/
+	{0, (EXP_BUS_REG_BASE_CS2 >> 12), ((EXP_BUS_REG_BASE_CS2 + EXP_CS2_SEG_SIZE - 1) >> 12), EXP_STRB_MODE|EXP_ALE_MODE|EXP_MEM_BUS_SIZE_8, 0x1A10201A, 0x03080403, 0x0000002},	/*TODO Values to check*/
+	{0, (EXP_BUS_REG_BASE_CS3 >> 12), ((EXP_BUS_REG_BASE_CS3 + EXP_CS3_SEG_SIZE - 1) >> 12), EXP_STRB_MODE|EXP_ALE_MODE|EXP_MEM_BUS_SIZE_8, 0x1A10201A, 0x03080403, 0x0000002},	/*BT8370*/
+	{1, (EXP_BUS_REG_BASE_CS4 >> 12), ((EXP_BUS_REG_BASE_CS4 + EXP_CS4_SEG_SIZE - 1) >> 12), EXP_NAND_MODE|EXP_MEM_BUS_SIZE_8, 0x00000001, 0x01010001, 0x00000002},	/* NAND: TODO Values to check */
+};
+
+/************************************************************************
+ *  Machine definition
+ *
+ ************************************************************************/
+static void __init platform_map_io(void)
+{
+	device_map_io();
+}
+
+static void __init platform_irq_init(void)
+{
+	device_irq_init();
+}
+
+static void __init platform_init(void)
+{
+	device_init();
+	board_gpio_init();
+
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+	spi_register_board_info(comcerto_spi_board_info, ARRAY_SIZE(comcerto_spi_board_info));
+#endif
+	mac_addr_init(&comcerto_pfe_pdata);
+
+	platform_add_devices(comcerto_devices, ARRAY_SIZE(comcerto_devices));
+}
+
+MACHINE_START(COMCERTO, "Comcerto 2000 MFCN EVM")
+	/* Mindspeed Technologies Inc. */
+	.atag_offset    = COMCERTO_AXI_DDR_BASE + 0x100,
+	.reserve	= platform_reserve,
+	.map_io		= platform_map_io,
+	.init_irq	= platform_irq_init,
+	.init_machine	= platform_init,
+	.timer		= &comcerto_timer,
+#ifdef CONFIG_ZONE_DMA
+	.dma_zone_size	= SZ_32M + 3*SZ_4M,
+#endif
+MACHINE_END
diff --git a/arch/arm/mach-comcerto/board-c2krtsm.c b/arch/arm/mach-comcerto/board-c2krtsm.c
new file mode 100644
index 0000000..8fad46a
--- /dev/null
+++ b/arch/arm/mach-comcerto/board-c2krtsm.c
@@ -0,0 +1,516 @@
+/*
+ * arch/arm/mach-comcerto/board-c2krtsm.c
+ *
+ *  Copyright (C) 2012 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/sched.h>
+#include <linux/device.h>
+#include <linux/serial_8250.h>
+#include <linux/phy.h>
+
+#include <linux/mtd/mtd.h>
+#if defined(CONFIG_MTD_NAND_COMCERTO) || defined(CONFIG_MTD_NAND_COMCERTO_MODULE)
+#include <linux/mtd/nand.h>
+#endif
+#include <linux/mtd/partitions.h>
+
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+#include <linux/spi/spi.h>
+#endif
+
+#include <asm/sizes.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/io.h>
+
+#include <asm/mach/flash.h>
+#include <asm/mach/arch.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/dma.h>
+#include <linux/dw_dmac.h>
+
+#include <linux/clockchips.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <asm/smp_twd.h>
+#include <asm/localtimer.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/time.h>
+
+
+
+extern void platform_reserve(void);
+extern void device_map_io (void);
+extern void device_irq_init(void);
+extern void device_init(void);
+extern struct sys_timer comcerto_timer;
+
+static void __init board_gpio_init(void)
+{
+#ifdef CONFIG_COMCERTO_PFE_UART_SUPPORT
+	writel((readl(COMCERTO_GPIO_PIN_SELECT_REG) & ~PFE_UART_GPIO) | PFE_UART_BUS, COMCERTO_GPIO_PIN_SELECT_REG);
+#endif
+
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI2_MSPD_LOW_SPEED)
+	/* enable SPI pins */
+	writel((readl(COMCERTO_GPIO_PIN_SELECT_REG1) & ~(SPI_MUX_GPIO_1)) | (SPI_MUX_BUS_1), COMCERTO_GPIO_PIN_SELECT_REG1);
+	writel((readl(COMCERTO_GPIO_63_32_PIN_SELECT) & ~(SPI_MUX_GPIO_2)) | (SPI_MUX_BUS_2), COMCERTO_GPIO_63_32_PIN_SELECT);
+#endif
+
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+	/* enable SPI pins */
+	writel((readl(COMCERTO_GPIO_PIN_SELECT_REG1) & ~(SPI_2_MUX_GPIO_1)) | (SPI_2_MUX_BUS_1), COMCERTO_GPIO_PIN_SELECT_REG1);
+	writel((readl(COMCERTO_GPIO_63_32_PIN_SELECT) & ~(SPI_2_MUX_GPIO_2)) | (SPI_2_MUX_BUS_2), COMCERTO_GPIO_63_32_PIN_SELECT);
+#endif
+
+#if defined(CONFIG_COMCERTO_I2C_SUPPORT)
+	writel((readl(COMCERTO_GPIO_PIN_SELECT_REG1) & ~I2C_GPIO) | I2C_BUS, COMCERTO_GPIO_PIN_SELECT_REG1);
+#endif
+
+#if defined(CONFIG_MTD_NAND_COMCERTO) || defined(CONFIG_MTD_NAND_COMCERTO_MODULE)
+	writel((readl(COMCERTO_GPIO_PIN_SELECT_REG1) & ~NAND_GPIO) | NAND_BUS, COMCERTO_GPIO_PIN_SELECT_REG1);
+#endif
+
+#if defined(CONFIG_MTD_COMCERTO_NOR)
+	writel((readl(COMCERTO_GPIO_PIN_SELECT_REG1) & ~NOR_GPIO) | NOR_BUS, COMCERTO_GPIO_PIN_SELECT_REG1);
+#endif
+}
+
+
+
+/* --------------------------------------------------------------------
+ *  NOR device
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_MTD_COMCERTO_NOR)
+
+static struct resource comcerto_nor_resources[] = {
+	{
+		.start	= NORFLASH_MEMORY_PHY1,
+		.end	= NORFLASH_MEMORY_PHY1 + SZ_64M - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct flash_platform_data comcerto_nor_data = {
+	.map_name	= "cfi_probe",
+	.width	= 2,
+};
+
+static struct platform_device comcerto_nor = {
+	.name           = "comcertoflash",
+	.id             = 0,
+	.num_resources  = ARRAY_SIZE(comcerto_nor_resources),
+	.resource       = comcerto_nor_resources,
+	.dev = {
+		.platform_data	= &comcerto_nor_data,
+	},
+};
+#endif
+
+/* --------------------------------------------------------------------
+ *  DMAC controller
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_COMCERTO_DW_DMA_SUPPORT)
+static struct resource dw_dmac_resource[] = {
+	{
+		.start          = DW_DMA_DMAC_BASEADDR,
+		.end            = DW_DMA_DMAC_BASEADDR + 0x2C0,
+		.flags          = IORESOURCE_MEM,
+	},
+	{
+		.start          = IRQ_DMAC,
+		.flags          = IORESOURCE_IRQ,
+	}
+};
+
+static struct dw_dma_platform_data dw_dmac_data = {
+	.nr_channels    = 8,
+};
+
+static u64 dw_dmac_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device dw_dmac_device = {
+	.name           = "dw_dmac",
+	.id             = 0,
+	.dev            = {
+		.dma_mask = &dw_dmac_dma_mask,
+		.platform_data  = &dw_dmac_data,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+	.resource       = dw_dmac_resource,
+	.num_resources  = ARRAY_SIZE(dw_dmac_resource),
+};
+#endif
+
+/* --------------------------------------------------------------------
+ *  SPI bus controller [FIXME]
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+struct spi_controller_pdata {
+	int use_dma;
+	int num_chipselects;
+	int bus_num;
+	u32 max_freq;
+};
+
+struct spi_platform_data {
+	int type;
+	int dummy;
+};
+
+struct spi_platform_data spi_pdata = {
+	.type = 0,
+	.dummy = 0,
+};
+
+static struct spi_board_info comcerto_spi_board_info[] = {
+	{
+		/* FIXME: for chipselect-0 */
+		.modalias = "comcerto_spi1",
+		.chip_select = 0,
+		.max_speed_hz = 4*1000*1000,
+		.bus_num = 0,
+		.irq = -1,
+		.mode = SPI_MODE_3,
+		.platform_data = &spi_pdata,
+	},
+
+	{
+		/* FIXME: for chipselect-1 */
+		.modalias = "comcerto_spi2",
+		.chip_select = 1,
+		.max_speed_hz = 4*1000*1000,
+		.bus_num = 0,
+		.irq = -1,
+		.mode = SPI_MODE_3,
+		.platform_data = &spi_pdata,
+	},
+
+	{
+		.modalias = "comcerto_spi3",
+		.chip_select = 2,
+		.max_speed_hz = 4*1000*1000,
+		.bus_num = 0,
+		.irq = -1,
+		.mode = SPI_MODE_3,
+		.platform_data = &spi_pdata,
+	},
+
+	{
+		.modalias = "legerity",
+		.chip_select = 3,
+		.max_speed_hz = 4*1000*1000,
+		.bus_num = 0,
+		.irq = -1,
+		.mode = SPI_MODE_3,
+		.platform_data = &spi_pdata,
+	},
+
+};
+#endif
+
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+struct spi_controller_pdata fast_spi_pdata = {
+	.use_dma = 1,
+	.num_chipselects = 2,
+	.bus_num = 1,
+	.max_freq = 60 * 1000 * 1000,
+};
+
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED) || defined(CONFIG_SPI2_MSPD_HIGH_SPEED)
+static struct resource comcerto_fast_spi_resource[] = {
+	{
+		.start  = COMCERTO_AXI_SPI_BASE,
+		.end    = COMCERTO_AXI_SPI_BASE + SZ_4K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = IRQ_SPI,
+		.flags  = IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device comcerto_fast_spi = {
+	.name = "comcerto_spi",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(comcerto_fast_spi_resource),
+	.resource = comcerto_fast_spi_resource,
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+	.dev = {
+		.platform_data = &fast_spi_pdata,
+	},
+#endif
+};
+#endif
+
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED)
+struct spi_controller_pdata ls_spi_pdata = {
+	.use_dma = 0,
+	.num_chipselects = 4,
+	.bus_num = 0,
+	.max_freq = 20 * 1000 * 1000,
+};
+#endif
+
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI2_MSPD_LOW_SPEED)
+static struct resource comcerto_spi_resource[] = {
+	{
+		.start  = COMCERTO_APB_SPI_BASE,
+		.end    = COMCERTO_APB_SPI_BASE + SZ_4K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = IRQ_SPI_LS,
+		.flags  = IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device comcerto_spi = {
+	.name = "comcerto_spi",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(comcerto_spi_resource),
+	.resource = comcerto_spi_resource,
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED)
+	.dev = {
+		.platform_data = &ls_spi_pdata,
+	},
+#endif
+};
+#endif
+
+/* --------------------------------------------------------------------
+ *  I2C bus controller
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_COMCERTO_I2C_SUPPORT)
+static struct resource comcerto_i2c_resources[] = {
+	{
+		.start	= COMCERTO_APB_I2C_BASE,
+		.end	= COMCERTO_APB_I2C_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IRQ_I2C,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device comcerto_i2c = {
+	.name           = "comcerto_i2c",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(comcerto_i2c_resources),
+	.resource       = comcerto_i2c_resources,
+};
+#endif
+
+
+static struct comcerto_tdm_data comcerto_tdm_pdata = {
+	.fsoutput = 1, /* Generic Pad Control and Version ID Register[2] */
+	.fspolarity = 0, /* 28 FSYNC_FALL(RISE)_EDGE */
+	.fshwidth = 1, /* High_Phase_Width[10:0] */
+	.fslwidth = 0xFF, /* Low_Phase_Width[10:0] */
+	.clockhz = 2048000, /* INC_VALUE[29:0] According to the desired TDM clock output frequency, this field should be configured */
+	.clockout = 1, /* 0 -> set bit 21, clear bit 20 in COMCERTO_GPIO_IOCTRL_REG
+			  (software control, clock input)
+			  1 -> set bit 21 and 20 in COMCERTO_GPIO_IOCTRL_REG
+			  (software control, clock output)
+			  2 -> clear bit 21 in COMCERTO_GPIO_IOCTRL_REG (hardware control) */
+	.tdmmux = 0x1, /* TDM interface Muxing:0x0 - TDM block, 0x1 - ZDS block,

+		0x2 - GPIO[63:60] signals and 0x3 - MSIF block is selected */
+#if 0
+/* FIX ME - Need correct values for TDM_DR, TDM_DX, TDM_FS and TDM_CK */
+	.tdmck = 0x3F,
+	.tdmfs = 0x3F,
+	.tdmdx = 0x3F,
+	.tdmdr = 0x3F,
+#endif
+};
+
+static struct platform_device comcerto_tdm_device = {
+	.name	= "comcerto-tdm",
+	.id		= 0,
+	.dev.platform_data = &comcerto_tdm_pdata,
+	.num_resources	= 0,
+	.resource = NULL,
+};
+
+static struct resource comcerto_pfe_resources[] = {
+	{
+		.name	= "apb",
+		.start  = COMCERTO_APB_PFE_BASE,
+		.end    = COMCERTO_APB_PFE_BASE + COMCERTO_APB_PFE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name	= "axi",
+		.start  = COMCERTO_AXI_PFE_BASE,
+		.end    = COMCERTO_AXI_PFE_BASE + COMCERTO_AXI_PFE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name	= "ddr",
+		.start  = COMCERTO_PFE_DDR_BASE,
+		.end	= COMCERTO_PFE_DDR_BASE + COMCERTO_PFE_DDR_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name	= "iram",
+		.start  = COMCERTO_PFE_IRAM_BASE,
+		.end	= COMCERTO_PFE_IRAM_BASE + COMCERTO_PFE_IRAM_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name	= "hif",
+		.start  = IRQ_PFE_HIF,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct comcerto_pfe_platform_data comcerto_pfe_pdata = {
+	.comcerto_eth_pdata[0] = {
+		.name = GEM0_ITF_NAME,
+		.device_flags = CONFIG_COMCERTO_GEMAC,
+		.mii_config = CONFIG_COMCERTO_USE_RGMII,
+		.gemac_mode = GEMAC_SW_CONF | GEMAC_SW_FULL_DUPLEX | GEMAC_SW_SPEED_1G,
+		.phy_flags = GEMAC_PHY_RGMII_ADD_DELAY,
+		.bus_id = 0,
+		.phy_id = 0,
+		.gem_id = 0,
+		.mac_addr = (u8[])GEM0_MAC,
+	},
+
+	.comcerto_eth_pdata[1] = {
+		.name = GEM1_ITF_NAME,
+		.device_flags = CONFIG_COMCERTO_GEMAC,
+		.mii_config = CONFIG_COMCERTO_USE_RGMII,
+		.gemac_mode = GEMAC_SW_CONF | GEMAC_SW_FULL_DUPLEX | GEMAC_SW_SPEED_1G,
+		.phy_flags = GEMAC_NO_PHY,
+		.gem_id = 1,
+		.mac_addr = (u8[])GEM1_MAC,
+	},
+
+	.comcerto_eth_pdata[2] = {
+		.name = GEM2_ITF_NAME,
+		.device_flags = CONFIG_COMCERTO_GEMAC,
+		.mii_config = CONFIG_COMCERTO_USE_RGMII,
+		.gemac_mode = GEMAC_SW_CONF | GEMAC_SW_FULL_DUPLEX | GEMAC_SW_SPEED_1G,
+		.phy_flags = GEMAC_NO_PHY,
+		.gem_id = 2,
+		.mac_addr = (u8[])GEM2_MAC,
+	},
+
+	/**
+	 * There is a single mdio bus coming out of C2K.  And that's the one
+	 * connected to GEM0. All PHY's, switchs will be connected to the same
+	 * bus using different addresses. Typically .bus_id is always 0, only
+	 * .phy_id will change in the different comcerto_eth_pdata[] structures above.
+	 */
+	.comcerto_mdio_pdata[0] = {
+		.enabled = 1,
+		.phy_mask = 0xFFFFFFFE,
+		.mdc_div = 96,
+		.irq = {
+			[0] = PHY_POLL,
+		},
+	},
+};
+
+static u64 comcerto_pfe_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device comcerto_pfe_device = {
+	.name		= "pfe",
+	.id		= 0,
+	.dev		= {
+		.platform_data		= &comcerto_pfe_pdata,
+		.dma_mask		= &comcerto_pfe_dma_mask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.num_resources	= ARRAY_SIZE(comcerto_pfe_resources),
+	.resource	= comcerto_pfe_resources,
+};
+
+static struct platform_device *comcerto_devices[] __initdata = {
+#if defined(CONFIG_MTD_COMCERTO_NOR)
+		&comcerto_nor,
+#endif
+#if defined(CONFIG_COMCERTO_I2C_SUPPORT)
+		&comcerto_i2c,
+#endif
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+		&comcerto_fast_spi,
+#endif
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI2_MSPD_LOW_SPEED)
+		&comcerto_spi,
+#endif
+#if defined(CONFIG_COMCERTO_DW_DMA_SUPPORT)
+		&dw_dmac_device,
+#endif
+		&comcerto_tdm_device,
+		&comcerto_pfe_device,
+	};
+
+
+/************************************************************************
+ *  Expansion bus
+ *
+ ************************************************************************/
+/* This variable is used by comcerto-1000.c to initialize the expansion bus */
+int comcerto_exp_values[5][7]= {
+	/* ENABLE, BASE, SEG_SZ, CFG, TMG1, TMG2, TMG3 */
+	{1, (EXP_BUS_REG_BASE_CS0 >> 12), ((EXP_BUS_REG_BASE_CS0 + EXP_CS0_SEG_SIZE - 1) >> 12), EXP_MEM_BUS_SIZE_16, 0x1A1A401F, 0x06060A04, 0x00000002},		/*TODO Values to check*/
+	{0, (EXP_BUS_REG_BASE_CS1 >> 12), ((EXP_BUS_REG_BASE_CS1 + EXP_CS1_SEG_SIZE - 1) >> 12), EXP_RDY_EN|EXP_MEM_BUS_SIZE_32, 0x1A1A401F, 0x06060A04, 0x00000002},	/*TODO Values to check*/
+	{0, (EXP_BUS_REG_BASE_CS2 >> 12), ((EXP_BUS_REG_BASE_CS2 + EXP_CS2_SEG_SIZE - 1) >> 12), EXP_STRB_MODE|EXP_ALE_MODE|EXP_MEM_BUS_SIZE_8, 0x1A10201A, 0x03080403, 0x0000002},	/*TODO Values to check*/
+	{0, (EXP_BUS_REG_BASE_CS3 >> 12), ((EXP_BUS_REG_BASE_CS3 + EXP_CS3_SEG_SIZE - 1) >> 12), EXP_STRB_MODE|EXP_ALE_MODE|EXP_MEM_BUS_SIZE_8, 0x1A10201A, 0x03080403, 0x0000002},	/*BT8370*/
+	{0, (EXP_BUS_REG_BASE_CS4 >> 12), ((EXP_BUS_REG_BASE_CS4 + EXP_CS4_SEG_SIZE - 1) >> 12), EXP_NAND_MODE|EXP_MEM_BUS_SIZE_8, 0x1A1A401F, 0x06060A04, 0x00000002},	/* NAND: TODO Values to check */
+};
+
+/************************************************************************
+ *  Machine definition
+ *
+ ************************************************************************/
+static void __init platform_map_io(void)
+{
+	device_map_io();
+}
+
+static void __init platform_irq_init(void)
+{
+	device_irq_init();
+}
+
+static void __init platform_init(void)
+{
+	device_init();
+	board_gpio_init();
+
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+	spi_register_board_info(comcerto_spi_board_info, ARRAY_SIZE(comcerto_spi_board_info));
+#endif
+	platform_add_devices(comcerto_devices, ARRAY_SIZE(comcerto_devices));
+}
+
+MACHINE_START(COMCERTO, "Comcerto 2000 RTSM")
+	/* Mindspeed Technologies Inc. */
+	.atag_offset    = COMCERTO_AXI_DDR_BASE + 0x100,
+	.reserve	= platform_reserve,
+	.map_io		= platform_map_io,
+	.init_irq	= platform_irq_init,
+	.init_machine	= platform_init,
+	.timer		= &comcerto_timer,
+MACHINE_END
diff --git a/arch/arm/mach-comcerto/clock.c b/arch/arm/mach-comcerto/clock.c
new file mode 100644
index 0000000..7ef79a9
--- /dev/null
+++ b/arch/arm/mach-comcerto/clock.c
@@ -0,0 +1,1023 @@
+/*
+ *  linux/arch/arm/mach-comcerto/clock.c
+ *
+ *  Copyright (C) 2008 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <asm/io.h>
+#include <mach/hardware.h>
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clkdev.h>
+#include <linux/printk.h>
+#include <linux/list.h>
+#include <mach/comcerto-2000/clock.h>
+
+static DEFINE_SPINLOCK(clock_lock);
+
+/* Forward declaration */
+static void HAL_set_clk_divider(unsigned long ,u32 , u32);
+static unsigned long HAL_get_clk_freq(u32, u32);
+
+/* API clk_put clk_get
+ * Declared in "include/linux/clk.h", include this
+ * in correspoding driver.
+ * Defined in drivers/clk/clkdev.c, will
+ * use the above.
+ */
+
+/* @ struct clk *
+ * API:local_clk_disable
+ * Call the device level disable.
+ * This will decrease the  usecount following to disabling
+ * the clock.
+*/
+static void local_clk_disable(struct clk *clk)
+{
+	u32 val;
+	if (clk->usecount == 0){
+		pr_warning("Warning : %s Clock is already disabled \n",clk->name);
+		return;
+	}
+
+	/* Decrement the usecount */
+	clk->usecount--;
+
+	if (!clk->usecount){
+		/* Take care of parent disable , if present for the clock.
+		 * Disable the parent , if no other clock is using.
+		*/
+		if (clk->parent)
+			local_clk_disable(clk->parent);
+
+		/* Apply the Clock register write here */
+		if (clk->enable_reg){
+			val = readl(clk->enable_reg);
+			val &= ~clk->enable_mask;
+			writel(val , clk->enable_reg);
+		}
+	}
+}
+
+/* @ struct clk *
+ * API:clk_disable used to disable clock for
+ * the devices.
+ * This API will be available to outside
+ * ( for all device driver).
+ * Call of this API should be followed by clk_get
+ * clk_disable->clk_put.
+*/
+
+void clk_disable(struct clk *clk)
+{
+        unsigned long flags;
+
+        spin_lock_irqsave(&clock_lock, flags);
+        local_clk_disable(clk);
+        spin_unlock_irqrestore(&clock_lock, flags);
+}
+
+EXPORT_SYMBOL(clk_disable);
+
+/* @ struct clk *
+ * API : Internal call for clk_disable_unused for 
+ * unused devices.
+*/
+static void __clk_disable_unused(struct clk *clk)
+{
+	unsigned long flags;
+	u32 val;
+
+        spin_lock_irqsave(&clock_lock, flags);
+	/* Apply the Clock register write here */
+	if (clk->enable_reg){
+		val = readl(clk->enable_reg);
+		val &= ~clk->enable_mask;
+                writel(val , clk->enable_reg);
+	}
+        spin_unlock_irqrestore(&clock_lock, flags);
+}
+
+/* @ struct clk *
+ * API:local_clk_enable
+ * Call the device level enable.
+ * This will increase the  usecount.
+*/
+static int local_clk_enable(struct clk *clk)
+{
+	int ret = 0;
+	u32 val;
+
+	if (clk->usecount == 0) {
+		/* Check for parent clock .Enable the parent clock,if available*/
+		if (clk->parent){
+			ret = local_clk_enable(clk->parent);
+			if (ret)
+				return -EINVAL;
+		}
+		if (clk->enable_reg){
+			val = readl(clk->enable_reg);
+                	val |= clk->enable_mask;
+                	writel(val , clk->enable_reg);
+			ret=0;
+		}
+	}
+	/* Increment the use count */
+	clk->usecount++;
+        return ret;
+}
+
+/* @ struct clk *
+ * API:clk_enable used to enable clock for
+ * the devices.
+ * This API will be available to outside
+ * ( for all device driver).
+ * Call of this API should be followed by clk_get
+ * clk_get -> clk_enable.
+*/
+int clk_enable(struct clk *clk)
+{
+	unsigned long flags;
+	int ret=0;
+
+	if (!clk)
+		return -EINVAL;
+
+	spin_lock_irqsave(&clock_lock, flags);
+	ret = local_clk_enable(clk);
+	spin_unlock_irqrestore(&clock_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_enable);
+
+
+/* @ struct clk *
+ * API:clk_get_rate used to get clock rate value
+ * for the devices. This API will be available to
+ * outside ( for all device driver).
+*/
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk->get_rate)
+		return clk->get_rate(clk);
+	else
+		return clk->rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+/* @ struct clk * , unsigned long
+ * API:local_set_rate used to set clock rate value
+ * for the devices.
+*/
+
+static int local_set_rate(struct clk *clk, unsigned long rate)
+{
+	int ret = -EINVAL;
+	if (clk->set_rate) {
+		ret = clk->set_rate(clk, rate);
+	}
+	return ret;
+}
+
+/* @ struct clk * , unsigned long
+ * API:clk_set_rate used to set clock rate value
+ * for the devices. This API will be available to
+ * outside ( for all device driver).
+*/
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned long actual_rate;
+	int ret = -EINVAL;
+        unsigned long flags;
+
+	spin_lock_irqsave(&clock_lock, flags);
+	actual_rate=clk->rate;
+
+	if (actual_rate != rate ){
+                ret = local_set_rate(clk, rate);
+        }
+        else{ /*configured rate is same as desired rate*/
+                pr_debug("Current rate value of clock source (%s) is same as desired rate value (%ld)\n",clk->name,clk->rate);
+                spin_unlock_irqrestore(&clock_lock, flags);
+                return 0;
+        }
+
+	if ( ret == -EINVAL ){
+		pr_debug("Cannot change clock:(%s) ,not supporting set_rate,set to previous value (%ld)\n",clk->name,clk->rate);
+	}else{
+		pr_debug("Changed clock:(%s) rate ,rate value is (%ld)\n",clk->name,clk->rate);
+	}
+	spin_unlock_irqrestore(&clock_lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+/* @ struct clk * 
+ * API:clk_get_parent used to parent clock source.
+ * This API will be available to
+ * outside ( for all device driver).
+*/
+struct clk *clk_get_parent(struct clk *clk)
+{
+        return clk->parent;
+}
+EXPORT_SYMBOL(clk_get_parent);
+
+/* @ struct clk * , unsigned long
+ * API:clk_set_parent used to set to a different
+ * parent clock source.
+ * This API will be available to
+ * outside ( for all device driver).
+*/
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+        unsigned long flags;
+
+	if (clk == NULL || IS_ERR(clk))
+                return -EINVAL;
+
+	/* Only set parent once and if none is already set. */
+        if (clk->parent)
+                return -EINVAL;
+
+	/* Cannot change parent on enabled clock */
+        if ( WARN_ON(clk->usecount))
+                return -EBUSY;
+
+	spin_lock_irqsave(&clock_lock, flags);
+	/* Set the parent in clk  strusture */
+        clk->parent = parent;
+	spin_unlock_irqrestore(&clock_lock, flags);
+        return 0;
+}
+EXPORT_SYMBOL(clk_set_parent);
+
+/*
+ * CLKGEN Divider registers
+ * The divider bypass bit in several configuration registers
+ * can only be written (if you read back you get zero).
+ *
+ * The Bug is in registers: 0x84 (A9DP_CLKDIV_CNTRL), 0x84 + 16 (L2CC_CLKDIV_CNTRL), 0x84 + 32
+ *	(TPI_CLKDIV_CNTRL), etc... until PLL_ADDR_SPACE at 0x1C0.
+ */
+
+/*
+ * Barebox uses IRAM to mirror the clock divider registers
+ * Linux will relocate this mirror from IRAM to DDR to free up IRAM.
+ */
+#define IRAM_CLK_REG_MIRROR		(0x8300FC00 - COMCERTO_AXI_IRAM_BASE + IRAM_MEMORY_VADDR)
+#define CLK_REG_DIV_BUG_BASE		AXI_CLK_DIV_CNTRL
+#define CLK_REG_DIV_BUG_SIZE		(PLL0_M_LSB - AXI_CLK_DIV_CNTRL)
+
+static u8 clk_div_backup_table [CLK_REG_DIV_BUG_SIZE];
+#define read_clk_div_bypass_backup(reg) readl(reg - CLK_REG_DIV_BUG_BASE + clk_div_backup_table)
+#define write_clk_div_bypass_backup(val, reg) writel(val, reg - CLK_REG_DIV_BUG_BASE + clk_div_backup_table)
+
+void HAL_clk_div_backup_relocate_table (void)
+{
+	memcpy (clk_div_backup_table, (void*) IRAM_CLK_REG_MIRROR, CLK_REG_DIV_BUG_SIZE);
+}
+EXPORT_SYMBOL(HAL_clk_div_backup_relocate_table);
+
+/*
+ * Get the reference clock after reading bootstrap
+ */
+unsigned long HAL_get_ref_clk (void)
+{
+	unsigned long clock_freq = 0;
+	unsigned int boot_strap, tmp;
+
+	boot_strap = readl(COMCERTO_GPIO_SYSTEM_CONFIG);
+	tmp = (boot_strap & GPIO_SYS_PLL_REF_CLK_MASK) >> GPIO_SYS_PLL_REF_CLK_SHIFT;
+
+	if ( USB_XTAL_REF_CLK == tmp )
+	{
+			if ( boot_strap & GPIO_USB_OSC_PAD_MASK )
+				clock_freq = REF_CLK_24MHZ;
+			else
+				clock_freq = REF_CLK_48MHZ;
+	}
+	else if ( SERDES_XTAL_REF_CLK == tmp )
+	{
+		if ( boot_strap & GPIO_SERDES_OSC_PAD_MASK )
+			clock_freq = REF_CLK_24MHZ;
+		else
+			clock_freq = REF_CLK_48MHZ;
+	}
+
+	return clock_freq;
+}
+EXPORT_SYMBOL(HAL_get_ref_clk);
+
+static unsigned long HAL_get_pll_freq(int pll_no)
+{
+	u32 p;
+	u32 od;
+	u32 m;
+	u32 k;
+	u32 s;
+	unsigned long pll_clk = 0;
+	unsigned long ref_clk = HAL_get_ref_clk();
+	unsigned long pll_div = 0;
+
+	if (pll_no < PLL3)
+	{
+		//get NF, NR and OD values
+		switch (pll_no)
+		{
+		case PLL0:
+			m = readl(PLL0_M_LSB) & 0xff;
+			m |= (readl(PLL0_M_MSB) & 0x3) << 8;
+			p = readl(PLL0_P) & 0x3f;
+			s = readl(PLL0_S) & 0x7;
+			od = (1 << s); // 2^s;
+			pll_div = readl(PLL0_DIV_CNTRL);
+			break;
+
+		case PLL1:
+			m = readl(PLL1_M_LSB) & 0xff;
+			m |= (readl(PLL1_M_MSB) & 0x3) << 8;
+			p = readl(PLL1_P) & 0x3f;
+			s = readl(PLL1_S) & 0x7;
+			od = (1 << s);
+			pll_div = readl(PLL1_DIV_CNTRL);
+			break;
+
+		case PLL2:
+			m = readl(PLL2_M_LSB) & 0xff;
+			m |= (readl(PLL2_M_MSB) & 0x3) << 8;
+			p = readl(PLL2_P) & 0x3f;
+			s = readl(PLL2_S) & 0x7;
+			od = (1 << s);
+			pll_div = readl(PLL2_DIV_CNTRL);
+			break;
+
+		default:
+			return 0;
+			break;
+		}
+
+		/* Ref Clock divided by 1000000. It should be displayed in MHz. */
+		pll_clk = ((ref_clk / 1000000) * m) / p / od ;
+		
+		if (pll_div & CLK_DIV_BYPASS)
+			pll_div = 1;
+		else
+			pll_div = pll_div & 0x1F;
+
+		if (pll_div > 1)
+			pll_clk = pll_clk/pll_div;
+
+	}
+	else if (pll_no == PLL3)
+	{
+		m = readl(PLL3_M_LSB) & 0xff;
+		m |= (readl(PLL3_M_MSB) & 0x3) << 8;
+		p = readl(PLL3_P) & 0x3f;
+		s = readl(PLL3_S) & 0x7;
+		k = readl(PLL3_K_LSB) & 0xff;
+		k |= (readl(PLL3_K_MSB) & 0xf) << 8;
+		od = (1 << s);
+		pll_clk = (((ref_clk / 1000000) * (m * 1024 + k)) / p / od + 1023) / 1024;
+	}
+
+	return (pll_clk * 1000000); /* convert into Hz and return it */
+}
+
+static void HAL_set_clk_divider(unsigned long rate,u32 ctrl_reg, u32 div_reg)
+{
+	u32 pll_src;
+	u32 val;
+	int divider;
+	unsigned long  pll_rate;
+
+	/* Get PLL Source */
+	pll_src = readl(ctrl_reg);
+	pll_src = (pll_src >> CLK_PLL_SRC_SHIFT) & CLK_PLL_SRC_MASK;
+
+	/* Get PLL Freq */
+	pll_rate = HAL_get_pll_freq(pll_src);
+
+	/* Get The Divider value For  Clock */
+	divider   =  pll_rate/rate;
+
+	if ( divider == 1){
+		write_clk_div_bypass_backup(CLK_DIV_BYPASS,div_reg);
+		/* Enable the Bypass bit in Hw reg (clk_div_bypass in div_reg) */
+		val = readl(div_reg);
+		val |= CLK_DIV_BYPASS;
+		writel(val , div_reg);
+	}
+	else
+	{
+		write_clk_div_bypass_backup(0,div_reg);
+		/* Write to the divider reg */
+		val = readl(div_reg);
+		val &= ~0x1f;
+		val |= divider;
+		writel(val, div_reg);
+		/* Clear the Bypass bit in Hw reg (clk_div_bypass in div_reg) */
+		val = readl(div_reg);
+		val &= ~CLK_DIV_BYPASS;
+		writel(val , div_reg);
+	}
+}
+
+static int HAL_get_clock_pll_source(u32 ctrl_reg)
+{
+	int pll_src;
+
+	/* Get PLL source */
+	pll_src = readl(ctrl_reg);
+	pll_src = (pll_src >> CLK_PLL_SRC_SHIFT) & CLK_PLL_SRC_MASK;
+
+	return pll_src;
+
+}
+
+static void HAL_set_clock_pll_source(u32 ctrl_reg,int pll_src){
+
+	switch(pll_src)
+	{
+		case PLL0:
+			writel(readl(ctrl_reg) | (1 << 0) , ctrl_reg);
+                	break;
+		case PLL1:
+			writel(readl(ctrl_reg) | (1 << 1) , ctrl_reg);
+                	break;
+		case PLL3:
+			writel(readl(ctrl_reg) | (1 << 3), ctrl_reg);
+                	break;
+		case PLL2:
+		default:
+			writel(readl(ctrl_reg) | (1 << 2), ctrl_reg);
+                	break;
+	}
+
+}
+
+static unsigned long HAL_get_clk_freq(u32 ctrl_reg, u32 div_reg)
+{
+	u32 pll_src;
+	u32 clk_div;
+	unsigned long clk_out;
+	unsigned long pll_clk;
+	int bypass = 0;
+
+	/* Get PLL Source */
+	pll_src = readl(ctrl_reg);
+	pll_src = (pll_src >> CLK_PLL_SRC_SHIFT) & CLK_PLL_SRC_MASK;
+
+	/* Get clock divider bypass value from IRAM Clock Divider registers mirror location */
+	clk_div = read_clk_div_bypass_backup(div_reg);
+
+	if (clk_div & CLK_DIV_BYPASS)
+		bypass = 1;
+	else
+	{
+		clk_div = readl(div_reg);
+		clk_div &= 0x1f;
+	}
+
+	pll_clk = HAL_get_pll_freq(pll_src); 
+
+	if (bypass)
+		clk_out = pll_clk;
+	else
+		clk_out = pll_clk / clk_div;
+
+	return clk_out;
+}
+
+/* Get rate API callback */
+static unsigned long HAL_get_clk(struct clk *clk)
+{
+	return HAL_get_clk_freq(clk->clkgen_reg, clk->div_reg);
+}
+
+/* Get rate API callback for those clocks having Parent */
+static unsigned long HAL_get_parent_clk(struct clk *clk)
+{
+	return clk_get_rate(clk->parent);
+}
+/* Specific Get rate API callback for arm peripherals */
+static unsigned long  HAL_get_arm_peri_clk(struct clk *clk)
+{
+	return clk_get_rate(clk->parent)/4 ;
+}
+
+/* Set rate APIs callbacks */
+static int HAL_set_clk(struct clk *clk,unsigned long rate)
+{
+	struct clk *clk_parent;
+	/* Get the parent clock */
+	clk_parent=clk_get_parent(clk);
+	if ( clk_parent || rate <= clk_parent->rate){
+		/* Set the divider value to reg */
+		HAL_set_clk_divider(rate,clk->clkgen_reg,clk->div_reg);
+		/* Set the rate value to clk structure */
+		clk->rate=rate;
+		return 0;
+	}else
+		return -EINVAL;
+}
+
+/* Initization of clk structure for individual device */
+
+static struct clk clk_pll0 = {
+	.name     = "pll0",
+};
+
+static struct clk clk_pll1 = {
+	.name   = "pll1",
+};
+
+static struct clk clk_pll2 = {
+	.name   = "pll2",
+};
+
+static struct clk clk_pll3 = {
+	.name   = "pll3",
+};
+
+
+
+static struct clk gemtx_clk = {
+	.name        = "gemtx",
+	.enable_reg  = GEMTX_CLK_CNTRL,
+	.clkgen_reg  = GEMTX_CLK_CNTRL,
+	.div_reg     = GEMTX_CLK_DIV_CNTRL,
+	.enable_mask = CLK_DOMAIN_MASK,
+	.get_rate    = HAL_get_clk,
+	.set_rate    = HAL_set_clk,
+};
+
+static struct clk ddr_clk = {
+	.name        = "ddr",
+	.enable_reg  = DDR_CLK_CNTRL,
+	.clkgen_reg  = DDR_CLK_CNTRL,
+	.div_reg     = DDR_CLK_DIV_CNTRL,
+	.enable_mask = CLK_DOMAIN_MASK,
+	.get_rate    = HAL_get_clk,
+};
+
+static struct clk arm_clk = {
+	.name        = "arm",
+	.enable_reg  = A9DP_CLK_CNTRL,
+	.clkgen_reg  = A9DP_CLK_CNTRL,
+	.div_reg     = A9DP_CLK_DIV_CNTRL,
+	.enable_mask = CLK_DOMAIN_MASK,
+	.get_rate    = HAL_get_clk,
+	.set_rate    = HAL_set_clk,
+};
+
+static struct clk l2cc_clk = {
+	.name        = "l2cc",
+	.enable_reg  = L2CC_CLK_CNTRL,
+	.clkgen_reg  = L2CC_CLK_CNTRL,
+	.div_reg     = L2CC_CLK_DIV_CNTRL,
+	.enable_mask = CLK_DOMAIN_MASK,
+	.get_rate    = HAL_get_clk,
+	.set_rate    = HAL_set_clk,
+};
+
+static struct clk axi_clk = {
+	.name        = "axi",
+	.enable_reg  = AXI_CLK_CNTRL_0,
+	.clkgen_reg  = AXI_CLK_CNTRL_0,
+	.div_reg     = AXI_CLK_DIV_CNTRL,
+	.enable_mask = CLK_DOMAIN_MASK,
+	.get_rate    = HAL_get_clk,
+	.set_rate    = HAL_set_clk,
+};
+
+static struct clk uart_clk = { /* Legacy UART */
+	.parent      = &axi_clk,
+	.name        = "uart",
+	.enable_reg  = AXI_CLK_CNTRL_1,
+	.enable_mask = CLK_DOMAIN_UART_MASK,
+	.get_rate    = HAL_get_parent_clk,
+};
+
+static struct clk ipsec_eape_clk = {
+	.name        = "ipsec_eape",
+	.enable_reg  = IPSEC_CLK_CNTRL,
+	.clkgen_reg  = IPSEC_CLK_CNTRL,
+	.div_reg     = IPSEC_CLK_DIV_CNTRL,
+	.enable_mask = CLK_DOMAIN_MASK,
+	.get_rate    = HAL_get_clk,
+};
+
+static struct clk ipsec_spacc_clk = {       /* IPSEC spacc clock for Elliptic EPN1802*/
+	.parent      = &axi_clk,
+	.name        = "ipsec_spacc",
+	.enable_reg  = AXI_CLK_CNTRL_1,
+	.enable_mask = CLK_DOMAIN_IPSEC_SPACC_MASK,
+	.get_rate    = HAL_get_parent_clk,
+};
+
+static struct clk dpi_cie_clk = {       /* DPI cie clock*/
+	.parent      = &axi_clk,
+	.name        = "dpi_cie",
+	.enable_reg  = AXI_CLK_CNTRL_0,
+	.enable_mask = CLK_DOMAIN_DPI_CIE_MASK,
+	.get_rate    = HAL_get_parent_clk,
+};
+
+static struct clk dpi_decomp_clk = {       /* DPI decomp clock*/
+	.parent      = &axi_clk,
+	.name        = "dpi_decomp",
+	.enable_reg  = AXI_CLK_CNTRL_0,
+	.enable_mask = CLK_DOMAIN_DPI_DECOMP_MASK,
+	.get_rate    = HAL_get_parent_clk,
+};
+
+static struct clk DUS_clk = { /* DMA,FAST-UART and SMI clock */
+	.parent      = &axi_clk,
+	.name        = "DUS",
+	.enable_reg  = AXI_CLK_CNTRL_1,
+	.enable_mask = CLK_DOMAIN_DUS_MASK,
+	.get_rate    = HAL_get_parent_clk,
+};
+
+static struct clk arm_peri_clk = {
+	.parent      = &arm_clk,
+	.name        = "arm_peri",
+	.enable_reg  = A9DP_MPU_CLK_CNTRL,
+	.enable_mask = CLK_DOMAIN_MASK,
+	.get_rate    = HAL_get_arm_peri_clk,
+};
+
+static struct clk hfe_core_clk = {
+	.name        = "hfe_core",
+	.enable_reg  = PFE_CLK_CNTRL,
+	.clkgen_reg  = PFE_CLK_CNTRL,
+	.div_reg     = PFE_CLK_DIV_CNTRL,
+	.enable_mask = CLK_DOMAIN_MASK,
+	.get_rate    = HAL_get_clk,
+	.set_rate    = HAL_set_clk,
+};
+
+static struct clk spi_i2c_clk = {
+	.parent      = &axi_clk,
+	.name        = "spi_i2c",
+	.enable_reg  = AXI_CLK_CNTRL_1,
+	.enable_mask = CLK_DOMAIN_SPI_I2C_MASK,
+	.get_rate    = HAL_get_parent_clk,
+};
+
+static struct clk tdmNTG_clk = {
+	.name        = "ntgref",
+	.enable_reg  = TDMNTG_REF_CLK_CNTRL,
+	.clkgen_reg  = TDMNTG_REF_CLK_CNTRL,
+	.div_reg     = TDMNTG_REF_CLK_DIV_CNTRL,
+	.enable_mask = CLK_DOMAIN_MASK,
+	.get_rate    = HAL_get_clk,
+	.set_rate    = HAL_set_clk,
+};
+
+static struct clk pcie0_clk = {
+	.parent      = &axi_clk,
+	.name        = "pcie0",
+	.enable_reg  = AXI_CLK_CNTRL_2,
+	.enable_mask = CLK_DOMAIN_PCIE0_MASK,
+	.get_rate    = HAL_get_parent_clk,
+};
+
+static struct clk pcie1_clk = {
+	.parent      = &axi_clk,
+	.name        = "pcie1",
+	.enable_reg  = AXI_CLK_CNTRL_2,
+	.enable_mask = CLK_DOMAIN_PCIE1_MASK,
+	.get_rate    = HAL_get_parent_clk,
+};
+
+static struct clk usb0_clk = {
+	.parent      = &axi_clk,
+	.name        = "usb0",
+	.enable_reg  = AXI_CLK_CNTRL_2,
+	.enable_mask = CLK_DOMAIN_USB0_MASK,
+	.get_rate    = HAL_get_parent_clk,
+};
+
+static struct clk usb1_clk = {
+	.parent      = &axi_clk,
+	.name        = "usb1",
+	.enable_reg  = AXI_CLK_CNTRL_2,
+	.enable_mask = CLK_DOMAIN_USB1_MASK,
+	.get_rate    = HAL_get_parent_clk,
+};
+
+static struct clk sata_clk = {            /* SATA AXI clock */
+	.parent      = &axi_clk,
+	.name        = "sata",
+	.enable_reg  = AXI_CLK_CNTRL_2,
+	.enable_mask = CLK_DOMAIN_SATA_MASK,
+	.get_rate    = HAL_get_parent_clk,
+};
+static struct clk sata_oob_clk = {
+	.name        = "sata_oob",	  /* SATA PMU alive clock */
+	.enable_reg  = SATA_OOB_CLK_CNTRL,
+	.clkgen_reg  = SATA_OOB_CLK_CNTRL,
+	.div_reg     = SATA_OOB_CLK_DIV_CNTRL,
+	.enable_mask = CLK_DOMAIN_MASK,
+	.get_rate    = HAL_get_clk,
+	.set_rate    = HAL_set_clk,
+};
+
+static struct clk sata_pmu_clk = {
+	.name        = "sata_pmu",	 /* SATA core clock control */
+	.enable_reg  = SATA_PMU_CLK_CNTRL,
+	.clkgen_reg  = SATA_PMU_CLK_CNTRL,
+	.div_reg     = SATA_PMU_CLK_DIV_CNTRL,
+	.enable_mask = CLK_DOMAIN_MASK,
+	.get_rate    = HAL_get_clk,
+	.set_rate    = HAL_set_clk,
+};
+
+static struct clk ext_phy0_clk = {
+	.name	     = "ext_phy0",
+	.enable_reg  = EXTPHY0_CLK_CNTRL,
+	.clkgen_reg  = EXTPHY0_CLK_CNTRL,
+	.div_reg     = EXTPHY0_CLK_DIV_CNTRL,
+	.enable_mask = CLK_DOMAIN_MASK,
+	.get_rate    = HAL_get_clk,
+	.set_rate    = HAL_set_clk,
+};
+
+static struct clk ext_phy1_clk = {
+	.name	     = "ext_phy1",
+	.enable_reg  = EXTPHY1_CLK_CNTRL,
+	.clkgen_reg  = EXTPHY1_CLK_CNTRL,
+	.div_reg     = EXTPHY1_CLK_DIV_CNTRL,
+	.enable_mask = CLK_DOMAIN_MASK,
+	.get_rate    = HAL_get_clk,
+	.set_rate    = HAL_set_clk,
+};
+
+static struct clk ext_phy2_clk = {
+	.name	     = "ext_phy2",
+	.enable_reg  = EXTPHY2_CLK_CNTRL,
+	.clkgen_reg  = EXTPHY2_CLK_CNTRL,
+	.div_reg     = EXTPHY2_CLK_DIV_CNTRL,
+	.enable_mask = CLK_DOMAIN_MASK,
+	.get_rate    = HAL_get_clk,
+	.set_rate    = HAL_set_clk,
+};
+
+static struct clk tpi_clk = {
+	.name	     = "tpi",
+	.enable_reg  = TPI_CLK_CNTRL,
+	.clkgen_reg  = TPI_CLK_CNTRL,
+	.div_reg     = TPI_CLK_DIV_CNTRL,
+	.enable_mask = CLK_DOMAIN_MASK,
+	.get_rate    = HAL_get_clk,
+	.set_rate    = HAL_set_clk,
+};
+
+static struct clk csys_clk = {
+	.name	     = "csys",
+	.enable_reg  = CSYS_CLK_CNTRL,
+	.clkgen_reg  = CSYS_CLK_CNTRL,
+	.div_reg     = CSYS_CLK_DIV_CNTRL,
+	.enable_mask = CLK_DOMAIN_MASK,
+	.get_rate    = HAL_get_clk,
+	.set_rate    = HAL_set_clk,
+};
+
+static struct clk tsuntg_clk = {
+	.name	     = "tsuntg",
+	.enable_reg  = TSUNTG_REF_CLK_CNTRL,
+	.clkgen_reg  = TSUNTG_REF_CLK_CNTRL,
+	.div_reg     = TSUNTG_REF_CLK_DIV_CNTRL,
+	.enable_mask = CLK_DOMAIN_MASK,
+	.get_rate    = HAL_get_clk,
+	.set_rate    = HAL_set_clk,
+};
+
+static struct clk sata_occ_clk = {
+	.name	     = "sata_occ",
+	.enable_reg  = SATA_OCC_CLK_CNTRL,
+	.clkgen_reg  = SATA_OCC_CLK_CNTRL,
+	.div_reg     = SATA_OCC_CLK_DIV_CNTRL,
+	.enable_mask = CLK_DOMAIN_MASK,
+	.get_rate    = HAL_get_clk,
+	.set_rate    = HAL_set_clk,
+};
+
+static struct clk pcie_occ_clk = {
+	.name	     = "pcie_occ",
+	.enable_reg  = PCIE_OCC_CLK_CNTRL,
+	.clkgen_reg  = PCIE_OCC_CLK_CNTRL,
+	.div_reg     = PCIE_OCC_CLK_DIV_CNTRL,
+	.enable_mask = CLK_DOMAIN_MASK,
+	.get_rate    = HAL_get_clk,
+	.set_rate    = HAL_set_clk,
+};
+
+static struct clk sgmii_occ_clk = {
+	.name	     = "sgmii_occ",
+	.enable_reg  = SGMII_OCC_CLK_CNTRL,
+	.clkgen_reg  = SGMII_OCC_CLK_CNTRL,
+	.div_reg     = SGMII_OCC_CLK_DIV_CNTRL,
+	.enable_mask = CLK_DOMAIN_MASK,
+	.get_rate    = HAL_get_clk,
+	.set_rate    = HAL_set_clk,
+};
+
+/* These clocks are visible outside this module
+ * and can be initialized , this list could be expanded
+ * according to new device support.
+ */
+static struct clk *c2k_clks[] __initdata = {
+	&clk_pll0,
+	&clk_pll1,
+	&clk_pll2,
+	&clk_pll3,
+	&uart_clk,
+	&DUS_clk,
+	&gemtx_clk,
+	&ipsec_eape_clk,
+	&ipsec_spacc_clk,
+	&dpi_cie_clk,
+	&dpi_decomp_clk,
+	&ddr_clk,
+	&arm_clk,
+	&l2cc_clk,
+	&axi_clk,
+	&arm_peri_clk,
+	&hfe_core_clk,
+	&spi_i2c_clk,
+	&tdmNTG_clk,
+	&pcie0_clk,
+	&pcie1_clk,
+	&usb0_clk,
+	&usb1_clk,
+	&sata_clk,
+	&sata_oob_clk,
+	&sata_pmu_clk,
+	&ext_phy0_clk,
+	&ext_phy1_clk,
+	&ext_phy2_clk,
+	&tpi_clk,
+	&csys_clk,
+	&tsuntg_clk,
+	&sata_occ_clk,
+	&pcie_occ_clk,
+	&sgmii_occ_clk,
+};
+
+static struct clk_lookup c2k_clksreg[] = {
+	{ .clk = &clk_pll0,         .con_id = "pll0"},
+	{ .clk = &clk_pll1,         .con_id = "pll1"},
+	{ .clk = &clk_pll2,         .con_id = "pll2"},
+	{ .clk = &clk_pll3,         .con_id = "pll3"},
+	{ .clk = &uart_clk,         .con_id = "uart"},
+	{ .clk = &DUS_clk,          .con_id = "DUS"},
+	{ .clk = &gemtx_clk,        .con_id = "gemtx"},
+	{ .clk = &ipsec_eape_clk,   .con_id = "ipsec_eape"},
+	{ .clk = &ipsec_spacc_clk,  .con_id = "ipsec_spacc"},
+	{ .clk = &dpi_cie_clk,      .con_id = "dpi_cie"},
+	{ .clk = &dpi_decomp_clk,   .con_id = "dpi_decomp"},
+	{ .clk = &ddr_clk,          .con_id = "ddr"},
+	{ .clk = &arm_clk,          .con_id = "arm"},
+	{ .clk = &l2cc_clk,         .con_id = "l2cc"},
+	{ .clk = &axi_clk,          .con_id = "axi"},
+	{ .clk = &arm_peri_clk,     .con_id = "arm_peri"},
+	{ .clk = &hfe_core_clk,     .con_id = "hfe_core"},
+	{ .clk = &spi_i2c_clk,      .con_id = "spi_i2c"},
+	{ .clk = &tdmNTG_clk,       .con_id = "ntgref"},
+	{ .clk = &pcie0_clk,        .con_id = "pcie0"},
+	{ .clk = &pcie1_clk,        .con_id = "pcie1"},
+	{ .clk = &usb0_clk,         .con_id = "usb0"},
+	{ .clk = &usb1_clk,         .con_id = "usb1"},
+	{ .clk = &sata_clk,    	    .con_id = "sata"},
+	{ .clk = &sata_oob_clk,     .con_id = "sata_oob"},
+	{ .clk = &sata_pmu_clk,     .con_id = "sata_pmu"},
+	{ .clk = &ext_phy0_clk,     .con_id = "ext_phy0"},
+	{ .clk = &ext_phy1_clk,     .con_id = "ext_phy1"},
+	{ .clk = &ext_phy2_clk,     .con_id = "ext_phy2"},
+	{ .clk = &tpi_clk,     	    .con_id = "tpi"},
+	{ .clk = &csys_clk,         .con_id = "csys"},
+	{ .clk = &tsuntg_clk,       .con_id = "tsuntg"},
+	{ .clk = &sata_occ_clk,     .con_id = "sata_occ"},
+	{ .clk = &pcie_occ_clk,     .con_id = "pcie_occ"},
+	{ .clk = &sgmii_occ_clk,    .con_id = "sgmii_occ"},
+};
+
+/* Initilize all the available clocks */
+int clk_init(void){
+        struct clk **clkp;
+	int pll_no;
+
+	spin_lock_init(&clock_lock);
+
+        /* Determine the barebox configured pll0,pll1,pll2,pll3 rate value */
+        clk_pll0.rate = HAL_get_pll_freq(PLL0);
+        clk_pll1.rate = HAL_get_pll_freq(PLL1);
+        clk_pll2.rate = HAL_get_pll_freq(PLL2);
+        clk_pll3.rate = HAL_get_pll_freq(PLL3);
+
+	/* Set the NTG ref clock to PLL src (gemtx PLL source)
+	 * Currently it is not set from barebox,set here.
+	*/
+	pll_no = HAL_get_clock_pll_source(gemtx_clk.clkgen_reg);
+	HAL_set_clock_pll_source(tdmNTG_clk.clkgen_reg,pll_no);
+
+        pr_info("PLL0 running at %ld MHz, PLL1 at %ld MHz PLL2 running at %ld MHz PLL3 running at %ld MHz\n",
+                clk_pll0.rate/1000000, clk_pll1.rate/1000000, clk_pll2.rate/1000000, clk_pll3.rate/1000000);
+        /* Initilization of Clocks present in C2k device */
+        for (clkp = c2k_clks; clkp < c2k_clks + ARRAY_SIZE(c2k_clks);clkp++) {
+                struct clk *clk = *clkp;
+		/* Setting the parent clock in the init
+		 * Only to those who can be configured with PLL source
+		 */
+		if (!clk->parent){
+			if (clk->clkgen_reg){ /* This check is for not to set parent for PLLS */
+				pll_no = HAL_get_clock_pll_source(clk->clkgen_reg);
+				switch (pll_no)
+				{
+					case PLL0:
+						clk_set_parent(clk,&clk_pll0);
+						break;
+					case PLL1:
+						clk_set_parent(clk,&clk_pll1);
+						break;
+					case PLL2:
+						clk_set_parent(clk,&clk_pll2);
+						break;
+					default:
+						break;
+				}
+			}
+		}
+        	/* Get The Device Clock Rate Values */
+		if ( clk->get_rate)
+			clk->rate=clk->get_rate(clk);
+                pr_debug("%s: clock %s, rate %ld\n",__func__, clk->name, clk->rate);
+        }
+
+        /* Creation of Clock Device Tree */
+        clkdev_add_table(c2k_clksreg, ARRAY_SIZE(c2k_clksreg));
+	return 0;
+
+}
+EXPORT_SYMBOL(clk_init);
+
+/*
+ * Disable any unused clocks left on by the bootloader(Barebox)
+ */
+static int __init clk_disable_unused(void)
+{
+        struct clk **clkp;
+
+        for (clkp = c2k_clks; clkp < c2k_clks + ARRAY_SIZE(c2k_clks);clkp++) {
+                struct clk *clk = *clkp;
+		if (clk->usecount > 0)
+			continue;
+
+		/* FIXME Currently there is no clock FW support for the
+                 * following clocks in corresponding driver . So skipping these
+		 * clocks from by default disable state.
+                 * All other unused clocks will be disabled.
+                */
+		if ( strcmp(clk->name, "hfe_core") &&
+				strcmp(clk->name, "ipsec_eape") &&
+				strcmp(clk->name, "pll3") &&
+				strcmp(clk->name, "arm_peri") )
+		{
+			pr_info("Clocks: disabled unused %s\n", clk->name);
+			__clk_disable_unused(clk);
+		}
+	}
+        return 0;
+}
+late_initcall(clk_disable_unused);
diff --git a/arch/arm/mach-comcerto/comcerto-2000.c b/arch/arm/mach-comcerto/comcerto-2000.c
new file mode 100644
index 0000000..b5b0cb7
--- /dev/null
+++ b/arch/arm/mach-comcerto/comcerto-2000.c
@@ -0,0 +1,1027 @@
+/*
+ *  linux/arch/arm/mach-comcerto/comcerto-2000.c
+ *
+ *  Copyright (C) 2011 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/memblock.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/io.h>
+#include <asm/sizes.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <mach/irqs.h>
+#include <linux/delay.h>
+#include <asm/pmu.h>
+#include <mach/dma.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/serial_8250.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/smp.h>
+#include <linux/uio_driver.h>
+
+#include <asm/mach-types.h>
+#include <asm/smp_twd.h>
+#include <asm/localtimer.h>
+
+#include <asm/mach/time.h>
+#include <asm/hardware/gic.h>
+#include <mach/reset.h>
+
+#include <mach/hardware.h>
+#include <asm/hardware/cache-l2x0.h>
+#include <mach/comcerto-2000.h>
+#include <linux/ahci_platform.h>
+#include <mach/serdes-c2000.h>
+#include <linux/clockchips.h>
+#include <linux/clk.h>
+#include <mach/comcerto-2000/clock.h>
+#include <mach/comcerto-2000/pm.h>
+#include <mach/gpio.h>
+
+struct c2k_gpio_pin_stat_info c2k_gpio_pin_stat =
+{
+	.c2k_gpio_pins_0_31 = 0x0,
+	.c2k_gpio_pins_32_63 = 0x0,
+};
+
+#ifdef CONFIG_CACHE_L2X0
+void __iomem *l2cache_base;
+#endif
+
+/***********************************************************
+ *   Virtual address Mapping                               *
+ *                                                         *
+ ***********************************************************/
+
+static struct map_desc comcerto_io_desc[] __initdata =
+{
+#ifdef CONFIG_COMCERTO_MSP
+	{
+		.virtual    = COMCERTO_MSP_VADDR,
+		.pfn        = __phys_to_pfn(COMCERTO_MSP_DDR_BASE),
+		.length     = COMCERTO_MSP_DDR_SIZE_CB,
+		.type       = MT_MSP
+	},
+	{
+		.virtual    = (COMCERTO_MSP_VADDR + COMCERTO_MSP_DDR_SIZE_CB),
+		.pfn        = __phys_to_pfn(COMCERTO_MSP_DDR_BASE + COMCERTO_MSP_DDR_SIZE_CB),
+		.length     = COMCERTO_MSP_DDR_SIZE_NCNB,
+		.type       = MT_MSP_NCNB
+	},
+       {
+               .virtual    = COMCERTO_PFE_VADDR,
+               .pfn        = __phys_to_pfn(COMCERTO_PFE_DDR_BASE),
+               .length     = COMCERTO_PFE_DDR_SIZE,
+               .type       = MT_DEVICE
+       },
+       {
+               .virtual    = COMCERTO_PFE_AXI_VADDR,
+               .pfn        = __phys_to_pfn(COMCERTO_AXI_PFE_BASE),
+               .length     = COMCERTO_AXI_PFE_SIZE,
+               .type       = MT_DEVICE
+       },
+#endif  /* CONFIG_COMCERTO_MSP */
+#if defined(CONFIG_PCI)
+        {
+                .virtual    = COMCERTO_AXI_PCIe0_VADDR_BASE,
+                .pfn        = __phys_to_pfn(COMCERTO_AXI_PCIe0_BASE),
+                .length     = SZ_16M,
+                .type       = MT_DEVICE
+        },
+        {
+                .virtual    = COMCERTO_AXI_PCIe1_VADDR_BASE,
+                .pfn        = __phys_to_pfn(COMCERTO_AXI_PCIe1_BASE),
+                .length     = SZ_16M,
+                .type       = MT_DEVICE
+        },
+#endif
+	{
+		.virtual    = COMCERTO_SCU_VADDR,
+		.pfn        = __phys_to_pfn(COMCERTO_SCU_BASE),
+		.length     = SZ_128K,
+		.type       = MT_DEVICE
+	},
+	{
+		.virtual    = IRAM_MEMORY_VADDR,
+		.pfn        = __phys_to_pfn(COMCERTO_AXI_IRAM_BASE),
+		.length     = IRAM_MEMORY_SIZE,
+		.type       = MT_DEVICE
+	},
+	{
+		.virtual    = COMCERTO_APB_VADDR,
+		.pfn        = __phys_to_pfn(COMCERTO_AXI_APB_BASE),
+		.length     = COMCERTO_APB_SIZE,
+		.type       = MT_DEVICE
+	},
+	{
+		.virtual	= COMCERTO_AXI_UART_SPI_VADDR,
+		.pfn		= __phys_to_pfn(COMCERTO_AXI_UART_SPI_BASE),
+		.length 	= COMCERTO_AXI_UART_SPI_SIZE,
+		.type		= MT_DEVICE
+	},
+	{
+		.virtual	= COMCERTO_DECT_VADDR,
+		.pfn		= __phys_to_pfn(COMCERTO_AXI_DECT_BASE),
+		.length		= 2 * SZ_1M,
+		.type		= MT_DEVICE
+	},
+	{
+		.virtual    = COMCERTO_SEMA_VADDR,
+		.pfn        = __phys_to_pfn(COMCERTO_AXI_SEMA_BASE),
+		.length     = SZ_16M,
+		.type       = MT_DEVICE
+	},
+};
+
+#if defined(CONFIG_COMCERTO_64K_PAGES)
+#define PFE_DMA_SIZE		(4 * SZ_1M)
+#else
+#define PFE_DMA_SIZE            (16 * SZ_1M)
+#endif
+
+#define DSPG_DECT_CSS_DMA_SIZE	(10 * SZ_1M)
+
+void __init device_map_io(void)
+{
+	unsigned long size = PFE_DMA_SIZE;
+
+#if defined(CONFIG_DSPG_DECT_CSS)
+	size += DSPG_DECT_CSS_DMA_SIZE;
+#endif
+
+	iotable_init(comcerto_io_desc, ARRAY_SIZE(comcerto_io_desc));
+
+	/* Increase consistent DMA zone size */
+	init_consistent_dma_size(size);
+}
+
+
+void __init device_irq_init(void)
+{
+	gic_init(0, SGI_IRQ(1), (void *)COMCERTO_GIC_DIST_VADDR, (void *)COMCERTO_GIC_CPU_VADDR);
+}
+
+/************************************************************************
+ *  GPIO
+ ************************************************************************/
+static __init void gpio_init(void)
+{
+
+#if defined(CONFIG_COMCERTO_UART1_SUPPORT)
+	writel(readl(COMCERTO_GPIO_MISC_PIN_SELECT) & ~0x3, COMCERTO_GPIO_MISC_PIN_SELECT);
+#endif
+
+#if defined(CONFIG_COMCERTO_UART0_SUPPORT)
+	writel((readl(COMCERTO_GPIO_PIN_SELECT_REG) & ~UART0_GPIO) | UART0_BUS, COMCERTO_GPIO_PIN_SELECT_REG);
+	c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= UART0_GPIO_PIN; /* GPIOs 8 to 11 are used for UART0 */
+#endif
+
+	/*
+	 * Configure each GPIO to be Output or Input
+	 * When Input, Configure to be Input, IRQ
+	 * When Input IRQ, Configure to be IRQ Rising Edge or IRQ falling Edge
+	 */
+
+	/*[FIXME]: GPIO Output, others are input*/
+	__raw_writel(__raw_readl(COMCERTO_GPIO_OE_REG) | COMCERTO_OUTPUT_GPIO, COMCERTO_GPIO_OE_REG);
+
+	/*[FIXME]: GPIO IRQ Configuration */
+	__raw_writel(COMCERTO_IRQ_RISING_EDGE_GPIO, COMCERTO_GPIO_INT_CFG_REG);
+
+#if !defined(CONFIG_C2K_MFCN_EVM)
+	/* [FIXME]: Need to have proper defines for enabling the GPIO irq */
+	__raw_writel(__raw_readl(COMCERTO_GPIO_OE_REG)     | (0x1 << 5), COMCERTO_GPIO_OE_REG);		// enable GPIO5 (SLIC_RESET_n) as output
+	__raw_writel(__raw_readl(COMCERTO_GPIO_OUTPUT_REG) | (0x1 << 5), COMCERTO_GPIO_OUTPUT_REG);     // clear reset
+	udelay(15);
+	__raw_writel(__raw_readl(COMCERTO_GPIO_OUTPUT_REG) & ~(0x1 << 5), COMCERTO_GPIO_OUTPUT_REG);	// put in reset
+	udelay(15);
+	__raw_writel(__raw_readl(COMCERTO_GPIO_OUTPUT_REG) | (0x1 << 5), COMCERTO_GPIO_OUTPUT_REG); 	// clear reset after some time
+#endif
+	__raw_writel(0x4, COMCERTO_GPIO_INT_CFG_REG); /* si3227 is falling edge interrupt(gpio1) */
+
+
+	/* [FIXME]: Are pins GPIO or pins used by another block*/
+	//__raw_writel(COMCERTO_GPIO_PIN_USAGE, COMCERTO_GPIO_IOCTRL_REG);
+}
+
+/************************************************************************
+ *  Expansion Bus
+ ************************************************************************/
+
+/*This variable is provided by the board file*/
+extern int comcerto_exp_values[5][7];
+
+static __init void exp_bus_init(void)
+{
+	int cs;
+	u32 cs_enable;
+	unsigned int axi_clk, clk_div;
+	struct clk *clk_axi;
+
+	/*First, Reset the Expansion block*/
+	__raw_writel(0x1, COMCERTO_EXP_SW_RST_R);
+
+	while (readl(COMCERTO_EXP_SW_RST_R) & 0x1) ;
+
+	/* Clock divider configuration, get the AXI clock first
+	 * AXI clock will be used for refernce count , as exp bus
+         * also have a dependancy with AXI.
+	*/
+        clk_axi = clk_get(NULL,"axi");
+
+	if (IS_ERR(clk_axi)) {
+		pr_err("comcerto_Device_init: Unable to obtain axi clock: %ld\n",PTR_ERR(clk_axi));
+	}
+
+	/*Enable the AXI clock */
+	if (clk_enable(clk_axi)){
+		pr_err("%s: Unable to enable axi clock:\n",__func__);
+	}
+
+        /* Get the AXI clock rate in HZ */
+        axi_clk = clk_get_rate(clk_axi);
+	/* Round divider up */
+	clk_div = (axi_clk + COMCERTO_EXPCLK - 1) / COMCERTO_EXPCLK;
+
+	__raw_writel(clk_div, COMCERTO_EXP_CLOCK_DIV_R);
+
+	cs_enable = 0;
+	for (cs = 0; cs < 5; cs++) {
+		/*configure only enabled CS */
+		{
+			if (comcerto_exp_values[cs][0] == 1)
+				cs_enable |= EXP_CSx_EN(cs);
+
+			/*mode configuration*/
+			__raw_writel(comcerto_exp_values[cs][3], COMCERTO_EXP_CSx_CFG_R(cs));
+
+			/*Chip select Base configuration (start of address space)*/
+			__raw_writel(comcerto_exp_values[cs][1], COMCERTO_EXP_CSx_BASE_R(cs));
+
+			/*Chip select Segment size configuration (end of address space)*/
+			__raw_writel(comcerto_exp_values[cs][2], COMCERTO_EXP_CSx_SEG_R(cs));
+
+			/*Chip select timing configuration*/
+			/* [FIXME] : Using default timing values */
+			__raw_writel(comcerto_exp_values[cs][4], COMCERTO_EXP_CSx_TMG1_R(cs));
+			__raw_writel(comcerto_exp_values[cs][5], COMCERTO_EXP_CSx_TMG2_R(cs));
+			__raw_writel(comcerto_exp_values[cs][6], COMCERTO_EXP_CSx_TMG3_R(cs));
+		}
+	}
+
+	/*Chip Select activation*/
+	__raw_writel(EXP_CLK_EN | cs_enable, COMCERTO_EXP_CS_EN_R);
+}
+
+static u32 armv7_aux_ctrl_read(void)
+{
+	u32 val;
+
+	asm volatile ("mrc p15, 0, %0, c1, c0, 1" : "=r"(val));
+
+	printk(KERN_INFO "ARMv7 AUX CTRL(%d): %#x\n", smp_processor_id(), val);
+
+	return val;
+}
+
+static void armv7_aux_ctrl_write(u32 val)
+{
+	printk(KERN_INFO "ARMv7 AUX CTRL(%d): %#x\n", smp_processor_id(), val);
+	asm volatile ("mcr p15, 0, %0, c1, c0, 1" : : "r"(val));
+}
+
+static void armv7_aux_ctrl_setup(void *info)
+{
+	u32 aux_ctrl;
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	aux_ctrl = armv7_aux_ctrl_read();
+
+#ifdef CONFIG_PL310_FULL_LINE_OF_ZERO
+	aux_ctrl |= (1 << 3);
+#endif
+
+#ifdef CONFIG_PL310_EXCLUSIVE_CACHE
+	aux_ctrl |= (1 << 7);
+#endif
+
+	armv7_aux_ctrl_write(aux_ctrl);
+
+	local_irq_restore(flags);
+}
+
+#ifdef CONFIG_CACHE_L2X0
+void l2x0_latency(u32 tag_ram_setup_lat, u32 tag_ram_rd_lat, u32 tag_ram_wr_lat, u32 data_ram_setup_lat, u32 data_ram_rd_lat, u32 data_ram_wr_lat)
+{
+	u32 val;
+
+	val = ((tag_ram_wr_lat - 1) << COMCERTO_L2CC_WR_LAT_SHIFT) | ((tag_ram_rd_lat - 1) << COMCERTO_L2CC_RD_LAT_SHIFT) | (tag_ram_setup_lat - 1);
+	writel(val, l2cache_base + L2X0_TAG_LATENCY_CTRL);
+
+	val = ((data_ram_wr_lat - 1) << COMCERTO_L2CC_WR_LAT_SHIFT) | ((data_ram_rd_lat - 1) << COMCERTO_L2CC_RD_LAT_SHIFT) | (data_ram_setup_lat - 1);
+	writel(val, l2cache_base + L2X0_DATA_LATENCY_CTRL);
+}
+
+void comcerto_l2cc_init(void)
+{
+	unsigned int aux_val, aux_mask;
+	unsigned int associativity, waysize;
+#ifdef CONFIG_L2X0_INSTRUCTION_ONLY
+	int i;
+#endif
+
+
+	l2cache_base = (void *)COMCERTO_L310_VADDR;
+	BUG_ON(!l2cache_base);
+
+	/* Set Latency of L2CC to minimum (i.e. 1 cycle) */
+	l2x0_latency(1, 1, 1, 1, 1, 1);
+
+	/* Set L2 address filtering, use L2CC M1 port for DDR accesses */
+	writel(0x80000000, l2cache_base + L2X0_ADDR_FILTER_END);
+	writel(0x00000000 | L2X0_ADDR_FILTER_EN, l2cache_base + L2X0_ADDR_FILTER_START);
+
+	associativity = (COMCERTO_L2CC_ASSOCIATIVITY_8WAY << COMCERTO_L2CC_ASSOCIATIVITY_SHIFT) & COMCERTO_L2CC_ASSOCIATIVITY_MASK;
+	waysize = (COMCERTO_L2CC_ASSOCIATIVITY_32KB << COMCERTO_L2CC_WAYSIZE_SHIFT) & COMCERTO_L2CC_WAYSIZE_MASK;
+	aux_val = associativity | waysize;
+	aux_mask = (COMCERTO_L2CC_ASSOCIATIVITY_MASK | COMCERTO_L2CC_WAYSIZE_MASK);
+
+	/* Shareable attribute override enable */
+	/* This prevents the cache from changing "normal memory/non-cacheable" accesses to
+	"normal memory/cacheable/writethrough no read/write allocate"*/
+	aux_val |= (1 << 22);
+	aux_mask |= (1 << 22);
+
+	/* Write allocate override, no write allocate */
+	aux_val |= (1 << 23);
+	aux_mask |= (3 << 23);
+
+#ifdef CONFIG_PL310_FULL_LINE_OF_ZERO
+	aux_val |= (1 << 0);
+	aux_mask |= (1 << 0);
+#endif
+
+#ifdef CONFIG_PL310_EARLY_WRITE_RESPONSE
+	aux_val |= (1 << 30);
+	aux_mask |= (1 << 30);
+#endif
+
+#ifdef CONFIG_PL310_STORE_BUFFER_DEVICE_LIMITATION
+	aux_val |= (1 << 11);
+	aux_mask |= (1 << 11);
+#endif
+
+#ifdef CONFIG_PL310_INSTRUCTION_PREFETCH
+	aux_val |= (1 << 29);
+	aux_mask |= (1 << 29);
+#endif
+
+#ifdef CONFIG_PL310_DATA_PREFETCH
+	aux_val |= (1 << 28);
+	aux_mask |= (1 << 28);
+#endif
+
+
+#ifdef CONFIG_PL310_EXCLUSIVE_CACHE
+	aux_val |= (1 << 12);
+	aux_mask |= (1 << 12);
+#endif
+
+	/* L2 8-way associativity with 32KB way size */
+	l2x0_init(l2cache_base, aux_val, aux_mask);
+
+#ifdef CONFIG_L2X0_INSTRUCTION_ONLY
+	for (i = 0; i < 8; i++)
+		writel_relaxed(0xffff, l2cache_base + L2X0_LOCKDOWN_WAY_D_BASE + i * L2X0_LOCKDOWN_STRIDE);
+
+	outer_flush_all();
+#endif
+
+	armv7_aux_ctrl_setup(NULL);
+
+	smp_call_function(armv7_aux_ctrl_setup, NULL, 1);
+}
+#endif
+
+#if defined(CONFIG_COMCERTO_SATA)
+
+#define SERDES_PHY1     1
+#define SERDES_PHY2     2
+
+static int comcerto_ahci_init(struct device *dev, void __iomem *mmio)
+{
+	struct serdes_regs_s *p_sata_phy_reg_file;
+	int serdes_regs_size;
+        u32 val;
+	int ref_clk_24;
+
+	/* Move SATA controller to DDRC2 port */
+	writel(readl(COMCERTO_GPIO_FABRIC_CTRL_REG) | 0x2, COMCERTO_GPIO_FABRIC_CTRL_REG);
+
+	val = readl(COMCERTO_GPIO_SYSTEM_CONFIG);
+	ref_clk_24 = val & (BIT_5_MSK|BIT_7_MSK);
+
+	if(ref_clk_24)
+	{
+		p_sata_phy_reg_file = &sata_phy_reg_file_24[0];
+		serdes_regs_size = sizeof(sata_phy_reg_file_24);
+		printk(KERN_INFO "SATA Serdes: 24Mhz ref clk\n");
+	}
+	else
+	{
+		p_sata_phy_reg_file = &sata_phy_reg_file_48[0];
+		serdes_regs_size = sizeof(sata_phy_reg_file_48);
+		printk(KERN_INFO "SATA Serdes: 48Mhz ref clk\n");
+	}
+
+	//Take SATA AXI domain out of reset
+	c2000_block_reset(COMPONENT_AXI_SATA,0);
+	//Bring SATA PMU and OOB out of reset
+	c2000_block_reset(COMPONENT_SATA_PMU,0);
+	c2000_block_reset(COMPONENT_SATA_OOB,0);
+
+        if ( (val & BOOT_SERDES1_CNF_SATA0) || (!(val & BOOT_SERDES2_CNF_SATA1)))
+        {
+                if (val & BOOT_SERDES1_CNF_SATA0)
+                {
+			//Bring Serdes1 out of reset
+			c2000_block_reset(COMPONENT_SERDES1,0);
+			//Bring SATA0 out of reset
+			c2000_block_reset(COMPONENT_SERDES_SATA0,0);
+
+                        /* Serdes Initialization. */
+                        if( serdes_phy_init(SERDES_PHY1,  p_sata_phy_reg_file,
+                                                serdes_regs_size / sizeof(serdes_regs_t),
+                                                SD_DEV_TYPE_SATA) )
+                        {
+                                printk(KERN_ERR "%s: Failed to initialize serdes1 !!\n", __func__);
+                                return -1;
+                        }
+
+                }
+
+                if (!(val & BOOT_SERDES2_CNF_SATA1))
+                {
+			//Bring Serdes2 out of reset
+			c2000_block_reset(COMPONENT_SERDES2,0);
+			//Bring SATA1 out of reset
+			c2000_block_reset(COMPONENT_SERDES_SATA1,0);
+
+                        /* Serdes Initialization. */
+                        if( serdes_phy_init(SERDES_PHY2,  p_sata_phy_reg_file,
+                                                serdes_regs_size / sizeof(serdes_regs_t),
+                                                SD_DEV_TYPE_SATA) )
+                        {
+                                printk(KERN_ERR "%s: Failed to initialize serdes2 !!\n", __func__);
+                                return -1;
+                        }
+                }
+        } else
+                return -1;
+
+        return 0;
+}
+#endif
+
+#if defined(CONFIG_COMCERTO_UART0_SUPPORT) || defined(CONFIG_COMCERTO_UART1_SUPPORT)
+#define UART_DWC_USR	0x1F
+static int fastuart_handle_irq(struct uart_port *p)
+{
+	unsigned int iir = p->serial_in(p, UART_IIR);
+	unsigned int dummy;
+	if (serial8250_handle_irq(p, iir)) {
+		return 1;
+	} else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
+		/* Clear the USR */
+		dummy = p->serial_in(p, UART_DWC_USR);
+		return 1;
+	}
+
+	return 0;
+}
+#endif
+
+static struct resource comcerto_pmu_resources[] = {
+	{
+		.start	= IRQ_A9_PMU0,
+		.end	= IRQ_A9_PMU0,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= IRQ_A9_PMU1,
+		.end	= IRQ_A9_PMU1,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device comcerto_pmu = {
+	.name		= "arm-pmu",
+	.id		= ARM_PMU_DEVICE_CPU,
+	.num_resources = ARRAY_SIZE(comcerto_pmu_resources),
+	.resource = comcerto_pmu_resources,
+};
+
+/* --------------------------------------------------------------------
+ *  Serial interface
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_COMCERTO_UART0_SUPPORT) || defined(CONFIG_COMCERTO_UART1_SUPPORT)
+static struct plat_serial8250_port comcerto_uart_data[] = {
+#ifdef CONFIG_COMCERTO_UART1_SUPPORT
+        {
+                .mapbase        = COMCERTO_AXI_UART1_BASE,
+		.membase	= (void *)COMCERTO_AXI_UART1_VADDR,
+                .irq            = IRQ_UART1,
+		.handle_irq	= fastuart_handle_irq,
+                .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP,
+                .iotype         = UPIO_MEM,
+                .regshift       = 2,
+        },
+#endif
+#ifdef CONFIG_COMCERTO_UART0_SUPPORT
+        {
+                .mapbase        = COMCERTO_AXI_UART0_BASE,
+                .membase        = (void *)COMCERTO_AXI_UART0_VADDR,
+                .irq            = IRQ_UART0,
+		.handle_irq	= fastuart_handle_irq,
+                .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP,
+                .iotype         = UPIO_MEM,
+                .regshift       = 2,
+	},
+#endif
+	{
+		.flags          = 0,
+	},
+};
+
+static struct platform_device comcerto_uart = {
+	.name       = "serial8250",
+	.id         = PLAT8250_DEV_PLATFORM,
+	.dev = {
+		.platform_data	= comcerto_uart_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_COMCERTO_MSP
+static struct resource comcerto_ved_resources[] = {
+	{
+		.name  = "voip",
+		.start = COMCERTO_MSP_DDR_BASE,
+		.end   = COMCERTO_MSP_DDR_BASE + COMCERTO_MSP_DDR_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name  = "irq",
+		.start = IRQ_PTP0,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device comcerto_ved = {
+	.name = "ved",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(comcerto_ved_resources),
+	.resource = comcerto_ved_resources,
+};
+#endif  /* CONFIG_COMCERTO_MSP */
+
+
+/* --------------------------------------------------------------------
+ *  USB 3.0 Host
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_COMCERTO_USB3_SUPPORT)
+static struct resource comcerto_usb3_resource[] = {
+        [0] = {
+                .start  = COMCERTO_AXI_USB3P0_BASE,
+                .end    = COMCERTO_AXI_USB3P0_BASE + SZ_8M - 1,
+                .flags  = IORESOURCE_MEM,
+        },
+        [1] = {
+                .start  = IRQ_USB3,
+                .end    = IRQ_USB3,
+                .flags  = IORESOURCE_IRQ,
+        },
+};
+
+static u64 comcerto_usb3_dmamask = 0xfffff000;
+
+struct platform_device comcerto_device_usb3 = {
+        .name           = "xhci-hcd",
+        .id             = -1,
+        .resource       = comcerto_usb3_resource,
+        .num_resources  = ARRAY_SIZE(comcerto_usb3_resource),
+        .dev            = {
+                .dma_mask               = &comcerto_usb3_dmamask,
+                .coherent_dma_mask      = DMA_BIT_MASK(32),
+        },
+};
+#endif
+
+/* --------------------------------------------------------------------
+ *  USB 2.0 Host 
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_COMCERTO_USB2_SUPPORT)
+
+static u64 comcerto_dwc_otg_dmamask = 0xFFFFFFFF /*DMA_BIT_MASK(32)*/;
+
+static struct resource comcerto_dwc_otg_resources[] = {
+	{
+		.start	= COMCERTO_AXI_USB2P0_BASE,
+		.end	= COMCERTO_AXI_USB2P0_BASE + 0xFFFFFF,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.start	= IRQ_USB2,
+		.end	= IRQ_USB2,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device comcerto_dwc_otg_device = {
+	.name			= "dwc_otg",
+	.resource		= comcerto_dwc_otg_resources,
+	.num_resources	= ARRAY_SIZE(comcerto_dwc_otg_resources),
+	.dev = {
+		.platform_data = NULL,
+        .dma_mask               = &comcerto_dwc_otg_dmamask,
+        .coherent_dma_mask      = DMA_BIT_MASK(32),
+	}
+};
+#endif
+
+#if defined(CONFIG_COMCERTO_SATA)
+static struct ahci_platform_data comcerto_ahci_pdata = {
+        .init = comcerto_ahci_init,
+};
+
+static struct resource comcerto_ahci_resource[] = {
+        [0] = {
+                .start  = COMCERTO_AXI_SATA_BASE,
+                .end    = COMCERTO_AXI_SATA_BASE + SZ_64K - 1,
+                .flags  = IORESOURCE_MEM,
+        },
+        [1] = {
+                .start  = IRQ_SATA,
+                .end    = IRQ_SATA,
+                .flags  = IORESOURCE_IRQ,
+        },
+};
+
+static u64 comcerto_ahci_dmamask = DMA_BIT_MASK(32);
+
+struct platform_device comcerto_device_ahci = {
+        .name           = "ahci",
+        .id             = -1,
+        .resource       = comcerto_ahci_resource,
+        .num_resources  = ARRAY_SIZE(comcerto_ahci_resource),
+        .dev            = {
+                .platform_data          = &comcerto_ahci_pdata,
+                .dma_mask               = &comcerto_ahci_dmamask,
+                .coherent_dma_mask      = DMA_BIT_MASK(32),
+        },
+};
+#endif
+
+/* --------------------------------------------------------------------
+ *  XOR Engine
+ * -------------------------------------------------------------------- */
+
+static struct resource comcerto_xor_resource[] = {
+		{
+				.name  = "xor base address",
+				.start = COMCERTO_APB_MDMA_BASE,
+				.end   = COMCERTO_APB_MDMA_BASE + COMCERTO_APB_MDMA_SIZE - 1,
+				.flags = IORESOURCE_MEM,
+		},
+		{
+				.name  = "IO2M IRQ",
+				.start = IRQ_MDMA_IO2M,
+				.flags = IORESOURCE_IRQ,
+		},
+};
+
+static u64 comcerto_xor_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device comcerto_xor_device = {
+	.name       = "comcerto_xor",
+	.id         = 0,
+	.dev        = {
+		.dma_mask    = &comcerto_xor_dma_mask,
+		.coherent_dma_mask    = DMA_BIT_MASK(32),
+	},
+	.num_resources  = ARRAY_SIZE(comcerto_xor_resource),
+	.resource = comcerto_xor_resource,
+};
+
+/* --------------------------------------------------------------------
+ *  Basic C2K MDMA Engine
+ * -------------------------------------------------------------------- */
+
+static struct resource comcerto_dma_resource[] = {
+		{
+				.name  = "c2k mdma base address",
+				.start = COMCERTO_APB_MDMA_BASE,
+				.end   = COMCERTO_APB_MDMA_BASE + COMCERTO_APB_MDMA_SIZE - 1,
+				.flags = IORESOURCE_MEM,
+		},
+		{
+				.name  = "IO2M IRQ",
+				.start = IRQ_MDMA_IO2M,
+				.flags = IORESOURCE_IRQ,
+		},
+};
+
+static u64 comcerto_dma_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device comcerto_dma_device = {
+	.name       = "comcerto_dma",
+	.id         = 0,
+	.dev        = {
+		.dma_mask    = &comcerto_dma_dma_mask,
+		.coherent_dma_mask    = DMA_BIT_MASK(32),
+	},
+	.num_resources  = ARRAY_SIZE(comcerto_dma_resource),
+	.resource = comcerto_dma_resource,
+};
+
+#if defined(CONFIG_COMCERTO_EPAVIS)
+static u64 comcerto_epavis_cie_dmamask = DMA_BIT_MASK(32);
+
+struct platform_device comcerto_device_epavis_cie = {
+        .name           = "lc_cie",
+        .id             = -1,
+        .dev            = {
+                .platform_data          = NULL,
+                .dma_mask               = &comcerto_epavis_cie_dmamask,
+                .coherent_dma_mask      = DMA_BIT_MASK(32),
+        },
+};
+static u64 comcerto_epavis_decomp_dmamask = DMA_BIT_MASK(32);
+
+struct platform_device comcerto_device_epavis_decomp = {
+        .name           = "lc_decomp",
+        .id             = -1,
+        .dev            = {
+                .platform_data          = NULL,
+                .dma_mask               = &comcerto_epavis_decomp_dmamask,
+                .coherent_dma_mask      = DMA_BIT_MASK(32),
+        },
+};
+#endif
+
+#if defined(CONFIG_COMCERTO_CSYS_TPI_CLOCK) 
+struct platform_device comcerto_device_tpi_csys_clk = {
+	.name		= "tpi_csys",
+	.id		= -1,
+	.dev		=  {
+		.platform_data		= NULL,
+	},
+};
+#endif
+
+int usb3_clk_internal = 1;
+static int __init get_usb3_clk_mode(char *str)
+{
+        if (!strcmp(str, "no"))
+                usb3_clk_internal = 0;
+
+        return 1;
+}
+
+__setup("usb3_internal_clk=", get_usb3_clk_mode);
+
+int is_mac_zero(u8 *buf)
+{
+        unsigned long dm;
+        for (dm = 0; dm < 6; dm++){
+		if ((*(buf+dm)) != 0)
+			return 1;
+	}
+	return 0;
+}
+
+static int __init mac_addr_atoi(u8 mac_addr[], char *mac_addr_str)
+{
+	int i, j, k;
+	int str_incr_cnt = 0;
+
+	if (*mac_addr_str == ',') {
+		*mac_addr_str++;
+		str_incr_cnt++;
+		return str_incr_cnt;
+	}
+
+	for (i = 0; i < 6; i++) {
+
+		j = hex_to_bin(*mac_addr_str++);
+		str_incr_cnt++;
+		if (j == -1)
+			return str_incr_cnt;
+
+		k = hex_to_bin(*mac_addr_str++);
+		str_incr_cnt++;
+		if (k == -1)
+			return str_incr_cnt;
+
+		mac_addr_str++;
+		str_incr_cnt++;
+		mac_addr[i] = (j << 4) + k;
+	}
+
+	return str_incr_cnt;
+}
+
+u8 c2k_mac_addr[3][14];
+
+static void __init mac_addr_setup(char *str)
+{
+	int str_incr_cnt = 0;
+
+	if (*str++ != '=' || !*str)  /* No mac addr specified */
+		return;
+
+	str_incr_cnt = mac_addr_atoi(c2k_mac_addr[0], str);
+
+	str += str_incr_cnt;
+
+	str_incr_cnt = mac_addr_atoi(c2k_mac_addr[1], str);
+
+	str += str_incr_cnt;
+
+	mac_addr_atoi(c2k_mac_addr[2], str);
+}
+__setup("mac_addr", mac_addr_setup);
+
+void __init mac_addr_init(struct comcerto_pfe_platform_data * comcerto_pfe_data_ptr)
+{
+	u8 gem_port_id;
+
+	for (gem_port_id = 0; gem_port_id < NUM_GEMAC_SUPPORT; gem_port_id++) {
+		if (is_mac_zero(c2k_mac_addr[gem_port_id]))  /* If mac is non-zero */
+			comcerto_pfe_data_ptr->comcerto_eth_pdata[gem_port_id].mac_addr = c2k_mac_addr[gem_port_id];
+	}
+
+}
+
+static struct platform_device *comcerto_common_devices[] __initdata = {
+#if defined(CONFIG_COMCERTO_UART0_SUPPORT) || defined(CONFIG_COMCERTO_UART1_SUPPORT)
+	&comcerto_uart,
+#endif
+#ifdef CONFIG_COMCERTO_MSP
+	&comcerto_ved,
+#endif  /* CONFIG_COMCERTO_MSP */
+	&comcerto_pmu,
+
+#if defined(CONFIG_COMCERTO_USB3_SUPPORT)
+	&comcerto_device_usb3,
+#endif
+
+#if defined(CONFIG_COMCERTO_USB2_SUPPORT)
+	&comcerto_dwc_otg_device,
+#endif	
+
+#if defined(CONFIG_COMCERTO_SATA)
+	&comcerto_device_ahci,
+#endif
+//	&comcerto_xor_device,
+	&comcerto_dma_device,
+#if defined(CONFIG_COMCERTO_EPAVIS)
+	&comcerto_device_epavis_cie,
+	&comcerto_device_epavis_decomp,
+#endif
+#if defined(CONFIG_COMCERTO_CSYS_TPI_CLOCK)
+	&comcerto_device_tpi_csys_clk,
+#endif
+};
+
+void __init device_init(void)
+{
+	/* Default value for the bit mask */
+	unsigned int default_host_utilpe_shared_bitmask = ~(USB2p0_IRQ|WOL_IRQ);
+	struct clk *axi_clk,*ddr_clk,*arm_clk,*l2cc_clk;
+	HAL_clk_div_backup_relocate_table ();
+	system_rev = (readl(COMCERTO_GPIO_DEVICE_ID_REG) >> 24) & 0xf;
+
+	/* Initialize the reset driver here */
+	reset_init();
+	
+	/* Enable the AXI,DDR,A9 susbsystem clock
+	 * this is just for s/w use count house keeping.
+	 * These clocks will never be disabled from bootloader while
+	 * booting. In fact we are keeping this because for these clocks , 
+	 * we dont have any driver to do a clk_enable. so doing  it here.
+	*/
+
+	/* Get the AXI clk structure */
+	axi_clk = clk_get(NULL,"axi");
+	if (IS_ERR(axi_clk)) {
+		pr_err("%s: Unable to obtain AXI clock: %ld\n",__func__,PTR_ERR(axi_clk));
+		/* System cannot proceed from here */
+		BUG();
+	}
+	/* Enable the AXI clk  */
+	if (clk_enable(axi_clk)){
+		pr_err("%s: Unable to enable AXI clock:\n",__func__);
+		/* System cannot proceed from here */
+		BUG();
+	}
+	
+	/* Get the DDR clock structure */
+	ddr_clk = clk_get(NULL,"ddr");
+	if (IS_ERR(ddr_clk)) {
+		pr_err("%s: Unable to obtain DDR clock: %ld\n",__func__,PTR_ERR(ddr_clk));
+		/* System cannot proceed from here */
+		BUG();
+	}
+	/* Enable the DDR clk  */
+ 	if (clk_enable(ddr_clk)){
+		pr_err("%s: Unable to enable DDR clock:\n",__func__);
+		/* System cannot proceed from here */
+		BUG();
+	}
+	
+	/* Get the CPU(A9) clock */
+	arm_clk = clk_get(NULL,"arm");
+	if (IS_ERR(arm_clk)) {
+		pr_err("%s: Unable to obtain A9(arm) clock: %ld\n",__func__,PTR_ERR(arm_clk));
+		/* System cannot proceed from here */
+		BUG();
+	}
+	/* Enable the ARM clk  */
+	if (clk_enable(arm_clk)){
+		pr_err("%s: Unable to enable A9(arm) clock:\n",__func__);
+		/* System cannot proceed from here */
+		BUG();
+	}
+
+	/* Get the L2CC clock */
+	l2cc_clk = clk_get(NULL,"l2cc");
+	if (IS_ERR(l2cc_clk)) {
+		pr_err("%s: Unable to obtain L2CC clock: %ld\n",__func__,PTR_ERR(l2cc_clk));
+		/* L2CC initilization cannot proceed from here */
+		BUG();
+	}
+
+	/* Enable the L2CC clk  */
+	if (clk_enable(l2cc_clk)){
+		pr_err("%s: Unable to enable L2CC clock:\n",__func__);
+		/* L2CC initilization cannot proceed from here */
+		BUG();
+	}
+	
+#ifdef CONFIG_CACHE_L2X0
+	comcerto_l2cc_init();
+#endif
+
+	exp_bus_init();
+
+	gpio_init();
+
+#ifdef CONFIG_COMCERTO_TDM_CLOCK
+	// [FIXME] Take TDM out of reset
+	//writel(readl(COMCERTO_BLOCK_RESET_REG) | TDM_RST, COMCERTO_BLOCK_RESET_REG);
+#endif
+	/* Default bit mask is applied here , which will be passed to Util-Pe*/
+	c2k_pm_bitmask_store(default_host_utilpe_shared_bitmask);
+
+	platform_add_devices(comcerto_common_devices, ARRAY_SIZE(comcerto_common_devices));
+}
+
+void __init platform_reserve(void)
+{
+	/* Allocate DDR block used by PFE/MSP, the base address is fixed so that util-pe code can
+	be linked at a fixed address */
+	if (memblock_reserve(COMCERTO_DDR_SHARED_BASE, COMCERTO_DDR_SHARED_SIZE) < 0)
+		BUG();
+
+	if (memblock_free(COMCERTO_DDR_SHARED_BASE, COMCERTO_DDR_SHARED_SIZE) < 0)
+		BUG();
+
+	if (memblock_remove(COMCERTO_DDR_SHARED_BASE, COMCERTO_DDR_SHARED_SIZE) < 0)
+		BUG();
+}
diff --git a/arch/arm/mach-comcerto/comcerto-tpicsys.c b/arch/arm/mach-comcerto/comcerto-tpicsys.c
new file mode 100644
index 0000000..e11e4f8
--- /dev/null
+++ b/arch/arm/mach-comcerto/comcerto-tpicsys.c
@@ -0,0 +1,118 @@
+/*
+ *  linux/arch/arm/mach-comcerto/comcerto-tpicsys.c
+ *
+ *  Copyright (C) 2008 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/err.h>
+#include <linux/module.h>
+
+struct clk *clk_tpi,*clk_csys;
+
+static int tpi_csys_probe(struct platform_device *pdev)
+{
+	int err=0;
+	/* Get the refrence to TPI clk structure */
+	clk_tpi = clk_get(NULL,"tpi");
+
+	/* Error Handling , if no TPI clock reference: return error */
+	if (IS_ERR(clk_tpi)) {
+		pr_err("%s: Unable to obtain  clock: %ld\n",__func__,PTR_ERR(clk_tpi));
+		err = PTR_ERR(clk_tpi);
+		goto err_tpi_get;
+	}
+
+	/* Enable the TPI clock ,required for cortex A9 JTAG */
+	err = clk_enable(clk_tpi);
+	if (err){
+		pr_err("%s: TPI clock failed to enable:\n",__func__);
+		goto err_tpi_enable;
+	}
+
+	/* Get the CSYS clk structure ,required ofr cortex A9 coresight*/
+	clk_csys = clk_get(NULL,"csys");
+
+	/* Error Handling , if no CSYS clock reference: return error 
+	 * Disable the TPI clock enabled before. 
+	 */
+	if (IS_ERR(clk_csys)) {
+		pr_err("%s: Unable to obtain  clock: %ld\n",__func__,PTR_ERR(clk_csys));
+		err = PTR_ERR(clk_csys);
+ 		goto err_csys_get;
+	}
+
+	/*Enable the  CSYS clock */
+	err = clk_enable(clk_csys);
+	if (err){
+		pr_err("%s: CSYS clock failed to enable:\n",__func__);
+		/* Disable the CSYS(A9 coresight clock also */ 
+		goto err_csys_enable;
+	}
+
+	return 0;
+
+err_csys_enable:
+	clk_put(clk_csys);
+err_csys_get:
+	clk_disable(clk_tpi);
+err_tpi_enable:
+	clk_put(clk_tpi);
+err_tpi_get:
+	return err;
+}
+
+static int tpi_csys_remove(struct platform_device *pdev)
+{
+
+	/* Disable the TPI/CSYS clock */
+	clk_disable(clk_tpi);
+	clk_put(clk_tpi);
+
+	clk_disable(clk_csys);
+	clk_put(clk_csys);
+
+	return 0;
+}
+	
+
+/* Structure for Device Driver */
+static struct platform_driver tpi_csys_platform_driver = {
+	.probe = tpi_csys_probe,
+	.remove = tpi_csys_remove,
+	.driver = {
+		.name = "tpi_csys",
+	},	
+};
+
+static int comcerto_tpi_csys_init(void)
+{
+	return platform_driver_register(&tpi_csys_platform_driver);
+}
+
+static void comcerto_tpi_csys_exit(void)
+{
+	platform_driver_unregister(&tpi_csys_platform_driver);
+}
+
+module_init(comcerto_tpi_csys_init);
+module_exit(comcerto_tpi_csys_exit);
+
+MODULE_DESCRIPTION("Comcerto TPI/CSYS");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-comcerto/comcerto-vwd.c b/arch/arm/mach-comcerto/comcerto-vwd.c
new file mode 100644
index 0000000..c5431d9
--- /dev/null
+++ b/arch/arm/mach-comcerto/comcerto-vwd.c
@@ -0,0 +1,55 @@
+/*
+ *  linux/arch/arm/mach-comcerto/comcerto-vwd.c
+ *
+ *  Copyright (C) 2011 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/module.h>
+
+
+static int comcerto_wifi_rx_dummy_hdlr(int (*hdlr)(struct sk_buff *skb));
+static int (*vwd_rx_hdlr)(struct sk_buff *) = comcerto_wifi_rx_dummy_hdlr;
+
+static int comcerto_wifi_rx_dummy_hdlr(int (*hdlr)(struct sk_buff *skb))
+{
+	return -1;
+}
+
+int comcerto_wifi_rx_fastpath_register(int (*hdlr)(struct sk_buff *skb))
+{
+	printk(KERN_INFO "%s:%d VWD Tx function registered\n", __func__, __LINE__ );
+	vwd_rx_hdlr = hdlr;
+
+	return 0;
+}
+
+void comcerto_wifi_rx_fastpath_unregister(void)
+{
+	printk(KERN_INFO "%s:%d VWD Tx function unregistered\n", __func__, __LINE__ );
+	vwd_rx_hdlr = comcerto_wifi_rx_dummy_hdlr;
+
+	return;
+}
+
+int comcerto_wifi_rx_fastpath(struct sk_buff *skb)
+{
+	return vwd_rx_hdlr(skb);
+
+}
+
+EXPORT_SYMBOL(comcerto_wifi_rx_fastpath_register);
+EXPORT_SYMBOL(comcerto_wifi_rx_fastpath_unregister);
+EXPORT_SYMBOL(comcerto_wifi_rx_fastpath);
diff --git a/arch/arm/mach-comcerto/dma.c b/arch/arm/mach-comcerto/dma.c
new file mode 100644
index 0000000..9911c9b
--- /dev/null
+++ b/arch/arm/mach-comcerto/dma.c
@@ -0,0 +1,214 @@
+/*
+;=======================================================================
+;        Filename : dma.c
+;        Purpose  : DW DMA APIs for Fast SPI and Fast UART.
+;======================================================================
+*/
+
+#include <mach/serial.h>
+#include <mach/hardware.h>
+#include <mach/dma.h>
+#include <asm/io.h>
+#include <linux/module.h>
+
+
+
+
+/*
+ ********************************************
+ * dma_ssi_xfer_cmplete_chk ()
+ *
+ * Check for the complete of DMA data xfer on given channal no.
+ *
+ ********************************************
+ */
+retcode dma_xfer_cmplete_chk(unsigned int ch_no)
+{
+        unsigned int channel_status = 0xF;
+
+        while(channel_status != 0x0)
+        {
+                channel_status = readl(DW_DMA_DMAC_CH_EN_REG);
+		channel_status = channel_status & ((1 << ch_no) & 0xFF);
+	}
+
+	return RETCODE_OK;
+}
+
+EXPORT_SYMBOL(dma_xfer_cmplete_chk);
+
+/*
+ ****************************************
+ *   dma_configure ()
+ *
+ *   Single-block Transfer -- without write-back of control
+ *   and status information enabled at the end of the single-block transfer
+ ****************************************
+ */
+void dma_configure(unsigned int source_add, unsigned int target_add, unsigned int data_len, unsigned int ch_no)
+{
+	unsigned int dma_channel = (1 << ch_no) & 0xFF ;
+	unsigned int ch_reg_multiplier = 0;
+	unsigned int ch_ctrl_l = 0;
+	unsigned int ch_cfg_l = 0;
+	unsigned int ch_cfg_h = 0;
+
+	/* DMA enable */
+	writel(DMA_GLOBAL_ENABLE, DW_DMA_DMAC_DMA_CFG_REG);
+
+	/* verify channel is not busy, done with last transaction */
+	dma_xfer_cmplete_chk(ch_no);
+
+	/* Configure DMA handshaking */
+
+	/* Writing a 1 to the Last Destination Transaction Request Register initiates a transaction. */
+	writel(((dma_channel << DMA_REG_WE_SHIFT) | (0x0 & 0xFF)), DW_DMA_DMAC_LST_DST_REG);
+
+/* The type of transaction, single or burst, depends on the state of the corresponding channel bit
+ * in the Single Source/Destination Transaction Request register.
+ */
+	writel(((dma_channel << DMA_REG_WE_SHIFT) | (0x0 & 0xFF)), DW_DMA_DMAC_SGL_REQ_DST_REG);
+
+	/* Clear Interrupts on the channal */
+
+	/* Clear for IntTfr Interrupt */
+	writel(dma_channel, DW_DMA_DMAC_CLEAR_TFR);
+	/* Clear for IntBlock Interrupt */
+	writel(dma_channel, DW_DMA_DMAC_CLEAR_BLK);
+	/* Clear for IntSrcTran Interrupts */
+	writel(dma_channel, DW_DMA_DMAC_CLEAR_SRC_TRAN);
+	/* Clear for IntDstTran Interrupt */
+	writel(dma_channel, DW_DMA_DMAC_CLEAR_DST_TRAN);
+	/* Clear for IntErr Interrupt */
+	writel(dma_channel, DW_DMA_DMAC_CLEAR_ERR);
+
+	/* Set up Interrupt Mask registers */
+
+	/* Mask for IntTfr Interrupt */
+	writel(((dma_channel << DMA_REG_WE_SHIFT) | (0x0 & 0xFF)), DW_DMA_DMAC_MASK_TFR);
+	/* Mask for IntBlock Interrupt */
+	writel(((dma_channel << DMA_REG_WE_SHIFT) | dma_channel), DW_DMA_DMAC_MASK_BLOCK);
+	/* Mask for IntSrcTran Interrupt */
+	writel(((dma_channel << DMA_REG_WE_SHIFT) | dma_channel), DW_DMA_DMAC_MASK_SRC_TRAN);
+	/* Mask for IntDstTran Interrupt */
+	writel(((dma_channel << DMA_REG_WE_SHIFT) | dma_channel), DW_DMA_DMAC_MASK_DST_TRAN);
+	/* Mask for IntErr Interrupt */
+	writel(((dma_channel << DMA_REG_WE_SHIFT) | (0x0 & 0xFF)), DW_DMA_DMAC_MASK_ERR);
+
+	/* configure channel specific registers */
+	if( ch_no != 0 )
+	{
+		ch_reg_multiplier = (DMA_CHANNEL_REG_COUNT << 3) ;
+		ch_reg_multiplier = ch_no * ch_reg_multiplier;
+	}
+
+	/* configure : Source Address Register for Channel */
+
+/* The starting source address is programmed before the DMA channel is enabled. While the DMA transfer is in
+ * progress, this register is updated to reflect the source address of the current AHB transfer.
+ */
+	/* SAR Address must be alligned to DMA_CTL_SRC_TR_WIDTH boundry */
+	writel(source_add, (DMA_CHANNEL_REG_SAR_BASE + ch_reg_multiplier));
+
+	/* configure : Destination Address Register for Channel */
+
+/* The starting destination address is programmed before the DMA channel is enabled. While the DMA transfer is in
+ * progress, this register is updated to reflect the destination address of the current AHB transfer.
+ */
+	/* DAR Address must be alligned to DMA_CTL_DST_TR_WIDTH boundry */
+	writel(target_add, (DMA_CHANNEL_REG_DAR_BASE + ch_reg_multiplier));
+
+
+	/* configure : Control Register for Channel [32-63] */
+/* The number programmed into BLOCK_TS indicates the total number of single transactions
+ * to perform for every block transfer; a single transaction is mapped to a single AMBA beat.
+ */
+	writel(data_len, (DMA_CHANNEL_REG_CTL_BASE + ch_reg_multiplier + ch_no));
+
+	/* configure : Control Register for Channel [0-31] */
+	ch_ctrl_l = (((DMA_CTL_INT_EN & DMA_CTL_INT_EN_MASK) << DMA_CTL_INT_EN_SHIFT) |
+				((DMA_CTL_DST_TR_WIDTH & DMA_CTL_DST_TR_WIDTH_MASK) << DMA_CTL_DST_TR_WIDTH_SHIFT) |
+				((DMA_CTL_SRC_TR_WIDTH & DMA_CTL_SRC_TR_WIDTH_MASK) << DMA_CTL_SRC_TR_WIDTH_SHIFT) |
+				((DMA_CTL_DINC & DMA_CTL_DINC_MASK) << DMA_CTL_DINC_SHIFT) |
+				((DMA_CTL_SINC & DMA_CTL_SINC_MASK) << DMA_CTL_SINC_SHIFT) |
+				((DMA_CTL_DEST_MSIZE & DMA_CTL_DEST_MSIZE_MASK) << DMA_CTL_DEST_MSIZE_SHIFT) |
+				((DMA_CTL_SRC_MSIZE & DMA_CTL_SRC_MSIZE_MASK) << DMA_CTL_SRC_MSIZE_SHIFT) |
+				((DMA_CTL_SRC_GATHER_EN & DMA_CTL_SRC_GATHER_EN_MASK) << DMA_CTL_SRC_GATHER_EN_SHIFT) |
+				((DMA_CTL_DST_SCATTER_EN & DMA_CTL_DST_SCATTER_EN_MASK) << DMA_CTL_DST_SCATTER_EN_SHIFT) |
+				((DMA_CTL_TT_FC & DMA_CTL_TT_FC_MASK) << DMA_CTL_TT_FC_SHIFT) |
+				((DMA_CTL_DMS & DMA_CTL_DMS_MASK) << DMA_CTL_DMS_SHIFT) |
+				((DMA_CTL_SMS & DMA_CTL_SMS_MASK) << DMA_CTL_SMS_SHIFT) |
+				((DMA_CTL_LLP_DST_EN & DMA_CTL_LLP_DST_EN_MASK) << DMA_CTL_LLP_DST_EN_SHIFT) |
+				((DMA_CTL_LLP_SRC_EN & DMA_CTL_LLP_SRC_EN_MASK) << DMA_CTL_LLP_SRC_EN_SHIFT));
+
+	writel(ch_ctrl_l, (DMA_CHANNEL_REG_CTL_BASE + ch_reg_multiplier));
+
+	/* configure : Linked List Pointer Register for Channel */
+	writel(0x0, (DMA_CHANNEL_REG_LLP_BASE + ch_reg_multiplier));
+
+	/* configure : Configuration Register for Channel [32-63] */
+	ch_cfg_h = (((DMA_CFG_FCMODE & DMA_CFG_FCMODE_MASK) << DMA_CFG_FCMODE_SHIFT) |
+			   ((DMA_CFG_FIFO_MODE & DMA_CFG_FIFO_MODE_MASK) << DMA_CFG_FIFO_MODE_SHIFT) |
+			   ((DMA_CFG_PROTCTL & DMA_CFG_PROTCTL_MASK) << DMA_CFG_PROTCTL_SHIFT) |
+			   ((DMA_CFG_DS_UPD_EN & DMA_CFG_DS_UPD_EN_MASK) << DMA_CFG_DS_UPD_EN_SHIFT) |
+			   ((DMA_CFG_SS_UPD_EN & DMA_CFG_SS_UPD_EN_MASK) << DMA_CFG_SS_UPD_EN_SHIFT) |
+			   ((ch_no /*DMA_CFG_SRC_PER*/ & DMA_CFG_SRC_PER_MASK) << DMA_CFG_SRC_PER_SHIFT) |
+			   ((DMA_CFG_DEST_PER & DMA_CFG_DEST_PER_MASK) << DMA_CFG_DEST_PER_SHIFT));
+
+	writel(ch_cfg_h, (DMA_CHANNEL_REG_CFG_BASE + ch_reg_multiplier + ch_no));
+
+	/* configure : Configuration Register for Channel [0-31] */
+	ch_cfg_l = (((ch_no & DMA_CFG_CH_PRIOR_MASK) << DMA_CFG_CH_PRIOR_SHIFT) |
+			   ((DMA_CFG_CH_SUSP & DMA_CFG_CH_SUSP_MASK) << DMA_CFG_CH_SUSP_SHIFT) |
+			   ((DMA_CFG_FIFO_EMPTY & DMA_CFG_FIFO_EMPTY_MASK) << DMA_CFG_FIFO_EMPTY_SHIFT) |
+			   ((DMA_CFG_HS_SEL_DST & DMA_CFG_HS_SEL_DST_MASK) << DMA_CFG_HS_SEL_DST_SHIFT) |
+			   ((DMA_CFG_HS_SEL_SRC & DMA_CFG_HS_SEL_SRC_MASK) << DMA_CFG_HS_SEL_SRC_SHIFT) |
+			   ((DMA_CFG_LOCK_CH_L & DMA_CFG_LOCK_CH_L_MASK) << DMA_CFG_LOCK_CH_L_SHIFT) |
+			   ((DMA_CFG_LOCK_B_L & DMA_CFG_LOCK_B_L_MASK) << DMA_CFG_LOCK_B_L_SHIFT) |
+			   ((DMA_CFG_LOCK_CH & DMA_CFG_LOCK_CH_MASK) << DMA_CFG_LOCK_CH_SHIFT) |
+			   ((DMA_CFG_LOCK_B & DMA_CFG_LOCK_B_MASK) << DMA_CFG_LOCK_B_SHIFT) |
+			   ((DMA_CFG_DST_HS_POL & DMA_CFG_DST_HS_POL_MASK) << DMA_CFG_DST_HS_POL_SHIFT) |
+			   ((DMA_CFG_SRC_HS_POL & DMA_CFG_SRC_HS_POL_MASK) << DMA_CFG_SRC_HS_POL_SHIFT) |
+			   ((DMA_CFG_MAX_ABRST & DMA_CFG_MAX_ABRST_MASK) << DMA_CFG_MAX_ABRST_SHIFT) |
+			   ((DMA_CFG_RELOAD_SRC & DMA_CFG_RELOAD_SRC_MASK) << DMA_CFG_RELOAD_SRC_SHIFT) |
+			   ((DMA_CFG_RELOAD_DST & DMA_CFG_RELOAD_DST_MASK) << DMA_CFG_RELOAD_DST_SHIFT));
+
+	writel(ch_cfg_l, (DMA_CHANNEL_REG_CFG_BASE + ch_reg_multiplier));
+
+	/* Enable the DMA channel */
+	writel(((dma_channel << DMA_REG_WE_SHIFT) | dma_channel), DW_DMA_DMAC_CH_EN_REG);
+
+	return ;
+}
+
+EXPORT_SYMBOL(dma_configure);
+
+int fast_uart_write(unsigned int len, const char *str)
+{
+	unsigned int dma_len;
+
+	while (len)
+	{
+		if (len > DMA_XFER_DLEN)
+			dma_len = DMA_XFER_DLEN;
+		else
+			dma_len = len;
+
+		while ((readl(DW_DMA_UART1_BASEADDR + UART_LSR) & LSR_TEMT) == 0) ;
+
+		dma_configure((unsigned int) str, DW_DMA_UART1_BASEADDR + UART_THR, dma_len, DMA_CHANNEL_1);
+
+		/* Wait for completion of DMA xfer (till channel is disabled by HW) */
+		if (RETCODE_OK != dma_xfer_cmplete_chk(DMA_CHANNEL_1))
+			return RETCODE_ERROR;
+
+		len -= dma_len;
+
+		str += dma_len;
+	}
+
+	return RETCODE_OK;
+}
+
+EXPORT_SYMBOL(fast_uart_write);
+
diff --git a/arch/arm/mach-comcerto/gpio.c b/arch/arm/mach-comcerto/gpio.c
new file mode 100644
index 0000000..6051dae
--- /dev/null
+++ b/arch/arm/mach-comcerto/gpio.c
@@ -0,0 +1,106 @@
+/*
+ *  linux/arch/arm/mach-comcerto/gpio.c
+ *
+ *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* [FIXME] */
+#if 0
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <linux/kernel_stat.h>
+
+#if !defined(CONFIG_ARCH_M83XXX)
+
+/* The GPIO IRQ block generates interrupts only on rising/falling edges of the GPIO pin signal.
+ * To avoid loosing interrupts or having spurious interrupts care must be taken.
+ * The general strategy is to loop and poll the GPIO pin to make sure no interrupts are missed.
+ * The GPIO IRQ must be acked inside the loop at each iteration. If it was acked
+ * before the loop there would be a race condition(1) where we exit comcerto_handle_gpio_level_irq() with
+ * the GPIO IRQ set, even if the source was already handled. If it was acked after the loop
+ * there would be a race condition(2) where we ack a GPIO IRQ but the source is not yet handled.
+ * The GPIO IRQ must be acked after all the driver handlers have been called (after handle_simple_irq())
+ * to also avoid the race mentioned in (1) above.
+ */
+
+extern int noirqdebug;
+extern int redirect_hardirq(struct irq_desc *desc);
+
+void comcerto_handle_gpio_level_irq(unsigned int irq, struct irq_desc *desc)
+{
+	struct irqaction *action;
+	irqreturn_t action_ret;
+	const unsigned int cpu = smp_processor_id();
+	u32 pending;
+
+	spin_lock(&desc->lock);
+
+	/*
+	 * Mask IRQ.
+	 */
+	desc->chip->mask(irq);
+
+	do {
+		if (unlikely(desc->status & IRQ_INPROGRESS))
+			goto out_unlock;
+		desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
+		kstat_cpu(cpu).irqs[irq]++;
+
+		action = desc->action;
+		if (unlikely(!action || (desc->status & IRQ_DISABLED))) {
+			desc->status |= IRQ_PENDING;
+			goto out_unlock;
+		}
+
+		desc->status |= IRQ_INPROGRESS;
+		/*
+		 * hardirq redirection to the irqd process context:
+		 */
+		if (redirect_hardirq(desc))
+			goto out_unlock;
+		desc->status &= ~IRQ_PENDING;
+		spin_unlock(&desc->lock);
+
+		action_ret = handle_IRQ_event(irq, action);
+		if (!noirqdebug)
+			note_interrupt(irq, desc, action_ret);
+
+		spin_lock(&desc->lock);
+		desc->status &= ~IRQ_INPROGRESS;
+
+		/*
+		 * Ack IRQ.
+		 */
+		desc->chip->ack(irq);
+		/*
+		 * Source interrupts are usually active low
+		 */
+		pending = comcerto_gpio_read(1 << ((irq - 1) & 0x1f)) ? 0 : 1;
+
+	} while (pending && !(desc->status & IRQ_DISABLED));
+
+	if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
+		desc->chip->unmask(irq);
+
+out_unlock:
+	spin_unlock(&desc->lock);
+}
+#endif
+#endif
diff --git a/arch/arm/mach-comcerto/headsmp.S b/arch/arm/mach-comcerto/headsmp.S
new file mode 100644
index 0000000..101cc49
--- /dev/null
+++ b/arch/arm/mach-comcerto/headsmp.S
@@ -0,0 +1,93 @@
+/*
+ * arch/arm/mach-transcede/headsmp.S
+ *
+ * Copyright (C) 2011 Mindspeed Technologies, Inc.
+ * Copyright (c) 2003 ARM Limited
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+#if defined(CONFIG_HOTPLUG_CPU)
+	__CPUINIT
+#else    
+	__INIT
+#endif    
+
+/*
+ * Realview specific entry point for secondary CPUs.  This provides
+ * a "holding pen" into which all secondary cores are held until we're
+ * ready for them to initialise.
+ */
+ENTRY(v7_invalidate_l1)
+	mov	r0, #0
+	mcr	p15, 2, r0, c0, c0, 0
+	mrc	p15, 1, r0, c0, c0, 0
+
+	ldr	r1, =0x7fff
+	and	r2, r1, r0, lsr #13
+
+	ldr	r1, =0x3ff
+
+	and	r3, r1, r0, lsr #3	@ NumWays - 1
+	add	r2, r2, #1		@ NumSets
+
+	and	r0, r0, #0x7
+	add	r0, r0, #4		@ SetShift
+
+	clz	r1, r3			@ WayShift
+	add	r4, r3, #1		@ NumWays
+1:	sub	r2, r2, #1		@ NumSets--
+	mov	r3, r4			@ Temp = NumWays
+2:	subs	r3, r3, #1		@ Temp--
+	mov	r5, r3, lsl r1
+	mov	r6, r2, lsl r0
+	orr	r5, r5, r6		@ Reg = (Temp<<WayShift)|(NumSets<<SetShift)
+	mcr	p15, 0, r5, c7, c6, 2
+	bgt	2b
+	cmp	r2, #0
+	bgt	1b
+	dsb
+	isb
+	mov	pc, lr
+ENDPROC(v7_invalidate_l1)
+
+
+ENTRY(comcerto_secondary_startup)
+	mov r0, #0xd3
+	msr cpsr_fsxc, r0
+	bl	v7_invalidate_l1
+	mrc	p15, 0, r0, c0, c0, 5
+	and	r0, r0, #15
+	adr	r4, 1f
+	ldmia	r4, {r5, r6}
+	sub	r4, r4, r5
+	add	r6, r6, r4
+pen:	ldr	r7, [r6]
+	cmp	r7, r0
+	bne	pen
+
+	/*
+	 * we've been released from the holding pen: secondary_stack
+	 * should now contain the SVC stack for this core
+	 */
+	b	secondary_startup
+
+1:	.long	.
+	.long	pen_release
+
diff --git a/arch/arm/mach-comcerto/hotplug.c b/arch/arm/mach-comcerto/hotplug.c
new file mode 100644
index 0000000..fed8465
--- /dev/null
+++ b/arch/arm/mach-comcerto/hotplug.c
@@ -0,0 +1,87 @@
+/*
+ * comcerto SMP cpu-hotplug support
+ *
+ * Copyright (C) 2012 Mindspeed Technologies, LTD.
+ * Author:
+ *      Satyabrata sahu <satyabrat.sahu@mindspeed.com>
+ *
+ * Platform file needed for the comcerto A9 SMP system . This file is based on arm
+ * realview smp platform.
+ * Copyright (c) 2002 ARM Limited.
+
+ * CPU-1 shutdown and reset . while makeing online , CPU-1 will be again in 
+ * out of reset mode.
+ *
+ * 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/kernel.h>
+#include <linux/errno.h>
+#include <linux/smp.h>
+#include <linux/io.h>
+
+#include <asm/cacheflush.h>
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <linux/kthread.h>  // for threads
+#include <linux/sched.h>  // for task_struct
+#include <linux/time.h>   // for using jiffies
+#include <linux/timer.h>
+
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+
+
+
+extern volatile int pen_release;
+
+extern cpu1_hotplug;
+extern u32 cpu1_hotplug_done;
+
+int platform_cpu_kill(unsigned int cpu)
+{
+	return 1;
+}
+
+/*
+ * platform-specific code to shutdown a CPU
+ * Called with IRQs disabled
+ */
+void platform_cpu_die(unsigned int cpu)
+{
+	/* Flush all cache  */
+	flush_cache_all();
+	dsb();
+
+	/*
+	 * we're ready for shutdown now, so do it
+	 */
+	
+         /* Entering to LOW power state. 
+	  * Go to Low power ,Configure the CPU to reset mode.
+	  */
+
+	if(cpu) {
+		/* Put A9 CPU-1 to reset */
+		cpu1_hotplug_done = 1;
+		wake_up(&cpu1_hotplug);
+		while(1);
+	}
+}
+
+int platform_cpu_disable(unsigned int cpu)
+{
+	/*
+	 * we don't allow CPU 0 to be shutdown (it is still too special
+	 * e.g. clock tick interrupts)
+	 */
+
+	if (!cpu)
+                pr_info("We are not allowing the CPU(%d) to shutdown. \n",cpu);
+	
+	return cpu == 0 ? -EPERM : 0;
+}
diff --git a/arch/arm/mach-comcerto/include/mach/board-c2kasic.h b/arch/arm/mach-comcerto/include/mach/board-c2kasic.h
new file mode 100644
index 0000000..c56c3c5
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/board-c2kasic.h
@@ -0,0 +1,55 @@
+/*
+ * arch/arm/mach-comcerto/include/mach/board-c2kasic.h
+ *
+ * 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.
+ */
+
+#ifndef __BOARD_C2KASIC_H__
+#define __BOARD_C2KASIC_H__
+
+#include <mach/hardware.h>
+
+	/***********************************
+	 * Expansion bus configuration
+	 ***********************************/
+
+	#define COMCERTO_EXPCLK		50000000	/* 50MHz */
+
+	/***********************************
+	 * GPIO
+	 ***********************************/
+	#define COMCERTO_OUTPUT_GPIO		(COMCERTO_NAND_CE)
+	#define COMCERTO_IRQ_RISING_EDGE_GPIO	0 // [FIXME]
+	#define COMCERTO_IRQ_FALLING_EDGE_GPIO	(GPIO_2 | GPIO_0) // [FIXME]
+	#define COMCERTO_IRQ_LEVEL_GPIO 	GPIO_2 // [FIXME]
+	/*Are pins used either as GPIO or as pins for others IP blocks*/
+	#define COMCERTO_GPIO_PIN_USAGE		(SPI_BUS) // [FIXME]
+
+	/***********************************
+	 * EEPROM
+	 ***********************************/
+
+	/***********************************
+	 * NOR
+	 ***********************************/
+	#define NORFLASH_MEMORY_PHY1		EXP_CS0_AXI_BASEADDR
+
+	/***********************************
+	 * NAND
+	 ***********************************/
+	#define COMCERTO_EXP_CS4_SEG_SZ		1
+
+	#define COMCERTO_NAND_FIO_ADDR		EXP_CS4_AXI_BASEADDR
+	#define COMCERTO_NAND_BR		0x20000000 /* BR is on GPIO_29 */
+	#define COMCERTO_NAND_CE		0x10000000 /* CE is on GPIO_28 */
+	#define COMCERTO_NAND_IO_SZ		((COMCERTO_EXP_CS4_SEG_SZ << 12) +0x1000)
+
+	/***********************************
+	 * SLIC
+	 ***********************************/
+	#define COMCERTO_SLIC_GPIO_IRQ		IRQ_G1
+
+
+#endif
diff --git a/arch/arm/mach-comcerto/include/mach/board-c2kevm.h b/arch/arm/mach-comcerto/include/mach/board-c2kevm.h
new file mode 100644
index 0000000..1e2d48f
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/board-c2kevm.h
@@ -0,0 +1,54 @@
+/*
+ * arch/arm/mach-comcerto/include/mach/board-c2kevm.h
+ *
+ * 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.
+ */
+
+#ifndef __BOARD_C2KEVM_H__
+#define __BOARD_C2KEVM_H__
+
+#include <mach/hardware.h>
+	
+	/***********************************
+	 * Expansion bus configuration
+	 ***********************************/
+	 
+	#define COMCERTO_EXPCLK		50000000	/* 50MHz */
+
+	/***********************************
+	 * GPIO
+	 ***********************************/
+	#define COMCERTO_OUTPUT_GPIO		(COMCERTO_NAND_CE)
+	#define COMCERTO_IRQ_RISING_EDGE_GPIO	0 // [FIXME]
+	#define COMCERTO_IRQ_FALLING_EDGE_GPIO	(GPIO_2 | GPIO_0) // [FIXME]
+	#define COMCERTO_IRQ_LEVEL_GPIO 	GPIO_2 // [FIXME]
+	/*Are pins used either as GPIO or as pins for others IP blocks*/
+	#define COMCERTO_GPIO_PIN_USAGE		(SPI_BUS) // [FIXME]
+
+	/***********************************
+	 * EEPROM
+	 ***********************************/
+
+	/***********************************
+	 * NOR
+	 ***********************************/
+	#define NORFLASH_MEMORY_PHY1		EXP_CS0_AXI_BASEADDR
+
+	/***********************************
+	 * NAND
+	 ***********************************/
+	#define COMCERTO_EXP_CS4_SEG_SZ		1
+
+	#define COMCERTO_NAND_FIO_ADDR		EXP_CS4_AXI_BASEADDR
+	#define COMCERTO_NAND_BR		0x20000000 /* BR is on GPIO_29 */
+	#define COMCERTO_NAND_CE		0x10000000 /* CE is on GPIO_28 */
+	#define COMCERTO_NAND_IO_SZ		((COMCERTO_EXP_CS4_SEG_SZ << 12) +0x1000)
+
+	/***********************************
+	 * SLIC
+	 ***********************************/
+	#define COMCERTO_SLIC_GPIO_IRQ		IRQ_G2
+
+#endif
diff --git a/arch/arm/mach-comcerto/include/mach/board-c2kmfcnevm.h b/arch/arm/mach-comcerto/include/mach/board-c2kmfcnevm.h
new file mode 100644
index 0000000..2c52c91
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/board-c2kmfcnevm.h
@@ -0,0 +1,54 @@
+/*
+ * arch/arm/mach-comcerto/include/mach/board-c2kmfcnevm.h
+ *
+ * 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.
+ */
+
+#ifndef __BOARD_C2KMFCNEVM_H__
+#define __BOARD_C2KMFCNEVM_H__
+
+#include <mach/hardware.h>
+	
+	/***********************************
+	 * Expansion bus configuration
+	 ***********************************/
+	 
+	#define COMCERTO_EXPCLK		50000000	/* 50MHz */
+
+	/***********************************
+	 * GPIO
+	 ***********************************/
+	#define COMCERTO_OUTPUT_GPIO		(COMCERTO_NAND_CE)
+	#define COMCERTO_IRQ_RISING_EDGE_GPIO	0 // [FIXME]
+	#define COMCERTO_IRQ_FALLING_EDGE_GPIO	(GPIO_2 | GPIO_0) // [FIXME]
+	#define COMCERTO_IRQ_LEVEL_GPIO 	GPIO_2 // [FIXME]
+	/*Are pins used either as GPIO or as pins for others IP blocks*/
+	#define COMCERTO_GPIO_PIN_USAGE		(SPI_BUS) // [FIXME]
+
+	/***********************************
+	 * EEPROM
+	 ***********************************/
+
+	/***********************************
+	 * NOR
+	 ***********************************/
+	#define NORFLASH_MEMORY_PHY1		EXP_CS0_AXI_BASEADDR
+
+	/***********************************
+	 * NAND
+	 ***********************************/
+	#define COMCERTO_EXP_CS4_SEG_SZ		1
+
+	#define COMCERTO_NAND_FIO_ADDR		EXP_CS4_AXI_BASEADDR
+	#define COMCERTO_NAND_BR		0x20000000 /* BR is on GPIO_29 */
+	#define COMCERTO_NAND_CE		0x10000000 /* CE is on GPIO_28 */
+	#define COMCERTO_NAND_IO_SZ		((COMCERTO_EXP_CS4_SEG_SZ << 12) +0x1000)
+
+	/***********************************
+	 * SLIC
+	 ***********************************/
+	#define COMCERTO_SLIC_GPIO_IRQ		IRQ_G2
+
+#endif
diff --git a/arch/arm/mach-comcerto/include/mach/board-c2krtsm.h b/arch/arm/mach-comcerto/include/mach/board-c2krtsm.h
new file mode 100644
index 0000000..b1541a4
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/board-c2krtsm.h
@@ -0,0 +1,56 @@
+/*
+ * arch/arm/mach-comcerto/include/mach/board-c2krtsm.h
+ *
+ * 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.
+ */
+
+#ifndef __BOARD_C2KRTSM_H__
+#define __BOARD_C2KRTSM_H__
+
+#include <mach/hardware.h>
+	
+	/***********************************
+	 * Expansion bus configuration
+	 ***********************************/
+	 
+	#define COMCERTO_EXPCLK		50000000	/* 50MHz */
+
+	/***********************************
+	 * GPIO
+	 ***********************************/
+	#define COMCERTO_OUTPUT_GPIO 		(COMCERTO_NAND_CE | COMCERTO_NAND_ALE | COMCERTO_NAND_CLE) // [FIXME]
+	#define COMCERTO_IRQ_RISING_EDGE_GPIO	0 // [FIXME]
+	#define COMCERTO_IRQ_FALLING_EDGE_GPIO	(GPIO_2 | GPIO_0) // [FIXME]
+	#define COMCERTO_IRQ_LEVEL_GPIO 	GPIO_2 // [FIXME]
+	/*Are pins used either as GPIO or as pins for others IP blocks*/
+	#define COMCERTO_GPIO_PIN_USAGE		(SPI_BUS) // [FIXME]
+
+	/***********************************
+	 * EEPROM
+	 ***********************************/
+	
+	/***********************************
+	 * NOR
+	 ***********************************/
+	#define NORFLASH_MEMORY_PHY1		EXP_CS0_AXI_BASEADDR
+
+	/***********************************
+	 * NAND
+	 ***********************************/
+	#define COMCERTO_EXP_CS4_SEG_SZ		1
+	
+	#define COMCERTO_NAND_FIO_ADDR		COMCERTO_EXP_CS4_BASE
+	#define COMCERTO_NAND_BR		GPIO_6
+	#define COMCERTO_NAND_CE		GPIO_29
+	#define COMCERTO_NAND_ALE		GPIO_30
+	#define COMCERTO_NAND_CLE		GPIO_31
+	#define COMCERTO_NAND_IO_SZ		((COMCERTO_EXP_CS4_SEG_SZ << 12) +0x1000)
+
+	/***********************************
+	 * SLIC
+	 ***********************************/
+	#define COMCERTO_SLIC_GPIO_IRQ		IRQ_G0
+
+#endif
diff --git a/arch/arm/mach-comcerto/include/mach/c2k_dma.h b/arch/arm/mach-comcerto/include/mach/c2k_dma.h
new file mode 100644
index 0000000..942ac7f
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/c2k_dma.h
@@ -0,0 +1,241 @@
+#ifndef C2K_DMA_H_
+#define C2K_DMA_H_
+
+#ifndef __ASSEMBLY__
+
+#include <linux/mm_types.h>
+#include <linux/time.h>
+
+//	Mem to IO Control
+#define M2IO_START	(1 << 0)
+#define M2IO_FLENEN	(1 << 1)
+#define M2IO_FCOM	(1 << 2)
+#define M2IO_DONOSTOP	(1 << 3)
+#define M2IO_DONOSTA	(1 << 4)
+
+//	IO to Mem: DMA Control
+#define IO2M_IRQFRDYN	(1 << 0)
+#define IO2M_IRQFLST	(1 << 1)
+#define IO2M_IRQFDON	(1 << 2)
+#define IO2M_IRQFLSH	(1 << 3)
+#define IO2M_IRQFLEN	(1 << 4)
+#define IO2M_IRQFTHLD	(1 << 5)
+
+// IRQ Status Register
+#define IRQ_IRQFRDYN	(1 << 0)
+#define IRQ_IRQFLST	(1 << 1)
+#define IRQ_IRQFDON	(1 << 2)
+#define IRQ_IRQFLSH	(1 << 3)
+#define IRQ_IRQFLEN	(1 << 4)
+#define IRQ_IRQFTHLD	(1 << 5)
+#define IRQ_IRQFCTRL	(1 << 6)
+
+// Inbound Frame and Buffer Descriptor Programming
+
+// BControl
+#define BLAST	(1 << 16)
+#define BFIX	(1 << 17)
+
+// Block Size
+#define XOR_BLOCK_SIZE_256	0
+#define XOR_BLOCK_SIZE_512	1
+#define XOR_BLOCK_SIZE_1024	2
+#define XOR_BLOCK_SIZE_2048	3
+#define XOR_BLOCK_SIZE_4096	4
+
+#define COMCERTO_XOR_MAX_SRC    6
+
+#define MDMA_INBOUND_BUF_DESC		256
+#define MDMA_OUTBOUND_BUF_DESC	256
+
+#define XOR_INBOUND_BUF_DESC	6
+#define XOR_OUTBOUND_BUF_DESC	2
+
+/* FLEN => Maximum no. of fdescs mdma can process at a time is 4k-1 */
+/* Need to verify if these many can be created in aram_pool. Don't know whether someone else use iram_pool */
+//#define XOR_FDESC_COUNT	256
+
+#define MDMA_MAX_BUF_SIZE		0xffff
+#define MDMA_SPLIT_BUF_SIZE		0x8000	/* half a page with 64kB pages */
+
+/* AxCACHE[3:0], bit[3]= WA, bit[2]= RA, bit[1]= C, bit[0]= B */
+#define BUFFERABLE		(1 << 0)
+#define CACHEABLE		(1 << 1)
+#define READ_ALLOC		(1 << 2)
+#define WRITE_ALLOC		(1 << 3)
+
+/* AxUSER[0] = coherent(1)/non_coherent(0) */
+
+/* AxUSER[4:1] */
+#define STRONGLY_ORDERED	0x0
+#define DEVICE			0x1
+#define NORMAL_NONCACHEABLE	0x3
+#define WRITETHROUGH		0x6
+#define WRITEBACK		0x7
+#define WRITEBACK_WA		0xf
+
+/* AxPROT[2:0], bit[2]= instruction(1)/data(0), bit[1]= non-secure(1)/secure(0) , bit[0] = privilege(1)/normal(0) */
+#define PRIVILEGE		(1 << 0)
+#define NON_SECURE		(1 << 1)
+#define INSTRUCTION		(1 << 2)
+
+
+#define AWUSER_COHERENT(x)		((((x) << 1) | 1) << 19)
+#define AWPROT(x)			((x) << 16)
+#define AWCACHE(x)			((x) << 12)
+
+#define ARUSER_COHERENT(x)		((((x) << 1) | 1) << 7)
+#define ARPROT(x)			((x) << 4)
+#define ARCACHE(x)			((x) << 0)
+
+enum mdma_transaction_type {
+	MDMA_MEMCPY,
+	MDMA_XOR,
+	MDMA_XOR_VAL,
+};
+
+struct comcerto_mdma_buffer_desc {
+	u32 bpointer;
+	u32 bcontrol;
+}__attribute__ ((aligned(8)));
+
+struct comcerto_memcpy_inbound_fdesc {
+	u32  next_desc;
+	u32  fcontrol;
+	u32  fstatus0;
+	u32  fstatus1;
+	struct comcerto_mdma_buffer_desc bdesc[MDMA_INBOUND_BUF_DESC];
+}__attribute__ ((aligned(16)));
+
+struct comcerto_memcpy_outbound_fdesc {
+	u32  next_desc;
+	u32  fcontrol;
+	u32  fstatus0;
+	u32  fstatus1;
+	struct comcerto_mdma_buffer_desc bdesc[MDMA_OUTBOUND_BUF_DESC];
+}__attribute__ ((aligned(16)));
+
+struct comcerto_xor_inbound_fdesc {
+	u32  next_desc;
+	u32  fcontrol;
+	u32  fstatus0;
+	u32  fstatus1;
+	struct comcerto_mdma_buffer_desc bdesc[XOR_INBOUND_BUF_DESC];
+}__attribute__ ((aligned(16)));
+
+struct comcerto_xor_outbound_fdesc {
+	u32  next_desc;
+	u32  fcontrol;
+	u32  fstatus0;
+	u32  fstatus1;
+	struct comcerto_mdma_buffer_desc bdesc[XOR_OUTBOUND_BUF_DESC];
+}__attribute__ ((aligned(16)));
+
+struct comcerto_dma_buf {
+	dma_addr_t phys_addr;
+	unsigned int len;
+	unsigned int split;
+};
+
+struct comcerto_dma_sg {
+	unsigned int input_idx;
+	unsigned int output_idx;
+	dma_addr_t high_phys_addr;
+	dma_addr_t low_phys_addr;
+#if defined(CONFIG_COMCERTO_MDMA_PROF)
+	struct timeval start;
+	struct timeval end;
+#endif
+	struct comcerto_dma_buf in_bdesc[MDMA_INBOUND_BUF_DESC];
+	struct comcerto_dma_buf out_bdesc[MDMA_OUTBOUND_BUF_DESC];
+};
+
+struct mdma_xor_struct {
+	int transaction_type;
+	int xor_block_size;
+	int xor_src_cnt;
+	dma_addr_t **xor_srcs;
+	dma_addr_t *xor_dest;
+};
+
+
+extern struct comcerto_memcpy_inbound_fdesc *mdma_in_desc;
+extern struct comcerto_memcpy_outbound_fdesc *mdma_out_desc;
+
+extern struct comcerto_xor_inbound_fdesc *xor_in_fdesc[];
+extern struct comcerto_xor_outbound_fdesc *xor_out_fdesc[];
+
+
+static inline void comcerto_dma_set_in_bdesc(u32 idx, u32 addr, u32 ctrl)
+{
+	mdma_in_desc->bdesc[idx].bpointer = addr;
+	mdma_in_desc->bdesc[idx].bcontrol = ctrl;
+}
+
+static inline void comcerto_dma_set_out_bdesc(u32 idx, u32 addr, u32 ctrl)
+{
+	mdma_out_desc->bdesc[idx].bpointer = addr;
+	mdma_out_desc->bdesc[idx].bcontrol = ctrl;
+}
+
+static inline void comcerto_dma_in_bdesc_ctrl_update(u32 idx, u32 ctrl)
+{
+	mdma_in_desc->bdesc[idx].bcontrol |= ctrl;
+}
+
+static inline void comcerto_dma_out_bdesc_ctrl_update(u32 idx, u32 ctrl)
+{
+	mdma_out_desc->bdesc[idx].bcontrol |= ctrl;
+}
+
+/****************** XOR functions ********************/
+static inline void mdma_xor_set_in_bdesc(u32 xor_cbuf_wr_cntr, u32 idx, u32 addr, u32 ctrl)
+{
+	xor_in_fdesc[xor_cbuf_wr_cntr]->bdesc[idx].bpointer = addr;
+	xor_in_fdesc[xor_cbuf_wr_cntr]->bdesc[idx].bcontrol = ctrl;
+}
+
+static inline void mdma_xor_set_out_bdesc(u32 xor_cbuf_wr_cntr, u32 idx, u32 addr, u32 ctrl)
+{
+	xor_out_fdesc[xor_cbuf_wr_cntr]->bdesc[idx].bpointer = addr;
+	xor_out_fdesc[xor_cbuf_wr_cntr]->bdesc[idx].bcontrol = ctrl;
+}
+
+static inline void mdma_xor_in_bdesc_ctrl_update(u32 xor_cbuf_wr_cntr,u32 idx, u32 ctrl)
+{
+	xor_in_fdesc[xor_cbuf_wr_cntr]->bdesc[idx].bcontrol |= ctrl;
+}
+
+static inline void mdma_xor_out_bdesc_ctrl_update(u32 xor_cbuf_wr_cntr,u32 idx, u32 ctrl)
+{
+	xor_out_fdesc[xor_cbuf_wr_cntr]->bdesc[idx].bcontrol |= ctrl;
+}
+
+/****************** XOR functions end ********************/
+
+extern void comcerto_dma_get(void);
+extern void comcerto_dma_put(void);
+extern void comcerto_dma_set_in_bdesc(u32 idx, u32 addr, u32 ctrl);
+extern void comcerto_dma_set_out_bdesc(u32 idx, u32 addr, u32 ctrl);
+extern void comcerto_dma_start(void);
+extern void comcerto_dma_wait(void);
+extern void comcerto_do_mdma_xor(unsigned int src_count, unsigned int bytes, dma_addr_t dest, dma_addr_t *srcs);
+extern void comcerto_do_mdma_memcpy(void);
+
+int comcerto_dma_sg_add_input(struct comcerto_dma_sg *sg, void *p, unsigned int len, int use_acp);
+int comcerto_dma_sg_add_output(struct comcerto_dma_sg *sg, void *p, unsigned int len, int use_acp);
+void comcerto_dma_sg_setup(struct comcerto_dma_sg *sg, unsigned int len);
+void comcerto_dma_sg_cleanup(struct comcerto_dma_sg *sg, unsigned int len);
+
+static inline void comcerto_dma_sg_init(struct comcerto_dma_sg *sg)
+{
+	sg->input_idx = 0;
+	sg->output_idx = 0;
+	sg->high_phys_addr = 0x0;
+	sg->low_phys_addr = 0xffffffff;
+}
+
+#endif
+
+#endif /* C2K_DMA_H_ */
+
diff --git a/arch/arm/mach-comcerto/include/mach/comcerto-2000.h b/arch/arm/mach-comcerto/include/mach/comcerto-2000.h
new file mode 100644
index 0000000..4a27d04
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/comcerto-2000.h
@@ -0,0 +1,250 @@
+/*
+ *  arch/arm/arch-comcerto/include/mach/comcerto-2000.h
+ *
+ *  Copyright (C) 2011 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#error "Do not include this directly, instead #include <asm/hardware.h>"
+#endif
+
+#ifndef __ASM_ARCH_COMCERTO2000_H__
+#define __ASM_ARCH_COMCERTO2000_H__
+
+
+/*
+  * System Clock Frequencies
+  */
+#ifdef CONFIG_RTSM_C2K
+#define COMCERTO_DEFAULTAXICLK          (600000000/3) /* Hz */
+#else
+#define COMCERTO_DEFAULTAXICLK          200000000 /* Hz */
+#endif
+
+
+/*
+ * SCU registers 
+ */
+#define COMCERTO_SCU_BASE					0xFFF00000			
+#define COMCERTO_GIC_CPU_BASE				(COMCERTO_SCU_BASE + 0x100)
+#define COMCERTO_TWD_BASE					(COMCERTO_SCU_BASE + 0x600)
+#define COMCERTO_TWD_PERCPU_BASE			(COMCERTO_SCU_BASE + 0x700)
+#define COMCERTO_GIC_DIST_BASE				(COMCERTO_SCU_BASE + 0x1000)
+#define COMCERTO_L310_BASE					(COMCERTO_SCU_BASE + 0x10000)
+
+#define COMCERTO_L2CC_ASSOCIATIVITY_SHIFT	16
+#define COMCERTO_L2CC_ASSOCIATIVITY_MASK	0x00010000
+#define COMCERTO_L2CC_ASSOCIATIVITY_8WAY	0x0
+#define COMCERTO_L2CC_ASSOCIATIVITY_16WAY	0x1
+
+#define COMCERTO_L2CC_WAYSIZE_SHIFT			17
+#define COMCERTO_L2CC_WAYSIZE_MASK			0x000E0000
+#define COMCERTO_L2CC_ASSOCIATIVITY_32KB	0x2
+
+#define COMCERTO_L2CC_WR_LAT_SHIFT			8
+#define COMCERTO_L2CC_RD_LAT_SHIFT			4
+
+
+/*
+  * Physical address of IO on APB Bus
+  */
+
+#define COMCERTO_APB_TDM_BASE			0x90400000
+#define COMCERTO_APB_USBPHY_SERDES_STAT_BASE	0x90410000
+#define COMCERTO_APB_TDMA_BASE			0x90420000
+#define COMCERTO_APB_TIMER_BASE			0x90450000
+#define COMCERTO_APB_PCI_SATA_USB_CTRL_BASE	0x90460000
+#define COMCERTO_APB_GPIO_BASE			0x90470000
+#define COMCERTO_APB_UART0_BASE			0x90490000
+#define COMCERTO_APB_SPI_BASE			0x90498000
+#define COMCERTO_APB_I2C_BASE			0x9049C000
+#define COMCERTO_APB_USB3_BASE			0x904A0000
+#define COMCERTO_APB_CLK_BASE			0x904B0000
+#define COMCERTO_APB_RTC_BASE			0x904E0000
+#define COMCERTO_APB_OTP_BASE			0x904F0000
+#define COMCERTO_APB_PFE_BASE			0x90500000
+#define COMCERTO_APB_SERDES_CONF_BASE		0x90590000
+#define COMCERTO_APB_EXPBUS_BASE		0x905A0000
+#define COMCERTO_APB_DDRPHY_BASE		0x905B0000
+#define COMCERTO_APB_TDMA2_BASE			0x905D0000
+#define COMCERTO_APB_MDMA_BASE			0x905E0000
+#define COMCERTO_APB_A9CS_BASE			0x90600000
+
+
+/*
+  * Physical address on AXI Bus
+  */
+#define COMCERTO_AXI_HIGHMEMDDR_BASE		0xFFFF0000
+#define COMCERTO_AXI_DDR_BASE			0x00000000
+#define COMCERTO_AXI_ACP_BASE			0x80000000 /* 48MB */
+#define COMCERTO_AXI_IRAM_BASE			0x83000000
+#define COMCERTO_AXI_IBR_BASE			0x90000000
+#define COMCERTO_AXI_APB_BASE			0x90400000 /* 12MB */
+#define COMCERTO_AXI_SEMA_BASE			0x91000000 /* 16MB */
+#define COMCERTO_AXI_USB2P0_BASE		0x92000000
+#define COMCERTO_AXI_TRUSTZONE_BASE		0x93000000
+#define COMCERTO_AXI_DPI0_BASE			0x94000000 /* 16MB */
+#define COMCERTO_AXI_DPI1_BASE			0x95000000 /* 16MB */
+#define COMCERTO_AXI_UART_SPI_BASE		0x96000000 /* 16MB */
+#define COMCERTO_AXI_UART0_BASE			(COMCERTO_AXI_UART_SPI_BASE + 0x00300000)
+#define COMCERTO_AXI_UART1_BASE			(COMCERTO_AXI_UART_SPI_BASE + 0x00400000)
+#define COMCERTO_AXI_SPI_BASE			(COMCERTO_AXI_UART_SPI_BASE + 0x00500000)
+#define COMCERTO_AXI_DDRCONFIG_BASE		0x97000000
+#define COMCERTO_AXI_PCIe1_BASE			0x99000000
+#define COMCERTO_AXI_PCIe0_BASE			0x98000000
+#define COMCERTO_AXI_IPSEC_BASE			0x9A000000
+#define COMCERTO_AXI_SPACC_PDU_BASE		0x9B000000 /* 16MB */
+#define COMCERTO_AXI_PFE_BASE			0x9C000000 /* 16MB */
+#define COMCERTO_AXI_SATA_BASE			0x9D000000 /* 16MB */
+#define COMCERTO_AXI_DECT_BASE			0x9E000000 /* 16MB */
+#define COMCERTO_AXI_USB3P0_BASE                0x9F000000 /* 16MB */
+#define COMCERTO_AXI_PCIe0_SLAVE_BASE	0xA0000000
+#define COMCERTO_AXI_PCIe1_SLAVE_BASE	0xB0000000
+#define COMCERTO_AXI_EXP_BASE			0xC0000000
+#define COMCERTO_AXI_EXP_ECC_BASE		0xCFFF0000 /* 64KB */
+
+#define COMCERTO_AXI_ACP_SIZE			(1 << 24)
+
+#define COMCERTO_DDR_SHARED_BASE		(COMCERTO_AXI_DDR_BASE + 0x2C00000)
+#define COMCERTO_DDR_SHARED_SIZE		(SZ_16M + SZ_4M)
+
+/* MSP memory map */
+#define COMCERTO_MSP_DDR_BASE			COMCERTO_DDR_SHARED_BASE
+#define COMCERTO_MSP_DDR_SIZE_CB		(SZ_1M * 5)
+#define COMCERTO_MSP_DDR_SIZE_NCNB		(SZ_1M * 3)
+#define COMCERTO_MSP_DDR_SIZE			(COMCERTO_MSP_DDR_SIZE_CB + COMCERTO_MSP_DDR_SIZE_NCNB)
+
+/* PFE memory map */
+#define COMCERTO_APB_PFE_SIZE			SZ_64K
+#define COMCERTO_AXI_PFE_SIZE			SZ_16M
+#define COMCERTO_AXI_IPSEC_SIZE			SZ_16M
+#define COMCERTO_PFE_DDR_BASE			(COMCERTO_DDR_SHARED_BASE + SZ_8M)
+#define COMCERTO_PFE_DDR_SIZE			(SZ_8M + SZ_4M)
+#define COMCERTO_PFE_IRAM_BASE			(COMCERTO_AXI_IRAM_BASE + 0x0000)
+#define COMCERTO_PFE_IRAM_SIZE			SZ_8K
+
+#define IO_SPACE_LIMIT					0
+
+/* MDMA memory map */
+#define COMCERTO_APB_MDMA_SIZE          SZ_1K+SZ_4
+
+/*
+ * Virtual address mapping
+ */
+#define COMCERTO_MSP_VADDR			0xf0000000
+#define COMCERTO_PFE_VADDR                     0xfa000000
+#define COMCERTO_PFE_AXI_VADDR         0xfc000000
+#define COMCERTO_SCU_VADDR				COMCERTO_SCU_BASE
+#define COMCERTO_GIC_CPU_VADDR			(COMCERTO_SCU_VADDR + 0x100)
+#define COMCERTO_GIC_GLOBAL_TIMER_VADDR	(COMCERTO_SCU_VADDR + 0x200)
+#define COMCERTO_TWD_VADDR				(COMCERTO_SCU_VADDR + 0x600)
+#define COMCERTO_GIC_DIST_VADDR			(COMCERTO_SCU_VADDR + 0x1000)
+#define COMCERTO_L310_VADDR				(COMCERTO_SCU_VADDR + 0x10000)
+
+#define COMCERTO_DISTR_INT_SET_PENDING                   (COMCERTO_GIC_DIST_VADDR + 0x200)
+#define COMCERTO_DISTR_INT_SET_PENDING_OFFSET_4          (COMCERTO_DISTR_INT_SET_PENDING + 0x4)
+#define COMCERTO_DISTR_INT_SET_PENDING_OFFSET_8          (COMCERTO_DISTR_INT_SET_PENDING + 0x8)
+
+#define IRAM_MEMORY_VADDR			0xf0800000
+#define COMCERTO_APB_VADDR				0xf0900000	/* VA of IO on APB bus */
+#define COMCERTO_APB_SIZE				0x00C00000	
+#define COMCERTO_AXI_UART_SPI_VADDR		0xF1600000 
+#define COMCERTO_AXI_UART_SPI_SIZE		0x01000000 
+#define COMCERTO_AXI_DMA_VADDR			(COMCERTO_AXI_UART_SPI_VADDR+0x00000000) 
+#define COMCERTO_AXI_UART0_VADDR		(COMCERTO_AXI_UART_SPI_VADDR+0x00300000) 
+#define COMCERTO_AXI_UART1_VADDR		(COMCERTO_AXI_UART_SPI_VADDR+0x00400000) 
+#define COMCERTO_AXI_SSI_VADDR			(COMCERTO_AXI_UART_SPI_VADDR+0x00500000) 
+
+#define COMCERTO_SEMA_VADDR			0xf4000000
+#define COMCERTO_AXI_PCIe0_VADDR_BASE		0xf5000000
+#define COMCERTO_AXI_PCIe1_VADDR_BASE		0xf6000000
+#define COMCERTO_DECT_VADDR			0xf7000000
+
+/* 
+  * Reference Clock Option in Boot Strap Register
+  *
+  * BIT [9:8] System PLL Refclk Select 
+  * '00' - USB XTAL
+  * '01' - Serdes #0 Refclk
+  * '10' - Serdes #1 Refclk
+  * '11' - Serdes XTAL
+  *
+  * BIT[7]   Serdes OSC PAD - Reference clock frequency selection bootstrap (inverted value of SF1)
+  * '0' - 30MHz ~ 50MHz
+  * '1' - 15MHz ~ 30MHz
+  * Note: SF0 is tied to 1 in GPIO block and might later on be controlled during DFT
+  *
+  * BIT[5]   USB/Sys PLL OSC PAD - Reference clock frequency selection bootstrap (inverted value of SF1)
+  *'0' - 30MHz ~ 50MHz
+  * '1' - 15MHz ~ 30MHz
+  * Note: SF0 is tied to 1 in GPIO block and might later on be controlled during DFT
+  *
+  */
+
+#define GPIO_SYS_PLL_REF_CLK_MASK			(0x00000100 | 0x00000200)
+#define GPIO_SYS_PLL_REF_CLK_SHIFT			8
+
+#define USB_XTAL_REF_CLK					0
+#define SERDES_0_REF_CLK					1
+#define SERDES_2_REF_CLK					2
+#define SERDES_XTAL_REF_CLK					3
+
+#define GPIO_SERDES_OSC_PAD_MASK			(0x00000080)
+#define GPIO_SERDES_OSC_PAD_SHIFT			7
+
+#define GPIO_USB_OSC_PAD_MASK				(0x00000020)
+#define GPIO_USB_OSC_PAD_SHIFT				5
+
+#define REF_CLK_24MHZ						24000000 /* 24 MHz */
+#define REF_CLK_48MHZ						48000000 /* 48 MHz */
+
+
+/* USB 2.0 */
+#define USB2_PHY_BASE						APB_VADDR(COMCERTO_APB_PCI_SATA_USB_CTRL_BASE)
+
+/* USB 3.0 */
+#define USB3_PHY_BASE           APB_VADDR(COMCERTO_APB_USB3_BASE)
+
+#define USBPHY_SERDES_STAT_BASE APB_VADDR(COMCERTO_APB_USBPHY_SERDES_STAT_BASE)
+
+/* Includes */
+#include <mach/comcerto-2000/clk-rst.h>
+#include <mach/comcerto-2000/timer.h>
+#include <mach/comcerto-2000/gpio.h>
+#include <mach/comcerto-2000/exp-bus.h>
+#include <mach/comcerto-2000/pcie.h>
+#include <mach/comcerto-2000/serdes.h>
+#include <mach/comcerto-2000/memory.h>
+#include <mach/c2k_dma.h>
+
+#define comcerto_timer4_set(hbound)	__raw_writel((hbound), COMCERTO_TIMER4_HIGH_BOUND)
+
+#define comcerto_timer4_get()		__raw_readl(COMCERTO_TIMER4_CURRENT_COUNT)
+
+
+#define comcerto_timer5_set(lbound, hbound, ctrl)  do {								\
+						      __raw_writel((ctrl) & 0x1, COMCERTO_TIMER5_CTRL);	\
+						      __raw_writel((lbound), COMCERTO_TIMER5_LOW_BOUND);	\
+						      __raw_writel((hbound), COMCERTO_TIMER5_HIGH_BOUND);	\
+						   } while(0)
+
+#define comcerto_timer5_get()		__raw_readl(COMCERTO_TIMER5_CURRENT_COUNT)
+
+/* Number of gemacs supported in comcerto 2000 */
+#define NUM_GEMAC_SUPPORT	3
+
+#endif
diff --git a/arch/arm/mach-comcerto/include/mach/comcerto-2000/clk-rst.h b/arch/arm/mach-comcerto/include/mach/comcerto-2000/clk-rst.h
new file mode 100644
index 0000000..631ea98
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/comcerto-2000/clk-rst.h
@@ -0,0 +1,252 @@
+/*
+ *  linux/arch/arm/mach-comcerto/include/mach/comcerto-2000/clk-rst.h
+ *
+ *  Copyright (C) 2008 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __CLK_H__
+#define __CLK_H__
+
+/*
+ * Clock Reset Registers
+ */
+#define DEVICE_RST_CNTRL		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x000)
+#define SERDES_RST_CNTRL		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x004)
+#define PCIe_SATA_RST_CNTRL		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x008)
+#define USB_RST_CNTRL			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x00C)
+#define GNRL_DEVICE_CNFG_0		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x010)
+#define GNRL_DEVICE_CNFG_1 		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x014)
+#define GNRL_DEVICE_STATUS		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x018)
+#define A9DP_PWR_STAT			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x028)
+#define A9DP_PWR_CNTRL			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x02C)
+#define GNRL_CLK_CNTRL_0 		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x030)
+#define GNRL_CLK_CNTRL_1		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x034)
+#define PLLS_GLOBAL_CNTRL		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x038)
+#define AXI_CLK_CNTRL_0			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x040)
+#define AXI_CLK_CNTRL_1			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x044)
+#define AXI_CLK_CNTRL_2			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x048)
+#define AXI_CLK_DIV_CNTRL		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x04C)
+#define AXI_RESET_0			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x050)
+#define AXI_RESET_1			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x054)
+#define AXI_RESET_2			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x058)
+#define A9DP_MPU_CLK_CNTRL		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x68)
+#define A9DP_MPU_CLK_DIV_CNTRL       	APB_VADDR(COMCERTO_APB_CLK_BASE + 0x6C)
+#define A9DP_MPU_RESET               	APB_VADDR(COMCERTO_APB_CLK_BASE + 0x70)
+#define A9DP_CPU_CLK_CNTRL           	APB_VADDR(COMCERTO_APB_CLK_BASE + 0x74)
+#define A9DP_CPU_RESET               	APB_VADDR(COMCERTO_APB_CLK_BASE + 0x78)
+#define A9DP_CLK_CNTRL               	APB_VADDR(COMCERTO_APB_CLK_BASE + 0x80)
+#define A9DP_CLK_DIV_CNTRL           	APB_VADDR(COMCERTO_APB_CLK_BASE + 0x84)
+#define A9DP_RESET                   	APB_VADDR(COMCERTO_APB_CLK_BASE + 0x88)
+#define L2CC_CLK_CNTRL			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x090)
+#define L2CC_CLK_DIV_CNTRL		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x094)
+#define L2CC_RESET			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x098)
+#define TPI_CLK_CNTRL			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x0A0)
+#define TPI_CLK_DIV_CNTRL		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x0A4)
+#define TPI_RESET			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x0A8)
+#define CSYS_CLK_CNTRL			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x0B0)
+#define CSYS_CLK_DIV_CNTRL		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x0B4)
+#define CSYS_RESET			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x0B8)
+#define EXTPHY0_CLK_CNTRL		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x0C0)
+#define EXTPHY0_CLK_DIV_CNTRL		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x0C4)
+#define EXTPHY0_RESET			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x0C8)
+#define EXTPHY1_CLK_CNTRL		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x0D0)
+#define EXTPHY1_CLK_DIV_CNTRL		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x0D4)
+#define EXTPHY1_RESET			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x0D8)
+#define EXTPHY2_CLK_CNTRL 		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x0E0)
+#define EXTPHY2_CLK_DIV_CNTRL 		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x0E4)
+#define EXTPHY2_RESET			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x0E8)
+#define DDR_CLK_CNTRL 			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x0F0)
+#define DDR_CLK_DIV_CNTRL 		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x0F4)
+#define DDR_RESET			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x0F8)
+#define PFE_CLK_CNTRL 			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x100)
+#define PFE_CLK_DIV_CNTRL 		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x104)
+#define PFE_RESET			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x108)
+#define IPSEC_CLK_CNTRL			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x110)
+#define IPSEC_CLK_DIV_CNTRL		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x114)
+#define IPSEC_RESET			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x118)
+#define DECT_CLK_CNTRL 			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x120)
+#define DECT_CLK_DIV_CNTRL 		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x124)
+#define DECT_RESET 			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x128)
+#define GEMTX_CLK_CNTRL			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x130)
+#define GEMTX_CLK_DIV_CNTRL		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x134)
+#define GEMTX_RESET			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x138)
+#define TDMNTG_REF_CLK_CNTRL 		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x140)
+#define TDMNTG_REF_CLK_DIV_CNTRL 	APB_VADDR(COMCERTO_APB_CLK_BASE + 0x144)
+#define TDMNTG_RESET 			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x148)
+#define TDM_CLK_CNTRL			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x14C)
+#define TSUNTG_REF_CLK_CNTRL 		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x150)
+#define TSUNTG_REF_CLK_DIV_CNTRL 	APB_VADDR(COMCERTO_APB_CLK_BASE + 0x154)
+#define TSUNTG_RESET 			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x158)
+#define SATA_PMU_CLK_CNTRL 		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x160)
+#define SATA_PMU_CLK_DIV_CNTRL 		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x164)
+#define SATA_PMU_RESET 			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x168)
+#define SATA_OOB_CLK_CNTRL 		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x170)
+#define SATA_OOB_CLK_DIV_CNTRL 		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x174)
+#define SATA_OOB_RESET 			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x178)
+#define SATA_OCC_CLK_CNTRL		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x180)
+#define SATA_OCC_CLK_DIV_CNTRL		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x184)
+#define SATA_OCC_RESET			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x188)
+#define PCIE_OCC_CLK_CNTRL		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x190)
+#define PCIE_OCC_CLK_DIV_CNTRL		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x194)
+#define PCIE_OCC_RESET			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x198)
+#define SGMII_OCC_CLK_CNTRL 		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x1A0)
+#define SGMII_OCC_CLK_DIV_CNTRL 	APB_VADDR(COMCERTO_APB_CLK_BASE + 0x1A4)
+#define SGMII_OCC_RESET 		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x1A8)
+#define PLL0_M_LSB			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x1C0)
+#define PLL0_M_MSB			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x1C4)
+#define PLL0_P				APB_VADDR(COMCERTO_APB_CLK_BASE + 0x1C8)
+#define PLL0_S				APB_VADDR(COMCERTO_APB_CLK_BASE + 0x1CC)
+#define PLL0_CNTRL			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x1D0)
+#define PLL0_TEST			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x1D4)
+#define PLL0_STATUS			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x1D8)
+#define PLL0_DIV_CNTRL			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x1DC)
+#define PLL1_M_LSB			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x1E0)
+#define PLL1_M_MSB			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x1E4)
+#define PLL1_P				APB_VADDR(COMCERTO_APB_CLK_BASE + 0x1E8)
+#define PLL1_S				APB_VADDR(COMCERTO_APB_CLK_BASE + 0x1EC)
+#define PLL1_CNTRL			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x1F0)
+#define PLL1_TEST			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x1F4)
+#define PLL1_STATUS			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x1F8)
+#define PLL1_DIV_CNTRL			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x1FC)
+#define PLL2_M_LSB			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x200)
+#define PLL2_M_MSB			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x204)
+#define PLL2_P				APB_VADDR(COMCERTO_APB_CLK_BASE + 0x208)
+#define PLL2_S				APB_VADDR(COMCERTO_APB_CLK_BASE + 0x20C)
+#define PLL2_CNTRL			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x210)
+#define PLL2_TEST			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x214)
+#define PLL2_STATUS			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x218)
+#define PLL2_DIV_CNTRL			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x21C)
+#define PLL3_M_LSB			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x220)
+#define PLL3_M_MSB			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x224)
+#define PLL3_P				APB_VADDR(COMCERTO_APB_CLK_BASE + 0x228)
+#define PLL3_S				APB_VADDR(COMCERTO_APB_CLK_BASE + 0x22c)
+#define PLL3_CNTRL			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x230)
+#define PLL3_TEST			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x234)
+#define PLL3_STATUS			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x238)
+#define PLL3_DITHER_CNTRL		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x23C)
+#define PLL3_K_LSB 			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x240)
+#define PLL3_K_MSB 			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x244)
+#define PLL3_MFR 			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x248)
+#define PLL3_MRR 			APB_VADDR(COMCERTO_APB_CLK_BASE + 0x24C)
+
+#define PLL0				0
+#define PLL1				1
+#define PLL2				2
+#define PLL3				3
+
+/* Device Reset Control Register (DEVICE_RST_CNTRL)*/
+
+#define CLK_DIV_RESTART         (1 << 7)
+#define WD_STATUS_CLR           (1 << 6)
+#define AXI_WD_RST_EN           (1 << 5)
+#define DEBUG_RST               (1 << 4)
+#define CLKRST_SCLR_RST         (1 << 3)
+#define FUNC_SCLR_RST           (1 << 2)
+#define GLB_SCLR_RST            (1 << 1)
+#define PWR_ON_SOFT_RST         (1 << 0)
+
+/* General Device Configuration Status Register (GNRL_DEVICE_STATUS) */
+#define CPU1_WD_RST_ACTIVATED   (1 << 2)
+#define CPU0_WD_RST_ACTIVATED   (1 << 1)
+#define AXI_WD_RST_ACTIVATED    (1 << 0)
+
+/* Clock Control Register */
+#define CLOCK_DOMAIN_ENABLE		1
+#define CLOCK_DOMAIN_ENABLE_SHIFT	0
+
+#define CLOCK_SOURCE_PLL0		0
+#define CLOCK_SOURCE_PLL1		1
+#define CLOCK_SOURCE_PLL2		2
+#define CLOCK_SOURCE_PLL3		3
+#define CLOCK_SOURCE_PLL4		4
+
+#define CLOCK_SOURCE_SHIFT		1
+
+#define CLK_DIV_BYPASS			(1 << 7)
+#define CLK_DIV_RATIO_MASK		0x1f
+
+#define PLL_VSEL			(1 << 6)
+#define PLL_LOCK_EN			(1 << 5)
+#define PLL_BYPASS			(1 << 4)
+#define PLL_RESET			(1 << 0)
+
+#define PLL_LOCK			(1 << 0)
+
+#define CLK_PLL_SRC_MASK		0x7
+#define CLK_PLL_SRC_SHIFT		1
+#define CLK_A9DP_PERI_DIV_BYPASS	(1 << 3)
+
+
+/* TDMNTG */
+#define TDMNTG_ADDR_SPACE_BASEADDR 		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x280)
+
+#define TDM_NTG_CLK_CTRL	(TDMNTG_ADDR_SPACE_BASEADDR + 0x00)
+#define TDM_NTG_INCR		(TDMNTG_ADDR_SPACE_BASEADDR + 0x04)
+#define TDM_FSYNC_GEN_CTRL	(TDMNTG_ADDR_SPACE_BASEADDR + 0x08)
+#define	TDM_FSYNC_LOW		(TDMNTG_ADDR_SPACE_BASEADDR + 0x0C)
+#define TDM_FSYNC_HIGH		(TDMNTG_ADDR_SPACE_BASEADDR + 0x10)
+
+#define FSYNC_FALL_EDGE		(1 << 1)
+#define	NTG_DIV_RST_N		(1 << 5)
+#define NTG_EN			(1 << 0)
+
+
+/* TSUNTG */
+#define TSUNTG_ADDR_SPACE_BASEADDR 		APB_VADDR(COMCERTO_APB_CLK_BASE + 0x2C0)
+
+/* USB 3.0 */
+#define USB1_UTMI_RST           (1 << 5)
+#define USB1_PHY_RST            (1 << 4)
+#define USB1_AXI_RST            (1 << 4)
+
+/* USB 2.0 */
+#define USB0_PHY_RST		(1 << 0)
+#define USB0_UTMI_RST		(1 << 1)
+#define USB0_AXI_RST		(1 << 3)
+
+/* CPU */
+#define CPU0_RST			(1 << 0)
+#define NEON0_RST			(1 << 1)
+#define CPU1_RST			(1 << 2)
+#define NEON1_RST			(1 << 3)
+
+#define CPU0_CLK_ENABLE		(1 << 0)
+#define NEON0_CLK_ENABLE	(1 << 1)
+#define CPU1_CLK_ENABLE		(1 << 2)
+#define NEON1_CLK_ENABLE	(1 << 3)
+
+#define GLOBAL_CLK_ENABLE	(1 << 0)
+
+#define CLAMP_CORE0     	(1 << 4)
+#define CLAMP_CORE1     	(1 << 6)
+#define CORE_PWRDWN0        (1 << 5)
+#define CORE_PWRDWN1        (1 << 7)
+#define MP_PWRDWN       	(1 << 0)
+
+#define SCPRE   			(1 << 4)
+#define SCALL   			(1 << 5)
+#define ISO_EN  			(1 << 6)
+
+#ifndef __ASSEMBLY__
+
+/* Function Declaration */
+extern void HAL_clk_div_backup_relocate_table (void);
+extern unsigned long HAL_get_ref_clk (void);
+#endif
+
+
+#endif
diff --git a/arch/arm/mach-comcerto/include/mach/comcerto-2000/clock.h b/arch/arm/mach-comcerto/include/mach/comcerto-2000/clock.h
new file mode 100644
index 0000000..e29fb2f
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/comcerto-2000/clock.h
@@ -0,0 +1,41 @@
+/*
+ * arch/arm/mach-comcerto/clock.h
+ *
+ * Clock control driver for Comcerto C2K device - internal header file
+ *
+ * This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#ifndef __ARCH_ARM_C2K_CLOCK_H__
+#define __ARCH_ARM_C2K_CLOCK_H__
+
+#define CLK_DOMAIN_MASK (1<<0)
+#define CLK_DOMAIN_SPI_I2C_MASK (1<<5)
+#define CLK_DOMAIN_TDMNTG_MASK (1<<4)
+#define CLK_DOMAIN_UART_MASK (1<<6)
+#define CLK_DOMAIN_PCIE0_MASK (1<<0)
+#define CLK_DOMAIN_PCIE1_MASK (1<<1)
+#define CLK_DOMAIN_IPSEC_SPACC_MASK (1<<2)
+#define CLK_DOMAIN_DPI_CIE_MASK (1<<5)
+#define CLK_DOMAIN_DPI_DECOMP_MASK (1<<6)
+#define CLK_DOMAIN_USB0_MASK (1<<3)
+#define CLK_DOMAIN_USB1_MASK (1<<4)
+#define CLK_DOMAIN_DUS_MASK  (1<<0)
+#define CLK_DOMAIN_SATA_MASK (1<<2)
+
+struct clk {
+	struct clk *parent;
+	const char *name;
+	unsigned long  rate;          /* Default rate value in HZ */
+	int usecount;
+	u32             enable_reg;
+	u32             clkgen_reg;
+	u32             div_reg;
+	u32             enable_mask;
+	unsigned long	(*get_rate)(struct clk *);
+        int 		(*set_rate) (struct clk *, unsigned long rate);
+};
+extern int clk_init(void);
+#endif
diff --git a/arch/arm/mach-comcerto/include/mach/comcerto-2000/exp-bus.h b/arch/arm/mach-comcerto/include/mach/comcerto-2000/exp-bus.h
new file mode 100644
index 0000000..9ca39a1
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/comcerto-2000/exp-bus.h
@@ -0,0 +1,102 @@
+/*
+ *  arch/arm/mach-comcerto/include/mach/comcerto-2000/exp-bus.h
+ *
+ *  Copyright (C) 2012 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __COMCERTO_EXP_BUS_H__
+#define __COMCERTO_EXP_BUS_H__
+
+
+/***** Registers address *****/
+
+#define COMCERTO_EXP_SW_RST_R			APB_VADDR(COMCERTO_APB_EXPBUS_BASE + 0x000)
+#define COMCERTO_EXP_CS_EN_R			APB_VADDR(COMCERTO_APB_EXPBUS_BASE + 0x004)
+#define COMCERTO_EXP_CSx_BASE_R(x)		APB_VADDR(COMCERTO_APB_EXPBUS_BASE + 0x008 + 0x4 * (x))
+#define COMCERTO_EXP_CSx_SEG_R(x)		APB_VADDR(COMCERTO_APB_EXPBUS_BASE + 0x01C + 0x4 * (x))
+#define COMCERTO_EXP_CSx_CFG_R(x)		APB_VADDR(COMCERTO_APB_EXPBUS_BASE + 0x030 + 0x4 * (x))
+#define COMCERTO_EXP_CSx_TMG1_R(x)		APB_VADDR(COMCERTO_APB_EXPBUS_BASE + 0x044 + 0x4 * (x))
+#define COMCERTO_EXP_CSx_TMG2_R(x)		APB_VADDR(COMCERTO_APB_EXPBUS_BASE + 0x058 + 0x4 * (x))
+#define COMCERTO_EXP_CSx_TMG3_R(x)		APB_VADDR(COMCERTO_APB_EXPBUS_BASE + 0x06C + 0x4 * (x))
+#define COMCERTO_EXP_CLOCK_DIV_R		APB_VADDR(COMCERTO_APB_EXPBUS_BASE + 0x080)
+#define COMCERTO_EXP_MFSM_R			APB_VADDR(COMCERTO_APB_EXPBUS_BASE + 0x100)
+#define COMCERTO_EXP_CSFSM_R			APB_VADDR(COMCERTO_APB_EXPBUS_BASE + 0x104)
+#define COMCERTO_EXP_WRSM_R			APB_VADDR(COMCERTO_APB_EXPBUS_BASE + 0x108)
+#define COMCERTO_EXP_RDSM_R			APB_VADDR(COMCERTO_APB_EXPBUS_BASE + 0x10C)
+
+	
+/***** Masks *****/
+
+/* EXP_SWRST_R register*/
+#define EXP_SW_RST			0x00000001
+	
+/* EXP_CS_EN_R register*/
+#define EXP_CS4_EN			0x00000020
+#define EXP_CS3_EN			0x00000010
+#define EXP_CS2_EN			0x00000008
+#define EXP_CS1_EN			0x00000004
+#define EXP_CS0_EN			0x00000002
+#define EXP_CSx_EN(x)			(1 << ((x) + 1))
+#define EXP_CLK_EN			0x00000001
+
+/* EXP_CSx_CFG_R register*/
+#define EXP_RDY_EDG			0x00000800
+#define EXP_RDY_EN			0x00000400
+#define EXP_NAND_MODE			0x00000200
+#define EXP_DM_MODE			0x00000100
+#define EXP_STRB_MODE			0x00000080
+#define EXP_ALE_MODE			0x00000040
+#define EXP_RE_CMD_LVL			0x00000020
+#define EXP_WE_CMD_LVL			0x00000010
+#define EXP_CS_LEVEL			0x00000008
+#define EXP_MEM_BUS_SIZE		0x00000006
+#define EXP_MEM_BUS_SIZE_32		0x00000004
+#define EXP_MEM_BUS_SIZE_16		0x00000002
+#define EXP_MEM_BUS_SIZE_8		0x00000000
+
+
+
+#define EXP_CS0_SEG_SIZE		SZ_128M
+#define EXP_CS1_SEG_SIZE		SZ_1M
+#define EXP_CS2_SEG_SIZE		SZ_1M
+#define EXP_CS3_SEG_SIZE		SZ_1M
+#define EXP_CS4_SEG_SIZE		SZ_1M
+
+#define EXP_CS0_AXI_BASEADDR		COMCERTO_AXI_EXP_BASE
+#define EXP_CS1_AXI_BASEADDR		(EXP_CS0_AXI_BASEADDR + EXP_CS0_SEG_SIZE)
+#define EXP_CS2_AXI_BASEADDR		(EXP_CS1_AXI_BASEADDR + EXP_CS1_SEG_SIZE)
+#define EXP_CS3_AXI_BASEADDR		(EXP_CS2_AXI_BASEADDR + EXP_CS2_SEG_SIZE)
+#define EXP_CS4_AXI_BASEADDR		(EXP_CS3_AXI_BASEADDR + EXP_CS3_SEG_SIZE)
+
+#define EXP_BUS_REG_BASE_CS0		(EXP_CS0_AXI_BASEADDR & ~0xf0000000)
+#define EXP_BUS_REG_BASE_CS1		(EXP_CS1_AXI_BASEADDR & ~0xf0000000)
+#define EXP_BUS_REG_BASE_CS2		(EXP_CS2_AXI_BASEADDR & ~0xf0000000)
+#define EXP_BUS_REG_BASE_CS3		(EXP_CS3_AXI_BASEADDR & ~0xf0000000)
+#define EXP_BUS_REG_BASE_CS4		(EXP_CS4_AXI_BASEADDR & ~0xf0000000)
+
+/* EXP_CSx_TMG1_R register */
+/* EXP_CSx_TMG2_R register */
+/* EXP_CSx_TMG3_R register */
+	
+/* EXP_CLOCK_DIV_R register */
+	
+/* EXP_MFSM_R register*/
+/* EXP_CSFSM_R register*/
+/* EXP_WRFSM_R register*/
+/* EXP_RDFSM_R register*/
+	
+#endif
diff --git a/arch/arm/mach-comcerto/include/mach/comcerto-2000/gpio.h b/arch/arm/mach-comcerto/include/mach/comcerto-2000/gpio.h
new file mode 100644
index 0000000..764b176
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/comcerto-2000/gpio.h
@@ -0,0 +1,315 @@
+/*
+ *  arch/arm/mach-comcerto/include/mach/comcerto-2000/gpio.h
+ *
+ *  Copyright (C) 2012 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __COMCERTO_GPIO_H__
+#define __COMCERTO_GPIO_H__
+
+/***** GPIO  *****/
+#define COMCERTO_GPIO_OUTPUT_REG		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x00)
+#define COMCERTO_GPIO_OE_REG			APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x04)
+#define COMCERTO_GPIO_INT_CFG_REG		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x08)
+#define COMCERTO_GPIO_INPUT_REG			APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x10)
+#define COMCERTO_GPIO_APB_WS			APB_VADDR(OMCERTO_APB_GPIO_BASE + 0x14)
+#define COMCERTO_GPIO_SYSTEM_CONFIG		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x1C)
+#define COMCERTO_GPIO_TDM_MUX			APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x28)
+#define COMCERTO_GPIO_MISC_CTRL			APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x34)
+#define COMCERTO_GPIO_DDR_AXI_CTRL		APB_VADDR(OMCERTO_APB_GPIO_BASE + 0x38)
+#define COMCERTO_GPIO_DDRC_STATUS		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x3C)
+#define COMCERTO_GPIO_BOOTSTRAP_STATUS		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x40)
+#define COMCERTO_GPIO_BOOTSTRAP_OVERRIDE	APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x44)
+
+
+#define COMCERTO_GPIO_DEVICE_ID_REG		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x50)
+#define COMCERTO_GPIO_PIN_SELECT_REG		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x58)
+#define COMCERTO_GPIO_PIN_SELECT_REG1		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x5C)
+#define COMCERTO_GPIO_MISC_PIN_SELECT		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x60)
+
+#define COMCERTO_GPIO_FABRIC_CTRL_REG		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x6C)
+#define COMCERTO_GPIO_A9_AUTH_CTRL_REG		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x70)
+#define COMCERTO_GPIO_A9_ACP_CONF_REG		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x74)
+#define COMCERTO_GPIO_PCIE_CLK_OUT_CTRL_REG	APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x80)
+#define COMCERTO_GPIO_INTR_CLR_REG		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x98)
+#define COMCERTO_GPIO_INTR_SET_REG		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x9C)
+#define COMCERTO_GPIO_INTR_MASK_REG		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0xA0)
+#define COMCERTO_GPIO_CSS_DECT_SYS_CFG0		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0xB0)
+#define COMCERTO_GPIO_CSS_DECT_SYS_CFG1		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0xB4)
+#define COMCERTO_GPIO_CSS_DECT_CTRL		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0xB8)
+#define COMCERTO_GPIO_63_32_PIN_OUTPUT		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0xD0)
+#define COMCERTO_GPIO_63_32_PIN_OUTPUT_EN	APB_VADDR(COMCERTO_APB_GPIO_BASE + 0xD4)
+#define COMCERTO_GPIO_63_32_PIN_INPUT		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0xD8)
+#define COMCERTO_GPIO_63_32_PIN_SELECT		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0xDC)
+
+#define	COMCERTO_GPIO_PAD_CONFIG0		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x100)
+#define	COMCERTO_GPIO_PAD_CONFIG1		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x104)
+#define	COMCERTO_GPIO_PAD_CONFIG2		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x108)
+#define	COMCERTO_GPIO_PAD_CONFIG3		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x10C)
+#define	COMCERTO_GPIO_PAD_CONFIG4		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x110)
+#define	COMCERTO_GPIO_PAD_CONFIG5		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x114)
+#define	COMCERTO_GPIO_PAD_CONFIG6		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x118)
+#define	COMCERTO_GPIO_PAD_CONFIG7		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x11C)
+#define	COMCERTO_GPIO_PAD_CONFIG8		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x120)
+#define	COMCERTO_GPIO_PAD_CONFIG9		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x124)
+#define	COMCERTO_GPIO_PAD_CONFIG10		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x128)
+#define	COMCERTO_GPIO_PAD_CONFIG11		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x12C)
+#define	COMCERTO_GPIO_PAD_CONFIG12		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x130)
+#define	COMCERTO_GPIO_PAD_CONFIG13		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x134)
+#define	COMCERTO_GPIO_PAD_CONFIG14		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x138)
+
+#define COMCERTO_GPIO_PMU_INTR_CLR		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x160)
+#define COMCERTO_GPIO_PMU_INTR_SET		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x164)
+#define COMCERTO_GPIO_PMU_INTR_MASK0		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x168)
+#define COMCERTO_GPIO_PMU_INTR_MASK1		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x16C)
+
+#define COMCERTO_GPIO_MEM_EMA_CONF0		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x1A4)
+#define COMCERTO_GPIO_MEM_EMA_CONF1		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x1A8)
+#define COMCERTO_GPIO_MEM_EMA_CONF2		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x1A8)
+#define COMCERTO_GPIO_MEM_EMA_CONF3		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x1AC)
+#define COMCERTO_GPIO_MEM_EMA_CONF4		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x1B0)
+#define COMCERTO_GPIO_MEM_EMA_CONF5		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x1B4)
+#define COMCERTO_GPIO_MEM_EMA_CONF6		APB_VADDR(COMCERTO_APB_GPIO_BASE + 0x1B8)
+
+#define GPIO_0		0x00000003
+#define GPIO_1		0x0000000C
+#define GPIO_2		0x00000030
+#define GPIO_3		0x000000C0
+#define GPIO_4		0x00000300
+#define GPIO_5		0x00000C00
+#define GPIO_6		0x00003000
+#define GPIO_7		0x0000C000
+#define GPIO_8		0x00030000
+#define GPIO_9		0x000C0000
+#define GPIO_10		0x00300000
+#define GPIO_11		0x00C00000
+#define GPIO_12		0x03000000
+#define GPIO_13		0x0C000000
+#define GPIO_14		0x30000000
+#define GPIO_15		0xC0000000
+#define GPIO_16		0x00000003
+#define GPIO_17		0x0000000C
+#define GPIO_18		0x00000030
+#define GPIO_19		0x000000C0
+#define GPIO_20		0x00000300
+#define GPIO_21		0x00000C00
+#define GPIO_22		0x00003000
+#define GPIO_23		0x0000C000
+#define GPIO_24		0x00030000
+#define GPIO_25		0x000C0000
+#define GPIO_26		0x00300000
+#define GPIO_27		0x00C00000
+#define GPIO_28		0x03000000
+#define GPIO_29		0x0C000000
+#define GPIO_30		0x30000000
+#define GPIO_31		0xC0000000
+
+#define GPIO_0_S	0x00000001
+#define GPIO_1_S	0x00000002
+#define GPIO_2_S	0x00000004
+
+/* GPIO Pin Number and Description */
+#define GPIO_PIN_NUM_0		0
+#define GPIO_PIN_NUM_1		1
+#define GPIO_PIN_NUM_2		2
+#define GPIO_PIN_NUM_3		3
+#define GPIO_PIN_NUM_4		4
+#define GPIO_PIN_NUM_5		5
+
+#define GPIO_PIN_DESC_0		"gpio-0"
+#define GPIO_PIN_DESC_1		"gpio-1"
+#define GPIO_PIN_DESC_2		"gpio-2"
+#define GPIO_PIN_DESC_3		"gpio-3"
+#define GPIO_PIN_DESC_4		"gpio-4"
+#define GPIO_PIN_DESC_5		"gpio-5"
+
+#define	GPIO_SET_0	0
+#define	GPIO_SET_1	1
+
+
+/* GPIO Pin Mask */
+#define GPIO_PIN_0		(0x1 << 0)
+#define GPIO_PIN_1		(0x1 << 1)
+#define GPIO_PIN_2		(0x1 << 2)
+#define GPIO_PIN_3		(0x1 << 3)
+#define GPIO_PIN_4		(0x1 << 4)
+#define GPIO_PIN_5		(0x1 << 5)
+#define GPIO_PIN_6		(0x1 << 6)
+#define GPIO_PIN_7		(0x1 << 7)
+#define GPIO_PIN_8		(0x1 << 8)
+#define GPIO_PIN_9		(0x1 << 9)
+#define GPIO_PIN_10		(0x1 << 10)
+#define GPIO_PIN_11		(0x1 << 11)
+#define GPIO_PIN_12		(0x1 << 12)
+#define GPIO_PIN_13		(0x1 << 13)
+#define GPIO_PIN_14		(0x1 << 14)
+#define GPIO_PIN_15		(0x1 << 15)
+#define GPIO_PIN_16		(0x1 << 16)
+#define GPIO_PIN_17		(0x1 << 17)
+#define GPIO_PIN_18		(0x1 << 18)
+#define GPIO_PIN_19		(0x1 << 19)
+#define GPIO_PIN_20		(0x1 << 20)
+#define GPIO_PIN_21		(0x1 << 21)
+#define GPIO_PIN_22		(0x1 << 22)
+#define GPIO_PIN_23		(0x1 << 23)
+#define GPIO_PIN_24		(0x1 << 24)
+#define GPIO_PIN_25		(0x1 << 25)
+#define GPIO_PIN_26		(0x1 << 26)
+#define GPIO_PIN_27		(0x1 << 27)
+#define GPIO_PIN_28		(0x1 << 28)
+#define GPIO_PIN_29		(0x1 << 29)
+#define GPIO_PIN_30		(0x1 << 30)
+#define GPIO_PIN_31		(0x1 << 31)
+
+#define GPIO_PIN_32		(0x1 << (32 - 32))
+#define GPIO_PIN_33		(0x1 << (33 - 32))
+#define GPIO_PIN_34		(0x1 << (34 - 32))
+#define GPIO_PIN_35		(0x1 << (35 - 32))
+#define GPIO_PIN_36		(0x1 << (36 - 32))
+#define GPIO_PIN_37		(0x1 << (37 - 32))
+#define GPIO_PIN_38		(0x1 << (38 - 32))
+#define GPIO_PIN_39		(0x1 << (39 - 32))
+#define GPIO_PIN_40		(0x1 << (40 - 32))
+#define GPIO_PIN_41		(0x1 << (41 - 32))
+#define GPIO_PIN_42		(0x1 << (42 - 32))
+#define GPIO_PIN_43		(0x1 << (43 - 32))
+#define GPIO_PIN_44		(0x1 << (44 - 32))
+#define GPIO_PIN_45		(0x1 << (45 - 32))
+#define GPIO_PIN_46		(0x1 << (46 - 32))
+#define GPIO_PIN_47		(0x1 << (47 - 32))
+#define GPIO_PIN_48		(0x1 << (48 - 32))
+#define GPIO_PIN_49		(0x1 << (49 - 32))
+#define GPIO_PIN_50		(0x1 << (50 - 32))
+#define GPIO_PIN_51		(0x1 << (51 - 32))
+#define GPIO_PIN_52		(0x1 << (52 - 32))
+#define GPIO_PIN_53		(0x1 << (53 - 32))
+#define GPIO_PIN_54		(0x1 << (54 - 32))
+#define GPIO_PIN_55		(0x1 << (55 - 32))
+#define GPIO_PIN_56		(0x1 << (56 - 32))
+#define GPIO_PIN_57		(0x1 << (57 - 32))
+#define GPIO_PIN_58		(0x1 << (58 - 32))
+#define GPIO_PIN_59		(0x1 << (59 - 32))
+#define GPIO_PIN_60		(0x1 << (60 - 32))
+#define GPIO_PIN_61		(0x1 << (61 - 32))
+#define GPIO_PIN_62		(0x1 << (62 - 32))
+#define GPIO_PIN_63		(0x1 << (63 - 32))
+
+/* GPIO Pin Select Pins */
+
+#define GPIO4_PWM0		(0x1 << 8)
+#define GPIO5_PWM1		(0x1 << 10)
+#define GPIO6_PWM2		(0x1 << 12)
+#define GPIO6_SATA0_ACT_LED 	(0x2 << 12)
+#define GPIO7_PWM3		(0x1 << 14)
+#define GPIO7_SATA0_CP_POD  	(0x2 << 14)
+#define GPIO8_UART0_RX		(0x2 << 16)
+#define GPIO9_UART0_TX		(0x2 << 18)
+#define GPIO10_UART0_RTS_N	(0x2 << 20)
+#define GPIO10_DECT0		(0x3 << 20)
+#define GPIO11_UART0_CTS_N	(0x2 << 22)
+#define GPIO11_DECT2		(0x3 << 22)
+#define GPIO12_PWM4		(0x1 << 24)
+#define GPIO12_PFE_UART_RX	(0x2 << 24)
+#define GPIO12_DECT3		(0x3 << 24)
+#define GPIO13_PWM5		(0x1 << 26)
+#define GPIO13_PFE_UART_TX	(0x2 << 26)
+#define GPIO13_DECT4		(0x3 << 26)
+#define GPIO14_SATA1_ACT_LED	(0x1 << 28)
+#define GPIO14_TIM_EVENT0	(0x2 << 28)
+#define GPIO14_DECT5		(0x3 << 28)
+#define GPIO15_SATA1_CP_POD 	(0x1 << 30)
+#define GPIO15_TIM_EVENT1	(0x2 << 30)
+#define GPIO15_RTCOSC		(0x3 << 30)
+#define GPIO16_I2C_SCL		(0x0 << 0)
+#define GPIO17_I2C_SDA		(0x0 << 2)
+#define GPIO18_SPI_SS0_N	(0x0 << 4)
+#define GPIO19_SPI_SS1_N	(0x0 << 6)
+#define GPIO20_SPI2_SS1_N	(0x0 << 8)
+#define GPIO21_SPI_SS2_N	(0x0 << 10)
+#define GPIO22_SPI_SS3_N	(0x0 << 12)
+#define GPIO23_EXP_CS2		(0x0 << 14)
+#define GPIO24_EXP_CS3		(0x0 << 16)
+#define GPIO25_EXP_ALE		(0x0 << 18)
+#define GPIO26_EXP_RDY		(0x0 << 20)
+#define GPIO27_TM_EXT_RESET	(0x0 << 22)
+#define GPIO28_EXP_NAND_CS 	(0x0 << 24)
+#define GPIO29_EXP_NAND_RDY	(0x0 << 26)
+#define GPIO30_SPI_TXD		(0x0 << 28)
+#define GPIO31_SPI_SCLK		(0x0 << 30)
+#define GPIO32_SPI_RXD		(0x0 << 0)
+#define GPIO33_SPI_2_RXD	(0x0 << 1)
+#define GPIO34_SPI_2_SS0_N	(0x0 << 2)
+
+#define BOOT_SERDES1_CNF_SATA0	(1 << 11)
+#define BOOT_SERDES2_CNF_SATA1  (1 << 12)
+
+				/* 0000 0000 0000 0000 0000 0011 0000 0000 */
+#define SPI_2_MUX_GPIO_1	(GPIO_4)
+#define SPI_2_MUX_BUS_1		(GPIO20_SPI2_SS1_N)
+#define SPI_2_MUX_GPIO_1_PIN	(GPIO_PIN_20)
+
+				/* 0000 0000 0000 0000 0000 0000 0000 0110 */
+#define SPI_2_MUX_GPIO_2	(GPIO_1_S | GPIO_2_S)
+#define SPI_2_MUX_BUS_2		(GPIO34_SPI_2_SS0_N | GPIO33_SPI_2_RXD)
+#define SPI_2_MUX_GPIO_2_PIN	(GPIO_PIN_34 | GPIO_PIN_33)
+
+				/* 1111 0000 0000 0000 0011 1100 1111 0000 */
+#define SPI_MUX_GPIO_1		(GPIO_30 | GPIO_31 | GPIO_18 | GPIO_19 | GPIO_21 | GPIO_22)
+#define SPI_MUX_BUS_1		(GPIO31_SPI_SCLK | GPIO30_SPI_TXD | GPIO22_SPI_SS3_N | GPIO21_SPI_SS2_N \
+					| GPIO19_SPI_SS1_N | GPIO18_SPI_SS0_N)
+#define SPI_MUX_GPIO_1_PIN	(GPIO_PIN_30 | GPIO_PIN_31 | GPIO_PIN_18 | GPIO_PIN_19 | GPIO_PIN_21 | GPIO_PIN_22)
+
+				/* 0000 0000 0000 0000 0000 0000 0000 0001 */
+#define SPI_MUX_GPIO_2		(GPIO_0_S)
+#define SPI_MUX_BUS_2		(GPIO32_SPI_RXD)
+#define SPI_MUX_GPIO_2_PIN	(GPIO_PIN_32)
+
+#define UART0_GPIO	(GPIO_8 | GPIO_9 | GPIO_10 | GPIO_11)
+#define UART0_BUS	(GPIO8_UART0_RX | GPIO9_UART0_TX | GPIO10_UART0_RTS_N | GPIO11_UART0_CTS_N)
+#define UART0_GPIO_PIN	(GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11)
+
+#define PFE_UART_GPIO		(GPIO_12 | GPIO_13)
+#define PFE_UART_BUS		(GPIO12_PFE_UART_RX | GPIO13_PFE_UART_TX)
+#define PFE_UART_GPIO_PIN	(GPIO_PIN_12 | GPIO_PIN_13)
+
+#define I2C_GPIO		(GPIO_16 | GPIO_17)
+#define I2C_BUS			(GPIO16_I2C_SCL | GPIO17_I2C_SDA)
+#define I2C_GPIO_PIN		(GPIO_PIN_16 | GPIO_PIN_17)
+
+#define NAND_GPIO		(GPIO_28 | GPIO_29 )
+#define NAND_BUS		(GPIO28_EXP_NAND_CS | GPIO29_EXP_NAND_RDY)
+#define NAND_GPIO_PIN		(GPIO_PIN_28 | GPIO_PIN_29)
+
+#define NOR_GPIO		(GPIO_25 | GPIO_26)
+#define NOR_BUS			(GPIO25_EXP_ALE | GPIO26_EXP_RDY)
+#define NOR_GPIO_PIN		(GPIO_PIN_25 | GPIO_PIN_26)
+
+#define C2K_GPIO_NR_GPIOS	64
+
+#define ARCH_NR_GPIOS		C2K_GPIO_NR_GPIOS
+
+#ifndef __ASSEMBLY__
+/* This is a temporary bit mask for avoiding usage of reserved gpio pins. */
+struct c2k_gpio_pin_stat_info {
+	uint32_t c2k_gpio_pins_0_31;
+	uint32_t c2k_gpio_pins_32_63;
+};
+
+extern struct c2k_gpio_pin_stat_info c2k_gpio_pin_stat;
+#endif
+
+#endif
diff --git a/arch/arm/mach-comcerto/include/mach/comcerto-2000/i2c.h b/arch/arm/mach-comcerto/include/mach/comcerto-2000/i2c.h
new file mode 100644
index 0000000..38bf9bd
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/comcerto-2000/i2c.h
@@ -0,0 +1,58 @@
+/*
+ *  linux/include/asm-arm/arch-comcerto/comcerto1000/i2c.h
+ *
+ *  Copyright (C) 2008 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef __ASM_ARCH_COMCERTO1000_I2C_H
+#define __ASM_ARCH_COMCERTO1000_I2C_H
+
+#define COMCERTO_I2C_ADDR		(0x00*4)
+#define COMCERTO_I2C_DATA		(0x01*4)
+#define COMCERTO_I2C_CNTR		(0x02*4)
+#define COMCERTO_I2C_STAT		(0x03*4)
+#define COMCERTO_I2C_CCRFS		(0x03*4)
+#define COMCERTO_I2C_XADDR		(0x04*4)
+#define COMCERTO_I2C_CCRH		(0x05*4)
+#define COMCERTO_I2C_RESET		(0x07*4)
+
+/* CNTR - Control register bits */
+#define CNTR_IEN			(1<<7)
+#define CNTR_ENAB			(1<<6)
+#define CNTR_STA			(1<<5)
+#define CNTR_STP			(1<<4)
+#define CNTR_IFLG			(1<<3)
+#define CNTR_AAK			(1<<2)
+
+/* STAT - Status codes */
+#define STAT_BUS_ERROR			0x00	/* Bus error in master mode only */
+#define STAT_START			0x08	/* Start condition transmitted */
+#define STAT_START_REPEATED		0x10	/* Repeated Start condition transmited */
+#define STAT_ADDR_WR_ACK		0x18	/* Address + Write bit transmitted, ACK received */
+#define STAT_ADDR_WR_NACK		0x20	/* Address + Write bit transmitted, NACK received */
+#define STAT_DATA_WR_ACK		0x28	/* Data byte transmitted in master mode , ACK received */
+#define STAT_DATA_WR_NACK		0x30	/* Data byte transmitted in master mode , NACK received */
+#define STAT_ARBIT_LOST			0x38	/* Arbitration lost in address or data byte */
+#define STAT_ADDR_RD_ACK		0x40	/* Address + Read bit transmitted, ACK received  */
+#define STAT_ADDR_RD_NACK		0x48	/* Address + Read bit transmitted, NACK received  */
+#define STAT_DATA_RD_ACK		0x50	/* Data byte received in master mode, ACK transmitted  */
+#define STAT_DATA_RD_NACK		0x58	/* Data byte received in master mode, NACK transmitted*/
+#define STAT_ARBIT_LOST_ADDR		0x68	/* Arbitration lost in address  */
+#define STAT_GENERAL_CALL		0x70	/* General Call, ACK transmitted */
+#define STAT_NO_RELEVANT_INFO		0xF8	/* No relevant status information, IFLF=0 */
+
+#endif /* __ASM_ARCH_COMCERTO1000_I2C_H */
diff --git a/arch/arm/mach-comcerto/include/mach/comcerto-2000/io.h b/arch/arm/mach-comcerto/include/mach/comcerto-2000/io.h
new file mode 100644
index 0000000..deb36f9
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/comcerto-2000/io.h
@@ -0,0 +1,77 @@
+/*
+ *  linux/include/asm-arm/arch-comcerto/comcerto-1000/io.h
+ *
+ *  Copyright (C) 2004,2005 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARCH_COMCERTO1000_IO_H
+#define __ASM_ARCH_COMCERTO1000_IO_H
+
+#include <asm/io.h>
+#include <mach/hardware.h>
+
+#if !defined(CONFIG_PCI)
+
+#define __io(a)			((void __iomem *)(a))
+#define __mem_pci(a)	(a)
+
+#else
+
+#define __mem_pci(a)	(a)
+
+/* IO ports are not supported */
+#define outb(v,p)	__readwrite_bug("outb")
+#define outw(v,p)	__readwrite_bug("outw")
+#define outl(v,p)	__readwrite_bug("outl")
+
+#define inb(p)		(__readwrite_bug("inb"), 0)
+#define inw(p)		(__readwrite_bug("inw"), 0)
+#define inl(p)		(__readwrite_bug("inl"), 0)
+
+#define outsb(p,d,l)	__readwrite_bug("outsb")
+#define outsw(p,d,l)	__readwrite_bug("outsw")
+#define outsl(p,d,l)	__readwrite_bug("outsl")
+
+#define insb(p,d,l)	(__readwrite_bug("insb"), 0)
+#define insw(p,d,l)	(__readwrite_bug("insw"), 0)
+#define insl(p,d,l)	(__readwrite_bug("insl"), 0)
+
+/*
+ * io{read,write}{8,16,32} macros
+ */
+
+#define ioread8(p)	({ unsigned int __v = __raw_readb(p); __v; })
+#define ioread16(p)	({ unsigned int __v = le16_to_cpu(__raw_readw(p)); __v; })
+#define ioread32(p)	({ unsigned int __v = le32_to_cpu(__raw_readl(p)); __v; })
+
+#define iowrite8(v,p)	__raw_writeb(v, p)
+#define iowrite16(v,p)	__raw_writew(cpu_to_le16(v), p)
+#define iowrite32(v,p)	__raw_writel(cpu_to_le32(v), p)
+
+#define ioread8_rep(p,d,c)	__raw_readsb(p,d,c)
+#define ioread16_rep(p,d,c)	__raw_readsw(p,d,c)
+#define ioread32_rep(p,d,c)	__raw_readsl(p,d,c)
+
+#define iowrite8_rep(p,s,c)	__raw_writesb(p,s,c)
+#define iowrite16_rep(p,s,c)	__raw_writesw(p,s,c)
+#define iowrite32_rep(p,s,c)	__raw_writesl(p,s,c)
+
+#define ioport_map(c,s)		(__readwrite_bug("ioport_map"), NULL)
+#define ioport_unmap(addr)	__readwrite_bug("ioport_unmap")
+
+#endif /* !defined(CONFIG_PCI) */
+
+#endif /* __ASM_ARCH_COMCERTO1000_IO_H */
diff --git a/arch/arm/mach-comcerto/include/mach/comcerto-2000/irqs.h b/arch/arm/mach-comcerto/include/mach/comcerto-2000/irqs.h
new file mode 100644
index 0000000..625af66
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/comcerto-2000/irqs.h
@@ -0,0 +1,121 @@
+/*
+ *  arch/arm/arch-comcerto/include/mach/comcerto-2000/irqs.h
+ *
+ *  Copyright (C) 2011 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __COMCERTO_IRQS_H__
+#define __COMCERTO_IRQS_H__
+
+#define FIQ_START		(0)
+
+#define SGI_IRQ(x)		(0 + (x))	/* ID0  - ID15 */
+#define PPI_IRQ(x)		(27 + (x))	/* ID27 - ID31 */
+#define LSPI_IRQ(x)		(32 + (x))	/* ID32 - ID62 */
+#define SPI_IRQ(x)		(63 + (x))      /* ID63 - ID1020 */
+
+#define IRQ_LOCALTIMER		PPI_IRQ(2)
+#define IRQ_LOCALWDOG		PPI_IRQ(3)
+
+#define IRQ_PTP0		LSPI_IRQ(0)
+#define IRQ_PTP1		LSPI_IRQ(1)
+#define IRQ_PTP2		LSPI_IRQ(2)
+#define IRQ_PTP3		LSPI_IRQ(3)
+#define IRQ_PFE_HIF		LSPI_IRQ(4)
+#define IRQ_PFE_HIFNCPY		LSPI_IRQ(5)
+#define IRQ_PFE_GPT		LSPI_IRQ(6)
+#define IRQ_FABRIC		LSPI_IRQ(7)
+#define IRQ_A9_L1_PAR		LSPI_IRQ(8)
+#define IRQ_A9_PMU0		LSPI_IRQ(9)
+#define IRQ_A9_PMU1		LSPI_IRQ(10)
+#define IRQ_L2			LSPI_IRQ(11)
+#define IRQ_EAPE		LSPI_IRQ(12)
+#define IRQ_SPACC		LSPI_IRQ(13)
+#define IRQ_CIE			LSPI_IRQ(14)
+#define IRQ_DEC			LSPI_IRQ(15)
+#define IRQ_SATA		LSPI_IRQ(16)
+#define IRQ_CSS0		LSPI_IRQ(17)
+#define IRQ_CSS1		LSPI_IRQ(18)
+#define IRQ_CSS2		LSPI_IRQ(19)
+#define IRQ_CSS3		LSPI_IRQ(20)
+#define IRQ_USB2		LSPI_IRQ(21)
+#define IRQ_USB3		LSPI_IRQ(22)
+#define IRQ_SATA_MSI		LSPI_IRQ(23)
+#define IRQ_CSS			LSPI_IRQ(24)
+#define IRQ_DMAC		LSPI_IRQ(25)
+#define IRQ_UART0		LSPI_IRQ(26)
+#define IRQ_UART1		LSPI_IRQ(27)
+#define IRQ_UART_S2		LSPI_IRQ(27)
+#define IRQ_SPI			LSPI_IRQ(28)
+#define IRQ_SPI_LS		LSPI_IRQ(29)
+#define IRQ_I2C			LSPI_IRQ(30)
+
+#define IRQ_PFE_UPE		SPI_IRQ(0)
+#define IRQ_DDRC		SPI_IRQ(1)
+#define IRQ_TDMA_TX		SPI_IRQ(2)
+#define IRQ_TDMA_RX		SPI_IRQ(3)
+#define IRQ_TDMA_AHBERR		SPI_IRQ(4)
+#define IRQ_PFE_UPE_TIMER	SPI_IRQ(5)
+#define IRQ_TDMA		SPI_IRQ(6)
+#define IRQ_SLIC		SPI_IRQ(7)
+#define IRQ_MDMA_M2IO		SPI_IRQ(8)
+#define IRQ_MDMA_IO2M		SPI_IRQ(9)
+#define IRQ_MDMA_AXIW		SPI_IRQ(10)
+#define IRQ_MDMA_AXIR		SPI_IRQ(11)
+#define IRQ_PCIe0		SPI_IRQ(12)
+#define IRQ_PCIe1		SPI_IRQ(13)
+#define IRQ_G0			SPI_IRQ(14)
+#define IRQ_G1			SPI_IRQ(15)
+#define IRQ_G2			SPI_IRQ(16)
+#define IRQ_G3			SPI_IRQ(17)
+#define IRQ_G4			SPI_IRQ(18)
+#define IRQ_G5			SPI_IRQ(19)
+#define IRQ_G6			SPI_IRQ(20)
+#define IRQ_G7			SPI_IRQ(21)
+#define IRQ_WOL			SPI_IRQ(22)
+#define IRQ_USB3_PME		SPI_IRQ(23)
+#define IRQ_TIMER0		SPI_IRQ(24)
+#define IRQ_TIMER1		SPI_IRQ(25)
+#define IRQ_TIMER2		SPI_IRQ(26)
+#define IRQ_TIMER3		SPI_IRQ(27)
+#define IRQ_TIMER4		SPI_IRQ(28)
+#define IRQ_TIMER5		SPI_IRQ(29)
+#define IRQ_TIMER6		SPI_IRQ(30)
+#define IRQ_RTC_ALM		SPI_IRQ(31)
+#define IRQ_RTC_PRI		SPI_IRQ(32)
+
+
+/* Software decoded interrupts used by PCIE */
+#define COMCERTO_IRQ_MAX	SPI_IRQ(33)	
+
+/* PCIE MSI virtual irqs */
+#define PCIE_NUM_MSI_IRQS	32
+#define PCIE0_MSI_INT_BASE	(COMCERTO_IRQ_MAX + 0)
+#define PCIE0_MSI_INT_END	(PCIE0_MSI_INT_BASE + PCIE_NUM_MSI_IRQS)
+#define PCIE1_MSI_INT_BASE	(PCIE0_MSI_INT_END + 0)
+#define PCIE1_MSI_INT_END	(PCIE1_MSI_INT_BASE + PCIE_NUM_MSI_IRQS)
+
+#define PCIE_NUM_INTX_IRQS	4
+#define PCIE0_INTX_BASE		(PCIE1_MSI_INT_END + 0)
+#define PCIE0_INTX_END		(PCIE0_INTX_BASE + PCIE_NUM_INTX_IRQS)
+#define PCIE1_INTX_BASE		(PCIE0_INTX_END + 0)
+#define PCIE1_INTX_END		(PCIE1_INTX_BASE + PCIE_NUM_INTX_IRQS)
+
+#define VIRQ_END		PCIE1_INTX_END
+#define NR_IRQS			256
+
+#endif
+
diff --git a/arch/arm/mach-comcerto/include/mach/comcerto-2000/memory.h b/arch/arm/mach-comcerto/include/mach/comcerto-2000/memory.h
new file mode 100644
index 0000000..8253848
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/comcerto-2000/memory.h
@@ -0,0 +1,38 @@
+/*
+ *  arch/arm/arch-comcerto/include/mach/comcerto-2000/memory.h
+ *
+ *  Copyright (C) 2011 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef __MEMORY_H__
+#define __MEMORY_H__
+
+	/* Physical addresses of memories */
+	#define IRAM_MEMORY_SIZE			SZ_64K
+
+/*
+ * Virtual view <-> DMA view memory address translations
+ * virt_to_bus: Used to translate the virtual address to an
+ *              address suitable to be passed to set_dma_addr
+ * bus_to_virt: Used to convert an address for DMA operations
+ *              to an address that the kernel can use.
+ */
+
+#define aram_to_virt(p)		(void*)(((unsigned long)p - COMCERTO_AXI_IRAM_BASE) + IRAM_MEMORY_VADDR)
+#define virt_to_aram(v)		(((unsigned long)v - IRAM_MEMORY_VADDR) + COMCERTO_AXI_IRAM_BASE)
+#endif
diff --git a/arch/arm/mach-comcerto/include/mach/comcerto-2000/pcie.h b/arch/arm/mach-comcerto/include/mach/comcerto-2000/pcie.h
new file mode 100644
index 0000000..019596a
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/comcerto-2000/pcie.h
@@ -0,0 +1,175 @@
+/*
+ *  linux/include/asm-arm/arch-comcerto/comcerto-2000/pcie.h
+ *
+ *  Copyright (C) 2008 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __COMCERTO_PCIE_H__
+#define __COMCERTO_PCIE_H__
+
+/* CFG0 Register definitions */
+#define DWC_CFG0_DEV_TYPE_MASK 		0x0F
+#define 	CFG0_DEV_TYPE_EP 	0x00
+#define 	CFG0_DEV_TYPE_LEP 	0x01
+#define 	CFG0_DEV_TYPE_RC 	0x04
+#define 	CFG0_DEV_TYPE_UP_SW 	0x05
+#define 	CFG0_DEV_TYPE_DWN_SW 	0x06
+
+/* CFG1,2 Register definitions */
+/*ID definitions of ARMISC*/
+#define AXI_OP_TYPE_ID_MASK		0x0000001F
+#define AXI_OP_TYPE_ID_BIT		0
+#define AXI_OP_BCM_ID			0x00000020
+#define AXI_OP_EP_ID			0x00000040
+#define AXI_OP_TD_ID			0x00000080
+#define AXI_OP_ATTRIBUTE_ID_MASK	0x00000300
+#define AXI_OP_ATTRIBUTE_ID_BIT		8
+#define AXI_OP_TC_ID_MASK		0x00001C00
+#define AXI_OP_TC_ID_BIT		10
+#define AXI_OP_MSG_CODE_ID_MASK		0x001FE000
+#define AXI_OP_MSG_CODE_ID_BIT		13
+#define AXI_OP_DBI_ACCESS_ID		0x00200000
+#define AXI_OP_TYPE_MASK	0x1F
+#define AXI_OP_TYPE_MEM_RDRW	0
+#define AXI_OP_TYPE_MEM_RDRW_LOCKED	1
+#define AXI_OP_TYPE_IO_RDRW	2
+#define AXI_OP_TYPE_CONFIG_RDRW_TYPE0	4
+#define AXI_OP_TYPE_CONFIG_RDRW_TYPE1	5
+#define AXI_OP_TYPE_MSG_REQ	16
+#define AXI_OP_TYPE_COMPLETION	10
+#define AXI_OP_TYPE_COMPLETION_LOCKED	11
+#define AXI_OP_TYPE_DBI_ELBI_ENABLE	1
+
+
+
+/* CFG5 Register definitions */
+#define 	CFG5_APP_INIT_RST	0x01
+#define 	CFG5_LTSSM_ENABLE	0x02
+#define 	CFG5_APP_RDY_L23	0x04
+#define 	CFG5_LINK_DOWN_RST	0x200
+
+
+/* STS0 Register definitions */
+#define 	STS0_LINK_REQ_RST_NOT	0x0001
+#define 	STS0_XMLH_LINK_UP	0x8000
+#define 	STS0_RDLH_LINK_UP	0x10000
+
+/* INTR_STS and INTR_EN Register definitions */
+#define 	INTR_CTRL_INTA_ASSERT	0x0001
+#define 	INTR_CTRL_INTA_DEASSERT	0x0002
+#define 	INTR_CTRL_INTB_ASSERT	0x0004
+#define 	INTR_CTRL_INTB_DEASSERT	0x0008
+#define 	INTR_CTRL_INTC_ASSERT	0x0010
+#define 	INTR_CTRL_INTC_DEASSERT	0x0020
+#define 	INTR_CTRL_INTD_ASSERT	0x0040
+#define 	INTR_CTRL_INTD_DEASSERT	0x0080
+#define 	INTR_CTRL_AER		0x0100
+#define 	INTR_CTRL_PME		0x0200
+#define 	INTR_CTRL_HP		0x0400
+#define 	INTR_CTRL_LINK_AUTO_BW	0x0800
+#define 	INTR_CTRL_MSI		0x1000
+
+/* synopsis specific PCIE configuration registers*/
+
+/* Port Logic Registers */
+#define PCIE_ALRT_REG              0x700
+#define PCIE_AFL0L1_REG            0x70C
+#define PCIE_SYMNUM_REG            0x718
+#define PCIE_G2CTRL_REG            0x80C
+
+#define PCIE_CAP_BASE           0x70
+#define PCIE_LCAP_REG           (PCIE_CAP_BASE + 0x0C)
+#define PCIE_LCNT2_REG          (PCIE_CAP_BASE + 0x30)
+
+	/* MSI interface registers */
+#define PCIE_MSI_ADDR_LO	0x820	/* 32 bits */
+#define PCIE_MSI_ADDR_HI	0x824	/* 32 bits */
+#define PCIE_MSI_INTR0_ENABLE	0x828	/* 32 bits */
+#define PCIE_MSI_INTR0_MASK	0x82C	/* 32 bits */
+#define PCIE_MSI_INTR0_STATUS	0x830	/* 32 bits */
+
+/* iATU interface registers */
+#define PCIE_iATU_VIEW_PORT	0x900	/* 32 bits */
+#define PCIE_iATU_CTRL1		0x904   /* 32 bits */
+#define PCIE_iATU_CTRL2		0x908	/* 32 bits */
+#define PCIE_iATU_SRC_LOW	0x90C	/* 32 bits */
+#define PCIE_iATU_SRC_HIGH	0x910	/* 32 bits */
+#define PCIE_iATU_LIMIT		0x914	/* 32 bits */
+#define PCIE_iATU_TRGT_LOW	0x918	/* 32 bits */
+#define PCIE_iATU_TRGT_HIGH	0x91C	/* 32 bits */
+
+/*******************************************************/
+/* BAR MASK Registers (uses dbi_cs2)                   */
+/*******************************************************/
+#define PCIE_BAR0_MASK_REG              0x100010
+
+/* iATU viewport register definitions */
+#define iATU_VIEW_PORT_ID_MASK	0x0F
+#define iATU_VIEW_PORT_ID_BIT	0
+#define iATU_VIEW_PORT_IN_BOUND	0X80000000
+
+/* iATU control1 register definitions */
+#define iATU_CTRL1_TYPE_MASK	0x001F
+#define iATU_CTRL1_TYPE_BIT	0
+#define iATU_CTRL1_TC_MASK	0x00E0
+#define iATU_CTRL1_TC_BIT	5
+#define iATU_CTRL1_TD		0x100
+
+
+/* iATU control2 register definitions */
+#define iATU_CTRL2_ID_EN		0x80000000
+#define iATU_CTRL2_IB_MEM_BAR_MATCH	0x40000000
+#define iATU_CTRL2_IB_CFG0_ACCEPT	0x40000000
+#define iATU_CTRL2_IB_MATCH_BAR0	0x00000000
+#define iATU_CTRL2_IB_MATCH_BAR1	0x00000100
+#define iATU_CTRL2_IB_MATCH_BAR2	0x00000200
+#define iATU_CTRL2_IB_MATCH_BAR3	0x00000300
+#define iATU_CTRL2_IB_MATCH_BAR4	0x00000400
+#define iATU_CTRL2_IB_MATCH_BAR5	0x00000500
+#define iATU_CTRL2_IB_MATCH_ROM		0x00000600
+
+#define iATU_ENTRY_MAX		8
+#define iATU_ENTRY_MEM		0
+#define iATU_ENTRY_IO		1
+#define iATU_ENTRY_CNF0		2
+#define iATU_ENTRY_CNF1		3
+#define iATU_ENTRY_MSG		4
+
+/** 254MB,s used for slave memory mapped address space remaining 2MB
+ *  is used for IO, CFG0/1 and MSG transalation. This value cann't be
+ *  increased.
+ */
+#define COMCERTO_PCIe_MEM_SIZE				(254 * 1024 *1024)
+#define COMCERTO_PCIe_MSG_SIZE				(1 * 1024 * 1024)
+#define COMCERTO_PCIe_IO_SIZE				(64 * 1024)
+#define COMCERTO_PCIe_CFG0_SIZE				(64 * 1024)
+#define COMCERTO_PCIe_CFG1_SIZE				(64 * 1024)
+
+/* Sum of all these space can maximum be 256MB */
+#define iATU_MEM_SIZE	(COMCERTO_PCIe_MEM_SIZE)
+#define iATU_MSG_SIZE	(COMCERTO_PCIe_MSG_SIZE)
+#define iATU_IO_SIZE	(COMCERTO_PCIe_IO_SIZE)
+#define iATU_CFG0_SIZE	(COMCERTO_PCIe_CFG0_SIZE)
+#define iATU_CFG1_SIZE	(COMCERTO_PCIe_CFG1_SIZE)
+
+#define iATU_GET_MEM_BASE( _base ) (_base + 0)
+#define iATU_GET_MSG_BASE( _base ) ( iATU_GET_MEM_BASE ( _base ) + iATU_MEM_SIZE)
+#define iATU_GET_IO_BASE( _base ) ( iATU_GET_MSG_BASE( _base ) + iATU_MSG_SIZE)
+#define iATU_GET_CFG0_BASE( _base ) ( iATU_GET_IO_BASE( _base ) + iATU_IO_SIZE)
+#define iATU_GET_CFG1_BASE( _base ) ( iATU_GET_CFG0_BASE( _base ) + iATU_CFG0_SIZE)
+
+#endif /* __COMCERTO_PCIE_H__ */
diff --git a/arch/arm/mach-comcerto/include/mach/comcerto-2000/pm.h b/arch/arm/mach-comcerto/include/mach/comcerto-2000/pm.h
new file mode 100644
index 0000000..80f2102
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/comcerto-2000/pm.h
@@ -0,0 +1,72 @@
+/*
+ * pm.h
+ *
+ * Power managemen driver for Comcerto C2K device - internal header file
+ *
+ * This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#ifndef __ARCH_ARM_C2K_PM_H__
+#define __ARCH_ARM_C2K_PM_H__
+
+/* PMU Interrup masks */
+#define GPIO0_IRQ               (1 << 0)
+#define GPIO1_IRQ               (1 << 1)
+#define GPIO2_IRQ               (1 << 2)
+#define GPIO3_IRQ               (1 << 3)
+
+#define GPIO4_IRQ               (1 << 4)
+#define GPIO5_IRQ               (1 << 5)
+#define GPIO6_IRQ               (1 << 6)
+#define GPIO7_IRQ               (1 << 7)
+
+#define TIMER0_IRQ              (1 << 8)
+#define TIMER1_IRQ              (1 << 9)
+#define TIMER2_IRQ              (1 << 10)
+#define TIMER3_IRQ              (1 << 11)
+
+#define ZDS_MSIF_IRQ            (1 << 12)
+#define RTC_ALM_IRQ             (1 << 13)
+#define RTC_PRI_IRQ             (1 << 14)
+#define PCIe0_IRQ               (1 << 15)
+
+#define PCIe1_IRQ               (1 << 16)
+#define SATA_IRQ                (1 << 17)
+#define SATA_MSI_IRQ            (1 << 18)
+#define USB2p0_IRQ              (1 << 19)
+
+#define USB3p0_IRQ              (1 << 20)
+#define HFE_0_IRQ               (1 << 21)
+#define WOL_IRQ                 (1 << 22)
+#define CSS_IRQ                 (1 << 23)
+
+#define DUS_DMAC_IRQ            (1 << 24)
+#define DUS_UART0_IRQ           (1 << 25)
+#define DUS_UART0UARTS2_IRQ     (1 << 26)
+#define HFE_1_IRQ               (1 << 27)
+
+#define USB3p0_PM               (1 << 28)
+#define PTP0_IRQ                (1 << 29)
+#define PTP1_IRQ                (1 << 30)
+#define PTP2_IRQ                (1 << 31)
+
+#define JUMP_TO_RESUME_1		        0xe3a00020 	/* mov	r0, #32 */
+#define JUMP_TO_RESUME_2		        0xe590f000 	/* ldr	pc, [r0] */
+
+/*
+ * Two Bytes are used as shared memory between Host and UtilPE
+ * One for installing the Suspend Event and Return Resume location
+ * 2nd to pass the bitmask
+ */
+#define HOST_UTILPE_SHARED_ADDRESS_OFF  0x2400 /* This is offset into the iRAM */
+#define HOST_UTILPE_SHARED_ADDRESS      (IRAM_MEMORY_VADDR+HOST_UTILPE_SHARED_ADDRESS_OFF)
+
+/* Global Variable for Shared Util-PE interrupt Mask */
+extern unsigned host_utilpe_shared_pmu_bitmask;
+
+void c2k_pm_bitmask_store(unsigned int);
+unsigned int c2k_pm_bitmask_show(void);
+
+#endif
diff --git a/arch/arm/mach-comcerto/include/mach/comcerto-2000/serdes.h b/arch/arm/mach-comcerto/include/mach/comcerto-2000/serdes.h
new file mode 100644
index 0000000..0fa0ffe
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/comcerto-2000/serdes.h
@@ -0,0 +1,61 @@
+
+/*
+ * Copyright (C) Mindspeed Technologies, Inc. 2011. All rights reserved.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * @file serdes.h
+ * @brief this header file will contain all required data structure
+ *        and function definitions for Snowbush SerDes PHY interface.
+ * @date 10/02/2011
+ */
+
+#ifndef __COMCERTO_SERDES_H__
+#define __COMCERTO_SERDES_H__
+
+/* SER-DES Address space */
+#define SD_COMMON_CMU     0x000
+#define SD_LANE0          0x200
+#define SD_LANE1          0x400
+#define SD_LANE2          0x600
+#define SD_LANE3          0x800
+#define SD_COMMON_LANE    0xA00
+
+#define SD_DEV_TYPE_PCIE	0	
+#define	SD_DEV_TYPE_SATA	1
+#define	SD_DEV_TYPE_SGMII	2
+
+
+#define COMCERTO_APB_SERDES0_BASE	APB_VADDR(COMCERTO_APB_SERDES_CONF_BASE)
+#define COMCERTO_APB_SERDES1_BASE	(COMCERTO_APB_SERDES0_BASE + 0x4000)
+#define COMCERTO_APB_SERDES2_BASE	(COMCERTO_APB_SERDES0_BASE + 0x8000)
+
+#define COMCERTO_DWC1_CFG_BASE 		APB_VADDR(COMCERTO_APB_USBPHY_SERDES_STAT_BASE)
+#define COMCERTO_DWC1_SERDES_CFG_BASE 	COMCERTO_DWC1_CFG_BASE + 0x2C
+#define SD_PHY_STS_REG_OFST		0x00
+#define SD_PHY_CTRL1_REG_OFST		0x04
+#define SD_PHY_CTRL2_REG_OFST		0x08
+#define SD_PHY_CTRL3_REG_OFST		0x0C
+
+
+#define COMCERTO_SERDES_REG( _num, _ofst) ((COMCERTO_APB_SERDES0_BASE + (0x4000 * _num)) + _ofst)
+
+#define COMCERTO_SERDES_DWC_CFG_REG( _num, _ofst) ((COMCERTO_DWC1_SERDES_CFG_BASE + (_num <<4)) + _ofst)
+
+#endif //__COMCERTO_SERDES_H__
diff --git a/arch/arm/mach-comcerto/include/mach/comcerto-2000/spi.h b/arch/arm/mach-comcerto/include/mach/comcerto-2000/spi.h
new file mode 100644
index 0000000..ce61974
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/comcerto-2000/spi.h
@@ -0,0 +1,71 @@
+/*
+ *  linux/include/asm-arm/arch-comcerto/comcerto1000/spi.h
+ *
+ *  Copyright (C) 2004,2008 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARCH_COMCERTO1000_SPI_H
+#define __ASM_ARCH_COMCERTO1000_SPI_H
+
+#define COMCERTO_SPI_FIFO_DEPTH		8
+
+/* SPI core registers */
+#define COMCERTO_SPI_CTRLR0		0x00
+#define COMCERTO_SPI_CTRLR1		0x04
+#define COMCERTO_SPI_SSIENR		0x08
+#define COMCERTO_SPI_MWCR		0x0C
+#define COMCERTO_SPI_SER		0x10
+#define COMCERTO_SPI_BAUDR		0x14
+#define COMCERTO_SPI_TXFTLR		0x18
+#define COMCERTO_SPI_RXFTLR		0x1C
+#define COMCERTO_SPI_TXFLR		0x20
+#define COMCERTO_SPI_RXFLR		0x24
+#define COMCERTO_SPI_SR			0x28
+#define COMCERTO_SPI_IMR		0x2C
+#define COMCERTO_SPI_ISR		0x30
+#define COMCERTO_SPI_RISR		0x34
+#define COMCERTO_SPI_TXOICR		0x38
+#define COMCERTO_SPI_RXOICR		0x3C
+#define COMCERTO_SPI_RXUICR		0x40
+#define COMCERTO_SPI_MSTICR		0x44
+#define COMCERTO_SPI_ICR		0x48
+#define COMCERTO_SPI_IDR		0x58
+#define COMCERTO_SPI_DR			0x60
+
+/* CTRLR0 - control register 0 bits/masks (incomplete) */
+#define SPI_CTRLR0_DFS_MASK		(15<<0)	/* Data frame size mask */
+#define SPI_CTRLR0_SCPOL		(1<<7)	/* Serial clock polarity */
+#define SPI_CTRLR0_SCPH			(1<<6)	/* Serial clock phase */
+#define SPI_CTRLR0_SRL			(1<<11)	/* Shift register loop */
+
+/* SR - status register bits */
+#define SPI_SR_BUSY			(1<<0)	/* SSI busy flag, serial transfer in progress */
+#define SPI_SR_TFNF			(1<<1)	/* Transmit FIFO not full */
+#define SPI_SR_TFE			(1<<2)	/* Transmit FIFO empty */
+#define SPI_SR_RFNE			(1<<3)	/* Receive FIFO not empty */
+#define SPI_SR_RFF			(1<<4)	/* Receive FIFO full */
+#define SPI_SR_TXE			(1<<5)	/* Transmission error */
+#define SPI_SR_DCOL			(1<<6)	/* Data collision error */
+
+/* IMR, ISR, RISR - interrupt mask/status bits */
+#define SPI_INT_TXEI			(1<<0)	/* Transmit FIFO empty interrupt status */
+#define SPI_INT_TXOI			(1<<1)	/* Transmit FIFO overflow interrupt status */
+#define SPI_INT_RXUI			(1<<2)	/* Receive FIFO underflow interrupt status */
+#define SPI_INT_RXOI			(1<<3)	/* Receive FIFO overflow interrupt status */
+#define SPI_INT_RXFI			(1<<4)	/* Receive FIFO full interrupt status */
+#define SPI_INT_MSTI			(1<<5)	/* Multi-Master contention interrupt status */
+
+#endif /* __ASM_ARCH_COMCERTO1000_SPI_H */
diff --git a/arch/arm/mach-comcerto/include/mach/comcerto-2000/timer.h b/arch/arm/mach-comcerto/include/mach/comcerto-2000/timer.h
new file mode 100644
index 0000000..99396fe
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/comcerto-2000/timer.h
@@ -0,0 +1,106 @@
+/*
+ *  linux/include/asm-arm/arch-comcerto/comcerto-1000/timer.h
+ *
+ *  Copyright (C) 2004-2008 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __TIMER_H__
+#define __TIMER_H__
+
+
+/* Comcerto Timers  */
+#define COMCERTO_TIMER0_HIGH_BOUND          APB_VADDR(COMCERTO_APB_TIMER_BASE + 0x00)
+#define COMCERTO_TIMER0_CURRENT_COUNT       APB_VADDR(COMCERTO_APB_TIMER_BASE + 0x04)
+#define COMCERTO_TIMER1_HIGH_BOUND          APB_VADDR(COMCERTO_APB_TIMER_BASE + 0x08)
+#define COMCERTO_TIMER1_CURRENT_COUNT       APB_VADDR(COMCERTO_APB_TIMER_BASE + 0x0C)
+#define COMCERTO_TIMER2_LOW_BOUND           APB_VADDR(COMCERTO_APB_TIMER_BASE + 0x10)
+#define COMCERTO_TIMER2_HIGH_BOUND          APB_VADDR(COMCERTO_APB_TIMER_BASE + 0x14)
+#define COMCERTO_TIMER2_CTRL                APB_VADDR(COMCERTO_APB_TIMER_BASE + 0x18)
+#define COMCERTO_TIMER2_CURRENT_COUNT       APB_VADDR(COMCERTO_APB_TIMER_BASE + 0x1C)
+#define COMCERTO_TIMER3_LOW_BOUND           APB_VADDR(COMCERTO_APB_TIMER_BASE + 0x20)
+#define COMCERTO_TIMER3_HIGH_BOUND          APB_VADDR(COMCERTO_APB_TIMER_BASE + 0x24)
+#define COMCERTO_TIMER3_CTRL                APB_VADDR(COMCERTO_APB_TIMER_BASE + 0x28)
+#define COMCERTO_TIMER3_CURRENT_COUNT       APB_VADDR(COMCERTO_APB_TIMER_BASE + 0x2C)
+#define COMCERTO_TIMER4_HIGH_BOUND          APB_VADDR(COMCERTO_APB_TIMER_BASE + 0x30)
+#define COMCERTO_TIMER4_CURRENT_COUNT       APB_VADDR(COMCERTO_APB_TIMER_BASE + 0x34)
+#define COMCERTO_TIMER5_LOW_BOUND           APB_VADDR(COMCERTO_APB_TIMER_BASE + 0x38)
+#define COMCERTO_TIMER5_HIGH_BOUND          APB_VADDR(COMCERTO_APB_TIMER_BASE + 0x3C)
+#define COMCERTO_TIMER5_CURRENT_COUNT       APB_VADDR(COMCERTO_APB_TIMER_BASE + 0x40)
+#define COMCERTO_TIMER5_CTRL                APB_VADDR(COMCERTO_APB_TIMER_BASE + 0x44)
+#define COMCERTO_TIMER_IRQ_MASK             APB_VADDR(COMCERTO_APB_TIMER_BASE + 0x48)
+#define COMCERTO_TIMER_STATUS               APB_VADDR(COMCERTO_APB_TIMER_BASE + 0x50)
+#define COMCERTO_TIMER_STATUS_CLR           APB_VADDR(COMCERTO_APB_TIMER_BASE + 0x50)
+#define COMCERTO_TIMER_WDT_HIGH_BOUND       APB_VADDR(COMCERTO_APB_TIMER_BASE + 0xD0)
+#define COMCERTO_TIMER_WDT_CONTROL          APB_VADDR(COMCERTO_APB_TIMER_BASE + 0xD4)
+#define COMCERTO_TIMER_WDT_CURRENT_COUNT    APB_VADDR(COMCERTO_APB_TIMER_BASE + 0xD8)
+
+#define COMCERTO_TIMER_WDT_CONTROL_TIMER_ENABLE		(1 << 0)
+
+/*COMCERTO_TIMER_IRQ_MASK*/
+#define COMCERTO_TIMER0     0x01
+#define COMCERTO_TIMER1     0x02
+#define COMCERTO_TIMER2     0x04
+#define COMCERTO_TIMER3     0x08
+#define COMCERTO_TIMER4     0x10
+#define COMCERTO_TIMER5     0x20
+#define COMCERTO_ALL        0xFF
+#define COMCERTO_TIMER_CSP  (COMCERTO_TIMER1 | COMCERTO_TIMER2 | COMCERTO_TIMER3 | COMCERTO_TIMER4 | COMCERTO_TIMER5)
+
+/*
+ * TIMERS
+ */
+
+
+/*Hardware Timer API*/
+#define COMCERTO_TIMER_RUN_ONCE		(1 << 0)
+#define __comcerto_timer_enable(t)	__raw_writel(__raw_readl(COMCERTO_TIMER_IRQ_MASK) | (1 << (t)), COMCERTO_TIMER_IRQ_MASK)
+#define __comcerto_timer_disable(t)	__raw_writel(__raw_readl(COMCERTO_TIMER_IRQ_MASK) & ~(1 << (t)), COMCERTO_TIMER_IRQ_MASK)
+#define comcerto_timer_ack(t)		__raw_writel(1 << (t), COMCERTO_TIMER_STATUS_CLR)
+
+#define comcerto_timer0_set(hbound)	__raw_writel((hbound), COMCERTO_TIMER0_HIGH_BOUND)
+#define comcerto_timer0_get()		__raw_readl(COMCERTO_TIMER0_CURRENT_COUNT)
+
+#define comcerto_timer1_set(hbound)	__raw_writel((hbound) & 0x3FFFFFFF, COMCERTO_TIMER1_HIGH_BOUND)
+#define comcerto_timer1_get()		__raw_readl(COMCERTO_TIMER1_CURRENT_COUNT)
+
+#define comcerto_timer2_set(lbound, hbound, ctrl)  do {\
+						      __raw_writel((ctrl) & 0x1, COMCERTO_TIMER2_CTRL);	\
+						      __raw_writel((lbound), COMCERTO_TIMER2_LOW_BOUND);	\
+						      __raw_writel((hbound), COMCERTO_TIMER2_HIGH_BOUND);	\
+						   } while (0)
+
+#define comcerto_timer2_get()		__raw_readl(COMCERTO_TIMER2_CURRENT_COUNT)
+
+
+#define comcerto_timer3_set(lbound, hbound, ctrl)  do {								\
+						      __raw_writel((ctrl) & 0x1, COMCERTO_TIMER3_CTRL);	\
+						      __raw_writel((lbound), COMCERTO_TIMER3_LOW_BOUND);	\
+						      __raw_writel((hbound), COMCERTO_TIMER3_HIGH_BOUND);	\
+						   } while(0)
+
+#define comcerto_timer3_get()		__raw_readl(COMCERTO_TIMER3_CURRENT_COUNT)
+
+#ifndef __ASSEMBLY__
+struct comcerto_timer {
+	unsigned long timeout;
+	void (*func) (unsigned long data);
+	unsigned long data;
+	unsigned char flags;
+	unsigned long thw;
+};
+#endif
+#endif
diff --git a/arch/arm/mach-comcerto/include/mach/comcerto-2000/wdt.h b/arch/arm/mach-comcerto/include/mach/comcerto-2000/wdt.h
new file mode 100644
index 0000000..6b78dbd
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/comcerto-2000/wdt.h
@@ -0,0 +1,24 @@
+/*
+ *  linux/include/asm/arch/comcerto1000/wdt.h
+ *
+ *  Copyright (C) 2004,2008 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARCH_COMCERTO1000_WDT_H
+#define __ASM_ARCH_COMCERTO1000_WDT_H
+
+
+#endif /* __ASM_ARCH_COMCERTO1000_WDT_H */
diff --git a/arch/arm/mach-comcerto/include/mach/comcerto-common.h b/arch/arm/mach-comcerto/include/mach/comcerto-common.h
new file mode 100644
index 0000000..6a14993
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/comcerto-common.h
@@ -0,0 +1,171 @@
+/*
+ *  arch/arm/mach-comcerto/include/mach/comcerto-common.h
+ *
+ *  Copyright (C) 2012 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#error "Do not include this directly, instead #include <asm/hardware.h>"
+#endif
+
+#ifndef __ASM_COMCERTO_COMMON_H__
+#define __ASM_COMCERTO_COMMON_H__
+
+#include <asm/types.h>
+
+#define APB_VADDR(x)	((x) - COMCERTO_AXI_APB_BASE + COMCERTO_APB_VADDR)		/* macro to get virtual address of IO on APB Bus from Physical address*/
+#define AXI_VADDR(x)	((x) - COMCERTO_AXI_SPI_BASE + COMCERTO_AXI_SSI_VADDR)	/* macro to get virtual address of IO on AXI Bus from Physical address*/
+
+#define  BIT_0_MSK   0x00000001
+#define  BIT_1_MSK   0x00000002
+#define  BIT_2_MSK   0x00000004
+#define  BIT_3_MSK   0x00000008
+#define  BIT_4_MSK   0x00000010
+#define  BIT_5_MSK   0x00000020
+#define  BIT_6_MSK   0x00000040
+#define  BIT_7_MSK   0x00000080
+#define  BIT_8_MSK   0x00000100
+#define  BIT_9_MSK   0x00000200
+#define  BIT_10_MSK  0x00000400
+#define  BIT_11_MSK  0x00000800
+#define  BIT_12_MSK  0x00001000
+#define  BIT_13_MSK  0x00002000
+#define  BIT_14_MSK  0x00004000
+#define  BIT_15_MSK  0x00008000
+#define  BIT_16_MSK  0x00010000
+#define  BIT_17_MSK  0x00020000
+#define  BIT_18_MSK  0x00040000
+#define  BIT_19_MSK  0x00080000
+#define  BIT_20_MSK  0x00100000
+#define  BIT_21_MSK  0x00200000
+#define  BIT_22_MSK  0x00400000
+#define  BIT_23_MSK  0x00800000
+#define  BIT_24_MSK  0x01000000
+#define  BIT_25_MSK  0x02000000
+#define  BIT_26_MSK  0x04000000
+#define  BIT_27_MSK  0x08000000
+#define  BIT_28_MSK  0x10000000
+#define  BIT_29_MSK  0x20000000
+#define  BIT_30_MSK  0x40000000
+#define  BIT_31_MSK  0x80000000
+
+/*
+ * GPIO
+ */
+/* Set gpio pins specified by gpiomask to be outputs */
+#define comcerto_gpio_enable_output(gpiomask)	__raw_writel(__raw_readl(COMCERTO_GPIO_OE_REG) | (gpiomask), COMCERTO_GPIO_OE_REG)
+
+/* Set output pins specified by gpiomask to low */
+#define comcerto_gpio_set_0(gpiomask)	__raw_writel(__raw_readl(COMCERTO_GPIO_OUTPUT_REG) & ~(gpiomask), COMCERTO_GPIO_OUTPUT_REG)
+
+/* Set output pins specified by gpiomask to high */
+#define comcerto_gpio_set_1(gpiomask)	__raw_writel(__raw_readl(COMCERTO_GPIO_OUTPUT_REG) | (gpiomask), COMCERTO_GPIO_OUTPUT_REG)
+
+/* Read status of input pins specified by gpiomask */
+#define comcerto_gpio_read(gpiomask)	(__raw_readl(COMCERTO_GPIO_INPUT_REG) & (gpiomask))
+
+
+#ifndef __ASSEMBLY__
+#define CONFIG_COMCERTO_GEMAC		1
+
+#define CONFIG_COMCERTO_USE_MII		1
+#define CONFIG_COMCERTO_USE_RMII		2
+#define CONFIG_COMCERTO_USE_GMII		4
+#define CONFIG_COMCERTO_USE_RGMII	8
+#define CONFIG_COMCERTO_USE_SGMII	0x10
+
+#define GEMAC_SW_CONF			(1 << 8) | (1 << 11)	// GEMAC configured by SW
+#define GEMAC_PHY_CONF		0			// GEMAC configured by phy lines (not for MII/GMII)
+#define GEMAC_SW_FULL_DUPLEX	(1 << 9)
+#define GEMAC_SW_SPEED_10M	(0 << 12)
+#define GEMAC_SW_SPEED_100M	(1 << 12)
+#define GEMAC_SW_SPEED_1G		(2 << 12)
+
+#define GEMAC_NO_PHY			(1 << 0)		// set if no phy connected to MAC (ex ethernet switch). In this case use MAC fixed configuration
+#define GEMAC_PHY_RGMII_ADD_DELAY	(1 << 1)
+
+/* gemac to interface name assignment */
+#define GEM0_ITF_NAME "eth0"
+#define GEM1_ITF_NAME "eth2"
+#define GEM2_ITF_NAME "eth3"
+
+#define GEM0_MAC { 0x00, 0xED, 0xCD, 0xEF, 0xAA, 0xCC }
+#define GEM1_MAC { 0x00, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E }
+#define GEM2_MAC { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }
+
+struct comcerto_eth_platform_data {
+	/* device specific information */
+	u32 device_flags;
+	char name[16];
+
+
+	/* board specific information */
+	u32 mii_config;
+	u32 gemac_mode;
+	u32 phy_flags;
+	u32 gem_id;
+	u32 bus_id;
+	u32 phy_id;
+	u8 *mac_addr;
+};
+
+struct comcerto_mdio_platform_data {
+	int enabled;
+	int irq[32];
+	u32 phy_mask;
+	int mdc_div;
+};
+
+struct comcerto_pfe_platform_data
+{
+	struct comcerto_eth_platform_data comcerto_eth_pdata[3];
+	struct comcerto_mdio_platform_data comcerto_mdio_pdata[3];
+};
+
+struct comcerto_tdm_data {
+	u8 fsoutput; /* Generic Pad Control and Version ID Register[2] */
+	u8 fspolarity; /*  28 FSYNC_FALL(RISE)_EDGE */
+	u16 fshwidth; /* High_Phase_Width[10:0] */
+	u16 fslwidth; /* Low_Phase_Width[26:16]] */
+	u32 clockhz; /* INC_VALUE[29:0] According to the desired TDM clock output frequency, this field should be configured */
+	u8 clockout; /* IO Control Register[21]  hardware or software control selection  IO Control Register[20] pads are input (output) */
+	u8 tdmmux;
+#if 0
+	u32 tdmck;
+	u32 tdmfs;
+	u32 tdmdx;
+	u32 tdmdr;
+#endif
+};
+
+/* L210 cache controller value
+    // Configure Aux:
+    //   [11:9]=[8:6]=[2:0]=001 RAM LAT = 2 cycles
+    //   [5:3]=000    Data write latency is 1
+    //   [12]=0       WRAP access is enabled
+    //   [16:13]=1000 8-way cache
+    //   [19:17]=001  16KB way
+    //   [20]=1       Event bus is enabled
+    //   [21]=1       Parity is enabled
+    //   [22]=0       Shared accesses treated as noncacheable
+    //   [23]=0       HPROT is used
+    //   [24]=1       Abort generation of exclusive access disabled
+*/
+#define L210_AUX_CTRL_REG	0x01330241
+
+#endif
+#endif
diff --git a/arch/arm/mach-comcerto/include/mach/debug-macro.S b/arch/arm/mach-comcerto/include/mach/debug-macro.S
new file mode 100644
index 0000000..c1efb9b
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/debug-macro.S
@@ -0,0 +1,53 @@
+/*
+ * arch/arm/mach-comcerto/include/mach/debug-macro.S
+ *
+ * Copyright (C) 2012 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define UART_LSR	0x14
+
+
+	.macro	addruart, rx, rv, tmp
+	moveq	\rx, #0x96000000	@ physical base address
+	@movne	\rv, #0xf1600000	@ virtual base
+	#ifdef CONFIG_COMCERTO_UART1_SUPPORT
+		orr	\rx, \rx, #0x00400000
+		orr	\rv, \rv, #0x00400000
+	#elif CONFIG_COMCERTO_UART0_SUPPORT
+		orr	\rx, \rx, #0x00300000
+		orr	\rv, \rv, #0x00300000
+	#else
+		#error no uart defined
+	#endif
+	.endm
+
+	.macro	senduart,rd,rx
+	strb	\rd, [\rx, #0x00]
+	.endm
+
+	.macro	waituart,rd,rx
+1001:	ldrb	\rd, [\rx, #UART_LSR]
+	tst	\rd, #0x20		@ wait for THRE
+	beq	1001b
+	.endm
+
+	.macro	busyuart,rd,rx
+1001:	ldrb	\rd, [\rx, #UART_LSR]
+	and	\rd, \rd, #0x60
+	teq	\rd, #0x60		@ wait for TEMT and THRE
+	bne	1001b
+	.endm
diff --git a/arch/arm/mach-comcerto/include/mach/debug.h b/arch/arm/mach-comcerto/include/mach/debug.h
new file mode 100644
index 0000000..0cc2eae
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/debug.h
@@ -0,0 +1,66 @@
+/*
+ *  linux/include/asm-arm/arch-comcerto/debug.h
+ *
+ *  Copyright (C) 2004,2005 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _DEBUG_H
+#define _DEBUG_H
+
+#include <linux/kernel.h>
+
+/* debug messages: to disable comment the next line */
+#define DEBUG_MSG
+
+/* several debug levels: 1 enables, 0 disables */
+
+#define DEBUG_ALWAYS 		1
+
+/* prints general information */
+#define DEBUG_INFO			1
+
+/* prints timing information */
+#define DEBUG_TIMING		0
+
+#define DEBUG_DISPLAY 		1
+
+#define VED_INIT_FUNC		1
+#define VED_RX_FUNC		0
+#define VED_TX_FUNC		0
+#define VED_STATE		0
+#define SMI_PART		0
+
+#define SKB_POOL_ERR		1
+#define SKB_POOL_INIT		0
+#define SKB_POOL_FUNC		0
+
+#define MSP_ERR			1
+#define MSP_INIT		0
+#define MSP_FUNC		0
+
+
+/* add other debug messages types here */
+
+/* the debug macro */
+#ifdef DEBUG_MSG
+#define info(fmt, args...) printk(KERN_INFO __FILE__ ": " fmt "\n" , ## args)
+#define PDEBUG(type, fmt, args...) do {if(type) info ("%d: " fmt, __LINE__ , ## args);} while(0)
+#else
+#define PDEBUG(type, fmt, args...) do{} while(0)
+#endif
+
+#endif	/* _DEBUG_H */
diff --git a/arch/arm/mach-comcerto/include/mach/dma.h b/arch/arm/mach-comcerto/include/mach/dma.h
new file mode 100644
index 0000000..cc08f34
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/dma.h
@@ -0,0 +1,552 @@
+/*
+ *  linux/include/asm-arm/arch-comcerto/dma.h
+ *
+ *  Copyright (C) 2004,2005 Mindspeed Technologies
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARCH_DMA_H
+#define __ASM_ARCH_DMA_H
+
+
+
+typedef long I32;
+typedef char I8;
+typedef unsigned char U8;
+typedef unsigned short U16;
+typedef unsigned long U32;
+typedef volatile unsigned char V8;
+typedef volatile unsigned short V16;
+typedef volatile unsigned long V32;
+typedef unsigned int BOOL; 
+typedef U32 (*CKSUMFUNC)(void);
+typedef U32 (*PLUGINPROC)(void * );
+
+typedef enum _retcode
+{
+   RETCODE_OK = 0,
+   RETCODE_ERROR,
+   RETCODE_BAD_PARAMETER,
+   RETCODE_MISMATCH,                /* Security violation. */
+   RETCODE_INVALID_FUSE_SETTING,    /* Security violation. */
+   RETCODE_INVALID_IMAGE_HEADER,    /* Security violation. */
+   RETCODE_RSA_ERROR,               /* Security Violation. */
+   RETCODE_NO_VALID_COPY,  
+   RETCODE_HDCP_KEY_LOAD_FAILED,
+   RETCODE_FUSE_PROGRAM_FAILED,
+   RETCODE_OTP_ERR,
+   RETCODE_FAILED,
+   RETCODE_BOOTDEV_UART,
+   RETCODE_BOOTDEV_FLASH,
+   RETCODE_BOOTDEV_INVALID,
+   RETCODE_FLASH_DEVICE_NOT_SUPPORTED,
+   RETCODE_FLASH_BAD_BLOCK,
+   RETCODE_FLASH_UNCORRECTABLE_ERROR,
+   RETCODE_UARTBOOT_ERROR,
+   RETCODE_NOT_SUPPORTED,
+   RETCODE_INVALID_BOOT_DEV,
+   RETCODE_SECURE_BOOT_ENABLE,
+   RETCODE_SECURE_BOOT_DISABLE,
+   RETCODE_YMODEM_HDR_ERROR,
+   RETCODE_YMODEM_PKT_ERROR,
+   RETCODE_YMODEM_DONE_ERROR,
+   RETCODE_PAD_ERROR,
+   RETCODE_ECC_ERR_CORRECTED,
+   RETCODE_ECC_ERR_UNCORRECTABLE,
+   RETCODE_ECC_DATA_ERROR,
+   RETCODE_NAND_BBT_OUT_OF_BOUND
+} retcode;
+
+
+
+/*
+  * DW DMA (HS SPI and UART) Block
+  */
+
+#define DW_DMA_DMAC_BASEADDR				(COMCERTO_AXI_UART_SPI_BASE+0x00000000)
+#define DW_DMA_UART0_BASEADDR				(COMCERTO_AXI_UART_SPI_BASE+0x00300000)
+#define DW_DMA_UART1_BASEADDR				(COMCERTO_AXI_UART_SPI_BASE+0x00400000)
+#define DW_DMA_SSI_BASEADDR					(COMCERTO_AXI_UART_SPI_BASE+0x00500000)
+
+
+/*
+  * DW DMA DMAC
+  */
+
+/* Channel Registers */  
+#define DW_DMA_DMAC_SAR0					(DW_DMA_DMAC_BASEADDR+0x000)
+#define DW_DMA_DMAC_DAR0					(DW_DMA_DMAC_BASEADDR+0x008)
+#define DW_DMA_DMAC_LLP0					(DW_DMA_DMAC_BASEADDR+0x010)
+#define DW_DMA_DMAC_CTL0					(DW_DMA_DMAC_BASEADDR+0x018)
+#define DW_DMA_DMAC_SSTAT0					(DW_DMA_DMAC_BASEADDR+0x020)
+#define DW_DMA_DMAC_DSTAT0					(DW_DMA_DMAC_BASEADDR+0x028)
+#define DW_DMA_DMAC_SSTATAR0				(DW_DMA_DMAC_BASEADDR+0x030)
+#define DW_DMA_DMAC_DSTATAR0				(DW_DMA_DMAC_BASEADDR+0x038)
+#define DW_DMA_DMAC_CFG0					(DW_DMA_DMAC_BASEADDR+0x040)
+#define DW_DMA_DMAC_SGR0					(DW_DMA_DMAC_BASEADDR+0x048)
+#define DW_DMA_DMAC_DSR0					(DW_DMA_DMAC_BASEADDR+0x050)
+
+#define DW_DMA_DMAC_SAR1					(DW_DMA_DMAC_BASEADDR+0x058)
+#define DW_DMA_DMAC_DAR1					(DW_DMA_DMAC_BASEADDR+0x060)
+#define DW_DMA_DMAC_LLP1					(DW_DMA_DMAC_BASEADDR+0x068)
+#define DW_DMA_DMAC_CTL1					(DW_DMA_DMAC_BASEADDR+0x070)
+#define DW_DMA_DMAC_SSTAT1					(DW_DMA_DMAC_BASEADDR+0x078)
+#define DW_DMA_DMAC_DSTAT1					(DW_DMA_DMAC_BASEADDR+0x080)
+#define DW_DMA_DMAC_SSTATAR1				(DW_DMA_DMAC_BASEADDR+0x088)
+#define DW_DMA_DMAC_DSTATAR1				(DW_DMA_DMAC_BASEADDR+0x090)
+#define DW_DMA_DMAC_CFG1					(DW_DMA_DMAC_BASEADDR+0x098)
+#define DW_DMA_DMAC_SGR1					(DW_DMA_DMAC_BASEADDR+0x0A0)
+#define DW_DMA_DMAC_DSR1					(DW_DMA_DMAC_BASEADDR+0x0A8)
+
+#define DW_DMA_DMAC_SAR2					(DW_DMA_DMAC_BASEADDR+0x0B0)
+#define DW_DMA_DMAC_DAR2					(DW_DMA_DMAC_BASEADDR+0x0B8)
+#define DW_DMA_DMAC_LLP2					(DW_DMA_DMAC_BASEADDR+0x0C0)
+#define DW_DMA_DMAC_CTL2					(DW_DMA_DMAC_BASEADDR+0x0C8)
+#define DW_DMA_DMAC_SSTAT2					(DW_DMA_DMAC_BASEADDR+0x0D0)
+#define DW_DMA_DMAC_DSTAT2					(DW_DMA_DMAC_BASEADDR+0x0D8)
+#define DW_DMA_DMAC_SSTATAR2				(DW_DMA_DMAC_BASEADDR+0x0E0)
+#define DW_DMA_DMAC_DSTATAR2				(DW_DMA_DMAC_BASEADDR+0x0E8)
+#define DW_DMA_DMAC_CFG2					(DW_DMA_DMAC_BASEADDR+0x0F0)
+#define DW_DMA_DMAC_SGR2					(DW_DMA_DMAC_BASEADDR+0x0F8)
+#define DW_DMA_DMAC_DSR2					(DW_DMA_DMAC_BASEADDR+0x100)
+
+#define DW_DMA_DMAC_SAR3					(DW_DMA_DMAC_BASEADDR+0x108)
+#define DW_DMA_DMAC_DAR3					(DW_DMA_DMAC_BASEADDR+0x110)
+#define DW_DMA_DMAC_LLP3					(DW_DMA_DMAC_BASEADDR+0x118)
+#define DW_DMA_DMAC_CTL3					(DW_DMA_DMAC_BASEADDR+0x120)
+#define DW_DMA_DMAC_SSTAT3					(DW_DMA_DMAC_BASEADDR+0x128)
+#define DW_DMA_DMAC_DSTAT3					(DW_DMA_DMAC_BASEADDR+0x130)
+#define DW_DMA_DMAC_SSTATAR3				(DW_DMA_DMAC_BASEADDR+0x138)
+#define DW_DMA_DMAC_DSTATAR3				(DW_DMA_DMAC_BASEADDR+0x140)
+#define DW_DMA_DMAC_CFG3					(DW_DMA_DMAC_BASEADDR+0x148)
+#define DW_DMA_DMAC_SGR3					(DW_DMA_DMAC_BASEADDR+0x150)
+#define DW_DMA_DMAC_DSR3					(DW_DMA_DMAC_BASEADDR+0x158)
+
+#define DW_DMA_DMAC_SAR4					(DW_DMA_DMAC_BASEADDR+0x160)
+#define DW_DMA_DMAC_DAR4					(DW_DMA_DMAC_BASEADDR+0x168)
+#define DW_DMA_DMAC_LLP4					(DW_DMA_DMAC_BASEADDR+0x170)
+#define DW_DMA_DMAC_CTL4					(DW_DMA_DMAC_BASEADDR+0x178)
+#define DW_DMA_DMAC_SSTAT4					(DW_DMA_DMAC_BASEADDR+0x180)
+#define DW_DMA_DMAC_DSTAT4					(DW_DMA_DMAC_BASEADDR+0x188)
+#define DW_DMA_DMAC_SSTATAR4				(DW_DMA_DMAC_BASEADDR+0x190)
+#define DW_DMA_DMAC_DSTATAR4				(DW_DMA_DMAC_BASEADDR+0x198)
+#define DW_DMA_DMAC_CFG4					(DW_DMA_DMAC_BASEADDR+0x1A0)
+#define DW_DMA_DMAC_SGR4					(DW_DMA_DMAC_BASEADDR+0x1A8)
+#define DW_DMA_DMAC_DSR4					(DW_DMA_DMAC_BASEADDR+0x1B0)
+
+#define DW_DMA_DMAC_SAR5					(DW_DMA_DMAC_BASEADDR+0x1B8)
+#define DW_DMA_DMAC_DAR5					(DW_DMA_DMAC_BASEADDR+0x1C0)
+#define DW_DMA_DMAC_LLP5					(DW_DMA_DMAC_BASEADDR+0x1C8)
+#define DW_DMA_DMAC_CTL5					(DW_DMA_DMAC_BASEADDR+0x1D0)
+#define DW_DMA_DMAC_SSTAT5					(DW_DMA_DMAC_BASEADDR+0x1D8)
+#define DW_DMA_DMAC_DSTAT5					(DW_DMA_DMAC_BASEADDR+0x1E0)
+#define DW_DMA_DMAC_SSTATAR5				(DW_DMA_DMAC_BASEADDR+0x1E8)
+#define DW_DMA_DMAC_DSTATAR5				(DW_DMA_DMAC_BASEADDR+0x1F0)
+#define DW_DMA_DMAC_CFG5					(DW_DMA_DMAC_BASEADDR+0x1F8)
+#define DW_DMA_DMAC_SGR5					(DW_DMA_DMAC_BASEADDR+0x200)
+#define DW_DMA_DMAC_DSR5					(DW_DMA_DMAC_BASEADDR+0x208)
+
+#define DW_DMA_DMAC_SAR6					(DW_DMA_DMAC_BASEADDR+0x210)
+#define DW_DMA_DMAC_DAR6					(DW_DMA_DMAC_BASEADDR+0x218)
+#define DW_DMA_DMAC_LLP6					(DW_DMA_DMAC_BASEADDR+0x220)
+#define DW_DMA_DMAC_CTL6					(DW_DMA_DMAC_BASEADDR+0x228)
+#define DW_DMA_DMAC_SSTAT6					(DW_DMA_DMAC_BASEADDR+0x230)
+#define DW_DMA_DMAC_DSTAT6					(DW_DMA_DMAC_BASEADDR+0x238)
+#define DW_DMA_DMAC_SSTATAR6				(DW_DMA_DMAC_BASEADDR+0x240)
+#define DW_DMA_DMAC_DSTATAR6				(DW_DMA_DMAC_BASEADDR+0x248)
+#define DW_DMA_DMAC_CFG6					(DW_DMA_DMAC_BASEADDR+0x250)
+#define DW_DMA_DMAC_SGR6					(DW_DMA_DMAC_BASEADDR+0x258)
+#define DW_DMA_DMAC_DSR6					(DW_DMA_DMAC_BASEADDR+0x260)
+
+#define DW_DMA_DMAC_SAR7					(DW_DMA_DMAC_BASEADDR+0x268)
+#define DW_DMA_DMAC_DAR7					(DW_DMA_DMAC_BASEADDR+0x270)
+#define DW_DMA_DMAC_LLP7					(DW_DMA_DMAC_BASEADDR+0x278)
+#define DW_DMA_DMAC_CTL7					(DW_DMA_DMAC_BASEADDR+0x280)
+#define DW_DMA_DMAC_SSTAT7					(DW_DMA_DMAC_BASEADDR+0x288)
+#define DW_DMA_DMAC_DSTAT7					(DW_DMA_DMAC_BASEADDR+0x290)
+#define DW_DMA_DMAC_SSTATAR7				(DW_DMA_DMAC_BASEADDR+0x298)
+#define DW_DMA_DMAC_DSTATAR7				(DW_DMA_DMAC_BASEADDR+0x2A0)
+#define DW_DMA_DMAC_CFG7					(DW_DMA_DMAC_BASEADDR+0x2A8)
+#define DW_DMA_DMAC_SGR7					(DW_DMA_DMAC_BASEADDR+0x2B0)
+#define DW_DMA_DMAC_DSR7					(DW_DMA_DMAC_BASEADDR+0x2B8)
+
+/* Interrupt Registers */
+#define DW_DMA_DMAC_RAW_TFR					(DW_DMA_DMAC_BASEADDR+0x2C0)
+#define DW_DMA_DMAC_RAW_BLOCK				(DW_DMA_DMAC_BASEADDR+0x2C8)
+#define DW_DMA_DMAC_RAW_SRC_TRAN			(DW_DMA_DMAC_BASEADDR+0x2D0)
+#define DW_DMA_DMAC_RAW_DST_TRAN			(DW_DMA_DMAC_BASEADDR+0x2D8)
+#define DW_DMA_DMAC_RAW_ERR					(DW_DMA_DMAC_BASEADDR+0x2E0)
+#define DW_DMA_DMAC_STATUS_TFR				(DW_DMA_DMAC_BASEADDR+0x2E8)
+#define DW_DMA_DMAC_STATUS_BLK				(DW_DMA_DMAC_BASEADDR+0x2F0)
+#define DW_DMA_DMAC_STATUS_SRC_TRAN			(DW_DMA_DMAC_BASEADDR+0x2F8)
+#define DW_DMA_DMAC_STATUS_DST_TRAN			(DW_DMA_DMAC_BASEADDR+0x300)
+#define DW_DMA_DMAC_STATUS_ERR				(DW_DMA_DMAC_BASEADDR+0x308)
+#define DW_DMA_DMAC_MASK_TFR				(DW_DMA_DMAC_BASEADDR+0x310)
+#define DW_DMA_DMAC_MASK_BLOCK				(DW_DMA_DMAC_BASEADDR+0x318)
+#define DW_DMA_DMAC_MASK_SRC_TRAN			(DW_DMA_DMAC_BASEADDR+0x320)
+#define DW_DMA_DMAC_MASK_DST_TRAN			(DW_DMA_DMAC_BASEADDR+0x328)
+#define DW_DMA_DMAC_MASK_ERR				(DW_DMA_DMAC_BASEADDR+0x330)
+#define DW_DMA_DMAC_CLEAR_TFR				(DW_DMA_DMAC_BASEADDR+0x338)
+#define DW_DMA_DMAC_CLEAR_BLK				(DW_DMA_DMAC_BASEADDR+0x340)
+#define DW_DMA_DMAC_CLEAR_SRC_TRAN			(DW_DMA_DMAC_BASEADDR+0x348)
+#define DW_DMA_DMAC_CLEAR_DST_TRAN			(DW_DMA_DMAC_BASEADDR+0x350)
+#define DW_DMA_DMAC_CLEAR_ERR				(DW_DMA_DMAC_BASEADDR+0x358)
+#define DW_DMA_DMAC_STATUS_INT				(DW_DMA_DMAC_BASEADDR+0x360)
+
+/* Software Handshaking Registers */
+#define DW_DMA_DMAC_REQ_SRC_REG				(DW_DMA_DMAC_BASEADDR+0x368)
+#define DW_DMA_DMAC_REQ_DST_REG				(DW_DMA_DMAC_BASEADDR+0x370)
+#define DW_DMA_DMAC_SGL_REQ_SRC_REG			(DW_DMA_DMAC_BASEADDR+0x378)
+#define DW_DMA_DMAC_SGL_REQ_DST_REG			(DW_DMA_DMAC_BASEADDR+0x380)
+#define DW_DMA_DMAC_LST_SRC_REG				(DW_DMA_DMAC_BASEADDR+0x388)
+#define DW_DMA_DMAC_LST_DST_REG				(DW_DMA_DMAC_BASEADDR+0x390)
+
+/* Miscellaneous Registers */
+#define DW_DMA_DMAC_DMA_CFG_REG				(DW_DMA_DMAC_BASEADDR+0x398)
+#define DW_DMA_DMAC_CH_EN_REG				(DW_DMA_DMAC_BASEADDR+0x3A0)
+#define DW_DMA_DMAC_DMA_LD_REG				(DW_DMA_DMAC_BASEADDR+0x3A8)
+#define DW_DMA_DMAC_DMA_TEST_REG			(DW_DMA_DMAC_BASEADDR+0x3B0)
+#define DW_DMA_DMAC_DMA_COMP_PA_RAMS_6		(DW_DMA_DMAC_BASEADDR+0x3C8)
+#define DW_DMA_DMAC_DMA_COMP_PA_RAMS_5		(DW_DMA_DMAC_BASEADDR+0x3D0)
+#define DW_DMA_DMAC_DMA_COMP_PA_RAMS_4		(DW_DMA_DMAC_BASEADDR+0x3D8)
+#define DW_DMA_DMAC_DMA_COMP_PA_RAMS_3		(DW_DMA_DMAC_BASEADDR+0x3E0)
+#define DW_DMA_DMAC_DMA_COMP_PA_RAMS_2		(DW_DMA_DMAC_BASEADDR+0x3E8)
+#define DW_DMA_DMAC_DMA_COMP_PA_RAMS_1		(DW_DMA_DMAC_BASEADDR+0x3F0)
+#define DW_DMA_DMAC_DMA_COMP_ID_REG			(DW_DMA_DMAC_BASEADDR+0x3F8)
+
+
+
+/*
+  * DW DMA UART0
+  */
+
+#define DW_DMA_UART0_RBR					(DW_DMA_UART0_BASEADDR+0x00)
+#define DW_DMA_UART0_THR					(DW_DMA_UART0_BASEADDR+0x00)
+#define DW_DMA_UART0_DLL					(DW_DMA_UART0_BASEADDR+0x00)
+#define DW_DMA_UART0_DLH					(DW_DMA_UART0_BASEADDR+0x04)
+#define DW_DMA_UART0_IER					(DW_DMA_UART0_BASEADDR+0x04)
+#define DW_DMA_UART0_IIR					(DW_DMA_UART0_BASEADDR+0x08)
+#define DW_DMA_UART0_FCR					(DW_DMA_UART0_BASEADDR+0x08)
+#define DW_DMA_UART0_LCR					(DW_DMA_UART0_BASEADDR+0x0C)
+#define DW_DMA_UART0_MCR					(DW_DMA_UART0_BASEADDR+0x10)
+#define DW_DMA_UART0_LSR					(DW_DMA_UART0_BASEADDR+0x14)
+#define DW_DMA_UART0_MSR					(DW_DMA_UART0_BASEADDR+0x18)
+#define DW_DMA_UART0_SCR					(DW_DMA_UART0_BASEADDR+0x1C)
+#define DW_DMA_UART0_LPDLL					(DW_DMA_UART0_BASEADDR+0x20)
+#define DW_DMA_UART0_LPDLH					(DW_DMA_UART0_BASEADDR+0x24)
+#define DW_DMA_UART0_SRBR					(DW_DMA_UART0_BASEADDR+0x30) /* Shadow Receive Buffer Register (0x30 to 0x6C) */
+#define DW_DMA_UART0_STHR					(DW_DMA_UART0_BASEADDR+0x30) /* Shadow Transmit Holding Register (0x30 to 0x6C) */
+#define DW_DMA_UART0_FAR					(DW_DMA_UART0_BASEADDR+0x40)
+#define DW_DMA_UART0_TFR					(DW_DMA_UART0_BASEADDR+0x70)
+#define DW_DMA_UART0_RFW					(DW_DMA_UART0_BASEADDR+0x74)
+#define DW_DMA_UART0_USR					(DW_DMA_UART0_BASEADDR+0x78)
+#define DW_DMA_UART0_TFL					(DW_DMA_UART0_BASEADDR+0x7C)
+#define DW_DMA_UART0_RFL					(DW_DMA_UART0_BASEADDR+0x80)
+#define DW_DMA_UART0_SRR					(DW_DMA_UART0_BASEADDR+0x84)
+#define DW_DMA_UART0_SRTS					(DW_DMA_UART0_BASEADDR+0x88)
+#define DW_DMA_UART0_DR						(DW_DMA_UART0_BASEADDR+0x8C)
+#define DW_DMA_UART0_SBCR					(DW_DMA_UART0_BASEADDR+0x90)
+#define DW_DMA_UART0_SDMAM					(DW_DMA_UART0_BASEADDR+0x94)
+#define DW_DMA_UART0_SFE					(DW_DMA_UART0_BASEADDR+0x98)
+#define DW_DMA_UART0_SRT					(DW_DMA_UART0_BASEADDR+0x9C)
+#define DW_DMA_UART0_STET					(DW_DMA_UART0_BASEADDR+0xA0)
+#define DW_DMA_UART0_HTX					(DW_DMA_UART0_BASEADDR+0xA4)
+#define DW_DMA_UART0_DMASA					(DW_DMA_UART0_BASEADDR+0xA8)
+#define DW_DMA_UART0_CPR					(DW_DMA_UART0_BASEADDR+0xF4)
+#define DW_DMA_UART0_UCV					(DW_DMA_UART0_BASEADDR+0xF8)
+#define DW_DMA_UART0_CTR					(DW_DMA_UART0_BASEADDR+0xFC)
+
+
+
+
+/*
+  * DW DMA UART1
+  */
+
+#define DW_DMA_UART1_RBR					(DW_DMA_UART1_BASEADDR+0x00)
+#define DW_DMA_UART1_THR					(DW_DMA_UART1_BASEADDR+0x00)
+#define DW_DMA_UART1_DLL					(DW_DMA_UART1_BASEADDR+0x00)
+#define DW_DMA_UART1_DLH					(DW_DMA_UART1_BASEADDR+0x04)
+#define DW_DMA_UART1_IER					(DW_DMA_UART1_BASEADDR+0x04)
+#define DW_DMA_UART1_IIR					(DW_DMA_UART1_BASEADDR+0x08)
+#define DW_DMA_UART1_FCR					(DW_DMA_UART1_BASEADDR+0x08)
+#define DW_DMA_UART1_LCR					(DW_DMA_UART1_BASEADDR+0x0C)
+#define DW_DMA_UART1_MCR					(DW_DMA_UART1_BASEADDR+0x10)
+#define DW_DMA_UART1_LSR					(DW_DMA_UART1_BASEADDR+0x14)
+#define DW_DMA_UART1_MSR					(DW_DMA_UART1_BASEADDR+0x18)
+#define DW_DMA_UART1_SCR					(DW_DMA_UART1_BASEADDR+0x1C)
+#define DW_DMA_UART1_LPDLL					(DW_DMA_UART1_BASEADDR+0x20)
+#define DW_DMA_UART1_LPDLH					(DW_DMA_UART1_BASEADDR+0x24)
+#define DW_DMA_UART1_SRBR					(DW_DMA_UART1_BASEADDR+0x30) /* Shadow Receive Buffer Register (0x30 to 0x6C) */
+#define DW_DMA_UART1_STHR					(DW_DMA_UART1_BASEADDR+0x30) /* Shadow Transmit Holding Register (0x30 to 0x6C) */
+#define DW_DMA_UART1_FAR					(DW_DMA_UART1_BASEADDR+0x40)
+#define DW_DMA_UART1_TFR					(DW_DMA_UART1_BASEADDR+0x70)
+#define DW_DMA_UART1_RFW					(DW_DMA_UART1_BASEADDR+0x74)
+#define DW_DMA_UART1_USR					(DW_DMA_UART1_BASEADDR+0x78)
+#define DW_DMA_UART1_TFL					(DW_DMA_UART1_BASEADDR+0x7C)
+#define DW_DMA_UART1_RFL					(DW_DMA_UART1_BASEADDR+0x80)
+#define DW_DMA_UART1_SRR					(DW_DMA_UART1_BASEADDR+0x84)
+#define DW_DMA_UART1_SRTS					(DW_DMA_UART1_BASEADDR+0x88)
+#define DW_DMA_UART1_DR						(DW_DMA_UART1_BASEADDR+0x8C)
+#define DW_DMA_UART1_SBCR					(DW_DMA_UART1_BASEADDR+0x90)
+#define DW_DMA_UART1_SDMAM					(DW_DMA_UART1_BASEADDR+0x94)
+#define DW_DMA_UART1_SFE					(DW_DMA_UART1_BASEADDR+0x98)
+#define DW_DMA_UART1_SRT					(DW_DMA_UART1_BASEADDR+0x9C)
+#define DW_DMA_UART1_STET					(DW_DMA_UART1_BASEADDR+0xA0)
+#define DW_DMA_UART1_HTX					(DW_DMA_UART1_BASEADDR+0xA4)
+#define DW_DMA_UART1_DMASA					(DW_DMA_UART1_BASEADDR+0xA8)
+#define DW_DMA_UART1_CPR					(DW_DMA_UART1_BASEADDR+0xF4)
+#define DW_DMA_UART1_UCV					(DW_DMA_UART1_BASEADDR+0xF8)
+#define DW_DMA_UART1_CTR					(DW_DMA_UART1_BASEADDR+0xFC)
+
+
+
+
+/* DMA Channels */
+#define DMA_CHANNEL_0					0x0
+#define DMA_CHANNEL_1					0x1
+#define DMA_CHANNEL_2					0x2
+#define DMA_CHANNEL_3					0x3
+#define DMA_CHANNEL_4					0x4
+#define DMA_CHANNEL_5					0x5
+#define DMA_CHANNEL_6					0x6
+#define DMA_CHANNEL_7					0x7
+
+/* DMA Channel mask */
+#define DMA_CHANNEL_0_MASK				0x00000001
+#define DMA_CHANNEL_1_MASK				0x00000002
+#define DMA_CHANNEL_2_MASK				0x00000004
+#define DMA_CHANNEL_3_MASK				0x00000008
+#define DMA_CHANNEL_4_MASK				0x00000010
+#define DMA_CHANNEL_5_MASK				0x00000020
+#define DMA_CHANNEL_6_MASK				0x00000040
+#define DMA_CHANNEL_7_MASK				0x00000080
+
+#define DMA_GLOBAL_ENABLE				0x1
+#define DMA_REG_WE_SHIFT				0x8
+
+
+#define DMA_CHANNEL_REG_SAR_BASE		DW_DMA_DMAC_SAR0
+#define DMA_CHANNEL_REG_DAR_BASE		DW_DMA_DMAC_DAR0
+#define DMA_CHANNEL_REG_LLP_BASE		DW_DMA_DMAC_LLP0
+#define DMA_CHANNEL_REG_CTL_BASE		DW_DMA_DMAC_CTL0
+#define DMA_CHANNEL_REG_SSTAT_BASE		DW_DMA_DMAC_SSTAT0
+#define DMA_CHANNEL_REG_DSTAT_BASE		DW_DMA_DMAC_DSTAT0
+#define DMA_CHANNEL_REG_SSTATAR_BASE	DW_DMA_DMAC_SSTATAR0
+#define DMA_CHANNEL_REG_DSTATAR_BASE	DW_DMA_DMAC_DSTATAR0
+#define DMA_CHANNEL_REG_CFG_BASE		DW_DMA_DMAC_CFG0
+#define DMA_CHANNEL_REG_SGR_BASE		DW_DMA_DMAC_SGR0
+#define DMA_CHANNEL_REG_DSR_BASE		DW_DMA_DMAC_DSR0
+
+
+#define DMA_CHANNEL_REG_COUNT			11
+#define DMA_CHANNEL_REG_SIZE			8
+
+
+/* DMA Control Register for Channel [0-31] */
+
+/* 
+ * Single-block Transfer -- without write-back 
+ * of control and status information enabled at 
+ * the end of the single-block transfer
+ */
+ 
+#define DMA_CTL_INT_EN					0x1
+#define DMA_CTL_INT_EN_MASK				0x1
+#define DMA_CTL_INT_EN_SHIFT			0
+
+#define DMA_CTL_DST_TR_WIDTH			0x0 		/* 8 bit */
+#define DMA_CTL_DST_TR_WIDTH_MASK		0x7
+#define DMA_CTL_DST_TR_WIDTH_SHIFT		1
+
+#define DMA_CTL_SRC_TR_WIDTH			0x0 		/* 8 bit */
+#define DMA_CTL_SRC_TR_WIDTH_MASK		0x7
+#define DMA_CTL_SRC_TR_WIDTH_SHIFT		4
+
+#define DMA_CTL_DINC					0x0 		/* Incriment */
+#define DMA_CTL_DINC_MASK				0x3
+#define DMA_CTL_DINC_SHIFT				7
+
+#define DMA_CTL_SINC					0x2 		/* No Change */
+#define DMA_CTL_SINC_MASK				0x3
+#define DMA_CTL_SINC_SHIFT				9
+
+#define DMA_CTL_DEST_MSIZE				0x3 //0x1 		/* Number of data items to be transferred = 4 */
+#define DMA_CTL_DEST_MSIZE_MASK			0x7
+#define DMA_CTL_DEST_MSIZE_SHIFT		11
+
+#define DMA_CTL_SRC_MSIZE				0x3 //0x1			/* Number of data items to be transferred = 4 */
+#define DMA_CTL_SRC_MSIZE_MASK			0x7
+#define DMA_CTL_SRC_MSIZE_SHIFT			14
+
+#define DMA_CTL_SRC_GATHER_EN			0x0			/* Disabled */
+#define DMA_CTL_SRC_GATHER_EN_MASK		0x1
+#define DMA_CTL_SRC_GATHER_EN_SHIFT		17
+
+#define DMA_CTL_DST_SCATTER_EN			0x0			/* Disabled */
+#define DMA_CTL_DST_SCATTER_EN_MASK		0x1
+#define DMA_CTL_DST_SCATTER_EN_SHIFT	18
+
+#define DMA_CTL_TT_FC					0x2			/* Peripheral to Memory, Flow Controller -- DW_ahb_dmac */
+#define DMA_CTL_TT_FC_MASK				0x7
+#define DMA_CTL_TT_FC_SHIFT				20
+
+#define DMA_CTL_DMS						0x0			/* ?????? AHB master 1 */
+#define DMA_CTL_DMS_MASK				0x3
+#define DMA_CTL_DMS_SHIFT				23
+
+#define DMA_CTL_SMS						0x1			/* ?????? AHB master 2 */
+#define DMA_CTL_SMS_MASK				0x3
+#define DMA_CTL_SMS_SHIFT				25
+
+#define DMA_CTL_LLP_DST_EN				0x0
+#define DMA_CTL_LLP_DST_EN_MASK			0x1
+#define DMA_CTL_LLP_DST_EN_SHIFT		27
+
+#define DMA_CTL_LLP_SRC_EN				0x0
+#define DMA_CTL_LLP_SRC_EN_MASK			0x1
+#define DMA_CTL_LLP_SRC_EN_SHIFT		28
+
+
+/* DMA Control Register for Channel [32-63] */
+/* 
+ * Single-block Transfer -- without write-back 
+ * of control and status information enabled at 
+ * the end of the single-block transfer
+ */
+
+/* DMA_CTL_BLOCK_TS
+ * When the DW_ahb_dmac is the flow controller, the user writes this
+ * field before the channel is enabled in order to indicate the block size.
+ *
+ * The number programmed into BLOCK_TS indicates the total number
+ * of single transactions to perform for every block transfer.
+ *
+ * The width of the single transaction is determined by
+ * DMA_CTL_SRC_TR_WIDTH.
+ */
+#define DMA_CTL_BLOCK_TS				SPI_NDF 
+#define DMA_CTL_BLOCK_TS_MASK			0XFFF
+#define DMA_CTL_BLOCK_TS_SHIFT			0
+
+#define DMA_CTL_DONE					0x0
+#define DMA_CTL_DONE_MASK				0x1
+#define DMA_CTL_DONE_SHIFT				12
+
+
+
+/* DMA Config Register for Channel [0-31] */
+/* 
+ * Single-block Transfer -- without write-back 
+ * of control and status information enabled at 
+ * the end of the single-block transfer
+ */
+
+#define DMA_CFG_RELOAD_DST				0x0			/* Disabled -- No Multi Block xfer */
+#define DMA_CFG_RELOAD_DST_MASK			0x1
+#define DMA_CFG_RELOAD_DST_SHIFT		31
+
+#define DMA_CFG_RELOAD_SRC				0x0			/* Disabled -- No Multi Block xfer */
+#define DMA_CFG_RELOAD_SRC_MASK			0x1
+#define DMA_CFG_RELOAD_SRC_SHIFT		30
+
+#define DMA_CFG_MAX_ABRST				0x0			/* max AMBA burst length -- not limited by software  */
+#define DMA_CFG_MAX_ABRST_MASK			0x3FF
+#define DMA_CFG_MAX_ABRST_SHIFT			20
+
+#define DMA_CFG_SRC_HS_POL				0x0			/* Active high */
+#define DMA_CFG_SRC_HS_POL_MASK			0x1
+#define DMA_CFG_SRC_HS_POL_SHIFT		19
+
+#define DMA_CFG_DST_HS_POL				0x0			/* Active high */
+#define DMA_CFG_DST_HS_POL_MASK			0x1
+#define DMA_CFG_DST_HS_POL_SHIFT		18
+
+#define DMA_CFG_LOCK_B					0x0			/* No Locked DMA Transfers */
+#define DMA_CFG_LOCK_B_MASK				0x1
+#define DMA_CFG_LOCK_B_SHIFT			17
+
+#define DMA_CFG_LOCK_CH					0x0			/* No exclusive Access to the channel */
+#define DMA_CFG_LOCK_CH_MASK			0x1
+#define DMA_CFG_LOCK_CH_SHIFT			16
+
+#define DMA_CFG_LOCK_B_L				0x0
+#define DMA_CFG_LOCK_B_L_MASK			0x3
+#define DMA_CFG_LOCK_B_L_SHIFT			14
+
+#define DMA_CFG_LOCK_CH_L				0x0
+#define DMA_CFG_LOCK_CH_L_MASK			0x3
+#define DMA_CFG_LOCK_CH_L_SHIFT			12
+
+#define DMA_CFG_HS_SEL_SRC				0x0 		/* Hardware handshaking */
+#define DMA_CFG_HS_SEL_SRC_MASK			0x1
+#define DMA_CFG_HS_SEL_SRC_SHIFT		11
+
+#define DMA_CFG_HS_SEL_DST				0x1 		/* S/w handshaking */
+#define DMA_CFG_HS_SEL_DST_MASK			0x1
+#define DMA_CFG_HS_SEL_DST_SHIFT		10
+
+#define DMA_CFG_FIFO_EMPTY				0x1			/* Channel FIFO empty */
+#define DMA_CFG_FIFO_EMPTY_MASK			0x1
+#define DMA_CFG_FIFO_EMPTY_SHIFT		9
+
+#define DMA_CFG_CH_SUSP					0x0			/* Not suspended */
+#define DMA_CFG_CH_SUSP_MASK			0x1
+#define DMA_CFG_CH_SUSP_SHIFT			8
+
+#define DMA_CFG_CH_PRIOR				0x0			/* Should be kept equal to channel no */
+#define DMA_CFG_CH_PRIOR_MASK			0x7
+#define DMA_CFG_CH_PRIOR_SHIFT			5
+
+
+/* DMA Config Register for Channel [32-63] */
+/* 
+ * Single-block Transfer -- without write-back 
+ * of control and status information enabled at 
+ * the end of the single-block transfer
+ */
+
+#define DMA_CFG_DEST_PER				0x0
+#define DMA_CFG_DEST_PER_MASK			0xF
+#define DMA_CFG_DEST_PER_SHIFT			11
+
+#define DMA_CFG_SRC_PER					0x4
+#define DMA_CFG_SRC_PER_MASK			0xF
+#define DMA_CFG_SRC_PER_SHIFT			7
+
+#define DMA_CFG_SS_UPD_EN				0x0			/* Disabled */
+#define DMA_CFG_SS_UPD_EN_MASK			0x1
+#define DMA_CFG_SS_UPD_EN_SHIFT			6
+
+#define DMA_CFG_DS_UPD_EN				0x0			/* Disabled */
+#define DMA_CFG_DS_UPD_EN_MASK			0x1
+#define DMA_CFG_DS_UPD_EN_SHIFT			5
+
+#define DMA_CFG_PROTCTL					0x1
+#define DMA_CFG_PROTCTL_MASK			0x7
+#define DMA_CFG_PROTCTL_SHIFT			2
+
+#define DMA_CFG_FIFO_MODE				0x0			/* Single AHB Space of the specified transfer width */
+#define DMA_CFG_FIFO_MODE_MASK			0x1
+#define DMA_CFG_FIFO_MODE_SHIFT			1
+
+#define DMA_CFG_FCMODE					0x0
+#define DMA_CFG_FCMODE_MASK				0x1
+#define DMA_CFG_FCMODE_SHIFT			0
+
+#define DMA_XFER_DLEN					16
+
+#endif /* _ASM_ARCH_DMA_H */
+
diff --git a/arch/arm/mach-comcerto/include/mach/ecc.h b/arch/arm/mach-comcerto/include/mach/ecc.h
new file mode 100644
index 0000000..f82a611
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/ecc.h
@@ -0,0 +1,126 @@
+#ifndef _ECC_H
+#define _ECC_H
+
+/* ECC Register Set */
+/********************/
+/* ECC Control Registers */
+#define ECC_SHIFT_EN_CFG	(0x0)
+#define ECC_GEN_CFG		(0x4)
+#define ECC_TAG_CFG		(0x8)
+#define ECC_INIT_CFG		(0xC)
+#define ECC_PRTY_OUT_SEL_CFG	(0x10)
+#define ECC_POLY_START_CFG	(0x14)
+#define ECC_CS_SEL_CFG		(0x18)
+/* ECC Status Registers */
+#define ECC_IDLE_STAT		(0x1C)
+#define ECC_POLY_STAT		(0x20)
+#define ECC_CORR_STAT		(0x24)
+#define ECC_CORR_DONE_STAT	(0x28)
+#define ECC_CORR_DATA_STAT	(0x2C)
+
+#if 0
+#define ECC_SHIFT_EN_CFG	(COMCERTO_AXI_EXP_ECC_BASE)
+#define ECC_GEN_CFG		(COMCERTO_AXI_EXP_ECC_BASE + 0x4)
+#define ECC_TAG_CFG		(COMCERTO_AXI_EXP_ECC_BASE + 0x8)
+#define ECC_INIT_CFG		(COMCERTO_AXI_EXP_ECC_BASE + 0xC)
+#define ECC_PRTY_OUT_SEL_CFG	(COMCERTO_AXI_EXP_ECC_BASE + 0x10)
+#define ECC_POLY_START_CFG	(COMCERTO_AXI_EXP_ECC_BASE + 0x14)
+#define ECC_CS_SEL_CFG		(COMCERTO_AXI_EXP_ECC_BASE + 0x18)
+/* ECC Status Registers */
+#define ECC_IDLE_STAT		(COMCERTO_AXI_EXP_ECC_BASE + 0x1C)
+#define ECC_POLY_STAT		(COMCERTO_AXI_EXP_ECC_BASE + 0x20)
+#define ECC_CORR_STAT		(COMCERTO_AXI_EXP_ECC_BASE + 0x24)
+#define ECC_CORR_DONE_STAT	(COMCERTO_AXI_EXP_ECC_BASE + 0x28)
+#define ECC_CORR_DATA_STAT	(COMCERTO_AXI_EXP_ECC_BASE + 0x2C)
+#endif
+
+/* ECC general configuration register parameters */
+#define HAMM_MODE	BIT_28_MSK
+#define BCH_MODE	(~ HAMM_MODE)
+
+#define PRTY_MODE_MASK	BIT_24_MSK
+#define PRTY_CALC	PRTY_MODE_MASK
+#define SYNDROME_CALC	(~ PRTY_CALC)
+
+#define	ECC_LVL_MASK	0x3F0000
+#define ECC_LVL_SHIFT	16
+
+#define BLK_SIZE_MASK 0x7FF
+
+#define ECC_LVL_2 0x2
+#define ECC_LVL_4 0x4
+#define ECC_LVL_6 0x6
+#define ECC_LVL_8 0x8
+#define ECC_LVL_10 0xA
+#define ECC_LVL_12 0xC
+#define ECC_LVL_14 0xE
+#define ECC_LVL_16 0x10
+#define ECC_LVL_18 0x12
+#define ECC_LVL_20 0x14
+#define ECC_LVL_22 0x16
+#define ECC_LVL_24 0x18
+#define ECC_LVL_26 0x1A
+#define ECC_LVL_28 0x1C
+#define ECC_LVL_30 0x1E
+#define ECC_LVL_32 0x20
+
+#if defined (CONFIG_NAND_COMCERTO_ECC_24_HW_BCH)
+	#define ECC_LVL_VAL ECC_LVL_24 /* ECC Level 24 is used */
+#elif defined (CONFIG_NAND_COMCERTO_ECC_8_HW_BCH)
+	#define ECC_LVL_VAL ECC_LVL_8 /* ECC Level 8 is used */
+#endif
+ 
+/* Block size used in Bytes*/
+#define ECC_BLOCK_SIZE_512 512
+#define ECC_BLOCK_SIZE_1024 1024
+
+/* Maximum value of ECC Block size is 2k-(1+14*ECC_LVL/8) Bytes */
+#define ECC_BLOCK_SIZE		ECC_BLOCK_SIZE_1024
+#define ECC_BLOCK_SIZE_SHIFT	ECC_BLOCK_SIZE_1024_SHIFT
+
+#define ECC_CS4_SEL 0x10
+#define ECC_CS3_SEL 0x08
+#define ECC_CS2_SEL 0x04
+#define ECC_CS1_SEL 0x02
+#define ECC_CS0_SEL 0x01
+
+#define ECC_INIT		0x1
+#define ECC_SHIFT_ENABLE	0x1
+#define ECC_SHIFT_DISABLE	0x0
+#define ECC_PARITY_OUT_EN	0x1
+#define ECC_PARITY_OUT_DISABLE	0x0
+#define ECC_UNCORR_ERR_HAMM	0x4
+
+/* Polynomial Start Configuration (ECC_POLY_START_CFG) */
+#define ECC_POLY_START		(1 << 0)
+
+/* Idle Status (ECC_IDLE_STAT) */
+#define ECC_IDLE		(1 << 0)
+
+/* Polynomial Status (ECC_POLY_STAT) */
+#define ECC_CORR_REQ		(1 << 0)
+#define ECC_ERASED_PAGE		(1 << 1)
+#define ECC_UNCORR_ERR_HAMM	(1 << 2)
+
+/* Correction Status (ECC_CORR_STAT) */
+#define ECC_TAG_MASK		0xFFFF
+#define ECC_NUM_ERR_MASK	0x3F
+#define ECC_NUM_ERR_SHIFT	16
+#define ECC_UNCORR		(1 << 24)
+
+/* Correction Done Status (ECC_CORR_DONE_STAT) */
+#define ECC_DONE		(1 << 0)
+
+/* Correction Data Status (ECC_CORR_DATA_STAT), BCH Mode */
+#define ECC_BCH_MASK		0xFFFF
+#define ECC_BCH_INDEX_MASK	0x7FF
+#define ECC_BCH_INDEX_SHIFT	16
+#define ECC_BCH_VALID		(1 << 31)
+
+/* Correction Data Status (ECC_CORR_DATA_STAT), Hamming Mode */
+#define ECC_HAMM_MASK		0xF
+#define ECC_HAMM_INDEX_MASK	0x1FF
+#define ECC_HAMM_INDEX_SHIFT	16
+#define ECC_HAMM_VALID		(1 << 31)
+
+#endif /*_ECC_H */
diff --git a/arch/arm/mach-comcerto/include/mach/entry-macro.S b/arch/arm/mach-comcerto/include/mach/entry-macro.S
new file mode 100644
index 0000000..e718efa
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/entry-macro.S
@@ -0,0 +1,29 @@
+/*
+ * arch/arm/mach-comcerto/include/mach/entry-macro.S
+ *
+ * Copyright (C) 2011 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <mach/hardware.h>
+#include <asm/hardware/gic.h>
+#include <asm/hardware/entry-macro-gic.S>
+
+	.macro	disable_fiq
+	.endm
+
+	.macro  arch_ret_to_user, tmp1, tmp2
+	.endm
diff --git a/arch/arm/mach-comcerto/include/mach/gpio.h b/arch/arm/mach-comcerto/include/mach/gpio.h
new file mode 100644
index 0000000..e0bfe4d
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/gpio.h
@@ -0,0 +1,2 @@
+
+#include "comcerto-2000/gpio.h"
diff --git a/arch/arm/mach-comcerto/include/mach/hardware.h b/arch/arm/mach-comcerto/include/mach/hardware.h
new file mode 100644
index 0000000..3099117
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/hardware.h
@@ -0,0 +1,50 @@
+/*
+ *  arch/arm/mach-comcerto/include/mach/hardware.h
+ *
+ *  Copyright (C) 2012 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <linux/types.h>
+
+	/***** Device *****/
+	#if defined(CONFIG_ARCH_M86XXX)
+		#include <mach/comcerto-2000.h>
+	#else
+		#error "mach/hardware.h :  Unknown architecture" 
+	#endif
+	
+
+	/***** Board *****/
+	#if defined(CONFIG_C2K_ASIC)
+		#include <mach/board-c2kasic.h>
+	#elif defined(CONFIG_C2K_EVM)
+		#include <mach/board-c2kevm.h>
+	#elif defined(CONFIG_C2K_MFCN_EVM)
+		#include <mach/board-c2kmfcnevm.h>
+	#elif defined(CONFIG_RTSM_C2K)
+		#include <mach/board-c2krtsm.h>
+	
+	#else
+		#error "mach/board_XXX.h :  Unknown board"
+	#endif
+
+	#include <mach/comcerto-common.h>
+
+#endif
diff --git a/arch/arm/mach-comcerto/include/mach/i2c.h b/arch/arm/mach-comcerto/include/mach/i2c.h
new file mode 100644
index 0000000..15ce3cd
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/i2c.h
@@ -0,0 +1,32 @@
+/*
+ *  linux/include/asm-arm/arch-comcerto/i2c.h
+ *
+ *  Copyright (C) 2008 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __ASM_ARCH_I2C_H
+#define __ASM_ARCH_I2C_H
+
+
+#if defined(CONFIG_ARCH_M86XXX)
+	#include <mach/comcerto-2000/i2c.h>
+#else
+	#error "mach/comcerto-2000/i2c.h :  Unknown architecture" 
+#endif
+
+#endif  /* __ASM_ARCH_I2C_H */
diff --git a/arch/arm/mach-comcerto/include/mach/io.h b/arch/arm/mach-comcerto/include/mach/io.h
new file mode 100644
index 0000000..80e7dc6
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/io.h
@@ -0,0 +1,30 @@
+/*
+ *  linux/include/asm-arm/arch-comcerto/io.h
+ *
+ *  Copyright (C) 2004,2008 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARCH_IO_H
+#define __ASM_ARCH_IO_H
+
+
+#if defined(CONFIG_ARCH_M86XXX)
+	#include <mach/comcerto-2000/io.h>
+#else
+	#error "Unsupported CPU"
+#endif
+
+#endif /* __ASM_ARCH_IO_H */
diff --git a/arch/arm/mach-comcerto/include/mach/irqs.h b/arch/arm/mach-comcerto/include/mach/irqs.h
new file mode 100644
index 0000000..154edd8
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/irqs.h
@@ -0,0 +1,21 @@
+/*
+ *  arch/arm/mach-comcerto/include/mach/irqs.h
+ *
+ *  Copyright (C) 2011 Mindspeed Technologies, Inc.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ASM_ARCH_IRQS_H
+#define __ASM_ARCH_IRQS_H
+
+#if defined(CONFIG_ARCH_M86XXX)
+	#include <mach/comcerto-2000/irqs.h>
+#else
+	#error "Unsupported CPU"
+#endif
+
+#endif  /* __ASM_ARCH_IRQS_H */
diff --git a/arch/arm/mach-comcerto/include/mach/memory.h b/arch/arm/mach-comcerto/include/mach/memory.h
new file mode 100644
index 0000000..82265a4
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/memory.h
@@ -0,0 +1,28 @@
+/*
+ *  arch/arm/mach-comcerto/include/mach/memory.h
+ *
+ *  Copyright (C) 2011 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+	#include <mach/hardware.h>
+
+	#define PLAT_PHYS_OFFSET		COMCERTO_AXI_DDR_BASE
+
+#endif
diff --git a/arch/arm/mach-comcerto/include/mach/msp_ioctl.h b/arch/arm/mach-comcerto/include/mach/msp_ioctl.h
new file mode 100644
index 0000000..b7231fd
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/msp_ioctl.h
@@ -0,0 +1,56 @@
+/*
+ *  arch/arm/mach-comcerto/include/mach/msp_ioctl.h
+ *
+ *  Copyright (C) 2004,2005 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _MSP_IOCTL_H
+#define _MSP_IOCTL_H
+
+struct MSP_IOCTL_IMAGE
+{
+	void *buf;
+	unsigned long len;
+};
+
+struct MSP_IOCTL_MEM_DUMP
+{
+	void *buf;
+	unsigned long addr;
+	unsigned long len;
+};
+
+#ifdef __KERNEL__
+int msp_ioctl_from_csp(unsigned int cmd, unsigned long arg);
+
+/* Only valid when called from the CSP */
+#define MSP_IOCTL_RESET_MSP_LOAD_FROM_KERNELBUF		_IOR(MSP_IOC_TYPE, 5, struct MSP_IOCTL_IMAGE)
+#define MSP_IOCTL_RESET_MSP_DUMP_TO_KERNELBUF		_IOWR(MSP_IOC_TYPE, 6, struct MSP_IOCTL_IMAGE)
+
+#endif
+
+#define MSP_IOC_TYPE					'm'
+#define MSP_IOCTL_DISPLAY_MSP_FROM_NORFLASH		_IO(MSP_IOC_TYPE, 1)
+#define MSP_IOCTL_RESET_MSP_LOAD_FROM_NORFLASH		_IO(MSP_IOC_TYPE, 2)
+#define MSP_IOCTL_RESET_MSP_LOAD_FROM_BUF		_IOR(MSP_IOC_TYPE, 3, struct MSP_IOCTL_IMAGE)
+#define MSP_IOCTL_RESET_MSP_DUMP_TO_BUF			_IOR(MSP_IOC_TYPE, 4, struct MSP_IOCTL_MEM_DUMP)
+
+#define MSP_DEVICE_NAME		"/dev/msp"
+
+#define MSP_DEVICE_MAJOR_NUM	237         /* this could be whatever you want, as long as it does not conflict with other modules */
+
+#endif /* _MSP_IOCTL_H */
diff --git a/arch/arm/mach-comcerto/include/mach/pcie-c2000.h b/arch/arm/mach-comcerto/include/mach/pcie-c2000.h
new file mode 100644
index 0000000..9110d4f
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/pcie-c2000.h
@@ -0,0 +1,97 @@
+
+/*
+ * linux/arch/arm/mach-comcerto/pcie-comcerto2000.h
+ *
+ * Copyright (C) 2004,2005 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef __PCIE_C2000__
+#define __PCIE_C2000__
+
+#define NUM_PCIE_PORTS	CONFIG_COMCERTO_NUM_PCIES
+#define MAX_PCIE_PORTS  2
+
+struct pcie_port {
+	u8			port;
+	u8			root_bus_nr;
+	u16			reset;
+	unsigned long		base;
+	unsigned long		remote_mem_baseaddr;
+	unsigned long		app_base;
+	void __iomem		*va_app_base;
+	void __iomem		*va_dbi_base;
+	unsigned long		cfg0_base;
+	void __iomem		*va_cfg0_base;
+	unsigned long		cfg1_base;
+	void __iomem		*va_cfg1_base;
+	unsigned int		cfg0_prev_taddr;
+	unsigned int		cfg1_prev_taddr;
+	unsigned int		cmd_reg_val;
+	spinlock_t		conf_lock;
+	spinlock_t		intr_lock;
+	spinlock_t		msi_map_lock;
+	char			mem_space_name[16];
+	char			io_space_name[16];
+	int 			port_mode;
+	int 			link_state;
+	int 			intx_base;
+	int			msi_base;
+	int			irq;
+	dma_addr_t 		msi_mbox_handle;
+	void 			*msi_mbox_baseaddr;
+	struct pcie_app_reg	*app_regs;
+	struct resource		res[2];
+	struct clk		*ref_clock;
+#if defined(CONFIG_COMCERTO_PCIE_OCC_CLOCK)
+	struct clk              *occ_clock;
+#endif
+};
+
+#define PCIE_PORT_MODE_NONE 	-1
+#define PCIE_PORT_MODE_EP 	CFG0_DEV_TYPE_EP
+#define PCIE_PORT_MODE_RC 	CFG0_DEV_TYPE_RC
+
+/* PCIe PM related defines */
+#define PCI_CAP_PM 0x40
+
+
+/* The following register definitions are as per "DWC_regs_rev04.doc" document */
+
+struct pcie_app_reg {
+	u32	cfg0;
+	u32	cfg1;
+	u32	cfg2;
+	u32	cfg3;
+	u32	cfg4;
+	u32	cfg5;
+	u32	cfg6;
+	u32	sts0;
+	u32	sts1;
+	u32	sts2;
+	u32	sts3;
+	u32	pwr_cfg_bdgt_data;
+	u32	pwr_cfg_bdgt_fn;
+	u32	radm_sts;
+	u32	pwr_sts_bdgt;
+	u32	intr_sts;
+	u32	intr_en;
+	u32	intr_msi_sts;
+	u32	intr_msi_en;
+};
+
+#endif
diff --git a/arch/arm/mach-comcerto/include/mach/reset.h b/arch/arm/mach-comcerto/include/mach/reset.h
new file mode 100644
index 0000000..16045ea
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/reset.h
@@ -0,0 +1,130 @@
+/*
+ *  linux/arch/arm/mach-comcerto/include/mach/comcerto-2000/reset.h
+ *
+ *  Header file for block reset for all the devices availble in the 
+ *  c2000 device.
+ *
+ *  Copyright (C) 2012 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef  __ARCH_COMCERTO2000_RESET_H
+#define  __ARCH_COMCERTO2000_RESET_H
+
+#define RTC_AXI_RESET_BIT		(1<<7)
+#define I2CSPI_AXI_RESET_BIT		(1<<5)
+#define DUS_AXI_RESET_BIT		(1<<0)
+#define TDM_AXI_RESET_BIT 		(1<<4)		
+#define PFE_SYS_AXI_RESET_BIT		(1<<3)
+#define IPSEC_SPACC_AXI_RESET_BIT	(1<<2)
+#define IPSEC_EAPE_AXI_RESET_BIT	(1<<1)
+#define DPI_CIE_AXI_RESET_BIT		(1<<5)
+#define DPI_DECOMP_AXI_RESET_BIT	(1<<6)
+#define USB1_AXI_RESET_BIT		(1<<4)
+#define USB1_PHY_RESET_BIT		(1<<4)
+#define USB0_AXI_RESET_BIT		(1<<3)
+#define USB0_PHY_RESET_BIT		(1<<0)
+#define SATA_AXI_RESET_BIT		(1<<2)
+#define SATA_PMU_RESET_BIT		(1<<0)
+#define SATA_OOB_RESET_BIT		(1<<0)
+#define PCIE1_AXI_RESET_BIT		(1<<1)
+#define PCIE0_AXI_RESET_BIT		(1<<0)
+#define PFE_CORE_RESET_BIT		(1<<0)
+#define IPSEC_EAPE_CORE_RESET_BIT	(1<<0)
+#define GEMTX_RESET_BIT			(1<<0)
+#define L2CC_RESET_BIT			(1<<0)
+#define DECT_RESET_BIT			(1<<0)
+#define DDR_CNTRL_RESET_BIT		(1<<1)
+#define DDR_PHY_RESET_BIT		(1<<0)
+#define SERDES0_RESET_BIT		(1<<0)
+#define SERDES1_RESET_BIT		(1<<1)
+#define SERDES2_RESET_BIT		(1<<2)
+#define SERDES_PCIE0_RESET_BIT		((1<<0)|(1<<1))
+#define SERDES_PCIE1_RESET_BIT		((1<<2)|(1<<3))
+#define SERDES_SATA0_RESET_BIT		((1<<4)|(1<<5))
+#define SERDES_SATA1_RESET_BIT		((1<<6)|(1<<7))
+#define SGMII_RESET_BIT			(1<<0)
+#define USB0_UTMI_RESET_BIT		(1<<1)
+#define USB1_UTMI_RESET_BIT		(1<<5)
+#define TDMNTG_RESET_BIT		(1<<0)
+
+/* C2000 device blocks which are to be put 
+ * in reset.
+ */
+typedef enum {
+	COMPONENT_AXI_RTC=0,             
+	COMPONENT_AXI_LEGACY_SPI,	
+	COMPONENT_AXI_I2C, 			
+	COMPONENT_AXI_DMA, 
+	COMPONENT_AXI_FAST_UART, 
+	COMPONENT_AXI_FAST_SPI, 
+	COMPONENT_AXI_TDM, 
+	COMPONENT_PFE_SYS,
+	COMPONENT_AXI_IPSEC_EAPE,
+	COMPONENT_AXI_IPSEC_SPACC,
+	COMPONENT_AXI_DPI_CIE,
+	COMPONENT_AXI_DPI_DECOMP,
+	COMPONENT_AXI_USB1 ,		/* USB controller1, AXI Clock Domain reset control */
+	COMPONENT_UTMI_USB1,  		/* USB controller1,UTMI Clock Domain reset control*/
+	COMPONENT_USB1_PHY,		/* USB PHY1 Reset control */
+	COMPONENT_AXI_USB0,		/* USB controller0, AXI Clock Domain reset control*/
+	COMPONENT_UTMI_USB0,  		/* USB controller0. UTMI Clock Domain reset control */
+	COMPONENT_USB0_PHY,		/* USB PHY0 Reset Control */
+	COMPONENT_AXI_SATA,		/* SATA controller AXI Clock Domain Control Both for SATA 0/1*/
+	COMPONENT_SERDES_SATA0,		/* SATA serdes Controller0  TX,Core Logic and RX clock domain control*/
+	COMPONENT_SERDES_SATA1,		/* SATA serdes Controller1  TX,Core Logic and RX clock domain control*/
+	COMPONENT_AXI_PCIE1,		/* PCIE Controller1,AXI Clock Domain reset control*/ 
+	COMPONENT_SERDES_PCIE1,		/* PCIE serdes Controller1  Striky register and power register*/
+	COMPONENT_AXI_PCIE0,		/* PCIE Controller0,AXI Clock Domain reset control*/
+	COMPONENT_SERDES_PCIE0,		/* PCIE Controller1,TX,Core Logic and RX clock domain control*/
+	COMPONENT_PFE_CORE,
+	COMPONENT_IPSEC_EAPE_CORE,
+	COMPONENT_GEMTX,
+	COMPONENT_L2CC,
+	COMPONENT_DECT,
+	COMPONENT_DDR_CNTLR,
+	COMPONENT_DDR_PHY,
+	COMPONENT_SERDES0,
+	COMPONENT_SERDES1,
+	COMPONENT_SERDES2,
+	COMPONENT_SGMII,
+	COMPONENT_SATA_PMU,
+	COMPONENT_SATA_OOB,
+	COMPONENT_TDMNTG,
+}C2000_RESET_COMPONENT;
+
+extern void comcerto_rst_cntrl_set(unsigned int dev_rst_cntrl_bit);
+extern void c2000_block_reset(int block,int state);
+extern void reset_init(void);
+
+#if defined(CONFIG_C2K_MFCN_EVM)
+/* C2000 device blocks which are to be put
+ * in out of reset(GPIO).
+ */
+typedef enum {
+	COMPONENT_ATHEROS_SWITCH=0,
+	COMPONENT_SLIC,
+	COMPONENT_PCIE0,
+	COMPONENT_PCIE1,
+	COMPONENT_USB_HUB,
+	COMPONENT_EXP_DAUGTHER_CARD,
+	COMPONENT_RGMII0,
+	COMPONENT_RGMII1
+}C2000_GEN2_GPIO_RESET_COMPONENT;
+
+void GPIO_reset_external_device(int block,int state);
+#endif
+#endif
diff --git a/arch/arm/mach-comcerto/include/mach/sema.h b/arch/arm/mach-comcerto/include/mach/sema.h
new file mode 100644
index 0000000..dcecc12
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/sema.h
@@ -0,0 +1,128 @@
+/*
+ *  arch/arm/mach-comcerto/include/mach/sema.h
+ *
+ *  Copyright (C) 2012 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_SEMA_H__
+#define __ASM_ARCH_SEMA_H__
+
+#ifdef CONFIG_COMCERTO_MSP
+
+#define COMCERTO_SEMA_COUNT (64)
+
+enum {
+	COMCERTO_SEMA_MSP,
+};
+
+/* get status and disable FIQ & IRQ */
+static inline unsigned long arch_local_frq_save(void)
+{
+	unsigned long flags;
+
+	asm volatile (
+		"mrs %0, cpsr @ arch_local_frq_save\n"
+		"cpsid if"
+		: "=r" (flags) : : "memory", "cc");
+
+	return flags;
+}
+
+#define local_frq_save() arch_local_frq_save()
+#define local_frq_restore(flags) local_irq_restore(flags)
+
+/**
+ * comcerto_sema_lock()
+ * Spin to lock. Always succeeds.
+ *
+ * In order to acquire the semaphore, the processor needs to read the
+ * semaphore value. If zero, the processor acquired the semaphore and
+ * HW will set it to one, to mark that the semaphore is taken, if one
+ * is read, the semaphore is already taken by another processor and
+ * the current processor needs to keep polling the semaphore until
+ * value of zero is received.
+ *
+ * C2K has COMCERTO_SEMA_COUNT=64, 1-bit semaphores.
+ */
+static inline void comcerto_sema_lock(volatile unsigned long lock_id)
+{
+	volatile unsigned long *p = (unsigned long *)COMCERTO_SEMA_VADDR;
+	unsigned long x;
+
+	if (lock_id >= COMCERTO_SEMA_COUNT) {
+		BUG();
+	}
+
+	p += lock_id;
+	x = *p;
+
+	if (x) {
+		while (*p) {
+			/* wait for lock */
+			;
+		}
+	}
+}
+
+/**
+ * comcerto_sema_unlock()
+ * Unlock. Always succeeds.
+ *
+ * After acquiring a semaphore the processor needs to write zero to it
+ * in order to release it.
+ */
+static inline void comcerto_sema_unlock(volatile unsigned long lock_id)
+{
+	volatile unsigned long *p = (unsigned long *)COMCERTO_SEMA_VADDR;
+
+	if (lock_id >= COMCERTO_SEMA_COUNT) {
+		BUG();
+	}
+
+	p += lock_id;
+	*p = 0;
+}
+
+static inline unsigned long msp_lock_frqsave(void)
+{
+	unsigned long flags;
+
+	flags = local_frq_save();
+	comcerto_sema_lock(COMCERTO_SEMA_MSP);
+
+	return flags;
+}
+
+static inline void msp_unlock_frqrestore(unsigned long flags)
+{
+	comcerto_sema_unlock(COMCERTO_SEMA_MSP);
+	local_frq_restore(flags);
+}
+
+#else  /* !CONFIG_COMCERTO_MSP */
+static inline unsigned long msp_lock_frqsave(void)
+{
+	return 0;
+}
+
+static inline void msp_unlock_frqrestore(unsigned long flags)
+{
+	return;
+}
+#endif /* CONFIG_COMCERTO_MSP */
+
+#endif  /* __ASM_ARCH_SEMA_H__ */
diff --git a/arch/arm/mach-comcerto/include/mach/serdes-c2000.h b/arch/arm/mach-comcerto/include/mach/serdes-c2000.h
new file mode 100644
index 0000000..121af86
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/serdes-c2000.h
@@ -0,0 +1,1993 @@
+
+/*
+ * Copyright (C) Mindspeed Technologies, Inc. 2011. All rights reserved.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * @file serdes.h
+ * @brief this header file will contain all required data structure
+ *        and function definitions for Snowbush SerDes PHY interface.
+ * @date 10/02/2011
+ */
+/* SER-DES Address space */
+
+
+typedef struct serdes_regs_s
+{
+  unsigned short ofst;
+  unsigned short val;
+}serdes_regs_t;
+
+int serdes_phy_init(int phy_num, struct serdes_regs_s *regs, int size, int type);
+void serdes_phy_reset(int phy_num);
+
+ /*  Initialize values of the Snowbush PHY (Serdes1) for SATA0 */
+
+/* 48MHz internal ref clock configuration */
+static struct serdes_regs_s sata_phy_reg_file_48[] =
+        {
+          { 0x000 << 2, 0x06},
+          { 0x001 << 2, 0x00},
+          { 0x002 << 2, 0x88},
+          { 0x003 << 2, 0x00},
+          { 0x004 << 2, 0x84},
+          { 0x005 << 2, 0x10},
+          { 0x006 << 2, 0x20},
+          { 0x007 << 2, 0x00},
+          { 0x008 << 2, 0x00},
+          { 0x009 << 2, 0x00},
+          { 0x00A << 2, 0x00},
+          { 0x00B << 2, 0x00},
+          { 0x00C << 2, 0x00},
+          { 0x00D << 2, 0x00},
+          { 0x00E << 2, 0x00},
+          { 0x00F << 2, 0x00},
+          { 0x010 << 2, 0x00},
+          { 0x011 << 2, 0x00},
+          { 0x012 << 2, 0x00},
+          { 0x013 << 2, 0x00},
+          { 0x014 << 2, 0x00},
+          { 0x015 << 2, 0x00},
+          { 0x016 << 2, 0x00},
+          { 0x017 << 2, 0x00},
+          { 0x018 << 2, 0x00},
+          { 0x019 << 2, 0x00},
+          { 0x01A << 2, 0x00},
+          { 0x01B << 2, 0x00},
+          { 0x01C << 2, 0x00},
+          { 0x01D << 2, 0x00},
+          { 0x01E << 2, 0x00},
+          { 0x01F << 2, 0x00},
+          { 0x020 << 2, 0x00},
+          { 0x021 << 2, 0x00},
+          { 0x022 << 2, 0xa0},
+          { 0x023 << 2, 0x62},
+          { 0x024 << 2, 0x00},
+          { 0x025 << 2, 0x00},
+          { 0x026 << 2, 0x00},
+          { 0x027 << 2, 0x00},
+          { 0x028 << 2, 0x00},
+          { 0x029 << 2, 0x00},
+          { 0x02A << 2, 0x00},
+          { 0x02B << 2, 0x00},
+          { 0x02C << 2, 0x00},
+          { 0x02D << 2, 0x00},
+          { 0x02E << 2, 0x04},
+          { 0x02F << 2, 0x50},
+          { 0x030 << 2, 0x70},
+          { 0x031 << 2, 0x02},
+          { 0x032 << 2, 0x25},
+          { 0x033 << 2, 0x40},
+          { 0x034 << 2, 0x01},
+          { 0x035 << 2, 0x40},
+          { 0x036 << 2, 0x00},
+          { 0x037 << 2, 0x00},
+          { 0x038 << 2, 0x00},
+          { 0x039 << 2, 0x00},
+          { 0x03A << 2, 0x00},
+          { 0x03B << 2, 0x00},
+          { 0x03C << 2, 0x00},
+          { 0x03D << 2, 0x00},
+          { 0x03E << 2, 0x00},
+          { 0x03F << 2, 0x00},
+          { 0x040 << 2, 0x00},
+          { 0x041 << 2, 0x00},
+          { 0x042 << 2, 0x00},
+          { 0x043 << 2, 0x00},
+          { 0x044 << 2, 0x00},
+          { 0x045 << 2, 0x00},
+          { 0x046 << 2, 0x00},
+          { 0x047 << 2, 0x00},
+          { 0x048 << 2, 0x00},
+          { 0x049 << 2, 0x00},
+          { 0x04A << 2, 0x00},
+          { 0x04B << 2, 0x00},
+          { 0x04C << 2, 0x00},
+          { 0x04D << 2, 0x00},
+          { 0x04E << 2, 0x00},
+          { 0x04F << 2, 0x00},
+          { 0x050 << 2, 0x00},
+          { 0x051 << 2, 0x00},
+          { 0x052 << 2, 0x00},
+          { 0x053 << 2, 0x00},
+          { 0x054 << 2, 0x00},
+          { 0x055 << 2, 0x00},
+          { 0x056 << 2, 0x00},
+          { 0x057 << 2, 0x00},
+          { 0x058 << 2, 0x00},
+          { 0x059 << 2, 0x00},
+          { 0x05A << 2, 0x00},
+          { 0x05B << 2, 0x00},
+          { 0x05C << 2, 0x00},
+          { 0x05D << 2, 0x00},
+          { 0x05E << 2, 0x00},
+          { 0x05F << 2, 0x00},
+          { 0x060 << 2, 0x00},
+          { 0x061 << 2, 0x2e},
+          { 0x062 << 2, 0x08},
+          { 0x063 << 2, 0x5e},
+          { 0x064 << 2, 0x00},
+          { 0x065 << 2, 0x42},
+          { 0x066 << 2, 0xd1},
+          { 0x067 << 2, 0xa0},
+          { 0x068 << 2, 0x28},
+          { 0x069 << 2, 0x78},
+          { 0x06A << 2, 0xcc},
+          { 0x06B << 2, 0xc1},
+          { 0x06C << 2, 0x4e},
+          { 0x06D << 2, 0x03},
+          { 0x06E << 2, 0x00},
+          { 0x06F << 2, 0x00},
+          { 0x070 << 2, 0x00},
+          { 0x071 << 2, 0x00},
+          { 0x072 << 2, 0x00},
+          { 0x200 << 2, 0x02},
+          { 0x201 << 2, 0x00},
+          { 0x202 << 2, 0x00},
+          { 0x203 << 2, 0x00},
+          { 0x204 << 2, 0x00},
+          { 0x205 << 2, 0x10},
+          { 0x206 << 2, 0x84},
+          { 0x207 << 2, 0x3C}, 
+          { 0x208 << 2, 0xe0},
+          { 0x210 << 2, 0x23},
+          { 0x211 << 2, 0x00},
+          { 0x212 << 2, 0x40},
+          { 0x213 << 2, 0x05},
+          { 0x214 << 2, 0x20},/* */
+          { 0x215 << 2, 0x17},
+          { 0x216 << 2, 0x00},
+          { 0x217 << 2, 0x68},
+          { 0x218 << 2, 0xe2},
+          { 0x219 << 2, 0x1e},
+          { 0x21A << 2, 0x18},
+          { 0x21B << 2, 0x0d},
+          { 0x21C << 2, 0x0c},
+          { 0x21D << 2, 0x00},
+          { 0x21E << 2, 0x00},
+          { 0x21F << 2, 0x00},
+          { 0x220 << 2, 0x00},
+          { 0x221 << 2, 0x00},
+          { 0x222 << 2, 0x00},
+          { 0x223 << 2, 0x00},
+          { 0x224 << 2, 0x00},
+          { 0x225 << 2, 0x00},
+          { 0x226 << 2, 0x00},
+          { 0x227 << 2, 0x00},
+          { 0x228 << 2, 0x00},
+          { 0x229 << 2, 0x00},
+          { 0x22A << 2, 0x00},
+          { 0x22B << 2, 0x00},
+          { 0x22C << 2, 0x00},
+          { 0x22D << 2, 0x00},
+          { 0x22E << 2, 0x00},
+          { 0x22F << 2, 0x00},
+          { 0x230 << 2, 0x00},
+          { 0x231 << 2, 0x00},
+          { 0x232 << 2, 0x00},
+          { 0x233 << 2, 0x00},
+          { 0x234 << 2, 0x00},
+          { 0x235 << 2, 0x00},
+          { 0x236 << 2, 0x00},
+          { 0x237 << 2, 0x00},
+          { 0x238 << 2, 0x00},
+          { 0x239 << 2, 0x00},
+          { 0x23A << 2, 0x00},
+          { 0x23B << 2, 0x00},
+          { 0x23C << 2, 0x00},
+          { 0x23D << 2, 0x00},
+          { 0x23E << 2, 0x00},
+          { 0x23F << 2, 0x00},
+          { 0x240 << 2, 0x00},
+          { 0x241 << 2, 0x00},
+          { 0x242 << 2, 0x00},
+          { 0x243 << 2, 0x00},
+          { 0x244 << 2, 0x00},
+          { 0x245 << 2, 0x00},
+          { 0x246 << 2, 0x00},
+          { 0x247 << 2, 0x00},
+          { 0x248 << 2, 0x00},
+          { 0x249 << 2, 0x00},
+          { 0x24A << 2, 0x00},
+          { 0x24B << 2, 0x00},
+          { 0x24C << 2, 0x00},
+          { 0x24D << 2, 0x00},
+          { 0x24E << 2, 0x00},
+          { 0x24F << 2, 0x00},
+          { 0x250 << 2, 0x60},
+          { 0x251 << 2, 0x0f},
+          { 0xA00 << 2, 0x00},
+          { 0xA01 << 2, 0x20},
+          { 0xA02 << 2, 0x00},
+          { 0xA03 << 2, 0x40},
+          { 0xA04 << 2, 0x24},
+          { 0xA05 << 2, 0xae},
+          { 0xA06 << 2, 0x19},
+          { 0xA07 << 2, 0x49},
+          { 0xA08 << 2, 0x04},
+          { 0xA09 << 2, 0xc3},
+          { 0xA0A << 2, 0x2a},
+          { 0xA0B << 2, 0xc6},
+          { 0xA0C << 2, 0x01},
+          { 0xA0D << 2, 0x03},
+          { 0xA0E << 2, 0x28},
+          { 0xA0F << 2, 0x98},
+          { 0xA10 << 2, 0x19},
+          { 0xA11 << 2, 0x00},
+          { 0xA12 << 2, 0x00},
+          { 0xA13 << 2, 0x80},
+          { 0xA14 << 2, 0xf0},
+          { 0xA15 << 2, 0xd0},
+          { 0xA16 << 2, 0x00},
+          { 0xA17 << 2, 0x00},
+          { 0xA30 << 2, 0x00},
+          { 0xA31 << 2, 0x00},
+          { 0xA32 << 2, 0x00},
+          { 0xA33 << 2, 0x00},
+          { 0xA34 << 2, 0x00},
+          { 0xA35 << 2, 0x00},
+          { 0xA36 << 2, 0x00},
+          { 0xA37 << 2, 0x00},
+          { 0xA38 << 2, 0x00},
+          { 0xA39 << 2, 0xa0},
+          { 0xA3A << 2, 0xa0},
+          { 0xA3B << 2, 0xa0},
+          { 0xA3C << 2, 0xa0},
+          { 0xA3D << 2, 0xa0},
+          { 0xA3E << 2, 0xa0},
+          { 0xA3F << 2, 0xa0},
+          { 0xA40 << 2, 0x62},
+          { 0xA41 << 2, 0x00},
+          { 0xA42 << 2, 0x80},
+          { 0xA43 << 2, 0x58},
+          { 0xA44 << 2, 0x00},
+          { 0xA45 << 2, 0x44},
+          { 0xA46 << 2, 0x5c},
+          { 0xA47 << 2, 0x86},
+          { 0xA48 << 2, 0x8d},
+          { 0xA49 << 2, 0xd0},
+          { 0xA4A << 2, 0x09},
+          { 0xA4B << 2, 0x90},
+          { 0xA4C << 2, 0x07},
+          { 0xA4D << 2, 0x40},
+          { 0xA4E << 2, 0x00},
+          { 0xA4F << 2, 0x00},
+          { 0xA50 << 2, 0x00},
+          { 0xA51 << 2, 0x20},
+          { 0xA52 << 2, 0x32},
+          { 0xA53 << 2, 0x00},
+          { 0xA54 << 2, 0x00},
+          { 0xA55 << 2, 0x00},
+          { 0xA56 << 2, 0x00},
+          { 0xA57 << 2, 0x00},
+          { 0xA58 << 2, 0x00},
+          { 0xA59 << 2, 0x00},
+          { 0xA5A << 2, 0x00},
+          { 0xA5B << 2, 0x00},
+          { 0xA5C << 2, 0x00},
+          { 0xA5D << 2, 0x00},
+          { 0xA5E << 2, 0x00},
+          { 0xA5F << 2, 0x00},
+          { 0xA60 << 2, 0x00},
+          { 0xA61 << 2, 0x00},
+          { 0xA62 << 2, 0x00},
+          { 0xA63 << 2, 0x00},
+          { 0xA64 << 2, 0x00},
+          { 0xA65 << 2, 0x00},
+          { 0xA66 << 2, 0x00},
+          { 0xA67 << 2, 0x00},
+          { 0xA68 << 2, 0x00},
+          { 0xA69 << 2, 0x00},
+          { 0xA6A << 2, 0x00},
+          { 0xA6B << 2, 0x00},
+          { 0xA6C << 2, 0x00},
+          { 0xA6D << 2, 0x00},
+          { 0xA6E << 2, 0x00},
+          { 0xA6F << 2, 0x00},
+          { 0xA70 << 2, 0x00},
+          { 0xA71 << 2, 0x00},
+          { 0xA72 << 2, 0x00},
+          { 0xA73 << 2, 0x00},
+          { 0xA74 << 2, 0x00},
+          { 0xA75 << 2, 0x00},
+          { 0xA76 << 2, 0x00},
+          { 0xA77 << 2, 0x00},
+          { 0xA78 << 2, 0x00},
+          { 0xA79 << 2, 0x00},
+          { 0xA7A << 2, 0x00},
+          { 0xA7B << 2, 0x00},
+          { 0xA7C << 2, 0x00},
+          { 0xA7D << 2, 0x00},
+          { 0xA7E << 2, 0x00},
+          { 0xA7F << 2, 0xd8},
+          { 0xA80 << 2, 0x1a},
+          { 0xA81 << 2, 0xff},
+          { 0xA82 << 2, 0x11},
+          { 0xA83 << 2, 0x00},
+          { 0xA84 << 2, 0x00},
+          { 0xA85 << 2, 0x00},
+          { 0xA86 << 2, 0x00},
+          { 0xA87 << 2, 0xf0},
+          { 0xA88 << 2, 0xff},
+          { 0xA89 << 2, 0xff},
+          { 0xA8A << 2, 0xff},
+          { 0xA8B << 2, 0xff},
+          { 0xA8C << 2, 0x1c},
+          { 0xA8D << 2, 0xc2},
+          { 0xA8E << 2, 0xc3},
+          { 0xA8F << 2, 0x3f},
+          { 0xA90 << 2, 0x0a},
+          { 0xA91 << 2, 0x00},
+          { 0xA92 << 2, 0x00},
+          { 0xA93 << 2, 0x00},
+          { 0xA94 << 2, 0x00},
+          { 0xA95 << 2, 0x00},
+          { 0xA96 << 2, 0xf8},
+          { 0x000 << 2, 0x07}
+        };
+
+/* 24MHz internal ref clock configuration */
+static struct serdes_regs_s sata_phy_reg_file_24[] =
+        {
+          { 0x000 << 2, 0x06},
+          { 0x001 << 2, 0x00},
+          { 0x002 << 2, 0x88},
+          { 0x003 << 2, 0x00},
+          { 0x004 << 2, 0x7b},
+          { 0x005 << 2, 0xc9},
+          { 0x006 << 2, 0x03},
+          { 0x007 << 2, 0x00},
+          { 0x008 << 2, 0x00},
+          { 0x009 << 2, 0x00},
+          { 0x00A << 2, 0x00},
+          { 0x00B << 2, 0x00},
+          { 0x00C << 2, 0x00},
+          { 0x00D << 2, 0x00},
+          { 0x00E << 2, 0x00},
+          { 0x00F << 2, 0x00},
+          { 0x010 << 2, 0x00},
+          { 0x011 << 2, 0x00},
+          { 0x012 << 2, 0x00},
+          { 0x013 << 2, 0x00},
+          { 0x014 << 2, 0x00},
+          { 0x015 << 2, 0x00},
+          { 0x016 << 2, 0x00},
+          { 0x017 << 2, 0x00},
+          { 0x018 << 2, 0x00},
+          { 0x019 << 2, 0x00},
+          { 0x01A << 2, 0x00},
+          { 0x01B << 2, 0x00},
+          { 0x01C << 2, 0x00},
+          { 0x01D << 2, 0x00},
+          { 0x01E << 2, 0x00},
+          { 0x01F << 2, 0x00},
+          { 0x020 << 2, 0x00},
+          { 0x021 << 2, 0x00},
+          { 0x022 << 2, 0xa0},
+          { 0x023 << 2, 0x54},
+          { 0x024 << 2, 0x00},
+          { 0x025 << 2, 0x00},
+          { 0x026 << 2, 0x00},
+          { 0x027 << 2, 0x00},
+          { 0x028 << 2, 0x00},
+          { 0x029 << 2, 0x00},
+          { 0x02A << 2, 0x00},
+          { 0x02B << 2, 0x00},
+          { 0x02C << 2, 0x00},
+          { 0x02D << 2, 0x00},
+          { 0x02E << 2, 0x04},
+          { 0x02F << 2, 0x50},
+          { 0x030 << 2, 0x70},
+          { 0x031 << 2, 0x02},
+          { 0x032 << 2, 0x25},
+          { 0x033 << 2, 0x40},
+          { 0x034 << 2, 0x01},
+          { 0x035 << 2, 0x40},
+          { 0x036 << 2, 0x00},
+          { 0x037 << 2, 0x00},
+          { 0x038 << 2, 0x00},
+          { 0x039 << 2, 0x00},
+          { 0x03A << 2, 0x00},
+          { 0x03B << 2, 0x00},
+          { 0x03C << 2, 0x00},
+          { 0x03D << 2, 0x00},
+          { 0x03E << 2, 0x00},
+          { 0x03F << 2, 0x00},
+          { 0x040 << 2, 0x00},
+          { 0x041 << 2, 0x00},
+          { 0x042 << 2, 0x00},
+          { 0x043 << 2, 0x00},
+          { 0x044 << 2, 0x00},
+          { 0x045 << 2, 0x00},
+          { 0x046 << 2, 0x00},
+          { 0x047 << 2, 0x00},
+          { 0x048 << 2, 0x00},
+          { 0x049 << 2, 0x00},
+          { 0x04A << 2, 0x00},
+          { 0x04B << 2, 0x00},
+          { 0x04C << 2, 0x00},
+          { 0x04D << 2, 0x00},
+          { 0x04E << 2, 0x00},
+          { 0x04F << 2, 0x00},
+          { 0x050 << 2, 0x00},
+          { 0x051 << 2, 0x00},
+          { 0x052 << 2, 0x00},
+          { 0x053 << 2, 0x00},
+          { 0x054 << 2, 0x00},
+          { 0x055 << 2, 0x00},
+          { 0x056 << 2, 0x00},
+          { 0x057 << 2, 0x00},
+          { 0x058 << 2, 0x00},
+          { 0x059 << 2, 0x00},
+          { 0x05A << 2, 0x00},
+          { 0x05B << 2, 0x00},
+          { 0x05C << 2, 0x00},
+          { 0x05D << 2, 0x00},
+          { 0x05E << 2, 0x00},
+          { 0x05F << 2, 0x00},
+          { 0x060 << 2, 0x00},
+          //{ 0x061 << 2, 0x2e}, //for Rev-A0 device
+          { 0x061 << 2, 0x2e}, //for Rev-A1 device
+          { 0x062 << 2, 0x00},
+          { 0x063 << 2, 0x5e},
+          { 0x064 << 2, 0x00},
+          { 0x065 << 2, 0x42},
+          { 0x066 << 2, 0xd1},
+          { 0x067 << 2, 0x20},
+          { 0x068 << 2, 0x28},
+          { 0x069 << 2, 0x78},
+          { 0x06A << 2, 0x2c},
+          { 0x06B << 2, 0xb9},
+          { 0x06C << 2, 0x5e},
+          { 0x06D << 2, 0x03},
+          { 0x06E << 2, 0x00},
+          { 0x06F << 2, 0x00},
+          { 0x070 << 2, 0x00},
+          { 0x071 << 2, 0x00},
+          { 0x072 << 2, 0x00},
+          { 0x200 << 2, 0x02},
+          { 0x201 << 2, 0x00},
+          { 0x202 << 2, 0x00},
+          { 0x203 << 2, 0x00},
+          { 0x204 << 2, 0x00},
+          { 0x205 << 2, 0x10},
+          { 0x206 << 2, 0x84},
+          { 0x207 << 2, 0x3c}, 
+          { 0x208 << 2, 0xe0},
+          { 0x210 << 2, 0x23},
+          { 0x211 << 2, 0x00},
+          { 0x212 << 2, 0x40},
+          { 0x213 << 2, 0x05},
+          { 0x214 << 2, 0xd0},/* */
+          { 0x215 << 2, 0x17},
+          { 0x216 << 2, 0x00},
+          { 0x217 << 2, 0x68},
+          { 0x218 << 2, 0xf2},
+          { 0x219 << 2, 0x1e},
+          { 0x21A << 2, 0x18},
+          { 0x21B << 2, 0x0d},
+          { 0x21C << 2, 0x0c},
+          { 0x21D << 2, 0x00},
+          { 0x21E << 2, 0x00},
+          { 0x21F << 2, 0x00},
+          { 0x220 << 2, 0x00},
+          { 0x221 << 2, 0x00},
+          { 0x222 << 2, 0x00},
+          { 0x223 << 2, 0x00},
+          { 0x224 << 2, 0x00},
+          { 0x225 << 2, 0x00},
+          { 0x226 << 2, 0x00},
+          { 0x227 << 2, 0x00},
+          { 0x228 << 2, 0x00},
+          { 0x229 << 2, 0x00},
+          { 0x22A << 2, 0x00},
+          { 0x22B << 2, 0x00},
+          { 0x22C << 2, 0x00},
+          { 0x22D << 2, 0x00},
+          { 0x22E << 2, 0x00},
+          { 0x22F << 2, 0x00},
+          { 0x230 << 2, 0x00},
+          { 0x231 << 2, 0x00},
+          { 0x232 << 2, 0x00},
+          { 0x233 << 2, 0x00},
+          { 0x234 << 2, 0x00},
+          { 0x235 << 2, 0x00},
+          { 0x236 << 2, 0x00},
+          { 0x237 << 2, 0x00},
+          { 0x238 << 2, 0x00},
+          { 0x239 << 2, 0x00},
+          { 0x23A << 2, 0x00},
+          { 0x23B << 2, 0x00},
+          { 0x23C << 2, 0x00},
+          { 0x23D << 2, 0x00},
+          { 0x23E << 2, 0x00},
+          { 0x23F << 2, 0x00},
+          { 0x240 << 2, 0x00},
+          { 0x241 << 2, 0x00},
+          { 0x242 << 2, 0x00},
+          { 0x243 << 2, 0x00},
+          { 0x244 << 2, 0x00},
+          { 0x245 << 2, 0x00},
+          { 0x246 << 2, 0x00},
+          { 0x247 << 2, 0x00},
+          { 0x248 << 2, 0x00},
+          { 0x249 << 2, 0x00},
+          { 0x24A << 2, 0x00},
+          { 0x24B << 2, 0x00},
+          { 0x24C << 2, 0x00},
+          { 0x24D << 2, 0x00},
+          { 0x24E << 2, 0x00},
+          { 0x24F << 2, 0x00},
+          { 0x250 << 2, 0x60},
+          { 0x251 << 2, 0x0f},
+          { 0xA00 << 2, 0x00},
+          { 0xA01 << 2, 0x20},
+          { 0xA02 << 2, 0x00},
+          { 0xA03 << 2, 0x40},
+          { 0xA04 << 2, 0x24},
+          { 0xA05 << 2, 0xae},
+          { 0xA06 << 2, 0x19},
+          { 0xA07 << 2, 0x49},
+          { 0xA08 << 2, 0x04},
+          { 0xA09 << 2, 0x83},
+          { 0xA0A << 2, 0x4b},
+          { 0xA0B << 2, 0xc5},
+          { 0xA0C << 2, 0x01},
+          { 0xA0D << 2, 0x03},
+          { 0xA0E << 2, 0x28},
+          { 0xA0F << 2, 0x98},
+          { 0xA10 << 2, 0x19},
+          { 0xA11 << 2, 0x00},
+          { 0xA12 << 2, 0x00},
+          { 0xA13 << 2, 0x80},
+          { 0xA14 << 2, 0xf0},
+          { 0xA15 << 2, 0xd0},
+          { 0xA16 << 2, 0x00},
+          { 0xA17 << 2, 0x00},
+          { 0xA30 << 2, 0x00},
+          { 0xA31 << 2, 0x00},
+          { 0xA32 << 2, 0x00},
+          { 0xA33 << 2, 0x00},
+          { 0xA34 << 2, 0x00},
+          { 0xA35 << 2, 0x00},
+          { 0xA36 << 2, 0x00},
+          { 0xA37 << 2, 0x00},
+          { 0xA38 << 2, 0x00},
+          { 0xA39 << 2, 0xa0},
+          { 0xA3A << 2, 0xa0},
+          { 0xA3B << 2, 0xa0},
+          { 0xA3C << 2, 0xa0},
+          { 0xA3D << 2, 0xa0},
+          { 0xA3E << 2, 0xa0},
+          { 0xA3F << 2, 0x54},
+          { 0xA40 << 2, 0x62},
+          { 0xA41 << 2, 0x00},
+          { 0xA42 << 2, 0x80},
+          { 0xA43 << 2, 0x58},
+          { 0xA44 << 2, 0x00},
+          { 0xA45 << 2, 0x44},
+          { 0xA46 << 2, 0x5c},
+          { 0xA47 << 2, 0x86},
+          { 0xA48 << 2, 0x8d},
+          { 0xA49 << 2, 0xd0},
+          { 0xA4A << 2, 0x09},
+          { 0xA4B << 2, 0x90},
+          { 0xA4C << 2, 0x07},
+          { 0xA4D << 2, 0x40},
+          { 0xA4E << 2, 0x00},
+          { 0xA4F << 2, 0x00},
+          { 0xA50 << 2, 0x00},
+          { 0xA51 << 2, 0x20},
+          { 0xA52 << 2, 0x32},
+          { 0xA53 << 2, 0x00},
+          { 0xA54 << 2, 0x00},
+          { 0xA55 << 2, 0x00},
+          { 0xA56 << 2, 0x00},
+          { 0xA57 << 2, 0x00},
+          { 0xA58 << 2, 0x00},
+          { 0xA59 << 2, 0x00},
+          { 0xA5A << 2, 0x00},
+          { 0xA5B << 2, 0x00},
+          { 0xA5C << 2, 0x00},
+          { 0xA5D << 2, 0x00},
+          { 0xA5E << 2, 0x00},
+          { 0xA5F << 2, 0x00},
+          { 0xA60 << 2, 0x00},
+          { 0xA61 << 2, 0x00},
+          { 0xA62 << 2, 0x00},
+          { 0xA63 << 2, 0x00},
+          { 0xA64 << 2, 0x00},
+          { 0xA65 << 2, 0x00},
+          { 0xA66 << 2, 0x00},
+          { 0xA67 << 2, 0x00},
+          { 0xA68 << 2, 0x00},
+          { 0xA69 << 2, 0x00},
+          { 0xA6A << 2, 0x00},
+          { 0xA6B << 2, 0x00},
+          { 0xA6C << 2, 0x00},
+          { 0xA6D << 2, 0x00},
+          { 0xA6E << 2, 0x00},
+          { 0xA6F << 2, 0x00},
+          { 0xA70 << 2, 0x00},
+          { 0xA71 << 2, 0x00},
+          { 0xA72 << 2, 0x00},
+          { 0xA73 << 2, 0x00},
+          { 0xA74 << 2, 0x00},
+          { 0xA75 << 2, 0x00},
+          { 0xA76 << 2, 0x00},
+          { 0xA77 << 2, 0x00},
+          { 0xA78 << 2, 0x00},
+          { 0xA79 << 2, 0x00},
+          { 0xA7A << 2, 0x00},
+          { 0xA7B << 2, 0x00},
+          { 0xA7C << 2, 0x00},
+          { 0xA7D << 2, 0x00},
+          { 0xA7E << 2, 0x00},
+          { 0xA7F << 2, 0xd8},
+          { 0xA80 << 2, 0x1a},
+          { 0xA81 << 2, 0xff},
+          { 0xA82 << 2, 0x11},
+          { 0xA83 << 2, 0x00},
+          { 0xA84 << 2, 0x00},
+          { 0xA85 << 2, 0x00},
+          { 0xA86 << 2, 0x00},
+          { 0xA87 << 2, 0xf0},
+          { 0xA88 << 2, 0xff},
+          { 0xA89 << 2, 0xff},
+          { 0xA8A << 2, 0xff},
+          { 0xA8B << 2, 0xff},
+          { 0xA8C << 2, 0x1c},
+          { 0xA8D << 2, 0xc2},
+          { 0xA8E << 2, 0xc3},
+          { 0xA8F << 2, 0x3f},
+          { 0xA90 << 2, 0x0a},
+          { 0xA91 << 2, 0x00},
+          { 0xA92 << 2, 0x00},
+          { 0xA93 << 2, 0x00},
+          { 0xA94 << 2, 0x00},
+          { 0xA95 << 2, 0x00},
+          { 0xA96 << 2, 0xf8},
+          { 0x000 << 2, 0x07}
+        };
+
+#if 0
+/* This is 60Mhz external ref clock configuration which is not used on the board currently */
+static struct serdes_regs_s sata0_phy_reg_file[] =
+	{
+    	  { 0x000 << 2, 0x06},
+	  { 0x001 << 2, 0x00},
+	  { 0x002 << 2, 0x80},
+	  { 0x003 << 2, 0x00},
+	  { 0x004 << 2, 0x00},
+	  { 0x005 << 2, 0x00},
+	  { 0x006 << 2, 0x00},
+	  { 0x007 << 2, 0x00},
+	  { 0x008 << 2, 0x00},
+	  { 0x009 << 2, 0x00},
+	  { 0x00A << 2, 0x00},
+	  { 0x00B << 2, 0x00},
+	  { 0x00C << 2, 0x00},
+	  { 0x00D << 2, 0x00},
+	  { 0x00E << 2, 0x00},
+	  { 0x00F << 2, 0x00},
+	  { 0x010 << 2, 0x00},
+	  { 0x011 << 2, 0x00},
+	  { 0x012 << 2, 0x00},
+	  { 0x013 << 2, 0x00},
+	  { 0x014 << 2, 0x00},
+	  { 0x015 << 2, 0x00},
+	  { 0x016 << 2, 0x00},
+	  { 0x017 << 2, 0x00},
+	  { 0x018 << 2, 0x00},
+	  { 0x019 << 2, 0x00},
+	  { 0x01A << 2, 0x00},
+	  { 0x01B << 2, 0x00},
+	  { 0x01C << 2, 0x00},
+	  { 0x01D << 2, 0x00},
+	  { 0x01E << 2, 0x00},
+	  { 0x01F << 2, 0x00},
+	  { 0x020 << 2, 0x00},
+	  { 0x021 << 2, 0x00},
+	  { 0x022 << 2, 0xa0},
+	  { 0x023 << 2, 0x64},
+	  { 0x024 << 2, 0x00},
+	  { 0x025 << 2, 0x00},
+	  { 0x026 << 2, 0x00},
+	  { 0x027 << 2, 0x00},
+	  { 0x028 << 2, 0x00},
+	  { 0x029 << 2, 0x00},
+	  { 0x02A << 2, 0x00},
+	  { 0x02B << 2, 0x00},
+	  { 0x02C << 2, 0x00},
+	  { 0x02D << 2, 0x00},
+	  { 0x02E << 2, 0x04},
+	  { 0x02F << 2, 0x50},
+	  { 0x030 << 2, 0x70},
+	  { 0x031 << 2, 0x02},
+	  { 0x032 << 2, 0x25},
+	  { 0x033 << 2, 0x40},
+	  { 0x034 << 2, 0x01},
+	  { 0x035 << 2, 0x40},
+	  { 0x036 << 2, 0x00},
+	  { 0x037 << 2, 0x00},
+	  { 0x038 << 2, 0x00},
+	  { 0x039 << 2, 0x00},
+	  { 0x03A << 2, 0x00},
+	  { 0x03B << 2, 0x00},
+	  { 0x03C << 2, 0x00},
+	  { 0x03D << 2, 0x00},
+	  { 0x03E << 2, 0x00},
+	  { 0x03F << 2, 0x00},
+	  { 0x040 << 2, 0x00},
+	  { 0x041 << 2, 0x00},
+	  { 0x042 << 2, 0x00},
+	  { 0x043 << 2, 0x00},
+	  { 0x044 << 2, 0x00},
+	  { 0x045 << 2, 0x00},
+	  { 0x046 << 2, 0x00},
+	  { 0x047 << 2, 0x00},
+	  { 0x048 << 2, 0x00},
+	  { 0x049 << 2, 0x00},
+	  { 0x04A << 2, 0x00},
+	  { 0x04B << 2, 0x00},
+	  { 0x04C << 2, 0x00},
+	  { 0x04D << 2, 0x00},
+	  { 0x04E << 2, 0x00},
+	  { 0x04F << 2, 0x00},
+	  { 0x050 << 2, 0x00},
+	  { 0x051 << 2, 0x00},
+	  { 0x052 << 2, 0x00},
+	  { 0x053 << 2, 0x00},
+	  { 0x054 << 2, 0x00},
+	  { 0x055 << 2, 0x00},
+	  { 0x056 << 2, 0x00},
+	  { 0x057 << 2, 0x00},
+	  { 0x058 << 2, 0x00},
+	  { 0x059 << 2, 0x00},
+	  { 0x05A << 2, 0x00},
+	  { 0x05B << 2, 0x00},
+	  { 0x05C << 2, 0x00},
+	  { 0x05D << 2, 0x00},
+	  { 0x05E << 2, 0x00},
+	  { 0x05F << 2, 0x00},
+	  { 0x060 << 2, 0x00},
+	  { 0x061 << 2, 0x2e},
+	  { 0x062 << 2, 0x00},
+	  { 0x063 << 2, 0x5e},
+	  { 0x064 << 2, 0x00},
+	  { 0x065 << 2, 0x42},
+	  { 0x066 << 2, 0xd1},
+	  { 0x067 << 2, 0xa0},
+	  { 0x068 << 2, 0x28},
+	  { 0x069 << 2, 0x78},
+	  { 0x06A << 2, 0x44},
+	  { 0x06B << 2, 0xce},
+	  { 0x06C << 2, 0x0b},
+	  { 0x06D << 2, 0x00},
+	  { 0x06E << 2, 0x00},
+	  { 0x06F << 2, 0x00},
+	  { 0x070 << 2, 0x00},
+	  { 0x071 << 2, 0x00},
+	  { 0x072 << 2, 0x00},
+          { 0x200 << 2, 0x02},
+	  { 0x201 << 2, 0x00},
+	  { 0x202 << 2, 0x00},
+	  { 0x203 << 2, 0x00},
+	  { 0x204 << 2, 0x00},
+	  { 0x205 << 2, 0x10},
+	  { 0x206 << 2, 0x84},
+	  { 0x207 << 2, 0x04},
+	  { 0x208 << 2, 0xe0},
+	  { 0x210 << 2, 0x23},
+	  { 0x211 << 2, 0x00},
+	  { 0x212 << 2, 0x00},
+	  { 0x213 << 2, 0x05},
+	  { 0x214 << 2, 0x38},
+	  { 0x215 << 2, 0x04},
+	  { 0x216 << 2, 0x00},
+	  { 0x217 << 2, 0x68},
+	  { 0x218 << 2, 0xf2},
+	  { 0x219 << 2, 0x1e},
+	  { 0x21A << 2, 0x18},
+	  { 0x21B << 2, 0x0d},
+	  { 0x21C << 2, 0x0d},
+	  { 0x21D << 2, 0x00},
+	  { 0x21E << 2, 0x00},
+	  { 0x21F << 2, 0x00},
+	  { 0x220 << 2, 0x00},
+	  { 0x221 << 2, 0x00},
+	  { 0x222 << 2, 0x00},
+	  { 0x223 << 2, 0x00},
+	  { 0x224 << 2, 0x00},
+	  { 0x225 << 2, 0x00},
+	  { 0x226 << 2, 0x00},
+	  { 0x227 << 2, 0x00},
+	  { 0x228 << 2, 0x00},
+	  { 0x229 << 2, 0x00},
+	  { 0x22A << 2, 0x00},
+	  { 0x22B << 2, 0x00},
+	  { 0x22C << 2, 0x00},
+	  { 0x22D << 2, 0x00},
+	  { 0x22E << 2, 0x00},
+	  { 0x22F << 2, 0x00},
+	  { 0x230 << 2, 0x00},
+	  { 0x231 << 2, 0x00},
+	  { 0x232 << 2, 0x00},
+	  { 0x233 << 2, 0x00},
+	  { 0x234 << 2, 0x00},
+	  { 0x235 << 2, 0x00},
+	  { 0x236 << 2, 0x00},
+	  { 0x237 << 2, 0x00},
+	  { 0x238 << 2, 0x00},
+	  { 0x239 << 2, 0x00},
+	  { 0x23A << 2, 0x00},
+	  { 0x23B << 2, 0x00},
+	  { 0x23C << 2, 0x00},
+	  { 0x23D << 2, 0x00},
+	  { 0x23E << 2, 0x00},
+	  { 0x23F << 2, 0x00},
+	  { 0x240 << 2, 0x00},
+	  { 0x241 << 2, 0x00},
+	  { 0x242 << 2, 0x00},
+	  { 0x243 << 2, 0x00},
+	  { 0x244 << 2, 0x00},
+	  { 0x245 << 2, 0x00},
+	  { 0x246 << 2, 0x00},
+	  { 0x247 << 2, 0x00},
+	  { 0x248 << 2, 0x00},
+	  { 0x249 << 2, 0x00},
+	  { 0x24A << 2, 0x00},
+	  { 0x24B << 2, 0x00},
+	  { 0x24C << 2, 0x00},
+	  { 0x24D << 2, 0x00},
+	  { 0x24E << 2, 0x00},
+	  { 0x24F << 2, 0x00},
+	  { 0x250 << 2, 0x60},
+	  { 0x251 << 2, 0x0f},
+	  { 0xA00 << 2, 0x00},
+	  { 0xA01 << 2, 0x20},
+	  { 0xA02 << 2, 0x00},
+	  { 0xA03 << 2, 0x40},
+	  { 0xA04 << 2, 0x24},
+	  { 0xA05 << 2, 0xae},
+	  { 0xA06 << 2, 0x19},
+	  { 0xA07 << 2, 0x49},
+	  { 0xA08 << 2, 0x04},
+	  { 0xA09 << 2, 0x23},
+	  { 0xA0A << 2, 0x48},
+	  { 0xA0B << 2, 0xc6},
+	  { 0xA0C << 2, 0x01},
+	  { 0xA0D << 2, 0x03},
+	  { 0xA0E << 2, 0x28},
+	  { 0xA0F << 2, 0x98},
+	  { 0xA10 << 2, 0x19},
+	  { 0xA11 << 2, 0x00},
+	  { 0xA12 << 2, 0x00},
+	  { 0xA13 << 2, 0x80},
+	  { 0xA14 << 2, 0xf0},
+	  { 0xA15 << 2, 0xd0},
+	  { 0xA16 << 2, 0x00},
+	  { 0xA17 << 2, 0x00},
+	  { 0xA30 << 2, 0x00},
+	  { 0xA31 << 2, 0x00},
+	  { 0xA32 << 2, 0x00},
+	  { 0xA33 << 2, 0x00},
+	  { 0xA34 << 2, 0x00},
+	  { 0xA35 << 2, 0x00},
+	  { 0xA36 << 2, 0x00},
+	  { 0xA37 << 2, 0x00},
+	  { 0xA38 << 2, 0x00},
+	  { 0xA39 << 2, 0xa0},
+	  { 0xA3A << 2, 0xa0},
+	  { 0xA3B << 2, 0xa0},
+	  { 0xA3C << 2, 0xa0},
+	  { 0xA3D << 2, 0xa0},
+	  { 0xA3E << 2, 0xa0},
+	  { 0xA3F << 2, 0xa0},
+	  { 0xA40 << 2, 0x64},
+	  { 0xA41 << 2, 0x00},
+	  { 0xA42 << 2, 0x80},
+	  { 0xA43 << 2, 0x58},
+	  { 0xA44 << 2, 0x00},
+	  { 0xA45 << 2, 0x44},
+	  { 0xA46 << 2, 0x5c},
+	  { 0xA47 << 2, 0x86},
+	  { 0xA48 << 2, 0x8d},
+	  { 0xA49 << 2, 0xd0},
+	  { 0xA4A << 2, 0x09},
+	  { 0xA4B << 2, 0x90},
+	  { 0xA4C << 2, 0x07},
+	  { 0xA4D << 2, 0x40},
+	  { 0xA4E << 2, 0x00},
+	  { 0xA4F << 2, 0x00},
+	  { 0xA50 << 2, 0x00},
+	  { 0xA51 << 2, 0x20},
+	  { 0xA52 << 2, 0x32},
+	  { 0xA53 << 2, 0x00},
+	  { 0xA54 << 2, 0x00},
+	  { 0xA55 << 2, 0x00},
+	  { 0xA56 << 2, 0x00},
+	  { 0xA57 << 2, 0x00},
+	  { 0xA58 << 2, 0x00},
+	  { 0xA59 << 2, 0x00},
+	  { 0xA5A << 2, 0x00},
+	  { 0xA5B << 2, 0x00},
+	  { 0xA5C << 2, 0x00},
+	  { 0xA5D << 2, 0x00},
+	  { 0xA5E << 2, 0x00},
+	  { 0xA5F << 2, 0x00},
+	  { 0xA60 << 2, 0x00},
+	  { 0xA61 << 2, 0x00},
+	  { 0xA62 << 2, 0x00},
+	  { 0xA63 << 2, 0x00},
+	  { 0xA64 << 2, 0x00},
+	  { 0xA65 << 2, 0x00},
+	  { 0xA66 << 2, 0x00},
+	  { 0xA67 << 2, 0x00},
+	  { 0xA68 << 2, 0x00},
+	  { 0xA69 << 2, 0x00},
+	  { 0xA6A << 2, 0x00},
+	  { 0xA6B << 2, 0x00},
+	  { 0xA6C << 2, 0x00},
+	  { 0xA6D << 2, 0x00},
+	  { 0xA6E << 2, 0x00},
+	  { 0xA6F << 2, 0x00},
+	  { 0xA70 << 2, 0x00},
+	  { 0xA71 << 2, 0x00},
+	  { 0xA72 << 2, 0x00},
+	  { 0xA73 << 2, 0x00},
+	  { 0xA74 << 2, 0x00},
+	  { 0xA75 << 2, 0x00},
+	  { 0xA76 << 2, 0x00},
+	  { 0xA77 << 2, 0x00},
+	  { 0xA78 << 2, 0x00},
+	  { 0xA79 << 2, 0x00},
+	  { 0xA7A << 2, 0x00},
+	  { 0xA7B << 2, 0x00},
+	  { 0xA7C << 2, 0x00},
+	  { 0xA7D << 2, 0x00},
+	  { 0xA7E << 2, 0x00},
+	  { 0xA7F << 2, 0xd8},
+	  { 0xA80 << 2, 0x1a},
+	  { 0xA81 << 2, 0xff},
+	  { 0xA82 << 2, 0x11},
+	  { 0xA83 << 2, 0x00},
+	  { 0xA84 << 2, 0x00},
+	  { 0xA85 << 2, 0x00},
+	  { 0xA86 << 2, 0x00},
+	  { 0xA87 << 2, 0xf0},
+	  { 0xA88 << 2, 0xff},
+	  { 0xA89 << 2, 0xff},
+	  { 0xA8A << 2, 0xff},
+	  { 0xA8B << 2, 0xff},
+	  { 0xA8C << 2, 0x1c},
+	  { 0xA8D << 2, 0xc2},
+	  { 0xA8E << 2, 0xc3},
+	  { 0xA8F << 2, 0x3f},
+	  { 0xA90 << 2, 0x0a},
+	  { 0xA91 << 2, 0x00},
+	  { 0xA92 << 2, 0x00},
+	  { 0xA93 << 2, 0x00},
+	  { 0xA94 << 2, 0x00},
+	  { 0xA95 << 2, 0x00},
+	  { 0xA96 << 2, 0xf8},
+	  { 0x000 << 2, 0x07}
+	};
+#endif
+
+static struct serdes_regs_s pcie_phy_reg_file_48[] =
+
+/* PCIe SERDES is using internal clock */
+  	{
+	  /* Common CMU block */
+  	  { 0x000 << 2, 0x06},
+  	  { 0x001 << 2, 0x00},
+  	  { 0x002 << 2, 0x09}, //
+ 	  { 0x003 << 2, 0x00},
+ 	  { 0x004 << 2, 0x60}, //
+ 	  { 0x005 << 2, 0x09}, //
+ 	  { 0x006 << 2, 0x0e}, //
+ 	  { 0x007 << 2, 0x00},
+ 	  { 0x008 << 2, 0x00},
+ 	  { 0x009 << 2, 0x00},
+ 	  { 0x00A << 2, 0x00},
+ 	  { 0x00B << 2, 0x00},
+ 	  { 0x00C << 2, 0x00},
+ 	  { 0x00D << 2, 0x00},
+ 	  { 0x00E << 2, 0x00},
+ 	  { 0x00F << 2, 0x00},
+ 	  { 0x010 << 2, 0x00},
+ 	  { 0x011 << 2, 0x00},
+ 	  { 0x012 << 2, 0x00},
+ 	  { 0x013 << 2, 0x00},
+ 	  { 0x014 << 2, 0x00},
+ 	  { 0x015 << 2, 0x00},
+ 	  { 0x016 << 2, 0x00},
+ 	  { 0x017 << 2, 0x00},
+ 	  { 0x018 << 2, 0x00},
+ 	  { 0x019 << 2, 0x00},
+ 	  { 0x01A << 2, 0x00},
+ 	  { 0x01B << 2, 0x00},
+ 	  { 0x01C << 2, 0x00},
+ 	  { 0x01D << 2, 0x00},
+ 	  { 0x01E << 2, 0x00},
+ 	  { 0x01F << 2, 0x00},
+ 	  { 0x020 << 2, 0x00},
+ 	  { 0x021 << 2, 0x00},
+ 	  { 0x022 << 2, 0xa0},
+ 	  { 0x023 << 2, 0x6c}, //
+ 	  { 0x024 << 2, 0x00},
+ 	  { 0x025 << 2, 0x00},
+ 	  { 0x026 << 2, 0x00},
+ 	  { 0x027 << 2, 0x00},
+ 	  { 0x028 << 2, 0x00},
+ 	  { 0x029 << 2, 0x00},
+ 	  { 0x02A << 2, 0x00},
+ 	  { 0x02B << 2, 0x00},
+ 	  { 0x02C << 2, 0x00},
+ 	  { 0x02D << 2, 0x00},
+ 	  { 0x02E << 2, 0x04},
+ 	  { 0x02F << 2, 0x50},
+ 	  { 0x030 << 2, 0x70},
+ 	  { 0x031 << 2, 0x02},
+ 	  { 0x032 << 2, 0x25},
+ 	  { 0x033 << 2, 0x40},
+ 	  { 0x034 << 2, 0x01},
+ 	  { 0x035 << 2, 0x40},
+ 	  { 0x036 << 2, 0x00},
+ 	  { 0x037 << 2, 0x00},
+ 	  { 0x038 << 2, 0x00},
+ 	  { 0x039 << 2, 0x00},
+ 	  { 0x03A << 2, 0x00},
+ 	  { 0x03B << 2, 0x00},
+ 	  { 0x03C << 2, 0x00},
+ 	  { 0x03D << 2, 0x00},
+ 	  { 0x03E << 2, 0x00},
+ 	  { 0x03F << 2, 0x00},
+ 	  { 0x040 << 2, 0x00},
+ 	  { 0x041 << 2, 0x00},
+ 	  { 0x042 << 2, 0x00},
+ 	  { 0x043 << 2, 0x00},
+ 	  { 0x044 << 2, 0x00},
+ 	  { 0x045 << 2, 0x00},
+ 	  { 0x046 << 2, 0x00},
+ 	  { 0x047 << 2, 0x00},
+ 	  { 0x048 << 2, 0x00},
+ 	  { 0x049 << 2, 0x00},
+ 	  { 0x04A << 2, 0x00},
+ 	  { 0x04B << 2, 0x00},
+ 	  { 0x04C << 2, 0x00},
+ 	  { 0x04D << 2, 0x00},
+ 	  { 0x04E << 2, 0x00},
+ 	  { 0x04F << 2, 0x00},
+ 	  { 0x050 << 2, 0x00},
+ 	  { 0x051 << 2, 0x00},
+ 	  { 0x052 << 2, 0x00},
+ 	  { 0x053 << 2, 0x00},
+ 	  { 0x054 << 2, 0x00},
+ 	  { 0x055 << 2, 0x00},
+ 	  { 0x056 << 2, 0x00},
+ 	  { 0x057 << 2, 0x00},
+ 	  { 0x058 << 2, 0x00},
+ 	  { 0x059 << 2, 0x00},
+ 	  { 0x05A << 2, 0x00},
+ 	  { 0x05B << 2, 0x00},
+ 	  { 0x05C << 2, 0x00},
+ 	  { 0x05D << 2, 0x00},
+ 	  { 0x05E << 2, 0x00},
+ 	  { 0x05F << 2, 0x00},
+ 	  { 0x060 << 2, 0x00},
+ 	  { 0x061 << 2, 0x2e},
+ 	  { 0x062 << 2, 0x08}, //
+ 	  { 0x063 << 2, 0x5e},
+ 	  { 0x064 << 2, 0x00},
+ 	  { 0x065 << 2, 0x42},
+  	  { 0x066 << 2, 0xd1},
+ 	  { 0x067 << 2, 0x90}, //
+ 	  { 0x068 << 2, 0x08},
+ 	  { 0x069 << 2, 0x90}, //
+ 	  { 0x06A << 2, 0x2c}, //
+ 	  { 0x06B << 2, 0x32}, //
+ 	  { 0x06C << 2, 0x59}, //
+ 	  { 0x06D << 2, 0x03}, //
+ 	  { 0x06E << 2, 0x00},
+ 	  { 0x06F << 2, 0x00},
+  	  { 0x070 << 2, 0x00},
+ 	  { 0x071 << 2, 0x00},
+ 	  { 0x072 << 2, 0x00},
+  	  /* Lane0 Block */
+  	  { 0x200 << 2, 0x00},
+ 	  { 0x201 << 2, 0x00},
+ 	  { 0x202 << 2, 0x00},
+ 	  { 0x203 << 2, 0x00},
+ 	  { 0x204 << 2, 0x00},
+ 	  { 0x205 << 2, 0x10},
+ 	  { 0x206 << 2, 0x84},
+ 	  { 0x207 << 2, 0x04},
+ 	  { 0x208 << 2, 0xe0},
+ 	  { 0x210 << 2, 0x23},
+ 	  { 0x211 << 2, 0x00},
+ 	  { 0x212 << 2, 0x00},
+ 	  { 0x213 << 2, 0x04}, //
+ 	  { 0x214 << 2, 0xc0}, //
+ 	  { 0x215 << 2, 0x18}, //
+ 	  { 0x216 << 2, 0x00},
+ 	  { 0x217 << 2, 0x68},
+ 	  { 0x218 << 2, 0xa2},
+ 	  { 0x219 << 2, 0x1e},
+ 	  { 0x21A << 2, 0x18},
+ 	  { 0x21B << 2, 0x0d},
+ 	  { 0x21C << 2, 0x0d},
+ 	  { 0x21D << 2, 0x00},
+ 	  { 0x21E << 2, 0x00},
+ 	  { 0x21F << 2, 0x00},
+ 	  { 0x220 << 2, 0x00},
+ 	  { 0x221 << 2, 0x00},
+ 	  { 0x222 << 2, 0x00},
+ 	  { 0x223 << 2, 0x00},
+ 	  { 0x224 << 2, 0x00},
+ 	  { 0x225 << 2, 0x00},
+ 	  { 0x226 << 2, 0x00},
+ 	  { 0x227 << 2, 0x00},
+ 	  { 0x228 << 2, 0x00},
+ 	  { 0x229 << 2, 0x00},
+ 	  { 0x22A << 2, 0x00},
+ 	  { 0x22B << 2, 0x00},
+ 	  { 0x22C << 2, 0x00},
+ 	  { 0x22D << 2, 0x00},
+ 	  { 0x22E << 2, 0x00},
+ 	  { 0x22F << 2, 0x00},
+ 	  { 0x230 << 2, 0x00},
+ 	  { 0x231 << 2, 0x00},
+ 	  { 0x232 << 2, 0x00},
+ 	  { 0x233 << 2, 0x00},
+ 	  { 0x234 << 2, 0x00},
+ 	  { 0x235 << 2, 0x00},
+ 	  { 0x236 << 2, 0x00},
+ 	  { 0x237 << 2, 0x00},
+ 	  { 0x238 << 2, 0x00},
+ 	  { 0x239 << 2, 0x00},
+ 	  { 0x23A << 2, 0x00},
+ 	  { 0x23B << 2, 0x00},
+ 	  { 0x23C << 2, 0x00},
+ 	  { 0x23D << 2, 0x00},
+ 	  { 0x23E << 2, 0x00},
+ 	  { 0x23F << 2, 0x00},
+ 	  { 0x240 << 2, 0x00},
+ 	  { 0x241 << 2, 0x00},
+ 	  { 0x242 << 2, 0x00},
+ 	  { 0x243 << 2, 0x00},
+ 	  { 0x244 << 2, 0x00},
+ 	  { 0x245 << 2, 0x00},
+ 	  { 0x246 << 2, 0x00},
+ 	  { 0x247 << 2, 0x00},
+ 	  { 0x248 << 2, 0x00},
+ 	  { 0x249 << 2, 0x00},
+ 	  { 0x24A << 2, 0x00},
+ 	  { 0x24B << 2, 0x00},
+ 	  { 0x24C << 2, 0x00},
+ 	  { 0x24D << 2, 0x00},
+ 	  { 0x24E << 2, 0x00},
+ 	  { 0x24F << 2, 0x00},
+ 	  { 0x250 << 2, 0x60},
+ 	  { 0x251 << 2, 0x0f},
+	  /* Common Lane Block */
+ 	  { 0xA00 << 2, 0xc0},
+ 	  { 0xA01 << 2, 0x90},
+ 	  { 0xA02 << 2, 0x02},
+ 	  { 0xA03 << 2, 0x40},
+ 	  { 0xA04 << 2, 0x3c},
+ 	  { 0xA05 << 2, 0x00},
+ 	  { 0xA06 << 2, 0x00},
+ 	  { 0xA07 << 2, 0x00},
+ 	  { 0xA08 << 2, 0x00},
+ 	  { 0xA09 << 2, 0xc3}, //
+ 	  { 0xA0A << 2, 0xca}, //
+ 	  { 0xA0B << 2, 0xc6},
+ 	  { 0xA0C << 2, 0x01},
+ 	  { 0xA0D << 2, 0x03},
+ 	  { 0xA0E << 2, 0x28},
+ 	  { 0xA0F << 2, 0x98},
+ 	  { 0xA10 << 2, 0x19},
+ 	  { 0xA11 << 2, 0x28},
+ 	  { 0xA12 << 2, 0x78},
+ 	  { 0xA13 << 2, 0xe1},
+ 	  { 0xA14 << 2, 0xf0},
+ 	  { 0xA15 << 2, 0x10},
+ 	  { 0xA16 << 2, 0xf4},
+ 	  { 0xA17 << 2, 0x00},
+  	  { 0xA30 << 2, 0x00},
+ 	  { 0xA31 << 2, 0x00},
+ 	  { 0xA32 << 2, 0x00},
+ 	  { 0xA33 << 2, 0x00},
+ 	  { 0xA34 << 2, 0x00},
+ 	  { 0xA35 << 2, 0x00},
+ 	  { 0xA36 << 2, 0x00},
+ 	  { 0xA37 << 2, 0x00},
+ 	  { 0xA38 << 2, 0x00},
+ 	  { 0xA39 << 2, 0xa0},
+ 	  { 0xA3A << 2, 0xa0},
+ 	  { 0xA3B << 2, 0xa0},
+ 	  { 0xA3C << 2, 0xa0},
+ 	  { 0xA3D << 2, 0xa0},
+ 	  { 0xA3E << 2, 0xa0},
+ 	  { 0xA3F << 2, 0xa0},
+ 	  { 0xA40 << 2, 0x6c}, //
+ 	  { 0xA41 << 2, 0x00},
+ 	  { 0xA42 << 2, 0xc0},
+ 	  { 0xA43 << 2, 0x9f},
+ 	  { 0xA44 << 2, 0x01},
+ 	  { 0xA45 << 2, 0x00},
+ 	  { 0xA46 << 2, 0x00},
+ 	  { 0xA47 << 2, 0x00},
+ 	  { 0xA48 << 2, 0x00},
+ 	  { 0xA49 << 2, 0x00},
+ 	  { 0xA4A << 2, 0x00},
+ 	  { 0xA4B << 2, 0x00},
+ 	  { 0xA4C << 2, 0x30},
+ 	  { 0xA4D << 2, 0x41},
+ 	  { 0xA4E << 2, 0x7e},
+ 	  { 0xA4F << 2, 0xd0},
+ 	  { 0xA50 << 2, 0xcc},
+ 	  { 0xA51 << 2, 0x85},
+ 	  { 0xA52 << 2, 0x52},
+ 	  { 0xA53 << 2, 0x93},
+ 	  { 0xA54 << 2, 0xe0},
+ 	  { 0xA55 << 2, 0x49},
+ 	  { 0xA56 << 2, 0xdd},
+ 	  { 0xA57 << 2, 0xb0},
+ 	  { 0xA58 << 2, 0x0b},
+ 	  { 0xA59 << 2, 0x02},
+ 	  { 0xA5A << 2, 0x00},
+ 	  { 0xA5B << 2, 0x00},
+ 	  { 0xA5C << 2, 0x00},
+ 	  { 0xA5D << 2, 0x00},
+ 	  { 0xA5E << 2, 0x00},
+ 	  { 0xA5F << 2, 0x00},
+ 	  { 0xA60 << 2, 0x00},
+ 	  { 0xA61 << 2, 0x00},
+  	  { 0xA62 << 2, 0x00},
+ 	  { 0xA63 << 2, 0x00},
+ 	  { 0xA64 << 2, 0x00},
+ 	  { 0xA65 << 2, 0x00},
+ 	  { 0xA66 << 2, 0x00},
+ 	  { 0xA67 << 2, 0x00},
+ 	  { 0xA68 << 2, 0x00},
+ 	  { 0xA69 << 2, 0x00},
+ 	  { 0xA6A << 2, 0x00},
+ 	  { 0xA6B << 2, 0x00},
+ 	  { 0xA6C << 2, 0x00},
+ 	  { 0xA6D << 2, 0x00},
+ 	  { 0xA6E << 2, 0x00},
+ 	  { 0xA6F << 2, 0x00},
+ 	  { 0xA70 << 2, 0x00},
+ 	  { 0xA71 << 2, 0x00},
+ 	  { 0xA72 << 2, 0x00},
+ 	  { 0xA73 << 2, 0x00},
+ 	  { 0xA74 << 2, 0x00},
+ 	  { 0xA75 << 2, 0x00},
+ 	  { 0xA76 << 2, 0x00},
+ 	  { 0xA77 << 2, 0x00},
+ 	  { 0xA78 << 2, 0x00},
+ 	  { 0xA79 << 2, 0x00},
+ 	  { 0xA7A << 2, 0x00},
+ 	  { 0xA7B << 2, 0x00},
+ 	  { 0xA7C << 2, 0x00},
+ 	  { 0xA7D << 2, 0x00},
+ 	  { 0xA7E << 2, 0x00},
+ 	  { 0xA7F << 2, 0xd8},
+ 	  { 0xA80 << 2, 0x1a},
+ 	  { 0xA81 << 2, 0xff},
+ 	  { 0xA82 << 2, 0x01},
+ 	  { 0xA83 << 2, 0x00},
+ 	  { 0xA84 << 2, 0x00},
+ 	  { 0xA85 << 2, 0x00},
+ 	  { 0xA86 << 2, 0x00},
+ 	  { 0xA87 << 2, 0xf0},
+ 	  { 0xA88 << 2, 0xff},
+ 	  { 0xA89 << 2, 0xff},
+ 	  { 0xA8A << 2, 0xff},
+ 	  { 0xA8B << 2, 0xff},
+ 	  { 0xA8C << 2, 0x1c},
+ 	  { 0xA8D << 2, 0xc2},
+ 	  { 0xA8E << 2, 0xc3},
+ 	  { 0xA8F << 2, 0x3f},
+ 	  { 0xA90 << 2, 0x0a},
+ 	  { 0xA91 << 2, 0x00},
+ 	  { 0xA92 << 2, 0x00},
+ 	  { 0xA93 << 2, 0x00},
+  	  { 0xA94 << 2, 0x00},
+ 	  { 0xA95 << 2, 0x00},
+ 	  { 0xA96 << 2, 0xf8},
+   	  { 0x000 << 2, 0x07}
+	};
+
+static struct serdes_regs_s pcie_phy_reg_file_100[] =
+        {
+          /* Common CMU block */
+         { 0x000 << 2, 0x06},
+          { 0x001 << 2, 0x00},
+          { 0x002 << 2, 0x09}, //
+          { 0x003 << 2, 0x00},
+          { 0x004 << 2, 0x00}, 
+          { 0x005 << 2, 0x00}, 
+          { 0x006 << 2, 0x00},
+          { 0x007 << 2, 0x00},
+          { 0x008 << 2, 0x00},
+          { 0x009 << 2, 0x00},
+          { 0x00A << 2, 0x00},
+          { 0x00B << 2, 0x00},
+          { 0x00C << 2, 0x00},
+          { 0x00D << 2, 0x00},
+          { 0x00E << 2, 0x00},
+          { 0x00F << 2, 0x00},
+          { 0x010 << 2, 0x00},
+          { 0x011 << 2, 0x00},
+          { 0x012 << 2, 0x00},
+          { 0x013 << 2, 0x00},
+          { 0x014 << 2, 0x00},
+          { 0x015 << 2, 0x00},
+          { 0x016 << 2, 0x00},
+          { 0x017 << 2, 0x00},
+          { 0x018 << 2, 0x00},
+          { 0x019 << 2, 0x00},
+          { 0x01A << 2, 0x00},
+          { 0x01B << 2, 0x00},
+          { 0x01C << 2, 0x00},
+          { 0x01D << 2, 0x00},
+          { 0x01E << 2, 0x00},
+          { 0x01F << 2, 0x00},
+          { 0x020 << 2, 0x00},
+          { 0x021 << 2, 0x00},
+          { 0x022 << 2, 0xa0},
+          { 0x023 << 2, 0x64}, 
+          { 0x024 << 2, 0x00},
+          { 0x025 << 2, 0x00},
+          { 0x026 << 2, 0x00},
+          { 0x027 << 2, 0x00},
+          { 0x028 << 2, 0x00},
+          { 0x029 << 2, 0x00},
+          { 0x02A << 2, 0x00},
+          { 0x02B << 2, 0x00},
+          { 0x02C << 2, 0x00},
+          { 0x02D << 2, 0x00},
+          { 0x02E << 2, 0x04},
+          { 0x02F << 2, 0x50},
+          { 0x030 << 2, 0x70},
+          { 0x031 << 2, 0x02},
+          { 0x032 << 2, 0x25},
+          { 0x033 << 2, 0x40},
+          { 0x034 << 2, 0x01},
+          { 0x035 << 2, 0x40},
+          { 0x036 << 2, 0x00},
+          { 0x037 << 2, 0x00},
+          { 0x038 << 2, 0x00},
+          { 0x039 << 2, 0x00},
+          { 0x03A << 2, 0x00},
+          { 0x03B << 2, 0x00},
+          { 0x03C << 2, 0x00},
+          { 0x03D << 2, 0x00},
+          { 0x03E << 2, 0x00},
+          { 0x03F << 2, 0x00},
+          { 0x040 << 2, 0x00},
+          { 0x041 << 2, 0x00},
+          { 0x042 << 2, 0x00},
+          { 0x043 << 2, 0x00},
+          { 0x044 << 2, 0x00},
+          { 0x045 << 2, 0x00},
+          { 0x046 << 2, 0x00},
+          { 0x047 << 2, 0x00},
+          { 0x048 << 2, 0x00},
+          { 0x049 << 2, 0x00},
+          { 0x04A << 2, 0x00},
+          { 0x04B << 2, 0x00},
+          { 0x04C << 2, 0x00},
+          { 0x04D << 2, 0x00},
+          { 0x04E << 2, 0x00},
+          { 0x04F << 2, 0x00},
+          { 0x050 << 2, 0x00},
+          { 0x051 << 2, 0x00},
+          { 0x052 << 2, 0x00},
+          { 0x053 << 2, 0x00},
+          { 0x054 << 2, 0x00},
+          { 0x055 << 2, 0x00},
+          { 0x056 << 2, 0x00},
+          { 0x057 << 2, 0x00},
+          { 0x058 << 2, 0x00},
+          { 0x059 << 2, 0x00},
+          { 0x05A << 2, 0x00},
+          { 0x05B << 2, 0x00},
+          { 0x05C << 2, 0x00},
+          { 0x05D << 2, 0x00},
+          { 0x05E << 2, 0x00},
+          { 0x05F << 2, 0x00},
+          { 0x060 << 2, 0x00},
+          { 0x061 << 2, 0x2e},//for Rev1 modified in code
+          { 0x062 << 2, 0x00}, 
+          { 0x063 << 2, 0x5e},
+          { 0x064 << 2, 0x00},
+          { 0x065 << 2, 0x42},
+          { 0x066 << 2, 0xd1},
+          { 0x067 << 2, 0x90}, 
+          { 0x068 << 2, 0x08},
+          { 0x069 << 2, 0x50}, 
+          { 0x06A << 2, 0x44}, 
+          { 0x06B << 2, 0xce}, 
+          { 0x06C << 2, 0x0b}, 
+          { 0x06D << 2, 0x00},
+          { 0x06E << 2, 0x00},
+          { 0x06F << 2, 0x00},
+          { 0x070 << 2, 0x00},
+          { 0x071 << 2, 0x00},
+          { 0x072 << 2, 0x00},
+          /* Lane0 Block */
+          { 0x200 << 2, 0x00},
+          { 0x201 << 2, 0x00},
+          { 0x202 << 2, 0x00},
+          { 0x203 << 2, 0x00},
+          { 0x204 << 2, 0x00},
+          { 0x205 << 2, 0x10},
+          { 0x206 << 2, 0x04},
+          { 0x207 << 2, 0x18},
+          { 0x208 << 2, 0xe0},
+          { 0x210 << 2, 0x23},
+          { 0x211 << 2, 0x00},
+          { 0x212 << 2, 0x00},
+          { 0x213 << 2, 0x03}, 
+          { 0x214 << 2, 0x3C}, 
+          { 0x215 << 2, 0x04}, 
+          { 0x216 << 2, 0x00},
+          { 0x217 << 2, 0x68},
+          { 0x218 << 2, 0xa2},
+          { 0x219 << 2, 0x1e},
+          { 0x21A << 2, 0x18},
+          { 0x21B << 2, 0x0d},
+          { 0x21C << 2, 0x0d},
+          { 0x21D << 2, 0x00},
+          { 0x21E << 2, 0x00},
+          { 0x21F << 2, 0x00},
+          { 0x220 << 2, 0x00},
+          { 0x221 << 2, 0x00},
+          { 0x222 << 2, 0x00},
+          { 0x223 << 2, 0x00},
+          { 0x224 << 2, 0x00},
+          { 0x225 << 2, 0x00},
+          { 0x226 << 2, 0x00},
+          { 0x227 << 2, 0x00},
+          { 0x228 << 2, 0x00},
+          { 0x229 << 2, 0x00},
+          { 0x22A << 2, 0x00},
+          { 0x22B << 2, 0x00},
+          { 0x22C << 2, 0x00},
+          { 0x22D << 2, 0x00},
+          { 0x22E << 2, 0x00},
+          { 0x22F << 2, 0x00},
+          { 0x230 << 2, 0x00},
+          { 0x231 << 2, 0x00},
+          { 0x232 << 2, 0x00},
+          { 0x233 << 2, 0x00},
+          { 0x234 << 2, 0x00},
+          { 0x235 << 2, 0x00},
+          { 0x236 << 2, 0x00},
+          { 0x237 << 2, 0x00},
+          { 0x238 << 2, 0x00},
+          { 0x239 << 2, 0x00},
+          { 0x23A << 2, 0x00},
+          { 0x23B << 2, 0x00},
+          { 0x23C << 2, 0x00},
+          { 0x23D << 2, 0x00},
+          { 0x23E << 2, 0x00},
+          { 0x23F << 2, 0x00},
+          { 0x240 << 2, 0x00},
+          { 0x241 << 2, 0x00},
+          { 0x242 << 2, 0x00},
+          { 0x243 << 2, 0x00},
+          { 0x244 << 2, 0x00},
+          { 0x245 << 2, 0x00},
+          { 0x246 << 2, 0x00},
+          { 0x247 << 2, 0x00},
+          { 0x248 << 2, 0x00},
+          { 0x249 << 2, 0x00},
+          { 0x24A << 2, 0x00},
+          { 0x24B << 2, 0x00},
+          { 0x24C << 2, 0x00},
+          { 0x24D << 2, 0x00},
+          { 0x24E << 2, 0x00},
+          { 0x24F << 2, 0x00},
+          { 0x250 << 2, 0xf6},
+          { 0x251 << 2, 0x03},
+          /* Common Lane Block */
+          { 0xA00 << 2, 0xc0},
+          { 0xA01 << 2, 0x90},
+          { 0xA02 << 2, 0x02},
+          { 0xA03 << 2, 0x40},
+          { 0xA04 << 2, 0x3c},
+          { 0xA05 << 2, 0x00},
+          { 0xA06 << 2, 0x00},
+          { 0xA07 << 2, 0x00},
+          { 0xA08 << 2, 0x00},
+          { 0xA09 << 2, 0x63}, //
+          { 0xA0A << 2, 0x49}, //
+          { 0xA0B << 2, 0xc6},
+          { 0xA0C << 2, 0x01},
+          { 0xA0D << 2, 0x03},
+          { 0xA0E << 2, 0x28},
+          { 0xA0F << 2, 0x98},
+          { 0xA10 << 2, 0x19},
+          { 0xA11 << 2, 0x28},
+          { 0xA12 << 2, 0x78},
+          { 0xA13 << 2, 0xe1},
+          { 0xA14 << 2, 0xf0},
+          { 0xA15 << 2, 0x10},
+          { 0xA16 << 2, 0xf4},
+          { 0xA17 << 2, 0x00},
+          { 0xA30 << 2, 0x00},
+          { 0xA31 << 2, 0x00},
+          { 0xA32 << 2, 0x00},
+          { 0xA33 << 2, 0x00},
+          { 0xA34 << 2, 0x00},
+          { 0xA35 << 2, 0x00},
+          { 0xA36 << 2, 0x00},
+          { 0xA37 << 2, 0x00},
+          { 0xA38 << 2, 0x00},
+          { 0xA39 << 2, 0xa0},
+          { 0xA3A << 2, 0xa0},
+          { 0xA3B << 2, 0xa0},
+          { 0xA3C << 2, 0xa0},
+          { 0xA3D << 2, 0xa0},
+          { 0xA3E << 2, 0xa0},
+          { 0xA3F << 2, 0xa0},
+          { 0xA40 << 2, 0x64},
+          { 0xA41 << 2, 0x00},
+          { 0xA42 << 2, 0xc0},
+          { 0xA43 << 2, 0x9f},
+          { 0xA44 << 2, 0x01},
+          { 0xA45 << 2, 0x00},
+          { 0xA46 << 2, 0x00},
+          { 0xA47 << 2, 0x00},
+          { 0xA48 << 2, 0x00},
+          { 0xA49 << 2, 0x00},
+          { 0xA4A << 2, 0x00},
+          { 0xA4B << 2, 0x00},
+          { 0xA4C << 2, 0x30},
+          { 0xA4D << 2, 0x41},
+          { 0xA4E << 2, 0x7e},
+          { 0xA4F << 2, 0xd0},
+          { 0xA50 << 2, 0xcc},
+          { 0xA51 << 2, 0x85},
+          { 0xA52 << 2, 0x52},
+          { 0xA53 << 2, 0x93},
+          { 0xA54 << 2, 0xe0},
+          { 0xA55 << 2, 0x49},
+          { 0xA56 << 2, 0xdd},
+          { 0xA57 << 2, 0xb0},
+          { 0xA58 << 2, 0x0b},
+          { 0xA59 << 2, 0x02},
+          { 0xA5A << 2, 0x00},
+          { 0xA5B << 2, 0x00},
+          { 0xA5C << 2, 0x00},
+          { 0xA5D << 2, 0x00},
+          { 0xA5E << 2, 0x00},
+          { 0xA5F << 2, 0x00},
+          { 0xA60 << 2, 0x00},
+          { 0xA61 << 2, 0x00},
+          { 0xA62 << 2, 0x00},
+          { 0xA63 << 2, 0x00},
+          { 0xA64 << 2, 0x00},
+          { 0xA65 << 2, 0x00},
+          { 0xA66 << 2, 0x00},
+          { 0xA67 << 2, 0x00},
+          { 0xA68 << 2, 0x00},
+          { 0xA69 << 2, 0x00},
+          { 0xA6A << 2, 0x00},
+          { 0xA6B << 2, 0x00},
+          { 0xA6C << 2, 0x00},
+          { 0xA6D << 2, 0x00},
+          { 0xA6E << 2, 0x00},
+          { 0xA6F << 2, 0x00},
+          { 0xA70 << 2, 0x00},
+          { 0xA71 << 2, 0x00},
+          { 0xA72 << 2, 0x00},
+          { 0xA73 << 2, 0x00},
+          { 0xA74 << 2, 0x00},
+          { 0xA75 << 2, 0x00},
+          { 0xA76 << 2, 0x00},
+          { 0xA77 << 2, 0x00},
+          { 0xA78 << 2, 0x00},
+          { 0xA79 << 2, 0x00},
+          { 0xA7A << 2, 0x00},
+          { 0xA7B << 2, 0x00},
+          { 0xA7C << 2, 0x00},
+          { 0xA7D << 2, 0x00},
+          { 0xA7E << 2, 0x00},
+          { 0xA7F << 2, 0xd8},
+          { 0xA80 << 2, 0x1a},
+          { 0xA81 << 2, 0xff},
+          { 0xA82 << 2, 0x01},
+          { 0xA83 << 2, 0x00},
+          { 0xA84 << 2, 0x00},
+          { 0xA85 << 2, 0x00},
+          { 0xA86 << 2, 0x00},
+          { 0xA87 << 2, 0xf0},
+          { 0xA88 << 2, 0xff},
+          { 0xA89 << 2, 0xff},
+          { 0xA8A << 2, 0xff},
+          { 0xA8B << 2, 0xff},
+          { 0xA8C << 2, 0x1c},
+          { 0xA8D << 2, 0xc2},
+          { 0xA8E << 2, 0xc3},
+          { 0xA8F << 2, 0x3f},
+          { 0xA90 << 2, 0x0a},
+          { 0xA91 << 2, 0x00},
+          { 0xA92 << 2, 0x00},
+          { 0xA93 << 2, 0x00},
+          { 0xA94 << 2, 0x00},
+          { 0xA95 << 2, 0x00},
+          { 0xA96 << 2, 0xf8},
+   	  { 0x000 << 2, 0x07}
+        };
+
+
+static struct serdes_regs_s pcie_phy_reg_file_24[] =
+/* PCIe SERDES is using internal clock */
+  	{
+	  /* Common CMU block */
+  	  { 0x000 << 2, 0x06},
+  	  { 0x001 << 2, 0x00},
+  	  { 0x002 << 2, 0x09}, //
+ 	  { 0x003 << 2, 0x00},
+ 	  { 0x004 << 2, 0x60}, //
+ 	  { 0x005 << 2, 0x09}, //
+ 	  { 0x006 << 2, 0x0e}, //
+ 	  { 0x007 << 2, 0x00},
+ 	  { 0x008 << 2, 0x00},
+ 	  { 0x009 << 2, 0x00},
+ 	  { 0x00A << 2, 0x00},
+ 	  { 0x00B << 2, 0x00},
+ 	  { 0x00C << 2, 0x00},
+ 	  { 0x00D << 2, 0x00},
+ 	  { 0x00E << 2, 0x00},
+ 	  { 0x00F << 2, 0x00},
+ 	  { 0x010 << 2, 0x00},
+ 	  { 0x011 << 2, 0x00},
+ 	  { 0x012 << 2, 0x00},
+ 	  { 0x013 << 2, 0x00},
+ 	  { 0x014 << 2, 0x00},
+ 	  { 0x015 << 2, 0x00},
+ 	  { 0x016 << 2, 0x00},
+ 	  { 0x017 << 2, 0x00},
+ 	  { 0x018 << 2, 0x00},
+ 	  { 0x019 << 2, 0x00},
+ 	  { 0x01A << 2, 0x00},
+ 	  { 0x01B << 2, 0x00},
+ 	  { 0x01C << 2, 0x00},
+ 	  { 0x01D << 2, 0x00},
+ 	  { 0x01E << 2, 0x00},
+ 	  { 0x01F << 2, 0x00},
+ 	  { 0x020 << 2, 0x00},
+ 	  { 0x021 << 2, 0x00},
+ 	  { 0x022 << 2, 0xa0},
+ 	  { 0x023 << 2, 0x68}, //
+ 	  { 0x024 << 2, 0x00},
+ 	  { 0x025 << 2, 0x00},
+ 	  { 0x026 << 2, 0x00},
+ 	  { 0x027 << 2, 0x00},
+ 	  { 0x028 << 2, 0x00},
+ 	  { 0x029 << 2, 0x00},
+ 	  { 0x02A << 2, 0x00},
+ 	  { 0x02B << 2, 0x00},
+ 	  { 0x02C << 2, 0x00},
+ 	  { 0x02D << 2, 0x00},
+ 	  { 0x02E << 2, 0x04},
+ 	  { 0x02F << 2, 0x50},
+ 	  { 0x030 << 2, 0x70},
+ 	  { 0x031 << 2, 0x02},
+ 	  { 0x032 << 2, 0x25},
+ 	  { 0x033 << 2, 0x40},
+ 	  { 0x034 << 2, 0x01},
+ 	  { 0x035 << 2, 0x40},
+ 	  { 0x036 << 2, 0x00},
+ 	  { 0x037 << 2, 0x00},
+ 	  { 0x038 << 2, 0x00},
+ 	  { 0x039 << 2, 0x00},
+ 	  { 0x03A << 2, 0x00},
+ 	  { 0x03B << 2, 0x00},
+ 	  { 0x03C << 2, 0x00},
+ 	  { 0x03D << 2, 0x00},
+ 	  { 0x03E << 2, 0x00},
+ 	  { 0x03F << 2, 0x00},
+ 	  { 0x040 << 2, 0x00},
+ 	  { 0x041 << 2, 0x00},
+ 	  { 0x042 << 2, 0x00},
+ 	  { 0x043 << 2, 0x00},
+ 	  { 0x044 << 2, 0x00},
+ 	  { 0x045 << 2, 0x00},
+ 	  { 0x046 << 2, 0x00},
+ 	  { 0x047 << 2, 0x00},
+ 	  { 0x048 << 2, 0x00},
+ 	  { 0x049 << 2, 0x00},
+ 	  { 0x04A << 2, 0x00},
+ 	  { 0x04B << 2, 0x00},
+ 	  { 0x04C << 2, 0x00},
+ 	  { 0x04D << 2, 0x00},
+ 	  { 0x04E << 2, 0x00},
+ 	  { 0x04F << 2, 0x00},
+ 	  { 0x050 << 2, 0x00},
+ 	  { 0x051 << 2, 0x00},
+ 	  { 0x052 << 2, 0x00},
+ 	  { 0x053 << 2, 0x00},
+ 	  { 0x054 << 2, 0x00},
+ 	  { 0x055 << 2, 0x00},
+ 	  { 0x056 << 2, 0x00},
+ 	  { 0x057 << 2, 0x00},
+ 	  { 0x058 << 2, 0x00},
+ 	  { 0x059 << 2, 0x00},
+ 	  { 0x05A << 2, 0x00},
+ 	  { 0x05B << 2, 0x00},
+ 	  { 0x05C << 2, 0x00},
+ 	  { 0x05D << 2, 0x00},
+ 	  { 0x05E << 2, 0x00},
+ 	  { 0x05F << 2, 0x00},
+ 	  { 0x060 << 2, 0x00},
+ 	  { 0x061 << 2, 0x2e}, //for Rev-A0 device
+ 	  { 0x062 << 2, 0x00}, //
+ 	  { 0x063 << 2, 0x5e},
+ 	  { 0x064 << 2, 0x00},
+ 	  { 0x065 << 2, 0x42},
+  	  { 0x066 << 2, 0x91},
+ 	  { 0x067 << 2, 0x10}, //
+ 	  { 0x068 << 2, 0x48},
+ 	  { 0x069 << 2, 0x90}, //
+ 	  { 0x06A << 2, 0x0c}, //
+ 	  { 0x06B << 2, 0x4c}, //
+ 	  { 0x06C << 2, 0x73}, //
+ 	  { 0x06D << 2, 0x03}, //
+ 	  { 0x06E << 2, 0x00},
+ 	  { 0x06F << 2, 0x00},
+  	  { 0x070 << 2, 0x00},
+ 	  { 0x071 << 2, 0x00},
+ 	  { 0x072 << 2, 0x00},
+  	  /* Lane0 Block */
+  	  { 0x200 << 2, 0x00},
+ 	  { 0x201 << 2, 0x00},
+ 	  { 0x202 << 2, 0x00},
+ 	  { 0x203 << 2, 0x00},
+ 	  { 0x204 << 2, 0x00},
+ 	  { 0x205 << 2, 0x10},
+ 	  { 0x206 << 2, 0x04},
+ 	  { 0x207 << 2, 0x18},
+ 	  { 0x208 << 2, 0xe0},
+ 	  { 0x210 << 2, 0x23},
+ 	  { 0x211 << 2, 0x00},
+ 	  { 0x212 << 2, 0x00},
+ 	  { 0x213 << 2, 0x04}, //
+ 	  { 0x214 << 2, 0x38}, //
+ 	  { 0x215 << 2, 0x10}, //
+ 	  { 0x216 << 2, 0x00},
+ 	  { 0x217 << 2, 0x68},
+ 	  { 0x218 << 2, 0xa2},
+ 	  { 0x219 << 2, 0x1e},
+ 	  { 0x21A << 2, 0x18},
+ 	  { 0x21B << 2, 0x0d},
+ 	  { 0x21C << 2, 0x0c},
+ 	  { 0x21D << 2, 0x00},
+ 	  { 0x21E << 2, 0x00},
+ 	  { 0x21F << 2, 0x00},
+ 	  { 0x220 << 2, 0x00},
+ 	  { 0x221 << 2, 0x00},
+ 	  { 0x222 << 2, 0x00},
+ 	  { 0x223 << 2, 0x00},
+ 	  { 0x224 << 2, 0x00},
+ 	  { 0x225 << 2, 0x00},
+ 	  { 0x226 << 2, 0x00},
+ 	  { 0x227 << 2, 0x00},
+ 	  { 0x228 << 2, 0x00},
+ 	  { 0x229 << 2, 0x00},
+ 	  { 0x22A << 2, 0x00},
+ 	  { 0x22B << 2, 0x00},
+ 	  { 0x22C << 2, 0x00},
+ 	  { 0x22D << 2, 0x00},
+ 	  { 0x22E << 2, 0x00},
+ 	  { 0x22F << 2, 0x00},
+ 	  { 0x230 << 2, 0x00},
+ 	  { 0x231 << 2, 0x00},
+ 	  { 0x232 << 2, 0x00},
+ 	  { 0x233 << 2, 0x00},
+ 	  { 0x234 << 2, 0x00},
+ 	  { 0x235 << 2, 0x00},
+ 	  { 0x236 << 2, 0x00},
+ 	  { 0x237 << 2, 0x00},
+ 	  { 0x238 << 2, 0x00},
+ 	  { 0x239 << 2, 0x00},
+ 	  { 0x23A << 2, 0x00},
+ 	  { 0x23B << 2, 0x00},
+ 	  { 0x23C << 2, 0x00},
+ 	  { 0x23D << 2, 0x00},
+ 	  { 0x23E << 2, 0x00},
+ 	  { 0x23F << 2, 0x00},
+ 	  { 0x240 << 2, 0x00},
+ 	  { 0x241 << 2, 0x00},
+ 	  { 0x242 << 2, 0x00},
+ 	  { 0x243 << 2, 0x00},
+ 	  { 0x244 << 2, 0x00},
+ 	  { 0x245 << 2, 0x00},
+ 	  { 0x246 << 2, 0x00},
+ 	  { 0x247 << 2, 0x00},
+ 	  { 0x248 << 2, 0x00},
+ 	  { 0x249 << 2, 0x00},
+ 	  { 0x24A << 2, 0x00},
+ 	  { 0x24B << 2, 0x00},
+ 	  { 0x24C << 2, 0x00},
+ 	  { 0x24D << 2, 0x00},
+ 	  { 0x24E << 2, 0x00},
+ 	  { 0x24F << 2, 0x00},
+ 	  { 0x250 << 2, 0xf6},
+ 	  { 0x251 << 2, 0x03},
+	  /* Common Lane Block */
+ 	  { 0xA00 << 2, 0xc0},
+ 	  { 0xA01 << 2, 0x90},
+ 	  { 0xA02 << 2, 0x02},
+ 	  { 0xA03 << 2, 0x40},
+ 	  { 0xA04 << 2, 0x3c},
+ 	  { 0xA05 << 2, 0x00},
+ 	  { 0xA06 << 2, 0x00},
+ 	  { 0xA07 << 2, 0x00},
+ 	  { 0xA08 << 2, 0x00},
+ 	  { 0xA09 << 2, 0x83}, //
+ 	  { 0xA0A << 2, 0x8b}, //
+ 	  { 0xA0B << 2, 0xc6},
+ 	  { 0xA0C << 2, 0x01},
+ 	  { 0xA0D << 2, 0x03},
+ 	  { 0xA0E << 2, 0x28},
+ 	  { 0xA0F << 2, 0x98},
+ 	  { 0xA10 << 2, 0x19},
+ 	  { 0xA11 << 2, 0x28},
+ 	  { 0xA12 << 2, 0x78},
+ 	  { 0xA13 << 2, 0xe1},
+ 	  { 0xA14 << 2, 0xf0},
+ 	  { 0xA15 << 2, 0x10},
+ 	  { 0xA16 << 2, 0xf4},
+ 	  { 0xA17 << 2, 0x00},
+  	  { 0xA30 << 2, 0x00},
+ 	  { 0xA31 << 2, 0x00},
+ 	  { 0xA32 << 2, 0x00},
+ 	  { 0xA33 << 2, 0x00},
+ 	  { 0xA34 << 2, 0x00},
+ 	  { 0xA35 << 2, 0x00},
+ 	  { 0xA36 << 2, 0x00},
+ 	  { 0xA37 << 2, 0x00},
+ 	  { 0xA38 << 2, 0x00},
+ 	  { 0xA39 << 2, 0xa0},
+ 	  { 0xA3A << 2, 0xa0},
+ 	  { 0xA3B << 2, 0xa0},
+ 	  { 0xA3C << 2, 0xa0},
+ 	  { 0xA3D << 2, 0xa0},
+ 	  { 0xA3E << 2, 0xa0},
+ 	  { 0xA3F << 2, 0xa0},
+ 	  { 0xA40 << 2, 0x68}, //
+ 	  { 0xA41 << 2, 0x00},
+ 	  { 0xA42 << 2, 0xc0},
+ 	  { 0xA43 << 2, 0x9f},
+ 	  { 0xA44 << 2, 0x01},
+ 	  { 0xA45 << 2, 0x00},
+ 	  { 0xA46 << 2, 0x00},
+ 	  { 0xA47 << 2, 0x00},
+ 	  { 0xA48 << 2, 0x00},
+ 	  { 0xA49 << 2, 0x00},
+ 	  { 0xA4A << 2, 0x00},
+ 	  { 0xA4B << 2, 0x00},
+ 	  { 0xA4C << 2, 0x30},
+ 	  { 0xA4D << 2, 0x41},
+ 	  { 0xA4E << 2, 0x7e},
+ 	  { 0xA4F << 2, 0xd0},
+ 	  { 0xA50 << 2, 0xcc},
+ 	  { 0xA51 << 2, 0x85},
+ 	  { 0xA52 << 2, 0x52},
+ 	  { 0xA53 << 2, 0x93},
+ 	  { 0xA54 << 2, 0xe0},
+ 	  { 0xA55 << 2, 0x49},
+ 	  { 0xA56 << 2, 0xdd},
+ 	  { 0xA57 << 2, 0xb0},
+ 	  { 0xA58 << 2, 0x0b},
+ 	  { 0xA59 << 2, 0x02},
+ 	  { 0xA5A << 2, 0x00},
+ 	  { 0xA5B << 2, 0x00},
+ 	  { 0xA5C << 2, 0x00},
+ 	  { 0xA5D << 2, 0x00},
+ 	  { 0xA5E << 2, 0x00},
+ 	  { 0xA5F << 2, 0x00},
+ 	  { 0xA60 << 2, 0x00},
+ 	  { 0xA61 << 2, 0x00},
+  	  { 0xA62 << 2, 0x00},
+ 	  { 0xA63 << 2, 0x00},
+ 	  { 0xA64 << 2, 0x00},
+ 	  { 0xA65 << 2, 0x00},
+ 	  { 0xA66 << 2, 0x00},
+ 	  { 0xA67 << 2, 0x00},
+ 	  { 0xA68 << 2, 0x00},
+ 	  { 0xA69 << 2, 0x00},
+ 	  { 0xA6A << 2, 0x00},
+ 	  { 0xA6B << 2, 0x00},
+ 	  { 0xA6C << 2, 0x00},
+ 	  { 0xA6D << 2, 0x00},
+ 	  { 0xA6E << 2, 0x00},
+ 	  { 0xA6F << 2, 0x00},
+ 	  { 0xA70 << 2, 0x00},
+ 	  { 0xA71 << 2, 0x00},
+ 	  { 0xA72 << 2, 0x00},
+ 	  { 0xA73 << 2, 0x00},
+ 	  { 0xA74 << 2, 0x00},
+ 	  { 0xA75 << 2, 0x00},
+ 	  { 0xA76 << 2, 0x00},
+ 	  { 0xA77 << 2, 0x00},
+ 	  { 0xA78 << 2, 0x00},
+ 	  { 0xA79 << 2, 0x00},
+ 	  { 0xA7A << 2, 0x00},
+ 	  { 0xA7B << 2, 0x00},
+ 	  { 0xA7C << 2, 0x00},
+ 	  { 0xA7D << 2, 0x00},
+ 	  { 0xA7E << 2, 0x00},
+ 	  { 0xA7F << 2, 0xd8},
+ 	  { 0xA80 << 2, 0x1a},
+ 	  { 0xA81 << 2, 0xff},
+ 	  { 0xA82 << 2, 0x01},
+ 	  { 0xA83 << 2, 0x00},
+ 	  { 0xA84 << 2, 0x00},
+ 	  { 0xA85 << 2, 0x00},
+ 	  { 0xA86 << 2, 0x00},
+ 	  { 0xA87 << 2, 0xf0},
+ 	  { 0xA88 << 2, 0xff},
+ 	  { 0xA89 << 2, 0xff},
+ 	  { 0xA8A << 2, 0xff},
+ 	  { 0xA8B << 2, 0xff},
+ 	  { 0xA8C << 2, 0x1c},
+ 	  { 0xA8D << 2, 0xc2},
+ 	  { 0xA8E << 2, 0xc3},
+ 	  { 0xA8F << 2, 0x3f},
+ 	  { 0xA90 << 2, 0x0a},
+ 	  { 0xA91 << 2, 0x00},
+ 	  { 0xA92 << 2, 0x00},
+ 	  { 0xA93 << 2, 0x00},
+  	  { 0xA94 << 2, 0x00},
+ 	  { 0xA95 << 2, 0x00},
+ 	  { 0xA96 << 2, 0xf8},
+   	  { 0x000 << 2, 0x07}
+	};
+
+
diff --git a/arch/arm/mach-comcerto/include/mach/serial.h b/arch/arm/mach-comcerto/include/mach/serial.h
new file mode 100644
index 0000000..1fea3f0
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/serial.h
@@ -0,0 +1,64 @@
+/* UART */
+#define LCR_CHAR_LEN_5          0x00      /* default */
+#define LCR_CHAR_LEN_6          0x01
+#define LCR_CHAR_LEN_7          0x02
+#define LCR_CHAR_LEN_8          0x03
+#define LCR_ONE_STOP            0x00      /* One stop bit! - default */
+#define LCR_TWO_STOP            0x04      /* Two stop bit! */
+#define LCR_PEN                 0x08      /* Parity Enable */
+#define LCR_PARITY_NONE         0x00
+#define LCR_EPS                 0x10      /* Even Parity Select */
+#define LCR_PS                  0x20      /* Enable Parity  Stuff */
+#define LCR_SBRK                0x40  /* Start Break */
+#define LCR_PSB                 0x80      /* Parity Stuff Bit */
+#define LCR_DLAB                0x80  /* UART 16550 Divisor Latch Assess */
+
+#define LSR_FIFOE               (1 << 7)        /* FIFO Error Status */
+#define LSR_TEMT                (1 << 6)        /* Transmitter Empty */
+#define LSR_TDRQ                (1 << 5)        /* Transmit Data Request */
+#define LSR_BI                  (1 << 4)        /* Break Interrupt */
+#define LSR_FE                  (1 << 3)        /* Framing Error */
+#define LSR_PE                  (1 << 2)        /* Parity Error */
+#define LSR_OE                  (1 << 1)        /* Overrun Error */
+#define LSR_DR                  (1 << 0)        /* Data Ready */
+
+#define IER_DMAE                (1 << 7)        /* DMA Requests Enable */
+#define IER_UUE                 (1 << 6)        /* UART Unit Enable */
+#define IER_NRZE                (1 << 5)        /* NRZ coding Enable */
+#define IER_RTIOE               (1 << 4)        /* Receiver Time Out Interrupt Enable */
+#define IER_MIE                 (1 << 3)        /* Modem Interrupt Enable */
+#define IER_RLSE                (1 << 2)        /* Receiver Line Status Interrupt Enable */
+#define IER_TIE                 (1 << 1)        /* Transmit Data request Interrupt Enable */
+#define IER_RAVIE               (1 << 0)        /* Receiver Data Available Interrupt Enable */
+
+#define IIR_FIFOES1             (1 << 7)        /* FIFO Mode Enable Status */
+#define IIR_FIFOES0             (1 << 6)        /* FIFO Mode Enable Status */
+#define IIR_TOD                 (1 << 3)        /* Time Out Detected */
+#define IIR_IID2                (1 << 2)        /* Interrupt Source Encoded */
+#define IIR_IID1                (1 << 1)        /* Interrupt Source Encoded */
+#define IIR_IP                  (1 << 0)        /* Interrupt Pending (active low) */
+
+/* UART 16550 FIFO Control Register */
+#define FCR_FIFOEN              0x01
+#define FCR_RCVRRES             0x02
+#define FCR_XMITRES             0x04
+
+/* Interrupt Enable Register */
+/* UART 16550 */
+#define IER_RXTH                0x01    /* Enable Received Data Available Interrupt */
+#define IER_TXTH                0x02    /* Enable Transmitter Empty Interrupt */
+
+#define UART_THR		0x00
+#define UART_RBR		0x00
+#define UART_DLL		0x00
+#define UART_IER		0x04
+#define UART_DLH		0x04
+#define UART_IIR		0x08
+#define UART_FCR		0x08
+#define UART_LCR		0x0C
+#define UART_MCR		0x10
+#define UART_LSR		0x14
+#define UART_MSR		0x18
+#define UART_SCR		0x1C
+
+
diff --git a/arch/arm/mach-comcerto/include/mach/spi.h b/arch/arm/mach-comcerto/include/mach/spi.h
new file mode 100644
index 0000000..7b303dd
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/spi.h
@@ -0,0 +1,21 @@
+/*
+ *  linux/include/asm-arm/arch-comcerto/irqs.h
+ *
+ *  Copyright (C) 2004,2005 Mindspeed Technologies, Inc.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ASM_ARCH_SPI_H
+#define __ASM_ARCH_SPI_H
+
+#if defined(CONFIG_ARCH_M86XX)
+	#include <mach/comcerto-2000/spi.h>
+#else
+	#error "Unsupported CPU"
+#endif
+
+#endif  /* __ASM_ARCH_SPI_H */
diff --git a/arch/arm/mach-comcerto/include/mach/system.h b/arch/arm/mach-comcerto/include/mach/system.h
new file mode 100644
index 0000000..150b46c
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/system.h
@@ -0,0 +1,42 @@
+/*
+ *  linux/include/asm-arm/arch-comcerto/system.h
+ *
+ *  Copyright (C) 2004,2005 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H
+
+#include <mach/hardware.h>
+#include <mach/io.h>
+#include <mach/comcerto-2000/clk-rst.h>
+#include <mach/reset.h>
+
+static inline void arch_idle(void)
+{
+	/*
+	 * This should do all the clock switching
+	 * and wait for interrupt tricks
+	 */
+	cpu_do_idle();
+}
+
+static inline void arch_reset(char mode, const char *cmd)
+{
+	comcerto_rst_cntrl_set(PWR_ON_SOFT_RST);
+}
+
+#endif /* __ASM_ARCH_SYSTEM_H */
diff --git a/arch/arm/mach-comcerto/include/mach/timex.h b/arch/arm/mach-comcerto/include/mach/timex.h
new file mode 100644
index 0000000..35ba9b3
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/timex.h
@@ -0,0 +1,28 @@
+/*
+ *  linux/include/asm-arm/arch-comcerto/timex.h
+ *
+ *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_TIMEX_H__
+#define __ASM_ARCH_TIMEX_H__
+
+	#include <mach/hardware.h>
+
+	#define CLOCK_TICK_RATE			COMCERTO_DEFAULTAXICLK
+
+#endif
diff --git a/arch/arm/mach-comcerto/include/mach/uncompress.h b/arch/arm/mach-comcerto/include/mach/uncompress.h
new file mode 100644
index 0000000..f3f0c4b
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/uncompress.h
@@ -0,0 +1,52 @@
+/*
+ *  linux/include/asm-arm/arch-comcerto/uncompress.h
+ *
+ *  Copyright (C) 2004,2008 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARCH_UNCOMPRESS_H
+#define __ASM_ARCH_UNCOMPRESS_H
+#include <asm/byteorder.h>
+
+#ifdef CONFIG_COMCERTO_UART1_SUPPORT
+	#define UART_DR		(*(volatile unsigned long *)0x96400000)
+	#define UART_LSR	(*(volatile unsigned long *)0x96400014)
+#elif CONFIG_COMCERTO_UART0_SUPPORT
+	#define UART_DR		(*(volatile unsigned long *)0x96300000)
+	#define UART_LSR	(*(volatile unsigned long *)0x96300014)
+#else
+	#error no uart configured
+#endif
+
+static inline void putc(int c)
+{
+	while (!( __cpu_to_le32(UART_LSR) & 0x20))
+		barrier();
+	UART_DR = __cpu_to_le32(c);
+}
+
+static void flush(void)
+{
+}
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup()
+
+#define arch_decomp_wdog()
+
+#endif /* __ASM_ARCH_UNCOMPRESS_H */
diff --git a/arch/arm/mach-comcerto/include/mach/vmalloc.h b/arch/arm/mach-comcerto/include/mach/vmalloc.h
new file mode 100644
index 0000000..daed580
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/vmalloc.h
@@ -0,0 +1,26 @@
+/*
+ *  arch/arm/mach-comcerto/include/mach/vmalloc.h
+ *
+ *  Copyright (C) 2011 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#if defined(CONFIG_ARCH_M86XXX)
+#define VMALLOC_END       (0xF0000000)
+#else
+#error "Unsupported CPU"
+#endif
diff --git a/arch/arm/mach-comcerto/include/mach/wdt.h b/arch/arm/mach-comcerto/include/mach/wdt.h
new file mode 100644
index 0000000..7090906
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/wdt.h
@@ -0,0 +1,22 @@
+/*
+ *  linux/include/asm-arm/arch-comcerto/irqs.h
+ *
+ *  Copyright (C) 2004,2005 Mindspeed Technologies, Inc.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ASM_ARCH_WDT_H
+#define __ASM_ARCH_WDT_H
+
+
+#if defined(CONFIG_ARCH_M86XXX)
+	#include <mach/comcerto-2000/wdt.h>
+#else
+	#error "mach/comcerto-2000/wdt.h :  Unknown architecture" 
+#endif
+
+#endif  /* __ASM_ARCH_WDT_H */
diff --git a/arch/arm/mach-comcerto/membuf.c b/arch/arm/mach-comcerto/membuf.c
new file mode 100644
index 0000000..7cd3494
--- /dev/null
+++ b/arch/arm/mach-comcerto/membuf.c
@@ -0,0 +1,411 @@
+/*
+ *  linux/arch/arm/mach-comcerto/membuf.c
+ *
+ *  Copyright (C) 2010 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/scatterlist.h>
+#include <asm/uaccess.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
+#define sg_page(sg)	((sg)->page)
+
+#define sg_virt(sg) (page_address(sg_page(sg)) + (sg)->offset)
+#endif
+
+#define MAX_BUFFERS	48
+
+#define MEMBUF_MINOR		0
+#define MEMBUF_MINOR_COUNT	1
+#define MEMBUF_DEV_COUNT	1
+
+#define MEMBUF_DEFAULT_PG_ORDER	6
+
+#define MEMBUF_DRV_NAME		"membuf"
+
+
+#define MEMBUF_GET_SCATTER _IOR('m', 1, struct usr_scatter_list)
+
+struct usr_scatter_list
+{
+	u8 entries;
+	u8 pg_order[MAX_BUFFERS];
+	u32 addr[MAX_BUFFERS];
+};
+
+struct membuf
+{
+	struct scatterlist sg[MAX_BUFFERS];
+	int sg_nr;
+
+	int size;	/* Total memory in use for the buffer data */
+	int real_size;	/* Total memory allocated for the scatter list */
+
+	int pg_order;
+
+	char mapped;
+};
+
+static struct membuf_dev
+{
+	struct cdev dev;
+	int devno;
+} membuf_dev;
+
+
+static int membuf_map(struct membuf *buf)
+{
+	int rc;
+
+	if (buf->mapped)
+	{
+		printk(KERN_ERR "%s: buffer already mapped\n", __func__);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = dma_map_sg(NULL, buf->sg, buf->sg_nr, DMA_TO_DEVICE);
+	if (rc != buf->sg_nr)
+		printk(KERN_ERR "%s: dma_map_sg() failed\n", __func__);
+	else
+		buf->mapped = 1;
+
+out:
+	return rc;
+}
+
+static void membuf_unmap(struct membuf *buf)
+{
+	if (!buf->mapped)
+		return;
+
+	dma_unmap_sg(NULL, buf->sg, buf->sg_nr, DMA_TO_DEVICE);
+
+	buf->mapped = 0;
+}
+
+static void membuf_free(struct membuf *buf)
+{
+	struct scatterlist *sg;
+	int i;
+
+	for (i = 0, sg = buf->sg; i < buf->sg_nr; i++, sg++) {
+		__free_pages(sg_page(sg), get_order(sg->length));
+	}
+
+	buf->sg_nr = 0;
+	buf->size = 0;
+	buf->real_size = 0;
+	buf->pg_order = MEMBUF_DEFAULT_PG_ORDER;
+}
+
+static void membuf_sync(struct membuf *buf)
+{
+	dma_sync_sg_for_device(NULL, buf->sg, buf->sg_nr, DMA_TO_DEVICE);
+}
+
+static int membuf_expand(struct membuf *buf, int size)
+{
+	struct scatterlist *sg;
+	void *page;
+	int len;
+
+	membuf_unmap(buf);
+
+	while (size > 0)
+	{
+		if (buf->sg_nr >= MAX_BUFFERS) {
+			printk(KERN_ERR "%s: too many scatter entries(%d) failed\n", __func__, buf->sg_nr);
+			return -ENOMEM;
+		}
+
+	retry:
+		page = (void *)__get_free_pages(GFP_KERNEL | __GFP_NOWARN, buf->pg_order);
+		if (!page) {
+			if (buf->pg_order-- > 1)
+				goto retry;
+
+			printk(KERN_ERR "%s: __get_free_pages(%d) failed\n", __func__, buf->pg_order);
+			return -ENOMEM;
+		}
+
+		sg = &buf->sg[buf->sg_nr];
+
+		len = PAGE_SIZE * (1 << buf->pg_order);
+
+		sg_set_buf(sg, page, len);
+
+		buf->sg_nr++;
+
+		buf->real_size += len;
+
+		if (size > len)
+			buf->size += len;
+		else
+			buf->size += size;
+
+		size -= len;
+	}
+
+	return 0;
+}
+
+
+static int get_sg_index(struct membuf *buf, int *offset)
+{
+	struct scatterlist *sg;
+	int i;
+
+	for (i = 0, sg = buf->sg; i < buf->sg_nr; i++, sg++) {
+		if (*offset < sg->length)
+			break;
+
+		*offset -= sg->length;
+	}
+
+//	printk(KERN_INFO "%d %d\n", i, *offset);
+
+	return i;
+}
+
+
+static ssize_t membuf_write(struct file *file, const char __user *data, size_t count, loff_t *off)
+{
+	struct membuf *buf = (struct membuf *)file->private_data;
+	struct scatterlist *sg;
+	int sg_offset, sg_i;
+	int count_now;
+	int offset = 0;
+	int rc;
+
+//	printk(KERN_INFO "%d\n", *off);
+
+	if ((*off + count) > buf->real_size) {
+
+		rc = membuf_expand(buf, (*off + count) - buf->real_size);
+		if (rc < 0) {
+			printk(KERN_ERR "%s: membuf_expand() failed\n", __func__);
+			goto out;
+		}
+	}
+
+	sg_offset = *off;
+	sg_i = get_sg_index(buf, &sg_offset);
+	sg = &buf->sg[sg_i];
+
+	while (count) {
+
+		count_now = min(sg->length - sg_offset, count);
+
+		if (copy_from_user(sg_virt(sg) + sg_offset, data + offset, count_now)) {
+			printk(KERN_ERR "%s: copy_from_user() failed\n", __func__);
+			rc = -EFAULT;
+			goto out;
+		}
+
+		count -= count_now;
+		offset += count_now;
+		sg++;
+		sg_offset = 0;
+	}
+
+	*off += offset;
+	rc = offset;
+
+out:
+	return rc;
+}
+
+static loff_t membuf_llseek(struct file *file, loff_t offset, int origin)
+{
+	struct membuf *buf = (struct membuf *)file->private_data;
+	loff_t new_offset;
+	int rc;
+
+	switch (origin) {
+	case 0: /* SEEK_SET */
+		new_offset = offset;
+		break;
+
+	case 1: /* SEEK_CUR */
+		new_offset = file->f_pos + offset;
+		break;
+
+	case 2: /* SEEK_END */
+		new_offset = buf->size + offset;
+		break;
+
+	default:
+		rc = -EINVAL;
+		goto err;
+	}
+
+	if (new_offset > buf->real_size) {
+		rc = membuf_expand(buf, new_offset - buf->real_size);
+		if (rc < 0) {
+			printk(KERN_ERR "%s: membuf_expand() failed\n", __func__);
+			goto err;
+		}
+	}
+
+	file->f_pos = new_offset;
+
+	return new_offset;
+
+err:
+	return rc;
+}
+
+
+static long membuf_ioctl(struct file *file,
+                unsigned int cmd, unsigned long arg)
+{
+	struct membuf *buf = (struct membuf *)file->private_data;
+	struct usr_scatter_list usr_sg;
+	struct scatterlist *sg;
+	int i;
+	int rc = 0;
+
+	switch (cmd) {
+	case MEMBUF_GET_SCATTER:
+
+		if (!buf->mapped)
+		{
+			rc = membuf_map(buf);
+			if (rc < 0)
+				break;
+		}
+
+		membuf_sync(buf);
+
+		usr_sg.entries = 0;
+		for (i = 0, sg = buf->sg; i < buf->sg_nr; i++, sg++) {
+			usr_sg.addr[usr_sg.entries] = sg_dma_address(sg);
+			usr_sg.pg_order[usr_sg.entries] = get_order(sg_dma_len(sg));
+
+/*
+			printk(KERN_INFO "%d %x %x %x %x %d\n", i, sg_virt(sg), sg_phys(sg),
+								 sg_dma_address(sg), usr_sg.pg_order[usr_sg.entries],
+								 sg->length);
+*/
+			usr_sg.entries++;
+		}
+
+		if (copy_to_user((void __user *)arg, &usr_sg, sizeof(struct usr_scatter_list))) {
+			printk(KERN_ERR "%s: copy_to_user() failed\n", __func__);
+			rc = -EFAULT;
+		}
+
+		break;
+
+	default:
+		printk(KERN_ERR "%s: unknown ioctl(%d)\n", __func__, cmd);
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+
+
+static int membuf_open(struct inode *in, struct file *file)
+{
+	struct membuf *buf;
+
+	buf = kzalloc(sizeof(struct membuf), GFP_KERNEL);
+	if (!buf) {
+		printk(KERN_ERR "%s: kmalloc() failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	buf->pg_order = MEMBUF_DEFAULT_PG_ORDER;
+
+	file->private_data = buf;
+
+	return 0;
+}
+
+
+static int membuf_release(struct inode *in, struct file *file)
+{
+	struct membuf *buf = (struct membuf *)file->private_data;
+
+	membuf_unmap(buf);
+	membuf_free(buf);
+
+	kfree(buf);
+
+	return 0;
+}
+
+
+static const struct file_operations membuf_fops = {
+	.owner = THIS_MODULE,
+	.write = membuf_write,
+	.llseek = membuf_llseek,
+	.unlocked_ioctl = membuf_ioctl,
+	.open = membuf_open,
+	.release = membuf_release,
+};
+
+static int __init membuf_init(void)
+{
+	int rc = 0;
+
+	rc = alloc_chrdev_region(&membuf_dev.devno, MEMBUF_MINOR, MEMBUF_MINOR_COUNT, MEMBUF_DRV_NAME);
+	if (rc < 0) {
+		printk(KERN_ERR "%s: alloc_chrdev_region() failed\n", __func__);
+		goto err0;
+	}
+
+	cdev_init(&membuf_dev.dev, &membuf_fops);
+	membuf_dev.dev.owner = THIS_MODULE;
+
+	rc = cdev_add (&membuf_dev.dev, membuf_dev.devno, MEMBUF_DEV_COUNT);
+	if (rc < 0) {
+		printk(KERN_ERR "%s: cdev_add() failed\n", __func__);
+		goto err1;
+	}
+
+	printk(KERN_INFO "%s: created membuf device(%d, %d)\n", __func__, MAJOR(membuf_dev.devno), MINOR(membuf_dev.devno));
+
+	return 0;
+
+err1:
+	unregister_chrdev_region(membuf_dev.devno, MEMBUF_DEV_COUNT);
+
+err0:
+	return rc;
+}
+
+static void __exit membuf_exit(void)
+{
+	cdev_del(&membuf_dev.dev);
+
+	unregister_chrdev_region(membuf_dev.devno, MEMBUF_DEV_COUNT);
+}
+
+
+module_init(membuf_init);
+module_exit(membuf_exit);
diff --git a/arch/arm/mach-comcerto/msp/Makefile b/arch/arm/mach-comcerto/msp/Makefile
new file mode 100644
index 0000000..c5e1af0
--- /dev/null
+++ b/arch/arm/mach-comcerto/msp/Makefile
@@ -0,0 +1,2 @@
+# Makefile Comcerto network firmware drivers
+obj-y += ved.o smi.o msp.o
diff --git a/arch/arm/mach-comcerto/msp/msp.c b/arch/arm/mach-comcerto/msp/msp.c
new file mode 100644
index 0000000..6a6affd
--- /dev/null
+++ b/arch/arm/mach-comcerto/msp/msp.c
@@ -0,0 +1,508 @@
+/*
+ *  arch/arm/mach-comcerto/msp/msp.c
+ *
+ *  Copyright (C) 2004,2008,2012 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <asm/fiq.h>
+#include <linux/platform_device.h>
+
+#include "ved.h"
+#include "msp.h"
+
+#define MSP_READY_DELAY (8000UL) /* msec */
+#define MSP_PROC_SECTION "msp_proc"
+#define VOIP_ENTRY_SECTION "voip_entries"
+
+#define MAGIC_LEN (0x24)
+#define MAGIC_OFF (0x20)
+
+#define MAX_SAVED_ALERT (20)
+
+#define COMCERTO_ATTR_SHOW(_name)	  \
+	static ssize_t comcerto_show_##_name(struct device *dev, struct device_attribute *attr, char *buf); \
+	static DEVICE_ATTR(_name, 0444, comcerto_show_##_name, NULL)
+
+#define COMCERTO_ATTR_SET(_name)	  \
+	static ssize_t comcerto_set_##_name(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); \
+	static DEVICE_ATTR(_name, 0200, NULL, comcerto_set_##_name)
+
+#define COMCERTO_ATTR(_name)	  \
+	static ssize_t comcerto_show_##_name(struct device *dev, struct device_attribute *attr, char *buf); \
+	static ssize_t comcerto_set_##_name(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); \
+	static DEVICE_ATTR(_name, 0644, comcerto_show_##_name, comcerto_set_##_name)
+
+COMCERTO_ATTR_SHOW(msp_info);
+COMCERTO_ATTR_SHOW(alert_info);
+COMCERTO_ATTR_SHOW(abi_rev);
+
+struct voip_fiq_code {
+	u32 len;
+	u8 data[MAGIC_LEN];	   /* use hardcoded instruction, see below */
+};
+
+static int voip_fiq_op(void *p, int release);
+
+static struct fiq_handler voip_fiq_handler = {
+	.name = "Comcerto VoIPoFIQ",
+	.fiq_op = voip_fiq_op,
+	.dev_id = NULL
+};
+
+static void (*voip_entry)(void); /* VoIP code entry point */
+static void (*voip_exit)(void);  /* VoIP code exit point */
+
+static void msp_poll(unsigned long arg);
+void update_pfe_status_for_MSP(void);
+static volatile struct msp_info * global_msp_info;
+
+struct pfe_info {
+	unsigned long buf_baseaddr;
+	unsigned long cbus_baseaddr;
+	void *owner;
+};
+
+struct tpfe_status {
+	unsigned long pfe_state;
+	unsigned long pfe_virt;
+	unsigned long axi_virt;
+	void *owner;
+} pfe_status;
+
+/* PFE inform MSP it is started and its parameters*/
+int msp_register_pfe(struct pfe_info *pfe_sync_info)
+{
+	/* save PFE status */
+	pfe_status.pfe_state = 1;
+	pfe_status.pfe_virt = pfe_sync_info->buf_baseaddr;
+	pfe_status.axi_virt = pfe_sync_info->cbus_baseaddr;
+	pfe_status.owner = pfe_sync_info->owner;
+
+	if (global_msp_info) {
+		/* msp is running, lock PFE, update PFE shared memory for MSP */
+		try_module_get(pfe_status.owner);
+		update_pfe_status_for_MSP();
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(msp_register_pfe);
+
+void update_pfe_status_for_MSP(void)
+{
+	global_msp_info->pfe_ready = pfe_status.pfe_state;
+	global_msp_info->pfe_virt = pfe_status.pfe_virt;
+	global_msp_info->pfe_phys = COMCERTO_PFE_DDR_BASE;
+	global_msp_info->axi_virt = pfe_status.axi_virt;
+	global_msp_info->axi_phys = COMCERTO_AXI_EXP_BASE;
+	global_msp_info->msp_virt = COMCERTO_MSP_VADDR;
+	global_msp_info->msp_phys = COMCERTO_MSP_DDR_BASE;
+}
+
+
+/* PFE inform MSP it is stopped */
+void msp_unregister_pfe(void)
+{
+	/* save PFE status */
+	pfe_status.pfe_state = 0;
+
+	if (global_msp_info) {
+		update_pfe_status_for_MSP();
+	}
+}
+EXPORT_SYMBOL(msp_unregister_pfe);
+
+static int voip_fiq_op(void *p, int release)
+{
+	return 0;
+}
+
+/**
+ * load_elf
+ *
+ *
+ */
+static int load_elf(struct _code_info *code_info)
+{
+	Elf32_Ehdr *this_elf_header = (Elf32_Ehdr *)(code_info->code);
+	Elf32_Half number_of_section = this_elf_header->e_shnum;
+	/* pointer to the section header */
+	Elf32_Shdr *this_section_headers = (Elf32_Shdr *)(code_info->code + this_elf_header->e_shoff);
+	Elf32_Off string_section_offset = this_section_headers[this_elf_header->e_shstrndx].sh_offset;
+	const char *section_name = NULL;
+	int rc = 0;
+	int i = 0;
+
+	if (!number_of_section) {
+		printk(KERN_ERR "error loading elf: number of section is zero\n");
+		rc = -1;
+
+		goto out;
+	}
+
+	/* parse all sections */
+	for (i = 0; i < number_of_section; i++) {
+		section_name = code_info->code  + string_section_offset + this_section_headers[i].sh_name;
+
+		if (!strncmp(section_name, MSP_PROC_SECTION, strlen(MSP_PROC_SECTION))) {
+			code_info->proc_addr = this_section_headers[i].sh_addr;
+		}
+
+		if (!strncmp(section_name, VOIP_ENTRY_SECTION, strlen(VOIP_ENTRY_SECTION))) {
+			code_info->sym_addr = this_section_headers[i].sh_addr;
+		}
+
+		/* retrieve the section name from the ELF buffer */
+
+		if ((this_section_headers[i].sh_flags != SHF_MIPS_ADDR)
+		    && this_section_headers[i].sh_flags
+			&& strncmp(section_name, "CHECKSUM", 8))
+		{
+			/* retrieve the section name from the ELF buffer */
+
+			if ((this_section_headers[i].sh_type & 3) == SHT_PROGBITS) {
+				memcpy(
+					(void *)this_section_headers[i].sh_addr,
+					(void*)(code_info->code + this_section_headers[i].sh_offset),
+					this_section_headers[i].sh_size);
+			}
+		}
+	}
+
+	if (code_info->proc_addr && code_info->sym_addr) {
+		code_info->program_addr = this_elf_header->e_entry;
+	} else {
+		printk(KERN_ERR "error loading elf: could not find %s or %s\n", MSP_PROC_SECTION, VOIP_ENTRY_SECTION);
+
+		rc = -1;
+	}
+
+out:
+	return rc;
+}
+
+static int msp_ready(struct comcerto_msp *msp, unsigned long timeout)
+{
+	/* timeout is passed in ms, set it in jiffies */
+	timeout = jiffies + (timeout * HZ) / 1000;
+
+	while (!msp->info || !msp->info->ready) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+
+		if (time_after(jiffies, timeout) && (!msp->info || !msp->info->ready)) {
+			printk(KERN_ERR "error: could not receive ack from VoIP\n");
+			msp->info = NULL;
+
+			goto err;
+		}
+	}
+
+	return 1;
+
+
+err:
+	return 0;
+}
+
+
+static int msp_start(struct comcerto_msp *msp)
+{
+	msp->state = MSP_STARTING;
+	msp->alert_seen = 0;
+
+	if (!msp_ready(msp, MSP_READY_DELAY)) {
+		printk(KERN_ERR "VoIP starting failed\n");
+
+		goto err;
+	}
+
+	printk(KERN_INFO "VoIP has been started successfully\n");
+
+	/* start heart beat timer */
+	init_timer(&msp->timer_expire);
+	msp->timer_expire.function = msp_poll;
+	msp->timer_expire.expires = jiffies + 1 * HZ; /* 1sec */
+	msp->timer_expire.data = (unsigned long)msp;
+	add_timer(&msp->timer_expire);
+	msp->state = MSP_RUNNING;
+	global_msp_info = msp->info;
+
+	if (pfe_status.pfe_state == 1) {
+		try_module_get(pfe_status.owner);
+		update_pfe_status_for_MSP();
+	}
+
+	return 0;
+
+
+err:
+	return -1;
+}
+
+static void msp_alert(struct comcerto_msp *msp)
+{
+	struct alert_type *alert = NULL;
+	int ialert = 0;
+
+	if (!msp->info) {
+		return;
+	}
+
+	while (msp->info->alert_number > msp->alert_seen) {
+		if (msp->alert_seen >= MAX_SAVED_ALERT) {
+			ialert = MAX_SAVED_ALERT - 1;
+		} else {
+			ialert = msp->alert_seen;
+		}
+
+		alert = (struct alert_type *)(msp->info->save_alert) + ialert;
+		msp->alert_seen++;
+
+		printk(KERN_ERR "VoIP alert: current number / total received = %lu/%lu\n", msp->alert_seen, msp->info->alert_number);
+		printk(KERN_ERR "\ttype: 0x%02x\n", alert->type & 0xff);
+		printk(KERN_ERR "\tchannel: %hu\n", alert->channel);
+		printk(KERN_ERR "\tlink register: 0x%08x\n", alert->abort_lr);
+		printk(KERN_ERR "\tunique ID: 0x%04x\n", alert->unique_id);
+		printk(KERN_ERR "\taction: 0x%04x\n", alert->action);
+		printk(KERN_ERR "\tlocaltime: 0x%08x\n", alert->localtime);
+		printk(KERN_ERR "\tval1: 0x%08x\n", alert->val1);
+		printk(KERN_ERR "\tval2: 0x%08x\n", alert->val2);
+	}
+}
+
+static void msp_poll(unsigned long arg)
+{
+	struct comcerto_msp *msp = (struct comcerto_msp *)arg;
+
+	switch (msp->state) {
+		case MSP_RESETTING:
+		case MSP_RESET:
+		case MSP_STARTING:
+		case MSP_CRASHED:
+			break;
+		case MSP_RUNNING: {
+			/* check for alerts */
+			msp_alert(msp);
+
+			if (!msp->info->heartbeat) {
+				printk(KERN_ERR "VoIP heart beat failure\n");
+				msp->state = MSP_CRASHED;
+			}
+
+			msp->info->heartbeat = 0;
+		} break;
+	}
+
+	msp->timer_expire.expires = jiffies + 1 * HZ; /* 1sec */
+	add_timer(&msp->timer_expire);
+}
+
+int comcerto_download_to_msp(struct comcerto_msp *msp)
+{
+	struct _code_info *code_info = &msp->code_info;
+	struct voip_sym *voip_sym;
+	struct voip_fiq_code voip_fiq;
+	void (*rtxc_handler)(void); /* FIQ handler code entry point */
+	int rc = 0;
+
+	if (load_elf(code_info)) {
+		printk(KERN_ERR "VoIP download failed\n");
+		rc = -EINVAL;
+
+		goto err;
+	}
+
+	/* save msp info pointer */
+	msp->info = (struct msp_info *)msp->code_info.proc_addr;
+	voip_sym = (struct voip_sym *)msp->code_info.sym_addr;
+
+	rtxc_handler = voip_sym->rtxc_handler;
+	voip_entry = voip_sym->voip_entry;
+	voip_exit = voip_sym->voip_exit;
+
+	if (!voip_entry || !voip_exit || !rtxc_handler) {
+		printk(KERN_ERR "failed extract symbol\n");
+		rc = -EINVAL;
+
+		goto err;
+	}
+
+	if (claim_fiq(&voip_fiq_handler)) {
+		printk(KERN_ERR "could not claim FIQ\n");
+		rc = -EINVAL;
+
+		goto err;
+	} else {
+		/* copy code to IVT */
+		unsigned int code = 0xe59ff018; /* LDR pc, [pc, #0x20]; here 0x20 == MAGIC_OFF, do not change it */
+
+		voip_fiq.len = MAGIC_LEN;
+		memcpy(voip_fiq.data + MAGIC_OFF, &rtxc_handler, sizeof(rtxc_handler));
+		memcpy(voip_fiq.data, &code, sizeof(code));
+
+		/* copy code to IVT */
+		set_fiq_handler(&voip_fiq.data[0], voip_fiq.len);
+	}
+
+err:
+	return rc;
+}
+
+int comcerto_start_msp(struct comcerto_msp *msp)
+{
+
+#ifdef CONFIG_SMP
+	struct cpumask in_mask;
+	int cpu = 0;
+	int pid = 0;
+
+	/* start voip on cpu where FIQ handler is registered */
+	cpumask_set_cpu(cpu, &in_mask);
+	sched_setaffinity(pid, &in_mask);
+#endif  /* CONFIG_SMP */
+
+	/* give control to MSP */
+	voip_entry();
+
+	return msp_start(msp);
+}
+
+void comcerto_stop_msp(struct comcerto_msp *msp)
+{
+	/* stop MSP gently */
+	voip_exit();
+
+	printk(KERN_INFO "VoIP has been stopped\n");
+
+	release_fiq(&voip_fiq_handler);
+
+	msp->state = MSP_RESET;
+	del_timer(&msp->timer_expire);
+	msp->info = NULL;
+
+	if (global_msp_info && (pfe_status.pfe_state == 1)) {
+		module_put(pfe_status.owner);
+	}
+
+	global_msp_info = 0;
+}
+
+static ssize_t comcerto_show_msp_info(struct device *dev,
+                                      struct device_attribute *attr, char *buf)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct net_device *ndev = platform_get_drvdata(pdev);
+	struct ved_priv *priv = netdev_priv(ndev);
+	struct comcerto_msp *msp = &priv->msp;
+	int len = 0;
+
+	if (!msp->info) {
+		return sprintf(buf + len, "no VoIP info available\n");
+	}
+
+	len += sprintf(buf + len, "ABI version: %lu\n", msp->info->abi_rev);
+	len += sprintf(buf + len, "VoIP version: %s\n", msp->info->msp_version);
+	len += sprintf(buf + len, "DSP version: %s\n", msp->info->spu_version);
+	len += sprintf(buf + len, "VoIP freq: %d Mhz\n", msp->info->ARMfreq);
+	len += sprintf(buf + len, "AMBA bus freq: %d MHz\n", msp->info->AMBAfreq);
+	len += sprintf(buf + len, "Alert number: %lu\n", msp->alert_seen);
+
+	return len;
+}
+
+static ssize_t comcerto_show_alert_info(struct device *dev,
+                                        struct device_attribute *attr, char *buf)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct net_device *ndev = platform_get_drvdata(pdev);
+	struct ved_priv *priv = netdev_priv(ndev);
+	struct comcerto_msp *msp = &priv->msp;
+	struct alert_type *alert;
+	unsigned long ialert = 0;
+	int len = 0;
+
+	if ( !msp->info || !msp->alert_seen ) {
+		return sprintf(buf + len, "no VoIP alert info available\n");
+	}
+
+	if (msp->alert_seen > MAX_SAVED_ALERT) {
+		ialert = MAX_SAVED_ALERT;
+	} else {
+		ialert = msp->alert_seen;
+	}
+
+	for (; ialert > 0; ialert--) {
+		alert = (struct alert_type *)(msp->info->save_alert) + ialert - 1;
+
+		len += sprintf(buf + len, "alert No: %lu\n", ((ialert == MAX_SAVED_ALERT) ? msp->alert_seen : ialert));
+		len += sprintf(buf + len, "\ttype: 0x%02X\n", (alert->type & 0xff));
+		len += sprintf(buf + len, "\tchannel: %hu\n", alert->channel);
+		len += sprintf(buf + len, "\tunique ID: 0x%04X\n", alert->unique_id);
+		len += sprintf(buf + len, "\taction: 0x%04X\n", alert->action);
+		len += sprintf(buf + len, "\tlink register: 0x%08X\n", alert->abort_lr);
+		len += sprintf(buf + len, "\tlocaltime: 0x%08X\n", alert->localtime);
+		len += sprintf(buf + len, "\tval1: 0x%08X\n", alert->val1);
+		len += sprintf(buf + len, "\tval2: 0x%08X\n", alert->val2);
+
+		/* Make sure we are not going out of buffer. Number to add is
+		   empirical, so, change buf above - change number below */
+		if (len + 175 > PAGE_SIZE) {
+			break;
+		}
+	}
+
+	return len;
+}
+
+static ssize_t comcerto_show_abi_rev(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+
+	struct platform_device *pdev = to_platform_device(dev);
+	struct net_device *ndev = platform_get_drvdata(pdev);
+	struct ved_priv *priv = netdev_priv(ndev);
+	struct comcerto_msp *msp = &priv->msp;
+	int len = 0;
+
+	if (!msp->info) {
+		return sprintf(buf + len, "no VoIP info available\n");
+	}
+
+	len += sprintf(buf + len, "%lu\n", msp->info->abi_rev);
+
+	return len;
+}
+
+int msp_init_sysfs(struct platform_device *pdev)
+{
+	if (device_create_file(&pdev->dev, &dev_attr_msp_info)
+	    || device_create_file(&pdev->dev, &dev_attr_alert_info)
+	    || device_create_file(&pdev->dev, &dev_attr_abi_rev))
+	{
+		printk(KERN_ERR "failed to create VoIP sysfs files\n");
+
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/arch/arm/mach-comcerto/msp/msp.h b/arch/arm/mach-comcerto/msp/msp.h
new file mode 100644
index 0000000..4f1b1f2
--- /dev/null
+++ b/arch/arm/mach-comcerto/msp/msp.h
@@ -0,0 +1,143 @@
+/*
+ *  arch/arm/mach-comcerto/msp/msp.h
+ *
+ *  Copyright (C) 2006,2012 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _COMCERTO_MSP_H
+#define _COMCERTO_MSP_H
+
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/elf.h>
+#include <linux/netdevice.h>
+#include <asm/pgtable.h>
+#include <mach/irqs.h>
+
+#define SHF_MIPS_ADDR (0x40000000)
+
+enum msp_state {
+	MSP_RESETTING = 0,
+	MSP_RESET,
+	MSP_STARTING,
+	MSP_RUNNING,
+	MSP_CRASHED
+};
+
+struct msp_stack_frame {
+	unsigned int r0;
+	unsigned int r1;
+	unsigned int r2;
+	unsigned int r3;
+	unsigned int r4;
+	unsigned int r5;
+	unsigned int r6;
+	unsigned int r7;
+	unsigned int r8;
+	unsigned int r9;
+	unsigned int r10;
+	unsigned int r11;
+	unsigned int r12;
+	unsigned int sp;
+	unsigned int lr;
+	unsigned int pc;
+};
+
+struct alert_type {
+	unsigned short type;
+	unsigned short channel;
+	unsigned short unique_id;
+	unsigned short action;
+	unsigned int abort_lr;
+	unsigned int val1;
+	unsigned int val2;
+	unsigned int localtime;
+};
+
+struct _code_info {
+	const unsigned char *code;
+	unsigned long size;
+
+	unsigned long checksum_program_addr;
+	unsigned long program_addr;
+	unsigned long proc_addr;
+	unsigned long sym_addr;
+	unsigned long checksum;
+};
+
+struct msp_info {
+	unsigned long abi_rev;
+	volatile unsigned long lock;
+	unsigned long device;
+	unsigned long revision;
+	char msp_version[32];
+	char spu_version[16];
+	/*  */
+	unsigned long CSPtoMSPQueuePhyaddr;
+	unsigned long MSPtoCSPQueuePhyaddr;
+	unsigned long SMRXCSPhyaddr;
+	unsigned long SMTXCSPhyaddr;
+	unsigned long SPDRV_ACP_MSP_Phyaddr;
+	/*  */
+	unsigned long ERAMsize;
+	unsigned long ARAMsize;
+	unsigned long IRAMsize;
+	unsigned short ARMfreq;
+	unsigned short AMBAfreq;
+	unsigned short SPUfreq;
+	unsigned long voip_ipaddr;
+	volatile unsigned long IPoffload;
+	volatile unsigned long ready;
+	volatile unsigned long heartbeat;
+	volatile unsigned long alert_number;
+	volatile unsigned long alert_frame;
+	volatile unsigned long save_alert;
+	unsigned long pfe_ready;
+	unsigned long pfe_virt;
+	unsigned long pfe_phys;
+	unsigned long axi_virt;
+	unsigned long axi_phys;
+	unsigned long msp_virt;
+	unsigned long msp_phys;
+};
+
+struct voip_sym {
+	void (*rtxc_handler)(void);
+	void (*voip_entry)(void);
+	void (*voip_exit)(void);
+	void (*voip_crash)(void *);
+};
+
+struct comcerto_msp {
+	unsigned long alert_seen;
+	unsigned long last_tick;
+	int state;
+
+	volatile struct msp_info *info;
+	struct _code_info code_info;
+	struct sk_buff_head msp_list;
+	struct timer_list timer_expire;
+	struct ctl_table_header *sysctl_header;
+	void* __iomem vectors_base;
+};
+
+int comcerto_download_to_msp(struct comcerto_msp *msp);
+int comcerto_start_msp(struct comcerto_msp *msp);
+void comcerto_stop_msp(struct comcerto_msp *msp);
+int msp_init_sysfs(struct platform_device *pdev);
+
+#endif  /* _COMCERTO_MSP_H */
diff --git a/arch/arm/mach-comcerto/msp/smi.c b/arch/arm/mach-comcerto/msp/smi.c
new file mode 100644
index 0000000..bb3822f
--- /dev/null
+++ b/arch/arm/mach-comcerto/msp/smi.c
@@ -0,0 +1,67 @@
+/*
+ *  arch/arm/mach-comcerto/msp/smi.h
+ *
+ *  Copyright (C) 2012 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <asm/io.h>
+
+#include "smi.h"
+#include "msp.h"
+
+void *smi_alloc_part(struct fastpart *fp)
+{
+	unsigned long flags = 0;
+	void *vaddr = NULL;
+
+	flags = msp_lock_frqsave();
+
+	if (fp->freeblk) {
+		vaddr = fp->freeblk;
+		fp->freeblk = (u32 * volatile)__raw_readl(vaddr);
+	}
+
+	msp_unlock_frqrestore(flags);
+
+	return vaddr;
+}
+
+void smi_free_part(struct fastpart *fp, void *vaddr)
+{
+	unsigned long flags = 0;
+
+	flags = msp_lock_frqsave();
+
+	__raw_writel((unsigned long)fp->freeblk, (unsigned long)vaddr);
+	fp->freeblk = vaddr;
+
+	msp_unlock_frqrestore(flags);
+}
+
+struct fastqueue *smi_queue_init(struct smiqueue *psmiq, unsigned long addr, void (*gen_msp_irq)(void))
+{
+        struct fastqueue *fpq = (struct fastqueue *)addr;
+
+        if (fpq) {
+                psmiq->fpq = fpq;
+                psmiq->storage = fpq->storage;
+                psmiq->gen_msp_irq = gen_msp_irq;
+        }
+
+        return fpq;
+}
diff --git a/arch/arm/mach-comcerto/msp/smi.h b/arch/arm/mach-comcerto/msp/smi.h
new file mode 100644
index 0000000..c45b2a6
--- /dev/null
+++ b/arch/arm/mach-comcerto/msp/smi.h
@@ -0,0 +1,150 @@
+/*
+ *  arch/arm/mach-comcerto/msp/smi.h
+ *
+ *  Copyright (C) 2012 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _COMCERTO_SMI_H
+#define _COMCERTO_SMI_H
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+
+#include <asm/io.h>
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/sema.h>
+
+#ifndef COMCERTO_IRQ_SET
+#define DISTR_INT_SET_PENDING (COMCERTO_GIC_DIST_BASE + 0x200)
+#define DISTR_CLEAR_PENDING (COMCERTO_GIC_DIST_BASE + 0x280)
+#define CPU_END_OF_INT (COMCERTO_GIC_CPU_BASE + 0x10)
+#define comcerto_softirq_set(irq)	  \
+	(*((volatile unsigned long *)DISTR_INT_SET_PENDING + ((irq) >> 5)) = 1 << ((irq) & 0x1f))
+#define comcerto_softirq_check(irq)	  \
+	((*((volatile unsigned long *)DISTR_INT_SET_PENDING + ((irq) >> 5)) >> ((irq) & 0x1f)) & 0x01)
+#define comcerto_irq_ack(irq)	  \
+	(* ((volatile unsigned long *) DISTR_CLEAR_PENDING + ((irq) >> 5)) = 1 << ((irq) % 32))
+
+//#define comcerto_irq_ack(irq) (*(volatile unsigned long *)(CPU_END_OF_INT) = irq)
+
+#endif  /* C2000 */
+
+/* shared structure (MSP uses the same type) */
+struct fastqueue {
+	u32 *storage;
+	u32 sema;
+	volatile u16 lock;
+	volatile u16 get;
+	volatile u16 put;
+	u16 size;
+};
+
+/* private structure (CSP only) */
+struct smiqueue {
+	u32 *storage;			  /* virtual address of fpq->storage */
+	struct fastqueue *fpq;	  /* queue pointer */
+	void (*gen_msp_irq)(void); /* CSP to MSP generate interrupt function */
+};
+
+struct fastpart {
+        volatile u8 lock;
+        u8 reserved1;
+        u32 * volatile freeblk;
+        u32 *storage;
+        u32 blksz;
+        u32 blkcnt;
+        u32 *end_of_storage;
+        u16 reserved2;
+        u16 reserved3;
+        u16 freecnt;
+};
+
+void *smi_alloc_part(struct fastpart *fp);
+void smi_free_part(struct fastpart *fp, void *v);
+
+
+struct fastqueue *smi_queue_init(struct smiqueue *psmiq, unsigned long addr, void (*gen_msp_irq)(void));
+
+static inline void smi_gen_msp_irq(void)
+{
+	comcerto_softirq_set(IRQ_PTP1);
+}
+
+static inline int smi_enqueue(struct smiqueue *psmiq, void *vaddr)
+{
+	struct fastqueue *fpq = psmiq->fpq;
+	unsigned long flags = 0;
+	u16 put = 0;
+	int rc = 0;
+
+	flags = msp_lock_frqsave();
+
+	put = fpq->put;
+
+	if (++put >= fpq->size) {
+		put = 0;
+	}
+
+	if (put != fpq->get) {
+		psmiq->storage[fpq->put] = (u32)vaddr;
+		fpq->put = put;
+
+		if (psmiq->gen_msp_irq) {
+			psmiq->gen_msp_irq();
+		}
+
+		rc = 1;
+	}
+
+	msp_unlock_frqrestore(flags);
+
+	return rc;
+}
+
+static inline void *smi_dequeue(struct smiqueue *psmiq)
+{
+	struct fastqueue *fpq = psmiq->fpq;
+	unsigned long flags = 0;
+	u32 get = 0;
+	void *vaddr = NULL;
+
+	flags = msp_lock_frqsave();
+
+	get = fpq->get;
+
+	if (fpq->put != get) {
+		vaddr = (void *)(psmiq->storage[get++]);
+
+		if (get == fpq->size) {
+			get = 0;
+		}
+
+		fpq->get = get;
+	}
+
+	msp_unlock_frqrestore(flags);
+
+	return vaddr;
+}
+
+static inline int smi_is_queue_empty(struct fastqueue *fpq)
+{
+	return (fpq->get == fpq->put);
+}
+
+#endif /* _COMCERTO_SMI_H */
diff --git a/arch/arm/mach-comcerto/msp/ved.c b/arch/arm/mach-comcerto/msp/ved.c
new file mode 100644
index 0000000..f9fc70f
--- /dev/null
+++ b/arch/arm/mach-comcerto/msp/ved.c
@@ -0,0 +1,557 @@
+/*
+ *  arch/arm/mach-comcerto/msp/ved.c
+ *
+ *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/interrupt.h>
+#include <linux/etherdevice.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/sched.h>
+
+#include "ved.h"
+
+static char ctrl_mac[6] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE };
+
+#define VED_POLL_WEIGHT (32)
+#define IP_SEC_HEADROOM (40)
+#define PKT_BUF_SZ (1540 + IP_SEC_HEADROOM) /* size of each rx buffer */
+
+static int ved_xmit(struct sk_buff *skb, struct net_device *dev);
+static struct net_device_stats *ved_get_stats(struct net_device *dev);
+static irqreturn_t ved_interrupt(int irq, void *dev_id);
+static int ved_open(struct net_device *dev);
+static int ved_release(struct net_device *dev);
+static int ved_rebuild_header(struct sk_buff *skb);
+static int ved_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
+                      const void *daddr, const void *saddr, unsigned int len);
+static int ved_write_packet(struct sk_buff *skb, struct net_device *dev);
+static int ved_read_packet(struct net_device *dev, struct FDesc * ThisFdesc);
+static int ved_poll(struct napi_struct *napi, int budget);
+static int start_ved(struct net_device *dev);
+static int stop_ved(struct net_device *dev);
+
+
+static int ved_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ved_priv *priv = (struct ved_priv *)netdev_priv(dev);
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	rc = ved_write_packet(skb, dev);
+
+	if (rc) {
+		priv->stats.tx_dropped++;
+	} else {
+		priv->stats.tx_packets++;
+		priv->stats.tx_bytes += skb->len;
+		dev->trans_start = jiffies; /* save the timestamp */
+	}
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return 0;
+}
+
+static inline void ved_ack_msp(void)
+{
+	comcerto_softirq_set(IRQ_PTP1);
+}
+
+static irqreturn_t ved_interrupt(int irq, void *dev_id)
+{
+	struct net_device *dev = (struct net_device *)dev_id;
+	struct ved_priv *priv = netdev_priv(dev);
+
+	spin_lock(&priv->lock);
+
+	if (napi_schedule_prep(&priv->napi)) {
+		comcerto_softirq_set(irq);
+
+		disable_irq_nosync(irq);
+		__napi_schedule(&priv->napi);
+	} else {
+		/* FIX by disabling interrupts */
+		/* disable_irq(irq); */
+	}
+
+	/* unlock the device */
+	spin_unlock(&priv->lock);
+
+	return IRQ_HANDLED;
+}
+
+static int ved_rebuild_header(struct sk_buff *skb)
+{
+	struct ethhdr *eth = (struct ethhdr *)skb->data;
+	struct net_device *dev = skb->dev;
+
+	memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+	memcpy(eth->h_dest, dev->dev_addr, dev->addr_len);
+	eth->h_dest[ETH_ALEN - 1] ^= 0x01;	/* dest is us xor 1 */
+
+	return 0;
+}
+
+static int ved_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
+                      const void *daddr, const void *saddr, unsigned int len)
+{
+	struct ethhdr *eth = (struct ethhdr *)skb_push(skb, ETH_HLEN);
+
+	eth->h_proto = htons(type);
+	memcpy(eth->h_source, saddr ? saddr : dev->dev_addr, dev->addr_len);
+	memcpy(eth->h_dest, daddr ? daddr : dev->dev_addr, dev->addr_len);
+	eth->h_dest[ETH_ALEN - 1] ^= 0x01;	/* dest is us xor 1 */
+
+	return dev->hard_header_len;
+}
+
+static int ved_open(struct net_device *dev)
+{
+	struct ved_priv *priv = netdev_priv(dev);
+	struct platform_device *pdev = priv->pdev;
+	const struct firmware *fw_entry;
+	const char fw_name[] = {"voip.axf"};
+	int rc = 0;
+
+	/* check if the interface is already opened */
+
+	if (priv->state == 1) {
+		/* interface is opened, nothing to be done */
+
+		return rc;
+	}
+
+	if (priv->msp.info) {
+		/* stop MSP */
+
+		del_timer(&priv->msp.timer_expire);
+		priv->msp.info = NULL;
+		priv->msp.state = MSP_RESET;
+	}
+
+	might_sleep();
+
+	memset((void *)COMCERTO_MSP_VADDR, 0x00, COMCERTO_MSP_DDR_SIZE);
+
+	if (request_firmware(&fw_entry, (char *)fw_name, &pdev->dev)) {
+		printk(KERN_ERR "could not find the VoIP firmware\n");
+		rc = -ETIMEDOUT;
+
+		return rc;
+	}
+
+	priv->msp.code_info.code = fw_entry->data;
+	priv->msp.code_info.size = fw_entry->size;
+
+	if (comcerto_download_to_msp(&priv->msp)) {
+		printk(KERN_ERR "failed download VoIP\n");
+		rc = -EREMOTEIO;
+
+		goto out;
+	}
+
+	if (comcerto_start_msp(&priv->msp)) {
+		printk(KERN_ERR "failed start VoIP\n");
+		rc = -EREMOTEIO;
+
+		goto out;
+	}
+
+	start_ved(dev);
+	napi_enable(&priv->napi);
+
+	if (request_irq(dev->irq, ved_interrupt, IRQF_SHARED, "comcerto_ved", dev)) {
+		printk(KERN_ERR "%s: failed to request irq#%d\n", dev->name, dev->irq);
+
+		comcerto_stop_msp(&priv->msp);
+		napi_disable(&priv->napi);
+		stop_ved(dev);
+
+		goto out;
+	}
+
+	netif_start_queue(dev);
+
+	priv->state = 1;
+
+
+out:
+	release_firmware(fw_entry);
+
+	return rc;
+}
+
+int ved_release(struct net_device *dev)
+{
+	struct ved_priv *priv = netdev_priv(dev);
+
+	/* do nothing if interface is already down */
+
+	if (priv->state) {
+		netif_stop_queue(dev); /* can't transmit any more */
+
+		napi_disable(&priv->napi);
+
+		/* disable irq */
+		free_irq(dev->irq, dev);
+
+		/* reset MSP device */
+		comcerto_stop_msp(&priv->msp);
+		stop_ved(dev);
+		priv->state = 0;
+	}
+
+	return 0;
+}
+
+static struct net_device_stats *ved_get_stats(struct net_device *dev)
+{
+	return &(((struct ved_priv *)netdev_priv(dev))->stats);
+}
+
+/**
+ *	ved_read_packet - read and process an REALPACKET (Ethernet) frame
+ *	@dev: device id
+ *	@ThisFdesc: Frame descriptor to parse
+ *
+ *	This function read and process received frame descriptor non pre-processed by MSP . (ethernet frames)
+ */
+static int ved_read_packet(struct net_device *dev, struct FDesc *ThisFdesc)
+{
+	struct ved_priv *priv = (struct ved_priv *)netdev_priv(dev);
+	char *data_addr;
+	int length, offset, reason;
+	struct sk_buff *skb;
+
+	skb = dev_alloc_skb(PKT_BUF_SZ);
+
+	if (!skb) {
+		printk(KERN_WARNING "no skb was allocated: packet is dropped\n");
+		priv->stats.rx_dropped++;
+
+		return 0;
+	}
+
+	length = ThisFdesc->Length;
+	offset = ThisFdesc->Offset;
+
+	ThisFdesc->FStatus = 0;
+	data_addr = (char *)(ThisFdesc->Payload + offset);
+
+	skb_reserve(skb, NET_IP_ALIGN);
+	memcpy(skb_put(skb, length), data_addr, length);
+	skb->dev = dev;
+	skb->protocol = eth_type_trans(skb, dev);
+
+	if ((reason = netif_receive_skb(skb))) {
+		priv->stats.rx_dropped++;
+	}
+
+	priv->stats.rx_packets++;
+	priv->stats.rx_bytes += length;
+	dev->last_rx = jiffies;
+
+	return 1;
+}
+
+static int ved_poll(struct napi_struct *napi, int budget)
+{
+
+	struct ved_priv *priv = container_of(napi, struct ved_priv, napi);
+	struct net_device *dev = priv->dev;
+	struct FDesc * ThisFdesc = NULL;
+	int done;
+	int rx_work_limit = budget;
+	int received = 0;
+
+restart_poll:
+	do {
+		comcerto_irq_ack(dev->irq);
+
+		while (!smi_is_queue_empty(priv->rx_smiq.fpq)) {
+			if (--rx_work_limit < 0) {
+				goto not_done;
+			}
+
+			ThisFdesc = smi_dequeue(&priv->rx_smiq);
+
+			done = ved_read_packet(dev, ThisFdesc);
+			smi_free_part(ThisFdesc->fpart, ThisFdesc);
+
+			if (!done) {
+				goto not_done;
+			} else {
+				received++;
+			}
+
+			break;
+		}
+	} while (comcerto_softirq_check(dev->irq));
+
+	/* we are happy/done, no more packets on ring; put us back
+	   to where we can start processing interrupts again */
+	napi_complete(napi);
+	/* enable_irq(dev->irq); */
+
+	/* The last op happens after poll completion. Which means the following:
+	 * 1. it can race with disabling irqs in irq handler (which are done to
+	 * schedule polls)
+	 * 2. it can race with dis/enabling irqs in other poll threads
+	 * 3. if an irq raised after the begining of the outer  beginning
+	 * loop(marked in the code above), it will be immediately
+	 * triggered here.
+	 *
+	 * Summarizing: the logic may results in some redundant irqs both
+	 * due to races in masking and due to too late acking of already
+	 * processed irqs. The good news: no events are ever lost.
+	 */
+
+	/* Let's have a last chance to process any missing interrupts we may
+	 * we may have missed while the IRQs line was masqued. Before leaving
+	 * poll mode, we check if data have been posted in the queue from MSP.
+	 * If true, then the IRQ line is disabled again and a new loop of polling
+	 * is scheduled. This double check work arround is well known in NAPI
+	 * based implementation (see documentations/NAPI_HOWTO.txt - appendix2)
+	 */
+
+	if (!smi_is_queue_empty(priv->rx_smiq.fpq) && napi_reschedule(napi)) {
+		/* disable_irq(dev->irq); */
+		goto restart_poll;
+	}
+
+	enable_irq(dev->irq);
+
+	return 0;
+
+not_done:
+	if (!received) {
+		received = 1;
+	}
+
+	return 1;
+}
+
+static int ved_write_packet(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ved_priv *priv = (struct ved_priv *)netdev_priv(dev);
+	struct FDesc *ThisFdesc;
+	u8 *buf;
+	u32 offset;
+
+	ThisFdesc = smi_alloc_part(priv->tx_smipart);
+
+	if (!ThisFdesc) {
+		dev_kfree_skb(skb);
+
+		return -ENOMEM;
+	}
+
+	offset = NET_IP_ALIGN;
+	buf = ThisFdesc->Payload + offset;
+
+	memcpy(buf, skb->data, skb->len);
+
+	ThisFdesc->Offset = offset;
+
+	ThisFdesc->Next = NULL;
+	ThisFdesc->Length = (u32)(skb->len);
+	ThisFdesc->FStatus = 0;
+	ThisFdesc->protocol = priv->default_packet_type;
+
+	/* free the original skb (local generation) */
+	dev_kfree_skb(skb);
+
+	if (!smi_enqueue(&priv->tx_smiq, ThisFdesc)) {
+		printk(KERN_WARNING "could not enqueue: queue is full: %#lx\n", (unsigned long)ThisFdesc);
+
+		smi_free_part(priv->tx_smipart, ThisFdesc);
+
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static int stop_ved(struct net_device *dev)
+{
+	return 0;
+}
+
+static int start_ved(struct net_device *dev)
+{
+	struct ved_priv *priv = (struct ved_priv *)netdev_priv(dev);
+	struct msp_info *info = (struct msp_info *)priv->msp.info;
+
+	if (!info) {
+		printk(KERN_ERR "no VoIP info found\n");
+
+		return -1;
+	}
+
+	printk(KERN_INFO "Device: %lx\n", info->device);
+	printk(KERN_INFO "Revision: %lx\n", info->revision);
+	printk(KERN_INFO "CSPtoMSPQueuePhyaddr: %#lx\n", info->CSPtoMSPQueuePhyaddr);
+	printk(KERN_INFO "MSPtoCSPQueuePhyaddr: %#lx\n", info->MSPtoCSPQueuePhyaddr);
+	printk(KERN_INFO "SMRXCSPhyaddr: %#lx\n", info->SMRXCSPhyaddr);
+	printk(KERN_INFO "SMTXCSPhyaddr: %#lx\n", info->SMTXCSPhyaddr);
+
+	printk(KERN_INFO "DSP version: %s\n", info->spu_version);
+	printk(KERN_INFO "VoIP version: %s\n", info->msp_version);
+
+	priv->tx_smipart = (struct fastpart *)(info->SMTXCSPhyaddr);
+	priv->rx_smipart = (struct fastpart *)(info->SMRXCSPhyaddr);
+
+	smi_queue_init(&priv->tx_smiq, info->CSPtoMSPQueuePhyaddr, smi_gen_msp_irq);
+	smi_queue_init(&priv->rx_smiq, info->MSPtoCSPQueuePhyaddr, NULL);
+
+	ved_ack_msp();
+
+	return 0;
+}
+
+static const struct net_device_ops ctrl_netdev_ops = {
+	.ndo_open = ved_open,
+	.ndo_stop = ved_release,
+	.ndo_start_xmit = ved_xmit,
+	.ndo_get_stats = ved_get_stats,
+};
+
+static const struct header_ops ctrl_header_ops = {
+	.create = ved_header,
+	.rebuild = ved_rebuild_header,
+};
+
+static int ved_probe(struct platform_device *pdev)
+{
+	struct net_device *dev = NULL;
+	struct ved_priv *priv= NULL;
+	int rc;
+
+	/* create an ethernet device instance */
+
+	dev = alloc_etherdev(sizeof (*priv));
+
+	if (!dev) {
+		printk(KERN_ERR "gemac %d device allocation failed\n", pdev->id);
+		rc = -ENOMEM;
+
+		goto err0;
+	}
+
+	priv = netdev_priv(dev);
+
+	memset(priv, 0, sizeof(struct ved_priv));
+
+	spin_lock_init(&priv->lock);
+
+	/* init private section */
+	priv->default_packet_type = PROTID_ETH;
+	priv->state = 0;		  /* closed */
+
+	priv->pdev = pdev;
+	priv->dev = dev;
+	platform_set_drvdata(pdev, dev);
+
+	/* copy the station address into the dev structure */
+	memcpy(dev->dev_addr, ctrl_mac, ETH_ALEN);
+
+	if (dev_alloc_name(dev, CTRL)) {
+		printk(KERN_ERR "could not allocate net device name %s\n", CTRL);
+		rc = -EINVAL;
+
+		goto err2;
+	}
+
+	SET_NETDEV_DEV(dev, &pdev->dev);
+
+	/* fill in device structure with ethernet-generic values */
+	ether_setup(dev);
+
+	/* initialize the device structure */
+	dev->netdev_ops = &ctrl_netdev_ops;
+	dev->header_ops = &ctrl_header_ops;
+	dev->destructor = free_netdev;
+
+	/* fill in device structure with ethernet-generic values */
+	dev->tx_queue_len = 0;
+	dev->flags |= IFF_NOARP;
+	dev->flags &= ~IFF_MULTICAST;
+	dev->irq = platform_get_irq_byname(pdev, "irq");
+
+	netif_napi_add(dev, &priv->napi, ved_poll, VED_POLL_WEIGHT);
+
+	skb_queue_head_init(&priv->msp.msp_list);
+
+	rc = register_netdev(dev);
+
+	if (rc) {
+		printk(KERN_ERR "could not register net device\n");
+
+		goto err0;
+	}
+
+	/* create all the sysfs files */
+	msp_init_sysfs(pdev);
+
+	return 0;
+
+
+err2:
+	platform_set_drvdata(pdev, NULL);
+	free_netdev(dev);
+
+err0:
+	return rc;
+}
+
+static int ved_remove(struct platform_device *pdev)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+
+	unregister_netdevice(dev);
+	platform_set_drvdata(pdev, NULL);
+	free_netdev(dev);
+
+	return 0;
+}
+
+/* Structure for a device driver */
+static struct platform_driver ved_driver = {
+	.probe = ved_probe,
+	.remove = ved_remove,
+	.driver = {
+		.name = "ved",
+	},
+};
+
+static int __init ved_init(void)
+{
+	return platform_driver_register(&ved_driver);
+}
+
+static void __exit ved_exit(void)
+{
+	platform_driver_unregister(&ved_driver);
+}
+
+
+module_init(ved_init);
+module_exit(ved_exit);
diff --git a/arch/arm/mach-comcerto/msp/ved.h b/arch/arm/mach-comcerto/msp/ved.h
new file mode 100644
index 0000000..f747cc5
--- /dev/null
+++ b/arch/arm/mach-comcerto/msp/ved.h
@@ -0,0 +1,100 @@
+/*
+ *  arch/arm/mach-comcerto/msp/ved.h
+ *
+ *  Copyright (C) 2012 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _COMCERTO_VED_H
+#define _COMCERTO_VED_H
+
+#include <linux/netdevice.h>
+
+#include "smi.h"
+#include "msp.h"
+
+/* Protocol index definition */
+enum {
+	PROTID_RAW,
+	PROTID_ETH,
+	PROTID_PPP,
+	PROTID_IPV4,
+	PROTID_IPV6,
+	PROTID_CSME,
+	PROTID_ARP,
+	PROTID_VLAN,
+	PROTID_UDP,
+	PROTID_TCP,
+	PROTID_ICMP,
+	PROTID_CSM_API,
+	MAX_PROTOCOL,
+	PROTO_INVALID
+};
+
+#define MAX_BDESC_NUMBER (4)
+#define CTRL "eth1"
+
+
+/*
+ * This structure is private to each device. It is used to pass
+ * packets in and out, so there is place for a packet
+ */
+
+struct ved_priv {
+	struct net_device_stats stats;
+	struct platform_device *pdev;
+	struct net_device *dev;
+	struct napi_struct napi;
+	spinlock_t lock;
+
+	struct _SKB_POOL *skbpool; /* skb pool for MSP to CSP buffer (max MTU size) */
+
+	/* smi (share memory interface) */
+	struct fastpart *tx_smipart;	/* CSP to MSP Fdesc fast part */
+	struct fastpart *rx_smipart;	/* MSP to CSP Fdesc fast part */
+	struct smiqueue tx_smiq;
+	struct smiqueue rx_smiq;
+	u32 default_packet_type;
+	struct comcerto_msp msp;
+	int state;
+};
+
+struct BDesc {
+	u8 *BPtr;
+	volatile u32 BControl;
+};
+
+struct FDesc {
+	struct FDesc *Next;
+	volatile u32 System;
+	volatile u32 FStatus;
+	volatile u32 FControl;
+	struct BDesc BDesc[MAX_BDESC_NUMBER];
+
+	u16 Length;
+	u16 Offset;
+	u16 protocol;
+	u16 protocol_hdr_len;
+	struct sk_buff *skb;
+	struct fastpart *fpart;
+	struct FDesc *Tail;
+	u32 nFDesc; /* nFdesc used by MSP or local phy addr of FDESC
+	             * (only used in direct EMAC control mode) */
+	void *pSFdesc; /* CSP must not touch this value */
+	u8 *Payload;
+};
+
+#endif /* _COMCERTO_VED_H */
diff --git a/arch/arm/mach-comcerto/pcie-c2000.c b/arch/arm/mach-comcerto/pcie-c2000.c
new file mode 100644
index 0000000..d4c01fb
--- /dev/null
+++ b/arch/arm/mach-comcerto/pcie-c2000.c
@@ -0,0 +1,1964 @@
+/*
+ * linux/arch/arm/mach-comcerto/pcie-c2000.c
+ *
+ * Copyright (C) 2004,2005 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#if defined(CONFIG_PCI_MSI)
+#include <linux/msi.h>
+#endif
+
+#include <asm/irq.h>
+#include <asm/delay.h>
+#include <asm/sizes.h>
+#include <asm/mach/pci.h>
+#include <linux/irq.h>
+#include <asm/io.h>
+#include <asm/mach/irq.h>
+#include <mach/pcie-c2000.h>
+#include <mach/serdes-c2000.h>
+#include <mach/reset.h>
+#include <mach/hardware.h>
+
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <mach/comcerto-2000/pm.h>
+//#define COMCERTO_PCIE_DEBUG
+
+#ifdef CONFIG_PCI_MSI
+static DECLARE_BITMAP(msi_irq_in_use[NUM_PCIE_PORTS], PCIE_NUM_MSI_IRQS);
+static int comcerto_msi_init(struct pcie_port *pp);
+#endif
+
+int pcie_external_clk = 0;
+static int __init get_pcie_clk_mode(char *str)
+{
+        if (!strcmp(str, "yes"))
+                pcie_external_clk = 1;
+
+        return 1;
+}
+
+__setup("pcie_external_clk=", get_pcie_clk_mode);
+
+int pcie_gen1_only = 0;
+static int __init get_pcie_gen_mode(char *str)
+{
+        if (!strcmp(str, "yes"))
+                pcie_gen1_only = 1;
+
+        return 1;
+}
+
+__setup("pcie_gen1_only=", get_pcie_gen_mode);
+
+
+/* DWC PCIEe configuration register offsets on APB */
+struct pcie_app_reg app_regs[MAX_PCIE_PORTS] = {
+	/* PCIe0 */
+	{
+		0x00000000,
+		0x00000004,
+		0x00000008,
+		0x0000000C,
+		0x00000010,
+		0x00000014,
+		0x00000018,
+		0x00000040,
+		0x00000044,
+		0x00000048,
+		0x00000058,
+		0x00000080,
+		0x00000084,
+		0x000000C0,
+		0x000000C4,
+		0x00000100,
+		0x00000104,
+		0x00000108,
+		0x0000010C
+	},
+	/* PCIe1 */
+	{
+		0x00000020,
+		0x00000024,
+		0x00000028,
+		0x0000002C,
+		0x00000030,
+		0x00000034,
+		0x00000038,
+		0x0000004C,
+		0x00000050,
+		0x00000054,
+		0x0000005C,
+		0x00000088,
+		0x0000008C,
+		0x000000C8,
+		0x000000CC,
+		0x00000110,
+		0x00000114,
+		0x00000118,
+		0x0000011C
+	}
+};
+
+/* Keeping all DDR area of 512MB accesible for inbound transaction */
+#define INBOUND_ADDR_MASK	0x1FFFFFFF
+
+
+#define PCIE_SETUP_iATU_IB_ENTRY( _pp, _view_port, _base, _limit, _ctl1, _ctl2, _target ) \
+{\
+	comcerto_dbi_write_reg(_pp, PCIE_iATU_VIEW_PORT, 4, (u32)(_view_port|iATU_VIEW_PORT_IN_BOUND)); \
+	comcerto_dbi_write_reg(_pp, PCIE_iATU_CTRL2, 4, 0); \
+	comcerto_dbi_write_reg(_pp, PCIE_iATU_SRC_LOW, 4, (u32)_base); \
+	comcerto_dbi_write_reg(_pp, PCIE_iATU_SRC_HIGH, 4, 0); \
+	comcerto_dbi_write_reg(_pp, PCIE_iATU_LIMIT, 4, (u32)((_base)+(_limit))); \
+	comcerto_dbi_write_reg(_pp, PCIE_iATU_TRGT_LOW, 4, (u32)_target); \
+	comcerto_dbi_write_reg(_pp, PCIE_iATU_TRGT_HIGH, 4, (u32)0); \
+	comcerto_dbi_write_reg(_pp, PCIE_iATU_CTRL1, 4, (u32)_ctl1); \
+	comcerto_dbi_write_reg(_pp, PCIE_iATU_CTRL2, 4, (u32)(_ctl2 |iATU_CTRL2_ID_EN) ); \
+}
+
+#define PCIE_SETUP_iATU_OB_ENTRY( _pp, _view_port, _base, _limit, _ctl1, _ctl2, _target ) \
+{\
+	comcerto_dbi_write_reg(_pp, PCIE_iATU_VIEW_PORT, 4, (u32)_view_port); \
+	comcerto_dbi_write_reg(_pp, PCIE_iATU_CTRL2, 4, 0); \
+	comcerto_dbi_write_reg(_pp, PCIE_iATU_SRC_LOW, 4, (u32)_base); \
+	comcerto_dbi_write_reg(_pp, PCIE_iATU_SRC_HIGH, 4, (u32)0); \
+	comcerto_dbi_write_reg(_pp, PCIE_iATU_LIMIT, 4, ((u32)((_base)+(_limit)))); \
+	comcerto_dbi_write_reg(_pp, PCIE_iATU_TRGT_LOW, 4, (u32)_target); \
+	comcerto_dbi_write_reg(_pp, PCIE_iATU_TRGT_HIGH, 4, (u32)0); \
+	comcerto_dbi_write_reg(_pp, PCIE_iATU_CTRL1, 4, (u32)_ctl1); \
+	comcerto_dbi_write_reg(_pp, PCIE_iATU_CTRL2, 4, (u32)(_ctl2 |iATU_CTRL2_ID_EN) ); \
+}
+
+#define MAX_LINK_UP_WAIT_JIFFIES	HZ /* 1 Second */
+
+static unsigned long pcie_cnf_base_addr[MAX_PCIE_PORTS] =
+		{ COMCERTO_AXI_PCIe0_BASE, COMCERTO_AXI_PCIe1_BASE };
+static unsigned long pcie_remote_base_addr[MAX_PCIE_PORTS] =
+		{ COMCERTO_AXI_PCIe0_SLAVE_BASE, COMCERTO_AXI_PCIe1_SLAVE_BASE };
+static int pcie_msi_base[MAX_PCIE_PORTS] =
+		{ PCIE0_MSI_INT_BASE, PCIE1_MSI_INT_BASE };
+static int pcie_intx_base[MAX_PCIE_PORTS] =
+		{ PCIE0_INTX_BASE, PCIE1_INTX_BASE };
+static int pcie_irqs[MAX_PCIE_PORTS] =
+		{ IRQ_PCIe0, IRQ_PCIe1 };
+
+
+static struct pcie_port pcie_port[MAX_PCIE_PORTS];
+
+static int pcie_port_is_host( int nr  )
+{
+	struct pcie_port *pp= &pcie_port[nr];
+
+	return ( pp->port_mode == PCIE_PORT_MODE_RC ) ? 1 : 0;
+}
+
+/**
+ * This function sets PCIe port mode.
+ */
+static void pcie_port_set_mode( int nr, int mode  )
+{
+	struct pcie_port *pp= &pcie_port[nr];
+
+	writel( (readl(pp->va_app_base + pp->app_regs->cfg0) & ~0xf) | mode, pp->va_app_base + pp->app_regs->cfg0);
+}
+
+/**
+ * This function returns the given port mode.
+ * @param nr	PCIe Port number.
+ */
+static int pcie_port_get_mode( int nr  )
+{
+	struct pcie_port *pp= &pcie_port[nr];
+
+	return ( readl(pp->va_app_base + pp->app_regs->cfg0) &
+			DWC_CFG0_DEV_TYPE_MASK );
+}
+
+/**
+ * This function checks whether link is up or not.
+ * Returns true if link is up otherwise returns false.
+ * @param pp	Pointer to PCIe Port control block.
+ */
+static int comcerto_pcie_link_up( struct pcie_port *pp  )
+{
+	unsigned long deadline = jiffies + MAX_LINK_UP_WAIT_JIFFIES;
+
+	do {
+		if (readl( pp->va_app_base + pp->app_regs->sts0 ) & STS0_RDLH_LINK_UP) {
+			return 1;
+		}
+
+		cond_resched();
+	} while (!time_after_eq(jiffies, deadline));
+
+	return 0;
+}
+
+/**
+ * bus_to_port().
+ *
+ */
+static struct pcie_port *bus_to_port(int bus)
+{
+	int i;
+
+	for (i = NUM_PCIE_PORTS - 1; i >= 0; i--) {
+		int rbus = pcie_port[i].root_bus_nr;
+		if ( !pcie_port_is_host(i) )
+			continue;
+		if (rbus != -1 && rbus <= bus)
+			break;
+	}
+
+	return i >= 0 ? pcie_port + i : NULL;
+}
+
+/**
+ * This function is used to read DBI registers.
+ */
+
+static void comcerto_dbi_read_reg(struct pcie_port *pp, int where, int size,
+		u32 *val)
+{
+	u32 va_address;
+
+	va_address = (u32)pp->va_dbi_base + (where & ~0x3);
+
+	*val = readl_relaxed(va_address);
+
+	if (size == 1)
+		*val = (*val >> (8 * (where & 3))) & 0xff;
+	else if (size == 2)
+		*val = (*val >> (8 * (where & 3))) & 0xffff;
+}
+
+/**
+ * This function is used to write into DBI registers.
+ */
+static void comcerto_dbi_write_reg(struct pcie_port *pp, int where, int size,
+		u32 val)
+{
+	u32 va_address;
+	int pos, val1, mask = 0;
+
+	va_address = (u32)pp->va_dbi_base + (where & ~0x3);
+
+	pos = (where & 0x3) << 3;
+
+	if (size == 4)
+		val1 = val;
+	else
+	{
+		if (size == 2)
+			mask = 0xffff;
+		else if (size == 1)
+			mask = 0xff;
+
+		val1 = readl_relaxed(va_address);
+		val1 = ( val1 & ~( mask  << pos ) ) | ( (val & mask) << pos );
+	}
+
+	writel_relaxed(val1, va_address);
+}
+
+static inline void nop_delay(void)
+{
+        int k;
+        for(k = 0 ; k < 1000; k++)
+                nop();
+}
+
+static int comcerto_pcie_rd_conf(struct pcie_port *pp, int bus_nr,
+		u32 devfn, int where, int size, u32 *val)
+{
+	u32 address;
+	u32 target_address = (u32)(bus_nr << 24) | (PCI_SLOT(devfn) << 19) | (PCI_FUNC(devfn) << 16);
+
+	/* Initialize iATU */
+	if (bus_nr != pp->root_bus_nr) {
+
+		if (pp->cfg1_prev_taddr != target_address) {
+			/* Type1 configuration request */
+			PCIE_SETUP_iATU_OB_ENTRY( pp, iATU_ENTRY_CNF1, (u32)iATU_GET_CFG1_BASE(pp->remote_mem_baseaddr),
+				iATU_CFG1_SIZE - 1, (AXI_OP_TYPE_CONFIG_RDRW_TYPE1 & iATU_CTRL1_TYPE_MASK),
+				0, target_address );
+			pp->cfg1_prev_taddr = target_address;
+		}
+
+		address = (u32)pp->va_cfg1_base |(where & 0xFFFC);
+	} else {
+		if (pp->cfg0_prev_taddr != target_address) {
+			/* Type0 configuration request */
+			PCIE_SETUP_iATU_OB_ENTRY( pp, iATU_ENTRY_CNF0, (u32)iATU_GET_CFG0_BASE(pp->remote_mem_baseaddr),
+				iATU_CFG0_SIZE - 1, (AXI_OP_TYPE_CONFIG_RDRW_TYPE0 & iATU_CTRL1_TYPE_MASK),
+				0, target_address );
+			pp->cfg0_prev_taddr = target_address;
+		}
+
+		address = (u32)pp->va_cfg0_base |(where & 0xFFFC);
+	}
+
+
+	*val = readl_relaxed(address);
+
+	/* Because of the imprecise external abort the processor is not able to get the exact instruction 
+           which caused the abort and hence when the abort handler tries to restore the PC to the next 
+           instruction to resume it is often wrong and it results in skipping few instruction after the 
+           readl_relaxed which has caused abort. So nop instructions are added after readl so that even 
+           if the some instructions are missed out it will miss the nop instruction only.
+	*/
+	nop_delay();
+
+	if (size == 1)
+		*val = (*val >> (8 * (where & 3))) & 0xff;
+	else if (size == 2)
+		*val = (*val >> (8 * (where & 3))) & 0xffff;
+
+#ifdef COMCERTO_PCIE_DEBUG
+	printk(KERN_DEBUG "%s: bus:%d dev:%d where:%d, size:%d addr : %x value:%x\n", __func__, bus_nr, devfn, where, size, address, *val);
+#endif
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pcie_read_conf(struct pci_bus *bus, u32 devfn, int where, int size, u32 *val)
+{
+	struct pcie_port *pp = bus_to_port(bus->number);
+	unsigned long flags;
+	int ret;
+
+
+#ifdef COMCERTO_PCIE_DEBUG
+	printk(KERN_DEBUG "%s: bus:%d dev:%d where:%d, size:%d\n", __func__, bus->number, devfn, where, size);
+#endif
+
+
+	/* Make sure that link is up.
+	 * Filter device numbers, unless it's a type1 access
+	 */
+	if ( (!pp->link_state)||
+			((bus->number == pp->root_bus_nr) && (PCI_SLOT(devfn) > 0)) ) {
+		*val = 0xffffffff;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+	BUG_ON (((where & 0x3) + size) > 4);
+
+	/* Enter critical section. */
+	spin_lock_irqsave(&pp->conf_lock, flags);
+	ret = comcerto_pcie_rd_conf(pp, bus->number, devfn, where, size, val);
+	/* Exit critical section. */
+	spin_unlock_irqrestore(&pp->conf_lock, flags);
+
+	return ret;
+}
+
+static int comcerto_pcie_wr_conf(struct pcie_port *pp, int bus_nr,
+		u32 devfn, int where, int size, u32 val)
+{
+	int ret = PCIBIOS_SUCCESSFUL;
+	u32 address;
+	u32 target_address = (u32)(bus_nr << 24) | (PCI_SLOT(devfn) << 19) | (PCI_FUNC(devfn) << 16);
+
+	/* Initialize iATU */
+	if (bus_nr != pp->root_bus_nr) {
+		if (pp->cfg1_prev_taddr != target_address) {
+			/* Type1 configuration request */
+			PCIE_SETUP_iATU_OB_ENTRY( pp, iATU_ENTRY_CNF1, (u32)iATU_GET_CFG1_BASE(pp->remote_mem_baseaddr),
+				iATU_CFG1_SIZE - 1, (AXI_OP_TYPE_CONFIG_RDRW_TYPE1 & iATU_CTRL1_TYPE_MASK),
+				0, target_address );
+			pp->cfg1_prev_taddr = target_address;
+		}
+
+		address = (u32)pp->va_cfg1_base |(where & 0xFFFC);
+	} else {
+		if (pp->cfg0_prev_taddr != target_address) {
+			/* Type0 configuration request */
+			PCIE_SETUP_iATU_OB_ENTRY( pp, iATU_ENTRY_CNF0, (u32)iATU_GET_CFG0_BASE(pp->remote_mem_baseaddr),
+				iATU_CFG0_SIZE - 1, (AXI_OP_TYPE_CONFIG_RDRW_TYPE0 & iATU_CTRL1_TYPE_MASK),
+				0, target_address );
+			pp->cfg0_prev_taddr = target_address;
+		}
+
+		address = (u32)pp->va_cfg0_base |(where & 0xFFFC);
+	}
+
+
+#ifdef COMCERTO_PCIE_DEBUG
+	printk(KERN_DEBUG "%s: bus:%d dev:%d where:%d, size:%d addr : %x value:%x\n", __func__, bus_nr, devfn, where, size, address, val);
+#endif
+	if (size == 4)
+		writel_relaxed(val, address);
+	else if (size == 2)
+		writew_relaxed(val, address + (where & 2));
+	else if (size == 1)
+		writeb_relaxed(val, address + (where & 3));
+	else
+		ret = PCIBIOS_BAD_REGISTER_NUMBER;
+
+	return ret;
+}
+
+static int pcie_write_conf(struct pci_bus *bus, u32 devfn, int where, int size, u32 val)
+{
+	struct pcie_port *pp = bus_to_port(bus->number);
+	unsigned long flags;
+	int ret;
+
+#ifdef COMCERTO_PCIE_DEBUG
+	printk(KERN_DEBUG "%s: bus:%d dev:%d where:%d, size:%d val:%d\n", __func__, bus->number, devfn, where, size, val);
+#endif
+
+	/* Make sure that link is up.
+	 * Filter device numbers, unless it's a type1 access
+	 */
+	if ( (!pp->link_state)||
+			((bus->number == pp->root_bus_nr) && (PCI_SLOT(devfn) > 0)) ) {
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+	BUG_ON (((where & 0x3) + size) > 4);
+
+	/* Enter critical section. */
+	spin_lock_irqsave(&pp->conf_lock, flags);
+	ret = comcerto_pcie_wr_conf(pp, bus->number, devfn, where, size, val);
+	if (where == PCI_COMMAND)
+		pp->cmd_reg_val = val & 0xffff;
+	/* Exit critical section. */
+	spin_unlock_irqrestore(&pp->conf_lock, flags);
+
+	return ret;
+}
+
+
+
+static u8 __init comcerto_pcie_swizzle(struct pci_dev *dev, u8 *pin)
+{
+	return PCI_SLOT(dev->devfn);
+}
+
+static int __init comcerto_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+	struct pcie_port *pp = bus_to_port(dev->bus->number);
+	int irq = (PCIE0_INTX_BASE + pp->port * PCIE_NUM_INTX_IRQS + pin - 1);
+
+	return irq;
+}
+
+static int __init comcerto_pcie_setup(int nr, struct pci_sys_data *sys)
+{
+	struct pcie_port *pp;
+	struct pcie_app_reg *app_reg;
+	u32 val;
+
+
+	if ((nr >= NUM_PCIE_PORTS) || !pcie_port_is_host(nr))
+		return 0;
+
+#ifdef COMCERTO_PCIE_DEBUG
+	printk(KERN_DEBUG "%s:%d nr:%d\n", __func__, __LINE__, nr);
+#endif
+
+
+	pp = &pcie_port[nr];
+
+	if (!pp->link_state)
+		return 0;
+
+	pp->root_bus_nr = sys->busnr;
+	app_reg = pp->app_regs;
+
+	/* Allocate device memory mapped and IO mapped regions */
+	snprintf(pp->mem_space_name, sizeof(pp->mem_space_name),
+			"PCIe %d MEM", pp->port);
+	pp->mem_space_name[sizeof(pp->mem_space_name) - 1] = 0;
+	pp->res[0].name = pp->mem_space_name;
+	pp->res[0].start = iATU_GET_MEM_BASE(pp->remote_mem_baseaddr);
+	pp->res[0].end = pp->res[0].start + iATU_MEM_SIZE - 1;
+	pp->res[0].flags = IORESOURCE_MEM;
+
+	snprintf(pp->io_space_name, sizeof(pp->io_space_name),
+			"PCIe %d I/O", pp->port);
+	pp->io_space_name[sizeof(pp->io_space_name) - 1] = 0;
+	pp->res[1].name = pp->io_space_name;
+	pp->res[1].start = iATU_GET_IO_BASE(pp->remote_mem_baseaddr);
+	pp->res[1].end = pp->res[1].start + iATU_IO_SIZE - 1;
+	pp->res[1].flags = IORESOURCE_IO;
+
+
+	if (request_resource(&iomem_resource, &pp->res[0]))
+	{
+		printk(KERN_ERR "%s:can't allocate PCIe Memory space", __func__);
+		return 0;
+	}
+
+	if (request_resource(&iomem_resource, &pp->res[1]))
+	{
+		printk(KERN_ERR "%s:can't allocate PCIe IO space", __func__);
+		return 0;
+	}
+
+	/* Generic PCIe unit setup.*/
+
+	/* Enable own BME. It is necessary to enable own BME to do a
+	 * memory transaction on a downstream device
+	 */
+	comcerto_dbi_read_reg(pp, PCI_COMMAND, 2, &val);
+	val |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER
+			| PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+	comcerto_dbi_write_reg(pp, PCI_COMMAND, 2, val);
+
+	/* Need to come back here*/
+
+	sys->resource[0] = &pp->res[0];
+	sys->resource[1] = &pp->res[1];
+	sys->resource[2] = NULL;
+
+	pp->cfg0_prev_taddr = 0xffffffff;
+	pp->cfg1_prev_taddr = 0xffffffff;
+
+	return 1;
+}
+
+static struct pci_ops pcie_ops = {
+	.read = pcie_read_conf,
+	.write = pcie_write_conf,
+};
+
+static struct pci_bus *__init comcerto_pcie_scan_bus(int nr, struct pci_sys_data *sys)
+{
+	struct pci_bus *bus;
+
+	if ((nr < NUM_PCIE_PORTS) && (pcie_port_is_host(nr))) {
+
+		bus = pci_scan_bus(sys->busnr, &pcie_ops, sys);
+	} else {
+		bus = NULL;
+		BUG();
+	}
+
+	return bus;
+}
+
+static struct hw_pci comcerto_pcie __initdata = {
+	.nr_controllers	= NUM_PCIE_PORTS,
+	.swizzle = comcerto_pcie_swizzle,
+	.map_irq = comcerto_pcie_map_irq,
+	.setup = comcerto_pcie_setup,
+	.scan = comcerto_pcie_scan_bus,
+};
+
+
+
+#ifdef CONFIG_PCI_MSI
+/* MSI int handler
+ */
+static void handle_msi(struct pcie_port *pp)
+{
+	unsigned long val, mask;
+	unsigned int pos, mask0;
+
+
+	val = readl_relaxed(pp->va_dbi_base + PCIE_MSI_INTR0_STATUS);
+
+continue_handle:
+
+	pos = 0;
+
+	while (val) {
+		mask0 = 1 << pos;
+
+		if (val & mask0) {
+			/* FIXME : WA for bz69520
+			 * To avoid race condition during avk the interrupt disabling interrupt before
+			 * Ack and enabling after Ack.
+			 */
+			spin_lock(&pp->intr_lock);
+			mask = readl_relaxed(pp->va_dbi_base + PCIE_MSI_INTR0_ENABLE);
+			writel_relaxed(mask & ~mask0, pp->va_dbi_base + PCIE_MSI_INTR0_ENABLE);
+			writel_relaxed(mask0, pp->va_dbi_base + PCIE_MSI_INTR0_STATUS);
+			writel_relaxed(mask, pp->va_dbi_base + PCIE_MSI_INTR0_ENABLE);
+			spin_unlock(&pp->intr_lock);
+			generic_handle_irq(pp->msi_base	+ pos);
+			val = val & ~mask0;
+		}
+		pos++;
+	}
+
+	val = readl_relaxed(pp->va_dbi_base + PCIE_MSI_INTR0_STATUS);
+	if(val)
+		goto continue_handle;
+
+#if 0
+	for (i = 0; i < (PCIE_NUM_MSI_IRQS >> 5); i++) {
+		val = readl_relaxed(pp->va_dbi_base + PCIE_MSI_INTR0_STATUS + (i * 12));
+		if (val) {
+			pos = 0;
+			while ((pos = find_next_bit(&val, 32, pos)) != 32) {
+				/* FIXME : WA for bz69520
+				 * To avoid race condition during avk the interrupt disabling interrupt before
+				 * Ack and enabling after Ack.
+				 */
+				spin_lock(&pp->intr_lock);
+				mask = readl_relaxed(pp->va_dbi_base + PCIE_MSI_INTR0_ENABLE + (i * 12));
+				writel_relaxed(mask & ~(1 << pos), pp->va_dbi_base + PCIE_MSI_INTR0_ENABLE + (i * 12));
+				writel_relaxed((1 << pos), pp->va_dbi_base + PCIE_MSI_INTR0_STATUS + (i * 12));
+				writel_relaxed(mask & (1 << pos), pp->va_dbi_base + PCIE_MSI_INTR0_ENABLE + (i * 12));
+				spin_unlock(&pp->intr_lock);
+				generic_handle_irq(pp->msi_base	+ (i * 32) + pos);
+				pos++;
+			}
+		}
+	}
+#endif
+}
+#else
+static void handle_msi(struct pcie_port *pp)
+{
+}
+#endif
+
+static void comcerto_pcie_int_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct pcie_port *pp = irq_get_handler_data(irq);
+	struct pcie_app_reg *app_reg = pp->app_regs;
+	struct irq_chip *chip;
+	unsigned int status;
+	int pos, ii;
+
+	chip = irq_desc_get_chip(desc);
+	chained_irq_enter(chip, desc);
+	status = readl_relaxed(pp->va_app_base + app_reg->intr_sts);
+
+	if (status & INTR_CTRL_MSI) {
+		writel_relaxed(INTR_CTRL_MSI, (pp->va_app_base + app_reg->intr_sts));
+		status &= ~(INTR_CTRL_MSI);
+		handle_msi(pp);
+	}
+
+	for (ii = 0; (ii < PCIE_NUM_INTX_IRQS) && status; ii++) {
+		pos = ii << 1;
+
+		/* Handle INTx Assert */
+		if (status & (INTR_CTRL_INTA_ASSERT << pos)) {
+			status &= ~(INTR_CTRL_INTA_ASSERT << pos);
+			writel_relaxed((INTR_CTRL_INTA_ASSERT << pos), (pp->va_app_base + app_reg->intr_sts));
+			generic_handle_irq(pp->intx_base + ii);
+		}
+
+		/*FIXME : No need to handle DEASSERT, simply clear the interrupt */
+		status &= ~(INTR_CTRL_INTA_DEASSERT << pos);
+#if 0
+		/* Handle INTx Deasert */
+		if (status & (INTR_CTRL_INTA_DEASSERT << pos)) {
+			status &= ~(INTR_CTRL_INTA_DEASSERT << pos);
+			writel_relaxed((INTR_CTRL_INTA_DEASSERT << pos), (pp->va_app_base + app_reg->intr_sts));
+		}
+#endif
+	}
+
+	if (status) {
+		printk(KERN_INFO "%s:Unhandled interrupt %x\n", __func__, status);
+		/* FIXME: HP, AER, PME interrupts need to be handled */
+		writel_relaxed(status, (pp->va_app_base + app_reg->intr_sts));
+	}
+
+	chained_irq_exit(chip, desc);
+}
+
+
+static void pcie_nop_intx_irq(struct irq_data *data )
+{
+	return;
+}
+
+static void pcie_unmask_intx_irq( struct irq_data *data )
+{
+	struct pcie_port *pp = data->chip_data;
+
+	spin_lock(&pp->conf_lock);
+	comcerto_pcie_wr_conf(pp, pp->root_bus_nr, 0, PCI_COMMAND, 2, (pp->cmd_reg_val & ~PCI_COMMAND_INTX_DISABLE));
+	spin_unlock(&pp->conf_lock);
+}
+
+static void pcie_enable_intx_irq( struct irq_data *data )
+{
+	int irq = data->irq;
+	struct pcie_port *pp = data->chip_data;
+	int irq_offset = irq - pp->intx_base;
+	struct pcie_app_reg *app_reg = (struct pcie_app_reg *)pp->app_regs;
+	unsigned long flags;
+
+	if( irq_offset >= PCIE_NUM_INTX_IRQS )
+		return;
+
+	/*
+	 * In interrupt sts/mask register each interrupt has two
+	 * consecutive bits, one for assert and another for dessert.
+	 */
+	irq_offset = irq_offset << 1;
+
+	spin_lock_irqsave(&pp->intr_lock, flags);
+	writel_relaxed(readl_relaxed(pp->va_app_base + app_reg->intr_en) | ( INTR_CTRL_INTA_ASSERT << irq_offset),
+			(pp->va_app_base + app_reg->intr_en) );
+	spin_unlock_irqrestore(&pp->intr_lock, flags);
+}
+
+static void pcie_mask_intx_irq( struct irq_data *data )
+{
+	struct pcie_port *pp = data->chip_data;
+
+	spin_lock(&pp->conf_lock);
+	comcerto_pcie_wr_conf(pp, pp->root_bus_nr, 0, PCI_COMMAND, 2, (pp->cmd_reg_val | PCI_COMMAND_INTX_DISABLE));
+	spin_unlock(&pp->conf_lock);
+}
+
+static void pcie_disable_intx_irq( struct irq_data *data )
+{
+	int irq = data->irq;
+	struct pcie_port *pp = data->chip_data;
+	int irq_offset = irq - pp->intx_base;
+	struct pcie_app_reg *app_reg = (struct pcie_app_reg *)pp->app_regs;
+	unsigned long flags;
+
+	if( irq_offset >= PCIE_NUM_INTX_IRQS )
+		return;
+
+	/*
+	 * In interrupt sts/mask register each interrupt has two
+	 * consecutive bits, one for assert and another for dessert.
+	 */
+	irq_offset = irq_offset << 1;
+
+	spin_lock_irqsave(&pp->intr_lock, flags);
+	writel_relaxed( readl_relaxed(pp->va_app_base + app_reg->intr_en) & ~( INTR_CTRL_INTA_ASSERT << irq_offset),
+			(pp->va_app_base + app_reg->intr_en) );
+	spin_unlock_irqrestore(&pp->intr_lock, flags);
+}
+
+static struct irq_chip pcie_intx_chip = {
+	.name = "PCIe INTx",
+	.irq_ack = pcie_nop_intx_irq,
+	.irq_enable = pcie_enable_intx_irq,
+	.irq_disable = pcie_disable_intx_irq,
+	.irq_mask = pcie_mask_intx_irq,
+	.irq_unmask = pcie_unmask_intx_irq,
+};
+
+static int comcerto_pcie_intx_init(struct pcie_port *pp)
+{
+	int i, irq;
+	struct pcie_app_reg *app_reg;
+
+	/* Disable INTX interrupt*/
+	app_reg = pp->app_regs;
+
+	writel(readl(pp->va_app_base + app_reg->intr_en) &
+			~(INTR_CTRL_INTA_ASSERT |
+				INTR_CTRL_INTB_ASSERT |
+				INTR_CTRL_INTC_ASSERT |
+				INTR_CTRL_INTD_ASSERT),
+			pp->va_app_base + app_reg->intr_en );
+
+	/* initilize INTX chip here only. MSI chip will be
+	 * initilized dynamically.*/
+	irq = pp->intx_base;
+	for (i = 0; i < PCIE_NUM_INTX_IRQS; i++) {
+		irq_set_chip_data(irq + i, pp);
+		irq_set_chip_and_handler(irq + i, &pcie_intx_chip,
+				handle_level_irq);
+		set_irq_flags(irq + i, IRQF_VALID);
+	}
+
+	irq_set_handler_data(pp->irq, pp);
+	irq_set_chained_handler(pp->irq, comcerto_pcie_int_handler);
+
+	/* FIXME Added for debuging */
+	writel(readl(pp->va_app_base + app_reg->intr_en) &
+			~(INTR_CTRL_AER |  INTR_CTRL_PME |
+ 			 INTR_CTRL_HP  |  INTR_CTRL_LINK_AUTO_BW ),
+			pp->va_app_base + app_reg->intr_en );
+
+
+	return 0;
+}
+
+static int comcerto_pcie_rc_int_init( struct pcie_port *pp )
+{
+
+	printk(KERN_INFO "%s\n",__func__);
+
+	comcerto_pcie_intx_init(pp);
+
+#ifdef CONFIG_PCI_MSI
+	comcerto_msi_init(pp);
+#endif
+
+	return 0;
+}
+
+#ifdef CONFIG_PCI_MSI
+static int find_valid_pos0(int port, int nvec, int pos, int *pos0)
+{
+	int flag = 1;
+	do {
+		pos = find_next_zero_bit(msi_irq_in_use[port],
+				PCIE_NUM_MSI_IRQS, pos);
+		/*if you have reached to the end then get out from here.*/
+		if (pos == PCIE_NUM_MSI_IRQS)
+			return -ENOSPC;
+		/* Check if this position is at correct offset.nvec is always a
+		 * power of two. pos0 must be nvec bit alligned.
+		 */
+		if (pos % nvec)
+			pos += nvec - (pos % nvec);
+		else
+			flag = 0;
+	} while (flag);
+
+	*pos0 = pos;
+	return 0;
+}
+
+#define GET_MSI_INT_REG_POS(_irq) ((_irq >> 5) * 12)
+#define GET_MSI_INT_OFST(_irq) (_irq & 0x1F)
+
+static void comcerto_msi_nop(struct irq_data *data)
+{
+	return;
+}
+
+static void comcerto_msi_unmask(struct irq_data *data)
+{
+	struct pcie_port *pp = data->chip_data;
+	int irq = data->irq - pp->msi_base;
+	int ofst, pos;
+	unsigned int val;
+	unsigned long flags;
+
+	if( irq >= PCIE_NUM_MSI_IRQS )
+		return;
+
+	pos = GET_MSI_INT_REG_POS(irq);
+	ofst = GET_MSI_INT_OFST(irq);
+#ifdef COMCERTO_PCIE_DEBUG
+	printk(KERN_DEBUG "%s: %x:%x\n",__func__, pos, ofst);
+#endif
+
+	spin_lock_irqsave(&pp->intr_lock, flags);
+	comcerto_dbi_read_reg(pp, PCIE_MSI_INTR0_MASK + pos, 4, &val);
+	val &= ~(1 << ofst);
+	comcerto_dbi_write_reg(pp, PCIE_MSI_INTR0_MASK + pos, 4, val);
+	spin_unlock_irqrestore(&pp->intr_lock, flags);
+
+	return;
+}
+
+static void comcerto_msi_mask(struct irq_data *data)
+{
+	struct pcie_port *pp = data->chip_data;
+	int irq = data->irq - pp->msi_base;
+	int ofst, pos;
+	unsigned int val;
+	unsigned long flags;
+
+	if( irq >= PCIE_NUM_MSI_IRQS )
+		return;
+
+	pos = GET_MSI_INT_REG_POS(irq);
+	ofst = GET_MSI_INT_OFST(irq);
+#ifdef COMCERTO_PCIE_DEBUG
+	printk(KERN_DEBUG "%s: %x:%x\n",__func__, pos, ofst);
+#endif
+
+	spin_lock_irqsave(&pp->intr_lock, flags);
+	comcerto_dbi_read_reg(pp, PCIE_MSI_INTR0_MASK + pos, 4, &val);
+	val |= (1 << ofst);
+	comcerto_dbi_write_reg(pp, PCIE_MSI_INTR0_MASK + pos, 4, val);
+	spin_unlock_irqrestore(&pp->intr_lock, flags);
+
+	return;
+}
+
+
+static void comcerto_msi_enable(struct irq_data *data)
+{
+	struct pcie_port *pp = data->chip_data;
+	int irq = data->irq - pp->msi_base;
+	int ofst, pos;
+	unsigned int val;
+	unsigned long flags;
+
+	if( irq >= PCIE_NUM_MSI_IRQS )
+		return;
+
+	pos = GET_MSI_INT_REG_POS(irq);
+	ofst = GET_MSI_INT_OFST(irq);
+
+#ifdef COMCERTO_PCIE_DEBUG
+	printk(KERN_DEBUG "%s: %x:%x\n",__func__, pos, ofst);
+#endif
+
+	spin_lock_irqsave(&pp->intr_lock, flags);
+	comcerto_dbi_read_reg(pp, PCIE_MSI_INTR0_ENABLE + pos, 4, &val);
+	val |= (1 << ofst);
+	comcerto_dbi_write_reg(pp, PCIE_MSI_INTR0_ENABLE + pos, 4, val);
+	spin_unlock_irqrestore(&pp->intr_lock, flags);
+
+	return;
+}
+
+
+static void comcerto_msi_disable(struct irq_data *data)
+{
+	struct pcie_port *pp = data->chip_data;
+	int irq = data->irq - pp->msi_base;
+	int ofst, pos;
+	unsigned int val;
+	unsigned long flags;
+
+	if( irq >= PCIE_NUM_MSI_IRQS )
+		return;
+
+	pos = GET_MSI_INT_REG_POS(irq);
+	ofst = GET_MSI_INT_OFST(irq);
+#ifdef COMCERTO_PCIE_DEBUG
+	printk(KERN_DEBUG "%s: %x:%x\n",__func__, pos, ofst);
+#endif
+
+	spin_lock_irqsave(&pp->intr_lock, flags);
+	comcerto_dbi_read_reg(pp, PCIE_MSI_INTR0_ENABLE + pos, 4, &val);
+	val &= ~(1 << ofst);
+	comcerto_dbi_write_reg(pp, PCIE_MSI_INTR0_ENABLE + pos, 4, val);
+	spin_unlock_irqrestore(&pp->intr_lock, flags);
+
+	return;
+}
+
+static struct irq_chip comcerto_msi_chip = {
+	.name = "PCI-MSI",
+	.irq_ack = comcerto_msi_nop,
+	.irq_enable = comcerto_msi_enable,
+	.irq_disable = comcerto_msi_disable,
+	.irq_mask = comcerto_msi_mask,
+	.irq_unmask = comcerto_msi_unmask,
+};
+
+/*
+ * Dynamic irq allocate and deallocation
+ */
+static int get_irq(int nvec, struct msi_desc *desc, int *pos)
+{
+	int irq, pos0, pos1, i;
+	struct pcie_port *pp = bus_to_port(desc->dev->bus->number);
+
+	pos0 = find_first_zero_bit(msi_irq_in_use[pp->port],
+			PCIE_NUM_MSI_IRQS);
+	if (pos0 % nvec) {
+		if (find_valid_pos0(pp->port, nvec, pos0, &pos0))
+			goto no_valid_irq;
+	}
+	if (nvec > 1) {
+		pos1 = find_next_bit(msi_irq_in_use[pp->port],
+				PCIE_NUM_MSI_IRQS, pos0);
+		/* there must be nvec number of consecutive free bits */
+		while ((pos1 - pos0) < nvec) {
+			if (find_valid_pos0(pp->port, nvec, pos1, &pos0))
+				goto no_valid_irq;
+			pos1 = find_next_bit(msi_irq_in_use[pp->port],
+					PCIE_NUM_MSI_IRQS, pos0);
+		}
+	}
+
+	irq = pp->msi_base + pos0;
+
+	if ((irq + nvec) > (pp->msi_base + PCIE_NUM_MSI_IRQS))
+		goto no_valid_irq;
+
+	i = 0;
+	while (i < nvec) {
+		set_bit(pos0 + i, msi_irq_in_use[pp->port]);
+		dynamic_irq_init(irq + i);
+		irq_set_chip_data(irq + i, pp);
+		irq_set_chip_and_handler(irq + i, &comcerto_msi_chip,
+				handle_simple_irq);
+		set_irq_flags(irq + i, IRQF_VALID);
+		i++;
+	}
+
+	irq_set_msi_desc(irq, desc);
+
+	*pos = pos0;
+	return irq;
+no_valid_irq:
+	printk(KERN_ERR "%s : MSI interrupt allocate failed\n", __func__);
+	*pos = pos0;
+	return -ENOSPC;
+}
+
+static void clean_irq(unsigned int irq)
+{
+	int res, bit, val, pos;
+	struct irq_data *data = irq_get_irq_data(irq);
+	struct pcie_port *pp = data->chip_data;
+	unsigned long flags;
+
+	if( !pp )
+		return;
+
+	pos = irq - pp->msi_base;
+
+	dynamic_irq_cleanup(irq);
+
+	spin_lock_irqsave(&pp->msi_map_lock, flags);
+	clear_bit(pos, msi_irq_in_use[pp->port]);
+
+	/* Disable corresponding interrupt on MSI interrupt
+	 * controller.
+	 */
+	res = (pos / 32) * 12;
+	bit = pos % 32;
+	comcerto_dbi_read_reg(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
+	val &= ~(1 << bit);
+	comcerto_dbi_write_reg(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+	spin_unlock_irqrestore(&pp->msi_map_lock, flags);
+
+}
+
+int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
+{
+	int irq, pos;
+	struct msi_msg msg;
+	struct pcie_port *pp = bus_to_port(pdev->bus->number);
+	unsigned long flags;
+
+	spin_lock_irqsave(&pp->msi_map_lock, flags);
+	irq = get_irq(1, desc, &pos);
+	spin_unlock_irqrestore(&pp->msi_map_lock, flags);
+
+
+	if (irq < 0)
+		return irq;
+
+	desc->msi_attrib.multiple = 0;
+
+	/* An EP will modify lower 8 bits(max) of msi data while
+	 * sending any msi interrupt
+	 */
+	msg.address_hi = 0x0;
+	msg.address_lo = pp->msi_mbox_handle;
+	msg.data = pos;
+	write_msi_msg(irq, &msg);
+
+	return 0;
+}
+
+void arch_teardown_msi_irq(unsigned int irq)
+{
+	clean_irq(irq);
+}
+
+static int comcerto_msi_init(struct pcie_port *pp)
+{
+	struct pcie_app_reg *app_reg = (struct pcie_app_reg *)pp->app_regs;
+
+	pp->msi_mbox_baseaddr = dma_alloc_coherent(NULL, sizeof(u32), &pp->msi_mbox_handle, GFP_KERNEL);
+	if (!pp->msi_mbox_baseaddr) {
+		printk(KERN_ERR "PCIe(%d): failed to allocate msi mailbox coherent memory\n", pp->port);
+		goto err;
+	}
+
+	comcerto_dbi_write_reg(pp, PCIE_MSI_ADDR_LO, 4, pp->msi_mbox_handle);
+	comcerto_dbi_write_reg(pp, PCIE_MSI_ADDR_HI, 4, 0);
+	/* Enbale MSI interrupt*/
+	writel(readl(pp->va_app_base + app_reg->intr_en) | INTR_CTRL_MSI,
+			pp->va_app_base + app_reg->intr_en);
+	return 0;
+
+err:
+	return -1;
+}
+#endif
+
+static void comcerto_pcie_rc_init(struct pcie_port *pp)
+{
+	struct pcie_app_reg *app_reg = pp->app_regs;
+	unsigned int val;
+
+
+	//FIXME : Bit:27 definition is not clear from document
+	//	  This register setting is copied from simulation code.
+	writel(readl(pp->va_app_base + app_reg->cfg0) | 0x08007FF0,
+			pp->va_app_base + app_reg->cfg0);
+
+
+	/**
+	 *FIXME : Bit:15 definition is not clear from document
+	 *	  This register setting is copied from simulation code.
+	 */
+	writel(readl(pp->va_app_base + app_reg->cfg4) | 0x00008000,
+			pp->va_app_base + app_reg->cfg4);
+
+	comcerto_dbi_read_reg(pp, PCIE_AFL0L1_REG, 4, &val);
+	val &= ~(0x00FFFF00);
+	val |= 0x00F1F100;
+	comcerto_dbi_write_reg(pp, PCIE_AFL0L1_REG, 4, val);
+
+	if(pcie_gen1_only)
+	{
+		comcerto_dbi_write_reg(pp, PCIE_LCNT2_REG, 4, 0x1);
+		comcerto_dbi_write_reg(pp, PCIE_LCAP_REG, 4, 0x1);
+	}
+	else
+	{
+		comcerto_dbi_read_reg(pp, PCIE_G2CTRL_REG, 4, &val);
+		val &= ~(0xFF);
+		val |= 0xF1;
+		comcerto_dbi_write_reg(pp, PCIE_G2CTRL_REG, 4, val);
+
+		// instruct pcie to switch to gen2 after init
+		comcerto_dbi_read_reg(pp, PCIE_G2CTRL_REG, 4, &val);
+		val |= (1 << 17);
+		comcerto_dbi_write_reg(pp, PCIE_G2CTRL_REG, 4, val);
+	}
+
+	/*setup iATU for outbound translation */
+	PCIE_SETUP_iATU_OB_ENTRY( pp, iATU_ENTRY_MEM, iATU_GET_MEM_BASE(pp->remote_mem_baseaddr),
+			iATU_MEM_SIZE - 1, 0, 0, pp->remote_mem_baseaddr );
+	PCIE_SETUP_iATU_OB_ENTRY( pp, iATU_ENTRY_IO, iATU_GET_IO_BASE(pp->remote_mem_baseaddr),
+			iATU_IO_SIZE - 1, (AXI_OP_TYPE_IO_RDRW & iATU_CTRL1_TYPE_MASK),
+			0, iATU_GET_IO_BASE(pp->remote_mem_baseaddr) );
+	PCIE_SETUP_iATU_OB_ENTRY( pp, iATU_ENTRY_MSG, iATU_GET_MSG_BASE(pp->remote_mem_baseaddr),
+			iATU_MSG_SIZE - 1, (AXI_OP_TYPE_MSG_REQ & iATU_CTRL1_TYPE_MASK),
+			0, iATU_GET_MSG_BASE(pp->remote_mem_baseaddr) );
+	PCIE_SETUP_iATU_IB_ENTRY( pp, 0, 0,
+			INBOUND_ADDR_MASK, 0, 0, COMCERTO_AXI_DDR_BASE);
+
+}
+
+static int pcie_app_init(struct pcie_port *pp, int nr, int mode)
+{
+
+	if (nr > MAX_PCIE_PORTS) {
+		printk(KERN_ERR "%s: Invalid port\n", __func__);
+		goto err0;
+	}
+
+	if (mode != CFG0_DEV_TYPE_RC) {
+		printk(KERN_ERR "%s: Unsupported mode selected mode: %d. \n", __func__, mode);
+		goto err0;
+	}
+
+        memset(pp, 0, sizeof(struct pcie_port));
+
+	pp->port = nr;
+        pp->app_regs = &app_regs[nr];
+        pp->root_bus_nr = nr;
+        pp->base = pcie_cnf_base_addr[nr];
+        pp->app_base = (unsigned long)COMCERTO_APB_PCI_SATA_USB_CTRL_BASE;
+	pp->va_app_base = (void __iomem *)APB_VADDR(COMCERTO_APB_PCI_SATA_USB_CTRL_BASE);
+        pp->remote_mem_baseaddr = pcie_remote_base_addr[nr];
+
+	if (!nr)
+		pp->va_dbi_base = (void __iomem *) COMCERTO_AXI_PCIe0_VADDR_BASE;
+	else
+		pp->va_dbi_base = (void __iomem *) COMCERTO_AXI_PCIe1_VADDR_BASE;
+
+	pp->va_cfg0_base = (void __iomem *)
+		ioremap( iATU_GET_CFG0_BASE(pp->remote_mem_baseaddr), iATU_CFG0_SIZE);
+	if (!pp->va_cfg0_base) {
+		pr_err("error with ioremap in function %s\n", __func__);
+		goto err0;
+	}
+	pp->va_cfg1_base = (void __iomem *)
+		ioremap( iATU_GET_CFG1_BASE(pp->remote_mem_baseaddr) , iATU_CFG1_SIZE);
+	if (!pp->va_cfg1_base) {
+		pr_err("error with ioremap in function %s\n", __func__);
+		goto err1;
+	}
+
+	pp->intx_base = pcie_intx_base[nr];
+	pp->msi_base = pcie_msi_base[nr];
+	pp->irq = pcie_irqs[nr];
+	spin_lock_init(&pp->conf_lock);
+	spin_lock_init(&pp->intr_lock);
+	spin_lock_init(&pp->msi_map_lock);
+	memset(pp->res, 0, sizeof(pp->res));
+
+	/* Get the reference clock to PCIe port*/
+	switch (nr) {
+		case 0:
+			pp->ref_clock = clk_get(NULL, "pcie0");
+			break;
+		case 1:
+			pp->ref_clock = clk_get(NULL, "pcie1");
+			break;
+		default:
+			printk(KERN_ERR "%s: Invalid port\n", __func__);
+			goto err2;
+	}
+	if (IS_ERR(pp->ref_clock)) {
+		pr_err("%s: Unable to obtain pcie%d clock: %ld\n", __func__, nr, PTR_ERR(pcie_port[nr].ref_clock));
+		goto err2;
+	}
+
+	/* Enable the PCIE_OCC clock */
+#if defined(CONFIG_COMCERTO_PCIE_OCC_CLOCK)
+	pp->occ_clock = clk_get(NULL,"pcie_occ");
+	if (IS_ERR(pp->occ_clock)) {
+		pr_err("%s: Unable to obtain pcie_occ clock: %ld\n", __func__, PTR_ERR(pp->occ_clock));
+		goto err_occ_clock;
+	}
+#endif
+	pcie_port_set_mode(nr, mode);
+	
+	return 0;
+
+#if defined(CONFIG_COMCERTO_PCIE_OCC_CLOCK)
+err_occ_clock:
+	clk_put(pp->occ_clock);
+#endif
+
+err2:
+	iounmap(pp->va_cfg1_base);
+err1:
+	iounmap(pp->va_cfg0_base);
+err0:
+	return -1;
+
+}
+
+#if defined(CONFIG_C2K_EVM) || defined(CONFIG_C2K_ASIC)
+#define PCIE_DEV_EXT_RESET_DEASSERT(_id) \
+	writel(readl(COMCERTO_GPIO_OUTPUT_REG) & ~(GPIO_PIN_27), COMCERTO_GPIO_OUTPUT_REG);
+
+#define PCIE_DEV_EXT_RESET_ASSERT(_id) \
+	writel(readl(COMCERTO_GPIO_OUTPUT_REG) | (GPIO_PIN_27), COMCERTO_GPIO_OUTPUT_REG);
+#else
+/* Board specific */
+#define PCIE_DEV_EXT_RESET_DEASSERT(_id)
+#define PCIE_DEV_EXT_RESET_ASSERT(_id)
+#endif
+
+static int comcerto_pcie_device_reset(struct pcie_port *pp)
+{
+	int ii;
+	struct pcie_port *l_pp = pp;
+	struct pci_dev *pci_dev = NULL;
+
+	printk(KERN_INFO "ENTER: Bringing PCIe%d device reset\n", pp->port);
+	if (!pp->link_state)
+		return -1;
+
+	/* On C2KEVM and ASIC same reset is connected to PCIe0/1.
+         * So, device might have kept in reset, using other PCIe host.
+	 */
+	if (!comcerto_pcie_link_up(pp)) {
+		printk(KERN_INFO "%s : Device is already link down state\n", __func__);
+		return 0;
+	}
+
+
+	/*FIXME : Below code might be required if we want to reset pcie device, without
+         *        invoking pcie device supend. If we invoke pcie device suspend it will
+	 *	  take care of saving pcie config space.
+         */
+#if 0
+	/* Now save the PCIe device configuration space.*/
+	while((pci_dev = pci_get_subsys(PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, pci_dev))) {
+		if (pp->root_bus_nr == pci_dev->bus->number) {
+			pci_save_state(pci_dev);
+		}
+	}
+
+	/* On C2KEVM/ASIC, since same GPIO27 is used to reset PCIe0/PCIe1 devices,
+	 * save configuration of devices on other PCIe also.
+	 * This may not be applicable for other cutomer boards.
+	 */
+#if defined(CONFIG_C2K_EVM) || defined(CONFIG_C2K_ASIC)
+	l_pp = &pcie_port[!pp->port];
+	pci_dev = NULL;
+
+	if (l_pp->link_state) {
+		while((pci_dev = pci_get_subsys(PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, pci_dev))) {
+			if (l_pp->root_bus_nr == pci_dev->bus->number) {
+				pci_save_state(pci_dev);
+			}
+		}
+	}
+#endif
+#endif
+
+	/************** Ready to issue rest *****************/
+	/* De-assert external reset (GPIO-27) */
+	PCIE_DEV_EXT_RESET_DEASSERT(pp->port);
+	printk(KERN_INFO "EXIT: Bringing PCIe%d device reset\n", pp->port);
+
+	return 0;
+
+}
+
+
+static int comcerto_pcie_device_reset_exit(struct pcie_port *pp)
+{
+	unsigned int val;
+	struct pci_dev *pci_dev;
+
+	printk(KERN_INFO "ENTER: Bringing PCIe%d device out-of-reset\n", pp->port);
+
+	if (!pp->link_state && pp->reset)
+		return -1;
+
+	/* Pull up external reset */
+	/* assert external reset (GPIO-27) */
+	PCIE_DEV_EXT_RESET_ASSERT(pp->port);
+
+	udelay(1000);
+	udelay(1000);
+	udelay(1000);
+	udelay(1000);
+	udelay(1000);
+	udelay(1000);
+	udelay(1000);
+
+	/* Restore the RC configuration */
+	comcerto_dbi_read_reg(pp, PCIE_AFL0L1_REG, 4, &val);
+	val &= ~(0x00FFFF00);
+	val |= 0x00F1F100;
+	comcerto_dbi_write_reg(pp, PCIE_AFL0L1_REG, 4, val);
+
+	if(pcie_gen1_only)
+	{
+		comcerto_dbi_write_reg(pp, PCIE_LCNT2_REG, 4, 0x1);
+		comcerto_dbi_write_reg(pp, PCIE_LCAP_REG, 4, 0x1);
+	}
+	else
+	{
+		comcerto_dbi_read_reg(pp, PCIE_G2CTRL_REG, 4, &val);
+		val &= ~(0xFF);
+		val |= 0xF1;
+		comcerto_dbi_write_reg(pp, PCIE_G2CTRL_REG, 4, val);
+	}
+
+	// instruct pcie to switch to gen2 after init
+	comcerto_dbi_read_reg(pp, PCIE_G2CTRL_REG, 4, &val);
+	val |= (1 << 17);
+	comcerto_dbi_write_reg(pp, PCIE_G2CTRL_REG, 4, val);
+
+	/*setup iATU for outbound translation */
+	PCIE_SETUP_iATU_OB_ENTRY( pp, iATU_ENTRY_MEM, iATU_GET_MEM_BASE(pp->remote_mem_baseaddr),
+			iATU_MEM_SIZE - 1, 0, 0, pp->remote_mem_baseaddr );
+	PCIE_SETUP_iATU_OB_ENTRY( pp, iATU_ENTRY_IO, iATU_GET_IO_BASE(pp->remote_mem_baseaddr),
+			iATU_IO_SIZE - 1, (AXI_OP_TYPE_IO_RDRW & iATU_CTRL1_TYPE_MASK),
+			0, iATU_GET_IO_BASE(pp->remote_mem_baseaddr) );
+	PCIE_SETUP_iATU_OB_ENTRY( pp, iATU_ENTRY_MSG, iATU_GET_MSG_BASE(pp->remote_mem_baseaddr),
+			iATU_MSG_SIZE - 1, (AXI_OP_TYPE_MSG_REQ & iATU_CTRL1_TYPE_MASK),
+			0, iATU_GET_MSG_BASE(pp->remote_mem_baseaddr) );
+	PCIE_SETUP_iATU_IB_ENTRY( pp, 0, 0,
+			INBOUND_ADDR_MASK, 0, 0, COMCERTO_AXI_DDR_BASE);
+
+	comcerto_dbi_write_reg(pp, PCIE_MSI_ADDR_LO, 4, pp->msi_mbox_handle);
+	comcerto_dbi_write_reg(pp, PCIE_MSI_ADDR_HI, 4, 0);
+
+	writel_relaxed(0x7, pp->va_app_base + pp->app_regs->cfg5);
+
+	/* Generic PCIe unit setup.*/
+
+	/* Enable own BME. It is necessary to enable own BME to do a
+	 * memory transaction on a downstream device
+	 */
+	comcerto_dbi_read_reg(pp, PCI_COMMAND, 2, &val);
+	val |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER
+			| PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+	comcerto_dbi_write_reg(pp, PCI_COMMAND, 2, val);
+
+	pp->cfg0_prev_taddr = 0xffffffff;
+	pp->cfg1_prev_taddr = 0xffffffff;
+
+	//udelay(1000);
+
+	if(comcerto_pcie_link_up(pp)) {
+	printk(KERN_INFO " Bringing PCIe%d device out-of-reset : Link Up\n", pp->port);
+	/*FIXME : Below code might be required if we want to bring pcie device out-of-reset,
+         *	  without invoking pcie device supend. If we invoke pcie device resume it will
+	 *	  take care of restoring, saved pcie config space.
+         */
+#if 0
+		pci_dev = NULL;
+		while((pci_dev = pci_get_subsys(PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, pci_dev))) {
+			if (pp->root_bus_nr == pci_dev->bus->number) {
+				pci_restore_state(pci_dev);
+			}
+		}
+#endif
+	}
+
+	printk(KERN_INFO "EXIT: Bringing PCIe%d device out-of-reset\n", pp->port);
+	return 0;
+
+}
+
+static ssize_t comcerto_pcie_show_reset(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+        struct pcie_port *pp = &pcie_port[pdev->id];
+
+	return sprintf(buf, "%d\n", pp->reset);
+}
+
+static ssize_t comcerto_pcie_set_reset(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+        struct pcie_port *pp = &pcie_port[pdev->id];
+	int reset = 0, rc;
+
+	if (!pcie_port_is_host(pdev->id) ||  !(pp->link_state))
+			return count;
+
+	sscanf(buf, "%d", &reset);
+
+	reset = reset ? 1:0;
+
+	if (pp->reset == reset) {
+		printk(KERN_INFO "%s: Already in same state\n", __func__);
+		return count;
+	}
+
+
+	if (reset) {
+		printk(KERN_INFO "ENTER : Putting PCIe%d device into reset\n", pdev->id);
+
+		if (!comcerto_pcie_device_reset(pp)) {
+			int ii = 10;
+
+			/* Wait for link_req_rst_not, to be de-asseted */
+			while (ii--) {
+
+				if (!(readl( pp->va_app_base + pp->app_regs->sts0 ) & STS0_LINK_REQ_RST_NOT)) {
+					printk(KERN_INFO "%s : (PCIe%d) link_req_rst_not is de-asseted\n", __func__, pp->port);
+					break;
+				}
+
+				udelay(1000);
+			}
+
+			if (ii == 10) 
+				printk(KERN_WARNING "%s : (PCIe%d) link_req_rst_not is not de-asseted \n", __func__, pp->port);
+
+			pp->reset = 1;
+			/* Disable LTSSM and initiate linkdown reset */
+			writel((readl(pp->va_app_base + pp->app_regs->cfg5) &
+						~(CFG5_LTSSM_ENABLE)) | CFG5_LINK_DOWN_RST,
+						 pp->va_app_base + pp->app_regs->cfg5);
+			udelay(1000);
+		}
+
+		printk(KERN_INFO "Disabling PCIe%d Controler Clock\n", pdev->id);
+
+		if (pcie_port[pdev->id].port_mode != PCIE_PORT_MODE_NONE)
+			clk_disable(pcie_port[pdev->id].ref_clock);
+
+		printk(KERN_INFO "EXIT : Putting PCIe%d device into reset\n", pdev->id);
+	}
+	else {
+
+		printk(KERN_INFO "ENTER: Bringing PCIe%d device outof reset\n", pdev->id);
+
+		printk(KERN_INFO "Enabling PCIe%d Controler Clock\n", pdev->id);
+
+		if(pcie_port[pdev->id].port_mode != PCIE_PORT_MODE_NONE) {
+			rc = clk_enable(pcie_port[pdev->id].ref_clock);
+			if (rc)
+				pr_err("%s: PCIe%d clock enable failed\n", __func__, pdev->id);
+		}
+
+		if (!comcerto_pcie_device_reset_exit(pp)) {
+			pp->reset = 0;
+		}
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(device_reset, 0644, comcerto_pcie_show_reset, comcerto_pcie_set_reset);
+
+
+static ssize_t comcerto_pcie_serdes_pd(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+        struct pcie_port *pp = &pcie_port[pdev->id];
+	int reset = 0, rc;
+
+	sscanf(buf, "%d", &reset);
+
+	reset = reset ? 1:0;
+
+	if (reset) {
+		printk(KERN_INFO "%s: Putting Serdes to Low Power and CMU Power Off\n", __func__);
+
+		if (pdev->id)
+			writel(readl(USBPHY_SERDES_STAT_BASE+0x44) | ((0x3 << 2)|(0x1 << 7)) , USBPHY_SERDES_STAT_BASE+0x44);
+		else
+			writel(readl(USBPHY_SERDES_STAT_BASE+0x34) | ((0x3 << 2)|(0x1 << 7)) , USBPHY_SERDES_STAT_BASE+0x34);
+	} else {
+		printk(KERN_INFO "%s: Getting Serdes out of Low Power and CMU Power On\n", __func__);
+
+		if (pdev->id)
+			writel(readl(USBPHY_SERDES_STAT_BASE+0x44) & ~((0x3 << 2)|(0x1 << 7)) , USBPHY_SERDES_STAT_BASE+0x44);
+		else
+			writel(readl(USBPHY_SERDES_STAT_BASE+0x34) & ~((0x3 << 2)|(0x1 << 7)) , USBPHY_SERDES_STAT_BASE+0x34);
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(serdes_pd, 0644, NULL, comcerto_pcie_serdes_pd);
+
+
+#ifdef CONFIG_PM
+static int no_irq_resume ;
+
+static int comcerto_pcie_suspend(struct device *dev)
+{
+	unsigned int val, i;
+	struct platform_device *pdev = to_platform_device(dev);
+
+	printk(KERN_INFO "%s: pcie device %p (id = %d):\n",
+			 __func__, pdev, pdev->id);
+
+	/* Check for the BitMask bit for PCIe, if it is enabled
+	 * then we are not going suspend the PCIe device , as by
+	 * this device , we will wake from System Resume.
+	 */
+	if ( !(host_utilpe_shared_pmu_bitmask & PCIe0_IRQ) || !(host_utilpe_shared_pmu_bitmask & PCIe1_IRQ) ){
+ 		/* We will Just return from here */
+		return 0;
+	}
+	if (pcie_port[pdev->id].port_mode != PCIE_PORT_MODE_NONE) {
+		if (comcerto_pcie_link_up(&pcie_port[pdev->id])){
+			/* Enable PME to root Port */
+			comcerto_dbi_read_reg(&pcie_port[pdev->id], (PCI_CAP_PM + PCI_PM_CTRL), 4, &val);
+			comcerto_dbi_write_reg(&pcie_port[pdev->id], (PCI_CAP_PM + PCI_PM_CTRL), 4, val | PCI_PM_CTRL_STATE_MASK);
+			/* Required PM Delay */
+			for (i = 0 ; i < 40 ; i++)
+				udelay(500);
+		}
+	}
+	no_irq_resume =0 ;
+	return 0;
+}
+
+static int comcerto_pcie_resume(struct device *dev)
+{
+	unsigned int val, i;
+	struct platform_device *pdev = to_platform_device(dev);
+
+	printk(KERN_INFO "%s: pcie device %p (id = %d)\n", 
+		__func__, pdev, pdev->id);
+ 	/* Check for the Bit_Mask bit for PCIe, if it is enabled
+ 	 * then we are not going suspend the PCIe device , as by
+	 * this device , we will wake from System Resume.
+ 	*/
+	if ( !(host_utilpe_shared_pmu_bitmask & PCIe0_IRQ) || !(host_utilpe_shared_pmu_bitmask & PCIe1_IRQ) ){
+
+ 		/* We will Just return
+ 		*/
+		return 0;
+	}
+	if( no_irq_resume == 0)
+       	{
+		if(pcie_port[pdev->id].port_mode != PCIE_PORT_MODE_NONE) {
+			if (comcerto_pcie_link_up(&pcie_port[pdev->id])){
+		    		/* Put In D0 State */
+		    		comcerto_dbi_read_reg(&pcie_port[pdev->id], (PCI_CAP_PM + PCI_PM_CTRL), 4, &val);
+		    		comcerto_dbi_write_reg(&pcie_port[pdev->id], (PCI_CAP_PM + PCI_PM_CTRL), 4, val & (~PCI_PM_CTRL_STATE_MASK));
+
+				/* Required PM Delay */
+		    		for (i = 0 ; i < 40 ; i++)
+			    		udelay(500);
+	    		}	
+		}	
+	}
+	return 0;
+}
+
+static int comcerto_pcie_noirq_resume(struct device *dev)
+{
+	int val,i;
+	struct platform_device *pdev = to_platform_device(dev);
+
+	printk(KERN_INFO "%s: pcie device %p (id = %d)\n",
+			 __func__, pdev, pdev->id);
+
+	/* Check for the Bit_Mask bit for PCIe, if it is enabled
+	 * then we are not going suspend the PCIe device , as by
+	 * this device , we will wake from System Resume.
+	 */
+	if ( !(host_utilpe_shared_pmu_bitmask & PCIe0_IRQ) || !(host_utilpe_shared_pmu_bitmask & PCIe1_IRQ) ){
+               /* We will Just return
+                */
+		return 0;
+	}
+	if(pcie_port[pdev->id].port_mode != PCIE_PORT_MODE_NONE) {
+		if (comcerto_pcie_link_up(&pcie_port[pdev->id])){
+			/* Put In D0 State */
+			comcerto_dbi_read_reg(&pcie_port[pdev->id], (PCI_CAP_PM + PCI_PM_CTRL), 4, &val);
+			comcerto_dbi_write_reg(&pcie_port[pdev->id], (PCI_CAP_PM + PCI_PM_CTRL), 4, val & (~PCI_PM_CTRL_STATE_MASK));
+			/* Required PM Delay */
+			for (i = 0 ; i < 40 ; i++)
+				udelay(500);
+	    	}
+	}	
+	return 0;
+}
+
+static const struct dev_pm_ops pcie_platform_pm_ops = {
+	.suspend = comcerto_pcie_suspend,
+	.resume = comcerto_pcie_resume,
+	.resume_noirq = comcerto_pcie_noirq_resume,
+};
+
+
+static struct platform_driver comcerto_pcie_driver = {
+	.driver = {
+		.name = "pcie",
+		.pm   = &pcie_platform_pm_ops,
+		.owner = THIS_MODULE,
+	},
+};
+
+static struct platform_device pcie_pwr0 = {
+	.name = "pcie",
+	.id = 0,
+};
+
+static struct platform_device pcie_pwr1 = {
+	.name = "pcie",
+	.id = 1,
+};
+#endif
+
+static void comcerto_serdes_set_polarity(struct serdes_regs_s *p_pcie_phy_reg_file, int current_polarity)
+{
+	switch(current_polarity)
+	{
+		case 0:
+			p_pcie_phy_reg_file[0x73].val = 0x0;
+			p_pcie_phy_reg_file[0x75].val = 0x0;
+			break;
+		case 1: 
+			p_pcie_phy_reg_file[0x73].val = 0x8;
+			p_pcie_phy_reg_file[0x75].val = 0x2;
+			break;
+		case 2:
+			p_pcie_phy_reg_file[0x73].val = 0x0;
+			p_pcie_phy_reg_file[0x75].val = 0x2;
+			break;
+		case 3:
+			p_pcie_phy_reg_file[0x73].val = 0x8;
+			p_pcie_phy_reg_file[0x75].val = 0x0;
+			break;
+	}
+
+}
+
+static int comcerto_pcie_bsp_link_init(struct pcie_port *pp, int nr, struct serdes_regs_s *p_pcie_phy_reg_file, int serdes_reg_size, int current_polarity)
+{
+	int axi_pcie_component;
+	int pcie_component;
+	int serdes_component;
+	int rc;
+	int if_err = 1;
+
+	comcerto_serdes_set_polarity(p_pcie_phy_reg_file, current_polarity);
+
+	if(nr == 0)
+	{
+		axi_pcie_component = COMPONENT_AXI_PCIE0;
+		pcie_component = COMPONENT_SERDES_PCIE0;	
+		serdes_component = COMPONENT_SERDES0;
+	}
+	else
+	{
+		axi_pcie_component = COMPONENT_AXI_PCIE1;
+		pcie_component = COMPONENT_SERDES_PCIE1;	
+		serdes_component = COMPONENT_SERDES1;
+	}
+
+	//Bring serdes out of reset
+	c2000_block_reset(axi_pcie_component,0);
+	c2000_block_reset(serdes_component,0);
+
+	/* SW select for ck_soc_div_i SOC clock */
+	writel(0xFF3C, COMCERTO_SERDES_DWC_CFG_REG( nr, SD_PHY_CTRL3_REG_OFST ));
+	writel(readl(COMCERTO_SERDES_DWC_CFG_REG( nr, SD_PHY_CTRL2_REG_OFST )) & ~0x3,
+			COMCERTO_SERDES_DWC_CFG_REG( nr, SD_PHY_CTRL2_REG_OFST ));
+
+	rc = clk_enable(pp->ref_clock);
+	if (rc){
+		pr_err("%s: PCIe%d clock enable failed\n", __func__, nr);
+		goto err1;
+	}
+	
+	/* Enable the PCIE_OCC clock */	
+#if defined(CONFIG_COMCERTO_PCIE_OCC_CLOCK)
+	rc =  clk_enable(pp->occ_clock);
+	if (rc){
+		pr_err("%s: PCIe_occ clock enable failed\n", __func__);
+		goto err_occ_clock;
+	}
+#endif
+
+	/* Serdes Initialization. */
+	if( serdes_phy_init(nr,  p_pcie_phy_reg_file,
+				serdes_reg_size/ sizeof(serdes_regs_t),
+				SD_DEV_TYPE_PCIE) )
+	{
+		pp->port_mode = PCIE_PORT_MODE_NONE;
+		pr_err("%s: Failed to initialize serdes (%d)\n", __func__, nr );
+		goto err_phy_link;
+	}
+
+	mdelay(1); //After CMU locks wait for sometime
+
+#if defined(CONFIG_C2K_MFCN_EVM)
+	if(nr == 0){
+		GPIO_reset_external_device(COMPONENT_PCIE0,0);
+	}else{
+		GPIO_reset_external_device(COMPONENT_PCIE1,0);
+	}
+
+	mdelay(1);
+#endif
+	//Bring PCIe out of reset
+	c2000_block_reset(pcie_component,0);
+
+	//Hold the LTSSM in detect state
+	writel(readl(pp->va_app_base + pp->app_regs->cfg5) & ~CFG5_LTSSM_ENABLE,
+			pp->va_app_base + pp->app_regs->cfg5);
+
+	comcerto_pcie_rc_init(pp);
+
+	//Enable LTSSM to start link initialization
+	writel(readl(pp->va_app_base + pp->app_regs->cfg5) | (CFG5_APP_INIT_RST | CFG5_LTSSM_ENABLE),
+			pp->va_app_base + pp->app_regs->cfg5);
+
+	pp->link_state = comcerto_pcie_link_up( &pcie_port[nr] );
+
+	if(!pp->link_state)
+	{
+		if_err = 0;
+		goto err_phy_link;
+	}
+
+	return 0;
+
+err_phy_link:
+	clk_disable(pp->ref_clock);
+	clk_put(pp->ref_clock);
+#if defined(CONFIG_COMCERTO_PCIE_OCC_CLOCK)
+err_occ_clock:
+	clk_disable(pp->occ_clock);
+	clk_put(pp->occ_clock);
+#endif
+
+err1:
+	//Put all to reset
+	c2000_block_reset(axi_pcie_component,1);
+	c2000_block_reset(serdes_component,1);
+	c2000_block_reset(pcie_component,1);
+
+	if(if_err)
+		return -1;
+	else
+		return 0;
+
+}
+
+static int comcerto_pcie_bsp_init(struct pcie_port *pp, int nr)
+{
+	struct serdes_regs_s *p_pcie_phy_reg_file;
+	int serdes_regs_size;
+	int polarity_max = 4;
+	int polarity;
+	int ret;
+
+
+	if (nr >= NUM_PCIE_PORTS) {
+		printk("%s : Invalid PCIe port number\n", __func__);
+		goto err0;
+	}
+
+	ret = pcie_app_init(pp, nr, CFG0_DEV_TYPE_RC);
+	if(ret == -1)
+		goto err0;;
+
+	pp->port_mode = pcie_port_get_mode(nr);
+
+	if(pcie_external_clk)
+	{
+		p_pcie_phy_reg_file = &pcie_phy_reg_file_100[0];
+		serdes_regs_size = sizeof(pcie_phy_reg_file_100);
+	}
+	else
+	{
+		if(HAL_get_ref_clk() == REF_CLK_24MHZ)
+		{
+                        p_pcie_phy_reg_file = &pcie_phy_reg_file_24[0];
+			serdes_regs_size = sizeof(pcie_phy_reg_file_24);
+			printk(KERN_INFO "PCIe: Ref clk 24Mhz\n");
+		}
+                else
+		{
+                        p_pcie_phy_reg_file = &pcie_phy_reg_file_48[0];
+			serdes_regs_size = sizeof(pcie_phy_reg_file_48);
+			printk(KERN_INFO "PCIe: Ref clk 48Mhz\n");
+		}
+        }
+
+	if (system_rev == 1) {
+		printk(KERN_INFO "PCIe: Detected C2K RevA1 device serdes clk devider old:new=%x:%x\n",
+				p_pcie_phy_reg_file[0x61].val, 0x06);
+		p_pcie_phy_reg_file[0x61].val = 0x6;
+	}
+
+	for(polarity = 0 ; polarity < polarity_max; polarity++)
+	{
+
+		ret = comcerto_pcie_bsp_link_init(pp, nr, p_pcie_phy_reg_file, serdes_regs_size, polarity);
+		if(ret == -1)
+			goto err1;;
+
+		if (pp->link_state)
+			goto linkup;
+
+		if(!pcie_port_is_host(nr))
+			return 0; //Endpoint, so no need to change polarity
+
+	}
+	
+	printk(KERN_INFO "PCIe%d: Link Up Failed \n",nr);
+
+err1: 	
+	iounmap(pp->va_cfg0_base);
+	iounmap(pp->va_cfg1_base);
+	pp->port_mode = PCIE_PORT_MODE_NONE;
+err0:
+	return -1;
+
+linkup:
+	printk(KERN_INFO "PCIe%d: Link Up Success \n",nr);
+	printk(KERN_INFO "PCIe%d: Polarity: %d Gen1 mode: %d External Clk: %d\n",nr, polarity, pcie_gen1_only,pcie_external_clk);
+	if (pcie_port_is_host(nr))
+		comcerto_pcie_rc_int_init(pp);	
+	return 0;
+
+}
+
+static int comcerto_pcie_abort_handler(unsigned long addr, unsigned int fsr,
+                                      struct pt_regs *regs)
+{
+        if (fsr & (1 << 10))
+                regs->ARM_pc += 4;
+        return 0;
+}
+
+
+static int __init comcerto_pcie_init(void)
+{
+        struct pcie_port *pp;
+	int i, rc;
+	int num_pcie_port = 1;
+	struct pci_dev *pdev = NULL;
+
+
+        pp = &pcie_port[0];
+	comcerto_pcie_bsp_init(pp, 0);
+
+	if ( (NUM_PCIE_PORTS == 2)  &&
+                        !(readl(COMCERTO_GPIO_SYSTEM_CONFIG) & BOOT_SERDES1_CNF_SATA0) )
+        {
+                num_pcie_port = 2;
+		pp = &pcie_port[1];
+		comcerto_pcie_bsp_init(pp, 1);
+        }
+
+	comcerto_pcie.nr_controllers = num_pcie_port;
+
+	pcibios_min_io = iATU_GET_IO_BASE(COMCERTO_AXI_PCIe0_SLAVE_BASE);
+	pcibios_min_mem = COMCERTO_AXI_PCIe0_SLAVE_BASE;
+	pci_add_flags(PCI_REASSIGN_ALL_RSRC);
+
+	hook_fault_code(16 + 6, comcerto_pcie_abort_handler, SIGBUS, 0, "imprecise external abort");
+
+	pci_common_init(&comcerto_pcie);
+
+	for ( i = 0; i < num_pcie_port; i++ )
+	{
+
+		if (!pcie_port_is_host(i) ||  !(pcie_port[i].link_state))
+			continue;
+
+		while((pdev = pci_get_subsys(PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, pdev))) {
+			if (pcie_port[i].root_bus_nr == pdev->bus->number) {
+				if( (rc = pcie_get_readrq(pdev)) > 512 ) {
+					printk(KERN_WARNING "PCIe%d Device rdreq size (%d) is more than supported\n", i, rc);
+					pcie_set_readrq(pdev, 512);
+				}
+			}
+		}
+	}
+
+
+#ifdef CONFIG_PM
+	platform_device_register(&pcie_pwr0);
+
+	if (device_create_file(&pcie_pwr0.dev, &dev_attr_device_reset))
+		printk(KERN_ERR "%s: Unable to create pcie0 reset sysfs entry\n", __func__);
+
+	if (device_create_file(&pcie_pwr0.dev, &dev_attr_serdes_pd))
+		printk(KERN_ERR "%s: Unable to create pcie0 serdes_pd sysfs entry\n", __func__);
+
+	if(num_pcie_port > 1) {
+		platform_device_register(&pcie_pwr1);
+
+		if (device_create_file(&pcie_pwr1.dev, &dev_attr_device_reset))
+			printk(KERN_ERR "%s: Unable to create pcie1 reset sysfs entry\n", __func__);
+
+		if (device_create_file(&pcie_pwr1.dev, &dev_attr_serdes_pd))
+			printk(KERN_ERR "%s: Unable to create pcie1 serdes_pd sysfs entry\n", __func__);
+	}
+
+	platform_driver_register(&comcerto_pcie_driver);
+#endif
+
+	return 0;
+}
+subsys_initcall(comcerto_pcie_init);
+
+
diff --git a/arch/arm/mach-comcerto/platsmp.c b/arch/arm/mach-comcerto/platsmp.c
new file mode 100644
index 0000000..7c0c727
--- /dev/null
+++ b/arch/arm/mach-comcerto/platsmp.c
@@ -0,0 +1,260 @@
+/*
+ *  arch/arm/mach-comcerto/platsmp.c
+ *
+ * Copyright (C) 2011 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/smp.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+
+#include <asm/cacheflush.h>
+#include <mach/hardware.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach-types.h>
+#include <asm/smp_scu.h>
+#include <asm/unified.h>
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <linux/kthread.h>  // for threads
+#include <linux/sched.h>  // for task_struct
+#include <linux/time.h>   // for using jiffies
+#include <linux/timer.h>
+
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/pid.h>
+
+
+extern void comcerto_secondary_startup(void);
+
+static void __iomem *scu_base_addr(void)
+{
+	return (void *)COMCERTO_SCU_VADDR;
+}
+
+/*
+ * Initialise the CPU possible map early - this describes the CPUs
+ * which may be present or become present in the system.
+ */
+void __init smp_init_cpus(void)
+{
+	void __iomem *scu_base = scu_base_addr();
+	unsigned int i, ncores;
+
+	ncores = scu_base ? scu_get_core_count(scu_base) : 1;
+
+	if (ncores > NR_CPUS) {
+		printk(KERN_WARNING
+		       "Comcerto: no. of cores (%d) greater than configured "
+		       "maximum of %d - clipping\n",
+		       ncores, NR_CPUS);
+		ncores = NR_CPUS;
+	}
+
+	for (i = 0; i < ncores; i++)
+		set_cpu_possible(i, true);
+
+	set_smp_cross_call(gic_raise_softirq);
+}
+
+#define JUMP_TO_KERNEL_START_1		0xe3a00020 	/* mov	r0, #32 */
+#define JUMP_TO_KERNEL_START_2		0xe590f000 	/* ldr	pc, [r0] */
+
+/* Creating Task for Cpu-1 Hotplug */
+struct task_struct *thread1=NULL;
+
+DECLARE_WAIT_QUEUE_HEAD(cpu1_hotplug);
+
+/*
+ * Hotplug signal from CPU Hotplug framework
+ * to invoke the Hotplug task
+ */
+u32 cpu1_hotplug_done;
+
+/* Cpu-1 Hotplug Task */
+void hotplug_cpu1_die(void)
+{
+	unsigned int reset;
+	struct cpumask in_mask;
+	int cpu = 0;
+	int pid = 0;
+
+	cpumask_set_cpu(cpu, &in_mask);
+	sched_setaffinity(pid, &in_mask);
+
+wait_for_cpu1_hotplug_done:
+
+	/* Waiting for hotplug event invoked by CPU hotplug framework */
+	wait_event(cpu1_hotplug, cpu1_hotplug_done>0);
+
+#ifdef CONFIG_NEON
+	__raw_writel((__raw_readl(A9DP_CPU_CLK_CNTRL) & ~NEON1_CLK_ENABLE), A9DP_CPU_CLK_CNTRL);
+	__raw_writel((__raw_readl(A9DP_CPU_RESET) | NEON1_RST), A9DP_CPU_RESET);
+#endif
+	__raw_writel((__raw_readl(A9DP_CPU_CLK_CNTRL) & ~CPU1_CLK_ENABLE), A9DP_CPU_CLK_CNTRL);
+	__raw_writel((__raw_readl(A9DP_PWR_CNTRL) | CLAMP_CORE1), A9DP_PWR_CNTRL);
+	__raw_writel((__raw_readl(A9DP_PWR_CNTRL) | CORE_PWRDWN1), A9DP_PWR_CNTRL);
+	__raw_writel((__raw_readl(A9DP_CPU_RESET) | CPU1_RST), A9DP_CPU_RESET);
+	__raw_writel((__raw_readl(A9DP_PWR_CNTRL) & ~CORE_PWRDWN1), A9DP_PWR_CNTRL);
+
+	cpu1_hotplug_done = 0;
+	goto wait_for_cpu1_hotplug_done;
+
+	return;
+}
+
+void __init platform_smp_prepare_cpus(unsigned int max_cpus)
+{
+	int i;
+	char our_thread[25]="cpu1_hotplug_thread";
+
+	/*
+	 * Initialise the present map, which describes the set of CPUs
+	 * actually populated at the present time.
+	 */
+	for (i = 0; i < max_cpus; i++)
+		set_cpu_present(i, true);
+
+	scu_enable(scu_base_addr());
+
+        /* Create cpu1_hotplug_thread */
+
+	printk(" Creating cpu1_hotplug_thread....\n");
+	cpu1_hotplug_done = 0;
+	thread1 = kthread_create(hotplug_cpu1_die,NULL,our_thread);
+
+	if((thread1))
+		{
+		printk(" cpu1_hotplug_thread Created\n");
+		wake_up_process(thread1);
+		}
+
+	return 0;
+}
+
+/*
+ * control for which core is the next to come out of the secondary
+ * boot "holding pen"
+ */
+volatile int __cpuinitdata pen_release = -1;
+
+/*
+ * Write pen_release in a way that is guaranteed to be visible to all
+ * observers, irrespective of whether they're taking part in coherency
+ * or not.  This is necessary for the hotplug code to work reliably.
+ */
+static void __cpuinit write_pen_release(int val)
+{
+	pen_release = val;
+	smp_wmb();
+	__cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
+	outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
+}
+
+static DEFINE_SPINLOCK(boot_lock);
+
+void __cpuinit platform_secondary_init(unsigned int cpu)
+{
+	/*
+	 * if any interrupts are already enabled for the primary
+	 * core (e.g. timer irq), then they will not have been enabled
+	 * for us: do so
+	 */
+	gic_secondary_init(0);
+
+	/*
+	 * let the primary processor know we're out of the
+	 * pen, then head off into the C entry point
+	 */
+	write_pen_release(-1);
+
+	/*
+	 * Synchronise with the boot thread.
+	 */
+	spin_lock(&boot_lock);
+	spin_unlock(&boot_lock);
+}
+
+int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+	unsigned long timeout;
+	unsigned int *loop = (unsigned int *)phys_to_virt(0x08);
+
+	/*
+	 * Install the comcerto_secondary_startup pointer at 0x20
+	 * Physical Address
+	 */
+	__raw_writel(BSYM(virt_to_phys(comcerto_secondary_startup)), phys_to_virt(0x20));
+	__raw_writel((unsigned int)JUMP_TO_KERNEL_START_1 , phys_to_virt(0x00));
+	__raw_writel((unsigned int)JUMP_TO_KERNEL_START_2 , phys_to_virt(0x04));
+	smp_wmb();
+	__cpuc_flush_dcache_area((void *)phys_to_virt(0x00), 0x24);
+	outer_clean_range(__pa(phys_to_virt(0x00)), __pa(phys_to_virt(0x24)));
+
+	/* Get CPU 1 out of reset */
+	__raw_writel((__raw_readl(A9DP_CPU_RESET) & ~CPU1_RST), A9DP_CPU_RESET);
+	__raw_writel((__raw_readl(A9DP_PWR_CNTRL) & ~CLAMP_CORE1), A9DP_PWR_CNTRL);
+	__raw_writel((__raw_readl(A9DP_CPU_CLK_CNTRL) | CPU1_CLK_ENABLE), A9DP_CPU_CLK_CNTRL);
+
+#ifdef CONFIG_NEON
+	/* Get NEON 1 out of reset */
+	__raw_writel((__raw_readl(A9DP_CPU_RESET) & ~NEON1_RST), A9DP_CPU_RESET);
+	__raw_writel((__raw_readl(A9DP_CPU_CLK_CNTRL) | NEON1_CLK_ENABLE), A9DP_CPU_CLK_CNTRL);
+#endif
+	/*
+	 * Set synchronisation state between this boot processor
+	 * and the secondary one
+	 */
+	spin_lock(&boot_lock);
+
+	/*
+	 * This is really belt and braces; we hold unintended secondary
+	 * CPUs in the holding pen until we're ready for them.  However,
+	 * since we haven't sent them a soft interrupt, they shouldn't
+	 * be there.
+	 */
+	write_pen_release(cpu);
+
+	/*
+	 * Send the secondary CPU a soft interrupt, thereby causing
+	 * the boot monitor to read the system wide flags register,
+	 * and branch to the address found there.
+	 */
+	timeout = jiffies + (1 * HZ);
+	while (time_before(jiffies, timeout)) {
+		smp_rmb();
+		if (pen_release == -1)
+			break;
+
+		udelay(10);
+	}
+
+	/*
+	 * now the secondary core is starting up let it run its
+	 * calibrations, then wait for it to finish
+	 */
+	spin_unlock(&boot_lock);
+
+	return pen_release != -1 ? -ENOSYS : 0;
+}
diff --git a/arch/arm/mach-comcerto/pm.c b/arch/arm/mach-comcerto/pm.c
new file mode 100644
index 0000000..128ee9d
--- /dev/null
+++ b/arch/arm/mach-comcerto/pm.c
@@ -0,0 +1,408 @@
+/*
+ * arch/arm/mach-comcerto/pm.c
+ * C2K Power Management
+ *
+ * Copyright (C) 2012 Mindspeed
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/suspend.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/interrupt.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <asm/suspend.h>
+#include <asm/irq.h>
+#include <linux/atomic.h>
+#include <asm/mach/time.h>
+#include <asm/mach/irq.h>
+#include <linux/console.h>
+
+
+#include <linux/smp.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+
+#include <asm/cacheflush.h>
+#include <mach/hardware.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach-types.h>
+#include <asm/smp_scu.h>
+#include <mach/comcerto-2000/pm.h>
+#include <linux/gpio.h>
+
+unsigned int host_utilpe_shared_pmu_bitmask;
+
+/* Externs */
+extern void comcerto_cpu_suspend(int save_state);
+extern	unsigned int * c2k_get_restore_pointer(void);
+extern void comcerto_cpu_restore (void);
+
+unsigned int c2k_pm_bitmask_show(void)
+{
+	return host_utilpe_shared_pmu_bitmask;
+}
+
+void c2k_pm_bitmask_store(unsigned int bitmask_value)
+{
+	/*
+	 * Initialize the shared pmu bitmask
+	 * This information can be configurable run time.
+	 * Can be passed from bootloader also (Not Implimented Yet)
+	 */
+	//host_utilpe_shared_pmu_bitmask = 0xFFE7FFFF;
+	host_utilpe_shared_pmu_bitmask = bitmask_value;
+
+	/* Pass the bitmask info to UtilPE */
+	*(((volatile unsigned int *)(HOST_UTILPE_SHARED_ADDRESS))+4) = host_utilpe_shared_pmu_bitmask;
+}
+
+
+static int comcerto_do_sram_idle(unsigned long save_state)
+{
+	comcerto_cpu_suspend(save_state);
+	return 0;
+}
+
+/*------------------------- L2 Cache and SCU Save Resume ----------------------------*/
+#define SCU_DATA_SIZE                32
+#define L2_DATA_SIZE                 96
+
+extern void pl310_save(void);
+extern void pl310_resume(void);
+
+typedef struct
+{
+    /* 0x00 */  volatile unsigned int control;
+    /* 0x04 */  const unsigned int configuration;
+    /* 0x08 */  union
+                {
+                    volatile unsigned int w;
+                    volatile unsigned char b[4];
+                } power_status;
+    /* 0x0c */  volatile unsigned int invalidate_all;
+                char padding1[48];
+    /* 0x40 */  volatile unsigned int filtering_start;
+    /* 0x44 */  volatile unsigned int filtering_end;
+                char padding2[8];
+    /* 0x50 */  volatile unsigned int access_control;
+    /* 0x54 */  volatile unsigned int ns_access_control;
+} a9_scu_registers;
+
+
+void save_a9_scu(u32 *pointer, unsigned scu_address)
+{
+    a9_scu_registers *scu = (a9_scu_registers *)scu_address;
+
+    pointer[0] = scu->control;
+    pointer[1] = scu->power_status.w;
+    pointer[2] = scu->filtering_start;
+    pointer[3] = scu->filtering_end;
+    pointer[4] = scu->access_control;
+    pointer[5] = scu->ns_access_control;
+}
+
+void restore_a9_scu(u32 *pointer, unsigned scu_address)
+{
+    a9_scu_registers *scu = (a9_scu_registers *)scu_address;
+
+    scu->invalidate_all = 0xffff;
+    scu->filtering_start = pointer[2];
+    scu->filtering_end = pointer[3];
+    scu->access_control = pointer[4];
+    scu->ns_access_control = pointer[5];
+    scu->power_status.w = pointer[1];
+    scu->control = pointer[0];
+}
+
+
+struct lockdown_regs
+{
+    unsigned int d, i;
+};
+
+typedef struct
+{
+    /* 0x000 */ const unsigned cache_id;
+    /* 0x004 */ const unsigned cache_type;
+                char padding1[0x0F8];
+    /* 0x100 */ volatile unsigned control;
+    /* 0x104 */ volatile unsigned aux_control;
+    /* 0x108 */ volatile unsigned tag_ram_control;
+    /* 0x10C */ volatile unsigned data_ram_control;
+                char padding2[0x0F0];
+    /* 0x200 */ volatile unsigned ev_counter_ctrl;
+    /* 0x204 */ volatile unsigned ev_counter1_cfg;
+    /* 0x208 */ volatile unsigned ev_counter0_cfg;
+    /* 0x20C */ volatile unsigned ev_counter1;
+    /* 0x210 */ volatile unsigned ev_counter0;
+    /* 0x214 */ volatile unsigned int_mask;
+    /* 0x218 */ const volatile unsigned int_mask_status;
+    /* 0x21C */ const volatile unsigned int_raw_status;
+    /* 0x220 */ volatile unsigned int_clear;
+                char padding3[0x50C];
+    /* 0x730 */ volatile unsigned cache_sync;
+                char padding4[0x03C];
+    /* 0x770 */ volatile unsigned inv_pa;
+                char padding5[0x008];
+    /* 0x77C */ volatile unsigned inv_way;
+                char padding6[0x030];
+    /* 0x7B0 */ volatile unsigned clean_pa;
+                char padding7[0x004];
+    /* 0x7B8 */ volatile unsigned clean_index;
+    /* 0x7BC */ volatile unsigned clean_way;
+                char padding8[0x030];
+    /* 0x7F0 */ volatile unsigned clean_inv_pa;
+                char padding9[0x004];
+    /* 0x7F8 */ volatile unsigned clean_inv_index;
+    /* 0x7FC */ volatile unsigned clean_inv_way;
+                char paddinga[0x100];
+    /* 0x900 */ volatile struct lockdown_regs lockdown[8];
+                char paddingb[0x010];
+    /* 0x950 */ volatile unsigned lock_line_en;
+    /* 0x954 */ volatile unsigned unlock_way;
+                char paddingc[0x2A8];
+    /* 0xC00 */ volatile unsigned addr_filtering_start;
+    /* 0xC04 */ volatile unsigned addr_filtering_end;
+                char paddingd[0x338];
+    /* 0xF40 */ volatile unsigned debug_ctrl;
+                char paddinge[0x01C];
+    /* 0xF60 */ volatile unsigned prefetch_ctrl;
+                char paddingf[0x01C];
+    /* 0xF80 */ volatile unsigned power_ctrl;
+} pl310_registers;
+
+
+typedef struct
+{
+    unsigned int aux_control;
+    unsigned int tag_ram_control;
+    unsigned int data_ram_control;
+    unsigned int ev_counter_ctrl;
+    unsigned int ev_counter1_cfg;
+    unsigned int ev_counter0_cfg;
+    unsigned int ev_counter1;
+    unsigned int ev_counter0;
+    unsigned int int_mask;
+    unsigned int lock_line_en;
+    struct lockdown_regs lockdown[8];
+    unsigned int unlock_way;
+    unsigned int addr_filtering_start;
+    unsigned int addr_filtering_end;
+    unsigned int debug_ctrl;
+    unsigned int prefetch_ctrl;
+    unsigned int power_ctrl;
+} pl310_context;
+
+
+void save_pl310(u32 *pointer, unsigned int pl310_address)
+{
+    pl310_registers *pl310 = (pl310_registers *)pl310_address;
+    pl310_context *context = (pl310_context *)pointer;
+    int i;
+
+    /* TODO: are all these registers are present in earlier PL310 versions? */
+    context->aux_control = pl310->aux_control;
+    context->tag_ram_control = pl310->tag_ram_control;
+    context->data_ram_control = pl310->data_ram_control;
+    context->ev_counter_ctrl = pl310->ev_counter_ctrl;
+    context->ev_counter1_cfg = pl310->ev_counter1_cfg;
+    context->ev_counter0_cfg = pl310->ev_counter0_cfg;
+    context->ev_counter1 = pl310->ev_counter1;
+    context->ev_counter0 = pl310->ev_counter0;
+    context->int_mask = pl310->int_mask;
+    context->lock_line_en = pl310->lock_line_en;
+
+    for (i=0; i<8; ++i)
+    {
+        context->lockdown[i].d = pl310->lockdown[i].d;
+        context->lockdown[i].i = pl310->lockdown[i].i;
+    }
+    context->addr_filtering_start = pl310->addr_filtering_start;
+    context->addr_filtering_end = pl310->addr_filtering_end;
+    context->debug_ctrl = pl310->debug_ctrl;
+    context->prefetch_ctrl = pl310->prefetch_ctrl;
+    context->power_ctrl = pl310->power_ctrl;
+}
+
+void restore_pl310(u32 *pointer, unsigned int pl310_address)
+{
+    pl310_registers *pl310 = (pl310_registers *)pl310_address;
+    pl310_context *context = (pl310_context *)pointer;
+    int i;
+
+    /* We may need to disable the PL310 if the boot code has turned it on */
+    if (pl310->control)
+    {
+        /* Wait for the cache to be idle, then disable */
+        pl310->cache_sync = 0;
+        dsb();
+        pl310->control = 0;
+    }
+
+    /* TODO: are all these registers present in earlier PL310 versions? */
+    pl310->aux_control = context->aux_control;
+    pl310->tag_ram_control = context->tag_ram_control;
+    pl310->data_ram_control = context->data_ram_control;
+    pl310->ev_counter_ctrl = context->ev_counter_ctrl;
+    pl310->ev_counter1_cfg = context->ev_counter1_cfg;
+    pl310->ev_counter0_cfg = context->ev_counter0_cfg;
+    pl310->ev_counter1 = context->ev_counter1;
+    pl310->ev_counter0 = context->ev_counter0;
+    pl310->int_mask = context->int_mask;
+    pl310->lock_line_en = context->lock_line_en;
+    for (i=0; i<8; ++i)
+    {
+        pl310->lockdown[i].d = context->lockdown[i].d;
+        pl310->lockdown[i].i= context->lockdown[i].i;
+    }
+    pl310->addr_filtering_start = context->addr_filtering_start;
+    pl310->addr_filtering_end = context->addr_filtering_end;
+    pl310->debug_ctrl = context->debug_ctrl;
+    pl310->prefetch_ctrl = context->prefetch_ctrl;
+    pl310->power_ctrl = context->power_ctrl;
+    dsb();
+    pl310->control = 1;
+    dsb();
+}
+
+/*------------------------- L2 Cache and SCU Save Resume ----------------------------*/
+
+static void C2k_pm_suspend(void)
+{
+	/* Variable to tell what needs to be saved and restored
+     	 * in C2k_pm_suspend_new */
+
+	/* save_state = 0 => Nothing to save and restored */
+	/* save_state = 1 => Only L1 and logic lost */
+	/* save_state = 2 => Only L2 lost */
+	/* save_state = 3 => L1, L2 and logic lost */
+ 	int save_state = 3;
+	unsigned int * p0;
+
+	unsigned int scu_data[SCU_DATA_SIZE];
+	unsigned int pl310_data[L2_DATA_SIZE];
+
+
+	printk(KERN_INFO "PM: C2000 Device is trying to enter Suspend mode ...\n");
+
+	p0 = (unsigned int *) comcerto_cpu_restore;
+
+	__raw_writel(virt_to_phys((unsigned int)p0), phys_to_virt(0x20));
+	__raw_writel((unsigned int)JUMP_TO_RESUME_1 , phys_to_virt(0x00));
+	__raw_writel((unsigned int)JUMP_TO_RESUME_2 , phys_to_virt(0x04));
+	smp_wmb();
+	__cpuc_flush_dcache_area((void *)phys_to_virt(0x00), 0x24);
+	outer_clean_range(__pa(phys_to_virt(0x00)), __pa(phys_to_virt(0x24)));
+
+	printk(KERN_INFO "PM: C2000 Jump Location Installed ... -- 0x%x  -- 0x%x  -- 0x%x \n", (unsigned int)p0, (unsigned int)comcerto_cpu_restore, virt_to_phys((unsigned int)p0));
+
+	printk(KERN_INFO "PM: Saving SCU Context ...\n");
+	save_a9_scu(&scu_data[0], (unsigned int *)COMCERTO_SCU_VADDR);
+
+	printk(KERN_INFO "PM: Saving L2 Cache Context ...\n");
+	save_pl310(&pl310_data[0], (unsigned int *)COMCERTO_L310_VADDR);
+
+	/* Pass the bitmask information to the uTilPE */
+	*(((volatile unsigned int *)(HOST_UTILPE_SHARED_ADDRESS))+4) = host_utilpe_shared_pmu_bitmask;
+
+	printk(KERN_INFO "PM: Going to Suspend ...\n");
+
+	cpu_suspend(save_state, comcerto_do_sram_idle);
+
+	restore_a9_scu(&scu_data[0], (unsigned int *)COMCERTO_SCU_VADDR);
+	restore_pl310(&pl310_data[0], (unsigned int *)COMCERTO_L310_VADDR);
+
+	printk(KERN_INFO "PM: C2000  is re-starting from Suspend State ...\n");
+
+	return;
+}
+
+/*  C2k_pm_enter
+ *  @state:         State we're entering.
+ */
+
+static int C2k_pm_enter(suspend_state_t state)
+{
+	switch(state)
+	{
+
+	case PM_SUSPEND_STANDBY:
+	case PM_SUSPEND_MEM:
+		C2k_pm_suspend();
+		break;
+	default:
+		return -EINVAL;
+	}
+	pr_info("PM: C2000 Leaving C2k_pm_enter \n");
+	return 0;
+}
+
+static int C2k_pm_valid_state(suspend_state_t state)
+{
+	switch (state) {
+		case PM_SUSPEND_ON:
+		case PM_SUSPEND_STANDBY:
+		case PM_SUSPEND_MEM:
+			return 1;
+		default:
+			return 0;
+	}
+}
+
+static suspend_state_t target_state;
+
+/*
+ * Called after processes are frozen, but before we shutdown devices.
+ */
+static int C2k_pm_begin(suspend_state_t state)
+{
+	target_state = state;
+	return 0;
+}
+
+/*
+ * Called right prior to thawing processes.
+ */
+static void C2k_pm_finish(void)
+{
+	printk(KERN_INFO "Suspend process is completed, Wait for C2000 device to resume \n");
+}
+
+
+/*
+ * Called right prior to thawing processes.
+ */
+static void C2k_pm_end(void)
+{
+	printk(KERN_INFO "Resume process is completed, C2000 device is Power on Again \n");
+        target_state = PM_SUSPEND_ON;
+}
+
+
+static const struct platform_suspend_ops C2k_pm_ops = {
+	.valid	   = C2k_pm_valid_state,
+	.begin     = C2k_pm_begin,
+	.enter     = C2k_pm_enter,
+	.finish    = C2k_pm_finish,
+	.end       = C2k_pm_end,
+};
+
+static int __init C2k_pm_init(void)
+{
+	printk(KERN_INFO "Power Management Mode Support For C2000: \n");
+
+	suspend_set_ops(&C2k_pm_ops);
+        return 0;
+}
+arch_initcall(C2k_pm_init);
+
diff --git a/arch/arm/mach-comcerto/reset.c b/arch/arm/mach-comcerto/reset.c
new file mode 100644
index 0000000..d87333a
--- /dev/null
+++ b/arch/arm/mach-comcerto/reset.c
@@ -0,0 +1,530 @@
+/*
+ *  linux/arch/arm/mach-comcerto/reset.c
+ *
+ *  driver for block reset for all the devices availble in the 
+ *  c2000 device.
+ *
+ *  Copyright (C) 2012 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <mach/reset.h>
+#include <asm/io.h>
+#include <linux/spinlock.h>
+
+#include <linux/gpio.h>
+
+static char i2cspi_state[2],dus_state[3];
+spinlock_t reset_lock;
+static spinlock_t gpio_lock;
+
+
+void comcerto_rst_cntrl_set(unsigned int dev_rst_cntrl_bit)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&reset_lock, flags);
+
+	__raw_writel((dev_rst_cntrl_bit | __raw_readl(DEVICE_RST_CNTRL)), DEVICE_RST_CNTRL);
+
+	spin_unlock_irqrestore(&reset_lock,flags);
+}
+EXPORT_SYMBOL(comcerto_rst_cntrl_set);
+
+/* @ int block : Id of device block to be put in reset
+ * @ int state : State value 0->OUT-OF-RESET , 1->RESET.
+ * API for block reset to all the device blocks
+ * available for C2000 devices.
+ */
+void c2000_block_reset(int block,int state)
+{
+unsigned long flags;
+spin_lock_irqsave(&reset_lock, flags);
+
+if(state){
+	/*  Code is to put the device block in RESET */
+	switch (block)
+	{
+		case COMPONENT_AXI_RTC:
+			/* Put the Timer device(AXI clock domain) in reset state */
+			writel(readl(AXI_RESET_1) | RTC_AXI_RESET_BIT, AXI_RESET_1);
+			break;
+		case COMPONENT_AXI_I2C:
+			i2cspi_state[0]=1;
+			goto i2cspi_rst;
+		case COMPONENT_AXI_LEGACY_SPI:
+			i2cspi_state[1]=1;
+		i2cspi_rst:
+			if(i2cspi_state[0] == 1 && i2cspi_state[1] == 1)
+				/* Put the I2C and LEGACY SPI(AXI clock domain) device in reset state */
+				writel(readl(AXI_RESET_1) | I2CSPI_AXI_RESET_BIT, AXI_RESET_1);
+			break;
+		case COMPONENT_AXI_DMA:
+			dus_state[0]=1;
+			goto dus_rst;
+		case COMPONENT_AXI_FAST_UART:
+			dus_state[1]=1;
+			goto dus_rst;
+		case COMPONENT_AXI_FAST_SPI:
+			dus_state[2]=1;
+		dus_rst:
+			if(dus_state[0] == 1 && dus_state[1] == 1 && dus_state[2] == 1)
+				/* Put the DUS (AXI clock domain) device in reset state */
+				writel(readl(AXI_RESET_1) | DUS_AXI_RESET_BIT, AXI_RESET_1);
+			break;
+		case COMPONENT_AXI_TDM:
+			/* Put the TDM(AXI clock domain) device in reset state */
+			writel(readl(AXI_RESET_1) | TDM_AXI_RESET_BIT, AXI_RESET_1);
+			break;
+		case COMPONENT_PFE_SYS:
+			/* Put the PFE device in reset state */
+			writel(readl(AXI_RESET_1) | PFE_SYS_AXI_RESET_BIT, AXI_RESET_1);
+			break;
+		case COMPONENT_AXI_IPSEC_EAPE:
+			/* Put the IPSEC EAPE (AXI clock domain) device in reset state */
+			writel(readl(AXI_RESET_1) | IPSEC_EAPE_AXI_RESET_BIT, AXI_RESET_1);
+			break;
+		case COMPONENT_AXI_IPSEC_SPACC:
+			/* Put the IPSEC SPACC (AXI clock domain) device in reset state */
+			writel(readl(AXI_RESET_1) | IPSEC_SPACC_AXI_RESET_BIT, AXI_RESET_1);
+			break;
+		case COMPONENT_AXI_DPI_CIE:
+			/* Put the DPI CIE (AXI clock domain) device in reset state */
+			writel(readl(AXI_RESET_0) | DPI_CIE_AXI_RESET_BIT, AXI_RESET_0);
+			break;
+		case COMPONENT_AXI_DPI_DECOMP:
+			/* Put the DPI DECOMP (AXI clock domain) device in reset state */
+			writel(readl(AXI_RESET_0) | DPI_DECOMP_AXI_RESET_BIT, AXI_RESET_0);
+			break;
+		case COMPONENT_AXI_USB0:
+			/* Put the USB0 device(AXI clock domain) in reset state */
+			writel(readl(AXI_RESET_2) | USB0_AXI_RESET_BIT, AXI_RESET_2);
+			break;
+		case COMPONENT_UTMI_USB0:
+			/* Put the USB0 device(UTMI clock domain) in reset state */
+			writel(readl(USB_RST_CNTRL) | USB0_UTMI_RESET_BIT, USB_RST_CNTRL);
+			break;
+		case COMPONENT_USB0_PHY:
+			/* Put the USB0_PHY device in reset state */
+			writel(readl(USB_RST_CNTRL) | USB0_PHY_RESET_BIT, USB_RST_CNTRL);
+			break;
+		case COMPONENT_AXI_USB1:
+			/* Put the USB1 device in reset state */
+			writel(readl(AXI_RESET_2) | USB1_AXI_RESET_BIT, AXI_RESET_2);
+			break;
+		case COMPONENT_UTMI_USB1:
+			/* Put the USB1 device(UTMI clock domain) in reset state */
+			writel(readl(USB_RST_CNTRL) | USB1_UTMI_RESET_BIT, USB_RST_CNTRL);
+			break;
+		case COMPONENT_USB1_PHY:
+			/* Put the USB1_PHY device in reset state */
+			writel(readl(USB_RST_CNTRL) | USB1_PHY_RESET_BIT, USB_RST_CNTRL);
+			break;
+		case COMPONENT_AXI_SATA:
+			/* Put the SATA device in reset state */
+			writel(readl(AXI_RESET_2) | SATA_AXI_RESET_BIT, AXI_RESET_2);
+			break;
+		case COMPONENT_AXI_PCIE0:
+			/* Put the PCIE0 device in reset state */
+			writel(readl(AXI_RESET_2) | PCIE0_AXI_RESET_BIT, AXI_RESET_2);
+			break;
+		case COMPONENT_AXI_PCIE1:
+			/* Put the PCIE1  device in reset state */
+			writel(readl(AXI_RESET_2) | PCIE1_AXI_RESET_BIT, AXI_RESET_2);
+			break;
+		case COMPONENT_PFE_CORE:
+			/* Put the PFE core  device in reset state */
+			writel(readl(PFE_RESET) | PFE_CORE_RESET_BIT, PFE_RESET);
+			break;
+		case COMPONENT_IPSEC_EAPE_CORE:
+			/* Put the IPSEC EAPE  core  device in reset state */
+			writel(readl(IPSEC_RESET) | IPSEC_EAPE_CORE_RESET_BIT, IPSEC_RESET);
+			break;
+		case COMPONENT_GEMTX:
+			/* Put the GEMTX device in reset state */
+			writel(readl(GEMTX_RESET) | GEMTX_RESET_BIT , GEMTX_RESET);
+			break;
+		case COMPONENT_DECT:
+			/* Put the DECT device in reset state */
+			writel(readl(DECT_RESET) | DECT_RESET_BIT , DECT_RESET);
+			break;
+		case COMPONENT_DDR_CNTLR:
+			/* Put the DDR controller  device in reset state */
+			writel(readl(DDR_RESET) | DDR_CNTRL_RESET_BIT , DDR_RESET);
+			break;
+		case COMPONENT_DDR_PHY:
+			/* Put the DDR PHY  device in reset state */
+			writel(readl(DDR_RESET) | DDR_PHY_RESET_BIT , DDR_RESET);
+			break;
+		case COMPONENT_SERDES0:
+			/* Put  SERDES0 controller  in Reset state */
+			writel(readl(SERDES_RST_CNTRL) | SERDES0_RESET_BIT ,SERDES_RST_CNTRL);
+			break;
+		case COMPONENT_SERDES_PCIE0:
+			/* Put the PCIE0 SERDES controller in Reset state */
+			writel(readl(PCIe_SATA_RST_CNTRL) | SERDES_PCIE0_RESET_BIT, PCIe_SATA_RST_CNTRL);
+			break;
+		case COMPONENT_SERDES1:
+			/* Put SERDES1 contrller 1 in reset state */
+			writel(readl(SERDES_RST_CNTRL) | SERDES1_RESET_BIT ,SERDES_RST_CNTRL);
+			break;
+		case COMPONENT_SERDES_PCIE1: 
+			/* Put PCIE1 serdes controller in reset state */
+			writel(readl(PCIe_SATA_RST_CNTRL) | SERDES_PCIE1_RESET_BIT , PCIe_SATA_RST_CNTRL);
+			break;
+		case COMPONENT_SERDES_SATA0: 
+			/* Put SATA0 serdes controller in reset state */
+			writel(readl(PCIe_SATA_RST_CNTRL) | (SERDES_SATA0_RESET_BIT), PCIe_SATA_RST_CNTRL);
+			break;
+		case COMPONENT_SERDES2:
+			/* Put SERDES2 contrller  in reset state */
+			writel(readl(SERDES_RST_CNTRL) | SERDES2_RESET_BIT ,SERDES_RST_CNTRL);
+			break;
+		case COMPONENT_SERDES_SATA1: 
+			/* Put SATA1 serdes controller in reset state */
+			writel(readl(PCIe_SATA_RST_CNTRL) | SERDES_SATA1_RESET_BIT , PCIe_SATA_RST_CNTRL);
+			break;
+		case COMPONENT_SGMII: 
+			/* Put SGMII serdes controller in reset state */
+			writel(readl(SGMII_OCC_RESET) | (SGMII_RESET_BIT), SGMII_OCC_RESET);
+			break;
+		case COMPONENT_SATA_PMU:
+			/* Put the SATA PMU(Keep Alive clock) in Reset state */
+			writel(readl(SATA_PMU_RESET) | SATA_PMU_RESET_BIT, SATA_PMU_RESET);
+			break;
+		case COMPONENT_SATA_OOB:
+			/* Put the SATA OOB in Reset state */
+			writel(readl(SATA_OOB_RESET) | SATA_OOB_RESET_BIT, SATA_OOB_RESET);
+			break;
+		case COMPONENT_TDMNTG:
+			/* Put the TDMNTG  in Reset state */
+			writel(readl(TDMNTG_RESET) | TDMNTG_RESET_BIT, TDMNTG_RESET);
+			break;
+		default :
+			break;
+	}	
+}else{
+	/* Code is to put the device block to Out of reset */
+	switch (block)
+	{
+		case COMPONENT_AXI_RTC:
+			/* Put the Timer device in Out-Of-Reset state */
+			writel(readl(AXI_RESET_1) & ~RTC_AXI_RESET_BIT, AXI_RESET_1);
+			break;
+		case COMPONENT_AXI_I2C:
+			i2cspi_state[0]=0;
+			goto i2cspi_outrst;
+		case COMPONENT_AXI_LEGACY_SPI:
+			i2cspi_state[1]=0;
+		i2cspi_outrst:
+			/* Put the I2C/SPI device in Out-Of-Reset state */
+			writel(readl(AXI_RESET_1) & ~I2CSPI_AXI_RESET_BIT, AXI_RESET_1);
+			break;
+		case COMPONENT_AXI_DMA:
+			dus_state[0]=0;
+			goto dus_outrst;
+		case COMPONENT_AXI_FAST_UART:
+			dus_state[1]=0;
+			goto dus_outrst;
+		case COMPONENT_AXI_FAST_SPI:
+			dus_state[2]=0;
+		dus_outrst:
+			/* Put the DUS devices in Out-Of-Reset state */
+			writel(readl(AXI_RESET_1) & ~DUS_AXI_RESET_BIT , AXI_RESET_1);
+			break;
+		case COMPONENT_AXI_TDM:
+			/* Put the TDM device in Out-Of-Reset state */
+			writel(readl(AXI_RESET_1) & ~TDM_AXI_RESET_BIT, AXI_RESET_1);
+			break;
+		case COMPONENT_PFE_SYS:
+			/* Put the PFE System devices in Out-Of-Reset state */
+			writel(readl(AXI_RESET_1) & ~PFE_SYS_AXI_RESET_BIT, AXI_RESET_1);
+			break;
+		case COMPONENT_AXI_IPSEC_EAPE:
+			/* Put the IPSEC EAPE devices in Out-Of-Reset state */
+			writel(readl(AXI_RESET_1) & ~IPSEC_EAPE_AXI_RESET_BIT, AXI_RESET_1);
+			break;
+		case COMPONENT_AXI_IPSEC_SPACC:
+			/* Put the IPSEC SPACC devices in Out-Of-Reset state */
+			writel(readl(AXI_RESET_1) & ~IPSEC_SPACC_AXI_RESET_BIT, AXI_RESET_1);
+			break;
+		case COMPONENT_AXI_DPI_CIE:
+			/* Put the DPI CIE devices in Out-Of-Reset state */
+			writel(readl(AXI_RESET_0) & ~DPI_CIE_AXI_RESET_BIT, AXI_RESET_0);
+			break;
+		case COMPONENT_AXI_DPI_DECOMP:
+			/* Put the DPI DECOMP devices in Out-Of-Reset state */
+			writel(readl(AXI_RESET_0) & ~DPI_DECOMP_AXI_RESET_BIT, AXI_RESET_0);
+			break;
+		case COMPONENT_AXI_USB0:
+			/* Put the USB0 device in Out-Of-Reset state */
+			writel(readl(AXI_RESET_2) & ~USB0_AXI_RESET_BIT, AXI_RESET_2);
+			break;
+		case COMPONENT_UTMI_USB0:
+			/* Put the USB0 device(UTMI clock domain) in Out-Of-reset state */
+			writel(readl(USB_RST_CNTRL) & ~USB0_UTMI_RESET_BIT, USB_RST_CNTRL);
+			break;
+		case COMPONENT_USB0_PHY:
+			/* Put the USB0_PHY devices in Out-Of-Reset state */
+			writel(readl(USB_RST_CNTRL)& ~USB0_PHY_RESET_BIT, USB_RST_CNTRL);
+			break;
+		case COMPONENT_AXI_USB1:
+			/* Put the USB1 device in Out-Of-Reset state */
+			writel(readl(AXI_RESET_2) & ~USB1_AXI_RESET_BIT, AXI_RESET_2);
+			break;
+		case COMPONENT_UTMI_USB1:
+			/* Put the USB1 device(UTMI clock domain) in Out-Of-reset state */
+			writel(readl(USB_RST_CNTRL) & ~USB1_UTMI_RESET_BIT, USB_RST_CNTRL);
+			break;
+		case COMPONENT_USB1_PHY:
+			/* Put the USB1_PHY devices in Out-Of-Reset state */
+			writel(readl(USB_RST_CNTRL)& ~USB1_PHY_RESET_BIT, USB_RST_CNTRL);
+			break;
+		case COMPONENT_AXI_SATA:
+			/* Put the SATA device in Out-Of-Reset state */
+			writel(readl(AXI_RESET_2) & ~SATA_AXI_RESET_BIT, AXI_RESET_2);
+			break;
+		case COMPONENT_AXI_PCIE0:
+			/* Put the PCIE0 device in Out-Of-reset state */
+			writel(readl(AXI_RESET_2) & ~PCIE0_AXI_RESET_BIT, AXI_RESET_2);
+			break;
+		case COMPONENT_AXI_PCIE1:
+			/* Put the PCIE1 device in Out-Of-Reset state */
+			writel(readl(AXI_RESET_2) & ~PCIE1_AXI_RESET_BIT, AXI_RESET_2);
+			break;
+		case COMPONENT_PFE_CORE:
+			/* Put the PFE core  device Out-Of-Reset state */
+			writel(readl(PFE_RESET) & ~PFE_CORE_RESET_BIT, PFE_RESET);
+			break;
+		case COMPONENT_IPSEC_EAPE_CORE:
+			/* Put the IPSEC EAPE  core  device in Out-Of-Reset state */
+			writel(readl(IPSEC_RESET) & ~IPSEC_EAPE_CORE_RESET_BIT, IPSEC_RESET);
+			break;
+		case COMPONENT_GEMTX:
+			/* Put the GEMTX device in Out-Of-Reset state */
+			writel(readl(GEMTX_RESET) & ~GEMTX_RESET_BIT , GEMTX_RESET);
+			break;
+		case COMPONENT_DECT:
+			/* Put the DECT device in Out-Of-Reset state */
+			writel(readl(DECT_RESET) & ~DECT_RESET_BIT , DECT_RESET);
+			break;
+		case COMPONENT_DDR_CNTLR:
+			/* Put the DDR controller  device in Out-Of-Reset state */
+			writel(readl(DDR_RESET) & ~DDR_CNTRL_RESET_BIT , DDR_RESET);
+			break;
+		case COMPONENT_DDR_PHY:
+			/* Put the DDR PHY  device in Out-Of-Reset state */
+			writel(readl(DDR_RESET) & ~DDR_PHY_RESET_BIT , DDR_RESET);
+			break;
+		case COMPONENT_SERDES0:
+			/* put the SERDES0 controller  in Out-of-Reset state */
+			writel(readl(SERDES_RST_CNTRL) & ~SERDES0_RESET_BIT ,SERDES_RST_CNTRL);
+			break;
+		case COMPONENT_SERDES_PCIE0:
+			/* Put the PCIE0 SERDES controller in Out-Of-Reset state */
+			writel(readl(PCIe_SATA_RST_CNTRL) & ~SERDES_PCIE0_RESET_BIT, PCIe_SATA_RST_CNTRL);
+			break;
+		case COMPONENT_SERDES1:
+			/* Put SEDES1 controller in Out-Of-reset state */
+			writel(readl(SERDES_RST_CNTRL)& ~SERDES1_RESET_BIT ,SERDES_RST_CNTRL);
+			break;
+		case COMPONENT_SERDES_PCIE1: 
+			/* Put PCIE1 serdes controller in Out-Of-Reset state */
+			writel(readl(PCIe_SATA_RST_CNTRL) & ~SERDES_PCIE1_RESET_BIT , PCIe_SATA_RST_CNTRL);
+			break;
+		case COMPONENT_SERDES_SATA0: 
+			writel(readl(PCIe_SATA_RST_CNTRL) & ~SERDES_SATA0_RESET_BIT, PCIe_SATA_RST_CNTRL);
+			break;
+		case COMPONENT_SERDES2:
+			/* Put Serdes contrller 1 in Out-Of-Reset state */
+			writel(readl(SERDES_RST_CNTRL) & ~SERDES2_RESET_BIT ,SERDES_RST_CNTRL);
+			break;
+		case COMPONENT_SERDES_SATA1: 
+			/* Put SATA1 serdes controller in Out-Of-reset state */
+			writel(readl(PCIe_SATA_RST_CNTRL) & ~SERDES_SATA1_RESET_BIT , PCIe_SATA_RST_CNTRL);
+			break;
+		case COMPONENT_SGMII: 
+			/* Put the SGMII controller in Out-Of-Reset state */
+			writel(readl(SGMII_OCC_RESET) & ~SGMII_RESET_BIT, SGMII_OCC_RESET);
+			break;
+		case COMPONENT_SATA_PMU:
+			/* Put the SATA PMU(KEEP ALIVE clock) in Out-Of-Reset state */
+			writel(readl(SATA_PMU_RESET) & ~SATA_PMU_RESET_BIT , SATA_PMU_RESET);
+			break;
+		case COMPONENT_SATA_OOB:
+			/* Put the SATA OOB  in Out-Of-Reset state */
+			writel(readl(SATA_OOB_RESET) & ~SATA_OOB_RESET_BIT , SATA_OOB_RESET);
+			break;
+		case COMPONENT_TDMNTG:
+			/* Put the TDMNTG  in Out-Of-Reset state */
+			writel(readl(TDMNTG_RESET) & ~TDMNTG_RESET_BIT, TDMNTG_RESET);
+			break;
+		default :
+			break;
+	}
+}
+spin_unlock_irqrestore(&reset_lock,flags);
+}
+EXPORT_SYMBOL(c2000_block_reset);
+
+#if defined(CONFIG_C2K_MFCN_EVM)
+void GPIO_reset_external_device(int block,int state)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&gpio_lock, flags);
+
+	/* Blocks to be put in out of Reset and reset mode
+	 * 0 ----> out of reset
+	 * 1 ----> reset
+	 */
+	switch (block){
+		case COMPONENT_ATHEROS_SWITCH:
+			if(gpio_request_one(GPIO_PIN_NUM_5, GPIOF_OUT_INIT_HIGH, GPIO_PIN_DESC_5)){
+				printk(KERN_ERR "%s:%d: Cannot request gpio for gpio-%d\n", \
+						__func__, __LINE__, GPIO_PIN_NUM_4);
+				return;
+			}
+
+			if (state){
+				gpio_set_value(GPIO_PIN_NUM_5, GPIO_SET_0);
+
+				gpio_direction_input(GPIO_PIN_NUM_5);
+			}else{
+				gpio_set_value(GPIO_PIN_NUM_5, GPIO_SET_0);
+
+				gpio_direction_output(GPIO_PIN_NUM_5, GPIO_SET_0);
+
+				gpio_set_value(GPIO_PIN_NUM_5, GPIO_SET_1);
+			}
+
+			gpio_free(GPIO_PIN_NUM_5);
+
+			break;
+
+		case COMPONENT_SLIC:
+			if(gpio_request_one(GPIO_PIN_NUM_4, GPIOF_OUT_INIT_HIGH, GPIO_PIN_DESC_4)){
+				printk(KERN_ERR "%s:%d: Cannot request gpio for gpio-%d\n", \
+						__func__, __LINE__, GPIO_PIN_NUM_4);
+				return;
+			}
+
+			if (state){
+				gpio_set_value(GPIO_PIN_NUM_4, GPIO_SET_0);
+
+				gpio_direction_input(GPIO_PIN_NUM_4);
+			}else{
+				gpio_set_value(GPIO_PIN_NUM_4, GPIO_SET_0);
+
+				gpio_direction_output(GPIO_PIN_NUM_4, GPIO_SET_0);
+
+				gpio_set_value(GPIO_PIN_NUM_4, GPIO_SET_1);
+			}
+
+			gpio_free(GPIO_PIN_NUM_4);
+
+			break;
+
+		case COMPONENT_PCIE0:
+			if (state){
+				writel(readl(COMCERTO_GPIO_63_32_PIN_OUTPUT) & ~GPIO_PIN_48, COMCERTO_GPIO_63_32_PIN_OUTPUT);
+				writel( readl(COMCERTO_GPIO_63_32_PIN_OUTPUT_EN) | GPIO_PIN_48, COMCERTO_GPIO_63_32_PIN_OUTPUT_EN);
+				writel(readl(COMCERTO_GPIO_63_32_PIN_SELECT) & ~GPIO_PIN_48, COMCERTO_GPIO_63_32_PIN_SELECT);
+			}else{
+				writel(readl(COMCERTO_GPIO_63_32_PIN_OUTPUT) & ~GPIO_PIN_48, COMCERTO_GPIO_63_32_PIN_OUTPUT);
+				writel( readl(COMCERTO_GPIO_63_32_PIN_OUTPUT_EN) & ~GPIO_PIN_48, COMCERTO_GPIO_63_32_PIN_OUTPUT_EN);
+				writel(readl(COMCERTO_GPIO_63_32_PIN_OUTPUT) | GPIO_PIN_48, COMCERTO_GPIO_63_32_PIN_OUTPUT);
+				writel(readl(COMCERTO_GPIO_63_32_PIN_SELECT) | GPIO_PIN_48, COMCERTO_GPIO_63_32_PIN_SELECT);
+			}
+			break;
+		case COMPONENT_PCIE1:
+			if (state){
+				writel(readl(COMCERTO_GPIO_63_32_PIN_OUTPUT) & ~GPIO_PIN_47, COMCERTO_GPIO_63_32_PIN_OUTPUT);
+				writel( readl(COMCERTO_GPIO_63_32_PIN_OUTPUT_EN) | GPIO_PIN_47, COMCERTO_GPIO_63_32_PIN_OUTPUT_EN);
+				writel(readl(COMCERTO_GPIO_63_32_PIN_SELECT) & ~GPIO_PIN_47, COMCERTO_GPIO_63_32_PIN_SELECT);
+			}else{
+				writel(readl(COMCERTO_GPIO_63_32_PIN_OUTPUT) & ~GPIO_PIN_47, COMCERTO_GPIO_63_32_PIN_OUTPUT);
+				writel( readl(COMCERTO_GPIO_63_32_PIN_OUTPUT_EN) & ~GPIO_PIN_47, COMCERTO_GPIO_63_32_PIN_OUTPUT_EN);
+				writel(readl(COMCERTO_GPIO_63_32_PIN_OUTPUT) | GPIO_PIN_47, COMCERTO_GPIO_63_32_PIN_OUTPUT);
+				writel(readl(COMCERTO_GPIO_63_32_PIN_SELECT) | GPIO_PIN_47, COMCERTO_GPIO_63_32_PIN_SELECT);
+			}
+			break;
+		case COMPONENT_USB_HUB:
+			if (state){
+				writel(readl(COMCERTO_GPIO_63_32_PIN_OUTPUT) & ~GPIO_PIN_50, COMCERTO_GPIO_63_32_PIN_OUTPUT);
+				writel( readl(COMCERTO_GPIO_63_32_PIN_OUTPUT_EN) | GPIO_PIN_50, COMCERTO_GPIO_63_32_PIN_OUTPUT_EN);
+				writel(readl(COMCERTO_GPIO_63_32_PIN_SELECT) & ~GPIO_PIN_50, COMCERTO_GPIO_63_32_PIN_SELECT);
+			}else{
+				writel(readl(COMCERTO_GPIO_63_32_PIN_OUTPUT) & ~GPIO_PIN_50, COMCERTO_GPIO_63_32_PIN_OUTPUT);
+				writel( readl(COMCERTO_GPIO_63_32_PIN_OUTPUT_EN) & ~GPIO_PIN_50, COMCERTO_GPIO_63_32_PIN_OUTPUT_EN);
+				writel(readl(COMCERTO_GPIO_63_32_PIN_OUTPUT) | GPIO_PIN_50, COMCERTO_GPIO_63_32_PIN_OUTPUT);
+				writel(readl(COMCERTO_GPIO_63_32_PIN_SELECT) | GPIO_PIN_50, COMCERTO_GPIO_63_32_PIN_SELECT);
+			}
+			break;
+		case COMPONENT_EXP_DAUGTHER_CARD:
+			if (state){
+				writel(readl(COMCERTO_GPIO_63_32_PIN_OUTPUT) & ~GPIO_PIN_49, COMCERTO_GPIO_63_32_PIN_OUTPUT);
+				writel( readl(COMCERTO_GPIO_63_32_PIN_OUTPUT_EN) | GPIO_PIN_49, COMCERTO_GPIO_63_32_PIN_OUTPUT_EN);
+				writel(readl(COMCERTO_GPIO_63_32_PIN_SELECT) & ~GPIO_PIN_49, COMCERTO_GPIO_63_32_PIN_SELECT);
+			}else{
+				writel(readl(COMCERTO_GPIO_63_32_PIN_OUTPUT) & ~GPIO_PIN_49, COMCERTO_GPIO_63_32_PIN_OUTPUT);
+				writel( readl(COMCERTO_GPIO_63_32_PIN_OUTPUT_EN) & ~GPIO_PIN_49, COMCERTO_GPIO_63_32_PIN_OUTPUT_EN);
+				writel(readl(COMCERTO_GPIO_63_32_PIN_OUTPUT) | GPIO_PIN_49, COMCERTO_GPIO_63_32_PIN_OUTPUT);
+				writel(readl(COMCERTO_GPIO_63_32_PIN_SELECT) | GPIO_PIN_49, COMCERTO_GPIO_63_32_PIN_SELECT);
+			}
+			break;
+		case COMPONENT_RGMII0:
+			if (state){
+				writel(readl(COMCERTO_GPIO_63_32_PIN_OUTPUT) & ~GPIO_PIN_46, COMCERTO_GPIO_63_32_PIN_OUTPUT);
+				writel( readl(COMCERTO_GPIO_63_32_PIN_OUTPUT_EN) | GPIO_PIN_46, COMCERTO_GPIO_63_32_PIN_OUTPUT_EN);
+				writel(readl(COMCERTO_GPIO_63_32_PIN_SELECT) & ~GPIO_PIN_46, COMCERTO_GPIO_63_32_PIN_SELECT);
+			}else{
+				writel(readl(COMCERTO_GPIO_63_32_PIN_OUTPUT) & ~GPIO_PIN_46, COMCERTO_GPIO_63_32_PIN_OUTPUT);
+				writel( readl(COMCERTO_GPIO_63_32_PIN_OUTPUT_EN) & ~GPIO_PIN_46, COMCERTO_GPIO_63_32_PIN_OUTPUT_EN);
+				writel(readl(COMCERTO_GPIO_63_32_PIN_OUTPUT) | GPIO_PIN_46, COMCERTO_GPIO_63_32_PIN_OUTPUT);
+				writel(readl(COMCERTO_GPIO_63_32_PIN_SELECT) | GPIO_PIN_46, COMCERTO_GPIO_63_32_PIN_SELECT);
+			}
+			break;
+		case COMPONENT_RGMII1:
+			if (state){
+				writel(readl(COMCERTO_GPIO_63_32_PIN_OUTPUT) & ~GPIO_PIN_45, COMCERTO_GPIO_63_32_PIN_OUTPUT);
+				writel( readl(COMCERTO_GPIO_63_32_PIN_OUTPUT_EN) | GPIO_PIN_45, COMCERTO_GPIO_63_32_PIN_OUTPUT_EN);
+				writel(readl(COMCERTO_GPIO_63_32_PIN_SELECT)& ~GPIO_PIN_45, COMCERTO_GPIO_63_32_PIN_SELECT);
+			}else{
+				writel(readl(COMCERTO_GPIO_63_32_PIN_OUTPUT) & ~GPIO_PIN_45, COMCERTO_GPIO_63_32_PIN_OUTPUT);
+				writel( readl(COMCERTO_GPIO_63_32_PIN_OUTPUT_EN) & ~GPIO_PIN_45, COMCERTO_GPIO_63_32_PIN_OUTPUT_EN);
+				writel(readl(COMCERTO_GPIO_63_32_PIN_OUTPUT) | GPIO_PIN_45, COMCERTO_GPIO_63_32_PIN_OUTPUT);
+				writel(readl(COMCERTO_GPIO_63_32_PIN_SELECT) | GPIO_PIN_45, COMCERTO_GPIO_63_32_PIN_SELECT);
+			}
+			break;
+		default:
+			break;
+	}
+
+	spin_unlock_irqrestore(&gpio_lock,flags);
+}
+EXPORT_SYMBOL(GPIO_reset_external_device);
+#endif
+
+void reset_init(void){
+
+	/*Initilize the DUS ,serde0/1/2 and I2CSPI dependancy values */
+	i2cspi_state[0]=i2cspi_state[1]=dus_state[0]=dus_state[1]=dus_state[2]=0;
+
+        spin_lock_init(&reset_lock);
+
+	/* Do Any boottime Reset/Out-Of-Reset to devices if required*/
+}
diff --git a/arch/arm/mach-comcerto/serdes-c2000.c b/arch/arm/mach-comcerto/serdes-c2000.c
new file mode 100644
index 0000000..955f1cc
--- /dev/null
+++ b/arch/arm/mach-comcerto/serdes-c2000.c
@@ -0,0 +1,190 @@
+
+/*
+ * Copyright (C) Mindspeed Technologies, Inc. 2011. All rights reserved.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * @file serdes.c
+ * @brief this C file will contain all required functions to program
+ *        Snowbush SerDes PHY interface.
+ * @date 10/02/2011
+ */
+
+#include <asm/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <asm/types.h>
+#include <asm/io.h>
+#include <mach/comcerto-2000.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <asm/irq.h>
+#include <asm/delay.h>
+#include <asm/sizes.h>
+#include <mach/serdes-c2000.h>
+
+#define MAX_LANE_OK_WAIT_JIFFIES	(200 * HZ) / 1000    /* 200ms */
+#define MAX_CMU_OK_WAIT_JIFFIES		(2000 * HZ) / 1000   /* 2 Seconds */
+
+/**
+ * This function Wait for the 'Lane OK' to be signaled by the 
+ * Snowbush Serdes PHY.
+ * @param sbphy_num	SerDes PHY intefrace number.
+ */
+static int wait_lane_ok(u32 sbphy_num)
+{
+	u32 rd_data = 0, masked_data = 0;
+	u32 lane_ok_dtctd_mask = 0x00001000;
+	unsigned long deadline = jiffies + MAX_LANE_OK_WAIT_JIFFIES;
+
+	/* Keep looping until you see the lane_ok_o of Serdes */
+	do
+	{
+		rd_data = readl(COMCERTO_SERDES_DWC_CFG_REG( sbphy_num, SD_PHY_STS_REG_OFST));
+
+		/* Mask lane_ok Status */
+		masked_data = rd_data & lane_ok_dtctd_mask;
+
+		if(masked_data == lane_ok_dtctd_mask) {
+			/* Lane OK Detected on Serdes Port */
+			printk(KERN_INFO "Serdes%d: Lane OK Passed\n",sbphy_num);
+			return 1;
+		}
+
+		cond_resched();
+
+	} while (!time_after_eq(jiffies, deadline));
+
+	printk(KERN_INFO "Serdes%d: Lane OK Failed\n",sbphy_num);
+	return 0;
+}
+
+
+/**
+ * This function wait for the 'CMU OK' to be signaled by the
+ * Snowbush Serdes PHY.
+ * @param sbphy_num	SerDes PHY intefrace number.
+ */
+static int wait_cmu_ok(u32 sbphy_num)
+{
+	u32 rd_data = 0, masked_data = 0;
+	u32 cmu_ok_dtctd_mask = 0x00004000;
+	int CMU_Offset;
+	unsigned long deadline = jiffies + MAX_CMU_OK_WAIT_JIFFIES;
+
+	CMU_Offset = COMCERTO_SERDES_DWC_CFG_REG( sbphy_num, SD_PHY_STS_REG_OFST );
+
+
+	/* Keep looping until you see the cmu_ok_o of Serdes */
+	do
+	{
+		rd_data = readl(CMU_Offset);
+
+		/* Mask cmu_ok Status */
+		masked_data = rd_data & cmu_ok_dtctd_mask;
+
+		if(masked_data == cmu_ok_dtctd_mask) {
+			/* CMU OK Detected on Serdes Port */
+			//printk(KERN_INFO "Serdes%d: CMU OK Passed\n",sbphy_num);
+			return 1;
+		}
+
+		cond_resched();
+
+	} while (!time_after_eq(jiffies, deadline));
+
+	printk(KERN_INFO "Serdes%d: CMU OK Failed\n",sbphy_num);
+
+	return 0;
+}
+
+
+/**
+ * This function wait for the specified configured Snowbush PHY
+ * (Serdes) to issue it's CMU-OK, and it's Lane to become Ready
+ * after releasing the CMU & Lane resets.
+ * @param sbphy_num	SerDes PHY intefrace number.
+ */
+static int wait_sb_cmu_lane_rdy(u32 sbphy_num, u32 type)
+{
+	u32 sd_ctl2_reg_offset;
+	u32 cmu_rst_mask = 0x00010000;
+	u32 lane_rst_mask = 0x00000040;
+	u32 tmp = 0;
+
+	sd_ctl2_reg_offset = COMCERTO_SERDES_DWC_CFG_REG( sbphy_num, SD_PHY_CTRL2_REG_OFST );
+
+	/* Releasing the CMU Reset */
+	tmp = readl(sd_ctl2_reg_offset);
+	tmp = tmp & (~cmu_rst_mask);
+	tmp = tmp | cmu_rst_mask;
+
+	writel(tmp, sd_ctl2_reg_offset );
+
+	/* Waiting for CMU OK */
+	if( !wait_cmu_ok(sbphy_num) )
+		return -1;
+
+	if ( type == SD_DEV_TYPE_PCIE )
+		writel(0xC3, COMCERTO_SERDES_REG(sbphy_num, (SD_COMMON_LANE << 2)));
+	else
+		writel(0x03, COMCERTO_SERDES_REG(sbphy_num, (SD_COMMON_LANE << 2)));
+
+	/* Releasing the Lane Reset */
+	tmp = readl(sd_ctl2_reg_offset);
+	tmp = tmp & (~lane_rst_mask);
+	tmp = tmp | lane_rst_mask;
+
+	writel(tmp, sd_ctl2_reg_offset);
+
+	/* Waiting for the Lane Ready */
+	if (type != SD_DEV_TYPE_PCIE) {
+		if( !wait_lane_ok(sbphy_num) )
+			return -1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * This function initialize the Snowbush PHY (Serdes) for operation
+ * with the one of the PCIE,SATA or SGMII IP blocks, and then waiting
+ * until it issue it's CMU-OK, and it's  Lane to become Ready after
+ * releasing the CMU & Lane Resets.
+ * @param phy_num	SerDes PHY intefrace number.
+ * @param *regs		Register file (Array of registers and coresponding
+ *                      values to be programmed).
+ * @param size		Number of registers to be programmed.
+ */
+int serdes_phy_init(int phy_num, struct serdes_regs_s *regs, int size, int type)
+{
+	int ii;
+
+	/* Initilize serdes phy registers */
+	for( ii = 0; ii < size; ii++ )
+		writel(regs[ii].val, COMCERTO_SERDES_REG(phy_num, regs[ii].ofst));
+
+	/* Wait for the initialization of Serdes-1 Port/Lane to become Ready */
+	return wait_sb_cmu_lane_rdy(phy_num, type);
+}
+
+EXPORT_SYMBOL(serdes_phy_init);
+
diff --git a/arch/arm/mach-comcerto/sleep.S b/arch/arm/mach-comcerto/sleep.S
new file mode 100644
index 0000000..5a5c275
--- /dev/null
+++ b/arch/arm/mach-comcerto/sleep.S
@@ -0,0 +1,284 @@
+/*
+ * arch/arm/mach-comcerto/sleep.S
+ *
+ * Author: Makarand Pawagi
+ *
+ * Copyright (C) 2013 Mindspeed Technologies, Inc.
+ * Copyright (c) 2003 ARM Limited
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/memory.h>
+
+#define SCRATCHPAD_SUSPEND_INDICATOR_LOC    (0xf0800000 + 0x2400)
+#define SCRATCHPAD_BASE_P       (0xf0800000+0x2400+0x100) /*IRAM_MEMORY_VADDR + Offset*/
+#define SCRATCHPAD_CPU_CONTEXT_LOC_OFFSET 0x70
+#define SCRATCHPAD_CPU_CONTEXT_LOC     SCRATCHPAD_BASE_P + SCRATCHPAD_CPU_CONTEXT_LOC_OFFSET
+
+
+	.text
+/* Function call to get the restore pointer for resume from OFF */
+ENTRY(c2k_get_restore_pointer)
+        stmfd   sp!, {lr}     @ save registers on stack
+	ARM ( adr	r0, comcerto_cpu_restore )
+        bic     r0, #PAGE_OFFSET
+        ldmfd   sp!, {pc}     @ restore regs and return
+ENTRY(get_restore_pointer_sz)
+        .word   . - get_restore_pointer_sz
+
+
+
+
+/*
+ * ======================
+ * == Idle entry point ==
+ * ======================
+ */
+
+/*
+ * Forces C2K into idle state
+ *
+ * comcerto_cpu_suspend() - This bit of code saves the CPU context if needed
+ * and executes the WFI instruction. Calling WFI effectively changes the
+ * power domains states to the desired target power states.
+ */
+	.align	3
+ENTRY(comcerto_cpu_suspend)
+	stmfd	sp!, {r4 - r11, lr}	@ save registers on stack
+
+	/*
+	 * r0 contains information about saving context:
+	 *   0 - No context lost
+	 *   1 - Only L1 and logic lost
+	 *   2 - Only L2 lost (Even L1 is retained we clean it along with L2)
+	 *   3 - Both L1 and L2 lost and logic lost
+	 */
+
+	/*
+	 * For OFF mode: save context and jump to WFI (comcerto_do_wfi)
+	 */
+	cmp	r0, #0x0		@ If no context save required,
+	beq	comcerto_do_wfi		@  jump to the WFI
+
+
+	/* Otherwise fall through to the save context code */
+comcerto_save_context_wfi:
+	/*
+	 * jump out to kernel flush routine
+	 *  - reuse that code is better
+	 *  - it executes in a cached space so is faster than refetch per-block
+	 *  - should be faster and will change with kernel
+	 *  - 'might' have to copy address, load and jump to it
+	 * Flush all data from the L1 data cache before disabling
+	 * SCTLR.C bit.
+	 */
+	ldr	r1, kernel_flush
+	mov	lr, pc
+	bx	r1
+
+	/*
+	 * Clear the SCTLR.C bit to prevent further data cache
+	 * allocation. Clearing SCTLR.C would make all the data accesses
+	 * strongly ordered and would not hit the cache.
+	 */
+	ARM ( mrc	p15, 0, r0, c1, c0, 0 )
+	ARM ( bic	r0, r0, #(1 << 2) )	@ Disable the C bit
+	ARM ( mcr	p15, 0, r0, c1, c0, 0 )
+	ARM ( isb )
+
+	/*
+	 * Invalidate L1 data cache. Even though only invalidate is
+	 * necessary exported flush API is used here. Doing clean
+	 * on already clean cache would be almost NOP.
+	 */
+	ldr	r1, kernel_flush
+	blx	r1
+	/*
+	 * The kernel doesn't interwork: v7_flush_dcache_all in particluar will
+	 * always return in Thumb state when CONFIG_THUMB2_KERNEL is enabled.
+	 * This sequence switches back to ARM.  Note that .align may insert a
+	 * nop: bx pc needs to be word-aligned in order to work.
+	 */
+ THUMB(	.thumb		)
+ THUMB(	.align		)
+ THUMB(	bx	pc	)
+ THUMB(	nop		)
+	.arm
+
+	b	comcerto_do_wfi
+
+/*
+ * Local variables
+ */
+kernel_flush:
+	.word v7_flush_dcache_all
+
+
+/* ===================================
+ * == WFI instruction => Enter idle ==
+ * ===================================
+ */
+
+/*
+ * Do WFI instruction
+ * Includes the resume path for non-OFF modes [TBD]
+ */
+	.align	3
+ENTRY(comcerto_do_wfi)
+
+	/* Store cpsr and spsr */
+        ldr 	r7, scratchpad_cpu_context_loc
+
+	/*mrs	r4, cpsr
+	mrs	r5, spsr
+	stmia	r7!, {r4-r5}*/
+
+
+
+	/* Saving all the banked registers */
+        mrs     r0, cpsr
+
+        /* Save the Undef mode reisters */
+        bic     r1, r0, #0x1f
+        orr     r1, r1, #0x1b
+        msr     cpsr_c, r1
+	ARM ( stmia	r7!, {r13-r14} )
+	mrs	r13, spsr
+	stmia	r7!, {r13}
+
+        /* Save the Abort mode reisters */
+        bic     r1, r0, #0x1f
+        orr     r1, r1, #0x17
+        msr     cpsr_c, r1
+	ARM ( stmia	r7!, {r13-r14} )
+	mrs	r13, spsr
+	stmia	r7!, {r13}
+
+        /* Save the IRQ mode reisters */
+        bic     r1, r0, #0x1f
+        orr     r1, r1, #0x12
+        msr     cpsr_c, r1
+	ARM ( stmia	r7!, {r13-r14} )
+	mrs	r13, spsr
+	stmia	r7!, {r13}
+
+        /* Save the FIQ mode reisters */
+        bic     r1, r0, #0x1f
+        orr     r1, r1, #0x11
+        msr     cpsr_c, r1
+	ARM ( stmia	r7!, {r8-r14} )
+	THUMB ( stmia	r7!, {r8-r12} )
+	mrs	r13, spsr
+	stmia	r7!, {r13}
+
+        /* Return to the original mode */
+        msr     cpsr_c, r0
+
+	/* We can Put DDR in self refresh mode here [TBD] */
+
+	/* Pass control to UtilPE */
+        ldr r4, scratchpad_reboot_indicator_loc
+        mov r5, #0xFF
+        str r5, [r4]
+
+	/* Data memory barrier and Data sync barrier */
+	dsb
+	dmb
+
+/*
+ * ===================================
+ * == WFI instruction => Enter idle ==
+ * ===================================
+ */
+	wfi				@ wait for interrupt
+
+/*
+ * =========================================
+ * ==  Resume path for non-OFF modes TBD  ==
+ * =========================================
+ */
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+/*
+ * ===================================
+ * TBD
+ * ===================================
+ */
+
+/*
+ * ==============================
+ * == Resume path for OFF mode ==
+ * ==============================
+ */
+
+/*
+ * The restore function is instaleed at 0x0 location
+ * of DDR.
+ */
+
+ENTRY(comcerto_cpu_restore)
+	ldr	r1, l2dis_3630
+	cmp	r1, #0x1		/*@ Test if L2 re-enable needed on 3630*/
+	bne	skipl2reen
+	mrc	p15, 0, r1, c1, c0, 1
+	orr	r1, r1, #2		/*@ re-enable L2 cache*/
+	mcr	p15, 0, r1, c1, c0, 1
+skipl2reen:
+
+
+	/* Now branch to the common CPU resume function */
+	blx	cpu_resume
+
+	.ltorg
+
+/*
+ * Local variables
+ */
+
+l2dis_3630:
+	.word
+
+
+ENTRY(copy_words)
+	cmp	r2, #0
+	beq	f1
+b0:
+	ldr	r3, [r1], #4
+	str	r3, [r0], #4
+	subs	r2, r2, #1
+	bne	b0
+f1:
+	bx	lr
+
+
+
+
+scratchpad_cpu_context_loc:
+        .word   SCRATCHPAD_CPU_CONTEXT_LOC
+scratchpad_reboot_indicator_loc:
+        .word   SCRATCHPAD_SUSPEND_INDICATOR_LOC
diff --git a/arch/arm/mach-comcerto/sysfstdm.c b/arch/arm/mach-comcerto/sysfstdm.c
new file mode 100644
index 0000000..0f50020
--- /dev/null
+++ b/arch/arm/mach-comcerto/sysfstdm.c
@@ -0,0 +1,552 @@
+ /*
+  *  Copyright (C) 2008 Mindspeed Technologies, Inc.
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 2 of the License, or
+  * (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+  */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <mach/comcerto-common.h>
+#include <asm/div64.h>
+#include <mach/comcerto-2000/clk-rst.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <mach/reset.h>
+
+/* Defalult Rate value is in Hz*/
+#define TDMNTG_DEFAULT_REF_CLK 500000000
+
+/* since 'ppm' means parts-per-million */
+#define MILLION (1000000UL)
+
+/* NTG to TDM clock dividers */
+#define COMCERTO_BLOCK_TDM_DIV	1
+#define COMCERTO_BLOCK_ZDS_DIV	24
+#define COMCERTO_BLOCK_GPIO_DIV	1
+#define COMCERTO_BLOCK_MSIF_DIV	12
+static int comcerto_block_clk_div [4] = {COMCERTO_BLOCK_TDM_DIV, COMCERTO_BLOCK_ZDS_DIV, COMCERTO_BLOCK_GPIO_DIV, COMCERTO_BLOCK_MSIF_DIV};
+static int block_selected;
+static int block_sel_cnt = 0;
+static spinlock_t block_lock;
+
+/*ntgref clock*/
+static struct clk *clk_ntg_ref;
+static unsigned long tdmntg_ref_clk;
+
+static unsigned long BaseClock = 0; /* frequency is set by clock_frequency_set() */
+
+static void fsync_output_set(unsigned int fsoutput)
+{
+	if (fsoutput)
+	{
+		writel(readl(COMCERTO_GPIO_TDM_MUX) | (1 << 0), COMCERTO_GPIO_TDM_MUX);
+		writel(readl(TDM_FSYNC_GEN_CTRL) | (1 << 0), TDM_FSYNC_GEN_CTRL);
+	}
+	else
+	{
+		writel(readl(COMCERTO_GPIO_TDM_MUX) & ~(1 << 0), COMCERTO_GPIO_TDM_MUX);
+		writel(readl(TDM_FSYNC_GEN_CTRL) & ~(1 << 0), TDM_FSYNC_GEN_CTRL);
+	}
+}
+
+static void fsync_polarity_set(unsigned int fspolarity)
+{
+	/* 28 FSYNC_FALL(RISE)_EDGE */
+	if (fspolarity)
+		writel(readl(TDM_FSYNC_GEN_CTRL) | FSYNC_FALL_EDGE, TDM_FSYNC_GEN_CTRL);
+	else
+		writel(readl(TDM_FSYNC_GEN_CTRL) & ~FSYNC_FALL_EDGE, TDM_FSYNC_GEN_CTRL);
+}
+
+static void fsync_lphase_set(u32 fslwidth)
+{
+	/* Low_Phase_Width 7ff- maximum */
+	if (fslwidth > 0x7FF) {
+		printk(KERN_ERR "%s: Low Phase width value is out of range %#x > 0x7FF\n", __func__, fslwidth);
+		return;
+	}
+
+	writel(fslwidth, TDM_FSYNC_LOW);
+}
+
+static void fsync_hphase_set(u32 fshwidth)
+{
+	/* High_Phase_Width 7ff- maximum */
+        if (fshwidth > 0x7FF) {
+		printk(KERN_ERR "%s: High Phase width value is out of range %#x > 0x7FF\n", __func__, fshwidth);
+		return;
+	}
+
+	writel(fshwidth, TDM_FSYNC_HIGH);
+}
+
+static void clock_frequency_set(unsigned long clockhz)
+{
+	unsigned long long ntg_incr ;
+
+	BaseClock = clockhz;
+
+	/* Calculate NTG clock: multiply TDM base clock with block divider */	
+	/* clock_frequency_set() is called with block_lock taken */
+	ntg_incr =  comcerto_block_clk_div[block_selected] * clockhz;
+	/* get frequency resolution on an 32-bit accumulator */
+	ntg_incr = ntg_incr * (1ULL << 32) + tdmntg_ref_clk / 2;
+	do_div(ntg_incr, tdmntg_ref_clk);
+	printk(KERN_INFO "%s: (%d:%d) NTG INCR value is %llu\n", __func__, block_selected, comcerto_block_clk_div[block_selected], ntg_incr);
+
+	/* ntg_incr = 0x10C6F7A for 2.048 MHz */
+	/* ntg_incr = 0xC953969 for 24.576 MHz */
+	/* ntg_incr = 0x192A7371 for 49.152 MHz */
+	writel(ntg_incr, TDM_NTG_INCR);
+}
+
+static unsigned long clock_frequency_get(void)
+{
+	unsigned long long clc_data;
+
+	/* According to the desired TDM clock output frequency, this field should be configured */
+	clc_data = (readl(TDM_NTG_INCR) & 0x3FFFFFFF);/* get frequency from resolution on an 32-bit accumulator */
+	clc_data = (clc_data * tdmntg_ref_clk + (1ULL << 31)) >> 32;
+	/* Divide down the Data with TDM block divider */
+	do_div(clc_data, comcerto_block_clk_div[block_selected]); /* do_div because of 64 bit operation*/
+	return (unsigned long)(clc_data);
+}
+
+static void clock_output_set(unsigned long clockout)
+{
+	switch (clockout) {
+	case 0:
+		writel((0x2 << 12) | (readl(COMCERTO_GPIO_BOOTSTRAP_OVERRIDE) & ~(0x3 << 12)), COMCERTO_GPIO_BOOTSTRAP_OVERRIDE);
+		break;
+	case 1:
+		writel((0x3 << 12) | (readl(COMCERTO_GPIO_BOOTSTRAP_OVERRIDE) &	~(0x3 << 12)), COMCERTO_GPIO_BOOTSTRAP_OVERRIDE);
+		break;
+	case 2:
+		writel((0x0 << 12) | (readl(COMCERTO_GPIO_BOOTSTRAP_OVERRIDE) &	~(0x3 << 12)), COMCERTO_GPIO_BOOTSTRAP_OVERRIDE);
+		break;
+	default:
+		printk(KERN_ERR "%s: Unknown clock output value\n", __func__);
+	}
+}
+
+static void clock_ppm_adjust(long ppm)
+{
+	unsigned long long clc_data;
+	unsigned long freq_set = BaseClock;
+	int nsign = 0;
+
+	if (!freq_set) {
+		printk(KERN_ERR "(%s): Could not adjust frequency: you should set it before\n", __func__);
+		return;
+	}
+
+	if (ppm < 0) {
+		nsign = 1;
+		ppm = -ppm;
+	}
+
+	if (nsign && (ppm >= MILLION)) {
+		/* overflow dangerous */
+		printk(KERN_ERR "(%s): This is too much ppm: -%lu\n", __func__, (unsigned long)ppm);
+		return;
+	}
+
+	clc_data = ppm * (1ULL << 32);
+
+	do_div(clc_data, MILLION);
+
+	if (nsign) {
+		clc_data = (1ULL << 32) - clc_data;
+	} else {
+		clc_data = (1ULL << 32) + clc_data;
+	}
+
+	clc_data = clc_data * freq_set + tdmntg_ref_clk / 2; /* with rounding to nearest integer */
+	clc_data *= comcerto_block_clk_div[block_selected];
+	do_div(clc_data, tdmntg_ref_clk);
+
+	if (clc_data & ~0x3FFFFFFF) {
+		/* unaccounted bits dangerous */
+		printk(KERN_ERR "(%s): This is too much ppm: %lu\n", __func__, (unsigned long)ppm);
+		return;
+	}
+
+	writel((clc_data & 0x3FFFFFFF) | (readl(TDM_NTG_INCR) & ~0x3FFFFFFF), TDM_NTG_INCR);
+}
+
+static long clock_ppm_get(void)
+{
+	unsigned long freq_set = BaseClock;
+	unsigned long freq = clock_frequency_get();
+	unsigned long long ppm;
+
+	if (freq > freq_set) {
+		ppm = (freq - freq_set) * MILLION + (freq_set >> 1);
+		do_div(ppm, freq_set);
+		return (long)ppm;
+	} else {
+		ppm = (freq_set - freq) * MILLION + (freq_set >> 1);
+		do_div(ppm, freq_set);
+		return (-1 * (long)ppm);
+	}
+}
+
+#define TDM_CTRL_SLIC_RESET 	0x80
+#define TDM_CTRL_CLK_DIV_BYPASS	0x40
+#define TDM_CTRL_DEF_DIV 	0x2
+#define TDM_CTLR_RESET_BYPASS TDM_CTRL_SLIC_RESET | TDM_CTRL_CLK_DIV_BYPASS | TDM_CTRL_DEF_DIV
+
+static void tdm_mux_set(u32 tdmmux)
+{
+	block_selected = tdmmux;
+	/* TDM interface Muxing [5:4]
+	00	TDM block is selected
+	01	ZDS block (Zarlink) is selected
+	10	GPIO[63:60] signals are selected
+	11	MSIF block (SiLabs) is selected */
+
+	switch (block_selected){
+	case 0:
+		/* TDM block selected (SiLabs si3227) */
+		writel(TDM_CTLR_RESET_BYPASS, TDM_CLK_CNTRL);    /* bypass TDM divider --> TDM = NTG out, keen ZDS/MSIF Slic reset */
+		writel((0x0 << 4) |(readl(COMCERTO_GPIO_MISC_PIN_SELECT) & ~(0x3 << 4)), COMCERTO_GPIO_MISC_PIN_SELECT);
+		break;
+
+	case 1:
+		/* ZDS block selected (Zarlink le88264) */
+		writel(TDM_CTRL_SLIC_RESET | COMCERTO_BLOCK_ZDS_DIV, TDM_CLK_CNTRL); /* TDM = NTG out / 24*/
+		writel((0x1 << 4) |(readl(COMCERTO_GPIO_MISC_PIN_SELECT) & ~(0x3 << 4)), COMCERTO_GPIO_MISC_PIN_SELECT);
+		writel(COMCERTO_BLOCK_ZDS_DIV, TDM_CLK_CNTRL); /* Remove out of reset */
+		break;
+
+	case 2:
+		/* GPIO[63:60] signals selected */
+		writel(TDM_CTLR_RESET_BYPASS, TDM_CLK_CNTRL); /* bypass TDM divider --> TDM = NTG out, keen ZDS/MSIF Slic reset */
+		writel((0x2 << 4) |(readl(COMCERTO_GPIO_MISC_PIN_SELECT) & ~(0x3 << 4)), COMCERTO_GPIO_MISC_PIN_SELECT);
+		break;
+
+	case 3:
+		/* MSIF block selected (SiLabs si32268) */
+		writel(TDM_CTRL_SLIC_RESET | COMCERTO_BLOCK_MSIF_DIV, TDM_CLK_CNTRL); /* TDM = NTG out / 12 */
+		writel((0x3 << 4) |(readl(COMCERTO_GPIO_MISC_PIN_SELECT) & ~(0x3 << 4)), COMCERTO_GPIO_MISC_PIN_SELECT);
+		writel(COMCERTO_BLOCK_MSIF_DIV, TDM_CLK_CNTRL); /* Remove out of reset */
+
+		/* Delay 100us after C2k TDM block has been un-reset, before SLIC is un-reset.
+		   Ensures MSIF interface clock is active well before SLIC is un-reset (SiLabs spec). 
+		*/
+		udelay(100);
+
+		writel(0x1 << 30, COMCERTO_GPIO_63_32_PIN_OUTPUT); /* remove slic out of reset */
+		break;
+
+	default:
+		printk(KERN_ERR "%s: Unknown TDM MUX value\n", __func__);
+	}
+}
+
+#if 0
+static void tdm_dr_set(u32 tdmdr)
+{
+	if(tdmdr > 0x3F)
+	{
+		printk(KERN_ERR "%s: TDM_DR value is out of range %#x >	0x3F\n", 	__func__, tdmdr);
+		return;
+	}
+
+	writel((tdmdr << 24) |(readl(COMCERTO_GPIO_PAD_CONFIG0) & ~(0x3F << 24)), COMCERTO_GPIO_PAD_CONFIG0);
+}
+
+static void tdm_dx_set(u32 tdmdx)
+{
+	if(tdmdx > 0x3F)
+	{
+		printk(KERN_ERR "%s: TDM_DX value is out of range %#x > 0x3F\n", __func__, tdmdx);
+		return;
+	}
+
+	writel((tdmdx << 18) |(readl(COMCERTO_GPIO_PAD_CONFIG0) & ~(0x3F << 18)), COMCERTO_GPIO_PAD_CONFIG0);
+}
+
+static void tdm_fs_set(u32 tdmfs)
+{
+	if(tdmfs > 0x3F)
+	{
+		printk(KERN_ERR "%s: TDM_FS value is out of range %#x > 0x3F\n", __func__, tdmfs);
+		return;
+	}
+
+	writel((tdmfs << 12) |(readl(COMCERTO_GPIO_PAD_CONFIG0) & ~(0x3F << 12)), COMCERTO_GPIO_PAD_CONFIG0);
+}
+
+static void tdm_ck_set(u32 tdmck)
+{
+	if(tdmck > 0x3F)
+	{
+		printk(KERN_ERR "%s: TDM_CK value is out of range %#x > 0x3F\n", __func__, tdmck);
+		return;
+	}
+
+	writel((tdmck << 6) |(readl(COMCERTO_GPIO_PAD_CONFIG0) & ~(0x3F << 6)), COMCERTO_GPIO_PAD_CONFIG0);
+}
+#endif
+
+int tdm_get_block(unsigned int block)
+{
+	unsigned long flags;
+	int rc = 0;
+
+	/* 0x0 - TDM block, 0x1 - ZDS block, 0x2 - GPIO[63:60] signals and 0x3 - MSIF block */
+	printk(KERN_INFO "%s: get block %d (selected %d)\n", __func__, block, block_selected);
+	if (block > 3)
+		return -EINVAL;
+
+	spin_lock_irqsave(&block_lock, flags);
+
+	if(block == block_selected)
+	{
+		block_sel_cnt++;
+	}
+	else
+	{
+		if (block_sel_cnt)
+		{
+			rc = -EBUSY;
+			goto out;
+		}
+
+		block_sel_cnt++;
+		/* Selected block global variable will be updated */
+		tdm_mux_set(block);
+		/* Clock to be recalculated accordingly to selected block */
+		clock_frequency_set(BaseClock);
+	}
+
+out:
+	spin_unlock_irqrestore(&block_lock,flags);
+
+	printk(KERN_INFO "%s: get block result %d\n", __func__, rc);
+	return rc;
+}
+
+void tdm_put_block(unsigned int block)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&block_lock, flags);
+
+	printk(KERN_INFO "%s: put block %d (selected %d, cnt %d)\n", 
+		__func__, block, block_selected, block_sel_cnt);
+
+	if (block == block_selected)
+	{
+		if (block_sel_cnt)
+			block_sel_cnt--;
+		else
+			printk(KERN_ERR "%s: block hasn't selected yet\n", __func__);
+	}
+	else
+		printk(KERN_ERR "%s: Invalid block\n", __func__);
+
+	spin_unlock_irqrestore(&block_lock,flags);
+}
+
+static ssize_t tdm_data_read(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	if (strcmp("fs_polarity", attr->attr.name) == 0) /* FSYNC_FALL(RISE)_EDGE */
+		return sprintf(buf, "%d\n", (readl(TDM_FSYNC_GEN_CTRL) >> 1) & 0x1);
+	else if (strcmp("fs_lwidth", attr->attr.name) == 0) /* Low_Phase_Width */
+		return sprintf(buf, "%x\n", (readl(TDM_FSYNC_LOW) & 0x3FF));
+	else if (strcmp("fs_hwidth", attr->attr.name) == 0) /* High_Phase_Width */
+		return sprintf(buf, "%x\n", (readl(TDM_FSYNC_HIGH) & 0x3FF));
+	else if (strcmp("fs_output", attr->attr.name) == 0) /* Generic Pad Control and Version ID Register[2] */
+		return sprintf(buf, "%d\n", readl(COMCERTO_GPIO_TDM_MUX) & 0x1);
+	else if (strcmp("clock_ppmshift", attr->attr.name) == 0)
+		return sprintf(buf, "%ld\n", clock_ppm_get());
+	else if (strcmp("clock_output", attr->attr.name) == 0)
+		return sprintf(buf, "%d\n", (readl(COMCERTO_GPIO_SYSTEM_CONFIG)	>> 3) & 0x1);
+	else if (strcmp("clock_hz", attr->attr.name) == 0)
+		return sprintf(buf, "%lu\n", clock_frequency_get());
+	else if (strcmp("tdm_mux", attr->attr.name) == 0)
+                return sprintf(buf, "%lu\n", (readl(COMCERTO_GPIO_MISC_PIN_SELECT) >> 4) & 0x3);
+	else
+	{
+		printk(KERN_ERR "%s: Unknown file attribute\n", __func__);
+		return -1;
+	}
+}
+
+static ssize_t tdm_data_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	unsigned long tdm_data = simple_strtoul(buf, NULL, 0);
+
+	if (strcmp("fs_polarity", attr->attr.name) == 0)
+		fsync_polarity_set(tdm_data);
+	else if (strcmp("fs_lwidth", attr->attr.name) == 0)
+		fsync_lphase_set(tdm_data);
+	else if (strcmp("fs_hwidth", attr->attr.name) == 0)
+		fsync_hphase_set(tdm_data);
+	else if (strcmp("fs_output", attr->attr.name) == 0)
+		fsync_output_set(tdm_data);
+	else if (strcmp("clock_hz", attr->attr.name) == 0)
+		clock_frequency_set(tdm_data);
+	else if (strcmp("clock_output", attr->attr.name) == 0)
+		clock_output_set(tdm_data);
+	else if (strcmp("clock_ppmshift", attr->attr.name) == 0)
+		clock_ppm_adjust(simple_strtol(buf, NULL, 0));
+	else if (strcmp("tdm_mux", attr->attr.name) == 0) {
+		if (tdm_data != block_selected)
+		{
+			tdm_put_block(block_selected);
+			tdm_get_block(tdm_data);
+		}
+		else
+			printk(KERN_INFO "%s: TDM block %d is already selected\n", __func__, block_selected);
+	}
+	else
+		printk(KERN_ERR "%s: Unknown file attribute \n", __func__);
+
+	return count;
+}
+
+static struct device_attribute fsoutput_attr = __ATTR(fs_output, 0644, tdm_data_read, tdm_data_write);
+static struct device_attribute fspolarity_attr = __ATTR(fs_polarity, 0644, tdm_data_read, tdm_data_write);
+static struct device_attribute fshwidth_attr = __ATTR(fs_hwidth, 0644, tdm_data_read, tdm_data_write);
+static struct device_attribute fslwidth_attr = __ATTR(fs_lwidth, 0644, tdm_data_read, tdm_data_write);
+static struct device_attribute clockhz_attr = __ATTR(clock_hz, 0644, tdm_data_read, tdm_data_write);
+static struct device_attribute clockout_attr = __ATTR(clock_output, 0644, tdm_data_read, tdm_data_write);
+static struct device_attribute clockppm_attr = __ATTR(clock_ppmshift, 0644, tdm_data_read, tdm_data_write);
+static struct device_attribute tdmmux_attr = __ATTR(tdm_mux, 0644, tdm_data_read, tdm_data_write);
+
+static int comcerto_tdm_probe(struct platform_device *pdev)
+{
+	struct comcerto_tdm_data *pdata = (struct comcerto_tdm_data *)pdev->dev.platform_data;
+	
+	int ret = 0;
+
+	spin_lock_init(&block_lock);
+	
+	/* Get the reference to ntgref clock structure*/
+	clk_ntg_ref = clk_get(NULL,"ntgref");
+	
+	/* Error Handling , if no ntgref clock reference: return error */
+	if (IS_ERR(clk_ntg_ref)) {
+		pr_err("%s: Unable to obtain ntgref clock: %ld\n",__func__,PTR_ERR(clk_ntg_ref));
+		return PTR_ERR(clk_ntg_ref);
+	}
+
+	/* Take TDM NTG out of reset*/
+	c2000_block_reset(COMPONENT_TDMNTG,0);
+
+	/*Enable the TDMNTG_REF  clock*/ 
+        ret = clk_enable(clk_ntg_ref);
+	
+	if (ret){
+		pr_err("%s: Unable to enable ntgref clock \n",__func__); 
+		return ret;
+	}
+
+	/* Set the rate value to 500000000 Hz for the ref clock */ 
+	clk_set_rate(clk_ntg_ref,TDMNTG_DEFAULT_REF_CLK);
+
+ 	/*Initialize the tdmntgref clock rate value */ 	
+	tdmntg_ref_clk = clk_get_rate(clk_ntg_ref);
+
+	writel((NTG_DIV_RST_N | NTG_EN), TDM_NTG_CLK_CTRL);
+
+	/* Inital configuration of tdm bus */
+	tdm_mux_set(pdata->tdmmux);
+	fsync_polarity_set(pdata->fspolarity);
+	fsync_lphase_set(pdata->fslwidth);
+	fsync_hphase_set(pdata->fshwidth);
+	clock_frequency_set(pdata->clockhz);
+	clock_output_set(pdata->clockout);
+	fsync_output_set(pdata->fsoutput);
+
+#if 0 // The default paramters are good
+	tdm_dr_set(pdata->tdmdr);
+	tdm_dx_set(pdata->tdmdx);
+	tdm_fs_set(pdata->tdmfs);
+	tdm_ck_set(pdata->tdmck);
+#endif
+
+	/* Creating sysfs files */
+	ret |= device_create_file(&pdev->dev, &fsoutput_attr);
+	ret |= device_create_file(&pdev->dev, &fspolarity_attr);
+	ret |= device_create_file(&pdev->dev, &fshwidth_attr);
+	ret |= device_create_file(&pdev->dev, &fslwidth_attr);
+	ret |= device_create_file(&pdev->dev, &clockhz_attr);
+	ret |= device_create_file(&pdev->dev, &clockout_attr);
+	ret |= device_create_file(&pdev->dev, &clockppm_attr);
+	ret |= device_create_file(&pdev->dev, &tdmmux_attr);
+
+	return ret;
+}
+
+static int comcerto_tdm_remove(struct platform_device *pdev)
+{
+	/* Disable the TDMNTG_REFclock */
+	clk_disable(clk_ntg_ref);
+	clk_put(clk_ntg_ref);
+	
+	/* Puuting TDMNTG is reset mode */
+	c2000_block_reset(COMPONENT_TDMNTG,1);
+
+	/* Remove the Device  File  */
+	device_remove_file(&pdev->dev, &fsoutput_attr);
+	device_remove_file(&pdev->dev, &fspolarity_attr);
+	device_remove_file(&pdev->dev, &fshwidth_attr);
+	device_remove_file(&pdev->dev, &fslwidth_attr);
+	device_remove_file(&pdev->dev, &clockhz_attr);
+	device_remove_file(&pdev->dev, &clockout_attr);
+	device_remove_file(&pdev->dev, &clockppm_attr);
+	device_remove_file(&pdev->dev, &tdmmux_attr);
+
+	return 0;
+}
+
+/* Structure for a device driver */
+static struct platform_driver comcerto_tdm_driver = {
+	.probe = comcerto_tdm_probe,
+	.remove = comcerto_tdm_remove,
+	.driver	= {
+		.name = "comcerto-tdm",
+	},
+};
+
+static int  comcerto_tdm_init(void)
+{
+	int ret = 0;
+
+	ret = platform_driver_register(&comcerto_tdm_driver);
+
+	return ret;
+}
+
+static void  comcerto_tdm_exit(void)
+{
+	platform_driver_unregister(&comcerto_tdm_driver);
+}
+
+module_init(comcerto_tdm_init);
+module_exit(comcerto_tdm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Comcerto TDM Driver");
+
diff --git a/arch/arm/mach-comcerto/time.c b/arch/arm/mach-comcerto/time.c
new file mode 100644
index 0000000..5ae39f5
--- /dev/null
+++ b/arch/arm/mach-comcerto/time.c
@@ -0,0 +1,603 @@
+/*
+ *  linux/arch/arm/mach-comcerto/time.c
+ *
+ *  Copyright (C) 2012 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/irq.h>
+
+#include <linux/export.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <asm/irq.h>
+#include <asm/smp_twd.h>
+#include <asm/sched_clock.h>
+#include <asm/localtimer.h>
+#include <asm/mach/time.h>
+#include <mach/hardware.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <mach/comcerto-2000/clock.h>
+
+/* Kernel needs a timer cadenced to 10ms */
+#define COMCERTO_KERNEL_TIMER_VALUE	(COMCERTO_AHBCLK / HZ)
+#define machinecycles_to_usecs(ticks) (((ticks) * 10)/ (COMCERTO_AHBCLK/100000))
+
+/*
+ * HARDWARE TIMER
+ * Can be use by any driver for its own need
+ */
+
+#define COMCERTO_TIMER_DEBUG	1
+#define TIMER_STATUS_ENABLED	(1 << 0)
+#define TIMER_STATUS_FREE	(1 << 1)
+#define COMCERTO_MAX_TIMERS	6
+
+/*
+ * HARDWARE TIMER
+ * Can be use by any driver for its own need
+ */
+
+/* List of available timers */
+struct timer_hw {
+	u8 id;
+	u8 status;
+	struct comcerto_timer *t;
+};
+struct timer_hw timer_hw [COMCERTO_MAX_TIMERS] = {
+	{0, 0, NULL}, /*  MSP timer    */
+	{1, 0, NULL}, /*  Clock event  */
+	{2, 0, NULL}, /*  CLock source + Sched clock */
+	{3, TIMER_STATUS_FREE, NULL},
+	{4, TIMER_STATUS_FREE, NULL},
+	{5, TIMER_STATUS_FREE, NULL}
+};
+
+static spinlock_t comcerto_timer_lock;
+
+static unsigned long COMCERTO_AHBCLK;
+
+static void comcerto_timer_disable(int t)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&comcerto_timer_lock, flags);
+	__comcerto_timer_disable(t);
+	spin_unlock_irqrestore(&comcerto_timer_lock, flags);
+}
+
+static unsigned long __comcerto_timer_get(int id)
+{
+	if (id == 1)
+	{
+		return comcerto_timer1_get();
+	}
+	else if (id == 2)
+	{
+		return comcerto_timer2_get();
+	}
+	else if (id == 3)
+	{
+		return comcerto_timer3_get();
+	}
+	else if (id == 4)
+	{
+		return comcerto_timer4_get();
+	}
+	else if (id == 5)
+	{
+		return comcerto_timer5_get();
+	}
+	else
+		return 0;
+}
+
+static void __comcerto_timer_set(int id, unsigned long count)
+{
+	if (id == 1)
+	{
+		comcerto_timer1_set(count);
+	}
+	else if (id == 2)
+	{
+		comcerto_timer2_set(0, count, 0);
+	}
+	else if (id == 3)
+	{
+		comcerto_timer3_set(0, count, 0);
+	}
+	else if (id == 4)
+	{
+		comcerto_timer4_set(count);
+	}
+	else if (id == 5)
+	{
+		comcerto_timer5_set(0, count, 0);
+	}
+}
+
+static void __timer_start(struct timer_hw *thw, unsigned long count)
+{
+	thw->status |= TIMER_STATUS_ENABLED;
+
+	__comcerto_timer_set(thw->id, count);
+
+	__comcerto_timer_enable(thw->id);
+}
+
+static void timer_start(struct timer_hw *thw, unsigned long count)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&comcerto_timer_lock, flags);
+	__timer_start(thw, count);
+	spin_unlock_irqrestore(&comcerto_timer_lock, flags);
+}
+
+static void __timer_stop(struct timer_hw *thw)
+{
+	__comcerto_timer_disable(thw->id);
+	thw->status &= ~ TIMER_STATUS_ENABLED;
+}
+
+static void timer_stop(struct timer_hw *thw)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&comcerto_timer_lock, flags);
+	__timer_stop(thw);
+	spin_unlock_irqrestore(&comcerto_timer_lock, flags);
+}
+
+static void __timer_free(struct timer_hw *thw)
+{
+	thw->status |= TIMER_STATUS_FREE;
+	thw->t->thw = (unsigned long) NULL;
+	thw->t = NULL;
+}
+
+static void timer_free(struct timer_hw *thw)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&comcerto_timer_lock, flags);
+	__timer_free(thw);
+	spin_unlock_irqrestore(&comcerto_timer_lock, flags);
+}
+
+
+static struct timer_hw *__timer_alloc(struct comcerto_timer *t)
+{
+	struct timer_hw *thw;
+	int i;
+
+	for (i = 0; i < COMCERTO_MAX_TIMERS; i++)
+	{
+		thw = &timer_hw[i];
+		if (thw->status & TIMER_STATUS_FREE)
+		{
+			thw->status &= ~ TIMER_STATUS_FREE;
+			t->thw = (unsigned long) thw;
+			thw->t = t;
+			goto found;
+		}
+	}
+
+	return NULL;
+found:
+	return thw;
+}
+
+static struct timer_hw *timer_alloc(struct comcerto_timer *t)
+{
+	struct timer_hw *thw;
+	unsigned long flags;
+
+	spin_lock_irqsave(&comcerto_timer_lock, flags);
+	thw = __timer_alloc(t);
+	spin_unlock_irqrestore(&comcerto_timer_lock, flags);
+
+	return thw;
+}
+
+int comcerto_timer_start(struct comcerto_timer *t)
+{
+	struct timer_hw *thw;
+
+	thw = (struct timer_hw *) t->thw;
+	if (!thw) {
+		thw = timer_alloc(t);
+		if (!thw) {
+			printk (KERN_ERR "Comcerto timer: unable to allocate hardware timer\n");
+			goto err;
+		}
+	}
+#ifdef COMCERTO_TIMER_DEBUG
+	if (thw->t != t) {
+		printk (KERN_ERR "Comcerto timer: timer corruption %#lx %#lx %#lx\n",
+					(unsigned long) thw, (unsigned long) thw->t, (unsigned long) t);
+
+		goto err;
+	}
+#endif /* COMCERTO_TIMER_DEBUG */
+
+	/* timeout in us */
+	timer_start(thw, (t->timeout * (COMCERTO_AHBCLK / 100000)) / 10);
+
+	return 0;
+
+  err:
+	return -1;
+}
+
+int comcerto_timer_stop(struct comcerto_timer *t)
+{
+	struct timer_hw *thw;
+
+	thw = (struct timer_hw *) t->thw;
+	if (!thw)
+		goto err;
+
+#ifdef COMCERTO_TIMER_DEBUG
+	if (thw->t != t) {
+		printk (KERN_ERR "Comcerto timer: timer corruption %#lx %#lx %#lx\n",
+					(unsigned long) thw, (unsigned long) thw->t, (unsigned long) t);
+
+		goto err;
+	}
+#endif /* COMCERTO_TIMER_DEBUG */
+
+	timer_stop(thw);
+	timer_free(thw);
+
+	return 0;
+
+  err:
+	return -1;
+}
+
+int comcerto_timer_read(struct comcerto_timer *t)
+{
+	struct timer_hw *thw;
+
+	thw = (struct timer_hw *) t->thw;
+	if (!thw)
+		goto err;
+
+#ifdef COMCERTO_TIMER_DEBUG
+	if (thw->t != t) {
+		printk (KERN_ERR "Comcerto timer: timer corruption %#lx %#lx %#lx\n",
+					(unsigned long) thw, (unsigned long) thw->t, (unsigned long) t);
+
+		goto err;
+	}
+#endif /* COMCERTO_TIMER_DEBUG */
+
+	return ((__comcerto_timer_get(thw->id) * 10) / (COMCERTO_AHBCLK / 100000));
+
+  err:
+	return -1;
+}
+
+EXPORT_SYMBOL(comcerto_timer_start);
+EXPORT_SYMBOL(comcerto_timer_stop);
+EXPORT_SYMBOL(comcerto_timer_read);
+
+int timer_hw_handler(u8 id)
+{
+	struct timer_hw *thw;
+	unsigned long flags;
+
+	thw = &timer_hw[id];
+
+	spin_lock_irqsave(&comcerto_timer_lock, flags);
+
+	if (thw->status & TIMER_STATUS_ENABLED) {
+
+		struct comcerto_timer *t = thw->t;
+
+		if (t->flags & COMCERTO_TIMER_RUN_ONCE) {
+			__timer_stop(thw);
+			__timer_free(thw);
+		}
+
+		spin_unlock_irqrestore(&comcerto_timer_lock, flags);
+
+		t->func(t->data);
+
+	} else {
+		spin_unlock_irqrestore(&comcerto_timer_lock, flags);
+		goto err;
+	}
+
+	return 0;
+
+  err:
+	return -1;
+}
+
+
+struct comcerto_clock_device
+{
+	int timer;
+	struct clock_event_device device;
+};
+
+/* This function must be called with interrupts disabled. We need to start as close from zero
+ * as possible - if we don't clear counter before setting high bound value we'll have innacurate
+ * results in ONESHOT mode.
+ */
+static int comcerto_clock_set_next_event(unsigned long evt, struct clock_event_device *dev)
+{
+	struct comcerto_clock_device *clock = container_of(dev, typeof(*clock), device);
+	unsigned long flags;
+
+	spin_lock_irqsave(&comcerto_timer_lock, flags);
+
+	/* now write correct bound and clear interrupt status.
+	   Writing high bound register automatically resets count to low bound value.
+	   For very small bound values it's possible that we ack the interrupt _after_ the timer has already expired,
+	   this is not very serious because the interrupt will be asserted again in a very short time */
+	__comcerto_timer_set(clock->timer, evt);
+	comcerto_timer_ack(clock->timer);
+
+	/* enable interrupt for ONESHOT mode */
+	if (dev->mode == CLOCK_EVT_MODE_ONESHOT)
+		__comcerto_timer_enable(clock->timer);
+
+	spin_unlock_irqrestore(&comcerto_timer_lock, flags);
+
+	return 0;
+}
+
+static void comcerto_clock_set_mode(enum clock_event_mode mode, struct clock_event_device *dev)
+{
+	struct comcerto_clock_device *clock = container_of(dev, typeof(*clock), device);
+	unsigned long flags;
+
+	/* This timer is true PERIODIC in hardware, to emulate ONESHOT we need to keep it masked
+	 * until set_next_event() call. Enable interrupt only for PERIODIC mode.
+	 */
+	spin_lock_irqsave(&comcerto_timer_lock, flags);
+
+	if (mode != CLOCK_EVT_MODE_PERIODIC)
+		__comcerto_timer_disable(clock->timer);
+	else {
+		__comcerto_timer_set(clock->timer, COMCERTO_KERNEL_TIMER_VALUE);
+		__comcerto_timer_enable(clock->timer);
+	}
+
+	spin_unlock_irqrestore(&comcerto_timer_lock, flags);
+}
+
+static struct comcerto_clock_device clock =
+{
+	.timer  = 1,
+	.device =
+	{
+		.name           = "timer1",
+		.features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+		.rating         = 200,
+		.shift          = 31,
+		.set_mode       = comcerto_clock_set_mode,
+		.set_next_event = comcerto_clock_set_next_event,
+	},
+};
+
+static cycle_t comcerto_timer2_read(struct clocksource *cs)
+{
+	return comcerto_timer2_get();
+}
+
+static struct clocksource clocksource =
+{
+	.name	= "timer2",
+	.rating	= 200,
+	.read	= comcerto_timer2_read,
+	.mask	= CLOCKSOURCE_MASK(32),
+	.shift	= 28,
+	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+
+/***********************************************************
+ *   KERNEL TIMER                                          *
+ *   (Functions called  by the kernel)                     *
+ ***********************************************************/
+
+#define irq_to_timer(irq)	(IRQ_TIMER0 - irq)
+#define timer_mask(timer)	(1 << timer)
+
+#ifdef CONFIG_LOCAL_TIMERS
+/*
+ * Setup the local clock events for a CPU.
+ */
+int __cpuinit local_timer_setup(struct clock_event_device *evt)
+{
+	evt->irq = IRQ_LOCALTIMER;
+	twd_timer_setup(evt);
+	return 0;
+}
+#endif
+
+/*
+ * Routine to catch timer interrupts
+ */
+static irqreturn_t comcerto_timer1_interrupt(int irq, void *dev_id)
+{
+	u32 status;
+	struct comcerto_clock_device *clock = dev_id;
+	struct clock_event_device *dev = &clock->device;
+
+	status = __raw_readl(COMCERTO_TIMER_STATUS) & __raw_readl(COMCERTO_TIMER_IRQ_MASK);
+
+	/* timer1 expired */
+	if (status & timer_mask(clock->timer)) {
+		/* we need to disable interrupt to simulate ONESHOT mode,
+		   do it before clearing the interrupt to avoid race */
+		if (dev->mode != CLOCK_EVT_MODE_PERIODIC)
+			comcerto_timer_disable(clock->timer);
+
+		comcerto_timer_ack(clock->timer);
+		dev->event_handler(dev);
+
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+irqreturn_t comcerto_timerN_interrupt(int irq, void *dev_id)
+{
+	u32 status;
+	int timer = irq_to_timer(irq);
+
+	status = __raw_readl(COMCERTO_TIMER_STATUS);
+	if (status & timer_mask(timer)) {
+		comcerto_timer_ack(timer);
+		timer_hw_handler(timer);
+
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+static struct irqaction comcerto_timer1_irq = {
+	.name		= "timer1",
+	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.handler	= comcerto_timer1_interrupt,
+	.dev_id		= &clock,
+};
+
+static struct irqaction comcerto_timer3_irq = {
+	.name		= "timer3",
+	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.handler	= comcerto_timerN_interrupt,
+};
+
+static struct irqaction comcerto_timer4_irq = {
+	.name		= "timer4",
+	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.handler	= comcerto_timerN_interrupt,
+};
+
+static struct irqaction comcerto_timer5_irq = {
+	.name		= "timer5",
+	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.handler	= comcerto_timerN_interrupt,
+};
+
+static DEFINE_CLOCK_DATA(cd);
+
+unsigned long long notrace sched_clock(void)
+{
+	u32 cyc = comcerto_timer2_get();
+
+	return cyc_to_sched_clock(&cd, cyc, (u32)~0);
+}
+
+static void notrace comcerto_update_sched_clock(void)
+{
+	u32 cyc;
+
+	cyc = comcerto_timer2_get();
+
+	update_sched_clock(&cd, cyc, (u32)~0);
+}
+
+void comcerto_hwtimer_init(void)
+{
+	/*
+	 * DO NOT MODIFY THE CONFIGURATION OF TIMER0
+	 * It is used by the MSP
+	 */
+	
+	struct clk *clk_axi;
+
+	/* Initializing the clock structure Tree declared/defined in clock.c */
+        clk_init();
+
+	spin_lock_init(&comcerto_timer_lock);
+
+	/* Mask all the timers except timer0 */
+	comcerto_timer_disable(1);
+	comcerto_timer_disable(2);
+	comcerto_timer_disable(3);
+	comcerto_timer_disable(4);
+	comcerto_timer_disable(5);
+
+	/* Get the AXI clock , to be used for AHB clock value*/
+	clk_axi = clk_get(NULL,"axi");
+	
+	if (IS_ERR(clk_axi)){
+		pr_err("%s: Unable to obtain axi clock: %ld\n",__func__,PTR_ERR(clk_axi));
+		/* System cannot proceed from here */
+		BUG();
+	}
+
+	/* Enable the AXI clock */
+	if (clk_enable(clk_axi)){
+		pr_err("%s: Unable to enable axi clock\n",__func__);
+		/* System cannot proceed from here */
+		BUG();
+	}
+
+	/* Get the AXI clock rate value , which will assigned to AHB clock value */
+	COMCERTO_AHBCLK = clk_get_rate(clk_axi);	
+
+	__comcerto_timer_set(2, 0xffffffff);
+	clocksource.mult = clocksource_hz2mult(COMCERTO_AHBCLK, clocksource.shift);
+	clocksource_register(&clocksource);
+
+	init_sched_clock(&cd, comcerto_update_sched_clock, 32, COMCERTO_AHBCLK);
+
+	clock.device.mult = div_sc(COMCERTO_AHBCLK, NSEC_PER_SEC, clock.device.shift);
+	clock.device.max_delta_ns = clockevent_delta2ns(0x3fffffff, &clock.device);
+	clock.device.min_delta_ns = clockevent_delta2ns(1, &clock.device);
+	clock.device.cpumask = cpumask_of(0);
+	clockevents_register_device(&clock.device);
+
+	/* Clear all the timers except timer0  */
+	__raw_writel(COMCERTO_TIMER_CSP, COMCERTO_TIMER_STATUS);
+
+	/* Register interrupt handler for interrupt on IRQ_TIMERB*/
+	irq_set_irq_type(IRQ_TIMER1, IRQ_TYPE_EDGE_RISING);
+	irq_set_irq_type(IRQ_TIMER3, IRQ_TYPE_EDGE_RISING);
+	irq_set_irq_type(IRQ_TIMER4, IRQ_TYPE_EDGE_RISING);
+	irq_set_irq_type(IRQ_TIMER5, IRQ_TYPE_EDGE_RISING);
+	setup_irq(IRQ_TIMER1, &comcerto_timer1_irq);
+	setup_irq(IRQ_TIMER3, &comcerto_timer3_irq);
+	setup_irq(IRQ_TIMER4, &comcerto_timer4_irq);
+	setup_irq(IRQ_TIMER5, &comcerto_timer5_irq);
+}
+
+static void __init comcerto_timer_init(void)
+{
+#ifdef CONFIG_LOCAL_TIMERS
+	twd_base = (void *)COMCERTO_TWD_VADDR;
+#endif
+
+	comcerto_hwtimer_init();
+}
+
+struct sys_timer comcerto_timer = {
+	.init	= comcerto_timer_init,
+};
+
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 67f75a0..ca9764e 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -753,6 +753,20 @@
 	  Say Y here to use the predictable round-robin cache replacement
 	  policy.  Unless you specifically require this or are unsure, say N.
 
+config CPU_SPECULATIVE_ACCESS_DISABLED
+	bool "Disable speculative accesses"
+	depends on CPU_V7 && ARCH_COMCERTO
+	help
+	  Disable speculative accesses for the processor. This may reduce overall system memory performance but
+	  can allow other, potentially unsafe, optimizations (see below). If unsure, say N.
+
+config CPU_DMA_PARTIAL_INVALIDATES
+	bool "Do partial invalidates in the DMA management functions"
+	depends on CPU_V7 && ARCH_COMCERTO && CPU_SPECULATIVE_ACCESS_DISABLED
+	help
+	  Say Y here to reduce the overhead of cache maintenance for DMA mapped memory zones. 
+	  WARNING: UNSAFE, this may lead to random memory corruption. If unsure, say N.
+
 config CPU_BPREDICT_DISABLE
 	bool "Disable branch prediction"
 	depends on CPU_ARM1020 || CPU_V6 || CPU_V6K || CPU_MOHAWK || CPU_XSC3 || CPU_V7 || CPU_FA526
@@ -822,7 +836,7 @@
 		   REALVIEW_EB_A9MP || ARCH_IMX_V6_V7 || MACH_REALVIEW_PBX || \
 		   ARCH_NOMADIK || ARCH_OMAP4 || ARCH_EXYNOS4 || ARCH_TEGRA || \
 		   ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || ARCH_SHMOBILE || \
-		   ARCH_PRIMA2 || ARCH_ZYNQ || ARCH_CNS3XXX || ARCH_HIGHBANK
+		   ARCH_PRIMA2 || ARCH_ZYNQ || ARCH_CNS3XXX || ARCH_HIGHBANK || ARCH_COMCERTO
 	default y
 	select OUTER_CACHE
 	select OUTER_CACHE_SYNC
@@ -837,6 +851,51 @@
 	  This option enables optimisations for the PL310 cache
 	  controller.
 
+config L2X0_INSTRUCTION_ONLY
+	bool "Use L2 cache for instructions only"
+	depends on CACHE_PL310
+	default n
+
+config PL310_EXCLUSIVE_CACHE
+	bool "Exclusive cache"
+	depends on CACHE_PL310
+	default n
+
+config PL310_EARLY_WRITE_RESPONSE
+	bool "Early write response"
+	depends on CACHE_PL310
+	default n
+
+config PL310_FULL_LINE_OF_ZERO
+	bool "Full line of zero"
+	depends on CACHE_PL310
+	default n
+
+config PL310_STORE_BUFFER_DEVICE_LIMITATION
+	bool "Store buffer device limitation"
+	depends on CACHE_PL310
+	default n
+
+config PL310_INSTRUCTION_PREFETCH
+	bool "Instruction prefetch"
+	depends on CACHE_PL310
+	default n
+
+config PL310_DATA_PREFETCH
+	bool "Data prefetch"
+	depends on CACHE_PL310
+	default n
+
+config PL310_DOUBLE_LINE_FILL
+	bool "Double line fill"
+	depends on CACHE_PL310
+	default n
+
+config PL310_INCR_DOUBLE_LINE_FILL
+	bool "Incremental double line fill"
+	depends on PL310_DOUBLE_LINE_FILL
+	default n
+
 config CACHE_TAUROS2
 	bool "Enable the Tauros2 L2 cache controller"
 	depends on (ARCH_DOVE || ARCH_MMP || CPU_PJ4)
@@ -867,7 +926,7 @@
 config ARM_DMA_MEM_BUFFERABLE
 	bool "Use non-cacheable memory for DMA" if (CPU_V6 || CPU_V6K) && !CPU_V7
 	depends on !(MACH_REALVIEW_PB1176 || REALVIEW_EB_ARM11MP || \
-		     MACH_REALVIEW_PB11MP)
+		     MACH_REALVIEW_PB11MP || COMCERTO_DDR_ECC_SUPPORT)
 	default y if CPU_V6 || CPU_V6K || CPU_V7
 	help
 	  Historically, the kernel has used strongly ordered mappings to
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index db7bcc0..3e504ec 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -299,8 +299,10 @@
 		lockregs = 1;
 
 	for (i = 0; i < lockregs; i++) {
+#ifndef CONFIG_L2X0_INSTRUCTION_ONLY
 		writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_D_BASE +
 			       i * L2X0_LOCKDOWN_STRIDE);
+#endif
 		writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_I_BASE +
 			       i * L2X0_LOCKDOWN_STRIDE);
 	}
@@ -311,6 +313,7 @@
 	__u32 aux;
 	__u32 cache_id;
 	__u32 way_size = 0;
+	__u32 prefetch = 0;
 	int ways;
 	const char *type;
 
@@ -330,11 +333,23 @@
 		else
 			ways = 8;
 		type = "L310";
+
 #ifdef CONFIG_PL310_ERRATA_753970
 		/* Unmapped register. */
 		sync_reg_offset = L2X0_DUMMY_REG;
 #endif
 		outer_cache.set_debug = pl310_set_debug;
+
+		prefetch = readl_relaxed(l2x0_base + L2X0_PREFETCH_CTRL);
+
+#ifdef CONFIG_PL310_DOUBLE_LINE_FILL
+		prefetch |= (1 << 30) | (1 << 24);
+#ifdef CONFIG_PL310_INCR_DOUBLE_LINE_FILL
+		prefetch |= (1 << 23);
+#endif
+#endif
+		writel_relaxed(prefetch, l2x0_base + L2X0_PREFETCH_CTRL);
+
 		break;
 	case L2X0_CACHE_ID_PART_L210:
 		ways = (aux >> 13) & 0xf;
@@ -385,8 +400,8 @@
 	outer_cache.disable = l2x0_disable;
 
 	printk(KERN_INFO "%s cache controller enabled\n", type);
-	printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d B\n",
-			ways, cache_id, aux, l2x0_size);
+	printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, PREFETCH_CTRL 0x%08x, Cache size: %d B\n",
+			ways, cache_id, aux, prefetch, l2x0_size);
 }
 
 #ifdef CONFIG_OF
diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S
index a655d3d..0c9258e 100644
--- a/arch/arm/mm/cache-v7.S
+++ b/arch/arm/mm/cache-v7.S
@@ -211,9 +211,16 @@
  * isn't mapped, just try the next page.
  */
 9001:
+#if !defined(CONFIG_COMCERTO_64K_PAGES)
 	mov	r12, r12, lsr #12
 	mov	r12, r12, lsl #12
 	add	r12, r12, #4096
+#else
+	mov	r12, r12, lsr #16
+	mov	r12, r12, lsl #16
+	add	r12, r12, #65536
+
+#endif
 	b	3b
  UNWIND(.fnend		)
 ENDPROC(v7_coherent_kern_range)
diff --git a/arch/arm/mm/copypage-v6.c b/arch/arm/mm/copypage-v6.c
index 3d9a155..8205008 100644
--- a/arch/arm/mm/copypage-v6.c
+++ b/arch/arm/mm/copypage-v6.c
@@ -20,9 +20,16 @@
 
 #include "mm.h"
 
+#if !defined(CONFIG_COMCERTO_64K_PAGES)
 #if SHMLBA > 16384
 #error FIX ME
 #endif
+#else
+#if SHMLBA > PAGE_SIZE
+#error FIX ME
+#endif
+#endif
+
 
 #define from_address	(0xffff8000)
 #define to_address	(0xffffc000)
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 1aa664a..c89301b 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -28,6 +28,78 @@
 #include <asm/mach/arch.h>
 
 #include "mm.h"
+#if defined(CONFIG_COMCERTO_UNCACHED_DMA)
+#include <linux/hugetlb.h>
+#include <asm/pgalloc.h>
+#include <asm/mach/map.h>
+#endif
+
+#ifdef CONFIG_COMCERTO_ZONE_DMA_NCNB
+extern unsigned long arm_dma_zone_size;
+#endif
+
+#if defined(CONFIG_COMCERTO_UNCACHED_DMA)
+static pgd_t *shadow_pg_dir;
+static u16 *shadow_pmd_count;
+
+static int __init init_shadow_page_table(void)
+{
+	pmd_t *pmd, *shadow_pmd;
+	pte_t *shadow_pte, *ptep;
+	unsigned long start, addr, end, pfn;
+	const struct mem_type *mt;
+	int count;
+
+	shadow_pg_dir = (pgd_t *)__get_free_pages(GFP_KERNEL | GFP_ATOMIC, get_order(16384));
+	if (!shadow_pg_dir)
+		return -ENOMEM;
+	shadow_pmd_count = (u16 *)__get_free_pages(GFP_KERNEL | GFP_ATOMIC, get_order(sizeof(u16) * PTRS_PER_PGD));
+	if (!shadow_pmd_count)
+		goto err1;
+
+	memset(shadow_pg_dir, 0, 16384);
+	memset(shadow_pmd_count, 0, sizeof(u16) * PTRS_PER_PGD);
+
+	mt = get_mem_type(MT_MEMORY);
+	start = 0;
+	count = 0;
+	do {
+		pmd = pmd_off_k((unsigned long) start);
+		if (!pmd_none(*pmd)) {
+			if (pmd_bad(*pmd) && ((pmd_val(*pmd) & ~SECTION_MASK) == mt->prot_sect)) {  // Only do it for MT_MEMORY areas
+				shadow_pmd = (pmd_t *)shadow_pg_dir + (pmd - pmd_off_k(0));
+				addr = (unsigned long)start & PMD_MASK;
+				end = addr + PMD_SIZE;
+
+				shadow_pte = (pte_t *)__get_free_page(PGALLOC_GFP | GFP_ATOMIC);
+				if (!shadow_pte)
+					goto err2;
+				pfn = __phys_to_pfn(pmd_val(*pmd) & PMD_MASK);
+				ptep = shadow_pte;
+				do {
+					set_pte_ext(ptep, pfn_pte(pfn, __pgprot(mt->prot_pte)), 0);
+					pfn++;
+				} while (ptep++, addr += PAGE_SIZE, addr != end);
+				__pmd_populate(shadow_pmd, __pa(shadow_pte), mt->prot_l1);
+			} else {
+				// Mark the shadow in use, so we never replace the already existing 2nd-level
+				shadow_pmd_count[pgd_index(start)]++;
+			}
+		}
+	} while (count++, start += PMD_SIZE, count < PTRS_PER_PGD);
+
+	return 0;
+
+err2:
+	__free_pages((struct page *)shadow_pmd_count, get_order(sizeof(u16) * PTRS_PER_PGD));
+	shadow_pmd_count = NULL;
+	//TODO: free already allocated shadow_pte tables
+err1:
+	__free_pages((struct page *)shadow_pg_dir, get_order(16384));
+	return -ENOMEM;
+}
+core_initcall(init_shadow_page_table);
+#endif
 
 static u64 get_coherent_dma_mask(struct device *dev)
 {
@@ -168,7 +240,7 @@
 	pte_t *pte;
 	int i = 0;
 	unsigned long base = consistent_base;
-	unsigned long num_ptes = (CONSISTENT_END - base) >> PMD_SHIFT;
+	unsigned long num_ptes = (CONSISTENT_END - base + PMD_SIZE -1) >> PMD_SHIFT;
 
 	consistent_pte = kmalloc(num_ptes * sizeof(pte_t), GFP_KERNEL);
 	if (!consistent_pte) {
@@ -195,8 +267,9 @@
 			ret = -ENOMEM;
 			break;
 		}
+#if !defined(CONFIG_COMCERTO_64K_PAGES)
 		WARN_ON(!pmd_none(*pmd));
-
+#endif
 		pte = pte_alloc_kernel(pmd, base);
 		if (!pte) {
 			printk(KERN_ERR "%s: no pte tables\n", __func__);
@@ -205,8 +278,8 @@
 		}
 
 		consistent_pte[i++] = pte;
-		base += PMD_SIZE;
-	} while (base < CONSISTENT_END);
+		base = (base + PMD_SIZE) & PMD_MASK;
+	} while ((base-1) < (CONSISTENT_END - 1));
 
 	return ret;
 }
@@ -455,6 +528,217 @@
 }
 EXPORT_SYMBOL(dma_free_coherent);
 
+#if defined(CONFIG_COMCERTO_UNCACHED_DMA)
+static inline void shadow_pmd_inc(const void *kaddr, int incr)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&init_mm.page_table_lock, flags);
+	shadow_pmd_count[pgd_index((unsigned long) kaddr)] += incr;
+	spin_unlock_irqrestore(&init_mm.page_table_lock, flags);
+}
+
+static inline void copy_pmd_fast(pmd_t *pmdpd, pmd_t *pmdps)
+{
+#if !defined(CONFIG_COMCERTO_64K_PAGES)
+	pmdpd[0] = pmdps[0];
+	pmdpd[1] = pmdps[1];
+#else
+	int i;
+	for(i = 0; i < LINKED_PMDS; i++)
+		pmdpd[i] = pmdps[i];
+#endif
+}
+#endif
+
+static inline void __dmac_map_area(const void *kaddr, size_t size,
+	int dir)
+{
+#if defined(CONFIG_COMCERTO_UNCACHED_DMA)
+	pmd_t *pmd, *shadow_pmd;
+	pte_t *pte;
+	const void *kaddr_page;
+	const struct mem_type *mt;
+	unsigned int nr_pages, nr_pages_pmd;
+
+	if (!shadow_pmd_count)
+		goto op;
+
+	// For now, be safe and only uncache full pages so we don't have to handle
+	// the case of pages being DMA-mapped multiple times
+	if ((dir == DMA_FROM_DEVICE) && ((((unsigned long) kaddr|size) & ~PAGE_MASK) == 0)) {
+		mt = get_mem_type(MT_MEMORY_NONCACHED);
+		kaddr_page = kaddr;
+		pmd = pmd_off_k((unsigned long) kaddr_page);
+		shadow_pmd = (pmd_t *)shadow_pg_dir + (pmd - pmd_off_k(0));
+		nr_pages = __phys_to_pfn(size);
+
+		if (nr_pages == 1) { // Optimize for the common case
+			shadow_pmd_inc(kaddr_page, 1);
+			if (pmd_bad(*pmd)) { //No 2nd-level page table, retrieve it from the shadows
+				// Small race condition here, but at worst we'll end up copying the shadow_pmd to the actual pmd twice.
+				// For now, map the whole PMD. TODO: try and map only 1 section (1MB).
+				copy_pmd_fast(pmd, shadow_pmd);
+			}
+
+			pte = pte_offset_kernel(pmd, (int) kaddr_page);
+			uncache_pte_ext(pte);
+			flush_tlb_kernel_page((unsigned long) kaddr_page);
+			goto op;
+		}
+
+		nr_pages_pmd = __phys_to_pfn(PMD_SIZE - ((unsigned long) kaddr_page & ~PMD_MASK));
+
+		while (nr_pages) {
+
+			nr_pages_pmd = min(nr_pages, nr_pages_pmd);
+			nr_pages -= nr_pages_pmd;
+
+			shadow_pmd_inc(kaddr_page, nr_pages_pmd);
+
+			if (pmd_bad(*pmd)) { //No 2nd-level page table, retrieve it from the shadows
+				// Small race condition here, but at worst we'll end up copying the shadow_pmd to the actual pmd twice.
+				// For now, map the whole PMD. TODO: try and map only 1 section (1MB).
+				copy_pmd_fast(pmd, shadow_pmd);
+			}
+
+			pte = pte_offset_kernel(pmd, (int) kaddr_page);
+			while (nr_pages_pmd) {
+				uncache_pte_ext(pte);
+				flush_tlb_kernel_page((unsigned long) kaddr_page);
+				pte++;
+				kaddr_page += PAGE_SIZE;
+				nr_pages_pmd--;
+			}
+
+			nr_pages_pmd = PTRS_PER_PTE;
+#if !defined(CONFIG_COMCERTO_64K_PAGES)
+			pmd += 2;
+			shadow_pmd += 2;
+#else
+			pmd += LINKED_PMDS;
+			shadow_pmd += LINKED_PMDS;
+#endif
+		}
+	}
+	op:
+#endif
+	dmac_map_area(kaddr, size, dir);
+}
+
+static inline void __dmac_unmap_area(const void *kaddr, size_t size,
+	int dir)
+{
+#if defined(CONFIG_COMCERTO_UNCACHED_DMA)
+	pmd_t *pmd;
+	pte_t *pte;
+	const struct mem_type *mt;
+	unsigned long pa;
+	const void *kaddr_page;
+	unsigned long flags;
+	unsigned int nr_pages, nr_pages_pmd, page_count;
+
+	if (!shadow_pmd_count)
+		goto op;
+
+	if ((dir == DMA_FROM_DEVICE) && ((((unsigned long) kaddr|size) & ~PAGE_MASK) == 0)) {
+		mt = get_mem_type(MT_MEMORY);
+		kaddr_page = kaddr;
+
+		pmd = pmd_off_k((unsigned long) kaddr_page);
+		pa = __virt_to_phys((unsigned long)kaddr_page & PMD_MASK);
+
+		nr_pages = __phys_to_pfn(size);
+
+		if (nr_pages == 1) { // Optimize for the common case
+			if (pmd_bad(*pmd)) // No 2nd-level page table, so page was never made non-cacheable.
+				goto op;
+			pte = pte_offset_kernel(pmd, (int) kaddr_page);
+			set_pte_ext(pte, *pte, 0);
+
+			spin_lock_irqsave(&init_mm.page_table_lock, flags);
+			shadow_pmd_count[pgd_index((unsigned long) kaddr_page)]--;
+			if (shadow_pmd_count[pgd_index((unsigned long) kaddr_page)] == 0) {
+#if !defined(CONFIG_COMCERTO_64K_PAGES)
+				*pmd = __pmd(pa | mt->prot_sect);
+				pmd++;
+				pa += SECTION_SIZE;
+				*pmd = __pmd(pa | mt->prot_sect);
+#else
+				pmd_t *orig_pmd = pmd;
+				while (pmd < (orig_pmd + LINKED_PMDS)) {
+					*pmd = __pmd(pa | mt->prot_sect);
+					pa += SECTION_SIZE;
+					pmd++;
+				}
+#endif
+			}
+			spin_unlock_irqrestore(&init_mm.page_table_lock, flags);
+
+			flush_tlb_kernel_page((unsigned long) kaddr_page);
+			return;
+		}
+
+		nr_pages_pmd = __phys_to_pfn(PMD_SIZE - ((unsigned long) kaddr_page & ~PMD_MASK));
+
+		while (nr_pages) {
+			if (pmd_bad(*pmd)) // No 2nd-level page table, so page was never made non-cacheable.
+				goto op;
+			nr_pages_pmd = min(nr_pages, nr_pages_pmd);
+			nr_pages -= nr_pages_pmd;
+
+			pte = pte_offset_kernel(pmd, (int) kaddr_page);
+			page_count = nr_pages_pmd;
+			while (page_count) {
+				set_pte_ext(pte, *pte, 0);
+				pte++;
+				page_count--;
+			}
+
+			spin_lock_irqsave(&init_mm.page_table_lock, flags);
+			shadow_pmd_count[pgd_index((unsigned long) kaddr_page)] -= nr_pages_pmd;
+			if (shadow_pmd_count[pgd_index((unsigned long) kaddr_page)] == 0) {
+#if !defined(CONFIG_COMCERTO_64K_PAGES)
+				*pmd = __pmd(pa | mt->prot_sect);
+				pmd++;
+				pa += SECTION_SIZE;
+				*pmd = __pmd(pa | mt->prot_sect);
+				pmd++;
+				pa += SECTION_SIZE;
+#else
+				pmd_t *orig_pmd = pmd;
+				while (pmd < (orig_pmd + LINKED_PMDS)) {
+					*pmd = __pmd(pa | mt->prot_sect);
+					pmd++;
+					pa += SECTION_SIZE;
+				}
+#endif
+			}
+			spin_unlock_irqrestore(&init_mm.page_table_lock, flags);
+
+			while (nr_pages_pmd) {
+				flush_tlb_kernel_page((unsigned long) kaddr_page);
+				kaddr_page += PAGE_SIZE;
+				nr_pages_pmd--;
+			}
+
+			nr_pages_pmd = PTRS_PER_PTE;
+		}
+
+		return;
+	}
+	op:
+#endif
+#if !defined(CONFIG_CPU_DMA_PARTIAL_INVALIDATES)
+	dmac_unmap_area(kaddr, size, dir);
+#else
+	size_t size_inv = min_t(size_t, 32, size);
+
+	dmac_unmap_area(kaddr, size_inv, dir);
+	dmac_unmap_area(kaddr + size - size_inv, size_inv, dir);
+#endif
+}
+
 /*
  * Make an area consistent for devices.
  * Note: Drivers should NOT use this function directly, as it will break
@@ -464,35 +748,58 @@
 void ___dma_single_cpu_to_dev(const void *kaddr, size_t size,
 	enum dma_data_direction dir)
 {
-	unsigned long paddr;
+	unsigned long paddr = __pa(kaddr);
 
 	BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1));
 
-	dmac_map_area(kaddr, size, dir);
+#ifdef CONFIG_COMCERTO_ZONE_DMA_NCNB
+	if ((paddr + size) <= arm_dma_zone_size) {
+		if (dir != DMA_FROM_DEVICE)
+			wmb();
 
-	paddr = __pa(kaddr);
+		return;
+	}
+#endif
+	__dmac_map_area(kaddr, size, dir);
+
+#if !defined(CONFIG_L2X0_INSTRUCTION_ONLY)
 	if (dir == DMA_FROM_DEVICE) {
 		outer_inv_range(paddr, paddr + size);
 	} else {
 		outer_clean_range(paddr, paddr + size);
 	}
 	/* FIXME: non-speculating: flush on bidirectional mappings? */
+#endif
 }
 EXPORT_SYMBOL(___dma_single_cpu_to_dev);
 
 void ___dma_single_dev_to_cpu(const void *kaddr, size_t size,
 	enum dma_data_direction dir)
 {
+	unsigned long paddr = __pa(kaddr);
+
 	BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1));
 
-	/* FIXME: non-speculating: not required */
+#ifdef CONFIG_COMCERTO_ZONE_DMA_NCNB
+	if ((paddr + size) <= arm_dma_zone_size)
+		return;
+#endif
+
+#if !defined(CONFIG_L2X0_INSTRUCTION_ONLY)
 	/* don't bother invalidating if DMA to device */
 	if (dir != DMA_TO_DEVICE) {
-		unsigned long paddr = __pa(kaddr);
+#if !defined(CONFIG_CPU_DMA_PARTIAL_INVALIDATES)
 		outer_inv_range(paddr, paddr + size);
-	}
+#else
+		size_t size_inv = min_t(size_t, 32, size);
 
-	dmac_unmap_area(kaddr, size, dir);
+		outer_inv_range(paddr, paddr + size_inv);
+		outer_inv_range(paddr + size - size_inv, paddr + size);
+#endif
+	}
+#endif
+
+	__dmac_unmap_area(kaddr, size, dir);
 }
 EXPORT_SYMBOL(___dma_single_dev_to_cpu);
 
@@ -534,6 +841,7 @@
 			vaddr = page_address(page) + offset;
 			op(vaddr, len, dir);
 		}
+
 		offset = 0;
 		page++;
 		left -= len;
@@ -543,16 +851,26 @@
 void ___dma_page_cpu_to_dev(struct page *page, unsigned long off,
 	size_t size, enum dma_data_direction dir)
 {
-	unsigned long paddr;
+	unsigned long paddr = page_to_phys(page) + off;
 
-	dma_cache_maint_page(page, off, size, dir, dmac_map_area);
+#ifdef CONFIG_COMCERTO_ZONE_DMA_NCNB
+	if ((paddr + size) <= arm_dma_zone_size) {
+		if (dir != DMA_FROM_DEVICE)
+			wmb();
 
-	paddr = page_to_phys(page) + off;
+		return;
+	}
+#endif
+
+	dma_cache_maint_page(page, off, size, dir, __dmac_map_area);
+
+#if !defined(CONFIG_L2X0_INSTRUCTION_ONLY)
 	if (dir == DMA_FROM_DEVICE) {
 		outer_inv_range(paddr, paddr + size);
 	} else {
 		outer_clean_range(paddr, paddr + size);
 	}
+#endif
 	/* FIXME: non-speculating: flush on bidirectional mappings? */
 }
 EXPORT_SYMBOL(___dma_page_cpu_to_dev);
@@ -562,12 +880,25 @@
 {
 	unsigned long paddr = page_to_phys(page) + off;
 
-	/* FIXME: non-speculating: not required */
-	/* don't bother invalidating if DMA to device */
-	if (dir != DMA_TO_DEVICE)
-		outer_inv_range(paddr, paddr + size);
+#ifdef CONFIG_COMCERTO_ZONE_DMA_NCNB
+	if ((paddr + size) <= arm_dma_zone_size)
+		return;
+#endif
 
-	dma_cache_maint_page(page, off, size, dir, dmac_unmap_area);
+#if !defined(CONFIG_L2X0_INSTRUCTION_ONLY)
+	/* don't bother invalidating if DMA to device */
+	if (dir != DMA_TO_DEVICE) {
+#if !defined(CONFIG_CPU_DMA_PARTIAL_INVALIDATES)
+		outer_inv_range(paddr, paddr + size);
+#else
+		size_t size_inv = min_t(size_t, 32, size);
+
+		outer_inv_range(paddr, paddr + size_inv);
+		outer_inv_range(paddr + size - size_inv, paddr + size);
+#endif
+	}
+#endif
+	dma_cache_maint_page(page, off, size, dir, __dmac_unmap_area);
 
 	/*
 	 * Mark the D-cache clean for this page to avoid extra flushing.
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
index 1a8d4aa..94e7396 100644
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -229,6 +229,26 @@
 	flush_dcache_mmap_unlock(mapping);
 }
 
+#if defined(CONFIG_L2X0_INSTRUCTION_ONLY)
+
+void __sync_outer_cache(pte_t *ptep, pte_t pteval)
+{
+	if (pte_present(*ptep) && pte_exec(*ptep) && (!pte_present(pteval) || !pte_exec(pteval))) {
+		unsigned long phys = __pfn_to_phys(pte_pfn(*ptep));
+
+//		printk(KERN_INFO "outer flush range: %x %x %lx-%lx\n", pte_val(*ptep), pteval, phys, phys + PAGE_SIZE);
+		outer_flush_range(phys, phys + PAGE_SIZE);
+	}
+}
+
+static void sync_outer_cache(struct page *page)
+{
+	unsigned long phys = page_to_phys(page);
+
+	outer_flush_range(phys, phys + PAGE_SIZE);
+}
+#endif
+
 #if __LINUX_ARM_ARCH__ >= 6
 void __sync_icache_dcache(pte_t pteval)
 {
@@ -300,6 +320,10 @@
 			__flush_dcache_aliases(mapping, page);
 		else if (mapping)
 			__flush_icache_all();
+
+#if defined(CONFIG_L2X0_INSTRUCTION_ONLY)
+		sync_outer_cache(page);
+#endif
 		set_bit(PG_dcache_clean, &page->flags);
 	}
 }
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index fbdd12e..f362cf8 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -288,7 +288,11 @@
 	if (arm_dma_zone_size) {
 		arm_adjust_dma_zone(zone_size, zhole_size,
 			arm_dma_zone_size >> PAGE_SHIFT);
+#ifdef CONFIG_COMCERTO_ZONE_DMA_NCNB
+		arm_dma_limit = 0xffffffff;
+#else
 		arm_dma_limit = PHYS_OFFSET + arm_dma_zone_size - 1;
+#endif
 	} else
 		arm_dma_limit = 0xffffffff;
 #endif
@@ -423,9 +427,15 @@
 
 	for (; pfn < end; pfn++) {
 		struct page *page = pfn_to_page(pfn);
+#if defined(CONFIG_L2X0_INSTRUCTION_ONLY)
+		unsigned long phys = page_to_phys(page);
+#endif
 		ClearPageReserved(page);
 		init_page_count(page);
 		__free_page(page);
+#if defined(CONFIG_L2X0_INSTRUCTION_ONLY)
+		outer_flush_range(phys, phys + PAGE_SIZE);
+#endif
 		pages++;
 	}
 
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index dc8c550..f452bdc 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -281,6 +281,18 @@
 				PMD_SECT_UNCACHED | PMD_SECT_XN,
 		.domain    = DOMAIN_KERNEL,
 	},
+	[MT_MSP] = {
+		.prot_pte  = PROT_PTE_DEVICE | L_PTE_MT_DEV_CACHED | L_PTE_XN,
+		.prot_l1   = PMD_TYPE_TABLE,
+		.prot_sect = PROT_SECT_DEVICE | PMD_SECT_WB,
+		.domain    = DOMAIN_IO,
+	},
+	[MT_MSP_NCNB] = {
+		.prot_pte  = PROT_PTE_DEVICE | L_PTE_XN,
+		.prot_l1   = PMD_TYPE_TABLE,
+		.prot_sect = PROT_SECT_DEVICE | PMD_SECT_S,
+		.domain    = DOMAIN_IO,
+	},
 };
 
 const struct mem_type *get_mem_type(unsigned int type)
@@ -572,8 +584,7 @@
 	if (((addr | end | phys) & ~SECTION_MASK) == 0) {
 		pmd_t *p = pmd;
 
-		if (addr & SECTION_SIZE)
-			pmd++;
+		pmd += (addr & (~PGDIR_MASK)) >> SECTION_SHIFT;
 
 		do {
 			*pmd = __pmd(phys | type->prot_sect);
@@ -1013,7 +1024,10 @@
 static void __init map_lowmem(void)
 {
 	struct memblock_region *reg;
-
+#ifdef CONFIG_COMCERTO_ZONE_DMA_NCNB
+	extern unsigned long arm_dma_zone_size;
+	phys_addr_t length_ncnb = arm_dma_zone_size, length_ncnb_now = 0;
+#endif
 	/* Map all the lowmem memory banks. */
 	for_each_memblock(memory, reg) {
 		phys_addr_t start = reg->base;
@@ -1024,7 +1038,31 @@
 			end = lowmem_limit;
 		if (start >= end)
 			break;
+#ifdef CONFIG_COMCERTO_ZONE_DMA_NCNB
+		if (length_ncnb > 0)
+		{
+			length_ncnb_now = min(length_ncnb, end - start);
+			map.pfn = __phys_to_pfn(start);
+			map.virtual = __phys_to_virt(start);
+			map.length = length_ncnb_now;
+			map.type = MT_MEMORY_NONCACHED;
 
+			printk("Comcerto: zone_dma mapping size=%lx type=%lx\n", (unsigned long) map.length, (unsigned long) map.type);
+
+			if (!arm_dma_zone.start)
+				arm_dma_zone.start = __phys_to_virt(start);
+
+			create_mapping(&map);
+			start += length_ncnb_now;
+			length_ncnb -= length_ncnb_now;
+
+			arm_dma_zone.end = __phys_to_virt(start);
+
+			if (start == end)
+				continue;
+
+		}
+#endif
 		map.pfn = __phys_to_pfn(start);
 		map.virtual = __phys_to_virt(start);
 		map.length = end - start;
diff --git a/arch/arm/mm/pgd.c b/arch/arm/mm/pgd.c
index b2027c1..27b9016 100644
--- a/arch/arm/mm/pgd.c
+++ b/arch/arm/mm/pgd.c
@@ -27,7 +27,7 @@
 	pmd_t *new_pmd, *init_pmd;
 	pte_t *new_pte, *init_pte;
 
-	new_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL, 2);
+	new_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL, get_order(16384));
 	if (!new_pgd)
 		goto no_pgd;
 
@@ -74,7 +74,7 @@
 no_pmd:
 	pud_free(mm, new_pud);
 no_pud:
-	free_pages((unsigned long)new_pgd, 2);
+	free_pages((unsigned long)new_pgd, get_order(16384));
 no_pgd:
 	return NULL;
 }
@@ -111,5 +111,5 @@
 	pgd_clear(pgd);
 	pud_free(mm, pud);
 no_pgd:
-	free_pages((unsigned long) pgd_base, 2);
+	free_pages((unsigned long) pgd_base, get_order(16384));
 }
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index 785365e..5f3bd9b 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -46,7 +46,7 @@
 	mrc	p15, 0, r0, c1, c0, 0		@ ctrl register
 	bic	r0, r0, #0x1000			@ ...i............
 	bic	r0, r0, #0x0006			@ .............ca.
-	mcr	p15, 0, r0, c1, c0, 0		@ disable caches
+#	mcr	p15, 0, r0, c1, c0, 0		@ disable caches
 	mov	pc, lr
 ENDPROC(cpu_v7_proc_fin)
 
@@ -149,7 +149,11 @@
 	bic	r3, r1, #0x000003f0
 	bic	r3, r3, #PTE_TYPE_MASK
 	orr	r3, r3, r2
+#if !defined(CONFIG_COMCERTO_64K_PAGES)
 	orr	r3, r3, #PTE_EXT_AP0 | 2
+#else
+	orr	r3, r3, #PTE_EXT_AP0 | 1
+#endif
 
 	tst	r1, #1 << 4
 	orrne	r3, r3, #PTE_EXT_TEX(1)
@@ -173,14 +177,65 @@
 	tstne	r1, #L_PTE_PRESENT
 	moveq	r3, #0
 
+#if !defined(CONFIG_COMCERTO_64K_PAGES)
  ARM(	str	r3, [r0, #2048]! )
  THUMB(	add	r0, r0, #2048 )
  THUMB(	str	r3, [r0] )
 	mcr	p15, 0, r0, c7, c10, 1		@ flush_pte
+ #else
+	ldr r1, =32768		@ PTE_HWTABLE_OFF
+	add r1, r1, r0
+	add r2, r1, #64		@ 16*4 bytes
+ 1:
+	sub r2, r2, #4
+ 	str	r3, [r2]!
+	cmp r1, r2
+	blo 1b
+	mcr	p15, 0, r1, c7, c10, 1		@ flush_pte
+	add r1, r1, #32				@ 1 cache line, since HW PTE takes 64 bytes
+	mcr	p15, 0, r1, c7, c10, 1		@ flush_pte
+ #endif
+
+
 #endif
 	mov	pc, lr
 ENDPROC(cpu_v7_set_pte_ext)
 
+/* Make the memory uncached, but keep Linux settings as is so memory may be
+ * reset to original attributes later on.
+ */
+ENTRY(cpu_v7_uncache_pte_ext)
+#ifdef CONFIG_MMU
+#if !defined(CONFIG_COMCERTO_64K_PAGES)
+ ARM(	ldr	r3, [r0, #2048]! )
+ THUMB(	add	r0, r0, #2048 )
+ THUMB( ldr r3, [r0] )
+		bic r3, r3, #0x48		@ clear TEX[0],C bits (see below)
+		orr r3, r3, #0x4  		@ set B bit (see below)
+ ARM(	str	r3, [r0, #2048]! )
+ THUMB(	str	r3, [r0] )
+ #else
+	ldr r1, =32768		@ PTE_HWTABLE_OFF
+	add r1, r1, r0
+	ldr r3, [r1]
+	add r2, r1, #64		@ 16*4 bytes
+ARM(	bic r3, r3, #0x1008 ) 	@ clear TEX[0],C bits (see below)
+THUMB(	bic r3, r3, #0x8 )
+THUMB(	bic r3, r3, #0x1000 )
+	orr r3, r3, #0x4			@ set B bit (see below)
+ 1:
+	sub r2, r2, #4
+	str	r3, [r2]!
+	cmp r1, r2
+	blo 1b
+ #endif
+
+
+#endif
+	mov	pc, lr
+ENDPROC(cpu_v7_uncache_pte_ext)
+
+
 	string	cpu_v7_name, "ARMv7 Processor"
 	.align
 
@@ -247,6 +302,9 @@
 	ALT_UP(orr	r1, r1, #TTB_FLAGS_UP)
 	mcr	p15, 0, r1, c2, c0, 0	@ TTB 0
 	mcr	p15, 0, r7, c2, c0, 1	@ TTB 1
+#if defined(CONFIG_COMCERTO_HW_KERNEL_PAGETABLE)
+	mov ip, #1						@ set TTBRCR.N to 1, so that addresses above 2GB will use TTB1
+#endif
 	mcr	p15, 0, ip, c2, c0, 2	@ TTB control register
 	mrc	p15, 0, r4, c1, c0, 1	@ Read Auxiliary control register
 	teq	r4, r9			@ Is it already set?
@@ -277,9 +335,16 @@
  *	- cache type register is implemented
  */
 __v7_ca5mp_setup:
-__v7_ca9mp_setup:
 	mov	r10, #(1 << 0)			@ TLB ops broadcasting
 	b	1f
+
+__v7_ca9mp_setup:
+	mov	r10, #(1 << 0)			@ TLB ops broadcasting
+#if !defined(CONFIG_CPU_SPECULATIVE_ACCESS_DISABLED)
+	orr	r10, #(3 << 1)			@ L1 data prefetch, L2 prefetch hints enable
+#endif
+	b	1f
+
 __v7_ca15mp_setup:
 	mov	r10, #0
 1:
@@ -371,6 +436,9 @@
 	dsb
 #ifdef CONFIG_MMU
 	mcr	p15, 0, r10, c8, c7, 0		@ invalidate I + D TLBs
+#if defined(CONFIG_COMCERTO_HW_KERNEL_PAGETABLE)
+	mov r10, #1						@ set TTBRCR.N to 1, so that addresses above 2GB will use TTB1
+#endif
 	mcr	p15, 0, r10, c2, c0, 2		@ TTB control register
 	ALT_SMP(orr	r4, r4, #TTB_FLAGS_SMP)
 	ALT_UP(orr	r4, r4, #TTB_FLAGS_UP)
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index ccbe16f..3a670a5 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -212,6 +212,7 @@
 onearm			MACH_ONEARM		ONEARM			1075
 smdk2443		MACH_SMDK2443		SMDK2443		1084
 fsg			MACH_FSG		FSG			1091
+comcerto		MACH_COMCERTO		COMCERTO		1094
 at91sam9260ek		MACH_AT91SAM9260EK	AT91SAM9260EK		1099
 glantank		MACH_GLANTANK		GLANTANK		1100
 n2100			MACH_N2100		N2100			1101
diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S
index 4fa9903..cc926c9 100644
--- a/arch/arm/vfp/entry.S
+++ b/arch/arm/vfp/entry.S
@@ -7,18 +7,20 @@
  * 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.
- *
- * Basic entry code, called from the kernel's undefined instruction trap.
- *  r0  = faulted instruction
- *  r5  = faulted PC+4
- *  r9  = successful return
- *  r10 = thread_info structure
- *  lr  = failure return
  */
 #include <asm/thread_info.h>
 #include <asm/vfpmacros.h>
 #include "../kernel/entry-header.S"
 
+@ VFP entry point.
+@
+@  r0  = instruction opcode (32-bit ARM or two 16-bit Thumb)
+@  r2  = PC value to resume execution after successful emulation
+@  r9  = normal "successful" return address
+@  r10 = this threads thread_info structure
+@  lr  = unrecognised instruction return address
+@  IRQs disabled.
+@
 ENTRY(do_vfp)
 #ifdef CONFIG_PREEMPT
 	ldr	r4, [r10, #TI_PREEMPT]	@ get preempt count
diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
index 2d30c7f..3a0efaa 100644
--- a/arch/arm/vfp/vfphw.S
+++ b/arch/arm/vfp/vfphw.S
@@ -61,13 +61,13 @@
 
 @ VFP hardware support entry point.
 @
-@  r0  = faulted instruction
-@  r2  = faulted PC+4
-@  r9  = successful return
+@  r0  = instruction opcode (32-bit ARM or two 16-bit Thumb)
+@  r2  = PC value to resume execution after successful emulation
+@  r9  = normal "successful" return address
 @  r10 = vfp_state union
 @  r11 = CPU number
-@  lr  = failure return
-
+@  lr  = unrecognised instruction return address
+@  IRQs enabled.
 ENTRY(vfp_support_entry)
 	DBGSTR3	"instr %08x pc %08x state %p", r0, r2, r10
 
@@ -161,9 +161,12 @@
 					@ exception before retrying branch
 					@ out before setting an FPEXC that
 					@ stops us reading stuff
-	VFPFMXR	FPEXC, r1		@ restore FPEXC last
-	sub	r2, r2, #4
-	str	r2, [sp, #S_PC]		@ retry the instruction
+	VFPFMXR	FPEXC, r1		@ Restore FPEXC last
+	sub	r2, r2, #4		@ Retry current instruction - if Thumb
+	str	r2, [sp, #S_PC]		@ mode it's two 16-bit instructions,
+					@ else it's one 32-bit instruction, so
+					@ always subtract 4 from the following
+					@ instruction address.
 #ifdef CONFIG_PREEMPT
 	get_thread_info	r10
 	ldr	r4, [r10, #TI_PREEMPT]	@ get preempt count
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 6cca0d2..a122aed 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -923,3 +923,6 @@
 source "drivers/crypto/Kconfig"
 
 endif	# if CRYPTO
+
+source "crypto/ocf/Kconfig"
+
diff --git a/crypto/Makefile b/crypto/Makefile
index 9e6eee2..3cde9f8 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -91,6 +91,8 @@
 obj-$(CONFIG_CRYPTO_USER_API_HASH) += algif_hash.o
 obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o
 
+obj-$(CONFIG_OCF_OCF) += ocf/
+
 #
 # generic algorithms and the async_tx api
 #
diff --git a/crypto/ocf/Config.in b/crypto/ocf/Config.in
new file mode 100644
index 0000000..652f76e
--- /dev/null
+++ b/crypto/ocf/Config.in
@@ -0,0 +1,38 @@
+#############################################################################
+
+mainmenu_option next_comment
+comment 'OCF Configuration'
+tristate 'OCF (Open Cryptograhic Framework)' CONFIG_OCF_OCF
+dep_mbool '  enable fips RNG checks (fips check on RNG data before use)' \
+				CONFIG_OCF_FIPS $CONFIG_OCF_OCF
+dep_mbool '  enable harvesting entropy for /dev/random' \
+				CONFIG_OCF_RANDOMHARVEST $CONFIG_OCF_OCF
+dep_tristate '  cryptodev (user space support)' \
+				CONFIG_OCF_CRYPTODEV $CONFIG_OCF_OCF
+dep_tristate '  cryptosoft (software crypto engine)' \
+				CONFIG_OCF_CRYPTOSOFT $CONFIG_OCF_OCF
+dep_tristate '  safenet (HW crypto engine)' \
+				CONFIG_OCF_SAFE $CONFIG_OCF_OCF
+dep_tristate '  IXP4xx (HW crypto engine)' \
+				CONFIG_OCF_IXP4XX $CONFIG_OCF_OCF
+dep_mbool    '  Enable IXP4xx HW to perform SHA1 and MD5 hashing (very slow)' \
+				CONFIG_OCF_IXP4XX_SHA1_MD5 $CONFIG_OCF_IXP4XX
+dep_tristate '  hifn (HW crypto engine)' \
+				CONFIG_OCF_HIFN $CONFIG_OCF_OCF
+dep_tristate '  talitos (HW crypto engine)' \
+				CONFIG_OCF_TALITOS $CONFIG_OCF_OCF
+dep_tristate '  pasemi (HW crypto engine)' \
+				CONFIG_OCF_PASEMI $CONFIG_OCF_OCF
+dep_tristate '  ep80579 (HW crypto engine)' \
+				CONFIG_OCF_EP80579 $CONFIG_OCF_OCF
+dep_tristate '  Micronas c7108 (HW crypto engine)' \
+				CONFIG_OCF_C7108 $CONFIG_OCF_OCF
+dep_tristate '  uBsec BCM5365 (HW crypto engine)'
+				CONFIG_OCF_UBSEC_SSB $CONFIG_OCF_OCF
+dep_tristate '  ocfnull (does no crypto)' \
+				CONFIG_OCF_OCFNULL $CONFIG_OCF_OCF
+dep_tristate '  ocf-bench (HW crypto in-kernel benchmark)' \
+				CONFIG_OCF_BENCH $CONFIG_OCF_OCF
+endmenu
+
+#############################################################################
diff --git a/crypto/ocf/Kconfig b/crypto/ocf/Kconfig
new file mode 100644
index 0000000..8b01ca5
--- /dev/null
+++ b/crypto/ocf/Kconfig
@@ -0,0 +1,48 @@
+menu "OCF Configuration"
+
+config OCF_OCF
+	tristate "OCF (Open Cryptograhic Framework)"
+	help
+	  A linux port of the OpenBSD/FreeBSD crypto framework.
+
+config OCF_RANDOMHARVEST
+	bool "crypto random --- harvest entropy for /dev/random"
+	depends on OCF_OCF
+	help
+	  Includes code to harvest random numbers from devices that support it.
+
+config OCF_FIPS
+	bool "enable fips RNG checks"
+	depends on OCF_OCF && OCF_RANDOMHARVEST
+	help
+	  Run all RNG provided data through a fips check before
+	  adding it /dev/random's entropy pool.
+
+config OCF_CRYPTODEV
+	tristate "cryptodev (user space support)"
+	depends on OCF_OCF
+	help
+	  The user space API to access crypto hardware.
+
+config OCF_CRYPTOSOFT
+	tristate "cryptosoft (software crypto engine)"
+	depends on OCF_OCF
+	help
+	  A software driver for the OCF framework that uses
+	  the kernel CryptoAPI.
+
+config OCF_BENCH
+	tristate "ocf-bench (HW crypto in-kernel benchmark)"
+	depends on OCF_OCF
+	help
+	  A very simple encryption test for the in-kernel interface
+	  of OCF.  Also includes code to benchmark the IXP Access library
+	  for comparison.
+
+config OCF_DM_CRYPT
+	bool "ocf-dm-crypt (HW crypto engine)"
+	depends on OCF_OCF
+	help
+	OCF support for crypto offloading of dm-crypt
+
+endmenu
diff --git a/crypto/ocf/Makefile b/crypto/ocf/Makefile
new file mode 100644
index 0000000..6b49294
--- /dev/null
+++ b/crypto/ocf/Makefile
@@ -0,0 +1,137 @@
+# for SGlinux builds
+-include $(ROOTDIR)/modules/.config
+
+OCF_OBJS = crypto.o criov.o
+
+ifdef CONFIG_OCF_RANDOMHARVEST
+	OCF_OBJS += random.o
+endif
+
+ifdef CONFIG_OCF_FIPS
+	OCF_OBJS += rndtest.o
+endif
+
+# Add in autoconf.h to get #defines for CONFIG_xxx
+AUTOCONF_H=$(ROOTDIR)/modules/autoconf.h
+ifeq ($(AUTOCONF_H), $(wildcard $(AUTOCONF_H)))
+	EXTRA_CFLAGS += -include $(AUTOCONF_H)
+	export EXTRA_CFLAGS
+endif
+
+ifndef obj
+	obj ?= .
+	_obj = subdir
+	mod-subdirs := safe hifn ixp4xx talitos ocfnull
+	export-objs += crypto.o criov.o random.o
+	list-multi += ocf.o
+	_slash :=
+else
+	_obj = obj
+	_slash := /
+endif
+
+EXTRA_CFLAGS += -I$(obj)/.
+
+obj-$(CONFIG_OCF_OCF)         += ocf.o
+obj-$(CONFIG_OCF_CRYPTODEV)   += cryptodev.o
+obj-$(CONFIG_OCF_CRYPTOSOFT)  += cryptosoft.o
+obj-$(CONFIG_OCF_BENCH)       += ocf-bench.o
+
+
+ocf-objs := $(OCF_OBJS)
+
+dummy:
+	@echo "Please consult the README for how to build OCF."
+	@echo "If you can't wait then the following should do it:"
+	@echo ""
+	@echo "    make ocf_modules"
+	@echo "    sudo make ocf_install"
+	@echo ""
+	@exit 1
+	
+$(list-multi) dummy1: $(ocf-objs)
+	$(LD) -r -o $@ $(ocf-objs)
+
+.PHONY:
+clean:
+	rm -f *.o *.ko .*.o.flags .*.ko.cmd .*.o.cmd .*.mod.o.cmd *.mod.c
+	rm -f */*.o */*.ko */.*.o.cmd */.*.ko.cmd */.*.mod.o.cmd */*.mod.c */.*.o.flags
+	rm -f */modules.order */modules.builtin modules.order modules.builtin
+
+ifdef TOPDIR
+-include $(TOPDIR)/Rules.make
+endif
+
+#
+# targets to build easily on the current machine
+#
+
+ocf_make:
+	make -C /lib/modules/$(shell uname -r)/build M=`pwd` $(OCF_TARGET) CONFIG_OCF_OCF=m
+	make -C /lib/modules/$(shell uname -r)/build M=`pwd` $(OCF_TARGET) CONFIG_OCF_OCF=m CONFIG_OCF_CRYPTOSOFT=m
+	-make -C /lib/modules/$(shell uname -r)/build M=`pwd` $(OCF_TARGET) CONFIG_OCF_OCF=m CONFIG_OCF_BENCH=m
+	-make -C /lib/modules/$(shell uname -r)/build M=`pwd` $(OCF_TARGET) CONFIG_OCF_OCF=m CONFIG_OCF_OCFNULL=m
+	-make -C /lib/modules/$(shell uname -r)/build M=`pwd` $(OCF_TARGET) CONFIG_OCF_OCF=m CONFIG_OCF_HIFN=m
+
+ocf_modules:
+	$(MAKE) ocf_make OCF_TARGET=modules
+
+ocf_install:
+	$(MAKE) ocf_make OCF_TARGET="modules modules_install"
+	depmod
+	mkdir -p /usr/include/crypto
+	cp cryptodev.h /usr/include/crypto/.
+
+#
+# generate full kernel patches for 2.4 and 2.6 kernels to make patching
+# your kernel easier
+#
+
+.PHONY: patch
+patch:
+	patchbase=.; \
+		[ -d $$patchbase/patches ] || patchbase=..; \
+		patch=ocf-linux-base.patch; \
+		patch24=ocf-linux-24.patch; \
+		patch26=ocf-linux-26.patch; \
+		patch3=ocf-linux-3.patch; \
+		( \
+			find . -name Makefile; \
+			find . -name Config.in; \
+			find . -name Kconfig; \
+			find . -name README; \
+			find . -name '*.[ch]' | grep -v '.mod.c'; \
+		) | while read t; do \
+			diff -Nau /dev/null $$t | sed 's?^+++ \./?+++ linux/crypto/ocf/?'; \
+		done > $$patch; \
+		cat $$patchbase/patches/linux-2.4.35-ocf.patch $$patch > $$patch24; \
+		cat $$patchbase/patches/linux-2.6.38-ocf.patch $$patch > $$patch26; \
+		cat $$patchbase/patches/linux-3.2.1-ocf.patch $$patch > $$patch3; \
+
+
+#
+# this target probably does nothing for anyone but me - davidm
+#
+
+.PHONY: release
+release:
+	REL=`date +%Y%m%d`; RELDIR=/tmp/ocf-linux-$$REL; \
+		CURDIR=`pwd`; \
+		rm -rf /tmp/ocf-linux-$$REL*; \
+		mkdir -p $$RELDIR/ocf; \
+		mkdir -p $$RELDIR/patches; \
+		mkdir -p $$RELDIR/crypto-tools; \
+		cp README* $$RELDIR/.; \
+		cp patches/[!C]* $$RELDIR/patches/.; \
+		cp tools/[!C]* $$RELDIR/crypto-tools/.; \
+		cp -r [!C]* Config.in $$RELDIR/ocf/.; \
+		rm -rf $$RELDIR/ocf/patches $$RELDIR/ocf/tools; \
+		rm -f $$RELDIR/ocf/README*; \
+		cp $$CURDIR/../../user/crypto-tools/[!C]* $$RELDIR/crypto-tools/.; \
+		make -C $$RELDIR/crypto-tools clean; \
+		make -C $$RELDIR/ocf clean; \
+		find $$RELDIR/ocf -name CVS | xargs rm -rf; \
+		cd $$RELDIR/..; \
+		tar cvf ocf-linux-$$REL.tar ocf-linux-$$REL; \
+		gzip -9 ocf-linux-$$REL.tar
+
diff --git a/crypto/ocf/criov.c b/crypto/ocf/criov.c
new file mode 100644
index 0000000..a8c1a8c
--- /dev/null
+++ b/crypto/ocf/criov.c
@@ -0,0 +1,215 @@
+/*      $OpenBSD: criov.c,v 1.9 2002/01/29 15:48:29 jason Exp $	*/
+
+/*
+ * Linux port done by David McCullough <david_mccullough@mcafee.com>
+ * Copyright (C) 2006-2010 David McCullough
+ * Copyright (C) 2004-2005 Intel Corporation.
+ * The license and original author are listed below.
+ *
+ * Copyright (c) 1999 Theo de Raadt
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+__FBSDID("$FreeBSD: src/sys/opencrypto/criov.c,v 1.5 2006/06/04 22:15:13 pjd Exp $");
+ */
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED)
+#include <linux/config.h>
+#endif
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/uio.h>
+#include <linux/skbuff.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+
+#include <uio.h>
+#include <cryptodev.h>
+
+/*
+ * This macro is only for avoiding code duplication, as we need to skip
+ * given number of bytes in the same way in three functions below.
+ */
+#define	CUIO_SKIP()	do {						\
+	KASSERT(off >= 0, ("%s: off %d < 0", __func__, off));		\
+	KASSERT(len >= 0, ("%s: len %d < 0", __func__, len));		\
+	while (off > 0) {						\
+		KASSERT(iol >= 0, ("%s: empty in skip", __func__));	\
+		if (off < iov->iov_len)					\
+			break;						\
+		off -= iov->iov_len;					\
+		iol--;							\
+		iov++;							\
+	}								\
+} while (0)
+
+void
+cuio_copydata(struct uio* uio, int off, int len, caddr_t cp)
+{
+	struct iovec *iov = uio->uio_iov;
+	int iol = uio->uio_iovcnt;
+	unsigned count;
+
+	CUIO_SKIP();
+	while (len > 0) {
+		KASSERT(iol >= 0, ("%s: empty", __func__));
+		count = min((int)(iov->iov_len - off), len);
+		memcpy(cp, ((caddr_t)iov->iov_base) + off, count);
+		len -= count;
+		cp += count;
+		off = 0;
+		iol--;
+		iov++;
+	}
+}
+
+void
+cuio_copyback(struct uio* uio, int off, int len, caddr_t cp)
+{
+	struct iovec *iov = uio->uio_iov;
+	int iol = uio->uio_iovcnt;
+	unsigned count;
+
+	CUIO_SKIP();
+	while (len > 0) {
+		KASSERT(iol >= 0, ("%s: empty", __func__));
+		count = min((int)(iov->iov_len - off), len);
+		memcpy(((caddr_t)iov->iov_base) + off, cp, count);
+		len -= count;
+		cp += count;
+		off = 0;
+		iol--;
+		iov++;
+	}
+}
+
+/*
+ * Return a pointer to iov/offset of location in iovec list.
+ */
+struct iovec *
+cuio_getptr(struct uio *uio, int loc, int *off)
+{
+	struct iovec *iov = uio->uio_iov;
+	int iol = uio->uio_iovcnt;
+
+	while (loc >= 0) {
+		/* Normal end of search */
+		if (loc < iov->iov_len) {
+	    		*off = loc;
+	    		return (iov);
+		}
+
+		loc -= iov->iov_len;
+		if (iol == 0) {
+			if (loc == 0) {
+				/* Point at the end of valid data */
+				*off = iov->iov_len;
+				return (iov);
+			} else
+				return (NULL);
+		} else {
+			iov++, iol--;
+		}
+    	}
+
+	return (NULL);
+}
+
+EXPORT_SYMBOL(cuio_copyback);
+EXPORT_SYMBOL(cuio_copydata);
+EXPORT_SYMBOL(cuio_getptr);
+
+static void
+skb_copy_bits_back(struct sk_buff *skb, int offset, caddr_t cp, int len)
+{
+	int i;
+	if (offset < skb_headlen(skb)) {
+		memcpy(skb->data + offset, cp, min_t(int, skb_headlen(skb), len));
+		len -= skb_headlen(skb);
+		cp += skb_headlen(skb);
+	}
+	offset -= skb_headlen(skb);
+	for (i = 0; len > 0 && i < skb_shinfo(skb)->nr_frags; i++) {
+		if (offset < skb_shinfo(skb)->frags[i].size) {
+			memcpy(page_address(skb_frag_page(&skb_shinfo(skb)->frags[i])) +
+					skb_shinfo(skb)->frags[i].page_offset,
+					cp, min_t(int, skb_shinfo(skb)->frags[i].size, len));
+			len -= skb_shinfo(skb)->frags[i].size;
+			cp += skb_shinfo(skb)->frags[i].size;
+		}
+		offset -= skb_shinfo(skb)->frags[i].size;
+	}
+}
+
+void
+crypto_copyback(int flags, caddr_t buf, int off, int size, caddr_t in)
+{
+
+	if ((flags & CRYPTO_F_SKBUF) != 0)
+		skb_copy_bits_back((struct sk_buff *)buf, off, in, size);
+	else if ((flags & CRYPTO_F_IOV) != 0)
+		cuio_copyback((struct uio *)buf, off, size, in);
+	else
+		bcopy(in, buf + off, size);
+}
+
+void
+crypto_copydata(int flags, caddr_t buf, int off, int size, caddr_t out)
+{
+
+	if ((flags & CRYPTO_F_SKBUF) != 0)
+		skb_copy_bits((struct sk_buff *)buf, off, out, size);
+	else if ((flags & CRYPTO_F_IOV) != 0)
+		cuio_copydata((struct uio *)buf, off, size, out);
+	else
+		bcopy(buf + off, out, size);
+}
+
+int
+crypto_apply(int flags, caddr_t buf, int off, int len,
+    int (*f)(void *, void *, u_int), void *arg)
+{
+#if 0
+	int error;
+
+	if ((flags & CRYPTO_F_SKBUF) != 0)
+		error = XXXXXX((struct mbuf *)buf, off, len, f, arg);
+	else if ((flags & CRYPTO_F_IOV) != 0)
+		error = cuio_apply((struct uio *)buf, off, len, f, arg);
+	else
+		error = (*f)(arg, buf + off, len);
+	return (error);
+#else
+	KASSERT(0, ("crypto_apply not implemented!\n"));
+#endif
+	return 0;
+}
+
+EXPORT_SYMBOL(crypto_copyback);
+EXPORT_SYMBOL(crypto_copydata);
+EXPORT_SYMBOL(crypto_apply);
+
diff --git a/crypto/ocf/crypto.c b/crypto/ocf/crypto.c
new file mode 100644
index 0000000..7722361
--- /dev/null
+++ b/crypto/ocf/crypto.c
@@ -0,0 +1,1766 @@
+/*-
+ * Linux port done by David McCullough <david_mccullough@mcafee.com>
+ * Copyright (C) 2006-2010 David McCullough
+ * Copyright (C) 2004-2005 Intel Corporation.
+ * The license and original author are listed below.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * Copyright (c) 2002-2006 Sam Leffler.  All rights reserved.
+ *
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if 0
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/opencrypto/crypto.c,v 1.27 2007/03/21 03:42:51 sam Exp $");
+#endif
+
+/*
+ * Cryptographic Subsystem.
+ *
+ * This code is derived from the Openbsd Cryptographic Framework (OCF)
+ * that has the copyright shown below.  Very little of the original
+ * code remains.
+ */
+/*-
+ * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
+ *
+ * This code was written by Angelos D. Keromytis in Athens, Greece, in
+ * February 2000. Network Security Technologies Inc. (NSTI) kindly
+ * supported the development of this code.
+ *
+ * Copyright (c) 2000, 2001 Angelos D. Keromytis
+ *
+ * Permission to use, copy, and modify this software with or without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all source code copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+__FBSDID("$FreeBSD: src/sys/opencrypto/crypto.c,v 1.16 2005/01/07 02:29:16 imp Exp $");
+ */
+
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED)
+#include <linux/config.h>
+#endif
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,4)
+#include <linux/kthread.h>
+#endif
+#include <cryptodev.h>
+
+/*
+ * keep track of whether or not we have been initialised, a big
+ * issue if we are linked into the kernel and a driver gets started before
+ * us
+ */
+static int crypto_initted = 0;
+
+/*
+ * Crypto drivers register themselves by allocating a slot in the
+ * crypto_drivers table with crypto_get_driverid() and then registering
+ * each algorithm they support with crypto_register() and crypto_kregister().
+ */
+
+/*
+ * lock on driver table
+ * we track its state as spin_is_locked does not do anything on non-SMP boxes
+ */
+static spinlock_t	crypto_drivers_lock;
+static int			crypto_drivers_locked;		/* for non-SMP boxes */
+
+#define	CRYPTO_DRIVER_LOCK() \
+			({ \
+				spin_lock_irqsave(&crypto_drivers_lock, d_flags); \
+			 	crypto_drivers_locked = 1; \
+				dprintk("%s,%d: DRIVER_LOCK()\n", __FILE__, __LINE__); \
+			 })
+#define	CRYPTO_DRIVER_UNLOCK() \
+			({ \
+			 	dprintk("%s,%d: DRIVER_UNLOCK()\n", __FILE__, __LINE__); \
+			 	crypto_drivers_locked = 0; \
+				spin_unlock_irqrestore(&crypto_drivers_lock, d_flags); \
+			 })
+#define	CRYPTO_DRIVER_ASSERT() \
+			({ \
+			 	if (!crypto_drivers_locked) { \
+					dprintk("%s,%d: DRIVER_ASSERT!\n", __FILE__, __LINE__); \
+			 	} \
+			 })
+
+/*
+ * Crypto device/driver capabilities structure.
+ *
+ * Synchronization:
+ * (d) - protected by CRYPTO_DRIVER_LOCK()
+ * (q) - protected by CRYPTO_Q_LOCK()
+ * Not tagged fields are read-only.
+ */
+struct cryptocap {
+	device_t	cc_dev;			/* (d) device/driver */
+	u_int32_t	cc_sessions;		/* (d) # of sessions */
+	u_int32_t	cc_koperations;		/* (d) # os asym operations */
+	/*
+	 * Largest possible operator length (in bits) for each type of
+	 * encryption algorithm. XXX not used
+	 */
+	u_int16_t	cc_max_op_len[CRYPTO_ALGORITHM_MAX + 1];
+	u_int8_t	cc_alg[CRYPTO_ALGORITHM_MAX + 1];
+	u_int8_t	cc_kalg[CRK_ALGORITHM_MAX + 1];
+
+	int		cc_flags;		/* (d) flags */
+#define CRYPTOCAP_F_CLEANUP	0x80000000	/* needs resource cleanup */
+	int		cc_qblocked;		/* (q) symmetric q blocked */
+	int		cc_kqblocked;		/* (q) asymmetric q blocked */
+
+	int		cc_unqblocked;		/* (q) symmetric q blocked */
+	int		cc_unkqblocked;		/* (q) asymmetric q blocked */
+};
+static struct cryptocap *crypto_drivers = NULL;
+static int crypto_drivers_num = 0;
+
+/*
+ * There are two queues for crypto requests; one for symmetric (e.g.
+ * cipher) operations and one for asymmetric (e.g. MOD)operations.
+ * A single mutex is used to lock access to both queues.  We could
+ * have one per-queue but having one simplifies handling of block/unblock
+ * operations.
+ */
+static LIST_HEAD(crp_q);		/* crypto request queue */
+static LIST_HEAD(crp_kq);		/* asym request queue */
+
+static spinlock_t crypto_q_lock;
+
+int crypto_all_qblocked = 0;  /* protect with Q_LOCK */
+module_param(crypto_all_qblocked, int, 0444);
+MODULE_PARM_DESC(crypto_all_qblocked, "Are all crypto queues blocked");
+
+int crypto_all_kqblocked = 0; /* protect with Q_LOCK */
+module_param(crypto_all_kqblocked, int, 0444);
+MODULE_PARM_DESC(crypto_all_kqblocked, "Are all asym crypto queues blocked");
+
+#define	CRYPTO_Q_LOCK() \
+			({ \
+				spin_lock_irqsave(&crypto_q_lock, q_flags); \
+			 	dprintk("%s,%d: Q_LOCK()\n", __FILE__, __LINE__); \
+			 })
+#define	CRYPTO_Q_UNLOCK() \
+			({ \
+			 	dprintk("%s,%d: Q_UNLOCK()\n", __FILE__, __LINE__); \
+				spin_unlock_irqrestore(&crypto_q_lock, q_flags); \
+			 })
+
+/*
+ * There are two queues for processing completed crypto requests; one
+ * for the symmetric and one for the asymmetric ops.  We only need one
+ * but have two to avoid type futzing (cryptop vs. cryptkop).  A single
+ * mutex is used to lock access to both queues.  Note that this lock
+ * must be separate from the lock on request queues to insure driver
+ * callbacks don't generate lock order reversals.
+ */
+static LIST_HEAD(crp_ret_q);		/* callback queues */
+static LIST_HEAD(crp_ret_kq);
+
+static spinlock_t crypto_ret_q_lock;
+#define	CRYPTO_RETQ_LOCK() \
+			({ \
+				spin_lock_irqsave(&crypto_ret_q_lock, r_flags); \
+				dprintk("%s,%d: RETQ_LOCK\n", __FILE__, __LINE__); \
+			 })
+#define	CRYPTO_RETQ_UNLOCK() \
+			({ \
+			 	dprintk("%s,%d: RETQ_UNLOCK\n", __FILE__, __LINE__); \
+				spin_unlock_irqrestore(&crypto_ret_q_lock, r_flags); \
+			 })
+#define	CRYPTO_RETQ_EMPTY()	(list_empty(&crp_ret_q) && list_empty(&crp_ret_kq))
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+static kmem_cache_t *cryptop_zone;
+static kmem_cache_t *cryptodesc_zone;
+#else
+static struct kmem_cache *cryptop_zone;
+static struct kmem_cache *cryptodesc_zone;
+#endif
+
+#define debug crypto_debug
+int crypto_debug = 0;
+module_param(crypto_debug, int, 0644);
+MODULE_PARM_DESC(crypto_debug, "Enable debug");
+EXPORT_SYMBOL(crypto_debug);
+
+/*
+ * Maximum number of outstanding crypto requests before we start
+ * failing requests.  We need this to prevent DOS when too many
+ * requests are arriving for us to keep up.  Otherwise we will
+ * run the system out of memory.  Since crypto is slow,  we are
+ * usually the bottleneck that needs to say, enough is enough.
+ *
+ * We cannot print errors when this condition occurs,  we are already too
+ * slow,  printing anything will just kill us
+ */
+
+static int crypto_q_cnt = 0;
+module_param(crypto_q_cnt, int, 0444);
+MODULE_PARM_DESC(crypto_q_cnt,
+		"Current number of outstanding crypto requests");
+
+static int crypto_q_max = 1000;
+module_param(crypto_q_max, int, 0644);
+MODULE_PARM_DESC(crypto_q_max,
+		"Maximum number of outstanding crypto requests");
+
+#define bootverbose crypto_verbose
+static int crypto_verbose = 0;
+module_param(crypto_verbose, int, 0644);
+MODULE_PARM_DESC(crypto_verbose,
+		"Enable verbose crypto startup");
+
+int	crypto_usercrypto = 1;	/* userland may do crypto reqs */
+module_param(crypto_usercrypto, int, 0644);
+MODULE_PARM_DESC(crypto_usercrypto,
+	   "Enable/disable user-mode access to crypto support");
+
+int	crypto_userasymcrypto = 1;	/* userland may do asym crypto reqs */
+module_param(crypto_userasymcrypto, int, 0644);
+MODULE_PARM_DESC(crypto_userasymcrypto,
+	   "Enable/disable user-mode access to asymmetric crypto support");
+
+int	crypto_devallowsoft = 0;	/* only use hardware crypto */
+module_param(crypto_devallowsoft, int, 0644);
+MODULE_PARM_DESC(crypto_devallowsoft,
+	   "Enable/disable use of software crypto support");
+
+/*
+ * This parameter controls the maximum number of crypto operations to 
+ * do consecutively in the crypto kernel thread before scheduling to allow 
+ * other processes to run. Without it, it is possible to get into a 
+ * situation where the crypto thread never allows any other processes to run.
+ * Default to 1000 which should be less than one second.
+ */
+static int crypto_max_loopcount = 1000;
+module_param(crypto_max_loopcount, int, 0644);
+MODULE_PARM_DESC(crypto_max_loopcount,
+	   "Maximum number of crypto ops to do before yielding to other processes");
+
+#ifndef CONFIG_NR_CPUS
+#define CONFIG_NR_CPUS 1
+#endif
+
+static struct task_struct *cryptoproc[CONFIG_NR_CPUS];
+static struct task_struct *cryptoretproc[CONFIG_NR_CPUS];
+static DECLARE_WAIT_QUEUE_HEAD(cryptoproc_wait);
+static DECLARE_WAIT_QUEUE_HEAD(cryptoretproc_wait);
+
+static	int crypto_proc(void *arg);
+static	int crypto_ret_proc(void *arg);
+static	int crypto_invoke(struct cryptocap *cap, struct cryptop *crp, int hint);
+static	int crypto_kinvoke(struct cryptkop *krp, int flags);
+static	void crypto_exit(void);
+static  int crypto_init(void);
+
+static	struct cryptostats cryptostats;
+
+static struct cryptocap *
+crypto_checkdriver(u_int32_t hid)
+{
+	if (crypto_drivers == NULL)
+		return NULL;
+	return (hid >= crypto_drivers_num ? NULL : &crypto_drivers[hid]);
+}
+
+/*
+ * Compare a driver's list of supported algorithms against another
+ * list; return non-zero if all algorithms are supported.
+ */
+static int
+driver_suitable(const struct cryptocap *cap, const struct cryptoini *cri)
+{
+	const struct cryptoini *cr;
+
+	/* See if all the algorithms are supported. */
+	for (cr = cri; cr; cr = cr->cri_next)
+		if (cap->cc_alg[cr->cri_alg] == 0)
+			return 0;
+	return 1;
+}
+
+
+/*
+ * Select a driver for a new session that supports the specified
+ * algorithms and, optionally, is constrained according to the flags.
+ * The algorithm we use here is pretty stupid; just use the
+ * first driver that supports all the algorithms we need. If there
+ * are multiple drivers we choose the driver with the fewest active
+ * sessions.  We prefer hardware-backed drivers to software ones.
+ *
+ * XXX We need more smarts here (in real life too, but that's
+ * XXX another story altogether).
+ */
+static struct cryptocap *
+crypto_select_driver(const struct cryptoini *cri, int flags)
+{
+	struct cryptocap *cap, *best;
+	int match, hid;
+
+	CRYPTO_DRIVER_ASSERT();
+
+	/*
+	 * Look first for hardware crypto devices if permitted.
+	 */
+	if (flags & CRYPTOCAP_F_HARDWARE)
+		match = CRYPTOCAP_F_HARDWARE;
+	else
+		match = CRYPTOCAP_F_SOFTWARE;
+	best = NULL;
+again:
+	for (hid = 0; hid < crypto_drivers_num; hid++) {
+		cap = &crypto_drivers[hid];
+		/*
+		 * If it's not initialized, is in the process of
+		 * going away, or is not appropriate (hardware
+		 * or software based on match), then skip.
+		 */
+		if (cap->cc_dev == NULL ||
+		    (cap->cc_flags & CRYPTOCAP_F_CLEANUP) ||
+		    (cap->cc_flags & match) == 0)
+			continue;
+
+		/* verify all the algorithms are supported. */
+		if (driver_suitable(cap, cri)) {
+			if (best == NULL ||
+			    cap->cc_sessions < best->cc_sessions)
+				best = cap;
+		}
+	}
+	if (best != NULL)
+		return best;
+	if (match == CRYPTOCAP_F_HARDWARE && (flags & CRYPTOCAP_F_SOFTWARE)) {
+		/* sort of an Algol 68-style for loop */
+		match = CRYPTOCAP_F_SOFTWARE;
+		goto again;
+	}
+	return best;
+}
+
+/*
+ * Create a new session.  The crid argument specifies a crypto
+ * driver to use or constraints on a driver to select (hardware
+ * only, software only, either).  Whatever driver is selected
+ * must be capable of the requested crypto algorithms.
+ */
+int
+crypto_newsession(u_int64_t *sid, struct cryptoini *cri, int crid)
+{
+	struct cryptocap *cap;
+	u_int32_t hid, lid;
+	int err;
+	unsigned long d_flags;
+
+	CRYPTO_DRIVER_LOCK();
+	if ((crid & (CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE)) == 0) {
+		/*
+		 * Use specified driver; verify it is capable.
+		 */
+		cap = crypto_checkdriver(crid);
+		if (cap != NULL && !driver_suitable(cap, cri))
+			cap = NULL;
+	} else {
+		/*
+		 * No requested driver; select based on crid flags.
+		 */
+		cap = crypto_select_driver(cri, crid);
+		/*
+		 * if NULL then can't do everything in one session.
+		 * XXX Fix this. We need to inject a "virtual" session
+		 * XXX layer right about here.
+		 */
+	}
+	if (cap != NULL) {
+		/* Call the driver initialization routine. */
+		hid = cap - crypto_drivers;
+		lid = hid;		/* Pass the driver ID. */
+		cap->cc_sessions++;
+		CRYPTO_DRIVER_UNLOCK();
+		err = CRYPTODEV_NEWSESSION(cap->cc_dev, &lid, cri);
+		CRYPTO_DRIVER_LOCK();
+		if (err == 0) {
+			(*sid) = (cap->cc_flags & 0xff000000)
+			       | (hid & 0x00ffffff);
+			(*sid) <<= 32;
+			(*sid) |= (lid & 0xffffffff);
+		} else
+			cap->cc_sessions--;
+	} else
+		err = EINVAL;
+	CRYPTO_DRIVER_UNLOCK();
+	return err;
+}
+
+static void
+crypto_remove(struct cryptocap *cap)
+{
+	CRYPTO_DRIVER_ASSERT();
+	if (cap->cc_sessions == 0 && cap->cc_koperations == 0)
+		bzero(cap, sizeof(*cap));
+}
+
+/*
+ * Delete an existing session (or a reserved session on an unregistered
+ * driver).
+ */
+int
+crypto_freesession(u_int64_t sid)
+{
+	struct cryptocap *cap;
+	u_int32_t hid;
+	int err = 0;
+	unsigned long d_flags;
+
+	dprintk("%s()\n", __FUNCTION__);
+	CRYPTO_DRIVER_LOCK();
+
+	if (crypto_drivers == NULL) {
+		err = EINVAL;
+		goto done;
+	}
+
+	/* Determine two IDs. */
+	hid = CRYPTO_SESID2HID(sid);
+
+	if (hid >= crypto_drivers_num) {
+		dprintk("%s - INVALID DRIVER NUM %d\n", __FUNCTION__, hid);
+		err = ENOENT;
+		goto done;
+	}
+	cap = &crypto_drivers[hid];
+
+	if (cap->cc_dev) {
+		CRYPTO_DRIVER_UNLOCK();
+		/* Call the driver cleanup routine, if available, unlocked. */
+		err = CRYPTODEV_FREESESSION(cap->cc_dev, sid);
+		CRYPTO_DRIVER_LOCK();
+	}
+
+	if (cap->cc_sessions)
+		cap->cc_sessions--;
+
+	if (cap->cc_flags & CRYPTOCAP_F_CLEANUP)
+		crypto_remove(cap);
+
+done:
+	CRYPTO_DRIVER_UNLOCK();
+	return err;
+}
+
+/*
+ * Return an unused driver id.  Used by drivers prior to registering
+ * support for the algorithms they handle.
+ */
+int32_t
+crypto_get_driverid(device_t dev, int flags)
+{
+	struct cryptocap *newdrv;
+	int i;
+	unsigned long d_flags;
+
+	if ((flags & (CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE)) == 0) {
+		printf("%s: no flags specified when registering driver\n",
+		    device_get_nameunit(dev));
+		return -1;
+	}
+
+	CRYPTO_DRIVER_LOCK();
+
+	for (i = 0; i < crypto_drivers_num; i++) {
+		if (crypto_drivers[i].cc_dev == NULL &&
+		    (crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP) == 0) {
+			break;
+		}
+	}
+
+	/* Out of entries, allocate some more. */
+	if (i == crypto_drivers_num) {
+		/* Be careful about wrap-around. */
+		if (2 * crypto_drivers_num <= crypto_drivers_num) {
+			CRYPTO_DRIVER_UNLOCK();
+			printk("crypto: driver count wraparound!\n");
+			return -1;
+		}
+
+		newdrv = kmalloc(2 * crypto_drivers_num * sizeof(struct cryptocap),
+				GFP_KERNEL);
+		if (newdrv == NULL) {
+			CRYPTO_DRIVER_UNLOCK();
+			printk("crypto: no space to expand driver table!\n");
+			return -1;
+		}
+
+		memcpy(newdrv, crypto_drivers,
+				crypto_drivers_num * sizeof(struct cryptocap));
+		memset(&newdrv[crypto_drivers_num], 0,
+				crypto_drivers_num * sizeof(struct cryptocap));
+
+		crypto_drivers_num *= 2;
+
+		kfree(crypto_drivers);
+		crypto_drivers = newdrv;
+	}
+
+	/* NB: state is zero'd on free */
+	crypto_drivers[i].cc_sessions = 1;	/* Mark */
+	crypto_drivers[i].cc_dev = dev;
+	crypto_drivers[i].cc_flags = flags;
+	if (bootverbose)
+		printf("crypto: assign %s driver id %u, flags %u\n",
+		    device_get_nameunit(dev), i, flags);
+
+	CRYPTO_DRIVER_UNLOCK();
+
+	return i;
+}
+
+/*
+ * Lookup a driver by name.  We match against the full device
+ * name and unit, and against just the name.  The latter gives
+ * us a simple widlcarding by device name.  On success return the
+ * driver/hardware identifier; otherwise return -1.
+ */
+int
+crypto_find_driver(const char *match)
+{
+	int i, len = strlen(match);
+	unsigned long d_flags;
+
+	CRYPTO_DRIVER_LOCK();
+	for (i = 0; i < crypto_drivers_num; i++) {
+		device_t dev = crypto_drivers[i].cc_dev;
+		if (dev == NULL ||
+		    (crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP))
+			continue;
+		if (strncmp(match, device_get_nameunit(dev), len) == 0 ||
+		    strncmp(match, device_get_name(dev), len) == 0)
+			break;
+	}
+	CRYPTO_DRIVER_UNLOCK();
+	return i < crypto_drivers_num ? i : -1;
+}
+
+/*
+ * Return the device_t for the specified driver or NULL
+ * if the driver identifier is invalid.
+ */
+device_t
+crypto_find_device_byhid(int hid)
+{
+	struct cryptocap *cap = crypto_checkdriver(hid);
+	return cap != NULL ? cap->cc_dev : NULL;
+}
+
+/*
+ * Return the device/driver capabilities.
+ */
+int
+crypto_getcaps(int hid)
+{
+	struct cryptocap *cap = crypto_checkdriver(hid);
+	return cap != NULL ? cap->cc_flags : 0;
+}
+
+/*
+ * Register support for a key-related algorithm.  This routine
+ * is called once for each algorithm supported a driver.
+ */
+int
+crypto_kregister(u_int32_t driverid, int kalg, u_int32_t flags)
+{
+	struct cryptocap *cap;
+	int err;
+	unsigned long d_flags;
+
+	dprintk("%s()\n", __FUNCTION__);
+	CRYPTO_DRIVER_LOCK();
+
+	cap = crypto_checkdriver(driverid);
+	if (cap != NULL &&
+	    (CRK_ALGORITM_MIN <= kalg && kalg <= CRK_ALGORITHM_MAX)) {
+		/*
+		 * XXX Do some performance testing to determine placing.
+		 * XXX We probably need an auxiliary data structure that
+		 * XXX describes relative performances.
+		 */
+
+		cap->cc_kalg[kalg] = flags | CRYPTO_ALG_FLAG_SUPPORTED;
+		if (bootverbose)
+			printf("crypto: %s registers key alg %u flags %u\n"
+				, device_get_nameunit(cap->cc_dev)
+				, kalg
+				, flags
+			);
+		err = 0;
+	} else
+		err = EINVAL;
+
+	CRYPTO_DRIVER_UNLOCK();
+	return err;
+}
+
+/*
+ * Register support for a non-key-related algorithm.  This routine
+ * is called once for each such algorithm supported by a driver.
+ */
+int
+crypto_register(u_int32_t driverid, int alg, u_int16_t maxoplen,
+    u_int32_t flags)
+{
+	struct cryptocap *cap;
+	int err;
+	unsigned long d_flags;
+
+	dprintk("%s(id=0x%x, alg=%d, maxoplen=%d, flags=0x%x)\n", __FUNCTION__,
+			driverid, alg, maxoplen, flags);
+
+	CRYPTO_DRIVER_LOCK();
+
+	cap = crypto_checkdriver(driverid);
+	/* NB: algorithms are in the range [1..max] */
+	if (cap != NULL &&
+	    (CRYPTO_ALGORITHM_MIN <= alg && alg <= CRYPTO_ALGORITHM_MAX)) {
+		/*
+		 * XXX Do some performance testing to determine placing.
+		 * XXX We probably need an auxiliary data structure that
+		 * XXX describes relative performances.
+		 */
+
+		cap->cc_alg[alg] = flags | CRYPTO_ALG_FLAG_SUPPORTED;
+		cap->cc_max_op_len[alg] = maxoplen;
+		if (bootverbose)
+			printf("crypto: %s registers alg %u flags %u maxoplen %u\n"
+				, device_get_nameunit(cap->cc_dev)
+				, alg
+				, flags
+				, maxoplen
+			);
+		cap->cc_sessions = 0;		/* Unmark */
+		err = 0;
+	} else
+		err = EINVAL;
+
+	CRYPTO_DRIVER_UNLOCK();
+	return err;
+}
+
+static void
+driver_finis(struct cryptocap *cap)
+{
+	u_int32_t ses, kops;
+
+	CRYPTO_DRIVER_ASSERT();
+
+	ses = cap->cc_sessions;
+	kops = cap->cc_koperations;
+	bzero(cap, sizeof(*cap));
+	if (ses != 0 || kops != 0) {
+		/*
+		 * If there are pending sessions,
+		 * just mark as invalid.
+		 */
+		cap->cc_flags |= CRYPTOCAP_F_CLEANUP;
+		cap->cc_sessions = ses;
+		cap->cc_koperations = kops;
+	}
+}
+
+/*
+ * Unregister a crypto driver. If there are pending sessions using it,
+ * leave enough information around so that subsequent calls using those
+ * sessions will correctly detect the driver has been unregistered and
+ * reroute requests.
+ */
+int
+crypto_unregister(u_int32_t driverid, int alg)
+{
+	struct cryptocap *cap;
+	int i, err;
+	unsigned long d_flags;
+
+	dprintk("%s()\n", __FUNCTION__);
+	CRYPTO_DRIVER_LOCK();
+
+	cap = crypto_checkdriver(driverid);
+	if (cap != NULL &&
+	    (CRYPTO_ALGORITHM_MIN <= alg && alg <= CRYPTO_ALGORITHM_MAX) &&
+	    cap->cc_alg[alg] != 0) {
+		cap->cc_alg[alg] = 0;
+		cap->cc_max_op_len[alg] = 0;
+
+		/* Was this the last algorithm ? */
+		for (i = 1; i <= CRYPTO_ALGORITHM_MAX; i++)
+			if (cap->cc_alg[i] != 0)
+				break;
+
+		if (i == CRYPTO_ALGORITHM_MAX + 1)
+			driver_finis(cap);
+		err = 0;
+	} else
+		err = EINVAL;
+	CRYPTO_DRIVER_UNLOCK();
+	return err;
+}
+
+/*
+ * Unregister all algorithms associated with a crypto driver.
+ * If there are pending sessions using it, leave enough information
+ * around so that subsequent calls using those sessions will
+ * correctly detect the driver has been unregistered and reroute
+ * requests.
+ */
+int
+crypto_unregister_all(u_int32_t driverid)
+{
+	struct cryptocap *cap;
+	int err;
+	unsigned long d_flags;
+
+	dprintk("%s()\n", __FUNCTION__);
+	CRYPTO_DRIVER_LOCK();
+	cap = crypto_checkdriver(driverid);
+	if (cap != NULL) {
+		driver_finis(cap);
+		err = 0;
+	} else
+		err = EINVAL;
+	CRYPTO_DRIVER_UNLOCK();
+
+	return err;
+}
+
+/*
+ * Clear blockage on a driver.  The what parameter indicates whether
+ * the driver is now ready for cryptop's and/or cryptokop's.
+ */
+int
+crypto_unblock(u_int32_t driverid, int what)
+{
+	struct cryptocap *cap;
+	int err;
+	unsigned long q_flags;
+
+	CRYPTO_Q_LOCK();
+	cap = crypto_checkdriver(driverid);
+	if (cap != NULL) {
+		if (what & CRYPTO_SYMQ) {
+			cap->cc_qblocked = 0;
+			cap->cc_unqblocked = 0;
+			crypto_all_qblocked = 0;
+		}
+		if (what & CRYPTO_ASYMQ) {
+			cap->cc_kqblocked = 0;
+			cap->cc_unkqblocked = 0;
+			crypto_all_kqblocked = 0;
+		}
+		wake_up_interruptible(&cryptoproc_wait);
+		err = 0;
+	} else
+		err = EINVAL;
+	CRYPTO_Q_UNLOCK(); //DAVIDM should this be a driver lock
+
+	return err;
+}
+
+/*
+ * Add a crypto request to a queue, to be processed by the kernel thread.
+ */
+int
+crypto_dispatch(struct cryptop *crp)
+{
+	struct cryptocap *cap;
+	int result = -1;
+	unsigned long q_flags;
+
+	dprintk("%s()\n", __FUNCTION__);
+
+	cryptostats.cs_ops++;
+
+	CRYPTO_Q_LOCK();
+	/*if (crypto_q_cnt >= crypto_q_max) {
+		cryptostats.cs_drops++;
+		CRYPTO_Q_UNLOCK();
+		return ENOMEM;
+	}*/
+	crypto_q_cnt++;
+
+	/* make sure we are starting a fresh run on this crp. */
+	crp->crp_flags &= ~CRYPTO_F_DONE;
+	crp->crp_etype = 0;
+
+	/*
+	 * Caller marked the request to be processed immediately; dispatch
+	 * it directly to the driver unless the driver is currently blocked.
+	 */
+	if ((crp->crp_flags & CRYPTO_F_BATCH) == 0) {
+		int hid = CRYPTO_SESID2HID(crp->crp_sid);
+		cap = crypto_checkdriver(hid);
+		/* Driver cannot disappear when there is an active session. */
+		KASSERT(cap != NULL, ("%s: Driver disappeared.", __func__));
+		if (!cap->cc_qblocked) {
+			crypto_all_qblocked = 0;
+			crypto_drivers[hid].cc_unqblocked = 1;
+			CRYPTO_Q_UNLOCK();
+			result = crypto_invoke(cap, crp, 0);
+			CRYPTO_Q_LOCK();
+			if (result == ERESTART)
+				if (crypto_drivers[hid].cc_unqblocked)
+					crypto_drivers[hid].cc_qblocked = 1;
+			crypto_drivers[hid].cc_unqblocked = 0;
+		}
+	}
+	if (result == ERESTART) {
+		/*
+		 * The driver ran out of resources, mark the
+		 * driver ``blocked'' for cryptop's and put
+		 * the request back in the queue.  It would
+		 * best to put the request back where we got
+		 * it but that's hard so for now we put it
+		 * at the front.  This should be ok; putting
+		 * it at the end does not work.
+		 */
+		list_add(&crp->crp_next, &crp_q);
+		cryptostats.cs_blocks++;
+		result = 0;
+	} else if (result == -1) {
+		TAILQ_INSERT_TAIL(&crp_q, crp, crp_next);
+		result = 0;
+	}
+	wake_up_interruptible(&cryptoproc_wait);
+	CRYPTO_Q_UNLOCK();
+	return result;
+}
+
+/*
+ * Add an asymetric crypto request to a queue,
+ * to be processed by the kernel thread.
+ */
+int
+crypto_kdispatch(struct cryptkop *krp)
+{
+	int error;
+	unsigned long q_flags;
+
+	cryptostats.cs_kops++;
+
+	error = crypto_kinvoke(krp, krp->krp_crid);
+	if (error == ERESTART) {
+		CRYPTO_Q_LOCK();
+		TAILQ_INSERT_TAIL(&crp_kq, krp, krp_next);
+		wake_up_interruptible(&cryptoproc_wait);
+		CRYPTO_Q_UNLOCK();
+		error = 0;
+	}
+	return error;
+}
+
+/*
+ * Verify a driver is suitable for the specified operation.
+ */
+static __inline int
+kdriver_suitable(const struct cryptocap *cap, const struct cryptkop *krp)
+{
+	return (cap->cc_kalg[krp->krp_op] & CRYPTO_ALG_FLAG_SUPPORTED) != 0;
+}
+
+/*
+ * Select a driver for an asym operation.  The driver must
+ * support the necessary algorithm.  The caller can constrain
+ * which device is selected with the flags parameter.  The
+ * algorithm we use here is pretty stupid; just use the first
+ * driver that supports the algorithms we need. If there are
+ * multiple suitable drivers we choose the driver with the
+ * fewest active operations.  We prefer hardware-backed
+ * drivers to software ones when either may be used.
+ */
+static struct cryptocap *
+crypto_select_kdriver(const struct cryptkop *krp, int flags)
+{
+	struct cryptocap *cap, *best, *blocked;
+	int match, hid;
+
+	CRYPTO_DRIVER_ASSERT();
+
+	/*
+	 * Look first for hardware crypto devices if permitted.
+	 */
+	if (flags & CRYPTOCAP_F_HARDWARE)
+		match = CRYPTOCAP_F_HARDWARE;
+	else
+		match = CRYPTOCAP_F_SOFTWARE;
+	best = NULL;
+	blocked = NULL;
+again:
+	for (hid = 0; hid < crypto_drivers_num; hid++) {
+		cap = &crypto_drivers[hid];
+		/*
+		 * If it's not initialized, is in the process of
+		 * going away, or is not appropriate (hardware
+		 * or software based on match), then skip.
+		 */
+		if (cap->cc_dev == NULL ||
+		    (cap->cc_flags & CRYPTOCAP_F_CLEANUP) ||
+		    (cap->cc_flags & match) == 0)
+			continue;
+
+		/* verify all the algorithms are supported. */
+		if (kdriver_suitable(cap, krp)) {
+			if (best == NULL ||
+			    cap->cc_koperations < best->cc_koperations)
+				best = cap;
+		}
+	}
+	if (best != NULL)
+		return best;
+	if (match == CRYPTOCAP_F_HARDWARE && (flags & CRYPTOCAP_F_SOFTWARE)) {
+		/* sort of an Algol 68-style for loop */
+		match = CRYPTOCAP_F_SOFTWARE;
+		goto again;
+	}
+	return best;
+}
+
+/*
+ * Dispatch an assymetric crypto request.
+ */
+static int
+crypto_kinvoke(struct cryptkop *krp, int crid)
+{
+	struct cryptocap *cap = NULL;
+	int error;
+	unsigned long d_flags;
+
+	KASSERT(krp != NULL, ("%s: krp == NULL", __func__));
+	KASSERT(krp->krp_callback != NULL,
+	    ("%s: krp->crp_callback == NULL", __func__));
+
+	CRYPTO_DRIVER_LOCK();
+	if ((crid & (CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE)) == 0) {
+		cap = crypto_checkdriver(crid);
+		if (cap != NULL) {
+			/*
+			 * Driver present, it must support the necessary
+			 * algorithm and, if s/w drivers are excluded,
+			 * it must be registered as hardware-backed.
+			 */
+			if (!kdriver_suitable(cap, krp) ||
+			    (!crypto_devallowsoft &&
+			     (cap->cc_flags & CRYPTOCAP_F_HARDWARE) == 0))
+				cap = NULL;
+		}
+	} else {
+		/*
+		 * No requested driver; select based on crid flags.
+		 */
+		if (!crypto_devallowsoft)	/* NB: disallow s/w drivers */
+			crid &= ~CRYPTOCAP_F_SOFTWARE;
+		cap = crypto_select_kdriver(krp, crid);
+	}
+	if (cap != NULL && !cap->cc_kqblocked) {
+		krp->krp_hid = cap - crypto_drivers;
+		cap->cc_koperations++;
+		CRYPTO_DRIVER_UNLOCK();
+		error = CRYPTODEV_KPROCESS(cap->cc_dev, krp, 0);
+		CRYPTO_DRIVER_LOCK();
+		if (error == ERESTART) {
+			cap->cc_koperations--;
+			CRYPTO_DRIVER_UNLOCK();
+			return (error);
+		}
+		/* return the actual device used */
+		krp->krp_crid = krp->krp_hid;
+	} else {
+		/*
+		 * NB: cap is !NULL if device is blocked; in
+		 *     that case return ERESTART so the operation
+		 *     is resubmitted if possible.
+		 */
+		error = (cap == NULL) ? ENODEV : ERESTART;
+	}
+	CRYPTO_DRIVER_UNLOCK();
+
+	if (error) {
+		krp->krp_status = error;
+		crypto_kdone(krp);
+	}
+	return 0;
+}
+
+
+/*
+ * Dispatch a crypto request to the appropriate crypto devices.
+ */
+static int
+crypto_invoke(struct cryptocap *cap, struct cryptop *crp, int hint)
+{
+	KASSERT(crp != NULL, ("%s: crp == NULL", __func__));
+	KASSERT(crp->crp_callback != NULL,
+	    ("%s: crp->crp_callback == NULL", __func__));
+	KASSERT(crp->crp_desc != NULL, ("%s: crp->crp_desc == NULL", __func__));
+
+	dprintk("%s()\n", __FUNCTION__);
+
+#ifdef CRYPTO_TIMING
+	if (crypto_timing)
+		crypto_tstat(&cryptostats.cs_invoke, &crp->crp_tstamp);
+#endif
+	if (cap->cc_flags & CRYPTOCAP_F_CLEANUP) {
+		struct cryptodesc *crd;
+		u_int64_t nid;
+
+		/*
+		 * Driver has unregistered; migrate the session and return
+		 * an error to the caller so they'll resubmit the op.
+		 *
+		 * XXX: What if there are more already queued requests for this
+		 *      session?
+		 */
+		crypto_freesession(crp->crp_sid);
+
+		for (crd = crp->crp_desc; crd->crd_next; crd = crd->crd_next)
+			crd->CRD_INI.cri_next = &(crd->crd_next->CRD_INI);
+
+		/* XXX propagate flags from initial session? */
+		if (crypto_newsession(&nid, &(crp->crp_desc->CRD_INI),
+		    CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE) == 0)
+			crp->crp_sid = nid;
+
+		crp->crp_etype = EAGAIN;
+		crypto_done(crp);
+		return 0;
+	} else {
+		/*
+		 * Invoke the driver to process the request.
+		 */
+		return CRYPTODEV_PROCESS(cap->cc_dev, crp, hint);
+	}
+}
+
+/*
+ * Release a set of crypto descriptors.
+ */
+void
+crypto_freereq(struct cryptop *crp)
+{
+	struct cryptodesc *crd;
+
+	if (crp == NULL)
+		return;
+
+#ifdef DIAGNOSTIC
+	{
+		struct cryptop *crp2;
+		unsigned long q_flags;
+
+		CRYPTO_Q_LOCK();
+		TAILQ_FOREACH(crp2, &crp_q, crp_next) {
+			KASSERT(crp2 != crp,
+			    ("Freeing cryptop from the crypto queue (%p).",
+			    crp));
+		}
+		CRYPTO_Q_UNLOCK();
+		CRYPTO_RETQ_LOCK();
+		TAILQ_FOREACH(crp2, &crp_ret_q, crp_next) {
+			KASSERT(crp2 != crp,
+			    ("Freeing cryptop from the return queue (%p).",
+			    crp));
+		}
+		CRYPTO_RETQ_UNLOCK();
+	}
+#endif
+
+	while ((crd = crp->crp_desc) != NULL) {
+		crp->crp_desc = crd->crd_next;
+		kmem_cache_free(cryptodesc_zone, crd);
+	}
+	kmem_cache_free(cryptop_zone, crp);
+}
+
+/*
+ * Acquire a set of crypto descriptors.
+ */
+struct cryptop *
+crypto_getreq(int num)
+{
+	struct cryptodesc *crd;
+	struct cryptop *crp;
+
+	crp = kmem_cache_alloc(cryptop_zone, SLAB_ATOMIC);
+	if (crp != NULL) {
+		memset(crp, 0, sizeof(*crp));
+		INIT_LIST_HEAD(&crp->crp_next);
+		init_waitqueue_head(&crp->crp_waitq);
+		while (num--) {
+			crd = kmem_cache_alloc(cryptodesc_zone, SLAB_ATOMIC);
+			if (crd == NULL) {
+				crypto_freereq(crp);
+				return NULL;
+			}
+			memset(crd, 0, sizeof(*crd));
+			crd->crd_next = crp->crp_desc;
+			crp->crp_desc = crd;
+		}
+	}
+	return crp;
+}
+
+/*
+ * Invoke the callback on behalf of the driver.
+ */
+void
+crypto_done(struct cryptop *crp)
+{
+	unsigned long q_flags;
+
+	dprintk("%s()\n", __FUNCTION__);
+	if ((crp->crp_flags & CRYPTO_F_DONE) == 0) {
+		crp->crp_flags |= CRYPTO_F_DONE;
+		CRYPTO_Q_LOCK();
+		crypto_q_cnt--;
+		CRYPTO_Q_UNLOCK();
+	} else
+		printk("crypto: crypto_done op already done, flags 0x%x",
+				crp->crp_flags);
+	if (crp->crp_etype != 0)
+		cryptostats.cs_errs++;
+	/*
+	 * CBIMM means unconditionally do the callback immediately;
+	 * CBIFSYNC means do the callback immediately only if the
+	 * operation was done synchronously.  Both are used to avoid
+	 * doing extraneous context switches; the latter is mostly
+	 * used with the software crypto driver.
+	 */
+	if ((crp->crp_flags & CRYPTO_F_CBIMM) ||
+	    ((crp->crp_flags & CRYPTO_F_CBIFSYNC) &&
+	     (CRYPTO_SESID2CAPS(crp->crp_sid) & CRYPTOCAP_F_SYNC))) {
+		/*
+		 * Do the callback directly.  This is ok when the
+		 * callback routine does very little (e.g. the
+		 * /dev/crypto callback method just does a wakeup).
+		 */
+		crp->crp_callback(crp);
+	} else {
+		unsigned long r_flags;
+		/*
+		 * Normal case; queue the callback for the thread.
+		 */
+		CRYPTO_RETQ_LOCK();
+		wake_up_interruptible(&cryptoretproc_wait);/* shared wait channel */
+		TAILQ_INSERT_TAIL(&crp_ret_q, crp, crp_next);
+		CRYPTO_RETQ_UNLOCK();
+	}
+}
+
+/*
+ * Invoke the callback on behalf of the driver.
+ */
+void
+crypto_kdone(struct cryptkop *krp)
+{
+	struct cryptocap *cap;
+	unsigned long d_flags;
+
+	if ((krp->krp_flags & CRYPTO_KF_DONE) != 0)
+		printk("crypto: crypto_kdone op already done, flags 0x%x",
+				krp->krp_flags);
+	krp->krp_flags |= CRYPTO_KF_DONE;
+	if (krp->krp_status != 0)
+		cryptostats.cs_kerrs++;
+
+	CRYPTO_DRIVER_LOCK();
+	/* XXX: What if driver is loaded in the meantime? */
+	if (krp->krp_hid < crypto_drivers_num) {
+		cap = &crypto_drivers[krp->krp_hid];
+		cap->cc_koperations--;
+		KASSERT(cap->cc_koperations >= 0, ("cc_koperations < 0"));
+		if (cap->cc_flags & CRYPTOCAP_F_CLEANUP)
+			crypto_remove(cap);
+	}
+	CRYPTO_DRIVER_UNLOCK();
+
+	/*
+	 * CBIMM means unconditionally do the callback immediately;
+	 * This is used to avoid doing extraneous context switches
+	 */
+	if ((krp->krp_flags & CRYPTO_KF_CBIMM)) {
+		/*
+		 * Do the callback directly.  This is ok when the
+		 * callback routine does very little (e.g. the
+		 * /dev/crypto callback method just does a wakeup).
+		 */
+		krp->krp_callback(krp);
+	} else {
+		unsigned long r_flags;
+		/*
+		 * Normal case; queue the callback for the thread.
+		 */
+		CRYPTO_RETQ_LOCK();
+		wake_up_interruptible(&cryptoretproc_wait);/* shared wait channel */
+		TAILQ_INSERT_TAIL(&crp_ret_kq, krp, krp_next);
+		CRYPTO_RETQ_UNLOCK();
+	}
+}
+
+int
+crypto_getfeat(int *featp)
+{
+	int hid, kalg, feat = 0;
+	unsigned long d_flags;
+
+	CRYPTO_DRIVER_LOCK();
+	for (hid = 0; hid < crypto_drivers_num; hid++) {
+		const struct cryptocap *cap = &crypto_drivers[hid];
+
+		if ((cap->cc_flags & CRYPTOCAP_F_SOFTWARE) &&
+		    !crypto_devallowsoft) {
+			continue;
+		}
+		for (kalg = 0; kalg < CRK_ALGORITHM_MAX; kalg++)
+			if (cap->cc_kalg[kalg] & CRYPTO_ALG_FLAG_SUPPORTED)
+				feat |=  1 << kalg;
+	}
+	CRYPTO_DRIVER_UNLOCK();
+	*featp = feat;
+	return (0);
+}
+
+/*
+ * Crypto thread, dispatches crypto requests.
+ */
+static int
+crypto_proc(void *arg)
+{
+	struct cryptop *crp, *submit;
+	struct cryptkop *krp, *krpp;
+	struct cryptocap *cap;
+	u_int32_t hid;
+	int result, hint;
+	unsigned long q_flags;
+	int loopcount = 0;
+
+	set_current_state(TASK_INTERRUPTIBLE);
+
+	CRYPTO_Q_LOCK();
+	for (;;) {
+		/*
+		 * we need to make sure we don't get into a busy loop with nothing
+		 * to do,  the two crypto_all_*blocked vars help us find out when
+		 * we are all full and can do nothing on any driver or Q.  If so we
+		 * wait for an unblock.
+		 */
+		crypto_all_qblocked  = !list_empty(&crp_q);
+
+		/*
+		 * Find the first element in the queue that can be
+		 * processed and look-ahead to see if multiple ops
+		 * are ready for the same driver.
+		 */
+		submit = NULL;
+		hint = 0;
+		list_for_each_entry(crp, &crp_q, crp_next) {
+			hid = CRYPTO_SESID2HID(crp->crp_sid);
+			cap = crypto_checkdriver(hid);
+			/*
+			 * Driver cannot disappear when there is an active
+			 * session.
+			 */
+			KASSERT(cap != NULL, ("%s:%u Driver disappeared.",
+			    __func__, __LINE__));
+			if (cap == NULL || cap->cc_dev == NULL) {
+				/* Op needs to be migrated, process it. */
+				if (submit == NULL)
+					submit = crp;
+				break;
+			}
+			if (!cap->cc_qblocked) {
+				if (submit != NULL) {
+					/*
+					 * We stop on finding another op,
+					 * regardless whether its for the same
+					 * driver or not.  We could keep
+					 * searching the queue but it might be
+					 * better to just use a per-driver
+					 * queue instead.
+					 */
+					if (CRYPTO_SESID2HID(submit->crp_sid) == hid)
+						hint = CRYPTO_HINT_MORE;
+					break;
+				} else {
+					submit = crp;
+					if ((submit->crp_flags & CRYPTO_F_BATCH) == 0)
+						break;
+					/* keep scanning for more are q'd */
+				}
+			}
+		}
+		if (submit != NULL) {
+			hid = CRYPTO_SESID2HID(submit->crp_sid);
+			crypto_all_qblocked = 0;
+			list_del(&submit->crp_next);
+			crypto_drivers[hid].cc_unqblocked = 1;
+			cap = crypto_checkdriver(hid);
+			CRYPTO_Q_UNLOCK();
+			KASSERT(cap != NULL, ("%s:%u Driver disappeared.",
+			    __func__, __LINE__));
+			result = crypto_invoke(cap, submit, hint);
+			CRYPTO_Q_LOCK();
+			if (result == ERESTART) {
+				/*
+				 * The driver ran out of resources, mark the
+				 * driver ``blocked'' for cryptop's and put
+				 * the request back in the queue.  It would
+				 * best to put the request back where we got
+				 * it but that's hard so for now we put it
+				 * at the front.  This should be ok; putting
+				 * it at the end does not work.
+				 */
+				/* XXX validate sid again? */
+				list_add(&submit->crp_next, &crp_q);
+				cryptostats.cs_blocks++;
+				if (crypto_drivers[hid].cc_unqblocked)
+					crypto_drivers[hid].cc_qblocked=0;
+				crypto_drivers[hid].cc_unqblocked=0;
+			}
+			crypto_drivers[hid].cc_unqblocked = 0;
+		}
+
+		crypto_all_kqblocked = !list_empty(&crp_kq);
+
+		/* As above, but for key ops */
+		krp = NULL;
+		list_for_each_entry(krpp, &crp_kq, krp_next) {
+			cap = crypto_checkdriver(krpp->krp_hid);
+			if (cap == NULL || cap->cc_dev == NULL) {
+				/*
+				 * Operation needs to be migrated, invalidate
+				 * the assigned device so it will reselect a
+				 * new one below.  Propagate the original
+				 * crid selection flags if supplied.
+				 */
+				krp->krp_hid = krp->krp_crid &
+				    (CRYPTOCAP_F_SOFTWARE|CRYPTOCAP_F_HARDWARE);
+				if (krp->krp_hid == 0)
+					krp->krp_hid =
+				    CRYPTOCAP_F_SOFTWARE|CRYPTOCAP_F_HARDWARE;
+				break;
+			}
+			if (!cap->cc_kqblocked) {
+				krp = krpp;
+				break;
+			}
+		}
+		if (krp != NULL) {
+			crypto_all_kqblocked = 0;
+			list_del(&krp->krp_next);
+			crypto_drivers[krp->krp_hid].cc_kqblocked = 1;
+			CRYPTO_Q_UNLOCK();
+			result = crypto_kinvoke(krp, krp->krp_hid);
+			CRYPTO_Q_LOCK();
+			if (result == ERESTART) {
+				/*
+				 * The driver ran out of resources, mark the
+				 * driver ``blocked'' for cryptkop's and put
+				 * the request back in the queue.  It would
+				 * best to put the request back where we got
+				 * it but that's hard so for now we put it
+				 * at the front.  This should be ok; putting
+				 * it at the end does not work.
+				 */
+				/* XXX validate sid again? */
+				list_add(&krp->krp_next, &crp_kq);
+				cryptostats.cs_kblocks++;
+			} else
+				crypto_drivers[krp->krp_hid].cc_kqblocked = 0;
+		}
+
+		if (submit == NULL && krp == NULL) {
+			/*
+			 * Nothing more to be processed.  Sleep until we're
+			 * woken because there are more ops to process.
+			 * This happens either by submission or by a driver
+			 * becoming unblocked and notifying us through
+			 * crypto_unblock.  Note that when we wakeup we
+			 * start processing each queue again from the
+			 * front. It's not clear that it's important to
+			 * preserve this ordering since ops may finish
+			 * out of order if dispatched to different devices
+			 * and some become blocked while others do not.
+			 */
+			dprintk("%s - sleeping (qe=%d qb=%d kqe=%d kqb=%d)\n",
+					__FUNCTION__,
+					list_empty(&crp_q), crypto_all_qblocked,
+					list_empty(&crp_kq), crypto_all_kqblocked);
+			loopcount = 0;
+			CRYPTO_Q_UNLOCK();
+			wait_event_interruptible(cryptoproc_wait,
+					!(list_empty(&crp_q) || crypto_all_qblocked) ||
+					!(list_empty(&crp_kq) || crypto_all_kqblocked) ||
+					kthread_should_stop());
+			if (signal_pending (current)) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+				spin_lock_irq(&current->sigmask_lock);
+#endif
+				flush_signals(current);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+				spin_unlock_irq(&current->sigmask_lock);
+#endif
+			}
+			CRYPTO_Q_LOCK();
+			dprintk("%s - awake\n", __FUNCTION__);
+			if (kthread_should_stop())
+				break;
+			cryptostats.cs_intrs++;
+		} else if (loopcount > crypto_max_loopcount) {
+			/*
+			 * Give other processes a chance to run if we've 
+			 * been using the CPU exclusively for a while.
+			 */
+			loopcount = 0;
+			CRYPTO_Q_UNLOCK();
+			schedule();
+			CRYPTO_Q_LOCK();
+		}
+		loopcount++;
+	}
+	CRYPTO_Q_UNLOCK();
+	return 0;
+}
+
+/*
+ * Crypto returns thread, does callbacks for processed crypto requests.
+ * Callbacks are done here, rather than in the crypto drivers, because
+ * callbacks typically are expensive and would slow interrupt handling.
+ */
+static int
+crypto_ret_proc(void *arg)
+{
+	struct cryptop *crpt;
+	struct cryptkop *krpt;
+	unsigned long  r_flags;
+
+	set_current_state(TASK_INTERRUPTIBLE);
+
+	CRYPTO_RETQ_LOCK();
+	for (;;) {
+		/* Harvest return q's for completed ops */
+		crpt = NULL;
+		if (!list_empty(&crp_ret_q))
+			crpt = list_entry(crp_ret_q.next, typeof(*crpt), crp_next);
+		if (crpt != NULL)
+			list_del(&crpt->crp_next);
+
+		krpt = NULL;
+		if (!list_empty(&crp_ret_kq))
+			krpt = list_entry(crp_ret_kq.next, typeof(*krpt), krp_next);
+		if (krpt != NULL)
+			list_del(&krpt->krp_next);
+
+		if (crpt != NULL || krpt != NULL) {
+			CRYPTO_RETQ_UNLOCK();
+			/*
+			 * Run callbacks unlocked.
+			 */
+			if (crpt != NULL)
+				crpt->crp_callback(crpt);
+			if (krpt != NULL)
+				krpt->krp_callback(krpt);
+			CRYPTO_RETQ_LOCK();
+		} else {
+			/*
+			 * Nothing more to be processed.  Sleep until we're
+			 * woken because there are more returns to process.
+			 */
+			dprintk("%s - sleeping\n", __FUNCTION__);
+			CRYPTO_RETQ_UNLOCK();
+			wait_event_interruptible(cryptoretproc_wait,
+					!list_empty(&crp_ret_q) ||
+					!list_empty(&crp_ret_kq) ||
+					kthread_should_stop());
+			if (signal_pending (current)) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+				spin_lock_irq(&current->sigmask_lock);
+#endif
+				flush_signals(current);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+				spin_unlock_irq(&current->sigmask_lock);
+#endif
+			}
+			CRYPTO_RETQ_LOCK();
+			dprintk("%s - awake\n", __FUNCTION__);
+			if (kthread_should_stop()) {
+				dprintk("%s - EXITING!\n", __FUNCTION__);
+				break;
+			}
+			cryptostats.cs_rets++;
+		}
+	}
+	CRYPTO_RETQ_UNLOCK();
+	return 0;
+}
+
+
+#if 0 /* should put this into /proc or something */
+static void
+db_show_drivers(void)
+{
+	int hid;
+
+	db_printf("%12s %4s %4s %8s %2s %2s\n"
+		, "Device"
+		, "Ses"
+		, "Kops"
+		, "Flags"
+		, "QB"
+		, "KB"
+	);
+	for (hid = 0; hid < crypto_drivers_num; hid++) {
+		const struct cryptocap *cap = &crypto_drivers[hid];
+		if (cap->cc_dev == NULL)
+			continue;
+		db_printf("%-12s %4u %4u %08x %2u %2u\n"
+		    , device_get_nameunit(cap->cc_dev)
+		    , cap->cc_sessions
+		    , cap->cc_koperations
+		    , cap->cc_flags
+		    , cap->cc_qblocked
+		    , cap->cc_kqblocked
+		);
+	}
+}
+
+DB_SHOW_COMMAND(crypto, db_show_crypto)
+{
+	struct cryptop *crp;
+
+	db_show_drivers();
+	db_printf("\n");
+
+	db_printf("%4s %8s %4s %4s %4s %4s %8s %8s\n",
+	    "HID", "Caps", "Ilen", "Olen", "Etype", "Flags",
+	    "Desc", "Callback");
+	TAILQ_FOREACH(crp, &crp_q, crp_next) {
+		db_printf("%4u %08x %4u %4u %4u %04x %8p %8p\n"
+		    , (int) CRYPTO_SESID2HID(crp->crp_sid)
+		    , (int) CRYPTO_SESID2CAPS(crp->crp_sid)
+		    , crp->crp_ilen, crp->crp_olen
+		    , crp->crp_etype
+		    , crp->crp_flags
+		    , crp->crp_desc
+		    , crp->crp_callback
+		);
+	}
+	if (!TAILQ_EMPTY(&crp_ret_q)) {
+		db_printf("\n%4s %4s %4s %8s\n",
+		    "HID", "Etype", "Flags", "Callback");
+		TAILQ_FOREACH(crp, &crp_ret_q, crp_next) {
+			db_printf("%4u %4u %04x %8p\n"
+			    , (int) CRYPTO_SESID2HID(crp->crp_sid)
+			    , crp->crp_etype
+			    , crp->crp_flags
+			    , crp->crp_callback
+			);
+		}
+	}
+}
+
+DB_SHOW_COMMAND(kcrypto, db_show_kcrypto)
+{
+	struct cryptkop *krp;
+
+	db_show_drivers();
+	db_printf("\n");
+
+	db_printf("%4s %5s %4s %4s %8s %4s %8s\n",
+	    "Op", "Status", "#IP", "#OP", "CRID", "HID", "Callback");
+	TAILQ_FOREACH(krp, &crp_kq, krp_next) {
+		db_printf("%4u %5u %4u %4u %08x %4u %8p\n"
+		    , krp->krp_op
+		    , krp->krp_status
+		    , krp->krp_iparams, krp->krp_oparams
+		    , krp->krp_crid, krp->krp_hid
+		    , krp->krp_callback
+		);
+	}
+	if (!TAILQ_EMPTY(&crp_ret_q)) {
+		db_printf("%4s %5s %8s %4s %8s\n",
+		    "Op", "Status", "CRID", "HID", "Callback");
+		TAILQ_FOREACH(krp, &crp_ret_kq, krp_next) {
+			db_printf("%4u %5u %08x %4u %8p\n"
+			    , krp->krp_op
+			    , krp->krp_status
+			    , krp->krp_crid, krp->krp_hid
+			    , krp->krp_callback
+			);
+		}
+	}
+}
+#endif
+
+
+static int
+crypto_init(void)
+{
+	int error;
+	unsigned long cpu;
+
+	dprintk("%s(%p)\n", __FUNCTION__, (void *) crypto_init);
+
+	if (crypto_initted)
+		return 0;
+	crypto_initted = 1;
+
+	spin_lock_init(&crypto_drivers_lock);
+	spin_lock_init(&crypto_q_lock);
+	spin_lock_init(&crypto_ret_q_lock);
+
+	cryptop_zone = kmem_cache_create("cryptop", sizeof(struct cryptop),
+				       0, SLAB_HWCACHE_ALIGN, NULL
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+				       , NULL
+#endif
+					);
+
+	cryptodesc_zone = kmem_cache_create("cryptodesc", sizeof(struct cryptodesc),
+				       0, SLAB_HWCACHE_ALIGN, NULL
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+				       , NULL
+#endif
+					);
+
+	if (cryptodesc_zone == NULL || cryptop_zone == NULL) {
+		printk("crypto: crypto_init cannot setup crypto zones\n");
+		error = ENOMEM;
+		goto bad;
+	}
+
+	crypto_drivers_num = CRYPTO_DRIVERS_INITIAL;
+	crypto_drivers = kmalloc(crypto_drivers_num * sizeof(struct cryptocap),
+			GFP_KERNEL);
+	if (crypto_drivers == NULL) {
+		printk("crypto: crypto_init cannot setup crypto drivers\n");
+		error = ENOMEM;
+		goto bad;
+	}
+
+	memset(crypto_drivers, 0, crypto_drivers_num * sizeof(struct cryptocap));
+
+	ocf_for_each_cpu(cpu) {
+		cryptoproc[cpu] = kthread_create(crypto_proc, (void *) cpu,
+									"ocf_%d", (int) cpu);
+		if (IS_ERR(cryptoproc[cpu])) {
+			error = PTR_ERR(cryptoproc[cpu]);
+			printk("crypto: crypto_init cannot start crypto thread; error %d",
+				error);
+			goto bad;
+		}
+		kthread_bind(cryptoproc[cpu], cpu);
+		wake_up_process(cryptoproc[cpu]);
+
+		cryptoretproc[cpu] = kthread_create(crypto_ret_proc, (void *) cpu,
+									"ocf_ret_%d", (int) cpu);
+		if (IS_ERR(cryptoretproc[cpu])) {
+			error = PTR_ERR(cryptoretproc[cpu]);
+			printk("crypto: crypto_init cannot start cryptoret thread; error %d",
+					error);
+			goto bad;
+		}
+		kthread_bind(cryptoretproc[cpu], cpu);
+		wake_up_process(cryptoretproc[cpu]);
+	}
+
+	return 0;
+bad:
+	crypto_exit();
+	return error;
+}
+
+
+static void
+crypto_exit(void)
+{
+	int cpu;
+
+	dprintk("%s()\n", __FUNCTION__);
+
+	/*
+	 * Terminate any crypto threads.
+	 */
+	ocf_for_each_cpu(cpu) {
+		kthread_stop(cryptoproc[cpu]);
+		kthread_stop(cryptoretproc[cpu]);
+	}
+
+	/* 
+	 * Reclaim dynamically allocated resources.
+	 */
+	if (crypto_drivers != NULL)
+		kfree(crypto_drivers);
+
+	if (cryptodesc_zone != NULL)
+		kmem_cache_destroy(cryptodesc_zone);
+	if (cryptop_zone != NULL)
+		kmem_cache_destroy(cryptop_zone);
+}
+
+
+EXPORT_SYMBOL(crypto_newsession);
+EXPORT_SYMBOL(crypto_freesession);
+EXPORT_SYMBOL(crypto_get_driverid);
+EXPORT_SYMBOL(crypto_kregister);
+EXPORT_SYMBOL(crypto_register);
+EXPORT_SYMBOL(crypto_unregister);
+EXPORT_SYMBOL(crypto_unregister_all);
+EXPORT_SYMBOL(crypto_unblock);
+EXPORT_SYMBOL(crypto_dispatch);
+EXPORT_SYMBOL(crypto_kdispatch);
+EXPORT_SYMBOL(crypto_freereq);
+EXPORT_SYMBOL(crypto_getreq);
+EXPORT_SYMBOL(crypto_done);
+EXPORT_SYMBOL(crypto_kdone);
+EXPORT_SYMBOL(crypto_getfeat);
+EXPORT_SYMBOL(crypto_userasymcrypto);
+EXPORT_SYMBOL(crypto_getcaps);
+EXPORT_SYMBOL(crypto_find_driver);
+EXPORT_SYMBOL(crypto_find_device_byhid);
+
+module_init(crypto_init);
+module_exit(crypto_exit);
+
+MODULE_LICENSE("BSD");
+MODULE_AUTHOR("David McCullough <david_mccullough@mcafee.com>");
+MODULE_DESCRIPTION("OCF (OpenBSD Cryptographic Framework)");
diff --git a/crypto/ocf/cryptodev.c b/crypto/ocf/cryptodev.c
new file mode 100644
index 0000000..2ee3618
--- /dev/null
+++ b/crypto/ocf/cryptodev.c
@@ -0,0 +1,1069 @@
+/*	$OpenBSD: cryptodev.c,v 1.52 2002/06/19 07:22:46 deraadt Exp $	*/
+
+/*-
+ * Linux port done by David McCullough <david_mccullough@mcafee.com>
+ * Copyright (C) 2006-2010 David McCullough
+ * Copyright (C) 2004-2005 Intel Corporation.
+ * The license and original author are listed below.
+ *
+ * Copyright (c) 2001 Theo de Raadt
+ * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Effort sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F30602-01-2-0537.
+ *
+__FBSDID("$FreeBSD: src/sys/opencrypto/cryptodev.c,v 1.34 2007/05/09 19:37:02 gnn Exp $");
+ */
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED)
+#include <linux/config.h>
+#endif
+#include <linux/types.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/unistd.h>
+#include <linux/module.h>
+#include <linux/wait.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/dcache.h>
+#include <linux/file.h>
+#include <linux/mount.h>
+#include <linux/miscdevice.h>
+#include <asm/uaccess.h>
+
+#include <cryptodev.h>
+#include <uio.h>
+
+extern asmlinkage long sys_dup(unsigned int fildes);
+
+#define debug cryptodev_debug
+int cryptodev_debug = 0;
+module_param(cryptodev_debug, int, 0644);
+MODULE_PARM_DESC(cryptodev_debug, "Enable cryptodev debug");
+
+struct csession_info {
+	u_int16_t	blocksize;
+	u_int16_t	minkey, maxkey;
+
+	u_int16_t	keysize;
+	/* u_int16_t	hashsize;  */
+	u_int16_t	authsize;
+	u_int16_t	authkey;
+	/* u_int16_t	ctxsize; */
+};
+
+struct csession {
+	struct list_head	list;
+	u_int64_t	sid;
+	u_int32_t	ses;
+
+	wait_queue_head_t waitq;
+
+	u_int32_t	cipher;
+
+	u_int32_t	mac;
+
+	caddr_t		key;
+	int		keylen;
+	u_char		tmp_iv[EALG_MAX_BLOCK_LEN];
+
+	caddr_t		mackey;
+	int		mackeylen;
+
+	struct csession_info info;
+
+	struct iovec	iovec;
+	struct uio	uio;
+	int		error;
+};
+
+struct fcrypt {
+	struct list_head	csessions;
+	int		sesn;
+};
+
+static struct csession *csefind(struct fcrypt *, u_int);
+static int csedelete(struct fcrypt *, struct csession *);
+static struct csession *cseadd(struct fcrypt *, struct csession *);
+static struct csession *csecreate(struct fcrypt *, u_int64_t,
+		struct cryptoini *crie, struct cryptoini *cria, struct csession_info *);
+static int csefree(struct csession *);
+
+static	int cryptodev_op(struct csession *, struct crypt_op *);
+static	int cryptodev_key(struct crypt_kop *);
+static	int cryptodev_find(struct crypt_find_op *);
+
+static int cryptodev_cb(void *);
+static int cryptodev_open(struct inode *inode, struct file *filp);
+
+/*
+ * Check a crypto identifier to see if it requested
+ * a valid crid and it's capabilities match.
+ */
+static int
+checkcrid(int crid)
+{
+	int hid = crid & ~(CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE);
+	int typ = crid & (CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE);
+	int caps = 0;
+	
+	/* if the user hasn't selected a driver, then just call newsession */
+	if (hid == 0 && typ != 0)
+		return 0;
+
+	caps = crypto_getcaps(hid);
+
+	/* didn't find anything with capabilities */
+	if (caps == 0) {
+		dprintk("%s: hid=%x typ=%x not matched\n", __FUNCTION__, hid, typ);
+		return EINVAL;
+	}
+	
+	/* the user didn't specify SW or HW, so the driver is ok */
+	if (typ == 0)
+		return 0;
+
+	/* if the type specified didn't match */
+	if (typ != (caps & (CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE))) {
+		dprintk("%s: hid=%x typ=%x caps=%x not matched\n", __FUNCTION__,
+				hid, typ, caps);
+		return EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+cryptodev_op(struct csession *cse, struct crypt_op *cop)
+{
+	struct cryptop *crp = NULL;
+	struct cryptodesc *crde = NULL, *crda = NULL;
+	int error = 0;
+
+	dprintk("%s()\n", __FUNCTION__);
+	if (cop->len > CRYPTO_MAX_DATA_LEN) {
+		dprintk("%s: %d > %d\n", __FUNCTION__, cop->len, CRYPTO_MAX_DATA_LEN);
+		return (E2BIG);
+	}
+
+	if (cse->info.blocksize && (cop->len % cse->info.blocksize) != 0) {
+		dprintk("%s: blocksize=%d len=%d\n", __FUNCTION__, cse->info.blocksize,
+				cop->len);
+		return (EINVAL);
+	}
+
+	cse->uio.uio_iov = &cse->iovec;
+	cse->uio.uio_iovcnt = 1;
+	cse->uio.uio_offset = 0;
+#if 0
+	cse->uio.uio_resid = cop->len;
+	cse->uio.uio_segflg = UIO_SYSSPACE;
+	cse->uio.uio_rw = UIO_WRITE;
+	cse->uio.uio_td = td;
+#endif
+	cse->uio.uio_iov[0].iov_len = cop->len;
+	if (cse->info.authsize)
+		cse->uio.uio_iov[0].iov_len += cse->info.authsize;
+	cse->uio.uio_iov[0].iov_base = kmalloc(cse->uio.uio_iov[0].iov_len,
+			GFP_KERNEL);
+
+	if (cse->uio.uio_iov[0].iov_base == NULL) {
+		dprintk("%s: iov_base kmalloc(%d) failed\n", __FUNCTION__,
+				(int)cse->uio.uio_iov[0].iov_len);
+		return (ENOMEM);
+	}
+
+	crp = crypto_getreq((cse->info.blocksize != 0) + (cse->info.authsize != 0));
+	if (crp == NULL) {
+		dprintk("%s: ENOMEM\n", __FUNCTION__);
+		error = ENOMEM;
+		goto bail;
+	}
+
+	if (cse->info.authsize && cse->info.blocksize) {
+		if (cop->op == COP_ENCRYPT) {
+			crde = crp->crp_desc;
+			crda = crde->crd_next;
+		} else {
+			crda = crp->crp_desc;
+			crde = crda->crd_next;
+		}
+	} else if (cse->info.authsize) {
+		crda = crp->crp_desc;
+	} else if (cse->info.blocksize) {
+		crde = crp->crp_desc;
+	} else {
+		dprintk("%s: bad request\n", __FUNCTION__);
+		error = EINVAL;
+		goto bail;
+	}
+
+	if ((error = copy_from_user(cse->uio.uio_iov[0].iov_base, cop->src,
+					cop->len))) {
+		dprintk("%s: bad copy\n", __FUNCTION__);
+		goto bail;
+	}
+
+	if (crda) {
+		crda->crd_skip = 0;
+		crda->crd_len = cop->len;
+		crda->crd_inject = cop->len;
+
+		crda->crd_alg = cse->mac;
+		crda->crd_key = cse->mackey;
+		crda->crd_klen = cse->mackeylen * 8;
+	}
+
+	if (crde) {
+		if (cop->op == COP_ENCRYPT)
+			crde->crd_flags |= CRD_F_ENCRYPT;
+		else
+			crde->crd_flags &= ~CRD_F_ENCRYPT;
+		crde->crd_len = cop->len;
+		crde->crd_inject = 0;
+
+		crde->crd_alg = cse->cipher;
+		crde->crd_key = cse->key;
+		crde->crd_klen = cse->keylen * 8;
+	}
+
+	crp->crp_ilen = cse->uio.uio_iov[0].iov_len;
+	crp->crp_flags = CRYPTO_F_IOV | CRYPTO_F_CBIMM
+		       | (cop->flags & COP_F_BATCH);
+	crp->crp_buf = (caddr_t)&cse->uio;
+	crp->crp_callback = (int (*) (struct cryptop *)) cryptodev_cb;
+	crp->crp_sid = cse->sid;
+	crp->crp_opaque = (void *)cse;
+
+	if (cop->iv) {
+		if (crde == NULL) {
+			error = EINVAL;
+			dprintk("%s no crde\n", __FUNCTION__);
+			goto bail;
+		}
+		if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */
+			error = EINVAL;
+			dprintk("%s arc4 with IV\n", __FUNCTION__);
+			goto bail;
+		}
+		if ((error = copy_from_user(cse->tmp_iv, cop->iv,
+						cse->info.blocksize))) {
+			dprintk("%s bad iv copy\n", __FUNCTION__);
+			goto bail;
+		}
+		memcpy(crde->crd_iv, cse->tmp_iv, cse->info.blocksize);
+		crde->crd_flags |= CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT;
+		crde->crd_skip = 0;
+	} else if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */
+		crde->crd_skip = 0;
+	} else if (crde) {
+		crde->crd_flags |= CRD_F_IV_PRESENT;
+		crde->crd_skip = cse->info.blocksize;
+		crde->crd_len -= cse->info.blocksize;
+	}
+
+	if (cop->mac && crda == NULL) {
+		error = EINVAL;
+		dprintk("%s no crda\n", __FUNCTION__);
+		goto bail;
+	}
+
+	/*
+	 * Let the dispatch run unlocked, then, interlock against the
+	 * callback before checking if the operation completed and going
+	 * to sleep.  This insures drivers don't inherit our lock which
+	 * results in a lock order reversal between crypto_dispatch forced
+	 * entry and the crypto_done callback into us.
+	 */
+	error = crypto_dispatch(crp);
+	if (error) {
+		dprintk("%s error in crypto_dispatch\n", __FUNCTION__);
+		goto bail;
+	}
+
+	dprintk("%s about to WAIT\n", __FUNCTION__);
+	/*
+	 * we really need to wait for driver to complete to maintain
+	 * state,  luckily interrupts will be remembered
+	 */
+	do {
+		error = wait_event_interruptible(crp->crp_waitq,
+				((crp->crp_flags & CRYPTO_F_DONE) != 0));
+		/*
+		 * we can't break out of this loop or we will leave behind
+		 * a huge mess,  however,  staying here means if your driver
+		 * is broken user applications can hang and not be killed.
+		 * The solution,  fix your driver :-)
+		 */
+		if (error) {
+			schedule();
+			error = 0;
+		}
+	} while ((crp->crp_flags & CRYPTO_F_DONE) == 0);
+	dprintk("%s finished WAITING error=%d\n", __FUNCTION__, error);
+
+	if (crp->crp_etype != 0) {
+		error = crp->crp_etype;
+		dprintk("%s error in crp processing\n", __FUNCTION__);
+		goto bail;
+	}
+
+	if (cse->error) {
+		error = cse->error;
+		dprintk("%s error in cse processing\n", __FUNCTION__);
+		goto bail;
+	}
+
+	if (cop->dst && (error = copy_to_user(cop->dst,
+					cse->uio.uio_iov[0].iov_base, cop->len))) {
+		dprintk("%s bad dst copy\n", __FUNCTION__);
+		goto bail;
+	}
+
+	if (cop->mac &&
+			(error=copy_to_user(cop->mac,
+				(caddr_t)cse->uio.uio_iov[0].iov_base + cop->len,
+				cse->info.authsize))) {
+		dprintk("%s bad mac copy\n", __FUNCTION__);
+		goto bail;
+	}
+
+bail:
+	if (crp)
+		crypto_freereq(crp);
+	if (cse->uio.uio_iov[0].iov_base)
+		kfree(cse->uio.uio_iov[0].iov_base);
+
+	return (error);
+}
+
+static int
+cryptodev_cb(void *op)
+{
+	struct cryptop *crp = (struct cryptop *) op;
+	struct csession *cse = (struct csession *)crp->crp_opaque;
+	int error;
+
+	dprintk("%s()\n", __FUNCTION__);
+	error = crp->crp_etype;
+	if (error == EAGAIN) {
+		crp->crp_flags &= ~CRYPTO_F_DONE;
+#ifdef NOTYET
+		/*
+		 * DAVIDM I am fairly sure that we should turn this into a batch
+		 * request to stop bad karma/lockup, revisit
+		 */
+		crp->crp_flags |= CRYPTO_F_BATCH;
+#endif
+		return crypto_dispatch(crp);
+	}
+	if (error != 0 || (crp->crp_flags & CRYPTO_F_DONE)) {
+		cse->error = error;
+		wake_up_interruptible(&crp->crp_waitq);
+	}
+	return (0);
+}
+
+static int
+cryptodevkey_cb(void *op)
+{
+	struct cryptkop *krp = (struct cryptkop *) op;
+	dprintk("%s()\n", __FUNCTION__);
+	wake_up_interruptible(&krp->krp_waitq);
+	return (0);
+}
+
+static int
+cryptodev_key(struct crypt_kop *kop)
+{
+	struct cryptkop *krp = NULL;
+	int error = EINVAL;
+	int in, out, size, i;
+
+	dprintk("%s()\n", __FUNCTION__);
+	if (kop->crk_iparams + kop->crk_oparams > CRK_MAXPARAM) {
+		dprintk("%s params too big\n", __FUNCTION__);
+		return (EFBIG);
+	}
+
+	in = kop->crk_iparams;
+	out = kop->crk_oparams;
+	switch (kop->crk_op) {
+	case CRK_MOD_EXP:
+		if (in == 3 && out == 1)
+			break;
+		return (EINVAL);
+	case CRK_MOD_EXP_CRT:
+		if (in == 6 && out == 1)
+			break;
+		return (EINVAL);
+	case CRK_DSA_SIGN:
+		if (in == 5 && out == 2)
+			break;
+		return (EINVAL);
+	case CRK_DSA_VERIFY:
+		if (in == 7 && out == 0)
+			break;
+		return (EINVAL);
+	case CRK_DH_COMPUTE_KEY:
+		if (in == 3 && out == 1)
+			break;
+		return (EINVAL);
+	default:
+		return (EINVAL);
+	}
+
+	krp = (struct cryptkop *)kmalloc(sizeof *krp, GFP_KERNEL);
+	if (!krp)
+		return (ENOMEM);
+	bzero(krp, sizeof *krp);
+	krp->krp_op = kop->crk_op;
+	krp->krp_status = kop->crk_status;
+	krp->krp_iparams = kop->crk_iparams;
+	krp->krp_oparams = kop->crk_oparams;
+	krp->krp_crid = kop->crk_crid;
+	krp->krp_status = 0;
+	krp->krp_flags = CRYPTO_KF_CBIMM;
+	krp->krp_callback = (int (*) (struct cryptkop *)) cryptodevkey_cb;
+	init_waitqueue_head(&krp->krp_waitq);
+
+	for (i = 0; i < CRK_MAXPARAM; i++)
+		krp->krp_param[i].crp_nbits = kop->crk_param[i].crp_nbits;
+	for (i = 0; i < krp->krp_iparams + krp->krp_oparams; i++) {
+		size = (krp->krp_param[i].crp_nbits + 7) / 8;
+		if (size == 0)
+			continue;
+		krp->krp_param[i].crp_p = (caddr_t) kmalloc(size, GFP_KERNEL);
+		if (i >= krp->krp_iparams)
+			continue;
+		error = copy_from_user(krp->krp_param[i].crp_p,
+				kop->crk_param[i].crp_p, size);
+		if (error)
+			goto fail;
+	}
+
+	error = crypto_kdispatch(krp);
+	if (error)
+		goto fail;
+
+	do {
+		error = wait_event_interruptible(krp->krp_waitq,
+				((krp->krp_flags & CRYPTO_KF_DONE) != 0));
+		/*
+		 * we can't break out of this loop or we will leave behind
+		 * a huge mess,  however,  staying here means if your driver
+		 * is broken user applications can hang and not be killed.
+		 * The solution,  fix your driver :-)
+		 */
+		if (error) {
+			schedule();
+			error = 0;
+		}
+	} while ((krp->krp_flags & CRYPTO_KF_DONE) == 0);
+
+	dprintk("%s finished WAITING error=%d\n", __FUNCTION__, error);
+	
+	kop->crk_crid = krp->krp_crid;		/* device that did the work */
+	if (krp->krp_status != 0) {
+		error = krp->krp_status;
+		goto fail;
+	}
+
+	for (i = krp->krp_iparams; i < krp->krp_iparams + krp->krp_oparams; i++) {
+		size = (krp->krp_param[i].crp_nbits + 7) / 8;
+		if (size == 0)
+			continue;
+		error = copy_to_user(kop->crk_param[i].crp_p, krp->krp_param[i].crp_p,
+				size);
+		if (error)
+			goto fail;
+	}
+
+fail:
+	if (krp) {
+		kop->crk_status = krp->krp_status;
+		for (i = 0; i < CRK_MAXPARAM; i++) {
+			if (krp->krp_param[i].crp_p)
+				kfree(krp->krp_param[i].crp_p);
+		}
+		kfree(krp);
+	}
+	return (error);
+}
+
+static int
+cryptodev_find(struct crypt_find_op *find)
+{
+	device_t dev;
+
+	if (find->crid != -1) {
+		dev = crypto_find_device_byhid(find->crid);
+		if (dev == NULL)
+			return (ENOENT);
+		strlcpy(find->name, device_get_nameunit(dev),
+		    sizeof(find->name));
+	} else {
+		find->crid = crypto_find_driver(find->name);
+		if (find->crid == -1)
+			return (ENOENT);
+	}
+	return (0);
+}
+
+static struct csession *
+csefind(struct fcrypt *fcr, u_int ses)
+{
+	struct csession *cse;
+
+	dprintk("%s()\n", __FUNCTION__);
+	list_for_each_entry(cse, &fcr->csessions, list)
+		if (cse->ses == ses)
+			return (cse);
+	return (NULL);
+}
+
+static int
+csedelete(struct fcrypt *fcr, struct csession *cse_del)
+{
+	struct csession *cse;
+
+	dprintk("%s()\n", __FUNCTION__);
+	list_for_each_entry(cse, &fcr->csessions, list) {
+		if (cse == cse_del) {
+			list_del(&cse->list);
+			return (1);
+		}
+	}
+	return (0);
+}
+	
+static struct csession *
+cseadd(struct fcrypt *fcr, struct csession *cse)
+{
+	dprintk("%s()\n", __FUNCTION__);
+	list_add_tail(&cse->list, &fcr->csessions);
+	cse->ses = fcr->sesn++;
+	return (cse);
+}
+
+static struct csession *
+csecreate(struct fcrypt *fcr, u_int64_t sid, struct cryptoini *crie,
+	struct cryptoini *cria, struct csession_info *info)
+{
+	struct csession *cse;
+
+	dprintk("%s()\n", __FUNCTION__);
+	cse = (struct csession *) kmalloc(sizeof(struct csession), GFP_KERNEL);
+	if (cse == NULL)
+		return NULL;
+	memset(cse, 0, sizeof(struct csession));
+
+	INIT_LIST_HEAD(&cse->list);
+	init_waitqueue_head(&cse->waitq);
+
+	cse->key = crie->cri_key;
+	cse->keylen = crie->cri_klen/8;
+	cse->mackey = cria->cri_key;
+	cse->mackeylen = cria->cri_klen/8;
+	cse->sid = sid;
+	cse->cipher = crie->cri_alg;
+	cse->mac = cria->cri_alg;
+	cse->info = *info;
+	cseadd(fcr, cse);
+	return (cse);
+}
+
+static int
+csefree(struct csession *cse)
+{
+	int error;
+
+	dprintk("%s()\n", __FUNCTION__);
+	error = crypto_freesession(cse->sid);
+	if (cse->key)
+		kfree(cse->key);
+	if (cse->mackey)
+		kfree(cse->mackey);
+	kfree(cse);
+	return(error);
+}
+
+static int
+cryptodev_ioctl(
+	struct inode *inode,
+	struct file *filp,
+	unsigned int cmd,
+	unsigned long arg)
+{
+	struct cryptoini cria, crie;
+	struct fcrypt *fcr = filp->private_data;
+	struct csession *cse;
+	struct csession_info info;
+	struct session2_op sop;
+	struct crypt_op cop;
+	struct crypt_kop kop;
+	struct crypt_find_op fop;
+	u_int64_t sid;
+	u_int32_t ses = 0;
+	int feat, fd, error = 0, crid;
+	mm_segment_t fs;
+
+	dprintk("%s(cmd=%x arg=%lx)\n", __FUNCTION__, cmd, arg);
+
+	switch (cmd) {
+
+	case CRIOGET: {
+		dprintk("%s(CRIOGET)\n", __FUNCTION__);
+		fs = get_fs();
+		set_fs(get_ds());
+		for (fd = 0; fd < files_fdtable(current->files)->max_fds; fd++)
+			if (files_fdtable(current->files)->fd[fd] == filp)
+				break;
+		fd = sys_dup(fd);
+		set_fs(fs);
+		put_user(fd, (int *) arg);
+		return IS_ERR_VALUE(fd) ? fd : 0;
+		}
+
+#define	CIOCGSESSSTR	(cmd == CIOCGSESSION ? "CIOCGSESSION" : "CIOCGSESSION2")
+	case CIOCGSESSION:
+	case CIOCGSESSION2:
+		dprintk("%s(%s)\n", __FUNCTION__, CIOCGSESSSTR);
+		memset(&crie, 0, sizeof(crie));
+		memset(&cria, 0, sizeof(cria));
+		memset(&info, 0, sizeof(info));
+		memset(&sop, 0, sizeof(sop));
+
+		if (copy_from_user(&sop, (void*)arg, (cmd == CIOCGSESSION) ?
+					sizeof(struct session_op) : sizeof(sop))) {
+			dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR);
+			error = EFAULT;
+			goto bail;
+		}
+
+		switch (sop.cipher) {
+		case 0:
+			dprintk("%s(%s) - no cipher\n", __FUNCTION__, CIOCGSESSSTR);
+			break;
+		case CRYPTO_NULL_CBC:
+			info.blocksize = NULL_BLOCK_LEN;
+			info.minkey = NULL_MIN_KEY_LEN;
+			info.maxkey = NULL_MAX_KEY_LEN;
+			break;
+		case CRYPTO_DES_CBC:
+			info.blocksize = DES_BLOCK_LEN;
+			info.minkey = DES_MIN_KEY_LEN;
+			info.maxkey = DES_MAX_KEY_LEN;
+			break;
+		case CRYPTO_3DES_CBC:
+			info.blocksize = DES3_BLOCK_LEN;
+			info.minkey = DES3_MIN_KEY_LEN;
+			info.maxkey = DES3_MAX_KEY_LEN;
+			break;
+		case CRYPTO_BLF_CBC:
+			info.blocksize = BLOWFISH_BLOCK_LEN;
+			info.minkey = BLOWFISH_MIN_KEY_LEN;
+			info.maxkey = BLOWFISH_MAX_KEY_LEN;
+			break;
+		case CRYPTO_CAST_CBC:
+			info.blocksize = CAST128_BLOCK_LEN;
+			info.minkey = CAST128_MIN_KEY_LEN;
+			info.maxkey = CAST128_MAX_KEY_LEN;
+			break;
+		case CRYPTO_SKIPJACK_CBC:
+			info.blocksize = SKIPJACK_BLOCK_LEN;
+			info.minkey = SKIPJACK_MIN_KEY_LEN;
+			info.maxkey = SKIPJACK_MAX_KEY_LEN;
+			break;
+		case CRYPTO_AES_CBC:
+			info.blocksize = AES_BLOCK_LEN;
+			info.minkey = AES_MIN_KEY_LEN;
+			info.maxkey = AES_MAX_KEY_LEN;
+			break;
+		case CRYPTO_ARC4:
+			info.blocksize = ARC4_BLOCK_LEN;
+			info.minkey = ARC4_MIN_KEY_LEN;
+			info.maxkey = ARC4_MAX_KEY_LEN;
+			break;
+		case CRYPTO_CAMELLIA_CBC:
+			info.blocksize = CAMELLIA_BLOCK_LEN;
+			info.minkey = CAMELLIA_MIN_KEY_LEN;
+			info.maxkey = CAMELLIA_MAX_KEY_LEN;
+			break;
+		default:
+			dprintk("%s(%s) - bad cipher\n", __FUNCTION__, CIOCGSESSSTR);
+			error = EINVAL;
+			goto bail;
+		}
+
+		switch (sop.mac) {
+		case 0:
+			dprintk("%s(%s) - no mac\n", __FUNCTION__, CIOCGSESSSTR);
+			break;
+		case CRYPTO_NULL_HMAC:
+			info.authsize = NULL_HASH_LEN;
+			break;
+		case CRYPTO_MD5:
+			info.authsize = MD5_HASH_LEN;
+			break;
+		case CRYPTO_SHA1:
+			info.authsize = SHA1_HASH_LEN;
+			break;
+		case CRYPTO_SHA2_256:
+			info.authsize = SHA2_256_HASH_LEN;
+			break;
+		case CRYPTO_SHA2_384:
+			info.authsize = SHA2_384_HASH_LEN;
+  			break;
+		case CRYPTO_SHA2_512:
+			info.authsize = SHA2_512_HASH_LEN;
+			break;
+		case CRYPTO_RIPEMD160:
+			info.authsize = RIPEMD160_HASH_LEN;
+			break;
+		case CRYPTO_MD5_HMAC:
+			info.authsize = MD5_HASH_LEN;
+			info.authkey = 16;
+			break;
+		case CRYPTO_SHA1_HMAC:
+			info.authsize = SHA1_HASH_LEN;
+			info.authkey = 20;
+			break;
+		case CRYPTO_SHA2_256_HMAC:
+			info.authsize = SHA2_256_HASH_LEN;
+			info.authkey = 32;
+			break;
+		case CRYPTO_SHA2_384_HMAC:
+			info.authsize = SHA2_384_HASH_LEN;
+			info.authkey = 48;
+  			break;
+		case CRYPTO_SHA2_512_HMAC:
+			info.authsize = SHA2_512_HASH_LEN;
+			info.authkey = 64;
+			break;
+		case CRYPTO_RIPEMD160_HMAC:
+			info.authsize = RIPEMD160_HASH_LEN;
+			info.authkey = 20;
+			break;
+		default:
+			dprintk("%s(%s) - bad mac\n", __FUNCTION__, CIOCGSESSSTR);
+			error = EINVAL;
+			goto bail;
+		}
+
+		if (info.blocksize) {
+			crie.cri_alg = sop.cipher;
+			crie.cri_klen = sop.keylen * 8;
+			if ((info.maxkey && sop.keylen > info.maxkey) ||
+				   	sop.keylen < info.minkey) {
+				dprintk("%s(%s) - bad key\n", __FUNCTION__, CIOCGSESSSTR);
+				error = EINVAL;
+				goto bail;
+			}
+
+			crie.cri_key = (u_int8_t *) kmalloc(crie.cri_klen/8+1, GFP_KERNEL);
+			if (copy_from_user(crie.cri_key, sop.key,
+							crie.cri_klen/8)) {
+				dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR);
+				error = EFAULT;
+				goto bail;
+			}
+			if (info.authsize)
+				crie.cri_next = &cria;
+		}
+
+		if (info.authsize) {
+			cria.cri_alg = sop.mac;
+			cria.cri_klen = sop.mackeylen * 8;
+			if (info.authkey && sop.mackeylen != info.authkey) {
+				dprintk("%s(%s) - mackeylen %d != %d\n", __FUNCTION__,
+						CIOCGSESSSTR, sop.mackeylen, info.authkey);
+				error = EINVAL;
+				goto bail;
+			}
+
+			if (cria.cri_klen) {
+				cria.cri_key = (u_int8_t *) kmalloc(cria.cri_klen/8,GFP_KERNEL);
+				if (copy_from_user(cria.cri_key, sop.mackey,
+								cria.cri_klen / 8)) {
+					dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR);
+					error = EFAULT;
+					goto bail;
+				}
+			}
+		}
+
+		/* NB: CIOGSESSION2 has the crid */
+		if (cmd == CIOCGSESSION2) {
+			crid = sop.crid;
+			error = checkcrid(crid);
+			if (error) {
+				dprintk("%s(%s) - checkcrid %x\n", __FUNCTION__,
+						CIOCGSESSSTR, error);
+				goto bail;
+			}
+		} else {
+			/* allow either HW or SW to be used */
+			crid = CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE;
+		}
+		error = crypto_newsession(&sid, (info.blocksize ? &crie : &cria), crid);
+		if (error) {
+			dprintk("%s(%s) - newsession %d\n",__FUNCTION__,CIOCGSESSSTR,error);
+			goto bail;
+		}
+
+		cse = csecreate(fcr, sid, &crie, &cria, &info);
+		if (cse == NULL) {
+			crypto_freesession(sid);
+			error = EINVAL;
+			dprintk("%s(%s) - csecreate failed\n", __FUNCTION__, CIOCGSESSSTR);
+			goto bail;
+		}
+		sop.ses = cse->ses;
+
+		if (cmd == CIOCGSESSION2) {
+			/* return hardware/driver id */
+			sop.crid = CRYPTO_SESID2HID(cse->sid);
+		}
+
+		if (copy_to_user((void*)arg, &sop, (cmd == CIOCGSESSION) ?
+					sizeof(struct session_op) : sizeof(sop))) {
+			dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR);
+			error = EFAULT;
+		}
+bail:
+		if (error) {
+			dprintk("%s(%s) - bail %d\n", __FUNCTION__, CIOCGSESSSTR, error);
+			if (crie.cri_key)
+				kfree(crie.cri_key);
+			if (cria.cri_key)
+				kfree(cria.cri_key);
+		}
+		break;
+	case CIOCFSESSION:
+		dprintk("%s(CIOCFSESSION)\n", __FUNCTION__);
+		get_user(ses, (uint32_t*)arg);
+		cse = csefind(fcr, ses);
+		if (cse == NULL) {
+			error = EINVAL;
+			dprintk("%s(CIOCFSESSION) - Fail %d\n", __FUNCTION__, error);
+			break;
+		}
+		csedelete(fcr, cse);
+		error = csefree(cse);
+		break;
+	case CIOCCRYPT:
+		dprintk("%s(CIOCCRYPT)\n", __FUNCTION__);
+		if(copy_from_user(&cop, (void*)arg, sizeof(cop))) {
+			dprintk("%s(CIOCCRYPT) - bad copy\n", __FUNCTION__);
+			error = EFAULT;
+			goto bail;
+		}
+		cse = csefind(fcr, cop.ses);
+		if (cse == NULL) {
+			error = EINVAL;
+			dprintk("%s(CIOCCRYPT) - Fail %d\n", __FUNCTION__, error);
+			break;
+		}
+		error = cryptodev_op(cse, &cop);
+		if(copy_to_user((void*)arg, &cop, sizeof(cop))) {
+			dprintk("%s(CIOCCRYPT) - bad return copy\n", __FUNCTION__);
+			error = EFAULT;
+			goto bail;
+		}
+		break;
+	case CIOCKEY:
+	case CIOCKEY2:
+		dprintk("%s(CIOCKEY)\n", __FUNCTION__);
+		if (!crypto_userasymcrypto)
+			return (EPERM);		/* XXX compat? */
+		if(copy_from_user(&kop, (void*)arg, sizeof(kop))) {
+			dprintk("%s(CIOCKEY) - bad copy\n", __FUNCTION__);
+			error = EFAULT;
+			goto bail;
+		}
+		if (cmd == CIOCKEY) {
+			/* NB: crypto core enforces s/w driver use */
+			kop.crk_crid =
+			    CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE;
+		}
+		error = cryptodev_key(&kop);
+		if(copy_to_user((void*)arg, &kop, sizeof(kop))) {
+			dprintk("%s(CIOCGKEY) - bad return copy\n", __FUNCTION__);
+			error = EFAULT;
+			goto bail;
+		}
+		break;
+	case CIOCASYMFEAT:
+		dprintk("%s(CIOCASYMFEAT)\n", __FUNCTION__);
+		if (!crypto_userasymcrypto) {
+			/*
+			 * NB: if user asym crypto operations are
+			 * not permitted return "no algorithms"
+			 * so well-behaved applications will just
+			 * fallback to doing them in software.
+			 */
+			feat = 0;
+		} else
+			error = crypto_getfeat(&feat);
+		if (!error) {
+		  error = copy_to_user((void*)arg, &feat, sizeof(feat));
+		}
+		break;
+	case CIOCFINDDEV:
+		if (copy_from_user(&fop, (void*)arg, sizeof(fop))) {
+			dprintk("%s(CIOCFINDDEV) - bad copy\n", __FUNCTION__);
+			error = EFAULT;
+			goto bail;
+		}
+		error = cryptodev_find(&fop);
+		if (copy_to_user((void*)arg, &fop, sizeof(fop))) {
+			dprintk("%s(CIOCFINDDEV) - bad return copy\n", __FUNCTION__);
+			error = EFAULT;
+			goto bail;
+		}
+		break;
+	default:
+		dprintk("%s(unknown ioctl 0x%x)\n", __FUNCTION__, cmd);
+		error = EINVAL;
+		break;
+	}
+	return(-error);
+}
+
+#ifdef HAVE_UNLOCKED_IOCTL
+static long
+cryptodev_unlocked_ioctl(
+	struct file *filp,
+	unsigned int cmd,
+	unsigned long arg)
+{
+	return cryptodev_ioctl(NULL, filp, cmd, arg);
+}
+#endif
+
+static int
+cryptodev_open(struct inode *inode, struct file *filp)
+{
+	struct fcrypt *fcr;
+
+	dprintk("%s()\n", __FUNCTION__);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
+	/*
+	 * on 2.6.35 private_data points to a miscdevice structure, we override
+	 * it,  which is currently safe to do.
+	 */
+	if (filp->private_data) {
+		printk("cryptodev: Private data already exists - %p!\n", filp->private_data);
+		return(-ENODEV);
+	}
+#endif
+
+	fcr = kmalloc(sizeof(*fcr), GFP_KERNEL);
+	if (!fcr) {
+		dprintk("%s() - malloc failed\n", __FUNCTION__);
+		return(-ENOMEM);
+	}
+	memset(fcr, 0, sizeof(*fcr));
+
+	INIT_LIST_HEAD(&fcr->csessions);
+	filp->private_data = fcr;
+	return(0);
+}
+
+static int
+cryptodev_release(struct inode *inode, struct file *filp)
+{
+	struct fcrypt *fcr = filp->private_data;
+	struct csession *cse, *tmp;
+
+	dprintk("%s()\n", __FUNCTION__);
+	if (!filp) {
+		printk("cryptodev: No private data on release\n");
+		return(0);
+	}
+
+	list_for_each_entry_safe(cse, tmp, &fcr->csessions, list) {
+		list_del(&cse->list);
+		(void)csefree(cse);
+	}
+	filp->private_data = NULL;
+	kfree(fcr);
+	return(0);
+}
+
+static struct file_operations cryptodev_fops = {
+	.owner = THIS_MODULE,
+	.open = cryptodev_open,
+	.release = cryptodev_release,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)
+	.ioctl = cryptodev_ioctl,
+#endif
+#ifdef HAVE_UNLOCKED_IOCTL
+	.unlocked_ioctl = cryptodev_unlocked_ioctl,
+#endif
+};
+
+static struct miscdevice cryptodev = {
+	.minor = CRYPTODEV_MINOR,
+	.name = "crypto",
+	.fops = &cryptodev_fops,
+};
+
+static int __init
+cryptodev_init(void)
+{
+	int rc;
+
+	dprintk("%s(%p)\n", __FUNCTION__, cryptodev_init);
+	rc = misc_register(&cryptodev);
+	if (rc) {
+		printk(KERN_ERR "cryptodev: registration of /dev/crypto failed\n");
+		return(rc);
+	}
+
+	return(0);
+}
+
+static void __exit
+cryptodev_exit(void)
+{
+	dprintk("%s()\n", __FUNCTION__);
+	misc_deregister(&cryptodev);
+}
+
+module_init(cryptodev_init);
+module_exit(cryptodev_exit);
+
+MODULE_LICENSE("BSD");
+MODULE_AUTHOR("David McCullough <david_mccullough@mcafee.com>");
+MODULE_DESCRIPTION("Cryptodev (user interface to OCF)");
diff --git a/crypto/ocf/cryptodev.h b/crypto/ocf/cryptodev.h
new file mode 100644
index 0000000..6067541
--- /dev/null
+++ b/crypto/ocf/cryptodev.h
@@ -0,0 +1,561 @@
+/*	$FreeBSD: src/sys/opencrypto/cryptodev.h,v 1.25 2007/05/09 19:37:02 gnn Exp $	*/
+/*	$OpenBSD: cryptodev.h,v 1.31 2002/06/11 11:14:29 beck Exp $	*/
+
+/*-
+ * Linux port done by David McCullough <david_mccullough@mcafee.com>
+ * Copyright (C) 2006-2010 David McCullough
+ * Copyright (C) 2004-2005 Intel Corporation.
+ * The license and original author are listed below.
+ *
+ * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
+ * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting
+ *
+ * This code was written by Angelos D. Keromytis in Athens, Greece, in
+ * February 2000. Network Security Technologies Inc. (NSTI) kindly
+ * supported the development of this code.
+ *
+ * Copyright (c) 2000 Angelos D. Keromytis
+ *
+ * Permission to use, copy, and modify this software with or without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all source code copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Copyright (c) 2001 Theo de Raadt
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Effort sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F30602-01-2-0537.
+ *
+ */
+
+#ifndef _CRYPTO_CRYPTO_H_
+#define _CRYPTO_CRYPTO_H_
+
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+#include <linux/in.h>
+#endif
+
+
+/* Some initial values */
+#define CRYPTO_DRIVERS_INITIAL	4
+#define CRYPTO_SW_SESSIONS	32
+
+/* Hash values */
+#define NULL_HASH_LEN		0
+#define MD5_HASH_LEN		16
+#define SHA1_HASH_LEN		20
+#define RIPEMD160_HASH_LEN	20
+#define SHA2_256_HASH_LEN	32
+#define SHA2_384_HASH_LEN	48
+#define SHA2_512_HASH_LEN	64
+#define MD5_KPDK_HASH_LEN	16
+#define SHA1_KPDK_HASH_LEN	20
+/* Maximum hash algorithm result length */
+#define HASH_MAX_LEN		SHA2_512_HASH_LEN /* Keep this updated */
+
+/* HMAC values */
+#define NULL_HMAC_BLOCK_LEN			1
+#define MD5_HMAC_BLOCK_LEN			64
+#define SHA1_HMAC_BLOCK_LEN			64
+#define RIPEMD160_HMAC_BLOCK_LEN	64
+#define SHA2_256_HMAC_BLOCK_LEN		64
+#define SHA2_384_HMAC_BLOCK_LEN		128
+#define SHA2_512_HMAC_BLOCK_LEN		128
+/* Maximum HMAC block length */
+#define HMAC_MAX_BLOCK_LEN		SHA2_512_HMAC_BLOCK_LEN /* Keep this updated */
+#define HMAC_IPAD_VAL			0x36
+#define HMAC_OPAD_VAL			0x5C
+
+/* Encryption algorithm block sizes */
+#define NULL_BLOCK_LEN			1
+#define DES_BLOCK_LEN			8
+#define DES3_BLOCK_LEN			8
+#define BLOWFISH_BLOCK_LEN		8
+#define SKIPJACK_BLOCK_LEN		8
+#define CAST128_BLOCK_LEN		8
+#define RIJNDAEL128_BLOCK_LEN	16
+#define AES_BLOCK_LEN			RIJNDAEL128_BLOCK_LEN
+#define CAMELLIA_BLOCK_LEN		16
+#define ARC4_BLOCK_LEN			1
+#define EALG_MAX_BLOCK_LEN		AES_BLOCK_LEN /* Keep this updated */
+
+/* Encryption algorithm min and max key sizes */
+#define NULL_MIN_KEY_LEN		0
+#define NULL_MAX_KEY_LEN		0
+#define DES_MIN_KEY_LEN			8
+#define DES_MAX_KEY_LEN			8
+#define DES3_MIN_KEY_LEN		24
+#define DES3_MAX_KEY_LEN		24
+#define BLOWFISH_MIN_KEY_LEN	4
+#define BLOWFISH_MAX_KEY_LEN	56
+#define SKIPJACK_MIN_KEY_LEN	10
+#define SKIPJACK_MAX_KEY_LEN	10
+#define CAST128_MIN_KEY_LEN		5
+#define CAST128_MAX_KEY_LEN		16
+#define RIJNDAEL128_MIN_KEY_LEN	16
+#define RIJNDAEL128_MAX_KEY_LEN	32
+#define AES_MIN_KEY_LEN			RIJNDAEL128_MIN_KEY_LEN
+#define AES_MAX_KEY_LEN			RIJNDAEL128_MAX_KEY_LEN
+#define CAMELLIA_MIN_KEY_LEN	16
+#define CAMELLIA_MAX_KEY_LEN	32
+#define ARC4_MIN_KEY_LEN		1
+#define ARC4_MAX_KEY_LEN		256
+
+/* Max size of data that can be processed */
+#define CRYPTO_MAX_DATA_LEN		64*1024 - 1
+
+#define CRYPTO_ALGORITHM_MIN	1
+#define CRYPTO_DES_CBC			1
+#define CRYPTO_3DES_CBC			2
+#define CRYPTO_BLF_CBC			3
+#define CRYPTO_CAST_CBC			4
+#define CRYPTO_SKIPJACK_CBC		5
+#define CRYPTO_MD5_HMAC			6
+#define CRYPTO_SHA1_HMAC		7
+#define CRYPTO_RIPEMD160_HMAC	8
+#define CRYPTO_MD5_KPDK			9
+#define CRYPTO_SHA1_KPDK		10
+#define CRYPTO_RIJNDAEL128_CBC	11 /* 128 bit blocksize */
+#define CRYPTO_AES_CBC			11 /* 128 bit blocksize -- the same as above */
+#define CRYPTO_ARC4				12
+#define CRYPTO_MD5				13
+#define CRYPTO_SHA1				14
+#define CRYPTO_NULL_HMAC		15
+#define CRYPTO_NULL_CBC			16
+#define CRYPTO_DEFLATE_COMP		17 /* Deflate compression algorithm */
+#define CRYPTO_SHA2_256_HMAC	18
+#define CRYPTO_SHA2_384_HMAC	19
+#define CRYPTO_SHA2_512_HMAC	20
+#define CRYPTO_CAMELLIA_CBC		21
+#define CRYPTO_SHA2_256			22
+#define CRYPTO_SHA2_384			23
+#define CRYPTO_SHA2_512			24
+#define CRYPTO_RIPEMD160		25
+#define	CRYPTO_LZS_COMP			26
+#define CRYPTO_ESP_RFC2406 		27
+//#define CRYPTO_ESP_RFC2406_TRANSPORT 20
+#define CRYPTO_ESP_RFC4303  		28
+#define CRYPTO_ESP4_RFC4303  		28
+#define CRYPTO_ESP6_RFC4303  		29
+#define CRYPTO_AH			30
+#define CRYPTO_AH4			30
+#define CRYPTO_AH6			31
+#define CRYPTO_SHA2_HMAC		32 /*TODO is it a duplicate entry*/
+#define CRYPTO_ALGORITHM_MAX		32 /* Keep updated - see below */
+
+/* Algorithm flags */
+#define CRYPTO_ALG_FLAG_SUPPORTED	0x01 /* Algorithm is supported */
+#define CRYPTO_ALG_FLAG_RNG_ENABLE	0x02 /* Has HW RNG for DH/DSA */
+#define CRYPTO_ALG_FLAG_DSA_SHA		0x04 /* Can do SHA on msg */
+
+/*
+ * Crypto driver/device flags.  They can set in the crid
+ * parameter when creating a session or submitting a key
+ * op to affect the device/driver assigned.  If neither
+ * of these are specified then the crid is assumed to hold
+ * the driver id of an existing (and suitable) device that
+ * must be used to satisfy the request.
+ */
+#define CRYPTO_FLAG_HARDWARE	0x01000000	/* hardware accelerated */
+#define CRYPTO_FLAG_SOFTWARE	0x02000000	/* software implementation */
+
+/* NB: deprecated */
+struct session_op {
+	u_int32_t	cipher;		/* ie. CRYPTO_DES_CBC */
+	u_int32_t	mac;		/* ie. CRYPTO_MD5_HMAC */
+
+	u_int32_t	keylen;		/* cipher key */
+	caddr_t		key;
+	int		mackeylen;	/* mac key */
+	caddr_t		mackey;
+
+  	u_int32_t	ses;		/* returns: session # */ 
+};
+
+struct session2_op {
+	u_int32_t	cipher;		/* ie. CRYPTO_DES_CBC */
+	u_int32_t	mac;		/* ie. CRYPTO_MD5_HMAC */
+
+	u_int32_t	keylen;		/* cipher key */
+	caddr_t		key;
+	int		mackeylen;	/* mac key */
+	caddr_t		mackey;
+
+  	u_int32_t	ses;		/* returns: session # */ 
+	int		crid;		/* driver id + flags (rw) */
+	int		pad[4];		/* for future expansion */
+};
+
+struct crypt_op {
+	u_int32_t	ses;
+	u_int16_t	op;		/* i.e. COP_ENCRYPT */
+#define COP_NONE	0
+#define COP_ENCRYPT	1
+#define COP_DECRYPT	2
+	u_int16_t	flags;
+#define	COP_F_BATCH	0x0008		/* Batch op if possible */
+	u_int		len;
+	caddr_t		src, dst;	/* become iov[] inside kernel */
+	caddr_t		mac;		/* must be big enough for chosen MAC */
+	caddr_t		iv;
+};
+
+/*
+ * Parameters for looking up a crypto driver/device by
+ * device name or by id.  The latter are returned for
+ * created sessions (crid) and completed key operations.
+ */
+struct crypt_find_op {
+	int		crid;		/* driver id + flags */
+	char		name[32];	/* device/driver name */
+};
+
+/* bignum parameter, in packed bytes, ... */
+struct crparam {
+	caddr_t		crp_p;
+	u_int		crp_nbits;
+};
+
+#define CRK_MAXPARAM	8
+
+struct crypt_kop {
+	u_int		crk_op;		/* ie. CRK_MOD_EXP or other */
+	u_int		crk_status;	/* return status */
+	u_short		crk_iparams;	/* # of input parameters */
+	u_short		crk_oparams;	/* # of output parameters */
+	u_int		crk_crid;	/* NB: only used by CIOCKEY2 (rw) */
+	struct crparam	crk_param[CRK_MAXPARAM];
+};
+#define CRK_ALGORITM_MIN	0
+#define CRK_MOD_EXP		0
+#define CRK_MOD_EXP_CRT		1
+#define CRK_DSA_SIGN		2
+#define CRK_DSA_VERIFY		3
+#define CRK_DH_COMPUTE_KEY	4
+#define CRK_ALGORITHM_MAX	4 /* Keep updated - see below */
+
+#define CRF_MOD_EXP		(1 << CRK_MOD_EXP)
+#define CRF_MOD_EXP_CRT		(1 << CRK_MOD_EXP_CRT)
+#define CRF_DSA_SIGN		(1 << CRK_DSA_SIGN)
+#define CRF_DSA_VERIFY		(1 << CRK_DSA_VERIFY)
+#define CRF_DH_COMPUTE_KEY	(1 << CRK_DH_COMPUTE_KEY)
+
+/*
+ * done against open of /dev/crypto, to get a cloned descriptor.
+ * Please use F_SETFD against the cloned descriptor.
+ */
+#define CRIOGET		_IOWR('c', 100, u_int32_t)
+#define CRIOASYMFEAT	CIOCASYMFEAT
+#define CRIOFINDDEV	CIOCFINDDEV
+
+/* the following are done against the cloned descriptor */
+#define CIOCGSESSION	_IOWR('c', 101, struct session_op)
+#define CIOCFSESSION	_IOW('c', 102, u_int32_t)
+#define CIOCCRYPT	_IOWR('c', 103, struct crypt_op)
+#define CIOCKEY		_IOWR('c', 104, struct crypt_kop)
+#define CIOCASYMFEAT	_IOR('c', 105, u_int32_t)
+#define CIOCGSESSION2	_IOWR('c', 106, struct session2_op)
+#define CIOCKEY2	_IOWR('c', 107, struct crypt_kop)
+#define CIOCFINDDEV	_IOWR('c', 108, struct crypt_find_op)
+
+struct cryptotstat {
+	struct timespec	acc;		/* total accumulated time */
+	struct timespec	min;		/* min time */
+	struct timespec	max;		/* max time */
+	u_int32_t	count;		/* number of observations */
+};
+
+struct cryptostats {
+	u_int32_t	cs_ops;		/* symmetric crypto ops submitted */
+	u_int32_t	cs_errs;	/* symmetric crypto ops that failed */
+	u_int32_t	cs_kops;	/* asymetric/key ops submitted */
+	u_int32_t	cs_kerrs;	/* asymetric/key ops that failed */
+	u_int32_t	cs_intrs;	/* crypto swi thread activations */
+	u_int32_t	cs_rets;	/* crypto return thread activations */
+	u_int32_t	cs_blocks;	/* symmetric op driver block */
+	u_int32_t	cs_kblocks;	/* symmetric op driver block */
+	/*
+	 * When CRYPTO_TIMING is defined at compile time and the
+	 * sysctl debug.crypto is set to 1, the crypto system will
+	 * accumulate statistics about how long it takes to process
+	 * crypto requests at various points during processing.
+	 */
+	struct cryptotstat cs_invoke;	/* crypto_dipsatch -> crypto_invoke */
+	struct cryptotstat cs_done;	/* crypto_invoke -> crypto_done */
+	struct cryptotstat cs_cb;	/* crypto_done -> callback */
+	struct cryptotstat cs_finis;	/* callback -> callback return */
+
+	u_int32_t	cs_drops;		/* crypto ops dropped due to congestion */
+};
+
+#ifdef __KERNEL__
+
+/* Standard initialization structure beginning */
+struct cryptoini {
+	int		cri_alg;	/* Algorithm to use */
+	int		cri_flags;
+	union {
+		struct {
+			int		cri_mlen;	/* Number of bytes we want from the
+					   entire hash. 0 means all. */
+			int			cri_klen;	/* Key length, in bits */
+			caddr_t		cri_key;	/* key to use */
+			u_int8_t	cri_iv[EALG_MAX_BLOCK_LEN];	/* IV to use */
+		} cri_alg;
+		struct {
+			u_int32_t basealg;
+			struct sockaddr_in tun_source;
+			struct sockaddr_in tun_destination;
+			int tun_df_mode;
+			int tun_ds_mode;
+		 	int tun_ttl_value;
+		 	int tun_replay_windowsize;
+		 	int spivalue ;
+		 	int replayinit;  /* set to 0 to disable replay on receive */
+		 	u_int64_t time_hard_lifetime;
+		 	u_int64_t time_soft_lifetime;
+		 	u_int64_t byte_hard_lifetime;
+		 	u_int64_t byte_soft_lifetime;
+		} cri_pack;	
+	} u;
+	struct cryptoini *cri_next;
+};
+#define cri_mlen		u.cri_alg.cri_mlen
+#define cri_klen		u.cri_alg.cri_klen
+#define cri_key			u.cri_alg.cri_key
+#define cri_iv			u.cri_alg.cri_iv
+#define crip_basealg			u.cri_pack.basealg
+#define crip_tun_source 		u.cri_pack.tun_source
+#define crip_tun_destination	u.cri_pack.tun_destination
+#define crip_tun_df_mode		u.cri_pack.tun_df_mode
+#define crip_tun_ds_mode	u.cri_pack.tun_ds_mode
+#define crip_tun_ttl_value	u.cri_pack.tun_ttl_value
+#define crip_tun_replay_windowsize u.cri_pack.tun_replay_windowsize
+#define crip_spivalue 		u.cri_pack.spivalue
+#define crip_replayinit		u.cri_pack.replayinit
+#define crip_time_hard_lifetime 	 u.cri_pack.time_hard_lifetime
+#define crip_time_soft_lifetime 	 u.cri_pack.time_soft_lifetime
+#define crip_byte_hard_lifetime 	 u.cri_pack.byte_hard_lifetime
+#define crip_byte_soft_lifetime 	 u.cri_pack.byte_soft_lifetime
+
+/* Describe boundaries of a single crypto operation */
+struct cryptodesc {
+	int		crd_skip;	/* How many bytes to ignore from start */
+	int		crd_len;	/* How many bytes to process */
+	int		crd_inject;	/* Where to inject results, if applicable */
+	int		crd_flags;
+
+#define CRD_F_ENCRYPT		0x01	/* Set when doing encryption */
+#define CRD_F_IV_PRESENT	0x02	/* When encrypting, IV is already in
+					   place, so don't copy. */
+#define CRD_F_IV_EXPLICIT	0x04	/* IV explicitly provided */
+#define CRD_F_DSA_SHA_NEEDED	0x08	/* Compute SHA-1 of buffer for DSA */
+#define CRD_F_KEY_EXPLICIT	0x10	/* Key explicitly provided */
+#define CRD_F_COMP		0x0f    /* Set when doing compression */
+
+	struct cryptoini	CRD_INI; /* Initialization/context data */
+#define crd_iv		CRD_INI.cri_iv
+#define crd_key		CRD_INI.cri_key
+#define crd_alg		CRD_INI.cri_alg
+#define crd_klen	CRD_INI.cri_klen
+#define crd_mlen	CRD_INI.cri_mlen
+
+	struct cryptodesc *crd_next;
+};
+
+/* Structure describing complete operation */
+struct cryptop {
+	struct list_head crp_next;
+	wait_queue_head_t crp_waitq;
+
+	u_int64_t	crp_sid;	/* Session ID */
+	int		crp_ilen;	/* Input data total length */
+	int		crp_olen;	/* Result total length */
+
+	int		crp_etype;	/*
+					 * Error type (zero means no error).
+					 * All error codes except EAGAIN
+					 * indicate possible data corruption (as in,
+					 * the data have been touched). On all
+					 * errors, the crp_sid may have changed
+					 * (reset to a new one), so the caller
+					 * should always check and use the new
+					 * value on future requests.
+					 */
+	int		crp_flags;
+
+#define CRYPTO_F_SKBUF		0x0001	/* Input/output are skbuf chains */
+#define CRYPTO_F_IOV		0x0002	/* Input/output are uio */
+#define CRYPTO_F_REL		0x0004	/* Must return data in same place */
+#define CRYPTO_F_BATCH		0x0008	/* Batch op if possible */
+#define CRYPTO_F_CBIMM		0x0010	/* Do callback immediately */
+#define CRYPTO_F_DONE		0x0020	/* Operation completed */
+#define CRYPTO_F_CBIFSYNC	0x0040	/* Do CBIMM if op is synchronous */
+
+	caddr_t		crp_buf;	/* Data to be processed */
+	caddr_t		crp_out_buf;	/* Crypto Result Buffer */
+	caddr_t		crp_opaque;	/* Opaque pointer, passed along */
+	struct cryptodesc *crp_desc;	/* Linked list of processing descriptors */
+
+	int (*crp_callback)(struct cryptop *); /* Callback function */
+};
+enum crypto_packet_return_code {
+		CRYPTO_OK=0,
+		CRYPTO_SOFT_TTL = 2,
+ 		CRYPTO_HARD_TTL,
+ 		CRYPTO_SA_INACTIVE,
+ 		CRYPTO_REPLAY,
+ 		CRYPTO_ICV_FAIL,
+ 		CRYPTO_SEQ_ROLL,
+ 		CRYPTO_MEM_ERROR,
+ 		CRYPTO_VERS_ERROR,
+ 		CRYPTO_PROT_ERROR,
+ 		CRYPTO_PYLD_ERROR,
+ 		CRYPTO_PAD_ERROR 
+};
+
+enum crypto_accel_type {
+                  CRYPTO_PACKET  =0x2,    /* OR together desired bits */
+                  CRYPTO_HARDWARE=0x1,
+                  CRYPTO_SOFTWARE=0x0
+};
+
+enum crypto_flags {
+                  CRYPTO_ENCRYPT=0x1, 	// same for encap (OCF l2)
+                  CRYPTO_DECRYPT=0x2,		// same for decap (OCF l2)
+                  CRYPTO_MAC_GEN=0x4,
+                  CRYPTO_MAC_CHECK=0x08,
+                  CRYPTO_COMPRESS_SMALLER=0x10,
+                  CRYPTO_COMPRESS_BIGGER=0x20
+};
+
+#define CRYPTO_BUF_CONTIG	0x0
+#define CRYPTO_BUF_IOV		0x1
+#define CRYPTO_BUF_SKBUF		0x2
+
+#define CRYPTO_OP_DECRYPT	0x0
+#define CRYPTO_OP_ENCRYPT	0x1
+
+/*
+ * Hints passed to process methods.
+ */
+#define CRYPTO_HINT_MORE	0x1	/* more ops coming shortly */
+
+struct cryptkop {
+	struct list_head krp_next;
+	wait_queue_head_t krp_waitq;
+
+	int		krp_flags;
+#define CRYPTO_KF_DONE		0x0001	/* Operation completed */
+#define CRYPTO_KF_CBIMM		0x0002	/* Do callback immediately */
+
+	u_int		krp_op;		/* ie. CRK_MOD_EXP or other */
+	u_int		krp_status;	/* return status */
+	u_short		krp_iparams;	/* # of input parameters */
+	u_short		krp_oparams;	/* # of output parameters */
+	u_int		krp_crid;	/* desired device, etc. */
+	u_int32_t	krp_hid;
+	struct crparam	krp_param[CRK_MAXPARAM];	/* kvm */
+	int		(*krp_callback)(struct cryptkop *);
+};
+
+#include <ocf-compat.h>
+
+/*
+ * Session ids are 64 bits.  The lower 32 bits contain a "local id" which
+ * is a driver-private session identifier.  The upper 32 bits contain a
+ * "hardware id" used by the core crypto code to identify the driver and
+ * a copy of the driver's capabilities that can be used by client code to
+ * optimize operation.
+ */
+#define CRYPTO_SESID2HID(_sid)	(((_sid) >> 32) & 0x00ffffff)
+#define CRYPTO_SESID2CAPS(_sid)	(((_sid) >> 32) & 0xff000000)
+#define CRYPTO_SESID2LID(_sid)	(((u_int32_t) (_sid)) & 0xffffffff)
+
+extern	int crypto_newsession(u_int64_t *sid, struct cryptoini *cri, int hard);
+extern	int crypto_freesession(u_int64_t sid);
+#define CRYPTOCAP_F_HARDWARE	CRYPTO_FLAG_HARDWARE
+#define CRYPTOCAP_F_SOFTWARE	CRYPTO_FLAG_SOFTWARE
+#define CRYPTOCAP_F_SYNC	0x04000000	/* operates synchronously */
+extern	int32_t crypto_get_driverid(device_t dev, int flags);
+extern	int crypto_find_driver(const char *);
+extern	device_t crypto_find_device_byhid(int hid);
+extern	int crypto_getcaps(int hid);
+extern	int crypto_register(u_int32_t driverid, int alg, u_int16_t maxoplen,
+	    u_int32_t flags);
+extern	int crypto_kregister(u_int32_t, int, u_int32_t);
+extern	int crypto_unregister(u_int32_t driverid, int alg);
+extern	int crypto_unregister_all(u_int32_t driverid);
+extern	int crypto_dispatch(struct cryptop *crp);
+extern	int crypto_kdispatch(struct cryptkop *);
+#define CRYPTO_SYMQ	0x1
+#define CRYPTO_ASYMQ	0x2
+extern	int crypto_unblock(u_int32_t, int);
+extern	void crypto_done(struct cryptop *crp);
+extern	void crypto_kdone(struct cryptkop *);
+extern	int crypto_getfeat(int *);
+
+extern	void crypto_freereq(struct cryptop *crp);
+extern	struct cryptop *crypto_getreq(int num);
+
+extern  int crypto_usercrypto;      /* userland may do crypto requests */
+extern  int crypto_userasymcrypto;  /* userland may do asym crypto reqs */
+extern  int crypto_devallowsoft;    /* only use hardware crypto */
+
+/*
+ * random number support,  crypto_unregister_all will unregister
+ */
+extern int crypto_rregister(u_int32_t driverid,
+		int (*read_random)(void *arg, u_int32_t *buf, int len), void *arg);
+extern int crypto_runregister_all(u_int32_t driverid);
+
+/*
+ * Crypto-related utility routines used mainly by drivers.
+ *
+ * XXX these don't really belong here; but for now they're
+ *     kept apart from the rest of the system.
+ */
+struct uio;
+extern	void cuio_copydata(struct uio* uio, int off, int len, caddr_t cp);
+extern	void cuio_copyback(struct uio* uio, int off, int len, caddr_t cp);
+extern	struct iovec *cuio_getptr(struct uio *uio, int loc, int *off);
+
+extern	void crypto_copyback(int flags, caddr_t buf, int off, int size,
+	    caddr_t in);
+extern	void crypto_copydata(int flags, caddr_t buf, int off, int size,
+	    caddr_t out);
+extern	int crypto_apply(int flags, caddr_t buf, int off, int len,
+	    int (*f)(void *, void *, u_int), void *arg);
+
+#endif /* __KERNEL__ */
+#endif /* _CRYPTO_CRYPTO_H_ */
diff --git a/crypto/ocf/cryptosoft.c b/crypto/ocf/cryptosoft.c
new file mode 100644
index 0000000..aa2383d
--- /dev/null
+++ b/crypto/ocf/cryptosoft.c
@@ -0,0 +1,1322 @@
+/*
+ * An OCF module that uses the linux kernel cryptoapi, based on the
+ * original cryptosoft for BSD by Angelos D. Keromytis (angelos@cis.upenn.edu)
+ * but is mostly unrecognisable,
+ *
+ * Written by David McCullough <david_mccullough@mcafee.com>
+ * Copyright (C) 2004-2011 David McCullough
+ * Copyright (C) 2004-2005 Intel Corporation.
+ *
+ * LICENSE TERMS
+ *
+ * The free distribution and use of this software in both source and binary
+ * form is allowed (with or without changes) provided that:
+ *
+ *   1. distributions of this source code include the above copyright
+ *      notice, this list of conditions and the following disclaimer;
+ *
+ *   2. distributions in binary form include the above copyright
+ *      notice, this list of conditions and the following disclaimer
+ *      in the documentation and/or other associated materials;
+ *
+ *   3. the copyright holder's name is not used to endorse products
+ *      built using this software without specific written permission.
+ *
+ * ALTERNATIVELY, provided that this notice is retained in full, this product
+ * may be distributed under the terms of the GNU General Public License (GPL),
+ * in which case the provisions of the GPL apply INSTEAD OF those given above.
+ *
+ * DISCLAIMER
+ *
+ * This software is provided 'as is' with no explicit or implied warranties
+ * in respect of its properties, including, but not limited to, correctness
+ * and/or fitness for purpose.
+ * ---------------------------------------------------------------------------
+ */
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED)
+#include <linux/config.h>
+#endif
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/crypto.h>
+#include <linux/mm.h>
+#include <linux/skbuff.h>
+#include <linux/random.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
+#include <linux/scatterlist.h>
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+#include <crypto/hash.h>
+#endif
+
+#include <cryptodev.h>
+#include <uio.h>
+
+struct {
+	softc_device_decl	sc_dev;
+} swcr_softc;
+
+#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK)
+
+#define SW_TYPE_CIPHER		0x01
+#define SW_TYPE_HMAC		0x02
+#define SW_TYPE_HASH		0x04
+#define SW_TYPE_COMP		0x08
+#define SW_TYPE_BLKCIPHER	0x10
+#define SW_TYPE_ALG_MASK	0x1f
+
+#define SW_TYPE_ASYNC		0x8000
+
+#define SW_TYPE_INUSE		0x10000000
+
+/* We change some of the above if we have an async interface */
+
+#define SW_TYPE_ALG_AMASK	(SW_TYPE_ALG_MASK | SW_TYPE_ASYNC)
+
+#define SW_TYPE_ABLKCIPHER	(SW_TYPE_BLKCIPHER | SW_TYPE_ASYNC)
+#define SW_TYPE_AHASH		(SW_TYPE_HASH | SW_TYPE_ASYNC)
+#define SW_TYPE_AHMAC		(SW_TYPE_HMAC | SW_TYPE_ASYNC)
+
+#define SCATTERLIST_MAX 16
+
+struct swcr_data {
+	struct work_struct  workq;
+	int					sw_type;
+	int					sw_alg;
+	struct crypto_tfm	*sw_tfm;
+	spinlock_t			sw_tfm_lock;
+	union {
+		struct {
+			char *sw_key;
+			int  sw_klen;
+			int  sw_mlen;
+		} hmac;
+		void *sw_comp_buf;
+	} u;
+	struct swcr_data	*sw_next;
+};
+
+struct swcr_req {
+	struct swcr_data	*sw_head;
+	struct swcr_data	*sw;
+	struct cryptop		*crp;
+	struct cryptodesc	*crd;
+	struct scatterlist	 sg[SCATTERLIST_MAX];
+	unsigned char		 iv[EALG_MAX_BLOCK_LEN];
+	char				 result[HASH_MAX_LEN];
+	void				*crypto_req;
+};
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+static kmem_cache_t *swcr_req_cache;
+#else
+static struct kmem_cache *swcr_req_cache;
+#endif
+
+#ifndef CRYPTO_TFM_MODE_CBC
+/*
+ * As of linux-2.6.21 this is no longer defined, and presumably no longer
+ * needed to be passed into the crypto core code.
+ */
+#define	CRYPTO_TFM_MODE_CBC	0
+#define	CRYPTO_TFM_MODE_ECB	0
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+	/*
+	 * Linux 2.6.19 introduced a new Crypto API, setup macro's to convert new
+	 * API into old API.
+	 */
+
+	/* Symmetric/Block Cipher */
+	struct blkcipher_desc
+	{
+		struct crypto_tfm *tfm;
+		void *info;
+	};
+	#define ecb(X)								#X , CRYPTO_TFM_MODE_ECB
+	#define cbc(X)								#X , CRYPTO_TFM_MODE_CBC
+	#define crypto_has_blkcipher(X, Y, Z)		crypto_alg_available(X, 0)
+	#define crypto_blkcipher_cast(X)			X
+	#define crypto_blkcipher_tfm(X)				X
+	#define crypto_alloc_blkcipher(X, Y, Z)		crypto_alloc_tfm(X, mode)
+	#define crypto_blkcipher_ivsize(X)			crypto_tfm_alg_ivsize(X)
+	#define crypto_blkcipher_blocksize(X)		crypto_tfm_alg_blocksize(X)
+	#define crypto_blkcipher_setkey(X, Y, Z)	crypto_cipher_setkey(X, Y, Z)
+	#define crypto_blkcipher_encrypt_iv(W, X, Y, Z)	\
+				crypto_cipher_encrypt_iv((W)->tfm, X, Y, Z, (u8 *)((W)->info))
+	#define crypto_blkcipher_decrypt_iv(W, X, Y, Z)	\
+				crypto_cipher_decrypt_iv((W)->tfm, X, Y, Z, (u8 *)((W)->info))
+	#define crypto_blkcipher_set_flags(x, y)	/* nop */
+	#define crypto_free_blkcipher(x)			crypto_free_tfm(x)
+	#define crypto_free_comp					crypto_free_tfm
+	#define crypto_free_hash					crypto_free_tfm
+
+	/* Hash/HMAC/Digest */
+	struct hash_desc
+	{
+		struct crypto_tfm *tfm;
+	};
+	#define hmac(X)							#X , 0
+	#define crypto_has_hash(X, Y, Z)		crypto_alg_available(X, 0)
+	#define crypto_hash_cast(X)				X
+	#define crypto_hash_tfm(X)				X
+	#define crypto_alloc_hash(X, Y, Z)		crypto_alloc_tfm(X, mode)
+	#define crypto_hash_digestsize(X)		crypto_tfm_alg_digestsize(X)
+	#define crypto_hash_digest(W, X, Y, Z)	\
+				crypto_digest_digest((W)->tfm, X, sg_num, Z)
+
+	/* Asymmetric Cipher */
+	#define crypto_has_cipher(X, Y, Z)		crypto_alg_available(X, 0)
+
+	/* Compression */
+	#define crypto_has_comp(X, Y, Z)		crypto_alg_available(X, 0)
+	#define crypto_comp_tfm(X)				X
+	#define crypto_comp_cast(X)				X
+	#define crypto_alloc_comp(X, Y, Z)		crypto_alloc_tfm(X, mode)
+	#define plain(X)	#X , 0
+#else
+	#define ecb(X)	"ecb(" #X ")" , 0
+	#define cbc(X)	"cbc(" #X ")" , 0
+	#define hmac(X)	"hmac(" #X ")" , 0
+	#define plain(X)	#X , 0
+#endif /* if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
+/* no ablkcipher in older kernels */
+#define crypto_alloc_ablkcipher(a,b,c)		(NULL)
+#define crypto_ablkcipher_tfm(x)			((struct crypto_tfm *)(x))
+#define crypto_ablkcipher_set_flags(a, b)	/* nop */
+#define crypto_ablkcipher_setkey(x, y, z)	(-EINVAL)
+#define	crypto_has_ablkcipher(a,b,c)		(0)
+#else
+#define	HAVE_ABLKCIPHER
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
+/* no ahash in older kernels */
+#define crypto_ahash_tfm(x)					((struct crypto_tfm *)(x))
+#define	crypto_alloc_ahash(a,b,c)			(NULL)
+#define	crypto_ahash_digestsize(x)			0
+#else
+#define	HAVE_AHASH
+#endif
+
+struct crypto_details {
+	char *alg_name;
+	int mode;
+	int sw_type;
+};
+
+static struct crypto_details crypto_details[] = {
+	[CRYPTO_DES_CBC]         = { cbc(des),          SW_TYPE_BLKCIPHER, },
+	[CRYPTO_3DES_CBC]        = { cbc(des3_ede),     SW_TYPE_BLKCIPHER, },
+	[CRYPTO_BLF_CBC]         = { cbc(blowfish),     SW_TYPE_BLKCIPHER, },
+	[CRYPTO_CAST_CBC]        = { cbc(cast5),        SW_TYPE_BLKCIPHER, },
+	[CRYPTO_SKIPJACK_CBC]    = { cbc(skipjack),     SW_TYPE_BLKCIPHER, },
+	[CRYPTO_MD5_HMAC]        = { hmac(md5),         SW_TYPE_HMAC, },
+	[CRYPTO_SHA1_HMAC]       = { hmac(sha1),        SW_TYPE_HMAC, },
+	[CRYPTO_RIPEMD160_HMAC]  = { hmac(ripemd160),   SW_TYPE_HMAC, },
+	[CRYPTO_MD5_KPDK]        = { plain(md5-kpdk),   SW_TYPE_HASH, },
+	[CRYPTO_SHA1_KPDK]       = { plain(sha1-kpdk),  SW_TYPE_HASH, },
+	[CRYPTO_AES_CBC]         = { cbc(aes),          SW_TYPE_BLKCIPHER, },
+	[CRYPTO_ARC4]            = { ecb(arc4),         SW_TYPE_BLKCIPHER, },
+	[CRYPTO_MD5]             = { plain(md5),        SW_TYPE_HASH, },
+	[CRYPTO_SHA1]            = { plain(sha1),       SW_TYPE_HASH, },
+	[CRYPTO_NULL_HMAC]       = { hmac(digest_null), SW_TYPE_HMAC, },
+	[CRYPTO_NULL_CBC]        = { cbc(cipher_null),  SW_TYPE_BLKCIPHER, },
+	[CRYPTO_DEFLATE_COMP]    = { plain(deflate),    SW_TYPE_COMP, },
+	[CRYPTO_SHA2_256_HMAC]   = { hmac(sha256),      SW_TYPE_HMAC, },
+	[CRYPTO_SHA2_384_HMAC]   = { hmac(sha384),      SW_TYPE_HMAC, },
+	[CRYPTO_SHA2_512_HMAC]   = { hmac(sha512),      SW_TYPE_HMAC, },
+	[CRYPTO_CAMELLIA_CBC]    = { cbc(camellia),     SW_TYPE_BLKCIPHER, },
+	[CRYPTO_SHA2_256]        = { plain(sha256),     SW_TYPE_HASH, },
+	[CRYPTO_SHA2_384]        = { plain(sha384),     SW_TYPE_HASH, },
+	[CRYPTO_SHA2_512]        = { plain(sha512),     SW_TYPE_HASH, },
+	[CRYPTO_RIPEMD160]       = { plain(ripemd160),  SW_TYPE_HASH, },
+};
+
+int32_t swcr_id = -1;
+module_param(swcr_id, int, 0444);
+MODULE_PARM_DESC(swcr_id, "Read-Only OCF ID for cryptosoft driver");
+
+int swcr_fail_if_compression_grows = 1;
+module_param(swcr_fail_if_compression_grows, int, 0644);
+MODULE_PARM_DESC(swcr_fail_if_compression_grows,
+                "Treat compression that results in more data as a failure");
+
+int swcr_no_ahash = 0;
+module_param(swcr_no_ahash, int, 0644);
+MODULE_PARM_DESC(swcr_no_ahash,
+                "Do not use async hash/hmac even if available");
+
+int swcr_no_ablk = 0;
+module_param(swcr_no_ablk, int, 0644);
+MODULE_PARM_DESC(swcr_no_ablk,
+                "Do not use async blk ciphers even if available");
+
+static struct swcr_data **swcr_sessions = NULL;
+static u_int32_t swcr_sesnum = 0;
+
+static	int swcr_process(device_t, struct cryptop *, int);
+static	int swcr_newsession(device_t, u_int32_t *, struct cryptoini *);
+static	int swcr_freesession(device_t, u_int64_t);
+
+static device_method_t swcr_methods = {
+	/* crypto device methods */
+	DEVMETHOD(cryptodev_newsession,	swcr_newsession),
+	DEVMETHOD(cryptodev_freesession,swcr_freesession),
+	DEVMETHOD(cryptodev_process,	swcr_process),
+};
+
+#define debug swcr_debug
+int swcr_debug = 0;
+module_param(swcr_debug, int, 0644);
+MODULE_PARM_DESC(swcr_debug, "Enable debug");
+
+static void swcr_process_req(struct swcr_req *req);
+
+/*
+ * somethings just need to be run with user context no matter whether
+ * the kernel compression libs use vmalloc/vfree for example.
+ */
+
+typedef struct {
+	struct work_struct wq;
+	void	(*func)(void *arg);
+	void	*arg;
+} execute_later_t;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+static void
+doing_it_now(struct work_struct *wq)
+{
+	execute_later_t *w = container_of(wq, execute_later_t, wq);
+	(w->func)(w->arg);
+	kfree(w);
+}
+#else
+static void
+doing_it_now(void *arg)
+{
+	execute_later_t *w = (execute_later_t *) arg;
+	(w->func)(w->arg);
+	kfree(w);
+}
+#endif
+
+static void
+execute_later(void (fn)(void *), void *arg)
+{
+	execute_later_t *w;
+
+	w = (execute_later_t *) kmalloc(sizeof(execute_later_t), SLAB_ATOMIC);
+	if (w) {
+		memset(w, '\0', sizeof(w));
+		w->func = fn;
+		w->arg = arg;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+		INIT_WORK(&w->wq, doing_it_now);
+#else
+		INIT_WORK(&w->wq, doing_it_now, w);
+#endif
+		schedule_work(&w->wq);
+	}
+}
+
+/*
+ * Generate a new software session.
+ */
+static int
+swcr_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri)
+{
+	struct swcr_data **swd;
+	u_int32_t i;
+	int error;
+	char *algo;
+	int mode;
+
+	dprintk("%s()\n", __FUNCTION__);
+	if (sid == NULL || cri == NULL) {
+		dprintk("%s,%d - EINVAL\n", __FILE__, __LINE__);
+		return EINVAL;
+	}
+
+	if (swcr_sessions) {
+		for (i = 1; i < swcr_sesnum; i++)
+			if (swcr_sessions[i] == NULL)
+				break;
+	} else
+		i = 1;		/* NB: to silence compiler warning */
+
+	if (swcr_sessions == NULL || i == swcr_sesnum) {
+		if (swcr_sessions == NULL) {
+			i = 1; /* We leave swcr_sessions[0] empty */
+			swcr_sesnum = CRYPTO_SW_SESSIONS;
+		} else
+			swcr_sesnum *= 2;
+
+		swd = kmalloc(swcr_sesnum * sizeof(struct swcr_data *), SLAB_ATOMIC);
+		if (swd == NULL) {
+			/* Reset session number */
+			if (swcr_sesnum == CRYPTO_SW_SESSIONS)
+				swcr_sesnum = 0;
+			else
+				swcr_sesnum /= 2;
+			dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
+			return ENOBUFS;
+		}
+		memset(swd, 0, swcr_sesnum * sizeof(struct swcr_data *));
+
+		/* Copy existing sessions */
+		if (swcr_sessions) {
+			memcpy(swd, swcr_sessions,
+			    (swcr_sesnum / 2) * sizeof(struct swcr_data *));
+			kfree(swcr_sessions);
+		}
+
+		swcr_sessions = swd;
+	}
+
+	swd = &swcr_sessions[i];
+	*sid = i;
+
+	while (cri) {
+		*swd = (struct swcr_data *) kmalloc(sizeof(struct swcr_data),
+				SLAB_ATOMIC);
+		if (*swd == NULL) {
+			swcr_freesession(NULL, i);
+			dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
+			return ENOBUFS;
+		}
+		memset(*swd, 0, sizeof(struct swcr_data));
+
+		if (cri->cri_alg < 0 ||
+				cri->cri_alg>=sizeof(crypto_details)/sizeof(crypto_details[0])){
+			printk("cryptosoft: Unknown algorithm 0x%x\n", cri->cri_alg);
+			swcr_freesession(NULL, i);
+			return EINVAL;
+		}
+
+		algo = crypto_details[cri->cri_alg].alg_name;
+		if (!algo || !*algo) {
+			printk("cryptosoft: Unsupported algorithm 0x%x\n", cri->cri_alg);
+			swcr_freesession(NULL, i);
+			return EINVAL;
+		}
+
+		mode = crypto_details[cri->cri_alg].mode;
+		(*swd)->sw_type = crypto_details[cri->cri_alg].sw_type;
+		(*swd)->sw_alg = cri->cri_alg;
+
+		spin_lock_init(&(*swd)->sw_tfm_lock);
+
+		/* Algorithm specific configuration */
+		switch (cri->cri_alg) {
+		case CRYPTO_NULL_CBC:
+			cri->cri_klen = 0; /* make it work with crypto API */
+			break;
+		default:
+			break;
+		}
+
+		if ((*swd)->sw_type & SW_TYPE_BLKCIPHER) {
+			dprintk("%s crypto_alloc_*blkcipher(%s, 0x%x)\n", __FUNCTION__,
+					algo, mode);
+
+			/* try async first */
+			(*swd)->sw_tfm = swcr_no_ablk ? NULL :
+					crypto_ablkcipher_tfm(crypto_alloc_ablkcipher(algo, 0, 0));
+			if ((*swd)->sw_tfm && !IS_ERR((*swd)->sw_tfm)) {
+				dprintk("%s %s cipher is async\n", __FUNCTION__, algo);
+				(*swd)->sw_type |= SW_TYPE_ASYNC;
+			} else {
+				(*swd)->sw_tfm = crypto_blkcipher_tfm(
+						crypto_alloc_blkcipher(algo, 0, CRYPTO_ALG_ASYNC));
+				if ((*swd)->sw_tfm && !IS_ERR((*swd)->sw_tfm))
+					dprintk("%s %s cipher is sync\n", __FUNCTION__, algo);
+			}
+			if (!(*swd)->sw_tfm || IS_ERR((*swd)->sw_tfm)) {
+				int err;
+				dprintk("cryptosoft: crypto_alloc_blkcipher failed(%s, 0x%x)\n",
+						algo,mode);
+				err = IS_ERR((*swd)->sw_tfm) ? -(PTR_ERR((*swd)->sw_tfm)) : EINVAL;
+				(*swd)->sw_tfm = NULL; /* ensure NULL */
+				swcr_freesession(NULL, i);
+				return err;
+			}
+
+			if (debug) {
+				dprintk("%s key:cri->cri_klen=%d,(cri->cri_klen + 7)/8=%d",
+						__FUNCTION__, cri->cri_klen, (cri->cri_klen + 7) / 8);
+				for (i = 0; i < (cri->cri_klen + 7) / 8; i++)
+					dprintk("%s0x%x", (i % 8) ? " " : "\n    ",
+							cri->cri_key[i] & 0xff);
+				dprintk("\n");
+			}
+			if ((*swd)->sw_type & SW_TYPE_ASYNC) {
+				/* OCF doesn't enforce keys */
+				crypto_ablkcipher_set_flags(
+						__crypto_ablkcipher_cast((*swd)->sw_tfm),
+							CRYPTO_TFM_REQ_WEAK_KEY);
+				error = crypto_ablkcipher_setkey(
+							__crypto_ablkcipher_cast((*swd)->sw_tfm),
+								cri->cri_key, (cri->cri_klen + 7) / 8);
+			} else {
+				/* OCF doesn't enforce keys */
+				crypto_blkcipher_set_flags(
+						crypto_blkcipher_cast((*swd)->sw_tfm),
+							CRYPTO_TFM_REQ_WEAK_KEY);
+				error = crypto_blkcipher_setkey(
+							crypto_blkcipher_cast((*swd)->sw_tfm),
+								cri->cri_key, (cri->cri_klen + 7) / 8);
+			}
+			if (error) {
+				printk("cryptosoft: setkey failed %d (crt_flags=0x%x)\n", error,
+						(*swd)->sw_tfm->crt_flags);
+				swcr_freesession(NULL, i);
+				return error;
+			}
+		} else if ((*swd)->sw_type & (SW_TYPE_HMAC | SW_TYPE_HASH)) {
+			dprintk("%s crypto_alloc_*hash(%s, 0x%x)\n", __FUNCTION__,
+					algo, mode);
+
+			/* try async first */
+			(*swd)->sw_tfm = swcr_no_ahash ? NULL :
+					crypto_ahash_tfm(crypto_alloc_ahash(algo, 0, 0));
+			if ((*swd)->sw_tfm) {
+				dprintk("%s %s hash is async\n", __FUNCTION__, algo);
+				(*swd)->sw_type |= SW_TYPE_ASYNC;
+			} else {
+				dprintk("%s %s hash is sync\n", __FUNCTION__, algo);
+				(*swd)->sw_tfm = crypto_hash_tfm(
+						crypto_alloc_hash(algo, 0, CRYPTO_ALG_ASYNC));
+			}
+
+			if (!(*swd)->sw_tfm) {
+				dprintk("cryptosoft: crypto_alloc_hash failed(%s,0x%x)\n",
+						algo, mode);
+				swcr_freesession(NULL, i);
+				return EINVAL;
+			}
+
+			(*swd)->u.hmac.sw_klen = (cri->cri_klen + 7) / 8;
+			(*swd)->u.hmac.sw_key = (char *)kmalloc((*swd)->u.hmac.sw_klen,
+					SLAB_ATOMIC);
+			if ((*swd)->u.hmac.sw_key == NULL) {
+				swcr_freesession(NULL, i);
+				dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
+				return ENOBUFS;
+			}
+			memcpy((*swd)->u.hmac.sw_key, cri->cri_key, (*swd)->u.hmac.sw_klen);
+			if (cri->cri_mlen) {
+				(*swd)->u.hmac.sw_mlen = cri->cri_mlen;
+			} else if ((*swd)->sw_type & SW_TYPE_ASYNC) {
+				(*swd)->u.hmac.sw_mlen = crypto_ahash_digestsize(
+						__crypto_ahash_cast((*swd)->sw_tfm));
+			} else  {
+				(*swd)->u.hmac.sw_mlen = crypto_hash_digestsize(
+						crypto_hash_cast((*swd)->sw_tfm));
+			}
+		} else if ((*swd)->sw_type & SW_TYPE_COMP) {
+			(*swd)->sw_tfm = crypto_comp_tfm(
+					crypto_alloc_comp(algo, 0, CRYPTO_ALG_ASYNC));
+			if (!(*swd)->sw_tfm) {
+				dprintk("cryptosoft: crypto_alloc_comp failed(%s,0x%x)\n",
+						algo, mode);
+				swcr_freesession(NULL, i);
+				return EINVAL;
+			}
+			(*swd)->u.sw_comp_buf = kmalloc(CRYPTO_MAX_DATA_LEN, SLAB_ATOMIC);
+			if ((*swd)->u.sw_comp_buf == NULL) {
+				swcr_freesession(NULL, i);
+				dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
+				return ENOBUFS;
+			}
+		} else {
+			printk("cryptosoft: Unhandled sw_type %d\n", (*swd)->sw_type);
+			swcr_freesession(NULL, i);
+			return EINVAL;
+		}
+
+		cri = cri->cri_next;
+		swd = &((*swd)->sw_next);
+	}
+	return 0;
+}
+
+/*
+ * Free a session.
+ */
+static int
+swcr_freesession(device_t dev, u_int64_t tid)
+{
+	struct swcr_data *swd;
+	u_int32_t sid = CRYPTO_SESID2LID(tid);
+
+	dprintk("%s()\n", __FUNCTION__);
+	if (sid > swcr_sesnum || swcr_sessions == NULL ||
+			swcr_sessions[sid] == NULL) {
+		dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
+		return(EINVAL);
+	}
+
+	/* Silently accept and return */
+	if (sid == 0)
+		return(0);
+
+	while ((swd = swcr_sessions[sid]) != NULL) {
+		swcr_sessions[sid] = swd->sw_next;
+		if (swd->sw_tfm) {
+			switch (swd->sw_type & SW_TYPE_ALG_AMASK) {
+#ifdef HAVE_AHASH
+			case SW_TYPE_AHMAC:
+			case SW_TYPE_AHASH:
+				crypto_free_ahash(__crypto_ahash_cast(swd->sw_tfm));
+				break;
+#endif
+#ifdef HAVE_ABLKCIPHER
+			case SW_TYPE_ABLKCIPHER:
+				crypto_free_ablkcipher(__crypto_ablkcipher_cast(swd->sw_tfm));
+				break;
+#endif
+			case SW_TYPE_BLKCIPHER:
+				crypto_free_blkcipher(crypto_blkcipher_cast(swd->sw_tfm));
+				break;
+			case SW_TYPE_HMAC:
+			case SW_TYPE_HASH:
+				crypto_free_hash(crypto_hash_cast(swd->sw_tfm));
+				break;
+			case SW_TYPE_COMP:
+				if (in_interrupt())
+					execute_later((void (*)(void *))crypto_free_comp, (void *)crypto_comp_cast(swd->sw_tfm));
+				else
+					crypto_free_comp(crypto_comp_cast(swd->sw_tfm));
+				break;
+			default:
+				crypto_free_tfm(swd->sw_tfm);
+				break;
+			}
+			swd->sw_tfm = NULL;
+		}
+		if (swd->sw_type & SW_TYPE_COMP) {
+			if (swd->u.sw_comp_buf)
+				kfree(swd->u.sw_comp_buf);
+		} else {
+			if (swd->u.hmac.sw_key)
+				kfree(swd->u.hmac.sw_key);
+		}
+		kfree(swd);
+	}
+	return 0;
+}
+
+static void swcr_process_req_complete(struct swcr_req *req)
+{
+	dprintk("%s()\n", __FUNCTION__);
+
+	if (req->sw->sw_type & SW_TYPE_INUSE) {
+		unsigned long flags;
+		spin_lock_irqsave(&req->sw->sw_tfm_lock, flags);
+		req->sw->sw_type &= ~SW_TYPE_INUSE;
+		spin_unlock_irqrestore(&req->sw->sw_tfm_lock, flags);
+	}
+
+	if (req->crp->crp_etype)
+		goto done;
+
+	switch (req->sw->sw_type & SW_TYPE_ALG_AMASK) {
+#if defined(HAVE_AHASH)
+	case SW_TYPE_AHMAC:
+	case SW_TYPE_AHASH:
+		crypto_copyback(req->crp->crp_flags, req->crp->crp_buf,
+				req->crd->crd_inject, req->sw->u.hmac.sw_mlen, req->result);
+		ahash_request_free(req->crypto_req);
+		break;
+#endif
+#if defined(HAVE_ABLKCIPHER)
+	case SW_TYPE_ABLKCIPHER:
+		ablkcipher_request_free(req->crypto_req);
+		break;
+#endif
+	case SW_TYPE_CIPHER:
+	case SW_TYPE_HMAC:
+	case SW_TYPE_HASH:
+	case SW_TYPE_COMP:
+	case SW_TYPE_BLKCIPHER:
+		break;
+	default:
+		req->crp->crp_etype = EINVAL;
+		goto done;
+	}
+
+	req->crd = req->crd->crd_next;
+	if (req->crd) {
+		swcr_process_req(req);
+		return;
+	}
+
+done:
+	dprintk("%s crypto_done %p\n", __FUNCTION__, req);
+	crypto_done(req->crp);
+	kmem_cache_free(swcr_req_cache, req);
+}
+
+#if defined(HAVE_ABLKCIPHER) || defined(HAVE_AHASH)
+static void swcr_process_callback(struct crypto_async_request *creq, int err)
+{
+	struct swcr_req *req = creq->data;
+
+	dprintk("%s()\n", __FUNCTION__);
+	if (err) {
+		if (err == -EINPROGRESS)
+			return;
+		dprintk("%s() fail %d\n", __FUNCTION__, -err);
+		req->crp->crp_etype = -err;
+	}
+
+	swcr_process_req_complete(req);
+}
+#endif /* defined(HAVE_ABLKCIPHER) || defined(HAVE_AHASH) */
+
+
+static void swcr_process_req(struct swcr_req *req)
+{
+	struct swcr_data *sw;
+	struct cryptop *crp = req->crp;
+	struct cryptodesc *crd = req->crd;
+	struct sk_buff *skb = (struct sk_buff *) crp->crp_buf;
+	struct uio *uiop = (struct uio *) crp->crp_buf;
+	int sg_num, sg_len, skip;
+
+	dprintk("%s()\n", __FUNCTION__);
+
+	/*
+	 * Find the crypto context.
+	 *
+	 * XXX Note that the logic here prevents us from having
+	 * XXX the same algorithm multiple times in a session
+	 * XXX (or rather, we can but it won't give us the right
+	 * XXX results). To do that, we'd need some way of differentiating
+	 * XXX between the various instances of an algorithm (so we can
+	 * XXX locate the correct crypto context).
+	 */
+	for (sw = req->sw_head; sw && sw->sw_alg != crd->crd_alg; sw = sw->sw_next)
+		;
+
+	/* No such context ? */
+	if (sw == NULL) {
+		crp->crp_etype = EINVAL;
+		dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
+		goto done;
+	}
+
+	/*
+	 * for some types we need to ensure only one user as info is stored in
+	 * the tfm during an operation that can get corrupted
+	 */
+	switch (sw->sw_type & SW_TYPE_ALG_AMASK) {
+#ifdef HAVE_AHASH
+	case SW_TYPE_AHMAC:
+	case SW_TYPE_AHASH:
+#endif
+	case SW_TYPE_HMAC:
+	case SW_TYPE_HASH: {
+		unsigned long flags;
+		spin_lock_irqsave(&sw->sw_tfm_lock, flags);
+		if (sw->sw_type & SW_TYPE_INUSE) {
+			spin_unlock_irqrestore(&sw->sw_tfm_lock, flags);
+			execute_later((void (*)(void *))swcr_process_req, (void *)req);
+			return;
+		}
+		sw->sw_type |= SW_TYPE_INUSE;
+		spin_unlock_irqrestore(&sw->sw_tfm_lock, flags);
+		} break;
+	}
+
+	req->sw = sw;
+	skip = crd->crd_skip;
+
+	/*
+	 * setup the SG list skip from the start of the buffer
+	 */
+	memset(req->sg, 0, sizeof(req->sg));
+	sg_init_table(req->sg, SCATTERLIST_MAX);
+	if (crp->crp_flags & CRYPTO_F_SKBUF) {
+		int i, len;
+
+		sg_num = 0;
+		sg_len = 0;
+
+		if (skip < skb_headlen(skb)) {
+			len = skb_headlen(skb) - skip;
+			if (len + sg_len > crd->crd_len)
+				len = crd->crd_len - sg_len;
+			sg_set_page(&req->sg[sg_num],
+				virt_to_page(skb->data + skip), len,
+				offset_in_page(skb->data + skip));
+			sg_len += len;
+			sg_num++;
+			skip = 0;
+		} else
+			skip -= skb_headlen(skb);
+
+		for (i = 0; sg_len < crd->crd_len &&
+					i < skb_shinfo(skb)->nr_frags &&
+					sg_num < SCATTERLIST_MAX; i++) {
+			if (skip < skb_shinfo(skb)->frags[i].size) {
+				len = skb_shinfo(skb)->frags[i].size - skip;
+				if (len + sg_len > crd->crd_len)
+					len = crd->crd_len - sg_len;
+				sg_set_page(&req->sg[sg_num],
+					skb_frag_page(&skb_shinfo(skb)->frags[i]),
+					len,
+					skb_shinfo(skb)->frags[i].page_offset + skip);
+				sg_len += len;
+				sg_num++;
+				skip = 0;
+			} else
+				skip -= skb_shinfo(skb)->frags[i].size;
+		}
+	} else if (crp->crp_flags & CRYPTO_F_IOV) {
+		int len;
+
+		sg_len = 0;
+		for (sg_num = 0; sg_len < crd->crd_len &&
+				sg_num < uiop->uio_iovcnt &&
+				sg_num < SCATTERLIST_MAX; sg_num++) {
+			if (skip <= uiop->uio_iov[sg_num].iov_len) {
+				len = uiop->uio_iov[sg_num].iov_len - skip;
+				if (len + sg_len > crd->crd_len)
+					len = crd->crd_len - sg_len;
+				sg_set_page(&req->sg[sg_num],
+					virt_to_page(uiop->uio_iov[sg_num].iov_base+skip),
+					len,
+					offset_in_page(uiop->uio_iov[sg_num].iov_base+skip));
+				sg_len += len;
+				skip = 0;
+			} else 
+				skip -= uiop->uio_iov[sg_num].iov_len;
+		}
+	} else {
+		sg_len = (crp->crp_ilen - skip);
+		if (sg_len > crd->crd_len)
+			sg_len = crd->crd_len;
+		sg_set_page(&req->sg[0], virt_to_page(crp->crp_buf + skip),
+			sg_len, offset_in_page(crp->crp_buf + skip));
+		sg_num = 1;
+	}
+	if (sg_num > 0)
+		sg_mark_end(&req->sg[sg_num-1]);
+
+	switch (sw->sw_type & SW_TYPE_ALG_AMASK) {
+
+#ifdef HAVE_AHASH
+	case SW_TYPE_AHMAC:
+	case SW_TYPE_AHASH:
+		{
+		int ret;
+
+		/* check we have room for the result */
+		if (crp->crp_ilen - crd->crd_inject < sw->u.hmac.sw_mlen) {
+			dprintk("cryptosoft: EINVAL crp_ilen=%d, len=%d, inject=%d "
+					"digestsize=%d\n", crp->crp_ilen, crd->crd_skip + sg_len,
+					crd->crd_inject, sw->u.hmac.sw_mlen);
+			crp->crp_etype = EINVAL;
+			goto done;
+		}
+
+		req->crypto_req =
+				ahash_request_alloc(__crypto_ahash_cast(sw->sw_tfm),GFP_ATOMIC);
+		if (!req->crypto_req) {
+			crp->crp_etype = ENOMEM;
+			dprintk("%s,%d: ENOMEM ahash_request_alloc", __FILE__, __LINE__);
+			goto done;
+		}
+
+		ahash_request_set_callback(req->crypto_req,
+				CRYPTO_TFM_REQ_MAY_BACKLOG, swcr_process_callback, req);
+
+		memset(req->result, 0, sizeof(req->result));
+
+		if (sw->sw_type & SW_TYPE_AHMAC)
+			crypto_ahash_setkey(__crypto_ahash_cast(sw->sw_tfm),
+					sw->u.hmac.sw_key, sw->u.hmac.sw_klen);
+		ahash_request_set_crypt(req->crypto_req, req->sg, req->result, sg_len);
+		ret = crypto_ahash_digest(req->crypto_req);
+		switch (ret) {
+		case -EINPROGRESS:
+		case -EBUSY:
+			return;
+		default:
+		case 0:
+			dprintk("hash OP %s %d\n", ret ? "failed" : "success", ret);
+			crp->crp_etype = ret;
+			goto done;
+		}
+		} break;
+#endif /* HAVE_AHASH */
+
+#ifdef HAVE_ABLKCIPHER
+	case SW_TYPE_ABLKCIPHER: {
+		int ret;
+		unsigned char *ivp = req->iv;
+		int ivsize = 
+			crypto_ablkcipher_ivsize(__crypto_ablkcipher_cast(sw->sw_tfm));
+
+		if (sg_len < crypto_ablkcipher_blocksize(
+				__crypto_ablkcipher_cast(sw->sw_tfm))) {
+			crp->crp_etype = EINVAL;
+			dprintk("%s,%d: EINVAL len %d < %d\n", __FILE__, __LINE__,
+					sg_len, crypto_ablkcipher_blocksize(
+						__crypto_ablkcipher_cast(sw->sw_tfm)));
+			goto done;
+		}
+
+		if (ivsize > sizeof(req->iv)) {
+			crp->crp_etype = EINVAL;
+			dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
+			goto done;
+		}
+
+		req->crypto_req = ablkcipher_request_alloc(
+				__crypto_ablkcipher_cast(sw->sw_tfm), GFP_ATOMIC);
+		if (!req->crypto_req) {
+			crp->crp_etype = ENOMEM;
+			dprintk("%s,%d: ENOMEM ablkcipher_request_alloc",
+					__FILE__, __LINE__);
+			goto done;
+		}
+
+		ablkcipher_request_set_callback(req->crypto_req,
+				CRYPTO_TFM_REQ_MAY_BACKLOG, swcr_process_callback, req);
+
+		if (crd->crd_flags & CRD_F_KEY_EXPLICIT) {
+			int i, error;
+
+			if (debug) {
+				dprintk("%s key:", __FUNCTION__);
+				for (i = 0; i < (crd->crd_klen + 7) / 8; i++)
+					dprintk("%s0x%x", (i % 8) ? " " : "\n    ",
+							crd->crd_key[i] & 0xff);
+				dprintk("\n");
+			}
+			/* OCF doesn't enforce keys */
+			crypto_ablkcipher_set_flags(__crypto_ablkcipher_cast(sw->sw_tfm),
+					CRYPTO_TFM_REQ_WEAK_KEY);
+			error = crypto_ablkcipher_setkey(
+						__crypto_ablkcipher_cast(sw->sw_tfm), crd->crd_key,
+						(crd->crd_klen + 7) / 8);
+			if (error) {
+				dprintk("cryptosoft: setkey failed %d (crt_flags=0x%x)\n",
+						error, sw->sw_tfm->crt_flags);
+				crp->crp_etype = -error;
+			}
+		}
+
+		if (crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */
+
+			if (crd->crd_flags & CRD_F_IV_EXPLICIT)
+				ivp = crd->crd_iv;
+			else
+				get_random_bytes(ivp, ivsize);
+			/*
+			 * do we have to copy the IV back to the buffer ?
+			 */
+			if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) {
+				crypto_copyback(crp->crp_flags, crp->crp_buf,
+						crd->crd_inject, ivsize, (caddr_t)ivp);
+			}
+			ablkcipher_request_set_crypt(req->crypto_req, req->sg, req->sg,
+					sg_len, ivp);
+			ret = crypto_ablkcipher_encrypt(req->crypto_req);
+
+		} else { /*decrypt */
+
+			if (crd->crd_flags & CRD_F_IV_EXPLICIT)
+				ivp = crd->crd_iv;
+			else
+				crypto_copydata(crp->crp_flags, crp->crp_buf,
+						crd->crd_inject, ivsize, (caddr_t)ivp);
+			ablkcipher_request_set_crypt(req->crypto_req, req->sg, req->sg,
+					sg_len, ivp);
+			ret = crypto_ablkcipher_decrypt(req->crypto_req);
+		}
+
+		switch (ret) {
+		case -EINPROGRESS:
+		case -EBUSY:
+			return;
+		default:
+		case 0:
+			dprintk("crypto OP %s %d\n", ret ? "failed" : "success", ret);
+			crp->crp_etype = ret;
+			goto done;
+		}
+		} break;
+#endif /* HAVE_ABLKCIPHER */
+
+	case SW_TYPE_BLKCIPHER: {
+		unsigned char iv[EALG_MAX_BLOCK_LEN];
+		unsigned char *ivp = iv;
+		struct blkcipher_desc desc;
+		int ivsize = crypto_blkcipher_ivsize(crypto_blkcipher_cast(sw->sw_tfm));
+
+		if (sg_len < crypto_blkcipher_blocksize(
+				crypto_blkcipher_cast(sw->sw_tfm))) {
+			crp->crp_etype = EINVAL;
+			dprintk("%s,%d: EINVAL len %d < %d\n", __FILE__, __LINE__,
+					sg_len, crypto_blkcipher_blocksize(
+						crypto_blkcipher_cast(sw->sw_tfm)));
+			goto done;
+		}
+
+		if (ivsize > sizeof(iv)) {
+			crp->crp_etype = EINVAL;
+			dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
+			goto done;
+		}
+
+		if (crd->crd_flags & CRD_F_KEY_EXPLICIT) {
+			int i, error;
+
+			if (debug) {
+				dprintk("%s key:", __FUNCTION__);
+				for (i = 0; i < (crd->crd_klen + 7) / 8; i++)
+					dprintk("%s0x%x", (i % 8) ? " " : "\n    ",
+							crd->crd_key[i] & 0xff);
+				dprintk("\n");
+			}
+			/* OCF doesn't enforce keys */
+			crypto_blkcipher_set_flags(crypto_blkcipher_cast(sw->sw_tfm),
+					CRYPTO_TFM_REQ_WEAK_KEY);
+			error = crypto_blkcipher_setkey(
+						crypto_blkcipher_cast(sw->sw_tfm), crd->crd_key,
+						(crd->crd_klen + 7) / 8);
+			if (error) {
+				dprintk("cryptosoft: setkey failed %d (crt_flags=0x%x)\n",
+						error, sw->sw_tfm->crt_flags);
+				crp->crp_etype = -error;
+			}
+		}
+
+		memset(&desc, 0, sizeof(desc));
+		desc.tfm = crypto_blkcipher_cast(sw->sw_tfm);
+
+		if (crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */
+
+			if (crd->crd_flags & CRD_F_IV_EXPLICIT) {
+				ivp = crd->crd_iv;
+			} else {
+				get_random_bytes(ivp, ivsize);
+			}
+			/*
+			 * do we have to copy the IV back to the buffer ?
+			 */
+			if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) {
+				crypto_copyback(crp->crp_flags, crp->crp_buf,
+						crd->crd_inject, ivsize, (caddr_t)ivp);
+			}
+			desc.info = ivp;
+			crypto_blkcipher_encrypt_iv(&desc, req->sg, req->sg, sg_len);
+
+		} else { /*decrypt */
+
+			if (crd->crd_flags & CRD_F_IV_EXPLICIT) {
+				ivp = crd->crd_iv;
+			} else {
+				crypto_copydata(crp->crp_flags, crp->crp_buf,
+						crd->crd_inject, ivsize, (caddr_t)ivp);
+			}
+			desc.info = ivp;
+			crypto_blkcipher_decrypt_iv(&desc, req->sg, req->sg, sg_len);
+		}
+		} break;
+
+	case SW_TYPE_HMAC:
+	case SW_TYPE_HASH:
+		{
+		char result[HASH_MAX_LEN];
+		struct hash_desc desc;
+
+		/* check we have room for the result */
+		if (crp->crp_ilen - crd->crd_inject < sw->u.hmac.sw_mlen) {
+			dprintk("cryptosoft: EINVAL crp_ilen=%d, len=%d, inject=%d "
+					"digestsize=%d\n", crp->crp_ilen, crd->crd_skip + sg_len,
+					crd->crd_inject, sw->u.hmac.sw_mlen);
+			crp->crp_etype = EINVAL;
+			goto done;
+		}
+
+		memset(&desc, 0, sizeof(desc));
+		desc.tfm = crypto_hash_cast(sw->sw_tfm);
+
+		memset(result, 0, sizeof(result));
+
+		if (sw->sw_type & SW_TYPE_HMAC) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+			crypto_hmac(sw->sw_tfm, sw->u.hmac.sw_key, &sw->u.hmac.sw_klen,
+					req->sg, sg_num, result);
+#else
+			crypto_hash_setkey(desc.tfm, sw->u.hmac.sw_key,
+					sw->u.hmac.sw_klen);
+			crypto_hash_digest(&desc, req->sg, sg_len, result);
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) */
+			
+		} else { /* SW_TYPE_HASH */
+			crypto_hash_digest(&desc, req->sg, sg_len, result);
+		}
+
+		crypto_copyback(crp->crp_flags, crp->crp_buf,
+				crd->crd_inject, sw->u.hmac.sw_mlen, result);
+		}
+		break;
+
+	case SW_TYPE_COMP: {
+		void *ibuf = NULL;
+		void *obuf = sw->u.sw_comp_buf;
+		int ilen = sg_len, olen = CRYPTO_MAX_DATA_LEN;
+		int ret = 0;
+
+		/*
+		 * we need to use an additional copy if there is more than one
+		 * input chunk since the kernel comp routines do not handle
+		 * SG yet.  Otherwise we just use the input buffer as is.
+		 * Rather than allocate another buffer we just split the tmp
+		 * buffer we already have.
+		 * Perhaps we should just use zlib directly ?
+		 */
+		if (sg_num > 1) {
+			int blk;
+
+			ibuf = obuf;
+			for (blk = 0; blk < sg_num; blk++) {
+				memcpy(obuf, sg_virt(&req->sg[blk]),
+						req->sg[blk].length);
+				obuf += req->sg[blk].length;
+			}
+			olen -= sg_len;
+		} else
+			ibuf = sg_virt(&req->sg[0]);
+
+		if (crd->crd_flags & CRD_F_ENCRYPT) { /* compress */
+			ret = crypto_comp_compress(crypto_comp_cast(sw->sw_tfm),
+					ibuf, ilen, obuf, &olen);
+			if (!ret && olen > crd->crd_len) {
+				dprintk("cryptosoft: ERANGE compress %d into %d\n",
+						crd->crd_len, olen);
+				if (swcr_fail_if_compression_grows)
+					ret = ERANGE;
+			}
+		} else { /* decompress */
+			ret = crypto_comp_decompress(crypto_comp_cast(sw->sw_tfm),
+					ibuf, ilen, obuf, &olen);
+			if (!ret && (olen + crd->crd_inject) > crp->crp_olen) {
+				dprintk("cryptosoft: ETOOSMALL decompress %d into %d, "
+						"space for %d,at offset %d\n",
+						crd->crd_len, olen, crp->crp_olen, crd->crd_inject);
+				ret = ETOOSMALL;
+			}
+		}
+		if (ret)
+			dprintk("%s,%d: ret = %d\n", __FILE__, __LINE__, ret);
+
+		/*
+		 * on success copy result back,
+		 * linux crpyto API returns -errno,  we need to fix that
+		 */
+		crp->crp_etype = ret < 0 ? -ret : ret;
+		if (ret == 0) {
+			/* copy back the result and return it's size */
+			crypto_copyback(crp->crp_flags, crp->crp_buf,
+					crd->crd_inject, olen, obuf);
+			crp->crp_olen = olen;
+		}
+		} break;
+
+	default:
+		/* Unknown/unsupported algorithm */
+		dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
+		crp->crp_etype = EINVAL;
+		goto done;
+	}
+
+done:
+	swcr_process_req_complete(req);
+}
+
+
+/*
+ * Process a crypto request.
+ */
+static int
+swcr_process(device_t dev, struct cryptop *crp, int hint)
+{
+	struct swcr_req *req = NULL;
+	u_int32_t lid;
+
+	dprintk("%s()\n", __FUNCTION__);
+	/* Sanity check */
+	if (crp == NULL) {
+		dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
+		return EINVAL;
+	}
+
+	crp->crp_etype = 0;
+
+	if (crp->crp_desc == NULL || crp->crp_buf == NULL) {
+		dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
+		crp->crp_etype = EINVAL;
+		goto done;
+	}
+
+	lid = crp->crp_sid & 0xffffffff;
+	if (lid >= swcr_sesnum || lid == 0 || swcr_sessions == NULL ||
+			swcr_sessions[lid] == NULL) {
+		crp->crp_etype = ENOENT;
+		dprintk("%s,%d: ENOENT\n", __FILE__, __LINE__);
+		goto done;
+	}
+
+	/*
+	 * do some error checking outside of the loop for SKB and IOV processing
+	 * this leaves us with valid skb or uiop pointers for later
+	 */
+	if (crp->crp_flags & CRYPTO_F_SKBUF) {
+		struct sk_buff *skb = (struct sk_buff *) crp->crp_buf;
+		if (skb_shinfo(skb)->nr_frags >= SCATTERLIST_MAX) {
+			printk("%s,%d: %d nr_frags > SCATTERLIST_MAX", __FILE__, __LINE__,
+					skb_shinfo(skb)->nr_frags);
+			goto done;
+		}
+	} else if (crp->crp_flags & CRYPTO_F_IOV) {
+		struct uio *uiop = (struct uio *) crp->crp_buf;
+		if (uiop->uio_iovcnt > SCATTERLIST_MAX) {
+			printk("%s,%d: %d uio_iovcnt > SCATTERLIST_MAX", __FILE__, __LINE__,
+					uiop->uio_iovcnt);
+			goto done;
+		}
+	}
+
+	/*
+	 * setup a new request ready for queuing
+	 */
+	req = kmem_cache_alloc(swcr_req_cache, SLAB_ATOMIC);
+	if (req == NULL) {
+		dprintk("%s,%d: ENOMEM\n", __FILE__, __LINE__);
+		crp->crp_etype = ENOMEM;
+		goto done;
+	}
+	memset(req, 0, sizeof(*req));
+
+	req->sw_head = swcr_sessions[lid];
+	req->crp = crp;
+	req->crd = crp->crp_desc;
+
+	swcr_process_req(req);
+	return 0;
+
+done:
+	crypto_done(crp);
+	if (req)
+		kmem_cache_free(swcr_req_cache, req);
+	return 0;
+}
+
+
+static int
+cryptosoft_init(void)
+{
+	int i, sw_type, mode;
+	char *algo;
+
+	dprintk("%s(%p)\n", __FUNCTION__, cryptosoft_init);
+
+	swcr_req_cache = kmem_cache_create("cryptosoft_req",
+				sizeof(struct swcr_req), 0, SLAB_HWCACHE_ALIGN, NULL
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+				, NULL
+#endif
+				);
+	if (!swcr_req_cache) {
+		printk("cryptosoft: failed to create request cache\n");
+		return -ENOENT;
+	}
+
+	softc_device_init(&swcr_softc, "cryptosoft", 0, swcr_methods);
+
+	swcr_id = crypto_get_driverid(softc_get_device(&swcr_softc),
+			CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_SYNC);
+	if (swcr_id < 0) {
+		printk("cryptosoft: Software crypto device cannot initialize!");
+		return -ENODEV;
+	}
+
+#define	REGISTER(alg) \
+		crypto_register(swcr_id, alg, 0,0)
+
+	for (i = 0; i < sizeof(crypto_details)/sizeof(crypto_details[0]); i++) {
+		int found;
+		
+		algo = crypto_details[i].alg_name;
+		if (!algo || !*algo) {
+			dprintk("%s:Algorithm %d not supported\n", __FUNCTION__, i);
+			continue;
+		}
+
+		mode = crypto_details[i].mode;
+		sw_type = crypto_details[i].sw_type;
+
+		found = 0;
+		switch (sw_type & SW_TYPE_ALG_MASK) {
+		case SW_TYPE_CIPHER:
+			found = crypto_has_cipher(algo, 0, CRYPTO_ALG_ASYNC);
+			break;
+		case SW_TYPE_HMAC:
+			found = crypto_has_hash(algo, 0, swcr_no_ahash?CRYPTO_ALG_ASYNC:0);
+			break;
+		case SW_TYPE_HASH:
+			found = crypto_has_hash(algo, 0, swcr_no_ahash?CRYPTO_ALG_ASYNC:0);
+			break;
+		case SW_TYPE_COMP:
+			found = crypto_has_comp(algo, 0, CRYPTO_ALG_ASYNC);
+			break;
+		case SW_TYPE_BLKCIPHER:
+			found = crypto_has_blkcipher(algo, 0, CRYPTO_ALG_ASYNC);
+			if (!found && !swcr_no_ablk)
+				found = crypto_has_ablkcipher(algo, 0, 0);
+			break;
+		}
+		if (found) {
+			REGISTER(i);
+		} else {
+			dprintk("%s:Algorithm Type %d not supported (algorithm %d:'%s')\n",
+					__FUNCTION__, sw_type, i, algo);
+		}
+	}
+	return 0;
+}
+
+static void
+cryptosoft_exit(void)
+{
+	dprintk("%s()\n", __FUNCTION__);
+	crypto_unregister_all(swcr_id);
+	swcr_id = -1;
+	kmem_cache_destroy(swcr_req_cache);
+}
+
+late_initcall(cryptosoft_init);
+module_exit(cryptosoft_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("David McCullough <david_mccullough@mcafee.com>");
+MODULE_DESCRIPTION("Cryptosoft (OCF module for kernel crypto)");
diff --git a/crypto/ocf/ocf-bench.c b/crypto/ocf/ocf-bench.c
new file mode 100644
index 0000000..f3fe9d0
--- /dev/null
+++ b/crypto/ocf/ocf-bench.c
@@ -0,0 +1,514 @@
+/*
+ * A loadable module that benchmarks the OCF crypto speed from kernel space.
+ *
+ * Copyright (C) 2004-2010 David McCullough <david_mccullough@mcafee.com>
+ *
+ * LICENSE TERMS
+ *
+ * The free distribution and use of this software in both source and binary
+ * form is allowed (with or without changes) provided that:
+ *
+ *   1. distributions of this source code include the above copyright
+ *      notice, this list of conditions and the following disclaimer;
+ *
+ *   2. distributions in binary form include the above copyright
+ *      notice, this list of conditions and the following disclaimer
+ *      in the documentation and/or other associated materials;
+ *
+ *   3. the copyright holder's name is not used to endorse products
+ *      built using this software without specific written permission.
+ *
+ * ALTERNATIVELY, provided that this notice is retained in full, this product
+ * may be distributed under the terms of the GNU General Public License (GPL),
+ * in which case the provisions of the GPL apply INSTEAD OF those given above.
+ *
+ * DISCLAIMER
+ *
+ * This software is provided 'as is' with no explicit or implied warranties
+ * in respect of its properties, including, but not limited to, correctness
+ * and/or fitness for purpose.
+ */
+
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED)
+#include <linux/config.h>
+#endif
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <cryptodev.h>
+
+#ifdef I_HAVE_AN_XSCALE_WITH_INTEL_SDK
+#define BENCH_IXP_ACCESS_LIB 1
+#endif
+#ifdef BENCH_IXP_ACCESS_LIB
+#include <IxTypes.h>
+#include <IxOsBuffMgt.h>
+#include <IxNpeDl.h>
+#include <IxCryptoAcc.h>
+#include <IxQMgr.h>
+#include <IxOsServices.h>
+#include <IxOsCacheMMU.h>
+#endif
+
+/*
+ * support for access lib version 1.4
+ */
+#ifndef IX_MBUF_PRIV
+#define IX_MBUF_PRIV(x) ((x)->priv)
+#endif
+
+/*
+ * the number of simultaneously active requests
+ */
+static int request_q_len = 40;
+module_param(request_q_len, int, 0);
+MODULE_PARM_DESC(request_q_len, "Number of outstanding requests");
+
+/*
+ * how many requests we want to have processed
+ */
+static int request_num = 1024;
+module_param(request_num, int, 0);
+MODULE_PARM_DESC(request_num, "run for at least this many requests");
+
+/*
+ * the size of each request
+ */
+static int request_size = 1488;
+module_param(request_size, int, 0);
+MODULE_PARM_DESC(request_size, "size of each request");
+
+/*
+ * OCF batching of requests
+ */
+static int request_batch = 1;
+module_param(request_batch, int, 0);
+MODULE_PARM_DESC(request_batch, "enable OCF request batching");
+
+/*
+ * OCF immediate callback on completion
+ */
+static int request_cbimm = 1;
+module_param(request_cbimm, int, 0);
+MODULE_PARM_DESC(request_cbimm, "enable OCF immediate callback on completion");
+
+/*
+ * a structure for each request
+ */
+typedef struct  {
+	struct work_struct work;
+#ifdef BENCH_IXP_ACCESS_LIB
+	IX_MBUF mbuf;
+#endif
+	unsigned char *buffer;
+} request_t;
+
+static request_t *requests;
+
+static spinlock_t ocfbench_counter_lock;
+static int outstanding;
+static int total;
+
+/*************************************************************************/
+/*
+ * OCF benchmark routines
+ */
+
+static uint64_t ocf_cryptoid;
+static unsigned long jstart, jstop;
+
+static int ocf_init(void);
+static int ocf_cb(struct cryptop *crp);
+static void ocf_request(void *arg);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+static void ocf_request_wq(struct work_struct *work);
+#endif
+
+static int
+ocf_init(void)
+{
+	int error;
+	struct cryptoini crie, cria;
+	struct cryptodesc crda, crde;
+
+	memset(&crie, 0, sizeof(crie));
+	memset(&cria, 0, sizeof(cria));
+	memset(&crde, 0, sizeof(crde));
+	memset(&crda, 0, sizeof(crda));
+
+	cria.cri_alg  = CRYPTO_SHA1_HMAC;
+	cria.cri_klen = 20 * 8;
+	cria.cri_key  = "0123456789abcdefghij";
+
+	//crie.cri_alg  = CRYPTO_3DES_CBC;
+	crie.cri_alg  = CRYPTO_AES_CBC;
+	crie.cri_klen = 24 * 8;
+	crie.cri_key  = "0123456789abcdefghijklmn";
+
+	crie.cri_next = &cria;
+
+	error = crypto_newsession(&ocf_cryptoid, &crie,
+				CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE);
+	if (error) {
+		printk("crypto_newsession failed %d\n", error);
+		return -1;
+	}
+	return 0;
+}
+
+static int
+ocf_cb(struct cryptop *crp)
+{
+	request_t *r = (request_t *) crp->crp_opaque;
+	unsigned long flags;
+
+	if (crp->crp_etype)
+		printk("Error in OCF processing: %d\n", crp->crp_etype);
+	crypto_freereq(crp);
+	crp = NULL;
+
+	/* do all requests  but take at least 1 second */
+	spin_lock_irqsave(&ocfbench_counter_lock, flags);
+	total++;
+	if (total > request_num && jstart + HZ < jiffies) {
+		outstanding--;
+		spin_unlock_irqrestore(&ocfbench_counter_lock, flags);
+		return 0;
+	}
+	spin_unlock_irqrestore(&ocfbench_counter_lock, flags);
+
+	schedule_work(&r->work);
+	return 0;
+}
+
+
+static void
+ocf_request(void *arg)
+{
+	request_t *r = arg;
+	struct cryptop *crp = crypto_getreq(2);
+	struct cryptodesc *crde, *crda;
+	unsigned long flags;
+
+	if (!crp) {
+		spin_lock_irqsave(&ocfbench_counter_lock, flags);
+		outstanding--;
+		spin_unlock_irqrestore(&ocfbench_counter_lock, flags);
+		return;
+	}
+
+	crde = crp->crp_desc;
+	crda = crde->crd_next;
+
+	crda->crd_skip = 0;
+	crda->crd_flags = 0;
+	crda->crd_len = request_size;
+	crda->crd_inject = request_size;
+	crda->crd_alg = CRYPTO_SHA1_HMAC;
+	crda->crd_key = "0123456789abcdefghij";
+	crda->crd_klen = 20 * 8;
+
+	crde->crd_skip = 0;
+	crde->crd_flags = CRD_F_IV_EXPLICIT | CRD_F_ENCRYPT;
+	crde->crd_len = request_size;
+	crde->crd_inject = request_size;
+	//crde->crd_alg = CRYPTO_3DES_CBC;
+	crde->crd_alg = CRYPTO_AES_CBC;
+	crde->crd_key = "0123456789abcdefghijklmn";
+	crde->crd_klen = 24 * 8;
+
+	crp->crp_ilen = request_size + 64;
+	crp->crp_flags = 0;
+	if (request_batch)
+		crp->crp_flags |= CRYPTO_F_BATCH;
+	if (request_cbimm)
+		crp->crp_flags |= CRYPTO_F_CBIMM;
+	crp->crp_buf = (caddr_t) r->buffer;
+	crp->crp_callback = ocf_cb;
+	crp->crp_sid = ocf_cryptoid;
+	crp->crp_opaque = (caddr_t) r;
+	crypto_dispatch(crp);
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+static void
+ocf_request_wq(struct work_struct *work)
+{
+	request_t *r = container_of(work, request_t, work);
+	ocf_request(r);
+}
+#endif
+
+static void
+ocf_done(void)
+{
+	crypto_freesession(ocf_cryptoid);
+}
+
+/*************************************************************************/
+#ifdef BENCH_IXP_ACCESS_LIB
+/*************************************************************************/
+/*
+ * CryptoAcc benchmark routines
+ */
+
+static IxCryptoAccCtx ixp_ctx;
+static UINT32 ixp_ctx_id;
+static IX_MBUF ixp_pri;
+static IX_MBUF ixp_sec;
+static int ixp_registered = 0;
+
+static void ixp_register_cb(UINT32 ctx_id, IX_MBUF *bufp,
+					IxCryptoAccStatus status);
+static void ixp_perform_cb(UINT32 ctx_id, IX_MBUF *sbufp, IX_MBUF *dbufp,
+					IxCryptoAccStatus status);
+static void ixp_request(void *arg);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+static void ixp_request_wq(struct work_struct *work);
+#endif
+
+static int
+ixp_init(void)
+{
+	IxCryptoAccStatus status;
+
+	ixp_ctx.cipherCtx.cipherAlgo = IX_CRYPTO_ACC_CIPHER_3DES;
+	ixp_ctx.cipherCtx.cipherMode = IX_CRYPTO_ACC_MODE_CBC;
+	ixp_ctx.cipherCtx.cipherKeyLen = 24;
+	ixp_ctx.cipherCtx.cipherBlockLen = IX_CRYPTO_ACC_DES_BLOCK_64;
+	ixp_ctx.cipherCtx.cipherInitialVectorLen = IX_CRYPTO_ACC_DES_IV_64;
+	memcpy(ixp_ctx.cipherCtx.key.cipherKey, "0123456789abcdefghijklmn", 24);
+
+	ixp_ctx.authCtx.authAlgo = IX_CRYPTO_ACC_AUTH_SHA1;
+	ixp_ctx.authCtx.authDigestLen = 12;
+	ixp_ctx.authCtx.aadLen = 0;
+	ixp_ctx.authCtx.authKeyLen = 20;
+	memcpy(ixp_ctx.authCtx.key.authKey, "0123456789abcdefghij", 20);
+
+	ixp_ctx.useDifferentSrcAndDestMbufs = 0;
+	ixp_ctx.operation = IX_CRYPTO_ACC_OP_ENCRYPT_AUTH ;
+
+	IX_MBUF_MLEN(&ixp_pri)  = IX_MBUF_PKT_LEN(&ixp_pri) = 128;
+	IX_MBUF_MDATA(&ixp_pri) = (unsigned char *) kmalloc(128, SLAB_ATOMIC);
+	IX_MBUF_MLEN(&ixp_sec)  = IX_MBUF_PKT_LEN(&ixp_sec) = 128;
+	IX_MBUF_MDATA(&ixp_sec) = (unsigned char *) kmalloc(128, SLAB_ATOMIC);
+
+	status = ixCryptoAccCtxRegister(&ixp_ctx, &ixp_pri, &ixp_sec,
+			ixp_register_cb, ixp_perform_cb, &ixp_ctx_id);
+
+	if (IX_CRYPTO_ACC_STATUS_SUCCESS == status) {
+		while (!ixp_registered)
+			schedule();
+		return ixp_registered < 0 ? -1 : 0;
+	}
+
+	printk("ixp: ixCryptoAccCtxRegister failed %d\n", status);
+	return -1;
+}
+
+static void
+ixp_register_cb(UINT32 ctx_id, IX_MBUF *bufp, IxCryptoAccStatus status)
+{
+	if (bufp) {
+		IX_MBUF_MLEN(bufp) = IX_MBUF_PKT_LEN(bufp) = 0;
+		kfree(IX_MBUF_MDATA(bufp));
+		IX_MBUF_MDATA(bufp) = NULL;
+	}
+
+	if (IX_CRYPTO_ACC_STATUS_WAIT == status)
+		return;
+	if (IX_CRYPTO_ACC_STATUS_SUCCESS == status)
+		ixp_registered = 1;
+	else
+		ixp_registered = -1;
+}
+
+static void
+ixp_perform_cb(
+	UINT32 ctx_id,
+	IX_MBUF *sbufp,
+	IX_MBUF *dbufp,
+	IxCryptoAccStatus status)
+{
+	request_t *r = NULL;
+	unsigned long flags;
+
+	/* do all requests  but take at least 1 second */
+	spin_lock_irqsave(&ocfbench_counter_lock, flags);
+	total++;
+	if (total > request_num && jstart + HZ < jiffies) {
+		outstanding--;
+		spin_unlock_irqrestore(&ocfbench_counter_lock, flags);
+		return;
+	}
+
+	if (!sbufp || !(r = IX_MBUF_PRIV(sbufp))) {
+		printk("crappo %p %p\n", sbufp, r);
+		outstanding--;
+		spin_unlock_irqrestore(&ocfbench_counter_lock, flags);
+		return;
+	}
+	spin_unlock_irqrestore(&ocfbench_counter_lock, flags);
+
+	schedule_work(&r->work);
+}
+
+static void
+ixp_request(void *arg)
+{
+	request_t *r = arg;
+	IxCryptoAccStatus status;
+	unsigned long flags;
+
+	memset(&r->mbuf, 0, sizeof(r->mbuf));
+	IX_MBUF_MLEN(&r->mbuf) = IX_MBUF_PKT_LEN(&r->mbuf) = request_size + 64;
+	IX_MBUF_MDATA(&r->mbuf) = r->buffer;
+	IX_MBUF_PRIV(&r->mbuf) = r;
+	status = ixCryptoAccAuthCryptPerform(ixp_ctx_id, &r->mbuf, NULL,
+			0, request_size, 0, request_size, request_size, r->buffer);
+	if (IX_CRYPTO_ACC_STATUS_SUCCESS != status) {
+		printk("status1 = %d\n", status);
+		spin_lock_irqsave(&ocfbench_counter_lock, flags);
+		outstanding--;
+		spin_unlock_irqrestore(&ocfbench_counter_lock, flags);
+		return;
+	}
+	return;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+static void
+ixp_request_wq(struct work_struct *work)
+{
+	request_t *r = container_of(work, request_t, work);
+	ixp_request(r);
+}
+#endif
+
+static void
+ixp_done(void)
+{
+	/* we should free the session here but I am lazy :-) */
+}
+
+/*************************************************************************/
+#endif /* BENCH_IXP_ACCESS_LIB */
+/*************************************************************************/
+
+int
+ocfbench_init(void)
+{
+	int i;
+	unsigned long mbps;
+	unsigned long flags;
+
+	printk("Crypto Speed tests\n");
+
+	requests = kmalloc(sizeof(request_t) * request_q_len, GFP_KERNEL);
+	if (!requests) {
+		printk("malloc failed\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < request_q_len; i++) {
+		/* +64 for return data */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+		INIT_WORK(&requests[i].work, ocf_request_wq);
+#else
+		INIT_WORK(&requests[i].work, ocf_request, &requests[i]);
+#endif
+		requests[i].buffer = kmalloc(request_size + 128, GFP_DMA);
+		if (!requests[i].buffer) {
+			printk("malloc failed\n");
+			return -EINVAL;
+		}
+		memset(requests[i].buffer, '0' + i, request_size + 128);
+	}
+
+	/*
+	 * OCF benchmark
+	 */
+	printk("OCF: testing ...\n");
+	if (ocf_init() == -1)
+		return -EINVAL;
+
+	spin_lock_init(&ocfbench_counter_lock);
+	total = outstanding = 0;
+	jstart = jiffies;
+	for (i = 0; i < request_q_len; i++) {
+		spin_lock_irqsave(&ocfbench_counter_lock, flags);
+		outstanding++;
+		spin_unlock_irqrestore(&ocfbench_counter_lock, flags);
+		ocf_request(&requests[i]);
+	}
+	while (outstanding > 0)
+		schedule();
+	jstop = jiffies;
+
+	mbps = 0;
+	if (jstop > jstart) {
+		mbps = (unsigned long) total * (unsigned long) request_size * 8;
+		mbps /= ((jstop - jstart) * 1000) / HZ;
+	}
+	printk("OCF: %d requests of %d bytes in %d jiffies (%d.%03d Mbps)\n",
+			total, request_size, (int)(jstop - jstart),
+			((int)mbps) / 1000, ((int)mbps) % 1000);
+	ocf_done();
+
+#ifdef BENCH_IXP_ACCESS_LIB
+	/*
+	 * IXP benchmark
+	 */
+	printk("IXP: testing ...\n");
+	ixp_init();
+	total = outstanding = 0;
+	jstart = jiffies;
+	for (i = 0; i < request_q_len; i++) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+		INIT_WORK(&requests[i].work, ixp_request_wq);
+#else
+		INIT_WORK(&requests[i].work, ixp_request, &requests[i]);
+#endif
+		spin_lock_irqsave(&ocfbench_counter_lock, flags);
+		outstanding++;
+		spin_unlock_irqrestore(&ocfbench_counter_lock, flags);
+		ixp_request(&requests[i]);
+	}
+	while (outstanding > 0)
+		schedule();
+	jstop = jiffies;
+
+	mbps = 0;
+	if (jstop > jstart) {
+		mbps = (unsigned long) total * (unsigned long) request_size * 8;
+		mbps /= ((jstop - jstart) * 1000) / HZ;
+	}
+	printk("IXP: %d requests of %d bytes in %d jiffies (%d.%03d Mbps)\n",
+			total, request_size, jstop - jstart,
+			((int)mbps) / 1000, ((int)mbps) % 1000);
+	ixp_done();
+#endif /* BENCH_IXP_ACCESS_LIB */
+
+	for (i = 0; i < request_q_len; i++)
+		kfree(requests[i].buffer);
+	kfree(requests);
+	return -EINVAL; /* always fail to load so it can be re-run quickly ;-) */
+}
+
+static void __exit ocfbench_exit(void)
+{
+}
+
+module_init(ocfbench_init);
+module_exit(ocfbench_exit);
+
+MODULE_LICENSE("BSD");
+MODULE_AUTHOR("David McCullough <david_mccullough@mcafee.com>");
+MODULE_DESCRIPTION("Benchmark various in-kernel crypto speeds");
diff --git a/crypto/ocf/ocf-compat.h b/crypto/ocf/ocf-compat.h
new file mode 100644
index 0000000..4ad1223
--- /dev/null
+++ b/crypto/ocf/ocf-compat.h
@@ -0,0 +1,372 @@
+#ifndef _BSD_COMPAT_H_
+#define _BSD_COMPAT_H_ 1
+/****************************************************************************/
+/*
+ * Provide compat routines for older linux kernels and BSD kernels
+ *
+ * Written by David McCullough <david_mccullough@mcafee.com>
+ * Copyright (C) 2010 David McCullough <david_mccullough@mcafee.com>
+ *
+ * LICENSE TERMS
+ *
+ * The free distribution and use of this software in both source and binary
+ * form is allowed (with or without changes) provided that:
+ *
+ *   1. distributions of this source code include the above copyright
+ *      notice, this list of conditions and the following disclaimer;
+ *
+ *   2. distributions in binary form include the above copyright
+ *      notice, this list of conditions and the following disclaimer
+ *      in the documentation and/or other associated materials;
+ *
+ *   3. the copyright holder's name is not used to endorse products
+ *      built using this software without specific written permission.
+ *
+ * ALTERNATIVELY, provided that this notice is retained in full, this file
+ * may be distributed under the terms of the GNU General Public License (GPL),
+ * in which case the provisions of the GPL apply INSTEAD OF those given above.
+ *
+ * DISCLAIMER
+ *
+ * This software is provided 'as is' with no explicit or implied warranties
+ * in respect of its properties, including, but not limited to, correctness
+ * and/or fitness for purpose.
+ */
+/****************************************************************************/
+#ifdef __KERNEL__
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED)
+#include <linux/config.h>
+#endif
+
+/*
+ * fake some BSD driver interface stuff specifically for OCF use
+ */
+
+typedef struct ocf_device *device_t;
+
+typedef struct {
+	int (*cryptodev_newsession)(device_t dev, u_int32_t *sidp, struct cryptoini *cri);
+	int (*cryptodev_freesession)(device_t dev, u_int64_t tid);
+	int (*cryptodev_process)(device_t dev, struct cryptop *crp, int hint);
+	int (*cryptodev_kprocess)(device_t dev, struct cryptkop *krp, int hint);
+} device_method_t;
+#define DEVMETHOD(id, func)	id: func
+
+struct ocf_device {
+	char name[32];		/* the driver name */
+	char nameunit[32];	/* the driver name + HW instance */
+	int  unit;
+	device_method_t	methods;
+	void *softc;
+};
+
+#define CRYPTODEV_NEWSESSION(dev, sid, cri) \
+	((*(dev)->methods.cryptodev_newsession)(dev,sid,cri))
+#define CRYPTODEV_FREESESSION(dev, sid) \
+	((*(dev)->methods.cryptodev_freesession)(dev, sid))
+#define CRYPTODEV_PROCESS(dev, crp, hint) \
+	((*(dev)->methods.cryptodev_process)(dev, crp, hint))
+#define CRYPTODEV_KPROCESS(dev, krp, hint) \
+	((*(dev)->methods.cryptodev_kprocess)(dev, krp, hint))
+
+#define device_get_name(dev)	((dev)->name)
+#define device_get_nameunit(dev)	((dev)->nameunit)
+#define device_get_unit(dev)	((dev)->unit)
+#define device_get_softc(dev)	((dev)->softc)
+
+#define	softc_device_decl \
+		struct ocf_device _device; \
+		device_t
+
+#define	softc_device_init(_sc, _name, _unit, _methods) \
+	if (1) {\
+	strncpy((_sc)->_device.name, _name, sizeof((_sc)->_device.name) - 1); \
+	snprintf((_sc)->_device.nameunit, sizeof((_sc)->_device.name), "%s%d", _name, _unit); \
+	(_sc)->_device.unit = _unit; \
+	(_sc)->_device.methods = _methods; \
+	(_sc)->_device.softc = (void *) _sc; \
+	*(device_t *)((softc_get_device(_sc))+1) = &(_sc)->_device; \
+	} else
+
+#define	softc_get_device(_sc)	(&(_sc)->_device)
+
+/*
+ * iomem support for 2.4 and 2.6 kernels
+ */
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+#define ocf_iomem_t	unsigned long
+
+/*
+ * implement simple workqueue like support for older kernels
+ */
+
+#include <linux/tqueue.h>
+
+#define work_struct tq_struct
+
+#define INIT_WORK(wp, fp, ap) \
+	do { \
+		(wp)->sync = 0; \
+		(wp)->routine = (fp); \
+		(wp)->data = (ap); \
+	} while (0)
+
+#define schedule_work(wp) \
+	do { \
+		queue_task((wp), &tq_immediate); \
+		mark_bh(IMMEDIATE_BH); \
+	} while (0)
+
+#define flush_scheduled_work()	run_task_queue(&tq_immediate)
+
+#else
+#define ocf_iomem_t	void __iomem *
+
+#include <linux/workqueue.h>
+
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+#include <linux/fdtable.h>
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
+#define files_fdtable(files)	(files)
+#endif
+
+#ifdef MODULE_PARM
+#undef module_param	/* just in case */
+#define	module_param(a,b,c)		MODULE_PARM(a,"i")
+#endif
+
+#define bzero(s,l)		memset(s,0,l)
+#define bcopy(s,d,l)	memcpy(d,s,l)
+#define bcmp(x, y, l)	memcmp(x,y,l)
+
+#define MIN(x,y)	((x) < (y) ? (x) : (y))
+
+#define device_printf(dev, a...) ({ \
+				printk("%s: ", device_get_nameunit(dev)); printk(a); \
+			})
+
+#undef printf
+#define printf(fmt...)	printk(fmt)
+
+#define KASSERT(c,p)	if (!(c)) { printk p ; } else
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+#define ocf_daemonize(str) \
+	daemonize(); \
+	spin_lock_irq(&current->sigmask_lock); \
+	sigemptyset(&current->blocked); \
+	recalc_sigpending(current); \
+	spin_unlock_irq(&current->sigmask_lock); \
+	sprintf(current->comm, str);
+#else
+#define ocf_daemonize(str) daemonize(str);
+#endif
+
+#define	TAILQ_INSERT_TAIL(q,d,m) list_add_tail(&(d)->m, (q))
+#define	TAILQ_EMPTY(q)	list_empty(q)
+#define	TAILQ_FOREACH(v, q, m) list_for_each_entry(v, q, m)
+
+#define read_random(p,l) get_random_bytes(p,l)
+
+#define DELAY(x)	((x) > 2000 ? mdelay((x)/1000) : udelay(x))
+#define strtoul simple_strtoul
+
+#define pci_get_vendor(dev)	((dev)->vendor)
+#define pci_get_device(dev)	((dev)->device)
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+#define pci_set_consistent_dma_mask(dev, mask) (0)
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
+#define pci_dma_sync_single_for_cpu pci_dma_sync_single
+#endif
+
+#ifndef DMA_32BIT_MASK
+#define DMA_32BIT_MASK  0x00000000ffffffffULL
+#endif
+
+#ifndef htole32
+#define htole32(x)	cpu_to_le32(x)
+#endif
+#ifndef htobe32
+#define htobe32(x)	cpu_to_be32(x)
+#endif
+#ifndef htole16
+#define htole16(x)	cpu_to_le16(x)
+#endif
+#ifndef htobe16
+#define htobe16(x)	cpu_to_be16(x)
+#endif
+
+/* older kernels don't have these */
+
+#include <asm/irq.h>
+#if !defined(IRQ_NONE) && !defined(IRQ_RETVAL)
+#define IRQ_NONE
+#define IRQ_HANDLED
+#define IRQ_WAKE_THREAD
+#define IRQ_RETVAL
+#define irqreturn_t void
+typedef irqreturn_t (*irq_handler_t)(int irq, void *arg, struct pt_regs *regs);
+#endif
+#ifndef IRQF_SHARED
+#define IRQF_SHARED	SA_SHIRQ
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+# define strlcpy(dest,src,len) \
+		({strncpy(dest,src,(len)-1); ((char *)dest)[(len)-1] = '\0'; })
+#endif
+
+#ifndef MAX_ERRNO
+#define MAX_ERRNO	4095
+#endif
+#ifndef IS_ERR_VALUE
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,5)
+#include <linux/err.h>
+#endif
+#ifndef IS_ERR_VALUE
+#define IS_ERR_VALUE(x) ((unsigned long)(x) >= (unsigned long)-MAX_ERRNO)
+#endif
+#endif
+
+/*
+ * common debug for all
+ */
+#if 1
+#define dprintk(a...)	do { if (debug) printk(a); } while(0)
+#else
+#define dprintk(a...)
+#endif
+
+#ifndef SLAB_ATOMIC
+/* Changed in 2.6.20, must use GFP_ATOMIC now */
+#define	SLAB_ATOMIC	GFP_ATOMIC
+#endif
+
+/*
+ * need some additional support for older kernels */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,2)
+#define pci_register_driver_compat(driver, rc) \
+	do { \
+		if ((rc) > 0) { \
+			(rc) = 0; \
+		} else if (rc == 0) { \
+			(rc) = -ENODEV; \
+		} else { \
+			pci_unregister_driver(driver); \
+		} \
+	} while (0)
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
+#define pci_register_driver_compat(driver,rc) ((rc) = (rc) < 0 ? (rc) : 0)
+#else
+#define pci_register_driver_compat(driver,rc)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+
+#include <linux/mm.h>
+#include <asm/scatterlist.h>
+
+static inline void sg_set_page(struct scatterlist *sg,  struct page *page,
+			       unsigned int len, unsigned int offset)
+{
+	sg->page = page;
+	sg->offset = offset;
+	sg->length = len;
+}
+
+static inline void *sg_virt(struct scatterlist *sg)
+{
+	return page_address(sg->page) + sg->offset;
+}
+
+#define sg_init_table(sg, n)
+
+#define sg_mark_end(sg)
+
+#endif
+
+#ifndef late_initcall
+#define late_initcall(init) module_init(init)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4) || !defined(CONFIG_SMP)
+#define ocf_for_each_cpu(cpu) for ((cpu) = 0; (cpu) == 0; (cpu)++)
+#else
+#define ocf_for_each_cpu(cpu) for_each_present_cpu(cpu)
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+#include <linux/sched.h>
+#define	kill_proc(p,s,v)	send_sig(s,find_task_by_vpid(p),0)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4)
+
+struct ocf_thread {
+	struct task_struct	*task;
+	int					(*func)(void *arg);
+	void				*arg;
+};
+
+/* thread startup helper func */
+static inline int ocf_run_thread(void *arg)
+{
+	struct ocf_thread *t = (struct ocf_thread *) arg;
+	if (!t)
+		return -1; /* very bad */
+	t->task = current;
+	daemonize();
+	spin_lock_irq(&current->sigmask_lock);
+	sigemptyset(&current->blocked);
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+	return (*t->func)(t->arg);
+}
+
+#define kthread_create(f,a,fmt...) \
+	({ \
+		struct ocf_thread t; \
+		pid_t p; \
+		t.task = NULL; \
+		t.func = (f); \
+		t.arg = (a); \
+		p = kernel_thread(ocf_run_thread, &t, CLONE_FS|CLONE_FILES); \
+		while (p != (pid_t) -1 && t.task == NULL) \
+			schedule(); \
+		if (t.task) \
+			snprintf(t.task->comm, sizeof(t.task->comm), fmt); \
+		(t.task); \
+	})
+
+#define kthread_bind(t,cpu)	/**/
+
+#define kthread_should_stop()	(strcmp(current->comm, "stopping") == 0)
+
+#define kthread_stop(t) \
+	({ \
+		strcpy((t)->comm, "stopping"); \
+		kill_proc((t)->pid, SIGTERM, 1); \
+		do { \
+			schedule(); \
+		} while (kill_proc((t)->pid, SIGTERM, 1) == 0); \
+	})
+
+#else
+#include <linux/kthread.h>
+#endif
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0)
+#define	skb_frag_page(x)	((x)->page)
+#endif
+
+#endif /* __KERNEL__ */
+
+/****************************************************************************/
+#endif /* _BSD_COMPAT_H_ */
diff --git a/crypto/ocf/random.c b/crypto/ocf/random.c
new file mode 100644
index 0000000..4bb773f
--- /dev/null
+++ b/crypto/ocf/random.c
@@ -0,0 +1,317 @@
+/*
+ * A system independant way of adding entropy to the kernels pool
+ * this way the drivers can focus on the real work and we can take
+ * care of pushing it to the appropriate place in the kernel.
+ *
+ * This should be fast and callable from timers/interrupts
+ *
+ * Written by David McCullough <david_mccullough@mcafee.com>
+ * Copyright (C) 2006-2010 David McCullough
+ * Copyright (C) 2004-2005 Intel Corporation.
+ *
+ * LICENSE TERMS
+ *
+ * The free distribution and use of this software in both source and binary
+ * form is allowed (with or without changes) provided that:
+ *
+ *   1. distributions of this source code include the above copyright
+ *      notice, this list of conditions and the following disclaimer;
+ *
+ *   2. distributions in binary form include the above copyright
+ *      notice, this list of conditions and the following disclaimer
+ *      in the documentation and/or other associated materials;
+ *
+ *   3. the copyright holder's name is not used to endorse products
+ *      built using this software without specific written permission.
+ *
+ * ALTERNATIVELY, provided that this notice is retained in full, this product
+ * may be distributed under the terms of the GNU General Public License (GPL),
+ * in which case the provisions of the GPL apply INSTEAD OF those given above.
+ *
+ * DISCLAIMER
+ *
+ * This software is provided 'as is' with no explicit or implied warranties
+ * in respect of its properties, including, but not limited to, correctness
+ * and/or fitness for purpose.
+ */
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED)
+#include <linux/config.h>
+#endif
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/unistd.h>
+#include <linux/poll.h>
+#include <linux/random.h>
+#include <cryptodev.h>
+
+#ifdef CONFIG_OCF_FIPS
+#include "rndtest.h"
+#endif
+
+#ifndef HAS_RANDOM_INPUT_WAIT
+#error "Please do not enable OCF_RANDOMHARVEST unless you have applied patches"
+#endif
+
+/*
+ * a hack to access the debug levels from the crypto driver
+ */
+extern int crypto_debug;
+#define debug crypto_debug
+
+/*
+ * a list of all registered random providers
+ */
+static LIST_HEAD(random_ops);
+static int started = 0;
+static int initted = 0;
+
+struct random_op {
+	struct list_head random_list;
+	u_int32_t driverid;
+	int (*read_random)(void *arg, u_int32_t *buf, int len);
+	void *arg;
+};
+
+static int random_proc(void *arg);
+
+static pid_t		randomproc = (pid_t) -1;
+static spinlock_t	random_lock;
+
+/*
+ * just init the spin locks
+ */
+static int
+crypto_random_init(void)
+{
+	spin_lock_init(&random_lock);
+	initted = 1;
+	return(0);
+}
+
+/*
+ * Add the given random reader to our list (if not present)
+ * and start the thread (if not already started)
+ *
+ * we have to assume that driver id is ok for now
+ */
+int
+crypto_rregister(
+	u_int32_t driverid,
+	int (*read_random)(void *arg, u_int32_t *buf, int len),
+	void *arg)
+{
+	unsigned long flags;
+	int ret = 0;
+	struct random_op	*rops, *tmp;
+
+	dprintk("%s,%d: %s(0x%x, %p, %p)\n", __FILE__, __LINE__,
+			__FUNCTION__, driverid, read_random, arg);
+
+	if (!initted)
+		crypto_random_init();
+
+#if 0
+	struct cryptocap	*cap;
+
+	cap = crypto_checkdriver(driverid);
+	if (!cap)
+		return EINVAL;
+#endif
+
+	list_for_each_entry_safe(rops, tmp, &random_ops, random_list) {
+		if (rops->driverid == driverid && rops->read_random == read_random)
+			return EEXIST;
+	}
+
+	rops = (struct random_op *) kmalloc(sizeof(*rops), GFP_KERNEL);
+	if (!rops)
+		return ENOMEM;
+
+	rops->driverid    = driverid;
+	rops->read_random = read_random;
+	rops->arg = arg;
+
+	spin_lock_irqsave(&random_lock, flags);
+	list_add_tail(&rops->random_list, &random_ops);
+	if (!started) {
+		randomproc = kernel_thread(random_proc, NULL, CLONE_FS|CLONE_FILES);
+		if (randomproc < 0) {
+			ret = randomproc;
+			printk("crypto: crypto_rregister cannot start random thread; "
+					"error %d", ret);
+		} else
+			started = 1;
+	}
+	spin_unlock_irqrestore(&random_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(crypto_rregister);
+
+int
+crypto_runregister_all(u_int32_t driverid)
+{
+	struct random_op *rops, *tmp;
+	unsigned long flags;
+
+	dprintk("%s,%d: %s(0x%x)\n", __FILE__, __LINE__, __FUNCTION__, driverid);
+
+	list_for_each_entry_safe(rops, tmp, &random_ops, random_list) {
+		if (rops->driverid == driverid) {
+			list_del(&rops->random_list);
+			kfree(rops);
+		}
+	}
+
+	spin_lock_irqsave(&random_lock, flags);
+	if (list_empty(&random_ops) && started)
+		kill_proc(randomproc, SIGKILL, 1);
+	spin_unlock_irqrestore(&random_lock, flags);
+	return(0);
+}
+EXPORT_SYMBOL(crypto_runregister_all);
+
+/*
+ * while we can add entropy to random.c continue to read random data from
+ * the drivers and push it to random.
+ */
+static int
+random_proc(void *arg)
+{
+	int n;
+	int wantcnt;
+	int bufcnt = 0;
+	int retval = 0;
+	int *buf = NULL;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+	daemonize();
+	spin_lock_irq(&current->sigmask_lock);
+	sigemptyset(&current->blocked);
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+	sprintf(current->comm, "ocf-random");
+#else
+	daemonize("ocf-random");
+	allow_signal(SIGKILL);
+#endif
+
+	(void) get_fs();
+	set_fs(get_ds());
+
+#ifdef CONFIG_OCF_FIPS
+#define NUM_INT (RNDTEST_NBYTES/sizeof(int))
+#else
+#define NUM_INT 32
+#endif
+
+	/*
+	 * some devices can transferr their RNG data direct into memory,
+	 * so make sure it is device friendly
+	 */
+	buf = kmalloc(NUM_INT * sizeof(int), GFP_DMA);
+	if (NULL == buf) {
+		printk("crypto: RNG could not allocate memory\n");
+		retval = -ENOMEM;
+		goto bad_alloc;
+	}
+
+	wantcnt = NUM_INT;   /* start by adding some entropy */
+
+	/*
+	 * its possible due to errors or driver removal that we no longer
+	 * have anything to do,  if so exit or we will consume all the CPU
+	 * doing nothing
+	 */
+	while (!list_empty(&random_ops)) {
+		struct random_op	*rops, *tmp;
+
+#ifdef CONFIG_OCF_FIPS
+		if (wantcnt)
+			wantcnt = NUM_INT; /* FIPs mode can do 20000 bits or none */
+#endif
+
+		/* see if we can get enough entropy to make the world
+		 * a better place.
+		 */
+		while (bufcnt < wantcnt && bufcnt < NUM_INT) {
+			list_for_each_entry_safe(rops, tmp, &random_ops, random_list) {
+
+				n = (*rops->read_random)(rops->arg, &buf[bufcnt],
+							 NUM_INT - bufcnt);
+
+				/* on failure remove the random number generator */
+				if (n == -1) {
+					list_del(&rops->random_list);
+					printk("crypto: RNG (driverid=0x%x) failed, disabling\n",
+							rops->driverid);
+					kfree(rops);
+				} else if (n > 0)
+					bufcnt += n;
+			}
+			/* give up CPU for a bit, just in case as this is a loop */
+			schedule();
+		}
+
+
+#ifdef CONFIG_OCF_FIPS
+		if (bufcnt > 0 && rndtest_buf((unsigned char *) &buf[0])) {
+			dprintk("crypto: buffer had fips errors, discarding\n");
+			bufcnt = 0;
+		}
+#endif
+
+		/*
+		 * if we have a certified buffer,  we can send some data
+		 * to /dev/random and move along
+		 */
+		if (bufcnt > 0) {
+			/* add what we have */
+			random_input_words(buf, bufcnt, bufcnt*sizeof(int)*8);
+			bufcnt = 0;
+		}
+
+		/* give up CPU for a bit so we don't hog while filling */
+		schedule();
+
+		/* wait for needing more */
+		wantcnt = random_input_wait();
+
+		if (wantcnt <= 0)
+			wantcnt = 0; /* try to get some info again */
+		else
+		 	/* round up to one word or we can loop forever */
+			wantcnt = (wantcnt + (sizeof(int)*8)) / (sizeof(int)*8);
+		if (wantcnt > NUM_INT) {
+			wantcnt = NUM_INT;
+		}
+
+		if (signal_pending(current)) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+			spin_lock_irq(&current->sigmask_lock);
+#endif
+			flush_signals(current);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+			spin_unlock_irq(&current->sigmask_lock);
+#endif
+		}
+	}
+	
+	kfree(buf);
+
+bad_alloc:
+	spin_lock_irq(&random_lock);
+	randomproc = (pid_t) -1;
+	started = 0;
+	spin_unlock_irq(&random_lock);
+
+	return retval;
+}
+
diff --git a/crypto/ocf/rndtest.c b/crypto/ocf/rndtest.c
new file mode 100644
index 0000000..7bed6a1
--- /dev/null
+++ b/crypto/ocf/rndtest.c
@@ -0,0 +1,300 @@
+/*	$OpenBSD$	*/
+
+/*
+ * OCF/Linux port done by David McCullough <david_mccullough@mcafee.com>
+ * Copyright (C) 2006-2010 David McCullough
+ * Copyright (C) 2004-2005 Intel Corporation.
+ * The license and original author are listed below.
+ *
+ * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Jason L. Wright
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED)
+#include <linux/config.h>
+#endif
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+#include <linux/time.h>
+#include <linux/unistd.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/time.h>
+#include <cryptodev.h>
+#include "rndtest.h"
+
+static struct rndtest_stats rndstats;
+
+static	void rndtest_test(struct rndtest_state *);
+
+/* The tests themselves */
+static	int rndtest_monobit(struct rndtest_state *);
+static	int rndtest_runs(struct rndtest_state *);
+static	int rndtest_longruns(struct rndtest_state *);
+static	int rndtest_chi_4(struct rndtest_state *);
+
+static	int rndtest_runs_check(struct rndtest_state *, int, int *);
+static	void rndtest_runs_record(struct rndtest_state *, int, int *);
+
+static const struct rndtest_testfunc {
+	int (*test)(struct rndtest_state *);
+} rndtest_funcs[] = {
+	{ rndtest_monobit },
+	{ rndtest_runs },
+	{ rndtest_chi_4 },
+	{ rndtest_longruns },
+};
+
+#define	RNDTEST_NTESTS	(sizeof(rndtest_funcs)/sizeof(rndtest_funcs[0]))
+
+static void
+rndtest_test(struct rndtest_state *rsp)
+{
+	int i, rv = 0;
+
+	rndstats.rst_tests++;
+	for (i = 0; i < RNDTEST_NTESTS; i++)
+		rv |= (*rndtest_funcs[i].test)(rsp);
+	rsp->rs_discard = (rv != 0);
+}
+
+
+extern int crypto_debug;
+#define rndtest_verbose 2
+#define rndtest_report(rsp, failure, fmt, a...) \
+	{ if (failure || crypto_debug) { printk("rng_test: " fmt "\n", a); } else; }
+
+#define	RNDTEST_MONOBIT_MINONES	9725
+#define	RNDTEST_MONOBIT_MAXONES	10275
+
+static int
+rndtest_monobit(struct rndtest_state *rsp)
+{
+	int i, ones = 0, j;
+	u_int8_t r;
+
+	for (i = 0; i < RNDTEST_NBYTES; i++) {
+		r = rsp->rs_buf[i];
+		for (j = 0; j < 8; j++, r <<= 1)
+			if (r & 0x80)
+				ones++;
+	}
+	if (ones > RNDTEST_MONOBIT_MINONES &&
+	    ones < RNDTEST_MONOBIT_MAXONES) {
+		if (rndtest_verbose > 1)
+			rndtest_report(rsp, 0, "monobit pass (%d < %d < %d)",
+			    RNDTEST_MONOBIT_MINONES, ones,
+			    RNDTEST_MONOBIT_MAXONES);
+		return (0);
+	} else {
+		if (rndtest_verbose)
+			rndtest_report(rsp, 1,
+			    "monobit failed (%d ones)", ones);
+		rndstats.rst_monobit++;
+		return (-1);
+	}
+}
+
+#define	RNDTEST_RUNS_NINTERVAL	6
+
+static const struct rndtest_runs_tabs {
+	u_int16_t min, max;
+} rndtest_runs_tab[] = {
+	{ 2343, 2657 },
+	{ 1135, 1365 },
+	{ 542, 708 },
+	{ 251, 373 },
+	{ 111, 201 },
+	{ 111, 201 },
+};
+
+static int
+rndtest_runs(struct rndtest_state *rsp)
+{
+	int i, j, ones, zeros, rv = 0;
+	int onei[RNDTEST_RUNS_NINTERVAL], zeroi[RNDTEST_RUNS_NINTERVAL];
+	u_int8_t c;
+
+	bzero(onei, sizeof(onei));
+	bzero(zeroi, sizeof(zeroi));
+	ones = zeros = 0;
+	for (i = 0; i < RNDTEST_NBYTES; i++) {
+		c = rsp->rs_buf[i];
+		for (j = 0; j < 8; j++, c <<= 1) {
+			if (c & 0x80) {
+				ones++;
+				rndtest_runs_record(rsp, zeros, zeroi);
+				zeros = 0;
+			} else {
+				zeros++;
+				rndtest_runs_record(rsp, ones, onei);
+				ones = 0;
+			}
+		}
+	}
+	rndtest_runs_record(rsp, ones, onei);
+	rndtest_runs_record(rsp, zeros, zeroi);
+
+	rv |= rndtest_runs_check(rsp, 0, zeroi);
+	rv |= rndtest_runs_check(rsp, 1, onei);
+
+	if (rv)
+		rndstats.rst_runs++;
+
+	return (rv);
+}
+
+static void
+rndtest_runs_record(struct rndtest_state *rsp, int len, int *intrv)
+{
+	if (len == 0)
+		return;
+	if (len > RNDTEST_RUNS_NINTERVAL)
+		len = RNDTEST_RUNS_NINTERVAL;
+	len -= 1;
+	intrv[len]++;
+}
+
+static int
+rndtest_runs_check(struct rndtest_state *rsp, int val, int *src)
+{
+	int i, rv = 0;
+
+	for (i = 0; i < RNDTEST_RUNS_NINTERVAL; i++) {
+		if (src[i] < rndtest_runs_tab[i].min ||
+		    src[i] > rndtest_runs_tab[i].max) {
+			rndtest_report(rsp, 1,
+			    "%s interval %d failed (%d, %d-%d)",
+			    val ? "ones" : "zeros",
+			    i + 1, src[i], rndtest_runs_tab[i].min,
+			    rndtest_runs_tab[i].max);
+			rv = -1;
+		} else {
+			rndtest_report(rsp, 0,
+			    "runs pass %s interval %d (%d < %d < %d)",
+			    val ? "ones" : "zeros",
+			    i + 1, rndtest_runs_tab[i].min, src[i],
+			    rndtest_runs_tab[i].max);
+		}
+	}
+	return (rv);
+}
+
+static int
+rndtest_longruns(struct rndtest_state *rsp)
+{
+	int i, j, ones = 0, zeros = 0, maxones = 0, maxzeros = 0;
+	u_int8_t c;
+
+	for (i = 0; i < RNDTEST_NBYTES; i++) {
+		c = rsp->rs_buf[i];
+		for (j = 0; j < 8; j++, c <<= 1) {
+			if (c & 0x80) {
+				zeros = 0;
+				ones++;
+				if (ones > maxones)
+					maxones = ones;
+			} else {
+				ones = 0;
+				zeros++;
+				if (zeros > maxzeros)
+					maxzeros = zeros;
+			}
+		}
+	}
+
+	if (maxones < 26 && maxzeros < 26) {
+		rndtest_report(rsp, 0, "longruns pass (%d ones, %d zeros)",
+			maxones, maxzeros);
+		return (0);
+	} else {
+		rndtest_report(rsp, 1, "longruns fail (%d ones, %d zeros)",
+			maxones, maxzeros);
+		rndstats.rst_longruns++;
+		return (-1);
+	}
+}
+
+/*
+ * chi^2 test over 4 bits: (this is called the poker test in FIPS 140-2,
+ * but it is really the chi^2 test over 4 bits (the poker test as described
+ * by Knuth vol 2 is something different, and I take him as authoritative
+ * on nomenclature over NIST).
+ */
+#define	RNDTEST_CHI4_K	16
+#define	RNDTEST_CHI4_K_MASK	(RNDTEST_CHI4_K - 1)
+
+/*
+ * The unnormalized values are used so that we don't have to worry about
+ * fractional precision.  The "real" value is found by:
+ *	(V - 1562500) * (16 / 5000) = Vn   (where V is the unnormalized value)
+ */
+#define	RNDTEST_CHI4_VMIN	1563181		/* 2.1792 */
+#define	RNDTEST_CHI4_VMAX	1576929		/* 46.1728 */
+
+static int
+rndtest_chi_4(struct rndtest_state *rsp)
+{
+	unsigned int freq[RNDTEST_CHI4_K], i, sum;
+
+	for (i = 0; i < RNDTEST_CHI4_K; i++)
+		freq[i] = 0;
+
+	/* Get number of occurances of each 4 bit pattern */
+	for (i = 0; i < RNDTEST_NBYTES; i++) {
+		freq[(rsp->rs_buf[i] >> 4) & RNDTEST_CHI4_K_MASK]++;
+		freq[(rsp->rs_buf[i] >> 0) & RNDTEST_CHI4_K_MASK]++;
+	}
+
+	for (i = 0, sum = 0; i < RNDTEST_CHI4_K; i++)
+		sum += freq[i] * freq[i];
+
+	if (sum >= 1563181 && sum <= 1576929) {
+		rndtest_report(rsp, 0, "chi^2(4): pass (sum %u)", sum);
+		return (0);
+	} else {
+		rndtest_report(rsp, 1, "chi^2(4): failed (sum %u)", sum);
+		rndstats.rst_chi++;
+		return (-1);
+	}
+}
+
+int
+rndtest_buf(unsigned char *buf)
+{
+	struct rndtest_state rsp;
+
+	memset(&rsp, 0, sizeof(rsp));
+	rsp.rs_buf = buf;
+	rndtest_test(&rsp);
+	return(rsp.rs_discard);
+}
+
diff --git a/crypto/ocf/rndtest.h b/crypto/ocf/rndtest.h
new file mode 100644
index 0000000..e9d8ec8
--- /dev/null
+++ b/crypto/ocf/rndtest.h
@@ -0,0 +1,54 @@
+/*	$FreeBSD: src/sys/dev/rndtest/rndtest.h,v 1.1 2003/03/11 22:54:44 sam Exp $	*/
+/*	$OpenBSD$	*/
+
+/*
+ * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Jason L. Wright
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/* Some of the tests depend on these values */
+#define	RNDTEST_NBYTES	2500
+#define	RNDTEST_NBITS	(8 * RNDTEST_NBYTES)
+
+struct rndtest_state {
+	int		rs_discard;	/* discard/accept random data */
+	u_int8_t	*rs_buf;
+};
+
+struct rndtest_stats {
+	u_int32_t	rst_discard;	/* number of bytes discarded */
+	u_int32_t	rst_tests;	/* number of test runs */
+	u_int32_t	rst_monobit;	/* monobit test failures */
+	u_int32_t	rst_runs;	/* 0/1 runs failures */
+	u_int32_t	rst_longruns;	/* longruns failures */
+	u_int32_t	rst_chi;	/* chi^2 failures */
+};
+
+extern int rndtest_buf(unsigned char *buf);
diff --git a/crypto/ocf/uio.h b/crypto/ocf/uio.h
new file mode 100644
index 0000000..03a6249
--- /dev/null
+++ b/crypto/ocf/uio.h
@@ -0,0 +1,54 @@
+#ifndef _OCF_UIO_H_
+#define _OCF_UIO_H_
+
+#include <linux/uio.h>
+
+/*
+ * The linux uio.h doesn't have all we need.  To be fully api compatible
+ * with the BSD cryptodev,  we need to keep this around.  Perhaps this can
+ * be moved back into the linux/uio.h
+ *
+ * Linux port done by David McCullough <david_mccullough@mcafee.com>
+ * Copyright (C) 2006-2010 David McCullough
+ * Copyright (C) 2004-2005 Intel Corporation.
+ *
+ * LICENSE TERMS
+ *
+ * The free distribution and use of this software in both source and binary
+ * form is allowed (with or without changes) provided that:
+ *
+ *   1. distributions of this source code include the above copyright
+ *      notice, this list of conditions and the following disclaimer;
+ *
+ *   2. distributions in binary form include the above copyright
+ *      notice, this list of conditions and the following disclaimer
+ *      in the documentation and/or other associated materials;
+ *
+ *   3. the copyright holder's name is not used to endorse products
+ *      built using this software without specific written permission.
+ *
+ * ALTERNATIVELY, provided that this notice is retained in full, this product
+ * may be distributed under the terms of the GNU General Public License (GPL),
+ * in which case the provisions of the GPL apply INSTEAD OF those given above.
+ *
+ * DISCLAIMER
+ *
+ * This software is provided 'as is' with no explicit or implied warranties
+ * in respect of its properties, including, but not limited to, correctness
+ * and/or fitness for purpose.
+ * ---------------------------------------------------------------------------
+ */
+
+struct uio {
+	struct	iovec *uio_iov;
+	int		uio_iovcnt;
+	off_t	uio_offset;
+	int		uio_resid;
+#if 0
+	enum	uio_seg uio_segflg;
+	enum	uio_rw uio_rw;
+	struct  thread *uio_td;
+#endif
+};
+
+#endif
diff --git a/drivers/Kconfig b/drivers/Kconfig
index b5e6f24..e116562 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -52,6 +52,8 @@
 
 source "drivers/spi/Kconfig"
 
+source "drivers/spi2/Kconfig"
+
 source "drivers/pps/Kconfig"
 
 source "drivers/ptp/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 1b31421..2fc7c1c 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -53,6 +53,7 @@
 obj-$(CONFIG_TARGET_CORE)	+= target/
 obj-$(CONFIG_MTD)		+= mtd/
 obj-$(CONFIG_SPI)		+= spi/
+obj-$(CONFIG_SPI2)		+= spi2/
 obj-y				+= net/
 obj-$(CONFIG_ATM)		+= atm/
 obj-$(CONFIG_FUSION)		+= message/
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index b175000..c697159 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -357,4 +357,35 @@
 	return (cap & 0x1f) + 1;
 }
 
+#if defined (CONFIG_COMCERTO_AHCI_PROF)
+
+#define MAX_AHCI_PORTS		4
+#define MAX_AHCI_SLOTS		32
+#define MAX_BINS		64
+#define US_SHIFT		8
+#define BYTE_SHIFT		14
+#define RATE_SHIFT		2
+
+struct ahci_port_stats {
+	struct timeval first_issue;
+	unsigned int pending_flag;
+	unsigned int nb_pending;
+	unsigned int nb_pending_max;
+	unsigned int nb_pending_total;
+	unsigned int bytes_pending;
+	unsigned int diff_us;
+	unsigned int pending_counter[MAX_BINS];
+	unsigned int rate_counter[MAX_BINS];
+
+	unsigned int init_prof;
+	unsigned int time_counter[MAX_BINS]; // 128us -> 16ms
+	unsigned int data_counter[MAX_BINS]; // 4K-> 1020K
+	unsigned int no_free_slot;
+	struct timeval last_req;
+};
+
+extern struct ahci_port_stats ahci_port_stats[MAX_AHCI_PORTS];
+extern unsigned int enable_ahci_prof;
+#endif
+
 #endif /* _AHCI_H */
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 43b8758..d1d9d58 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -21,7 +21,21 @@
 #include <linux/platform_device.h>
 #include <linux/libata.h>
 #include <linux/ahci_platform.h>
+#include <linux/clk.h>
+#include <mach/reset.h>
+#include <mach/comcerto-2000/pm.h>
 #include "ahci.h"
+#include <mach/serdes-c2000.h>
+
+#ifdef CONFIG_ARCH_M86XXX 
+/* SATA Clocks */
+static struct clk *sata_oob_clk; /* Core clock */
+static struct clk *sata_pmu_clk; /* PMU alive clock */
+static struct clk *sata_clk;	/* Sata AXI ref clock */
+#if defined(CONFIG_COMCERTO_SATA_OCC_CLOCK)
+static struct clk *sata_occ_clk; /* sata OCC clock */
+#endif
+#endif 
 
 enum ahci_type {
 	AHCI,		/* standard platform ahci */
@@ -62,6 +76,91 @@
 	AHCI_SHT("ahci_platform"),
 };
 
+#ifdef CONFIG_PM
+static int ahci_platform_suspend(struct platform_device *pdev, pm_message_t state)
+{
+        struct ata_host *host = platform_get_drvdata(pdev);
+	int ret=0;
+
+#ifdef CONFIG_ARCH_M86XXX
+	 /* Check for the Bit_Mask bit for SATA, if it is enabled
+	  * then we are not going suspend the SATA device , as by
+	  * this device , we will wake from System Resume.
+	 */
+	if ( !(host_utilpe_shared_pmu_bitmask & SATA_IRQ )){
+
+                /* We will Just return
+                */
+		return ret;
+	}
+#endif
+
+        if (host)
+		ret = ata_host_suspend(host, state);
+
+#ifdef CONFIG_ARCH_M86XXX
+	if (!ret) /* sucessfully done the host suspend */
+	{
+		/* No do the clock disable PMU,OOB,AXI here */
+		clk_disable(sata_clk);
+		clk_disable(sata_oob_clk);
+		clk_disable(sata_pmu_clk);
+
+		/* PM Performance Enhancement : SRDS1 PD SATA1/SRDS2 PD SATA2 - P2 state, */
+		/* Resets the entire PHY module and CMU power down */
+		if (readl(COMCERTO_GPIO_SYSTEM_CONFIG) & BOOT_SERDES1_CNF_SATA0)
+			writel((readl((COMCERTO_DWC1_CFG_BASE+0x44)) | 0xCC), (COMCERTO_DWC1_CFG_BASE+0x44));
+		else if (readl(COMCERTO_GPIO_SYSTEM_CONFIG) & BOOT_SERDES2_CNF_SATA1)
+			writel((readl((COMCERTO_DWC1_CFG_BASE+0x54)) | 0xCC), (COMCERTO_DWC1_CFG_BASE+0x54));
+
+	}
+#endif
+	
+        return ret;
+}
+
+static int ahci_platform_resume(struct platform_device *pdev)
+{
+        struct ata_host *host = platform_get_drvdata(pdev);
+
+#ifdef CONFIG_ARCH_M86XXX
+	/* PM Performance Enhancement : SRDS1 PD SATA1/SRDS2 PD SATA2 - P2 state, */
+	/* Enable PHY module and CMU power UP */
+	if (readl(COMCERTO_GPIO_SYSTEM_CONFIG) & BOOT_SERDES1_CNF_SATA0)
+ 		writel((readl((COMCERTO_DWC1_CFG_BASE+0x44)) & ~0xCC), (COMCERTO_DWC1_CFG_BASE+0x44));
+	else if (readl(COMCERTO_GPIO_SYSTEM_CONFIG) & BOOT_SERDES2_CNF_SATA1)
+		writel((readl((COMCERTO_DWC1_CFG_BASE+0x54)) & ~0xCC), (COMCERTO_DWC1_CFG_BASE+0x54));
+
+	/* Check for the Bit_Mask bit for SATA, if it is enabled
+	 * then we are not going suspend the SATA device , as by
+	 * this device , we will wake from System Resume.
+	*/
+
+	if ( !(host_utilpe_shared_pmu_bitmask & SATA_IRQ )){
+
+                /* We will Just return
+                */
+		return 0;
+	}
+
+	/* Do the  clock enable here  PMU,OOB,AXI */
+	clk_enable(sata_clk);
+	clk_enable(sata_oob_clk);
+	clk_enable(sata_pmu_clk);
+#endif
+
+        if (host) 
+		ata_host_resume(host);
+
+	return 0;
+}
+#else
+#define ahci_platform_suspend NULL
+#define ahci_platform_resume NULL
+#endif
+
+
+
 static int __init ahci_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -76,7 +175,66 @@
 	int n_ports;
 	int i;
 	int rc;
+#ifdef CONFIG_ARCH_M86XXX
+	/* Get the Reference and Enable  the SATA clocks here */
 
+	sata_clk = clk_get(NULL,"sata");
+	/* Error Handling , if no SATA(AXI) clock reference: return error */
+	if (IS_ERR(sata_clk)) {
+		pr_err("%s: Unable to obtain SATA(AXI) clock: %ld\n",__func__,PTR_ERR(sata_clk));
+		return PTR_ERR(sata_clk);
+ 	}
+
+	/*Enable the SATA(AXI) clock here */
+        rc = clk_enable(sata_clk);
+	if (rc){
+		pr_err("%s: SATA(AXI) clock enable failed \n",__func__);
+                return rc;
+	}
+	sata_oob_clk = clk_get(NULL,"sata_oob");
+	/* Error Handling , if no SATA_OOB clock reference: return error */
+	if (IS_ERR(sata_oob_clk)) {
+		pr_err("%s: Unable to obtain SATA_OOB clock: %ld\n",__func__,PTR_ERR(sata_oob_clk));
+		return PTR_ERR(sata_oob_clk);
+ 	}
+
+	sata_pmu_clk = clk_get(NULL,"sata_pmu");
+	/* Error Handling , if no SATA_PMU clock reference: return error */
+	if (IS_ERR(sata_pmu_clk)) {
+		pr_err("%s: Unable to obtain SATA_PMU clock: %ld\n",__func__,PTR_ERR(sata_pmu_clk));
+		return PTR_ERR(sata_pmu_clk);
+	}
+	/*Enable the SATA(PMU and OOB) clocks here */
+        rc = clk_enable(sata_oob_clk);
+	if (rc){
+		pr_err("%s: SATA_OOB clock enable failed \n",__func__);
+                return rc;
+	}
+
+        rc = clk_enable(sata_pmu_clk);
+	if (rc){
+		pr_err("%s: SATA_PMU clock enable failed \n",__func__);
+		return rc;
+	}
+#if defined(CONFIG_COMCERTO_SATA_OCC_CLOCK)
+	sata_occ_clk = clk_get(NULL,"sata_occ");
+	/* Error Handling , if no sata occ clock reference: return error */
+	if (IS_ERR(sata_occ_clk)) {
+		pr_err("%s: Unable to obtain sata occ clock: %ld\n",__func__,PTR_ERR(sata_occ_clk));
+		return PTR_ERR(sata_occ_clk);
+ 	}
+	/*Enable the sata_occ clocks here */
+        rc = clk_enable(sata_occ_clk);
+	if (rc){
+		pr_err("%s: sata occ clock enable failed \n",__func__);
+		return rc;
+	}
+#endif
+	/* Set the SATA PMU clock to 30 MHZ and OOB clock to 125MHZ */
+	clk_set_rate(sata_oob_clk,125000000);
+	clk_set_rate(sata_pmu_clk,30000000);
+	
+#endif
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!mem) {
 		dev_err(dev, "no mmio space\n");
@@ -164,6 +322,12 @@
 		if (ap->flags & ATA_FLAG_EM)
 			ap->em_message_type = hpriv->em_msg_type;
 
+#ifdef CONFIG_ARCH_M86XXX
+		/* Optimized PFE/SATA DDR interaction,
+		limit read burst size of SATA controller */
+		writel(0x41, ahci_port_base(ap) + 0x70);
+#endif
+
 		/* disabled/not-implemented port */
 		if (!(hpriv->port_map & (1 << i)))
 			ap->ops = &ata_dummy_port_ops;
@@ -198,6 +362,31 @@
 
 	if (pdata && pdata->exit)
 		pdata->exit(dev);
+#ifdef CONFIG_ARCH_M86XXX
+	/* Disbale the SATA clocks Here */
+	clk_disable(sata_clk);
+	clk_put(sata_clk);
+	clk_disable(sata_oob_clk);
+	clk_put(sata_oob_clk);
+	clk_disable(sata_pmu_clk);
+	clk_put(sata_pmu_clk);
+#if defined(CONFIG_COMCERTO_SATA_OCC_CLOCK)
+	clk_disable(sata_occ_clk);
+	clk_put(sata_occ_clk);
+#endif
+	/*Putting  SATA in reset state 
+	 * Sata axi clock domain in reset state
+	 * Serdes 1/2 in reset state, this depends upon PCIE1 and SGMII 
+         * sata 0/1 serdes controller in reset state
+	*/
+	c2000_block_reset(COMPONENT_AXI_SATA,1);
+
+	c2000_block_reset(COMPONENT_SERDES1,1);
+	c2000_block_reset(COMPONENT_SERDES_SATA0,1);
+
+	c2000_block_reset(COMPONENT_SERDES2,1);
+	c2000_block_reset(COMPONENT_SERDES_SATA1,1);
+#endif
 
 	return 0;
 }
@@ -209,13 +398,17 @@
 MODULE_DEVICE_TABLE(of, ahci_of_match);
 
 static struct platform_driver ahci_driver = {
-	.remove = __devexit_p(ahci_remove),
-	.driver = {
-		.name = "ahci",
-		.owner = THIS_MODULE,
-		.of_match_table = ahci_of_match,
+	.remove  = __devexit_p(ahci_remove),
+#ifdef CONFIG_PM
+	.suspend = ahci_platform_suspend,
+	.resume  = ahci_platform_resume,
+#endif
+	.driver  = {
+		 .name = "ahci",
+		 .owner = THIS_MODULE,
+		 .of_match_table = ahci_of_match,
 	},
-	.id_table	= ahci_devtype,
+	.id_table = ahci_devtype,
 };
 
 static int __init ahci_init(void)
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 3c92dbd..a0e3c7c 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -1724,6 +1724,8 @@
 	}
 }
 
+/*
+*/
 irqreturn_t ahci_interrupt(int irq, void *dev_instance)
 {
 	struct ata_host *host = dev_instance;
@@ -1808,6 +1810,57 @@
 		pp->fbs_last_dev = qc->dev->link->pmp;
 	}
 
+#if defined(CONFIG_COMCERTO_AHCI_PROF)
+	if (enable_ahci_prof) {
+		struct ahci_port_stats *stats = &ahci_port_stats[ap->port_no];
+		struct timeval now;
+		int bin;
+
+		do_gettimeofday(&now);
+
+		if (stats->init_prof) {
+			int diff_time_us;
+
+			diff_time_us = (now.tv_sec - stats->last_req.tv_sec) * 1000 * 1000 + (now.tv_usec - stats->last_req.tv_usec);
+
+			bin = diff_time_us >> US_SHIFT;
+			if (bin >= MAX_BINS)
+				bin = MAX_BINS - 1;
+
+			stats->time_counter[bin]++;
+		}
+		else {
+			stats->init_prof = 1;
+		}
+
+		stats->last_req = now;
+
+		bin = qc->nbytes >> BYTE_SHIFT;
+		if (bin >= MAX_BINS)
+			bin = MAX_BINS - 1;
+
+		stats->data_counter[bin]++;
+
+		if (!stats->nb_pending) {
+			stats->first_issue = now;
+			stats->nb_pending_total = 0;
+		}
+
+		stats->nb_pending_total++;
+
+		/* This should never overflow */
+		stats->pending_counter[stats->nb_pending & (MAX_AHCI_SLOTS - 1)]++;
+
+		stats->nb_pending++;
+
+		if (stats->nb_pending_total > stats->nb_pending_max)
+			stats->nb_pending_max = stats->nb_pending_total;
+
+		stats->bytes_pending += qc->nbytes;
+		stats->pending_flag |= 1 << qc->tag;
+	}
+#endif
+
 	writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
 
 	ahci_sw_activity(qc->dev->link);
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index c04ad68..0d285e2 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4663,6 +4663,15 @@
 #endif /* __BIG_ENDIAN */
 }
 
+#if defined(CONFIG_COMCERTO_AHCI_PROF)
+
+#include "ahci.h"
+
+struct ahci_port_stats ahci_port_stats[MAX_AHCI_PORTS];
+unsigned int enable_ahci_prof = 0;
+
+#endif
+
 /**
  *	ata_qc_new - Request an available ATA command, for queueing
  *	@ap: target port
@@ -4690,6 +4699,13 @@
 	if (qc)
 		qc->tag = i;
 
+#if defined(CONFIG_COMCERTO_AHCI_PROF)
+	if (enable_ahci_prof)
+		if (qc == NULL) {
+			ahci_port_stats[ap->port_no].no_free_slot++;
+		}
+#endif
+
 	return qc;
 }
 
@@ -4741,6 +4757,48 @@
 	if (likely(ata_tag_valid(tag))) {
 		qc->tag = ATA_TAG_POISON;
 		clear_bit(tag, &ap->qc_allocated);
+
+#if defined(CONFIG_COMCERTO_AHCI_PROF)
+		if (enable_ahci_prof) {
+			struct ahci_port_stats *stats = &ahci_port_stats[ap->port_no];
+
+			if (stats->pending_flag & (1 << tag)) {
+				stats->pending_flag &= ~(1 << tag);
+				stats->nb_pending--;
+
+				if (!stats->nb_pending) {
+					struct timeval now;
+					int diff_time_us;
+					unsigned int rate;
+					int bin;
+
+					do_gettimeofday(&now);
+
+					diff_time_us = ((now.tv_sec - stats->first_issue.tv_sec) * 1000 * 1000) +
+								(now.tv_usec - stats->first_issue.tv_usec);
+
+					stats->diff_us += diff_time_us;
+
+					/* Do the average for at least 10MiB of data transfered */
+					if (stats->bytes_pending > (10 * (1 << 20))) {
+
+						rate = ((stats->bytes_pending / stats->diff_us) * 1000 * 1000) >> 20; //MiBps
+
+						bin = rate >> RATE_SHIFT;
+						if (bin >= MAX_BINS)
+							bin = MAX_BINS - 1;
+
+						/* Track how many KiB were transfered at this rate */
+						stats->rate_counter[bin] += stats->bytes_pending >> 10;
+
+						/* Reset stats */
+						stats->bytes_pending = 0;
+						stats->diff_us = 0;
+					}
+				}
+			}
+		}
+#endif
 	}
 }
 
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index b96544a..1955d73 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1146,3 +1146,192 @@
 	return async_error;
 }
 EXPORT_SYMBOL_GPL(device_pm_wait_for_dev);
+
+
+/*
+ * Code added to suppoprt  device SUSPEND(L1 and L2 ) and RESUME
+ * (L1 = clock gating L2 = clock gating + reset) .
+ * Depends upon config option CONFIG_PM_SYSFS_MANUAL
+ *
+ */
+
+#ifdef CONFIG_PM_SYSFS_MANUAL
+
+static DEFINE_MUTEX(dpm_lock);
+
+/**
+ *	dpm_manual_resume - resume the device .
+ *      uses device_resume and device_complete to acheive feature.
+ *      part of the code borrowed from dpm_resume and dpm_resume_complete.
+ *	@dev:   Device.
+ * 	@state: State to enter.
+*/
+
+void dpm_manual_resume(struct device *dev,pm_message_t state)
+{
+	int error;
+	struct list_head list;
+	ktime_t starttime = ktime_get();
+
+	might_sleep();
+
+	/* Device resume prepare starts here */
+	mutex_lock(&dpm_list_mtx);
+        pm_transition = state;
+	INIT_COMPLETION(dev->power.completion);
+	mutex_unlock(&dpm_list_mtx);
+
+	error = device_resume(dev, state, false);
+	if (error) {
+		suspend_stats.failed_resume++;
+		dpm_save_failed_step(SUSPEND_RESUME);
+		dpm_save_failed_dev(dev_name(dev));
+		pm_dev_err(dev, state, "", error);
+	}
+
+	mutex_lock(&dpm_list_mtx);
+	if (!list_empty(&dev->power.entry))
+		list_move_tail(&dev->power.entry, &dpm_prepared_list);
+	mutex_unlock(&dpm_list_mtx);
+	
+	/* DPM complete start */
+	INIT_LIST_HEAD(&list);
+	mutex_lock(&dpm_list_mtx);
+	dev->power.is_prepared = false;
+	list_move(&dev->power.entry, &list);
+	mutex_unlock(&dpm_list_mtx);
+
+	device_complete(dev, state);
+	dev->power.power_state=state;
+	dpm_show_time(starttime, state, NULL);
+}
+
+
+/**
+ *	dpm_manual_resume_start - Start the process for Power one device back to work.
+ *	@dev:   Device.
+ *	@state: State to enter.
+ *      Code inspired from dpm_resume_end().
+ *
+ *	Bring one device back to the on state by first powering it
+ *	on, then restoring state. We only operate on devices that aren't
+ *	already on.
+ */
+
+void dpm_manual_resume_start(struct device * dev,pm_message_t state)
+{
+	mutex_lock(&dpm_lock);
+	if (dev->power.power_state.event == state.event){
+		printk(KERN_ERR "PM: We are already in the resume state \n");
+		goto done;
+        }
+	/* Device resume starts from here */
+	dpm_manual_resume(dev,state);
+done:
+	mutex_unlock(&dpm_lock);
+
+}
+
+/**
+ *	dpm_manual_prepare - prepare the device for power transition.
+ *	Part of the code borrowed from dpm_prapare.
+ *	@dev:   Device.
+ *	@state: State to enter.
+ */
+static int dpm_manual_prepare(struct device * dev , pm_message_t state)
+{
+	/* This part of code is borrowed from dpm_prepare
+	 * make the deice for prepare.
+	*/
+	int error = 0;
+	might_sleep();
+	
+	/* Call the device prepare */
+	error = device_prepare(dev, state);
+
+	mutex_lock(&dpm_list_mtx);
+	if (error){
+		printk(KERN_INFO "PM: Device %s not prepared " "for power transition: code %d\n",
+			dev_name(dev), error);
+		goto done;
+	}
+	dev->power.is_prepared = true;
+	if (!list_empty(&dev->power.entry))
+		list_move_tail(&dev->power.entry, &dpm_prepared_list);
+
+done:
+	mutex_unlock(&dpm_list_mtx);	
+	return error;
+}
+
+/**
+ *	dpm_manual_suspend - Helper routing to call the device_suspend.
+ *	Part of the code borrowed from dpm_supend().
+ *	@dev:   Device.
+ *	@state: State to enter.
+ */
+static int dpm_manual_suspend(struct device * dev, pm_message_t state)
+{
+	ktime_t starttime;
+	int error=0;
+
+	might_sleep();
+
+	mutex_lock(&dpm_list_mtx);
+	pm_transition = state;
+	mutex_unlock(&dpm_list_mtx);
+	
+	error = device_suspend(dev);
+	
+	mutex_lock(&dpm_list_mtx);
+	if (error){
+		pm_dev_err(dev, state, "", error);
+                dpm_save_failed_dev(dev_name(dev));
+	}	
+	if (!list_empty(&dev->power.entry))
+		list_move(&dev->power.entry, &dpm_suspended_list);
+	mutex_unlock(&dpm_list_mtx);
+
+	dev->power.power_state=state;
+	dpm_show_time(starttime, state, NULL);
+	return error;
+}
+
+/**
+ *      dpm_manual_suspend_start - Put one device in Power of L1/L2 state.
+ *      Power off L1 - clock gating , Power off L2 - clock gating + device reset
+ *  	Part of the code borrowed from dpm_suspend_start.
+ *      @dev:   Device.
+ *      @state: State to enter.
+ */
+int dpm_manual_suspend_start(struct device * dev, pm_message_t state)
+{
+	int error=0;
+
+	/* Start the global mutex value*/
+	mutex_lock(&dpm_lock);
+
+	if (dev->power.power_state.event == state.event){
+		if ( state.event == PM_EVENT_SUSPEND )
+			printk(KERN_ERR "PM: We are already in the suspend (power off L1) state \n");
+#if 0
+		else if ( state.event == PM_EVENT_SUSPEND_L2)
+			printk(KERN_ERR "PM: We are already in the suspend (Power off L2) state \n");
+#endif
+		goto done;
+        }
+
+	/* Devce PM prepare starts from here */
+	error=dpm_manual_prepare(dev,state);
+	
+	if (error){
+		suspend_stats.failed_prepare++;
+		dpm_save_failed_step(SUSPEND_PREPARE);
+		goto done;
+	}else
+		error = dpm_manual_suspend(dev,state);	
+done:
+	mutex_unlock(&dpm_lock);
+	return error;
+}
+#endif
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index 95706fa..fe10b841 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -330,6 +330,7 @@
 {
 	struct device_opp *dev_opp;
 	struct opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+	int c = 0;
 
 	if (!dev || !freq) {
 		dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
@@ -341,10 +342,15 @@
 		return opp;
 
 	list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
+		++c;
 		if (temp_opp->available) {
 			/* go to the next node, before choosing prev */
 			if (temp_opp->rate > *freq)
+			{
+				if (c == 1)
+					opp = temp_opp;
 				break;
+			}
 			else
 				opp = temp_opp;
 		}
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index 9bf6232..8e9d09d 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -81,3 +81,15 @@
 static inline void wakeup_sysfs_remove(struct device *dev) {}
 
 #endif
+
+/* Added for SYSFS support to handle from Device power management from 
+ * user space. Manual PM  configuration.
+ */
+
+#ifdef  CONFIG_PM_SYSFS_MANUAL
+
+extern int dpm_manual_suspend_start(struct device * , pm_message_t );
+extern void dpm_manual_resume_start(struct device * , pm_message_t);
+
+#endif /* CONFIG_PM_SYSFS_MANUAL */
+
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index adf41be0..1d2db86 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -89,6 +89,12 @@
  *	value are used only if the driver calls pm_runtime_use_autosuspend().
  *
  *	wakeup_count - Report the number of wakeup events related to the device
+ *      
+ *      MSPD: Added the support for manual PM operation for NON-CPU devices.
+ *      This is operated through power/state file . operates in two states
+ *      PM_EVENT_SUSPEND= Power off L1 state (device Clock gating )
+ *	PM_EVENT_SUSPEND_L2=Power off L2 state ( device Clock gating + reset). 
+ *      
  */
 
 static const char enabled[] = "enabled";
@@ -97,6 +103,44 @@
 const char power_group_name[] = "power";
 EXPORT_SYMBOL_GPL(power_group_name);
 
+#ifdef CONFIG_PM_SYSFS_MANUAL
+static ssize_t state_show(struct device * dev, struct device_attribute *attr, char * buf)
+{
+	if (dev->power.power_state.event == PM_EVENT_SUSPEND) /* Power off L1 state */
+		return sprintf(buf, "2\n");
+#if 0
+	else if (dev->power.power_state.event == PM_EVENT_SUSPEND_L2) /* Power off L2 state */
+		return sprintf(buf, "3\n");
+#endif
+	else 
+		return sprintf(buf, "0\n");
+}
+
+static ssize_t state_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t n)
+{
+	pm_message_t state;
+	int error = -EINVAL;
+	
+	if ((n == 2) && (buf[0] == '2')) {
+                state.event = PM_EVENT_SUSPEND; 
+                error = dpm_manual_suspend_start(dev, state); /* Power off L1 state */
+        }
+#if 0
+	if ((n == 2) && (buf[0] == '3')) {
+                state.event = PM_EVENT_SUSPEND_L2;
+                error = dpm_manual_suspend(dev, state);       /* Power off L2 state */
+        }	
+#endif
+	if ((n == 2) && (buf[0] == '0')) {
+                state.event = PM_EVENT_RESUME;
+                dpm_manual_resume_start(dev, state);
+		error = 0;
+        }
+	return error ? error : n;
+}
+static DEVICE_ATTR(state, 0644, state_show, state_store);
+#endif
+
 #ifdef CONFIG_PM_RUNTIME
 static const char ctrl_auto[] = "auto";
 static const char ctrl_on[] = "on";
@@ -432,11 +476,13 @@
 		return -EINVAL;
 	return n;
 }
-
 static DEVICE_ATTR(async, 0644, async_show, async_store);
 #endif /* CONFIG_PM_ADVANCED_DEBUG */
 
 static struct attribute *power_attrs[] = {
+#ifdef CONFIG_PM_SYSFS_MANUAL
+	 &dev_attr_state.attr,
+#endif
 #ifdef CONFIG_PM_ADVANCED_DEBUG
 #ifdef CONFIG_PM_SLEEP
 	&dev_attr_async.attr,
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 6035ab8..8c3acdf 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -130,6 +130,9 @@
  * 	void add_interrupt_randomness(int irq);
  * 	void add_disk_randomness(struct gendisk *disk);
  *
+ *      void random_input_words(__u32 *buf, size_t wordcount, int ent_count)
+ *      int random_input_wait(void);
+ *
  * add_input_randomness() uses the input layer interrupt timing, as well as
  * the event type information from the hardware.
  *
@@ -147,6 +150,13 @@
  * seek times do not make for good sources of entropy, as their seek
  * times are usually fairly consistent.
  *
+ * random_input_words() just provides a raw block of entropy to the input
+ * pool, such as from a hardware entropy generator.
+ *
+ * random_input_wait() suspends the caller until such time as the
+ * entropy pool falls below the write threshold, and returns a count of how
+ * much entropy (in bits) is needed to sustain the pool.
+ *
  * All of these routines try to estimate how many bits of randomness a
  * particular randomness source.  They do this by keeping track of the
  * first and second order deltas of the event timings.
@@ -722,6 +732,63 @@
 }
 #endif
 
+/*
+ * random_input_words - add bulk entropy to pool
+ *
+ * @buf: buffer to add
+ * @wordcount: number of __u32 words to add
+ * @ent_count: total amount of entropy (in bits) to credit
+ *
+ * this provides bulk input of entropy to the input pool
+ *
+ */
+void random_input_words(__u32 *buf, size_t wordcount, int ent_count)
+{
+	mix_pool_bytes(&input_pool, buf, wordcount*4);
+
+	credit_entropy_bits(&input_pool, ent_count);
+
+	DEBUG_ENT("crediting %d bits => %d\n",
+		  ent_count, input_pool.entropy_count);
+	/*
+	 * Wake up waiting processes if we have enough
+	 * entropy.
+	 */
+	if (input_pool.entropy_count >= random_read_wakeup_thresh)
+		wake_up_interruptible(&random_read_wait);
+}
+EXPORT_SYMBOL(random_input_words);
+
+/*
+ * random_input_wait - wait until random needs entropy
+ *
+ * this function sleeps until the /dev/random subsystem actually
+ * needs more entropy, and then return the amount of entropy
+ * that it would be nice to have added to the system.
+ */
+int random_input_wait(void)
+{
+	int count;
+
+	wait_event_interruptible(random_write_wait, 
+			 input_pool.entropy_count < random_write_wakeup_thresh);
+
+	count = random_write_wakeup_thresh - input_pool.entropy_count;
+
+        /* likely we got woken up due to a signal */
+	if (count <= 0) count = random_read_wakeup_thresh; 
+
+	DEBUG_ENT("requesting %d bits from input_wait()er %d<%d\n",
+		  count,
+		  input_pool.entropy_count, random_write_wakeup_thresh);
+
+	return count;
+}
+EXPORT_SYMBOL(random_input_wait);
+
+
+#define EXTRACT_SIZE 10
+
 /*********************************************************************
  *
  * Entropy extraction routines
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index e24a2a1..c08b968 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -45,7 +45,7 @@
 choice
 	prompt "Default CPUFreq governor"
 	default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110
-	default CPU_FREQ_DEFAULT_GOV_PERFORMANCE
+	default CPU_FREQ_DEFAULT_GOV_ONDEMAND
 	help
 	  This option sets which CPUFreq governor shall be loaded at
 	  startup. If in doubt, select 'performance'.
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 72a0044..ad6b9bfb 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -30,3 +30,8 @@
 	  SoC (S5PV310 or S5PC210).
 
 	  If in doubt, say N.
+
+config CPU_FREQ_C2K
+	bool "CPUfreq driver for Comcerto"
+	depends on ARCH_COMCERTO && CPU_FREQ
+	default y
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index a48bc02..5cc3681 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -47,3 +47,4 @@
 ##################################################################################
 # PowerPC platform drivers
 obj-$(CONFIG_CPU_FREQ_MAPLE)		+= maple-cpufreq.o
+obj-$(CONFIG_CPU_FREQ_C2K)             += c2k-cpufreq.o
diff --git a/drivers/cpufreq/c2k-cpufreq.c b/drivers/cpufreq/c2k-cpufreq.c
new file mode 100644
index 0000000..dd3b9c4
--- /dev/null
+++ b/drivers/cpufreq/c2k-cpufreq.c
@@ -0,0 +1,250 @@
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/compiler.h>
+#include <linux/gfp.h>
+
+#include <asm/system.h>
+
+#include <mach/hardware.h>
+#include <linux/netdevice.h>
+#include <linux/clk.h>
+
+#define NR_FREQS        15
+
+//#define C2K_CPUFREQ_DEBUG
+#ifdef C2K_CPUFREQ_DEBUG
+	#define c2k_cpufreq_debug(fmt, arg...)   printk(fmt, ##arg)
+#else
+	#define c2k_cpufreq_debug(fmt, arg...)     ;
+#endif
+
+extern struct cpufreq_governor cpufreq_gov_ondemand;
+
+static struct cpufreq_frequency_table comcerto_clk_frqs[NR_FREQS + 1];
+
+static int comcerto_verify_speed(struct cpufreq_policy *policy)
+{
+	if (policy->cpu < 0)
+		return -EINVAL;
+
+	return cpufreq_frequency_table_verify(policy, comcerto_clk_frqs);
+}
+
+static unsigned int comcerto_getspeed(unsigned int cpu)
+{
+	struct clk *clk_arm;
+
+	if (cpu < 0)
+		return -EINVAL;
+
+	c2k_cpufreq_debug ("%s: Get speed for cpu(%d)\n", __func__, cpu);
+
+	clk_arm = clk_get(NULL,"arm");
+	if (IS_ERR(clk_arm)) {
+		pr_err("cpufreq: Unable to obtain ARMCLK: %ld\n",
+				PTR_ERR(clk_arm));
+		return PTR_ERR(clk_arm);
+	}
+
+	return clk_get_rate(clk_arm); /* we get freq in hz */
+}
+
+static int comcerto_set_target(struct cpufreq_policy *policy,
+                             unsigned int target_freq,
+                             unsigned int relation)
+{
+	struct cpufreq_freqs freqs;
+	unsigned int index;
+	struct clk *clk_arm;
+	int ret;
+	int j = 0;
+
+	ret = cpufreq_frequency_table_target(policy, comcerto_clk_frqs, target_freq, relation, &index);
+	if (ret < 0)
+		return ret;
+
+	if (policy->cpu >= NR_CPUS) {
+		pr_debug("%s: couldn't limit to CPUs in this domain\n", \
+				__func__);
+		return -EAGAIN;
+	}
+
+	clk_arm = clk_get(NULL,"arm");
+	if (IS_ERR(clk_arm)) {
+		pr_err("%s: cpufreq: Unable to obtain ARMCLK: %ld\n", __func__,\
+				PTR_ERR(clk_arm));
+		return PTR_ERR(clk_arm);
+	}
+
+	freqs.old = comcerto_getspeed(policy->cpu);
+	if (freqs.old == target_freq)
+	{
+		c2k_cpufreq_debug ("%s: old freq (%d) equals new freq(%d).\n", \
+			__func__, freqs.old, target_freq);
+		return 0;
+	}
+
+	freqs.new = comcerto_clk_frqs[index].frequency;
+
+	c2k_cpufreq_debug("%s: Transition(cpu:%d) %d-%dHz\n", __func__,\
+				policy->cpu, freqs.old, freqs.new);
+
+	while (j < NR_CPUS)
+	{
+		if (!cpu_online(j))
+		{
+			j++;
+			continue;
+		}
+		freqs.cpu = j;
+		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+		j++;
+	}
+	j = 0;
+
+	policy->cur = freqs.new;
+	ret = clk_set_rate(clk_arm, freqs.new);
+	if (ret < 0) {
+		pr_debug("cpufreq: Failed to set rate %dHz: %d\n",
+				freqs.new, ret);
+		j = 0;
+		goto err;
+	}
+
+	while (j < NR_CPUS)
+	{
+		if (!cpu_online(j))
+		{
+			j++;
+			continue;
+		}
+		freqs.cpu = j;
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+		j++;
+	}
+
+	c2k_cpufreq_debug("%s:Set actual frequency %luHz\n", __func__, \
+			clk_get_rate(clk_arm));
+
+	return 0;
+err:
+	policy->cur = freqs.old;
+	freqs.new = freqs.old;
+	while (j < NR_CPUS)
+	{
+		if (!cpu_online(j))
+		{
+			j++;
+			continue;
+		}
+		freqs.cpu = j;
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+		j++;
+	}
+
+        return ret;
+}
+
+static int comcerto_init_table(int cpu)
+{
+	int i;
+	struct clk *clk_arm;
+	struct clk *clk_pll;
+
+        if (cpu != 0)
+                return 0;
+
+	clk_arm = clk_get(NULL,"arm");
+	if (IS_ERR(clk_arm)) {
+		pr_err("cpufreq: Unable to obtain ARMCLK: %ld\n",
+				PTR_ERR(clk_arm));
+		return PTR_ERR(clk_arm);
+	}
+
+	clk_pll = clk_get_parent(clk_arm);
+
+	comcerto_clk_frqs[0].frequency = clk_get_rate(clk_arm);
+	comcerto_clk_frqs[0].index = clk_get_rate(clk_pll)/clk_get_rate(clk_arm);
+
+	c2k_cpufreq_debug("\n\n ### cpufreq Table ###\n");
+
+	c2k_cpufreq_debug ("comcerto_clk_frqs[0].index = %d, comcerto_clk_frqs[0].frequency = %d\n",\
+				comcerto_clk_frqs[0].index, comcerto_clk_frqs[0].frequency);
+
+	for (i = 1; comcerto_clk_frqs[0].index + i <= NR_FREQS; i++) 
+	{
+		comcerto_clk_frqs[i].frequency = (comcerto_clk_frqs[0].frequency \
+			* comcerto_clk_frqs[0].index) / (comcerto_clk_frqs[0].index + i);
+
+		comcerto_clk_frqs[i].index = comcerto_clk_frqs[0].index + i;
+
+		c2k_cpufreq_debug ("comcerto_clk_frqs[%d].index = %d, comcerto_clk_frqs[%d].frequency = %d\n",\
+					i, comcerto_clk_frqs[i].index, i, comcerto_clk_frqs[i].frequency);
+	}
+
+	comcerto_clk_frqs[i].frequency = CPUFREQ_TABLE_END;
+
+	return 0;
+}
+
+static int comcerto_cpu_init(struct cpufreq_policy *policy)
+{
+	comcerto_init_table(policy->cpu);
+
+	cpufreq_frequency_table_cpuinfo(policy, comcerto_clk_frqs);
+
+	cpufreq_frequency_table_get_attr(comcerto_clk_frqs, policy->cpu);
+
+	/* PLL stabalisation time */
+	policy->cpuinfo.transition_latency = 10000; /* 10us */
+
+	/* Current Frequency */
+	policy->cur = comcerto_clk_frqs[0].frequency;
+
+	/* Governor used */
+	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+	return 0;
+}
+
+static struct freq_attr *comcerto_cpufreq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver comcerto_driver = {
+	.name = "comcerto",
+	.init = comcerto_cpu_init,
+	.verify = comcerto_verify_speed,
+	.target = comcerto_set_target,
+	.get = comcerto_getspeed,
+	.attr = comcerto_cpufreq_attr,
+	.flags = CPUFREQ_STICKY,
+	.owner = THIS_MODULE,
+};
+
+static int __init comcerto_cpufreq_init(void)
+{
+	printk ("Registering CPUFreq(%s)\n", comcerto_driver.name);
+
+	return  cpufreq_register_driver(&comcerto_driver);
+}
+
+static void __exit comcerto_cpufreq_exit(void)
+{
+	cpufreq_unregister_driver(&comcerto_driver);
+}
+
+MODULE_AUTHOR ("Satendra Pratap <satendra.pratap@gmail.com>");
+MODULE_DESCRIPTION ("CPUFreq driver for Mindspeed's C2000 SoC");
+MODULE_LICENSE ("GPL");
+
+late_initcall(comcerto_cpufreq_init);
+module_exit(comcerto_cpufreq_exit);
+
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 987a165..c23af68 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -923,8 +923,10 @@
 #ifdef CONFIG_HOTPLUG_CPU
 	for_each_online_cpu(sibling) {
 		struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling);
+
 		if (cp && cp->governor &&
 		    (cpumask_test_cpu(cpu, cp->related_cpus))) {
+
 			policy->governor = cp->governor;
 			found = 1;
 			break;
diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index 8f04910..85302e6 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -65,4 +65,10 @@
 
 comment "DEVFREQ Drivers"
 
+config COMCERTO_DEVFREQ_SUPPORT
+	bool "Enable Comcerto devfreq"
+	select DEVFREQ_GOV_SIMPLE_ONDEMAND
+	help
+		Adds devfreq support in Comcerto.
+
 endif # PM_DEVFREQ
diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
index 4564a89..af24e66 100644
--- a/drivers/devfreq/Makefile
+++ b/drivers/devfreq/Makefile
@@ -3,3 +3,4 @@
 obj-$(CONFIG_DEVFREQ_GOV_PERFORMANCE)	+= governor_performance.o
 obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE)	+= governor_powersave.o
 obj-$(CONFIG_DEVFREQ_GOV_USERSPACE)	+= governor_userspace.o
+obj-$(CONFIG_COMCERTO_DEVFREQ_SUPPORT)	+= c2k-devfreq.o
diff --git a/drivers/devfreq/c2k-devfreq.c b/drivers/devfreq/c2k-devfreq.c
new file mode 100644
index 0000000..5919d0a
--- /dev/null
+++ b/drivers/devfreq/c2k-devfreq.c
@@ -0,0 +1,279 @@
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/opp.h>
+#include <linux/devfreq.h>
+
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/jiffies.h>
+
+#include <linux/clk.h>
+#include <linux/c2k-devfreq.h>
+
+//#define	C2K_DEVFREQ_DEBUG
+
+int devfreq_counters_init(struct c2k_devfreq_data *data)
+{
+	devfreq_counters **dc = &data->dpc;
+
+	*dc = kzalloc(sizeof (devfreq_counters), GFP_KERNEL);
+	if (dc == NULL) {
+		printk ("%s: Cannot allocate memory for devfreq_counters.\n"\
+				, __func__);
+		return -ENOMEM;
+	}
+
+#ifdef C2K_DEVFREQ_USE_KTIME
+	(*dc)->start_time = ktime_get();
+#else
+	(*dc)->fentry_time = 0UL;
+	(*dc)->prev_count = 0UL;
+	(*dc)->busy_time = 0UL;
+	(*dc)->start_time = jiffies;
+#endif
+	return 0;
+}
+EXPORT_SYMBOL(devfreq_counters_init);
+
+static int c2k_devfreq_pm_notifier_event(struct notifier_block *this,
+               unsigned long event, void *ptr)
+{
+       struct c2k_devfreq_data *data = container_of(&this, struct c2k_devfreq_data,
+                                                pm_notifier);
+
+       switch (event) {
+       case PM_SUSPEND_PREPARE:
+               /* Deactivate DVFS */
+               mutex_lock(&data->lock);
+               data->disabled = true;
+               mutex_unlock(&data->lock);
+               return NOTIFY_OK;
+       case PM_POST_RESTORE:
+       case PM_POST_SUSPEND:
+               /* Reactivate */
+               mutex_lock(&data->lock);
+               data->disabled = false;
+               mutex_unlock(&data->lock);
+               return NOTIFY_OK;
+       }
+
+       return NOTIFY_DONE;
+}
+
+/*
+ * @devfreq_target  Returns desired operating frequency for the device.
+ *                      Basically, get_target_freq will run
+ *                      devfreq_dev_profile.get_dev_status() to get the
+ *                      status of the device (load = busy_time / total_time).
+ */
+static int devfreq_target(struct device *dev, unsigned long *freq)
+{
+	struct platform_device *pdev = container_of(dev, struct platform_device, dev);
+	struct c2k_devfreq_data *data = platform_get_drvdata(pdev);
+	unsigned long old_freq = opp_get_freq(data->curr_opp);
+	struct opp *new_opp;
+	int err = 0;
+
+	mutex_lock(&data->lock);
+
+#ifdef C2K_DEVFREQ_DEBUG
+	c2k_devfreq_debug ("%s:current opp <f=%lu v=%lu>\n", __func__, \
+		opp_get_freq(data->curr_opp), opp_get_voltage(data->curr_opp));
+#endif
+	if (data->disabled)
+		goto out;
+
+	/* here...find corresponding OPP w.r.t |_*freq_| */
+	new_opp = opp_find_freq_floor(dev, freq);
+	if (IS_ERR(new_opp)) {
+		printk("%s: Invalid frequency %lu kHz.\n",
+			__func__, *freq);
+		err = PTR_ERR(new_opp);
+		goto out;
+	}
+#ifdef C2K_DEVFREQ_DEBUG
+	c2k_devfreq_debug ("%s:new opp <f=%lu v=%lu>\n", __func__, \
+		opp_get_freq(new_opp), opp_get_voltage(new_opp));
+#endif
+	data->curr_opp = new_opp; 
+	*freq = opp_get_freq(new_opp);
+
+	/* now set freq */
+	if (old_freq != *freq)
+	{
+		if (*freq >= UINT_MAX)
+			*freq = data->max_freq;
+		if (*freq == 0)
+			*freq = data->min_freq;
+
+		err = data->set_freq(data, freq); /* uses clk struct */
+	}
+	else
+		goto out;
+
+	if (err)
+		goto out;
+
+	/* we could set voltage also */
+out:
+	mutex_unlock(&data->lock);
+	return err;
+}
+
+/*
+ * @total_time          The total time represented by this instance of
+ *                      devfreq_dev_status
+ * @busy_time           The time that the device was working among the
+ *                      total_time.
+ */
+static int get_devfreq_status(struct device *dev, struct devfreq_dev_status *stat)
+{
+	struct platform_device *pdev = container_of(dev, struct platform_device, dev);
+	struct c2k_devfreq_data *data = platform_get_drvdata(pdev);
+	devfreq_counters *dc = data->dpc;
+
+	stat->current_frequency = opp_get_freq(data->curr_opp);
+
+	/* Here goes a list of mechanisms to fetch busy/total time:
+	   - Performance counters
+	   - Measure the time between "operation start" and "operation end" and
+	   accumulate the time (getting busy time. probably by ktime?)
+	   - Measure the idle time (CPUIDLE/CPUFREQ does this)
+	   - Count the number of operation and calculate the operational time
+	   based on the number.
+	 */
+
+	stat->busy_time = (unsigned long)module_busy_time(dc);
+
+	stat->total_time = (unsigned long)module_busy_plus_not_busy_time(dc);
+
+	devfreq_reset_counters(dc);
+
+	return 0;
+}
+
+int c2k_driver_devfreq(struct device *dev, struct c2k_devfreq_data *data)
+{
+	struct devfreq *ldevfreq;
+	struct opp *opp;
+	int i, err = 0;
+
+	BUG_ON(data==NULL);
+
+#ifdef C2K_DEVFREQ_DEBUG
+	c2k_devfreq_debug("%s: initializing for dev %s\n", __func__, dev_name(dev));
+#endif
+	if (!(data->vdd_int))
+	{
+		data->vdd_int = regulator_get(dev, "c2k_default_vcc");
+
+		if (IS_ERR(data->vdd_int)) {
+			printk ("%s: Cannot get the regulator \"vcc_c2k\"\n", __func__);
+			err = PTR_ERR(data->vdd_int);
+			goto err_regulator;
+		}
+	}
+
+	data->dev = dev;
+	mutex_init(&data->lock);
+
+	/* OPP Entries assumed to be setup by now */
+	if (data->opp_table)
+	{
+		for (i = 0; data->opp_table[i].idx != 0; i++) {
+		#ifdef C2K_DEVFREQ_DEBUG
+			c2k_devfreq_debug("%s: Adding opp entry: %ld Hz, %ld uvolt.\n",\
+				__func__, data->opp_table[i].freq, data->opp_table[i].volt);
+		#endif
+			err = opp_add(dev, data->opp_table[i].freq, data->opp_table[i].volt);
+	
+			if (err) {
+				printk("%s: Cannot add opp entries: err = %d\n",__func__, err);
+				goto err_opp_add;
+			}
+		}
+	}
+	else
+	{
+		printk ("%s: Not using OPP framework.\n", __func__);
+	}
+
+	if (data->devfreq_profile->initial_freq > 0)
+	{
+		opp = opp_find_freq_floor(dev, &(data->devfreq_profile->initial_freq));
+		if (IS_ERR(opp)) {
+			printk("%s: Invalid initial frequency %lu kHz.\n",
+				__func__, data->devfreq_profile->initial_freq);
+			err = PTR_ERR(opp);
+			goto err_opp_add;
+		}
+		data->curr_opp = opp; 
+	}
+	else
+		return -EINVAL;
+
+	if (!data->devfreq_profile->target)
+		data->devfreq_profile->target = devfreq_target; /* using default */
+
+	if (!data->devfreq_profile->get_dev_status)
+		data->devfreq_profile->get_dev_status = get_devfreq_status; /* using default */
+
+	if (!data->gov)
+		data->gov = &devfreq_simple_ondemand; /* using default governer */
+
+	dev_set_drvdata(dev, data);
+
+	ldevfreq = devfreq_add_device(dev, data->devfreq_profile, data->gov, NULL);
+	if (!ldevfreq)
+	{
+		printk ("%s: devfreq_add_device failed with err = %d\n", __func__, err);
+		goto err_opp_add;
+	}
+
+	if (data->pm_notifier)
+	{
+		err = register_pm_notifier(data->pm_notifier);
+		if (err) {
+			printk ("%s: Failed to setup pm notifier.\n", __func__);
+			goto err_notifier;
+		}
+	}
+	else
+	{
+		data->pm_notifier = (struct notifier_block*)kzalloc\
+				(sizeof(struct notifier_block), GFP_KERNEL);
+
+	        if (data->pm_notifier == NULL) {
+        	        printk ("%s: Cannot allocate memory for pm_notifier.\n",\
+				__func__);
+        	        return -ENOMEM;
+        	}
+
+		data->pm_notifier->notifier_call = c2k_devfreq_pm_notifier_event; /* default pm notifier */
+
+		err = register_pm_notifier(data->pm_notifier);
+		if (err) {
+			printk ("%s: Failed to setup pm notifier.\n", __func__);
+			goto err_notifier;
+		}
+	}
+
+	err = devfreq_counters_init(data);
+
+	return err;
+
+err_notifier:
+	devfreq_remove_device(ldevfreq);
+err_opp_add:
+	regulator_put(data->vdd_int);
+err_regulator:
+	kfree(data);
+	return err;
+}
+EXPORT_SYMBOL(c2k_driver_devfreq);
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index da85c0d..c5005a9 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -122,6 +122,22 @@
 	---help---
 	  Enable support for the Marvell XOR engine.
 
+config COMCERTO_XOR
+	tristate "Mindspeed Comcerto 2000 XOR engine support"
+	depends on ARCH_M86XXX
+	select DMA_ENGINE
+	select ASYNC_TX_ENABLE_CHANNEL_SWITCH
+	---help---
+	  Enable support for the Mindspeed XOR engine.
+
+config COMCERTO_DMA_BASIC
+	tristate "Mindspeed Comcerto 2000 MDMA engine basic support"
+	depends on ARCH_M86XXX
+	select DMA_ENGINE
+	select ASYNC_TX_ENABLE_CHANNEL_SWITCH
+	---help---
+	  Enable support for the Mindspeed mdma engine.
+
 config MX3_IPU
 	bool "MX3x Image Processing Unit support"
 	depends on SOC_IMX31 || SOC_IMX35
@@ -272,6 +288,15 @@
 
 	  If unsure, say N.
 
+config RAID_ZERO_COPY
+        bool "Optimized DMA/XOR offload: reduce raid5 memcpy which offloaded for dma"
+        depends on ASYNC_TX_DMA
+        help
+          This allows the async_tx api try to reduce raid5 memcpy operations for
+          dma. If you have dma device to support memcpy offloading, you can set
+          it as Y, else N.
+
+
 config DMATEST
 	tristate "DMA Test client"
 	depends on DMA_ENGINE
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 30cf3b1..4e08999 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -26,3 +26,5 @@
 obj-$(CONFIG_PCH_DMA) += pch_dma.o
 obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o
 obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
+obj-$(CONFIG_COMCERTO_XOR) += comcerto_xor.o
+obj-$(CONFIG_COMCERTO_DMA_BASIC) += c2k_dma.o
diff --git a/drivers/dma/c2k_dma.c b/drivers/dma/c2k_dma.c
new file mode 100644
index 0000000..c5b7d91
--- /dev/null
+++ b/drivers/dma/c2k_dma.c
@@ -0,0 +1,1178 @@
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+#include <linux/sched.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <asm/io.h>
+#include <mach/c2k_dma.h>
+#include <linux/dmaengine.h>
+#include <linux/circ_buf.h>
+#include <linux/delay.h>
+
+
+#define XOR_MAX_SRC_CNT	6
+
+#define virt_to_xor_dma(pbase, vbase, vaddr)		((pbase + ((unsigned long)vaddr - (unsigned long)vbase)))
+
+struct comcerto_xor_device {
+	struct dma_device        device;
+};
+
+struct comcerto_xor_chan {
+	struct comcerto_xor_device        *device;
+	struct dma_chan                 chan;
+	struct tasklet_struct       irq_tasklet;
+	spinlock_t                  lock;
+	dma_cookie_t                completed_cookie;
+};
+
+struct comcerto_sw_xor_desc {
+	struct dma_async_tx_descriptor async_tx;
+	int src_cnt;
+	size_t len;
+	dma_addr_t dma_dest;
+	dma_addr_t dma_src[XOR_MAX_SRC_CNT];
+};
+
+void *comcerto_xor_pool_virt;
+dma_addr_t comcerto_xor_pool_phy;
+
+spinlock_t	comcerto_xor_cleanup_lock;
+static DECLARE_WAIT_QUEUE_HEAD(comcerto_xor_wait_queue);
+static int comcerto_xor_sleeping = 0;
+
+static int xor_rd_idx = 0;
+static int xor_wr_idx = 0;
+static int xor_dma_idx = 0;
+static int xor_sw_rd_idx = 0;
+static int xor_sw_wr_idx = 0;
+static int xor_sw_wr_prev_idx = 0;
+static int xor_current_batch_count = 0;
+
+#define XOR_FDESC_COUNT 512
+#if defined(CONFIG_COMCERTO_64K_PAGES)
+#define XOR_SW_FDESC_COUNT 32
+#else
+#define XOR_SW_FDESC_COUNT XOR_FDESC_COUNT
+#endif
+
+struct timer_list comcerto_xor_timer;
+#define COMPLETION_TIMEOUT      msecs_to_jiffies(100)
+static int comerto_xor_timer_first = 1;
+
+struct comcerto_xor_inbound_fdesc *xor_in_fdesc[XOR_FDESC_COUNT];
+struct comcerto_xor_outbound_fdesc *xor_out_fdesc[XOR_FDESC_COUNT];
+struct comcerto_sw_xor_desc     sw_xor_desc[XOR_SW_FDESC_COUNT];
+
+struct comcerto_xor_device *comcerto_xor_dev;
+struct comcerto_xor_chan   comcerto_xor_ch;
+#define OWNER_XOR_FREE	1
+#define OWNER_MEMCPY_FREE 2
+#define OWNER_XOR_BUSY	3
+#define OWNER_MEMCPY_BUSY	4
+static int dma_owned = 0;
+static int memcpy_processed_ongoing = 0;
+static int memcpy_pending_count = 0;
+
+
+//static int mdma_busy = 0;
+static int mdma_done;
+static spinlock_t mdma_lock;
+
+static void *virtbase;
+
+#define M2IO_CONTROL           (virtbase)
+#define M2IO_HEAD              (virtbase + 0x4)
+#define M2IO_BURST             (virtbase + 0x8)
+#define M2IO_FLEN              (virtbase + 0xC)
+#define M2IO_IRQ_ENABLE        (virtbase + 0x10)
+#define M2IO_IRQ_STATUS        (virtbase + 0x14)
+#define M2IO_RESET             (virtbase + 0x20)
+
+#define IO2M_CONTROL           (virtbase + 0x80)
+#define IO2M_HEAD              (virtbase + 0x84)
+#define IO2M_BURST             (virtbase + 0x88)
+#define IO2M_FLEN              (virtbase + 0x8C)
+#define IO2M_IRQ_ENABLE        (virtbase + 0x90)
+#define IO2M_IRQ_STATUS        (virtbase + 0x94)
+#define IO2M_RESET             (virtbase + 0xA0)
+
+#define FDONE_MASK	0x80000000
+
+#define FLENEN          0x2
+
+static DECLARE_WAIT_QUEUE_HEAD(mdma_memcpy_busy_queue);
+static DECLARE_WAIT_QUEUE_HEAD(mdma_done_queue);
+
+unsigned long mdma_in_desc_phy;
+unsigned long mdma_out_desc_phy;
+
+struct comcerto_memcpy_inbound_fdesc *mdma_in_desc;
+struct comcerto_memcpy_outbound_fdesc *mdma_out_desc;
+
+EXPORT_SYMBOL(mdma_in_desc);
+EXPORT_SYMBOL(mdma_out_desc);
+
+static inline void comcerto_xor_set_in_bdesc(u32 buf_idx, u32 bdesc_idx, u32 addr, u32 ctrl)
+{
+	xor_in_fdesc[buf_idx]->bdesc[bdesc_idx].bpointer = addr;
+	xor_in_fdesc[buf_idx]->bdesc[bdesc_idx].bcontrol = ctrl;
+}
+
+static inline void comcerto_xor_set_out_bdesc(u32 buf_idx, u32 bdesc_idx, u32 addr, u32 ctrl)
+{
+	xor_out_fdesc[buf_idx]->bdesc[bdesc_idx].bpointer = addr;
+	xor_out_fdesc[buf_idx]->bdesc[bdesc_idx].bcontrol = ctrl;
+}
+
+static void comcerto_xor_set_desc(sw_idx,  hw_idx)
+{
+	int i,split_no;
+	u32 fstatus0 = 0;
+	u32 addr;
+	int split_size;
+	dma_addr_t dest;
+	dma_addr_t *srcs;	
+	u32 block_size;
+	int src_cnt;
+
+	block_size = sw_xor_desc[sw_idx].len;
+	src_cnt = sw_xor_desc[sw_idx].src_cnt;
+	srcs = sw_xor_desc[sw_idx].dma_src;
+	dest = sw_xor_desc[sw_idx].dma_dest;
+
+	if(block_size != PAGE_SIZE)
+		printk("%s: input buffers not %d len\n",__func__, (unsigned int)PAGE_SIZE);	
+
+#if defined(CONFIG_COMCERTO_64K_PAGES)
+	block_size = block_size/16; //to get 4K
+	split_size = 16;
+#else
+	split_size = 1;
+#endif
+
+	for(split_no = 0 ; split_no < split_size; split_no++)
+	{
+
+		for(i = 0; i < src_cnt - 1; i++) {
+			addr = (u32)sw_xor_desc[sw_idx].dma_src[i] + 4096 * split_no;
+			comcerto_xor_set_in_bdesc(hw_idx, i, addr, block_size);
+		}
+
+		addr = (u32)sw_xor_desc[sw_idx].dma_src[src_cnt - 1] + 4096 * split_no;
+		comcerto_xor_set_in_bdesc(hw_idx, src_cnt - 1, addr, block_size | BLAST);
+
+		fstatus0 = 1; // New Req, reset block counter, block offset, clear scratchpad (overwrite existing data)
+		fstatus0 |=  (1 << 1); // Read SP, return content of scratch pad after processing input data
+		fstatus0 |=  (0 << 2); // Mode, Encode
+		fstatus0 |=  (src_cnt << 4); // Number of blocks to be processed
+		fstatus0 |=  (1 << 9); // Type, XOR
+		fstatus0 |=  (XOR_BLOCK_SIZE_4096 << 11);
+
+		xor_in_fdesc[hw_idx]->fcontrol = 0;
+		xor_in_fdesc[hw_idx]->fstatus0 = fstatus0;
+		xor_in_fdesc[hw_idx]->fstatus1 = 0;
+
+		addr = (u32)sw_xor_desc[sw_idx].dma_dest + 4096 * split_no;
+		comcerto_xor_set_out_bdesc(hw_idx, 0, addr, block_size | BLAST);
+
+		xor_out_fdesc[hw_idx]->fcontrol = 0;
+		xor_out_fdesc[hw_idx]->fstatus0 = 0;
+		xor_out_fdesc[hw_idx]->fstatus1 = 0;
+
+		hw_idx = (hw_idx + 1) % XOR_FDESC_COUNT;
+	}
+
+	xor_wr_idx = hw_idx;
+}
+
+static inline int comcerto_dma_busy(void)
+{
+	return (readl_relaxed(IO2M_CONTROL) & 0x1);
+}
+
+static void comcerto_xor_update_dma_head(int idx)
+{
+	u32 out_desc_head, in_desc_head;
+	out_desc_head = virt_to_xor_dma(comcerto_xor_pool_phy, comcerto_xor_pool_virt, xor_out_fdesc[idx]);
+	in_desc_head = virt_to_xor_dma(comcerto_xor_pool_phy, comcerto_xor_pool_virt, xor_in_fdesc[idx]);
+
+	wmb();
+	writel_relaxed(out_desc_head, IO2M_HEAD);
+	writel_relaxed(in_desc_head, M2IO_HEAD);
+}
+
+static void comcerto_xor_update_dma_flen(int flen)
+{
+	wmb();
+	writel_relaxed(flen, M2IO_FLEN);
+	writel_relaxed(flen, IO2M_FLEN);
+}
+
+static int comcerto_xor_rb_full(void)
+{
+	if(CIRC_SPACE(xor_sw_wr_idx, xor_sw_rd_idx, XOR_SW_FDESC_COUNT) > 0)
+		return 0;
+	else
+		return 1;
+}
+
+void comcerto_xor_request_wait(void)
+{
+	DEFINE_WAIT(wait);
+
+	prepare_to_wait(&comcerto_xor_wait_queue, &wait, TASK_UNINTERRUPTIBLE);
+
+	comcerto_xor_sleeping++;
+
+	while (comcerto_xor_rb_full()) {
+		spin_unlock_bh(&comcerto_xor_ch.lock);
+		schedule();
+		spin_lock_bh(&comcerto_xor_ch.lock);
+		prepare_to_wait(&comcerto_xor_wait_queue, &wait, TASK_UNINTERRUPTIBLE);
+	}
+
+	finish_wait(&comcerto_xor_wait_queue, &wait);
+	comcerto_xor_sleeping--;
+}
+
+static void comcerto_dma_process(void)
+{
+	unsigned long pending_count;
+
+	if(!dma_owned || dma_owned==OWNER_XOR_FREE)
+	{
+		pending_count = CIRC_CNT(xor_wr_idx, xor_dma_idx, XOR_FDESC_COUNT);
+		if(pending_count)
+		{
+			dma_owned = OWNER_XOR_BUSY;
+			xor_current_batch_count = pending_count;
+			comcerto_xor_update_dma_flen(pending_count);
+			comcerto_xor_update_dma_head(xor_dma_idx);
+		}
+	}
+}
+
+static void comcerto_xor_cleanup(void)
+{
+	int i,j,k;
+	int idx;
+	int cleanup_count;
+	unsigned long flags;
+	int split_size;
+	struct comcerto_sw_xor_desc *sw_desc;
+
+	spin_lock_irqsave(&mdma_lock, flags);
+	cleanup_count = CIRC_CNT(xor_dma_idx, xor_rd_idx, XOR_FDESC_COUNT);
+	spin_unlock_irqrestore(&mdma_lock, flags);
+
+#if defined(CONFIG_COMCERTO_64K_PAGES)
+	split_size = 16;
+#else
+	split_size = 1;
+#endif
+
+	if(cleanup_count && (cleanup_count % split_size == 0))
+	{
+		for(i = 0 ; i < cleanup_count/split_size; i++)
+		{
+			struct dma_async_tx_descriptor *tx;
+
+#if defined(CONFIG_COMCERTO_64K_PAGES)
+			if(xor_rd_idx%16)
+				printk("%s: xor_rd_idx %d not multiple of 16\n",__func__, xor_rd_idx);
+#endif
+			idx = xor_sw_rd_idx;
+			tx = &sw_xor_desc[idx].async_tx;
+			sw_desc = &sw_xor_desc[idx];
+
+			for (j = 0; j < sw_desc->src_cnt; j++) {
+				dma_unmap_page(NULL, sw_desc->dma_src[j], sw_desc->len, DMA_TO_DEVICE);
+			}
+			dma_unmap_page(NULL, sw_desc->dma_dest, sw_desc->len, DMA_BIDIRECTIONAL);
+
+			comcerto_xor_ch.completed_cookie = tx->cookie;
+
+			if (tx->callback) {
+				tx->callback(tx->callback_param);
+				tx->callback = NULL;
+			}
+			else
+				printk("No Callback\n");
+
+			smp_mb();		
+
+			spin_lock_irqsave(&mdma_lock, flags);
+			for(k = 0 ; k < split_size; k++)
+			{
+				xor_rd_idx = (xor_rd_idx + 1) % XOR_FDESC_COUNT;
+			}
+			spin_unlock_irqrestore(&mdma_lock, flags);
+
+			xor_sw_rd_idx = (xor_sw_rd_idx + 1) % XOR_SW_FDESC_COUNT;
+		}
+	}
+	else
+	{
+		if(cleanup_count)
+			printk("%s: cleanup_count %d not multiple of 16\n",__func__, cleanup_count);
+	}
+}
+
+static void comcerto_xor_tasklet(unsigned long data)
+{
+	spin_lock_bh(&comcerto_xor_ch.lock);
+
+	comcerto_xor_cleanup();
+
+	spin_unlock_bh(&comcerto_xor_ch.lock);
+}
+
+static void comcerto_xor_timer_fnc(unsigned long data)
+{
+	unsigned long           flags;
+
+	spin_lock_irqsave(&mdma_lock, flags);
+
+	if(comcerto_xor_sleeping)
+		wake_up(&comcerto_xor_wait_queue);
+
+	spin_unlock_irqrestore(&mdma_lock, flags);
+
+	comcerto_xor_tasklet(0);
+
+	mod_timer(&comcerto_xor_timer, jiffies + COMPLETION_TIMEOUT);
+
+}
+
+
+static void comcerto_xor_issue_pending(struct dma_chan *chan)
+{
+	unsigned long           flags;
+
+
+	spin_lock_irqsave(&mdma_lock, flags);
+
+	comcerto_dma_process();
+
+	if(comcerto_xor_sleeping)
+		wake_up(&comcerto_xor_wait_queue);
+
+	spin_unlock_irqrestore(&mdma_lock, flags);
+
+	comcerto_xor_tasklet(0);
+}
+
+static inline struct comcerto_sw_xor_desc *txd_to_comcerto_desc(struct dma_async_tx_descriptor *txd)
+{
+	return container_of(txd, struct comcerto_sw_xor_desc, async_tx);
+}
+
+
+static dma_cookie_t comcerto_xor_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+	unsigned long flags;
+
+	struct dma_chan *c = tx->chan;
+	dma_cookie_t cookie;
+
+	spin_lock_bh(&comcerto_xor_ch.lock);
+
+	cookie = c->cookie;
+	cookie++;
+	if (cookie < 0)
+		cookie = 1;
+	tx->cookie = cookie;
+	c->cookie = cookie;
+
+	spin_lock_irqsave(&mdma_lock, flags);
+
+	comcerto_xor_set_desc(xor_sw_wr_prev_idx, xor_wr_idx);
+	xor_sw_wr_prev_idx = (xor_sw_wr_prev_idx + 1) % XOR_SW_FDESC_COUNT ;
+	comcerto_dma_process();
+
+	spin_unlock_irqrestore(&mdma_lock, flags);
+
+	spin_unlock_bh(&comcerto_xor_ch.lock);
+
+	if(comerto_xor_timer_first)
+	{
+		mod_timer(&comcerto_xor_timer, jiffies + COMPLETION_TIMEOUT);
+		comerto_xor_timer_first = 0;
+	}
+	return cookie;
+}
+
+	struct dma_async_tx_descriptor *
+comcerto_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *srcs,
+		unsigned int src_cnt, size_t len, unsigned long xor_flags)
+{
+	int desc_idx;
+	int i;
+
+	spin_lock_bh(&comcerto_xor_ch.lock);
+	if(comcerto_xor_rb_full())
+	{
+		comcerto_xor_request_wait();
+	}
+
+	desc_idx = xor_sw_wr_idx;
+	xor_sw_wr_idx = (xor_sw_wr_idx + 1) % XOR_SW_FDESC_COUNT ;
+
+	sw_xor_desc[desc_idx].async_tx.flags = xor_flags;
+	sw_xor_desc[desc_idx].src_cnt = src_cnt;
+	sw_xor_desc[desc_idx].len = len;
+	sw_xor_desc[desc_idx].dma_dest = dest;
+	for(i = 0; i < src_cnt; i++)
+		sw_xor_desc[desc_idx].dma_src[i] = srcs[i];
+
+	spin_unlock_bh(&comcerto_xor_ch.lock);
+
+	return &sw_xor_desc[desc_idx].async_tx;
+
+}
+
+
+static int comcerto_xor_alloc_chan_resources(struct dma_chan *chan)
+{
+	int i;
+
+	for(i = 0; i < XOR_SW_FDESC_COUNT; i++) {
+		memset(&sw_xor_desc[i], 0, sizeof(struct comcerto_sw_xor_desc));
+		sw_xor_desc[i].async_tx.tx_submit = comcerto_xor_tx_submit;
+		sw_xor_desc[i].async_tx.cookie = 0;
+		dma_async_tx_descriptor_init(&sw_xor_desc[i].async_tx, chan);
+	}
+	return XOR_SW_FDESC_COUNT;
+}
+
+static void comcerto_xor_free_chan_resources(struct dma_chan *chan)
+{
+	//TODO
+
+	printk("*** %s ***\n",__func__);
+
+	return;
+}
+
+static enum dma_status comcerto_xor_status(struct dma_chan *chan,
+		dma_cookie_t cookie,
+		struct dma_tx_state *txstate)
+{
+	dma_cookie_t last_used;
+	dma_cookie_t last_complete;
+
+	last_used = chan->cookie;
+	last_complete = comcerto_xor_ch.completed_cookie;
+	dma_set_tx_state(txstate, last_complete, last_used, 0);
+
+	return dma_async_is_complete(cookie, last_complete, last_used);
+}
+
+
+#if defined(CONFIG_COMCERTO_MDMA_PROF)
+
+unsigned int mdma_time_counter[256];
+unsigned int mdma_reqtime_counter[256];
+unsigned int mdma_data_counter[256];
+static struct timeval last_mdma;
+unsigned int init_mdma_prof = 0;
+unsigned int enable_mdma_prof = 0;
+
+void comcerto_dma_profiling_start(struct comcerto_dma_sg *sg, unsigned int len)
+{
+	long diff_time_us;
+
+	if (enable_mdma_prof) {
+		do_gettimeofday(&sg->start);
+
+		if (init_mdma_prof) {
+			diff_time_us = ((sg->start.tv_sec - last_mdma.tv_sec) * 1000000 + sg->start.tv_usec - last_mdma.tv_usec) >> 4;
+			if (diff_time_us < 256) {
+				mdma_time_counter[diff_time_us]++;
+			}
+			else {
+				mdma_time_counter[255]++;
+			}
+		}
+
+		len >>= 13;
+
+		if (len < 256)
+			mdma_data_counter[len]++;
+		else
+			mdma_data_counter[255]++;
+	}
+}
+
+void comcerto_dma_profiling_end(struct comcerto_dma_sg *sg)
+{
+	long diff_time_us;
+
+	if (enable_mdma_prof) {
+		do_gettimeofday(&sg->end);
+
+		diff_time_us = ((sg->end.tv_sec - sg->start.tv_sec) * 1000000 + sg->end.tv_usec - sg->start.tv_usec) >> 4;
+		if (diff_time_us < 256) {
+			mdma_reqtime_counter[diff_time_us]++;
+		}
+		else
+			mdma_reqtime_counter[255]++;
+
+		if (!init_mdma_prof)
+			init_mdma_prof = 1;
+
+		last_mdma = sg->end;
+	}
+}
+
+#else
+void comcerto_dma_profiling_start(struct comcerto_dma_sg *sg, unsigned int len) {}
+void comcerto_dma_profiling_end(struct comcerto_dma_sg *sg) {}
+#endif
+
+
+static inline dma_addr_t dma_acp_map_page(struct comcerto_dma_sg *sg, void *p, unsigned int len, int dir, int use_acp)
+{
+	dma_addr_t phys_addr = virt_to_phys(p);
+	dma_addr_t low, high;
+
+	if (!use_acp)
+		goto map;
+
+	if ((phys_addr >= sg->low_phys_addr) && (phys_addr + len) < sg->high_phys_addr)
+	{
+		/* In range, skip mapping */
+		return COMCERTO_AXI_ACP_BASE + phys_addr;
+	}
+
+	/* Try to grow window, if possible */
+	if (phys_addr < sg->low_phys_addr)
+		low = phys_addr & ~(COMCERTO_AXI_ACP_SIZE - 1);
+	else
+		low = sg->low_phys_addr;
+
+	if ((phys_addr + len) > sg->high_phys_addr)
+		high = (phys_addr + len + COMCERTO_AXI_ACP_SIZE - 1) & ~(COMCERTO_AXI_ACP_SIZE - 1);
+	else
+		high = sg->high_phys_addr;
+
+	if ((high - low) <= COMCERTO_AXI_ACP_SIZE) {
+		sg->low_phys_addr = low;
+		sg->high_phys_addr = high;
+
+		return COMCERTO_AXI_ACP_BASE + phys_addr;
+	}
+
+map:
+	return dma_map_single(NULL, p, len, dir); //TODO add proper checks
+}
+
+
+int comcerto_dma_sg_add_input(struct comcerto_dma_sg *sg, void *p, unsigned int len, int use_acp)
+{
+	dma_addr_t phys_addr;
+
+	if (unlikely(len > (MDMA_MAX_BUF_SIZE + 1))) {
+		printk(KERN_ERR "%s: tried to add a page larger than %d kB.\n", __func__, MDMA_MAX_BUF_SIZE + 1);
+		return -2;
+	}
+
+	if (len <= MDMA_MAX_BUF_SIZE) {
+		if (sg->input_idx >= MDMA_INBOUND_BUF_DESC)
+			return -1;
+
+		phys_addr = dma_acp_map_page(sg, p, len, DMA_TO_DEVICE, use_acp);
+
+		sg->in_bdesc[sg->input_idx].split = 0;
+		sg->in_bdesc[sg->input_idx].phys_addr = phys_addr;
+		sg->in_bdesc[sg->input_idx].len = len;
+		sg->input_idx++;
+
+		return 0;
+	}
+	else { /* len = MSPD_MDMA_MAX_BUF_SIZE +1, split it in 2 pieces */
+		if (sg->input_idx >= (MDMA_INBOUND_BUF_DESC - 1))
+			return -1;
+
+		phys_addr = dma_acp_map_page(sg, p, len, DMA_TO_DEVICE, use_acp);
+
+		sg->in_bdesc[sg->input_idx].split = 1;
+		sg->in_bdesc[sg->input_idx].phys_addr = phys_addr;
+		sg->in_bdesc[sg->input_idx].len = MDMA_SPLIT_BUF_SIZE;
+		sg->input_idx++;
+		sg->in_bdesc[sg->input_idx].split = 0;
+		sg->in_bdesc[sg->input_idx].phys_addr = phys_addr + MDMA_SPLIT_BUF_SIZE;
+		sg->in_bdesc[sg->input_idx].len = len - MDMA_SPLIT_BUF_SIZE;
+		sg->input_idx++;
+
+		return 0;
+	}
+}
+EXPORT_SYMBOL(comcerto_dma_sg_add_input);
+
+int comcerto_dma_sg_add_output(struct comcerto_dma_sg *sg, void *p, unsigned int len, int use_acp)
+{
+	dma_addr_t phys_addr;
+
+	if (unlikely(len > (MDMA_MAX_BUF_SIZE + 1))) {
+		printk(KERN_ERR "%s: tried to add a page larger than %d kB.\n", __func__, MDMA_MAX_BUF_SIZE + 1);
+		return -2;
+	}
+
+	if (len <= MDMA_MAX_BUF_SIZE) {
+		if (sg->output_idx >= MDMA_OUTBOUND_BUF_DESC)
+			return -1;
+
+		phys_addr = dma_acp_map_page(sg, p, len, DMA_FROM_DEVICE, use_acp);
+
+		sg->out_bdesc[sg->output_idx].split = 0;
+		sg->out_bdesc[sg->output_idx].phys_addr = phys_addr;
+		sg->out_bdesc[sg->output_idx].len = len;
+		sg->output_idx++;
+
+		return 0;
+	}
+	else { /* len = MDMA_MAX_BUF_SIZE +1, split it in 2 pieces */
+		if (sg->output_idx >= (MDMA_OUTBOUND_BUF_DESC - 1))
+			return -1;
+
+		phys_addr = dma_acp_map_page(sg, p, len, DMA_FROM_DEVICE, use_acp);
+
+		sg->out_bdesc[sg->output_idx].split = 1;
+		sg->out_bdesc[sg->output_idx].phys_addr = phys_addr;
+		sg->out_bdesc[sg->output_idx].len = MDMA_SPLIT_BUF_SIZE;
+		sg->output_idx++;
+		sg->out_bdesc[sg->output_idx].split = 0;
+		sg->out_bdesc[sg->output_idx].phys_addr = phys_addr + MDMA_SPLIT_BUF_SIZE;
+		sg->out_bdesc[sg->output_idx].len = len - MDMA_SPLIT_BUF_SIZE;
+		sg->output_idx++;
+
+		return 0;
+	}
+}
+EXPORT_SYMBOL(comcerto_dma_sg_add_output);
+
+void comcerto_dma_sg_setup(struct comcerto_dma_sg *sg, unsigned int len)
+{
+	int i;
+	unsigned int remaining;
+
+	comcerto_dma_profiling_start(sg, len);
+
+	writel_relaxed(sg->low_phys_addr |
+			AWUSER_COHERENT(WRITEBACK) | AWPROT(0x0) | AWCACHE(CACHEABLE | BUFFERABLE) |
+			ARUSER_COHERENT(WRITEBACK) | ARPROT(0x0) | ARCACHE(CACHEABLE | BUFFERABLE),
+			COMCERTO_GPIO_A9_ACP_CONF_REG);
+
+	remaining = len;
+	i = 0;
+	while (remaining > sg->in_bdesc[i].len) {
+
+		if (sg->in_bdesc[i].phys_addr >= COMCERTO_AXI_ACP_BASE)
+			sg->in_bdesc[i].phys_addr -= sg->low_phys_addr;
+
+		comcerto_dma_set_in_bdesc(i, sg->in_bdesc[i].phys_addr, sg->in_bdesc[i].len);
+		remaining -= sg->in_bdesc[i].len;
+		i++;
+	}
+
+	if (sg->in_bdesc[i].phys_addr >= COMCERTO_AXI_ACP_BASE)
+		sg->in_bdesc[i].phys_addr -= sg->low_phys_addr;
+
+	comcerto_dma_set_in_bdesc(i, sg->in_bdesc[i].phys_addr, remaining | BLAST);
+
+	remaining = len;
+	i = 0;
+
+	while (remaining > sg->out_bdesc[i].len) {
+		if (sg->out_bdesc[i].phys_addr >= COMCERTO_AXI_ACP_BASE)
+			sg->out_bdesc[i].phys_addr -= sg->low_phys_addr;
+
+		comcerto_dma_set_out_bdesc(i, sg->out_bdesc[i].phys_addr, sg->out_bdesc[i].len);
+		remaining -= sg->out_bdesc[i].len;
+		i++;
+	}
+
+	if (sg->out_bdesc[i].phys_addr >= COMCERTO_AXI_ACP_BASE)
+		sg->out_bdesc[i].phys_addr -= sg->low_phys_addr;
+
+	comcerto_dma_set_out_bdesc(i, sg->out_bdesc[i].phys_addr, remaining | BLAST);
+}
+EXPORT_SYMBOL(comcerto_dma_sg_setup);
+
+void comcerto_dma_sg_cleanup(struct comcerto_dma_sg *sg, unsigned int len)
+{
+	int i;
+	unsigned int remaining;
+
+	remaining = len;
+	i = 0;
+	while (remaining > sg->in_bdesc[i].len) {
+		if (sg->in_bdesc[i].split) {
+			sg->in_bdesc[i+1].phys_addr = sg->in_bdesc[i].phys_addr;
+			sg->in_bdesc[i+1].len += sg->in_bdesc[i].len;
+		}
+		else {
+			if (sg->in_bdesc[i].phys_addr < COMCERTO_AXI_ACP_BASE)
+				dma_unmap_page(NULL, sg->in_bdesc[i].phys_addr, sg->in_bdesc[i].len, DMA_TO_DEVICE);
+			remaining -= sg->in_bdesc[i].len;
+		}
+		i++;
+	}
+
+	if (sg->in_bdesc[i].phys_addr < COMCERTO_AXI_ACP_BASE)
+		dma_unmap_page(NULL, sg->in_bdesc[i].phys_addr, sg->in_bdesc[i].len, DMA_TO_DEVICE);
+
+	remaining = len;
+	i = 0;
+	while (remaining > sg->out_bdesc[i].len) {
+		if (sg->out_bdesc[i].split) {
+			sg->out_bdesc[i+1].phys_addr = sg->out_bdesc[i].phys_addr;
+			sg->out_bdesc[i+1].len += sg->out_bdesc[i].len;
+		}
+		else {
+			if (sg->out_bdesc[i].phys_addr < COMCERTO_AXI_ACP_BASE)
+				dma_unmap_page(NULL, sg->out_bdesc[i].phys_addr, sg->out_bdesc[i].len, DMA_FROM_DEVICE);
+			remaining -= sg->out_bdesc[i].len;
+		}
+		i++;
+	}
+
+	if (sg->out_bdesc[i].phys_addr < COMCERTO_AXI_ACP_BASE)
+		dma_unmap_page(NULL, sg->out_bdesc[i].phys_addr, sg->out_bdesc[i].len, DMA_FROM_DEVICE);
+
+
+	comcerto_dma_profiling_end(sg);
+}
+EXPORT_SYMBOL(comcerto_dma_sg_cleanup);
+
+void comcerto_dma_get(void)
+{
+	unsigned long flags;
+	DEFINE_WAIT(wait);
+
+	spin_lock_irqsave(&mdma_lock, flags);
+
+	if (dma_owned && (dma_owned != OWNER_MEMCPY_FREE)) {
+		prepare_to_wait(&mdma_memcpy_busy_queue, &wait, TASK_UNINTERRUPTIBLE);
+
+		memcpy_pending_count++;
+
+		while (!dma_owned || !(dma_owned == OWNER_MEMCPY_FREE)) {
+			spin_unlock_irqrestore(&mdma_lock, flags);
+			schedule();
+			spin_lock_irqsave(&mdma_lock, flags);
+			prepare_to_wait(&mdma_memcpy_busy_queue, &wait, TASK_UNINTERRUPTIBLE);
+		}
+
+		memcpy_pending_count--;
+
+		finish_wait(&mdma_memcpy_busy_queue, &wait);
+	}
+	dma_owned = OWNER_MEMCPY_BUSY;
+
+	spin_unlock_irqrestore(&mdma_lock, flags);
+}
+EXPORT_SYMBOL(comcerto_dma_get);
+
+void comcerto_dma_put(void)
+{
+#if 0
+	unsigned long flags;
+
+	spin_lock_irqsave(&mdma_lock, flags);
+	mdma_busy = 0;
+	spin_unlock_irqrestore(&mdma_lock, flags);
+
+	wake_up(&mdma_memcpy_busy_queue);
+#endif
+}
+EXPORT_SYMBOL(comcerto_dma_put);
+
+/* Called once to setup common registers */
+static void comcerto_dma_setup(void)
+{
+	/* IO2M_IRQ_ENABLE: Enable IRQ_IRQFDON*/
+	writel_relaxed(IRQ_IRQFDON|IRQ_IRQFLEN|IRQ_IRQFTHLD|IRQ_IRQFLST, IO2M_IRQ_ENABLE);
+	writel_relaxed(IRQ_IRQFDON|IRQ_IRQFLEN|IRQ_IRQFTHLD|IRQ_IRQFLST, M2IO_IRQ_ENABLE);
+
+	writel_relaxed(FLENEN, M2IO_CONTROL);
+	writel_relaxed(0xf | (0x3ff << 8), M2IO_BURST);
+	writel_relaxed(FLENEN, IO2M_CONTROL);
+	writel_relaxed(0xf | (0x3ff << 8), IO2M_BURST);
+}
+
+
+void comcerto_dma_start(void)
+{
+	mdma_done = 0;
+
+	mdma_in_desc->next_desc = 0;
+	mdma_in_desc->fcontrol = 0;
+	mdma_in_desc->fstatus0 = 0;
+	mdma_in_desc->fstatus1 = 0;
+
+	// outbound
+	mdma_out_desc->next_desc = 0;
+	mdma_out_desc->fcontrol = 0;
+	mdma_out_desc->fstatus0 = 0;
+	mdma_out_desc->fstatus1 = 0;
+
+	wmb();
+
+	// Initialize the Outbound Head Pointer
+	writel_relaxed(mdma_out_desc_phy, IO2M_HEAD);
+
+	// Initialize the Inbound Head Pointer
+	writel_relaxed(mdma_in_desc_phy, M2IO_HEAD);
+
+	writel_relaxed(1, M2IO_FLEN);
+	writel_relaxed(1, IO2M_FLEN);
+
+	wmb();
+}
+EXPORT_SYMBOL(comcerto_dma_start);
+
+
+void comcerto_dma_wait(void)
+{
+	DEFINE_WAIT(wait);
+
+	prepare_to_wait(&mdma_done_queue, &wait, TASK_UNINTERRUPTIBLE);
+
+	if (!mdma_done)
+		schedule();
+
+	finish_wait(&mdma_done_queue, &wait);
+}
+EXPORT_SYMBOL(comcerto_dma_wait);
+
+static void comcerto_dump_regs(void)
+{
+	u32 val;
+
+	val = readl_relaxed(M2IO_CONTROL);
+	printk(KERN_ERR"M2IO_CONTROL         0x%8x.\n",val);
+
+	val = readl_relaxed(M2IO_HEAD);
+	printk(KERN_ERR"M2IO_HEAD            0x%8x.\n",val);
+
+	val = readl_relaxed(M2IO_BURST);
+	printk(KERN_ERR"M2IO_BURST           0x%8x.\n",val);
+
+	val = readl_relaxed(M2IO_FLEN);
+	printk(KERN_ERR"M2IO_FLEN            0x%8x.\n",val);
+
+	val = readl_relaxed(M2IO_IRQ_ENABLE);
+	printk(KERN_ERR"M2IO_IRQ_ENABLE      0x%8x.\n",val);
+
+	val = readl_relaxed(M2IO_IRQ_STATUS);
+	printk(KERN_ERR"M2IO_IRQ_STATUS      0x%8x.\n",val);
+
+	val = readl_relaxed(M2IO_RESET);
+	printk(KERN_ERR"M2IO_RESET           0x%8x.\n",val);
+
+	val = readl_relaxed(IO2M_CONTROL);
+	printk(KERN_ERR"IO2M_CONTROL         0x%8x.\n",val);
+
+	val = readl_relaxed(IO2M_HEAD);
+	printk(KERN_ERR"IO2M_HEAD            0x%8x.\n",val);
+
+	val = readl_relaxed(IO2M_BURST);
+	printk(KERN_ERR"IO2M_BURST           0x%8x.\n",val);
+
+	val = readl_relaxed(IO2M_FLEN);
+	printk(KERN_ERR"IO2M_FLEN            0x%8x.\n",val);
+
+	val = readl_relaxed(IO2M_IRQ_ENABLE);
+	printk(KERN_ERR"IO2M_IRQ_ENABLE      0x%8x.\n",val);
+
+	val = readl_relaxed(IO2M_IRQ_STATUS);
+	printk(KERN_ERR"IO2M_IRQ_STATUS      0x%8x.\n",val);
+
+	val = readl_relaxed(IO2M_RESET);
+	printk(KERN_ERR"IO2M_RESET           0x%8x.\n",val);
+}
+
+static irqreturn_t c2k_dma_handle_interrupt(int irq, void *data)
+{
+	int i;
+	int pending_count;
+	unsigned long flags;
+	u32 intr_cause = readl_relaxed(IO2M_IRQ_STATUS);
+
+	writel_relaxed(intr_cause, IO2M_IRQ_STATUS);
+
+	if (unlikely(intr_cause & ~(IRQ_IRQFDON | IRQ_IRQFLST | IRQ_IRQFLEN))) {
+		if (intr_cause & IRQ_IRQFRDYN)
+			printk(KERN_ALERT "IRQFRDYN: A frame is started but the frame is not ready");
+
+		if (intr_cause & IRQ_IRQFLSH)
+			printk(KERN_ALERT "IRQFLSH: IO has more data than the memory buffer");
+
+		if (intr_cause & IRQ_IRQFTHLD)
+			printk(KERN_ALERT "IRQFTHLD: Frame threshold reached. FLEN=FTHLDL");
+
+		if (intr_cause & IRQ_IRQFCTRL)
+			printk(KERN_ALERT "IRQFCTRL: 1 frame is completed or when a frame is started but not ready");	
+
+		comcerto_dump_regs();
+	}
+
+	if (intr_cause & IRQ_IRQFDON) {
+
+	}
+
+	if (intr_cause & IRQ_IRQFLEN) {
+
+		spin_lock_irqsave(&mdma_lock, flags);
+		if(!dma_owned)
+			printk(KERN_ALERT " NULL MDMA Ownership !!!\n");
+
+
+		if(dma_owned==OWNER_XOR_BUSY)
+		{
+
+			for(i = 0 ; i < xor_current_batch_count; i++)
+				xor_dma_idx = (xor_dma_idx + 1) % XOR_FDESC_COUNT;
+
+			xor_current_batch_count = 0;
+
+
+			if(memcpy_pending_count)
+			{
+				dma_owned = OWNER_MEMCPY_FREE;
+				wake_up(&mdma_memcpy_busy_queue);
+			}
+			else
+			{
+				pending_count = CIRC_CNT(xor_wr_idx, xor_dma_idx, XOR_FDESC_COUNT);
+				if(pending_count)
+				{
+					dma_owned = OWNER_XOR_BUSY;
+					xor_current_batch_count = pending_count;
+					comcerto_xor_update_dma_flen(xor_current_batch_count);
+					comcerto_xor_update_dma_head(xor_dma_idx);
+				}
+				else
+				{
+					dma_owned = 0;
+				}
+			}
+
+			if(comcerto_xor_sleeping)
+			{
+				wake_up(&comcerto_xor_wait_queue);
+			}
+
+			tasklet_schedule(&comcerto_xor_ch.irq_tasklet);
+		}
+		else //memcpy
+		{
+			mdma_done = 1;
+			wake_up(&mdma_done_queue);
+
+			memcpy_processed_ongoing++;
+			pending_count = CIRC_CNT(xor_wr_idx, xor_dma_idx, XOR_FDESC_COUNT);
+
+			if(pending_count)
+			{
+				memcpy_processed_ongoing = 0;
+				dma_owned = OWNER_XOR_BUSY;
+				xor_current_batch_count = pending_count;
+				comcerto_xor_update_dma_flen(xor_current_batch_count);
+				comcerto_xor_update_dma_head(xor_dma_idx);
+
+				if(comcerto_xor_sleeping)
+				{
+					wake_up(&comcerto_xor_wait_queue);
+				}
+			}
+			else
+			{
+				if(memcpy_pending_count)
+				{
+					dma_owned = OWNER_MEMCPY_FREE;
+					wake_up(&mdma_memcpy_busy_queue);
+				}
+				else
+				{
+					dma_owned = 0;
+				}
+			}
+
+		}
+		spin_unlock_irqrestore(&mdma_lock, flags);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int __devexit comcerto_dma_remove(struct platform_device *pdev)
+{
+	int irq;
+
+	irq = platform_get_irq(pdev, 0);
+
+	iounmap(virtbase);
+
+	free_irq(irq, NULL);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static int __devinit comcerto_dma_probe(struct platform_device *pdev)
+{
+	struct resource      *io;
+	int                  irq;
+	void *memcpy_pool = (void *)IRAM_MEMORY_VADDR;
+	void *xor_pool;
+	int i;
+	struct dma_device    *dma_dev;
+	int ret = 0;
+
+	/* Retrieve related resources(mem, irq) from platform_device */
+	io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!io)
+		return -ENODEV;
+
+	irq = platform_get_irq(pdev,0);
+	if (irq < 0)
+		return irq;
+
+	ret = request_irq(irq, c2k_dma_handle_interrupt, 0, "MDMA", NULL);
+	if (ret < 0)
+		return ret;
+
+	virtbase = ioremap(io->start, resource_size(io));
+	if (!virtbase)
+		goto err_free_irq;
+
+	/* Initialize comcerto_xor_device */
+	comcerto_xor_dev = devm_kzalloc(&pdev->dev, sizeof(struct comcerto_xor_device), GFP_KERNEL);
+
+	if(!comcerto_xor_dev)
+	{
+		ret = -ENOMEM;
+		goto err_free_remap;
+	}
+
+	dma_dev = &comcerto_xor_dev->device;
+	INIT_LIST_HEAD(&dma_dev->channels);
+	dma_cap_set(DMA_XOR,dma_dev->cap_mask);
+	dma_dev->dev = &pdev->dev;
+	dma_dev->device_alloc_chan_resources = comcerto_xor_alloc_chan_resources;
+	dma_dev->device_free_chan_resources  = comcerto_xor_free_chan_resources;
+	dma_dev->device_tx_status            = comcerto_xor_status;
+	dma_dev->device_issue_pending        = comcerto_xor_issue_pending;
+	dma_dev->device_prep_dma_xor         = comcerto_xor_prep_dma_xor;
+	dma_dev->max_xor = XOR_MAX_SRC_CNT;
+	platform_set_drvdata(pdev,comcerto_xor_dev);
+
+	/* Initialize comcerto_xor_chan */
+	comcerto_xor_ch.chan.device = dma_dev;
+	list_add_tail(&comcerto_xor_ch.chan.device_node,&dma_dev->channels);
+
+	ret = dma_async_device_register(dma_dev);
+	if (unlikely(ret)) {
+		printk(KERN_ERR "%s: Failed to register XOR DMA channel %d\n",__func__,ret);
+		goto err_free_dma;
+	}
+	else
+		printk(KERN_INFO "%s: XOR DMA channel registered\n",__func__);
+
+	spin_lock_init(&comcerto_xor_ch.lock);
+	spin_lock_init(&comcerto_xor_cleanup_lock);
+
+	spin_lock_init(&mdma_lock);
+
+	//Memcpy descriptor initializing
+	mdma_in_desc = (struct comcerto_memcpy_inbound_fdesc *) (memcpy_pool);
+	memcpy_pool += sizeof(struct comcerto_memcpy_inbound_fdesc);
+	memcpy_pool = (void *)((unsigned long)(memcpy_pool + 15) & ~15);
+	mdma_out_desc = (struct comcerto_memcpy_outbound_fdesc *) (memcpy_pool);
+	memcpy_pool += sizeof(struct comcerto_memcpy_outbound_fdesc);
+	memcpy_pool = (void *)((unsigned long)(memcpy_pool + 15) & ~15);
+
+	mdma_in_desc_phy = virt_to_aram(mdma_in_desc);
+	mdma_out_desc_phy = virt_to_aram(mdma_out_desc);
+
+	//XOR descriptor initializing
+	comcerto_xor_pool_virt = dma_alloc_coherent(NULL, XOR_FDESC_COUNT * (sizeof(struct comcerto_xor_inbound_fdesc) 
+				+  sizeof(struct comcerto_xor_outbound_fdesc)), &comcerto_xor_pool_phy, GFP_KERNEL);
+	xor_pool = comcerto_xor_pool_virt;
+
+	for (i = 0; i < XOR_FDESC_COUNT; i++) {
+		xor_in_fdesc[i] = (struct comcerto_xor_inbound_fdesc *) (xor_pool);
+		xor_pool += sizeof(struct comcerto_xor_inbound_fdesc);
+		xor_pool = (void *)((unsigned long)(xor_pool + 15) & ~15);
+		xor_out_fdesc[i] = (struct comcerto_xor_outbound_fdesc *) (xor_pool);
+		xor_pool += sizeof(struct comcerto_xor_outbound_fdesc);
+		xor_pool = (void *)((unsigned long)(xor_pool + 15) & ~15);
+
+		memset(xor_in_fdesc[i], 0 , sizeof(struct comcerto_xor_inbound_fdesc));
+		memset(xor_out_fdesc[i], 0 , sizeof(struct comcerto_xor_outbound_fdesc));
+	}
+
+	for(i = 0; i < XOR_FDESC_COUNT - 1; i++) {
+		xor_in_fdesc[i]->next_desc = virt_to_xor_dma(comcerto_xor_pool_phy, comcerto_xor_pool_virt, xor_in_fdesc[i+1]);
+		xor_out_fdesc[i]->next_desc = virt_to_xor_dma(comcerto_xor_pool_phy, comcerto_xor_pool_virt, xor_out_fdesc[i+1]);
+	}
+	xor_in_fdesc[XOR_FDESC_COUNT-1]->next_desc = virt_to_xor_dma(comcerto_xor_pool_phy, comcerto_xor_pool_virt, xor_in_fdesc[0]);
+	xor_out_fdesc[XOR_FDESC_COUNT-1]->next_desc = virt_to_xor_dma(comcerto_xor_pool_phy, comcerto_xor_pool_virt, xor_out_fdesc[0]);
+
+	init_timer(&comcerto_xor_timer);
+	comcerto_xor_timer.function = comcerto_xor_timer_fnc;
+	comcerto_xor_timer.data = 0;
+
+	tasklet_init(&comcerto_xor_ch.irq_tasklet, comcerto_xor_tasklet, 0);
+
+	comcerto_dma_setup();
+
+	goto out;
+
+err_free_dma:
+	platform_set_drvdata(pdev,NULL);
+	kfree(comcerto_xor_dev);
+err_free_remap:
+	iounmap(virtbase);	
+err_free_irq:
+	free_irq(irq, NULL);
+out:
+	return ret;
+}
+
+
+static struct platform_driver comcerto_dma_driver = {
+	.probe        = comcerto_dma_probe,
+	.remove       = comcerto_dma_remove,
+	.driver       = {
+		.owner = THIS_MODULE,
+		.name  = "comcerto_dma",
+	},
+};
+
+static int __init comcerto_dma_init(void)
+{
+	return platform_driver_register(&comcerto_dma_driver);
+}
+module_init(comcerto_dma_init);
+
+static void __exit comcerto_dma_exit(void)
+{
+	platform_driver_unregister(&comcerto_dma_driver);
+}
+module_exit(comcerto_dma_exit);
+
+MODULE_DESCRIPTION("DMA engine driver for Mindspeed Comcerto C2000 devices");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/dma/comcerto_xor.c b/drivers/dma/comcerto_xor.c
new file mode 100644
index 0000000..eb0b3a2
--- /dev/null
+++ b/drivers/dma/comcerto_xor.c
@@ -0,0 +1,1237 @@
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/memory.h>
+#include "comcerto_xor.h"
+
+#define to_comcerto_xor_chan(dma_chan)              \
+	    container_of(dma_chan,struct comcerto_xor_chan, chan)
+
+#define to_comcerto_xor_device(dev)             \
+	    container_of(dev,struct comcerto_xor_device, device)
+
+#define to_comcerto_xor_slot(tx)                \
+		container_of(tx, struct comcerto_xor_desc_slot, async_tx)
+
+/* ---------------------- Functions to set/read frame descriptor --------------------------- */
+
+/* ------- Set inbound frame descriptor ------- */
+
+static void comcerto_set_next_desc_inbound(struct comcerto_xor_desc_slot *slot, u32 next_desc_addr)
+{
+	struct comcerto_xor_inbound_desc *hw_desc = slot->hw_desc_inbound;
+	hw_desc->next_desc = next_desc_addr;
+}
+
+static void comcerto_set_fcontrol_inbound(struct comcerto_xor_desc_slot *slot)
+{
+	struct comcerto_xor_inbound_desc *hw_desc = slot->hw_desc_inbound;
+
+	switch (slot->type) {
+	case DMA_XOR:
+	case DMA_XOR_VAL:
+	case DMA_MEMCPY:
+		hw_desc->fcontrol = 0;
+		break;
+	default:
+		dev_printk(KERN_ERR, slot->async_tx.chan->device->dev,
+				   "error: unsupported operation %d.\n",slot->type);
+	}
+}
+
+static void comcerto_set_fstatus0_inbound(struct comcerto_xor_desc_slot *slot)
+{
+	struct comcerto_xor_inbound_desc *hw_desc = slot->hw_desc_inbound;
+
+	switch (slot->type) {
+
+	case DMA_XOR:
+		hw_desc->fstatus0 = 1; 						// New Req, reset block counter, block offset, clear scratchpad (overwrite existing data)
+		hw_desc->fstatus0 = hw_desc->fstatus0 | (1 << 1); 		// Read SP, return content of scratch pad after processing input data
+		hw_desc->fstatus0 = hw_desc->fstatus0 | (0 << 2); 		// Mode, Encode
+		hw_desc->fstatus0 = hw_desc->fstatus0 | (slot->src_cnt << 4); 	// Number of blocks to be processed
+		hw_desc->fstatus0 = hw_desc->fstatus0 | (1 << 9); 		// Type, XOR
+		if(slot->len == 256)
+			hw_desc->fstatus0 = hw_desc->fstatus0 | (XOR_BLOCK_SIZE_256 << 11);
+		if(slot->len == 512)
+			hw_desc->fstatus0 = hw_desc->fstatus0 | (XOR_BLOCK_SIZE_512 << 11);
+		if(slot->len == 1024)
+			hw_desc->fstatus0 = hw_desc->fstatus0 | (XOR_BLOCK_SIZE_1024 << 11);
+		if(slot->len == 2048)
+			hw_desc->fstatus0 = hw_desc->fstatus0 | (XOR_BLOCK_SIZE_2048 << 11);
+		if(slot->len == 4096)
+			hw_desc->fstatus0 = hw_desc->fstatus0 | (XOR_BLOCK_SIZE_4096 << 11);
+		break;
+
+	case DMA_XOR_VAL:
+		hw_desc->fstatus0 = 1; 						// New Req, reset block counter, block offset, clear scratchpad (overwrite existing data)
+		hw_desc->fstatus0 = hw_desc->fstatus0 | (0 << 1); 		// Read SP, no output generated, only status
+		hw_desc->fstatus0 = hw_desc->fstatus0 | (1 << 2); 		// Mode, Validate
+		hw_desc->fstatus0 = hw_desc->fstatus0 | (slot->src_cnt << 4);	// Number of blocks to be processed
+		hw_desc->fstatus0 = hw_desc->fstatus0 | (1 << 9); 		// Type, XOR
+		if(slot->len == 256)
+			hw_desc->fstatus0 = hw_desc->fstatus0 | (XOR_BLOCK_SIZE_256 << 11);
+		if(slot->len == 512)
+			hw_desc->fstatus0 = hw_desc->fstatus0 | (XOR_BLOCK_SIZE_512 << 11);
+		if(slot->len == 1024)
+			hw_desc->fstatus0 = hw_desc->fstatus0 | (XOR_BLOCK_SIZE_1024 << 11);
+		if(slot->len == 2048)
+			hw_desc->fstatus0 = hw_desc->fstatus0 | (XOR_BLOCK_SIZE_2048 << 11);
+		if(slot->len == 4096)
+			hw_desc->fstatus0 = hw_desc->fstatus0 | (XOR_BLOCK_SIZE_4096 << 11);
+		break;
+	case DMA_MEMCPY:
+		break;
+	default:
+		dev_printk(KERN_ERR, slot->async_tx.chan->device->dev,
+				   "error: unsupported operation %d.\n",slot->type);
+		return;
+	}
+}
+
+static void comcerto_set_buff_info_inbound(struct comcerto_xor_desc_slot *slot, dma_addr_t *src)
+{
+	struct comcerto_xor_inbound_desc *hw_desc = slot->hw_desc_inbound;
+	int i;
+
+	if(slot->src_cnt > COMCERTO_XOR_MAX_SRC){
+		dev_printk(KERN_ERR, slot->async_tx.chan->device->dev,
+						   "error: max source available is %d.\n",COMCERTO_XOR_MAX_SRC);
+		return;
+	}
+
+	for(i=0; i<slot->src_cnt; i++) {
+		hw_desc->buff_info[i*2] = src[i];
+		if(i == slot->src_cnt - 1)
+			hw_desc->buff_info[i*2 + 1] = slot->len | BLAST;
+		else
+			hw_desc->buff_info[i*2 + 1] = slot->len;
+	}
+}
+
+/* ------- Set outbound frame descriptor ------- */
+
+static void comcerto_set_next_desc_outbound(struct comcerto_xor_desc_slot *slot, u32 next_desc_addr)
+{
+	struct comcerto_xor_outbound_desc *hw_desc = slot->hw_desc_outbound;
+	hw_desc->next_desc = next_desc_addr;
+}
+
+static void comcerto_set_fcontrol_outbound(struct comcerto_xor_desc_slot *slot)
+{
+	struct comcerto_xor_outbound_desc *hw_desc = slot->hw_desc_outbound;
+
+	switch (slot->type) {
+	case DMA_XOR:
+	case DMA_XOR_VAL:
+	case DMA_MEMCPY:
+		hw_desc->fcontrol = 0;
+		break;
+	default:
+		dev_printk(KERN_ERR, slot->async_tx.chan->device->dev,
+				   "error: unsupported operation %d.\n",slot->type);
+		return;
+	}
+}
+
+static void comcerto_set_buff_info_outbound(struct comcerto_xor_desc_slot *slot, dma_addr_t dest)
+{
+	struct comcerto_xor_outbound_desc *hw_desc = slot->hw_desc_outbound;
+
+	hw_desc->buff_info[0] = dest;
+	hw_desc->buff_info[1] = slot->len | BLAST;
+}
+
+/* ------- Read inbound frame descriptor ------- */
+
+static u32 comcerto_get_buff_info_inbound(struct comcerto_xor_desc_slot *slot, u16 i)
+{
+	struct comcerto_xor_inbound_desc *hw_desc = slot->hw_desc_inbound;
+	return hw_desc->buff_info[i*2];
+}
+
+/* ------- Read outbound frame descriptor ------- */
+
+static u32 comcerto_get_fstatus0_outbound(struct comcerto_xor_desc_slot *slot)
+{
+	struct comcerto_xor_outbound_desc *hw_desc = slot->hw_desc_outbound;
+	return hw_desc->fstatus0;
+}
+
+static u32 comcerto_get_buff_info_outbound(struct comcerto_xor_desc_slot *slot, u16 i)
+{
+	struct comcerto_xor_outbound_desc *hw_desc = slot->hw_desc_outbound;
+	return hw_desc->buff_info[i*2];
+}
+
+static void comcerto_xor_inbound_desc_init(struct comcerto_xor_desc_slot *slot,
+		                             dma_addr_t *src)
+{
+	struct comcerto_xor_inbound_desc *hw_desc = slot->hw_desc_inbound;
+
+	memset(hw_desc, 0, sizeof(struct comcerto_xor_inbound_desc));
+	comcerto_set_fcontrol_inbound(slot);
+	comcerto_set_fstatus0_inbound(slot);
+	comcerto_set_next_desc_inbound(slot, 0);
+	comcerto_set_buff_info_inbound(slot, src);
+}
+
+static void comcerto_xor_outbound_desc_init(struct comcerto_xor_desc_slot *slot,
+		                              dma_addr_t dest)
+{
+	struct comcerto_xor_outbound_desc *hw_desc = slot->hw_desc_outbound;
+
+	memset(hw_desc, 0, sizeof(struct comcerto_xor_outbound_desc));
+	comcerto_set_fcontrol_outbound(slot);
+	comcerto_set_next_desc_outbound(slot, 0);
+
+	if(dest)
+		comcerto_set_buff_info_outbound(slot, dest);
+}
+
+/* --------------------- Functions of register configuration --------------------------*/
+
+/* ------- Set inbound register ------- */
+
+static void comcerto_xor_set_register_m2io_control(struct comcerto_xor_chan *comcerto_xor_ch, u32 value)
+{
+	__raw_writel(value, M2IO_CONTROL(comcerto_xor_ch));
+}
+
+static void comcerto_xor_set_register_m2io_head(struct comcerto_xor_chan *comcerto_xor_ch, u32 value)
+{
+	__raw_writel(value, M2IO_HEAD(comcerto_xor_ch));
+}
+
+/* ------- Set outbound register ------- */
+
+static void comcerto_xor_set_register_io2m_head(struct comcerto_xor_chan *comcerto_xor_ch, u32 value)
+{
+	__raw_writel(value, IO2M_HEAD(comcerto_xor_ch));
+}
+
+static void comcerto_xor_set_register_io2m_irq_enable(struct comcerto_xor_chan *comcerto_xor_ch, u32 value)
+{
+	__raw_writel(value, IO2M_IRQ_ENABLE(comcerto_xor_ch));
+}
+
+static void comcerto_xor_set_register_io2m_irq_status(struct comcerto_xor_chan *comcerto_xor_ch, u32 value)
+{
+	__raw_writel(value, IO2M_IRQ_STATUS(comcerto_xor_ch));
+}
+
+/* ------- Read inbound register ------- */
+
+static u32 comcerto_xor_get_register_m2io_control(struct comcerto_xor_chan *comcerto_xor_ch)
+{
+	return __raw_readl(M2IO_CONTROL(comcerto_xor_ch));
+}
+
+/* ------- Read outbound register ------- */
+
+static u32 comcerto_xor_get_register_io2m_control(struct comcerto_xor_chan *comcerto_xor_ch)
+{
+	return __raw_readl(IO2M_CONTROL(comcerto_xor_ch));
+}
+
+static u32 comcerto_xor_get_register_io2m_head(struct comcerto_xor_chan *comcerto_xor_ch)
+{
+	return __raw_readl(IO2M_HEAD(comcerto_xor_ch));
+}
+
+static u32 comcerto_xor_get_register_io2m_irq_status(struct comcerto_xor_chan *comcerto_xor_ch)
+{
+	return __raw_readl(IO2M_IRQ_STATUS(comcerto_xor_ch));
+}
+
+static void comcerto_dump_xor_regs(struct comcerto_xor_chan *comcerto_xor_ch)
+{
+	u32 val;
+
+	val = __raw_readl(M2IO_CONTROL(comcerto_xor_ch));
+	dev_printk(KERN_ERR, comcerto_xor_ch->device->device.dev,
+			   "M2IO_CONTROL         0x%8x.\n",val);
+
+	val = __raw_readl(M2IO_HEAD(comcerto_xor_ch));
+	dev_printk(KERN_ERR, comcerto_xor_ch->device->device.dev,
+			   "M2IO_HEAD            0x%8x.\n",val);
+
+	val = __raw_readl(M2IO_BURST(comcerto_xor_ch));
+	dev_printk(KERN_ERR, comcerto_xor_ch->device->device.dev,
+			   "M2IO_BURST           0x%8x.\n",val);
+
+	val = __raw_readl(M2IO_FLEN(comcerto_xor_ch));
+	dev_printk(KERN_ERR, comcerto_xor_ch->device->device.dev,
+			   "M2IO_FLEN            0x%8x.\n",val);
+
+	val = __raw_readl(M2IO_IRQ_ENABLE(comcerto_xor_ch));
+	dev_printk(KERN_ERR, comcerto_xor_ch->device->device.dev,
+			   "M2IO_IRQ_ENABLE      0x%8x.\n",val);
+
+	val = __raw_readl(M2IO_IRQ_STATUS(comcerto_xor_ch));
+	dev_printk(KERN_ERR, comcerto_xor_ch->device->device.dev,
+			   "M2IO_IRQ_STATUS      0x%8x.\n",val);
+
+	val = __raw_readl(M2IO_RESET(comcerto_xor_ch));
+	dev_printk(KERN_ERR, comcerto_xor_ch->device->device.dev,
+			   "M2IO_RESET           0x%8x.\n",val);
+
+	val = __raw_readl(IO2M_CONTROL(comcerto_xor_ch));
+	dev_printk(KERN_ERR, comcerto_xor_ch->device->device.dev,
+			   "IO2M_CONTROL         0x%8x.\n",val);
+
+	val = __raw_readl(IO2M_HEAD(comcerto_xor_ch));
+	dev_printk(KERN_ERR, comcerto_xor_ch->device->device.dev,
+			   "IO2M_HEAD            0x%8x.\n",val);
+
+	val = __raw_readl(IO2M_BURST(comcerto_xor_ch));
+	dev_printk(KERN_ERR, comcerto_xor_ch->device->device.dev,
+			   "IO2M_BURST           0x%8x.\n",val);
+
+	val = __raw_readl(IO2M_FLEN(comcerto_xor_ch));
+	dev_printk(KERN_ERR, comcerto_xor_ch->device->device.dev,
+			   "IO2M_FLEN            0x%8x.\n",val);
+
+	val = __raw_readl(IO2M_IRQ_ENABLE(comcerto_xor_ch));
+	dev_printk(KERN_ERR, comcerto_xor_ch->device->device.dev,
+			   "IO2M_IRQ_ENABLE      0x%8x.\n",val);
+
+	val = __raw_readl(IO2M_IRQ_STATUS(comcerto_xor_ch));
+	dev_printk(KERN_ERR, comcerto_xor_ch->device->device.dev,
+			   "IO2M_IRQ_STATUS      0x%8x.\n",val);
+
+	val = __raw_readl(IO2M_RESET(comcerto_xor_ch));
+	dev_printk(KERN_ERR, comcerto_xor_ch->device->device.dev,
+			   "IO2M_RESET           0x%8x.\n",val);
+
+}
+
+static void comcerto_xor_register_init(struct comcerto_xor_chan *comcerto_xor_ch)
+{
+	u32 value;
+
+	/* M2IO_CONTROL: Enable DONOSTA */
+	value = M2IO_DONOSTA;
+	comcerto_xor_set_register_m2io_control(comcerto_xor_ch,value);
+
+	/* IO2M_IRQ_ENABLE: Enable IRQFRDYN, IRQFLST and IRQFLSH*/
+	value = IO2M_IRQFRDYN | IO2M_IRQFLST | IO2M_IRQFLSH;
+	comcerto_xor_set_register_io2m_irq_enable(comcerto_xor_ch,value);
+}
+
+
+/* --------------------------- Miscellaneous functions --------------------------------*/
+
+static dma_cookie_t comcerto_xor_run_tx_complete_actions(struct comcerto_xor_desc_slot *slot,
+		                                           struct comcerto_xor_chan *comcerto_xor_ch,
+		                                           dma_cookie_t cookie)
+{
+	u16 src_cnt;
+
+	if(slot->async_tx.cookie < 0)
+		printk(KERN_ERR "Invalid cookie.");
+
+	if(slot->async_tx.cookie >0 ) {
+		cookie = slot->async_tx.cookie;
+		src_cnt = slot->src_cnt;
+
+		if(slot->async_tx.callback)
+			slot->async_tx.callback(slot->async_tx.callback_param);
+
+		if(slot->len) {
+			struct device *dev = comcerto_xor_ch->device->device.dev;
+			enum dma_ctrl_flags flags = slot->async_tx.flags;
+			dma_addr_t src, dest;
+
+			dest = comcerto_get_buff_info_outbound(slot,0);
+			if(!(flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
+				enum dma_data_direction dir;
+
+				if(src_cnt > 1)
+					dir = DMA_BIDIRECTIONAL;
+				else
+					dir = DMA_FROM_DEVICE;
+
+				dma_unmap_page(dev, dest, slot->len, dir);
+			}
+
+			if(!(flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
+				while(src_cnt--){
+					src = comcerto_get_buff_info_inbound(slot, src_cnt);
+					if(src == dest)
+						continue;
+					dma_unmap_page(dev, src, slot->len, DMA_TO_DEVICE);
+				}
+			}
+		}
+	}
+	dma_run_dependencies(&slot->async_tx);
+	return cookie;
+}
+
+static int comcerto_xor_clean_completed_slots(struct comcerto_xor_chan *comcerto_xor_ch)
+{
+	struct comcerto_xor_desc_slot *iter, *__iter;
+
+	list_for_each_entry_safe(iter, __iter, &comcerto_xor_ch->completed_slots, completed_node) {
+		if(async_tx_test_ack(&iter->async_tx)) {
+			list_del(&iter->completed_node);
+			iter->busy = 0;
+		}
+	}
+	return 0;
+}
+
+static void __comcerto_xor_slot_cleanup(struct comcerto_xor_chan *comcerto_xor_ch)
+{
+	struct comcerto_xor_desc_slot *iter, *__iter;
+	dma_cookie_t cookie = 0;
+	u32 current_desc = comcerto_xor_get_register_io2m_head(comcerto_xor_ch);
+	int seen_current = 0;
+
+	comcerto_xor_clean_completed_slots(comcerto_xor_ch);
+
+	list_for_each_entry_safe(iter,__iter,&comcerto_xor_ch->chain,chain_node) {
+		prefetch(__iter);
+		prefetch(&__iter->async_tx);
+
+		if(seen_current)
+			break;
+
+		if(iter->hw_desc_outbound_dma == current_desc) {
+			seen_current = 1;
+
+			/* When we arrived here, the hardware may in two
+			 * possible situations:
+			 *
+			 *    1. Not working, stopped
+			 *    2. Working on current_desc
+			 *
+			 * For case 1, following if statement will be false and we'll
+			 * continue to clean this slot.
+			 * For case 2, we just break and leave the last slot
+			 * to be cleaned at next execution.
+			 */
+
+			if(!(comcerto_xor_get_register_m2io_control(comcerto_xor_ch)&(0x1)) &&
+					!(comcerto_xor_get_register_io2m_control(comcerto_xor_ch)&(0x1)))
+				break;
+		}
+
+		if(iter->xor_check_result && iter->async_tx.cookie)
+			*iter->xor_check_result = comcerto_get_fstatus0_outbound(iter)&(0x1);
+
+		cookie = comcerto_xor_run_tx_complete_actions(iter,comcerto_xor_ch,cookie);
+		list_del(&iter->chain_node);
+		if(!async_tx_test_ack(&iter->async_tx))
+			list_add_tail(&iter->completed_node, &comcerto_xor_ch->completed_slots);
+		else
+			iter->busy = 0;
+	}
+
+	if(cookie > 0)
+		comcerto_xor_ch->completed_cookie = cookie;
+}
+
+
+static void comcerto_xor_slot_cleanup(struct comcerto_xor_chan *comcerto_xor_ch)
+{
+	spin_lock_bh(&comcerto_xor_ch->lock);
+	__comcerto_xor_slot_cleanup(comcerto_xor_ch);
+	spin_unlock_bh(&comcerto_xor_ch->lock);
+}
+
+static void comcerto_xor_tasklet(unsigned long data)
+{
+	struct comcerto_xor_chan *comcerto_xor_ch = (struct comcerto_xor_chan *) data;
+	comcerto_xor_slot_cleanup(comcerto_xor_ch);
+}
+
+static struct comcerto_xor_desc_slot *
+comcerto_xor_alloc_slot(struct comcerto_xor_chan *comcerto_xor_ch)
+{
+	struct comcerto_xor_desc_slot *iter, *__iter = NULL;
+	int slot_found, retry = 0;
+
+retry:
+	slot_found = 0;
+	if(retry == 0 )
+		iter = comcerto_xor_ch->last_used;
+	else
+		iter = list_entry(&comcerto_xor_ch->all_slots,struct comcerto_xor_desc_slot, slot_node);
+
+	list_for_each_entry_safe_continue(
+		iter, __iter, &comcerto_xor_ch->all_slots, slot_node) {
+			prefetch(__iter);
+			prefetch(&__iter->async_tx);
+			if(iter->busy) {
+				if (retry)
+					break;
+				slot_found=0;
+				continue;
+			}
+
+			iter->async_tx.cookie = -EBUSY;
+			iter->xor_check_result = NULL;
+			iter->busy = 1;
+			comcerto_xor_ch->last_used = iter;
+			return iter;
+	}
+
+	if(!retry++)
+		goto retry;
+
+	tasklet_schedule(&comcerto_xor_ch->irq_tasklet);
+
+	return NULL;
+}
+
+static dma_cookie_t comcerto_desc_assign_cookie(struct comcerto_xor_chan *comcerto_xor_ch,
+		                                  struct comcerto_xor_desc_slot * slot)
+{
+	dma_cookie_t cookie = comcerto_xor_ch->chan.cookie;
+
+	if(++cookie < 0)
+		cookie = 1;
+	comcerto_xor_ch->chan.cookie = slot->async_tx.cookie = cookie;
+	return cookie;
+}
+
+
+/*------------------------------- XOR API Function-------------------------------------*/
+
+static enum dma_status comcerto_xor_status(struct dma_chan *chan,
+		                             dma_cookie_t cookie,
+		                             struct dma_tx_state *txstate)
+{
+	struct comcerto_xor_chan *comcerto_xor_ch = to_comcerto_xor_chan(chan);
+	dma_cookie_t last_used;
+	dma_cookie_t last_complete;
+
+	last_used = chan->cookie;
+	last_complete = comcerto_xor_ch->completed_cookie;
+	dma_set_tx_state(txstate, last_complete, last_used, 0);
+
+	return dma_async_is_complete(cookie, last_complete, last_used);
+}
+
+static void comcerto_xor_issue_pending(struct dma_chan *chan)
+{
+	struct comcerto_xor_chan *comcerto_xor_ch = to_comcerto_xor_chan(chan);
+
+	if(comcerto_xor_ch->pending >= COMCERTO_XOR_THRESHOLD && comcerto_xor_ch->to_be_started) {
+		comcerto_xor_ch->pending = 0;
+		comcerto_xor_set_register_m2io_head(comcerto_xor_ch, comcerto_xor_ch->to_be_started->async_tx.phys);
+		comcerto_xor_set_register_io2m_head(comcerto_xor_ch, comcerto_xor_ch->to_be_started->hw_desc_outbound_dma);
+		comcerto_xor_ch->to_be_started = NULL;
+	}
+}
+
+static dma_cookie_t comcerto_xor_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+	struct comcerto_xor_desc_slot *slot = to_comcerto_xor_slot(tx);
+	struct comcerto_xor_desc_slot *old_chain_tail;
+	dma_cookie_t cookie;
+	struct comcerto_xor_chan *comcerto_xor_ch;
+	struct dma_chan *chan;
+	chan = tx->chan;
+	comcerto_xor_ch = to_comcerto_xor_chan(chan);
+
+	spin_lock_bh(&comcerto_xor_ch->lock);
+	cookie = comcerto_desc_assign_cookie(comcerto_xor_ch, slot);
+
+	/* If chain list is empty, the hardware is absolutely stopped.
+	 * Thus, we need only reset the head register in order to start
+	 * the DMA
+	 */
+
+	if(list_empty(&comcerto_xor_ch->chain)){
+		list_add_tail(&slot->chain_node, &comcerto_xor_ch->chain);
+		comcerto_xor_ch->to_be_started = slot;
+		comcerto_xor_ch->pending++;
+		comcerto_xor_issue_pending(&comcerto_xor_ch->chan);
+	}
+	else {
+
+	/* If chain list is not empty, the hardware may or may not stopped.
+	 *     - It may not stopped because the chain is not empty. That is to
+	 *       say, the hardware still have request to process
+	 *     - It may stopped because the hardware has already finished the
+	 *       processing. But just haven't cleared the chain. (The chain can
+	 *       be only cleared in the tasklet.)
+	 * For whatever case, we just:
+	 *     - update the FNext field of last element in chain.
+	 *     - set head register to restart the XOR processing if the hardware
+	 *       is not working
+	 */
+
+		old_chain_tail = list_entry(comcerto_xor_ch->chain.prev,
+				                    struct comcerto_xor_desc_slot,
+				                    chain_node);
+
+		list_add_tail(&slot->chain_node,&comcerto_xor_ch->chain);
+
+		comcerto_set_next_desc_outbound(old_chain_tail,slot->hw_desc_outbound_dma);
+		comcerto_set_next_desc_inbound(old_chain_tail,slot->async_tx.phys);
+
+		if(!(comcerto_xor_get_register_m2io_control(comcerto_xor_ch)&(0x1)) &&
+				!(comcerto_xor_get_register_io2m_control(comcerto_xor_ch)&(0x1))){
+
+			if(!comcerto_xor_ch->to_be_started)
+				comcerto_xor_ch->to_be_started = slot;
+			comcerto_xor_ch->pending++;
+			comcerto_xor_issue_pending(&comcerto_xor_ch->chan);
+		}
+	}
+    spin_unlock_bh(&comcerto_xor_ch->lock);
+    return cookie;
+}
+
+static void comcerto_xor_free_chan_resources(struct dma_chan *chan)
+{
+	struct comcerto_xor_chan *comcerto_xor_ch = to_comcerto_xor_chan(chan);
+	struct comcerto_xor_desc_slot *iter, *__iter;
+	int in_use_descs = 0;
+
+	comcerto_xor_slot_cleanup(comcerto_xor_ch);
+
+	spin_lock_bh(&comcerto_xor_ch->lock);
+
+	list_for_each_entry_safe(iter, __iter, &comcerto_xor_ch->chain, chain_node) {
+		in_use_descs++;
+		list_del(&iter->chain_node);
+	}
+
+	list_for_each_entry_safe(iter, __iter, &comcerto_xor_ch->completed_slots, completed_node) {
+		in_use_descs++;
+		list_del(&iter->completed_node);
+	}
+
+	list_for_each_entry_safe_reverse(iter, __iter, &comcerto_xor_ch->all_slots, slot_node) {
+		list_del(&iter->slot_node);
+		kfree(iter);
+		comcerto_xor_ch->slot_allocated--;
+	}
+
+	comcerto_xor_ch->last_used = NULL;
+
+	spin_unlock_bh(&comcerto_xor_ch->lock);
+
+	if(in_use_descs)
+		dev_err(comcerto_xor_ch->device->device.dev,
+				"freeing %d in use descriptors!\n", in_use_descs);
+}
+
+static int comcerto_xor_alloc_chan_resources(struct dma_chan *chan)
+{
+	struct comcerto_xor_chan *comcerto_xor_ch = to_comcerto_xor_chan(chan);
+	struct comcerto_xor_desc_slot *slot = NULL;
+	int num_slots_per_pool = PAGE_SIZE / (COMCERTO_XOR_INBOUND_DESC_SIZE + COMCERTO_XOR_OUTBOUND_DESC_SIZE);
+	int total_slots = POOL_NUMBER * num_slots_per_pool;
+	int gap = PAGE_SIZE - num_slots_per_pool * (COMCERTO_XOR_INBOUND_DESC_SIZE + COMCERTO_XOR_OUTBOUND_DESC_SIZE);
+	int i,j;
+	char *dma_desc_pool_virt_addr;
+	char *dma_desc_pool_addr;
+
+	i = j = comcerto_xor_ch->slot_allocated;
+	j %= num_slots_per_pool;
+
+	while( i < total_slots) {
+
+		slot = kzalloc(sizeof(*slot), GFP_KERNEL);
+		if(!slot) {
+			printk(KERN_INFO "comcerto XOR Channel only initialized %d slot descriptors.\n", i);
+			break;
+		}
+
+		dma_desc_pool_virt_addr = (char *) comcerto_xor_ch->device->dma_desc_pool_virt[i/num_slots_per_pool];
+		slot->hw_desc_inbound = (void *) &dma_desc_pool_virt_addr[j*COMCERTO_XOR_INBOUND_DESC_SIZE];
+		slot->hw_desc_outbound = (void *) &dma_desc_pool_virt_addr[num_slots_per_pool*COMCERTO_XOR_INBOUND_DESC_SIZE + gap + j*COMCERTO_XOR_OUTBOUND_DESC_SIZE];
+
+		dma_async_tx_descriptor_init(&slot->async_tx, chan);
+		slot->async_tx.tx_submit = comcerto_xor_tx_submit;
+
+		INIT_LIST_HEAD(&slot->slot_node);
+		INIT_LIST_HEAD(&slot->chain_node);
+		INIT_LIST_HEAD(&slot->completed_node);
+
+		dma_desc_pool_addr = (char *) comcerto_xor_ch->device->dma_desc_pool[i/num_slots_per_pool];
+		slot->async_tx.phys = (dma_addr_t) &dma_desc_pool_addr[j*COMCERTO_XOR_INBOUND_DESC_SIZE];
+		slot->hw_desc_outbound_dma = (dma_addr_t) &dma_desc_pool_addr[num_slots_per_pool*COMCERTO_XOR_INBOUND_DESC_SIZE + gap + j*COMCERTO_XOR_OUTBOUND_DESC_SIZE];
+		slot->busy=0;
+
+		i++;
+		if(++j == num_slots_per_pool)
+			j=0;
+
+		spin_lock_bh(&comcerto_xor_ch->lock);
+		comcerto_xor_ch->slot_allocated = i;
+		list_add_tail(&slot->slot_node, &comcerto_xor_ch->all_slots);
+		spin_unlock_bh(&comcerto_xor_ch->lock);
+
+	}
+
+	if(comcerto_xor_ch->slot_allocated && !comcerto_xor_ch->last_used)
+		comcerto_xor_ch->last_used = list_entry(comcerto_xor_ch->all_slots.next, struct comcerto_xor_desc_slot, slot_node);
+
+	return comcerto_xor_ch->slot_allocated ? comcerto_xor_ch->slot_allocated : -ENOMEM;
+}
+
+static struct dma_async_tx_descriptor *
+comcerto_xor_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
+				size_t len, unsigned long flags)
+{
+	struct comcerto_xor_chan *comcerto_xor_ch = to_comcerto_xor_chan(chan);
+	struct comcerto_xor_desc_slot *slot;
+
+	spin_lock_bh(&comcerto_xor_ch->lock);
+	slot = comcerto_xor_alloc_slot(comcerto_xor_ch);
+	if(slot) {
+		slot->type = DMA_MEMCPY;
+		slot->len = len;
+		slot->src_cnt = 1;
+		slot->async_tx.flags = flags;
+		comcerto_xor_inbound_desc_init(slot,&src);
+
+		comcerto_xor_outbound_desc_init(slot,dest);
+	}
+	spin_unlock_bh(&comcerto_xor_ch->lock);
+
+	return slot ? &slot->async_tx : NULL;
+}
+
+static struct dma_async_tx_descriptor *
+comcerto_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
+		            unsigned int src_cnt, size_t len, unsigned long flags)
+{
+	struct comcerto_xor_chan *comcerto_xor_ch = to_comcerto_xor_chan(chan);
+	struct comcerto_xor_desc_slot *slot;
+
+	if(unlikely(len!=256&&len!=512&&len!=1024&&len!=2048&&len!=4096)) {
+		printk(KERN_ERR "Length %d is not supported for XOR.\n", len);
+		return NULL;
+	}
+
+	spin_lock_bh(&comcerto_xor_ch->lock);
+	slot = comcerto_xor_alloc_slot(comcerto_xor_ch);
+	if(slot) {
+		slot->type = DMA_XOR;
+		slot->len = len;
+		slot->src_cnt = src_cnt;
+		slot->async_tx.flags = flags;
+		comcerto_xor_inbound_desc_init(slot,src);
+
+		comcerto_xor_outbound_desc_init(slot,dest);
+	}
+	spin_unlock_bh(&comcerto_xor_ch->lock);
+
+	return slot ? &slot->async_tx : NULL;
+}
+
+static struct dma_async_tx_descriptor *
+comcerto_xor_prep_dma_xor_val(struct dma_chan *chan, dma_addr_t *src,
+                        unsigned int src_cnt, size_t len,
+                        u32 *result, unsigned long flags)
+{
+	struct comcerto_xor_chan *comcerto_xor_ch = to_comcerto_xor_chan(chan);
+	struct comcerto_xor_desc_slot *slot;
+
+	if(unlikely(len!=256&&len!=512&&len!=1024&&len!=2048&&len!=4096)) {
+		printk(KERN_ERR "Length %d is not supported for XOR.\n", len);
+		return NULL;
+	}
+
+	spin_lock_bh(&comcerto_xor_ch->lock);
+	slot = comcerto_xor_alloc_slot(comcerto_xor_ch);
+
+	if(slot) {
+		slot->type = DMA_XOR_VAL;
+		slot->len = len;
+		slot->src_cnt = src_cnt;
+		slot->async_tx.flags = flags;
+		slot->xor_check_result = result;
+		comcerto_xor_inbound_desc_init(slot,src);
+
+		comcerto_xor_outbound_desc_init(slot,0);
+	}
+	spin_unlock_bh(&comcerto_xor_ch->lock);
+
+	return slot ? &slot->async_tx : NULL;
+}
+
+static irqreturn_t comcerto_xor_interrupt_handler(int irq, void *data)
+{
+	struct comcerto_xor_chan *comcerto_xor_ch = data;
+	int do_taskset=0;
+	u32 intr_cause = comcerto_xor_get_register_io2m_irq_status(comcerto_xor_ch);
+
+	if(intr_cause & IRQ_IRQFRDYN) {
+		printk(KERN_ALERT "IRQFRDYN: A frame is started but the frame is not ready");
+		comcerto_dump_xor_regs(comcerto_xor_ch);
+		comcerto_xor_set_register_io2m_irq_status(comcerto_xor_ch,1<<0);
+		do_taskset=1;
+	}
+
+	if(intr_cause & IRQ_IRQFLST) {
+	    comcerto_xor_set_register_io2m_irq_status(comcerto_xor_ch,1<<1);
+		do_taskset=1;
+	}
+
+	if(intr_cause & IRQ_IRQFDON)
+		comcerto_xor_set_register_io2m_irq_status(comcerto_xor_ch,1<<2);
+
+	if(intr_cause & IRQ_IRQFLSH) {
+		printk(KERN_ALERT "IRQFLSH: IO has more data than the memory buffer");
+		comcerto_dump_xor_regs(comcerto_xor_ch);
+		comcerto_xor_set_register_io2m_irq_status(comcerto_xor_ch,1<<3);
+		do_taskset=1;
+	}
+
+	if(intr_cause & IRQ_IRQFLEN) {
+		comcerto_xor_set_register_io2m_irq_status(comcerto_xor_ch,1<<4);
+		do_taskset=1;
+	}
+
+	if(intr_cause & IRQ_IRQFTHLD) {
+		printk(KERN_ALERT "IRQFTHLD: Frame threshold reached. FLEN=FTHLDL");
+		comcerto_dump_xor_regs(comcerto_xor_ch);
+		comcerto_xor_set_register_io2m_irq_status(comcerto_xor_ch,1<<5);
+		do_taskset=1;
+	}
+
+	if(intr_cause & IRQ_IRQFCTRL) {
+		printk(KERN_ALERT "IRQFCTRL: 1 frame is completed or when a frame is started but not ready");
+		comcerto_dump_xor_regs(comcerto_xor_ch);
+		comcerto_xor_set_register_io2m_irq_status(comcerto_xor_ch,1<<6);
+		do_taskset=1;
+	}
+
+	if(do_taskset)
+	    	tasklet_schedule(&comcerto_xor_ch->irq_tasklet);
+
+	return IRQ_HANDLED;
+}
+
+#define COMCERTO_XOR_NUM_SRC_TEST 4
+static int __devinit comcerto_xor_xor_self_test(struct comcerto_xor_device *device)
+{
+	int i, src_idx;
+	struct page *dest;
+	struct page *xor_srcs[COMCERTO_XOR_NUM_SRC_TEST];
+	struct page *zero_sum_srcs[COMCERTO_XOR_NUM_SRC_TEST+1];
+	dma_addr_t dma_srcs[COMCERTO_XOR_NUM_SRC_TEST];
+	dma_addr_t dma_zero_srcs[COMCERTO_XOR_NUM_SRC_TEST+1];
+	dma_addr_t dest_dma;
+	struct dma_async_tx_descriptor *tx;
+	struct dma_chan *dma_chan;
+	dma_cookie_t cookie;
+	u8 cmp_byte = 0;
+	u32 cmp_word;
+	u32 zero_sum_result;
+	int err = 0;
+	struct comcerto_xor_chan *comcerto_chan;
+
+	for (src_idx = 0; src_idx < COMCERTO_XOR_NUM_SRC_TEST; src_idx++) {
+		xor_srcs[src_idx] = alloc_page(GFP_KERNEL);
+		if (!xor_srcs[src_idx]) {
+			while (src_idx--)
+				__free_page(xor_srcs[src_idx]);
+			return -ENOMEM;
+		}
+	}
+
+	dest = alloc_page(GFP_KERNEL);
+	if (!dest) {
+		while (src_idx--)
+			__free_page(xor_srcs[src_idx]);
+		return -ENOMEM;
+	}
+
+	for (src_idx = 0; src_idx < COMCERTO_XOR_NUM_SRC_TEST; src_idx++) {
+		u8 *ptr = page_address(xor_srcs[src_idx]);
+		for (i = 0; i < PAGE_SIZE; i++)
+			ptr[i] = (1 << src_idx);
+	}
+
+	for (src_idx = 0; src_idx < COMCERTO_XOR_NUM_SRC_TEST; src_idx++)
+		cmp_byte ^= (u8) (1 << src_idx);
+
+	cmp_word = (cmp_byte << 24) | (cmp_byte << 16) |
+			(cmp_byte << 8) | cmp_byte;
+
+	memset(page_address(dest), 0, PAGE_SIZE);
+
+	dma_chan = container_of(device->device.channels.next,
+			                struct dma_chan,
+			                device_node);
+	if (comcerto_xor_alloc_chan_resources(dma_chan) < 1) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	dest_dma = dma_map_page(dma_chan->device->dev, dest, 0,
+			                PAGE_SIZE, DMA_FROM_DEVICE);
+	comcerto_chan = to_comcerto_xor_chan(dma_chan);
+
+	for (i = 0; i < COMCERTO_XOR_NUM_SRC_TEST; i++)
+		dma_srcs[i] = dma_map_page(dma_chan->device->dev, xor_srcs[i],
+				                   0, PAGE_SIZE, DMA_TO_DEVICE);
+
+	tx = comcerto_xor_prep_dma_xor(dma_chan, dest_dma, dma_srcs,
+			                 COMCERTO_XOR_NUM_SRC_TEST, PAGE_SIZE, 0);
+
+	cookie = comcerto_xor_tx_submit(tx);
+	comcerto_xor_issue_pending(dma_chan);
+	async_tx_ack(tx);
+	msleep(8);
+
+	if (comcerto_xor_status(dma_chan, cookie, NULL) != DMA_SUCCESS) {
+		dev_printk(KERN_ERR, dma_chan->device->dev,
+				   "Self-test xor timed out, disabling\n");
+		err = -ENODEV;
+		goto free_resources;
+	}
+
+	dma_sync_single_for_cpu(device->device.dev, dest_dma,
+			                PAGE_SIZE, DMA_FROM_DEVICE);
+	for (i = 0; i < (PAGE_SIZE / sizeof(u32)); i++) {
+		u32 *ptr = page_address(dest);
+		if (ptr[i] != cmp_word) {
+			dev_printk(KERN_ERR, dma_chan->device->dev,
+					   "Self-test xor failed compare, disabling."
+					   " index %d, data %x, expected %x\n", i,
+					   ptr[i], cmp_word);
+			err = -ENODEV;
+			goto free_resources;
+		}
+	}
+	dma_sync_single_for_device(device->device.dev,dest_dma,
+			                   PAGE_SIZE, DMA_TO_DEVICE);
+
+	if(!dma_has_cap(DMA_XOR_VAL,dma_chan->device->cap_mask))
+		goto free_resources;
+
+	for(i = 0; i < COMCERTO_XOR_NUM_SRC_TEST; i++)
+		zero_sum_srcs[i]=xor_srcs[i];
+	zero_sum_srcs[i] = alloc_page(GFP_KERNEL);
+	for (src_idx = 0; src_idx < 1; src_idx++) {
+		u8 *ptr = page_address(zero_sum_srcs[i]);
+		for (i = 0; i < PAGE_SIZE; i++)
+			ptr[i] = 1 | 1<<1 | 1<<2 | 1<<3;
+	}
+
+	zero_sum_result=1;
+
+	for(i=0;i<COMCERTO_XOR_NUM_SRC_TEST+1;i++)
+		dma_zero_srcs[i]=dma_map_page(dma_chan->device->dev,
+				                 zero_sum_srcs[i],0,PAGE_SIZE,
+				                 DMA_TO_DEVICE);
+	tx = comcerto_xor_prep_dma_xor_val(dma_chan,dma_zero_srcs,
+			                     COMCERTO_XOR_NUM_SRC_TEST+1, PAGE_SIZE,
+			                     &zero_sum_result,
+			                     DMA_CTRL_ACK);
+	cookie = comcerto_xor_tx_submit(tx);
+	comcerto_xor_issue_pending(dma_chan);
+	msleep(8);
+
+	if (comcerto_xor_status(dma_chan, cookie, NULL) != DMA_SUCCESS) {
+		dev_printk(KERN_ERR, dma_chan->device->dev,
+				   "Self-test zero sum timed out, disabling\n");
+		err = -ENODEV;
+		goto free_resources;
+	}
+
+	if(zero_sum_result != 0) {
+		dev_printk(KERN_ERR, dma_chan->device->dev,
+				   "Self-test zero sum failed compare, disabling\n");
+		err = -ENODEV;
+		goto free_resources;
+	}
+	__free_page(zero_sum_srcs[COMCERTO_XOR_NUM_SRC_TEST]);
+free_resources:
+	comcerto_xor_free_chan_resources(dma_chan);
+out:
+	src_idx = COMCERTO_XOR_NUM_SRC_TEST;
+
+	while (src_idx--)
+		__free_page(xor_srcs[src_idx]);
+	__free_page(dest);
+	return err;
+
+}
+
+static int __devinit comcerto_xor_memcpy_self_test(struct comcerto_xor_device *device)
+{
+	int i;
+	struct page *dest;
+	struct page *src;
+	dma_addr_t src_dma;
+	dma_addr_t dest_dma;
+	struct dma_async_tx_descriptor *tx;
+	struct dma_chan *dma_chan;
+	dma_cookie_t cookie;
+	int err = 0;
+	struct comcerto_xor_chan *comcerto_chan;
+
+	src = alloc_page(GFP_KERNEL);
+	if (!src)
+		return -ENOMEM;
+
+	dest = alloc_page(GFP_KERNEL);
+	if (!dest) {
+		__free_page(src);
+		return -ENOMEM;
+	}
+
+	/* Fill in src buffer */
+	for (i = 0; i < PAGE_SIZE; i++) {
+		u8 *ptr = page_address(src);
+		((u8 *) ptr)[i] = (u8)i;
+	}
+
+	memset(page_address(dest), 0, PAGE_SIZE);
+
+	dma_chan = container_of(device->device.channels.next,
+			                struct dma_chan,
+			                device_node);
+	if (comcerto_xor_alloc_chan_resources(dma_chan) < 1) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	dest_dma = dma_map_page(dma_chan->device->dev, dest, 0,
+			                PAGE_SIZE, DMA_FROM_DEVICE);
+	comcerto_chan = to_comcerto_xor_chan(dma_chan);
+
+	src_dma = dma_map_page(dma_chan->device->dev, src,
+				        0, PAGE_SIZE, DMA_TO_DEVICE);
+
+	tx = comcerto_xor_prep_dma_memcpy(dma_chan, dest_dma, src_dma,
+			                 PAGE_SIZE, 0);
+
+	cookie = comcerto_xor_tx_submit(tx);
+	comcerto_xor_issue_pending(dma_chan);
+	async_tx_ack(tx);
+	msleep(8);
+
+	if (comcerto_xor_status(dma_chan, cookie, NULL) != DMA_SUCCESS) {
+		dev_printk(KERN_ERR, dma_chan->device->dev,
+				   "Self-test xor timed out, disabling\n");
+		err = -ENODEV;
+		goto free_resources;
+	}
+
+	dma_sync_single_for_cpu(device->device.dev, dest_dma,
+			                PAGE_SIZE, DMA_FROM_DEVICE);
+
+	if (memcmp(page_address(src), page_address(dest), PAGE_SIZE)) {
+		dev_printk(KERN_ERR, dma_chan->device->dev,
+			   "Self-test copy failed compare, disabling\n");
+		err = -ENODEV;
+		goto free_resources;
+	}
+
+free_resources:
+	comcerto_xor_free_chan_resources(dma_chan);
+out:
+	__free_page(src);
+	__free_page(dest);
+	return err;
+
+}
+
+static int __devexit comcerto_xor_remove(struct platform_device *pdev)
+{
+	struct comcerto_xor_device *comcerto_xor_dev = platform_get_drvdata(pdev);
+	struct dma_device *dma_dev = &comcerto_xor_dev->device;
+	struct comcerto_xor_chan   *comcerto_xor_ch;
+	struct dma_chan *chan, *__chan;
+	int i;
+	int irq;
+
+	irq = platform_get_irq(pdev,0);
+
+	dma_async_device_unregister(dma_dev);
+
+	for(i=0;i<POOL_NUMBER;i++)
+		dma_free_coherent(&pdev->dev, PAGE_SIZE,
+				          comcerto_xor_dev->dma_desc_pool_virt[i],
+				          comcerto_xor_dev->dma_desc_pool[i]);
+
+	list_for_each_entry_safe(chan, __chan, &dma_dev->channels,
+			                 device_node) {
+		comcerto_xor_ch = to_comcerto_xor_chan(chan);
+		devm_free_irq(&pdev->dev, irq, comcerto_xor_ch);
+		list_del(&chan->device_node);
+		devm_iounmap(&pdev->dev, comcerto_xor_ch->mmr_base);
+		kfree(comcerto_xor_ch);
+	}
+
+	platform_set_drvdata(pdev,NULL);
+	kfree(comcerto_xor_dev);
+
+	return 0;
+}
+
+static int __devinit comcerto_xor_probe(struct platform_device *pdev)
+{
+	struct resource      *io;
+	struct dma_device    *dma_dev;
+	struct comcerto_xor_device *comcerto_xor_dev;
+	struct comcerto_xor_chan   *comcerto_xor_ch;
+	int                  irq;
+	int                  ret = 0;
+	int                  i;
+
+	/* Retrieve related resources(mem, irq) from platform_device */
+	io = platform_get_resource(pdev,IORESOURCE_MEM,0);
+	if(!io)
+		return -ENODEV;
+
+	irq = platform_get_irq(pdev,0);
+	if(irq<0)
+		return irq;
+
+	/* Initialize comcerto_xor_device */
+	comcerto_xor_dev = devm_kzalloc(&pdev->dev, sizeof(*comcerto_xor_dev), GFP_KERNEL);
+
+	if(!comcerto_xor_dev)
+		return -ENOMEM;
+
+	dma_dev = &comcerto_xor_dev->device;
+	INIT_LIST_HEAD(&dma_dev->channels);
+
+	for(i = 0 ; i < POOL_NUMBER; i++)
+	{
+		comcerto_xor_dev->dma_desc_pool_virt[i] = dma_alloc_writecombine(&pdev->dev,
+			                                                PAGE_SIZE,
+			                                                &comcerto_xor_dev->dma_desc_pool[i],
+			                                                GFP_KERNEL);
+		if(!comcerto_xor_dev->dma_desc_pool_virt[i])
+		{
+			ret = -ENOMEM;
+			goto err_free_dma;
+		}
+	}
+
+	dma_cap_set(DMA_XOR,dma_dev->cap_mask);
+	dma_cap_set(DMA_XOR_VAL,dma_dev->cap_mask);
+//	dma_cap_set(DMA_MEMCPY,dma_dev->cap_mask);
+
+	dma_dev->dev = &pdev->dev;
+	dma_dev->device_alloc_chan_resources = comcerto_xor_alloc_chan_resources;
+	dma_dev->device_free_chan_resources  = comcerto_xor_free_chan_resources;
+	dma_dev->device_tx_status            = comcerto_xor_status;
+	dma_dev->device_issue_pending        = comcerto_xor_issue_pending;
+	dma_dev->device_prep_dma_xor         = comcerto_xor_prep_dma_xor;
+	dma_dev->device_prep_dma_xor_val     = comcerto_xor_prep_dma_xor_val;
+//	dma_dev->device_prep_dma_memcpy = comcerto_xor_prep_dma_memcpy;
+	dma_dev->max_xor = COMCERTO_XOR_MAX_SRC;
+
+	platform_set_drvdata(pdev,comcerto_xor_dev);
+
+	/* Initialize comcerto_xor_chan */
+
+	comcerto_xor_ch  = devm_kzalloc(&pdev->dev,sizeof(*comcerto_xor_ch),GFP_KERNEL);
+	if(!comcerto_xor_ch) {
+		ret = -ENOMEM;
+		goto err_free_dma;
+	}
+
+	comcerto_xor_ch->device = comcerto_xor_dev;
+	comcerto_xor_ch->pending = 0;
+	comcerto_xor_ch->slot_allocated = 0;
+	comcerto_xor_ch->completed_cookie = 0;
+	comcerto_xor_ch->mmr_base = devm_ioremap(&pdev->dev, io->start,resource_size(io));
+	if(!comcerto_xor_ch->mmr_base) {
+		ret = -ENOMEM;
+		goto err_free_ch;
+	}
+
+	tasklet_init(&comcerto_xor_ch->irq_tasklet,comcerto_xor_tasklet,(unsigned long)comcerto_xor_ch);
+
+	ret = devm_request_irq(&pdev->dev, irq, comcerto_xor_interrupt_handler,
+			               0, dev_name(&pdev->dev), comcerto_xor_ch);
+	if(ret)
+		goto err_free_remap;
+
+	spin_lock_init(&comcerto_xor_ch->lock);
+	INIT_LIST_HEAD(&comcerto_xor_ch->all_slots);
+	INIT_LIST_HEAD(&comcerto_xor_ch->chain);
+	INIT_LIST_HEAD(&comcerto_xor_ch->completed_slots);
+	comcerto_xor_ch->chan.device = dma_dev;
+
+	list_add_tail(&comcerto_xor_ch->chan.device_node,&dma_dev->channels);
+
+	comcerto_xor_register_init(comcerto_xor_ch);
+
+	if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) {
+		ret = comcerto_xor_xor_self_test(comcerto_xor_dev);
+		dev_dbg(&pdev->dev, "xor self test returned %d\n", ret);
+		if(ret)
+			goto err_free_irq;
+	}
+
+	if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask)) {
+		ret = comcerto_xor_memcpy_self_test(comcerto_xor_dev);
+		dev_dbg(&pdev->dev, "memcpy self test returned %d\n", ret);
+		if(ret)
+			goto err_free_irq;
+	}
+
+	
+	ret = dma_async_device_register(dma_dev);
+
+	if (ret) {
+		dev_dbg(&pdev->dev, "Failed to register channel %d\n",ret);
+		goto err_free_irq;
+	}
+
+	goto out;
+
+err_free_irq:
+	devm_free_irq(&pdev->dev, irq, comcerto_xor_ch);
+err_free_remap:
+	devm_iounmap(&pdev->dev, comcerto_xor_ch->mmr_base);
+err_free_ch:
+	devm_kfree(&pdev->dev, comcerto_xor_ch);
+err_free_dma:
+	platform_set_drvdata(pdev,NULL);
+	while(i--)
+		dma_free_coherent(&pdev->dev,PAGE_SIZE,comcerto_xor_dev->dma_desc_pool_virt[i],
+			comcerto_xor_dev->dma_desc_pool[i]);
+	devm_kfree(&pdev->dev, comcerto_xor_dev);
+out:
+    return ret;
+}
+
+static struct platform_driver comcerto_xor_driver = {
+	.probe        = comcerto_xor_probe,
+	.remove       = comcerto_xor_remove,
+	.driver       = {
+			.owner = THIS_MODULE,
+			.name  = "comcerto_xor",
+	},
+};
+
+static int __init comcerto_xor_init(void)
+{
+	int ret = platform_driver_register(&comcerto_xor_driver);
+	return ret;
+}
+module_init(comcerto_xor_init);
+
+static void __exit comcerto_xor_exit(void)
+{
+	platform_driver_unregister(&comcerto_xor_driver);
+	return;
+}
+module_exit(comcerto_xor_exit);
+
+MODULE_DESCRIPTION("XOR engine driver for Mindspeed Comcerto C2000 devices");
+MODULE_LICENSE("GPL");
diff --git a/drivers/dma/comcerto_xor.h b/drivers/dma/comcerto_xor.h
new file mode 100644
index 0000000..a53534a
--- /dev/null
+++ b/drivers/dma/comcerto_xor.h
@@ -0,0 +1,135 @@
+/*
+ * comcerto_xor.h
+ *
+ *  Created on: May 11, 2012
+ *      Author: bwang
+ */
+
+#ifndef COMCERTO_XOR_H_
+#define COMCERTO_XOR_H_
+
+#include<linux/types.h>
+#include<linux/io.h>
+#include<linux/dmaengine.h>
+#include<linux/interrupt.h>
+
+#define POOL_NUMBER 4
+#define COMCERTO_XOR_INBOUND_DESC_SIZE         64
+#define COMCERTO_XOR_OUTBOUND_DESC_SIZE        32
+#define COMCERTO_XOR_MAX_SRC                   6
+#define COMCERTO_XOR_MAX_DEST                  2
+#ifdef CONFIG_COMCERTO_XOR_EXTENDED_TEST
+#define COMCERTO_XOR_THRESHOLD                 100
+#endif
+#ifndef CONFIG_COMCERTO_XOR_EXTENDED_TEST
+#define COMCERTO_XOR_THRESHOLD                 1
+#endif
+
+#define M2IO_CONTROL(chan)               (chan->mmr_base)
+#define M2IO_HEAD(chan)                  (chan->mmr_base + 0x4)
+#define M2IO_BURST(chan)                 (chan->mmr_base + 0x8)
+#define M2IO_FLEN(chan)                  (chan->mmr_base + 0xC)
+#define M2IO_IRQ_ENABLE(chan)            (chan->mmr_base + 0x10)
+#define M2IO_IRQ_STATUS(chan)            (chan->mmr_base + 0x14)
+#define M2IO_RESET(chan)                 (chan->mmr_base + 0x20)
+
+#define IO2M_CONTROL(chan)               (chan->mmr_base + 0x80)
+#define IO2M_HEAD(chan)                  (chan->mmr_base + 0x84)
+#define IO2M_BURST(chan)                 (chan->mmr_base + 0x88)
+#define IO2M_FLEN(chan)                  (chan->mmr_base + 0x8C)
+#define IO2M_IRQ_ENABLE(chan)            (chan->mmr_base + 0x90)
+#define IO2M_IRQ_STATUS(chan)            (chan->mmr_base + 0x94)
+#define IO2M_RESET(chan)                 (chan->mmr_base + 0xA0)
+
+//	Mem to IO Control
+#define M2IO_START	(1 << 0)
+#define M2IO_FLENEN	(1 << 1)
+#define M2IO_FCOM	(1 << 2)
+#define M2IO_DONOSTOP	(1 << 3)
+#define M2IO_DONOSTA	(1 << 4)
+
+//	IO to Mem: DMA Control
+#define IO2M_IRQFRDYN	(1 << 0)
+#define IO2M_IRQFLST	(1 << 1)
+#define IO2M_IRQFDON	(1 << 2)
+#define IO2M_IRQFLSH	(1 << 3)
+#define IO2M_IRQFLEN	(1 << 4)
+#define IO2M_IRQFTHLD	(1 << 5)
+
+// IRQ Status Register
+#define IRQ_IRQFRDYN	(1 << 0)
+#define IRQ_IRQFLST	(1 << 1)
+#define IRQ_IRQFDON	(1 << 2)
+#define IRQ_IRQFLSH	(1 << 3)
+#define IRQ_IRQFLEN	(1 << 4)
+#define IRQ_IRQFTHLD	(1 << 5)
+#define IRQ_IRQFCTRL	(1 << 6)
+
+// Inbound Frame and Buffer Descriptor Programming
+
+// BControl
+#define BLAST	(1 << 16)
+#define BFIX	(1 << 17)
+
+// Block Size
+#define XOR_BLOCK_SIZE_256	0
+#define XOR_BLOCK_SIZE_512	1
+#define XOR_BLOCK_SIZE_1024	2
+#define XOR_BLOCK_SIZE_2048	3
+#define XOR_BLOCK_SIZE_4096	4
+
+struct comcerto_xor_device {
+	dma_addr_t               dma_desc_pool[POOL_NUMBER];
+	void                     *dma_desc_pool_virt[POOL_NUMBER];
+	struct dma_device        device;
+};
+
+struct comcerto_xor_desc_slot {
+	struct list_head               slot_node;
+	struct list_head               chain_node;
+	struct list_head               completed_node;
+	enum dma_transaction_type      type;
+	void                           *hw_desc_inbound;
+	void                           *hw_desc_outbound;
+	dma_addr_t                     hw_desc_outbound_dma;
+	int                            busy;
+	u16                            src_cnt;
+	size_t                         len;
+	struct dma_async_tx_descriptor async_tx;
+	u32                            *xor_check_result;
+};
+
+struct comcerto_xor_chan {
+	int                         pending;
+	int                         slot_allocated;
+	dma_cookie_t                completed_cookie;
+	spinlock_t                  lock;
+	void __iomem                *mmr_base;
+	struct list_head            all_slots;
+	struct list_head            chain;
+	struct list_head            completed_slots;
+	struct comcerto_xor_device        *device;
+	struct dma_chan		        chan;
+	struct comcerto_xor_desc_slot     *last_used;
+	struct comcerto_xor_desc_slot     *to_be_started;
+	struct tasklet_struct       irq_tasklet;
+};
+
+struct comcerto_xor_inbound_desc {
+	u32  next_desc;
+	u32  fcontrol;
+	u32  fstatus0;
+	u32  fstatus1;
+	u32  buff_info[12]; // 6 Buffer Descriptors
+};
+
+struct comcerto_xor_outbound_desc {
+	u32  next_desc;
+	u32  fcontrol;
+	u32  fstatus0;
+	u32  fstatus1;
+	u32  buff_info[4]; // 2 Buffer Descriptors
+};
+
+
+#endif /* COMCERTO_XOR_H_ */
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 4e04157..ea83fe8 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -147,6 +147,13 @@
 	help
 	  Say yes here to support the Xilinx FPGA GPIO device
 
+config GPIO_C2K
+	def_bool y
+	depends on ARCH_M86XXX
+	bool "Comcerto 2000 GPIO support"
+	help
+	  Say yes here to support the Comcerto 2000 GPIO device
+
 config GPIO_VR41XX
 	tristate "NEC VR4100 series General-purpose I/O Uint support"
 	depends on CPU_VR41XX
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 4e018d6..924348b 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -62,3 +62,5 @@
 obj-$(CONFIG_GPIO_WM8350)	+= gpio-wm8350.o
 obj-$(CONFIG_GPIO_WM8994)	+= gpio-wm8994.o
 obj-$(CONFIG_GPIO_XILINX)	+= gpio-xilinx.o
+obj-$(CONFIG_GPIO_C2K)		+= gpio-c2k.o
+
diff --git a/drivers/gpio/gpio-c2k.c b/drivers/gpio/gpio-c2k.c
new file mode 100644
index 0000000..df9d7d2
--- /dev/null
+++ b/drivers/gpio/gpio-c2k.c
@@ -0,0 +1,152 @@
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <mach/comcerto-common.h>
+#include <asm/io.h>
+#include <mach/gpio.h>
+
+#define DRV_NAME "c2k-gpio"
+static DEFINE_SPINLOCK(c2k_gpio_lock);
+
+static struct c2k_gpio_chip {
+	struct gpio_chip chip;
+};
+
+static int c2k_is_gpio_rsvd(unsigned offset)
+{
+	if (offset < 32)
+		return ((c2k_gpio_pin_stat.c2k_gpio_pins_0_31 >> offset) & 0x1) ? 1 : 0 ;
+	else if (offset < 64)
+		return ((c2k_gpio_pin_stat.c2k_gpio_pins_32_63 >> (offset - 32)) & 0x1) ? 1 : 0;
+	else
+		return -EINVAL;
+}
+
+static int c2k_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	if (offset < 32)
+		return __raw_readl(COMCERTO_GPIO_INPUT_REG) & (0x1 << offset);
+	else if (offset < 64)
+		return __raw_readl(COMCERTO_GPIO_63_32_PIN_INPUT) & (0x1 << (offset - 32));
+	else
+		return -EINVAL;
+}
+
+static inline void __c2k_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	u32 data;
+
+	if (offset < 32) {
+		data = __raw_readl(COMCERTO_GPIO_OUTPUT_REG);
+		if (value)
+			data |= (1 << offset);
+		else
+			data &= ~(1 << offset);
+		__raw_writel(data, COMCERTO_GPIO_OUTPUT_REG);
+	} else {
+		data = __raw_readl(COMCERTO_GPIO_63_32_PIN_OUTPUT);
+		if (value)
+			data |= (1 << (offset - 32));
+		else
+			data &= ~(1 << (offset - 32));
+		__raw_writel(data, COMCERTO_GPIO_63_32_PIN_OUTPUT);
+	}
+}
+
+static void c2k_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	u32 data;
+	unsigned long flags;
+
+	if (offset > 63)
+		return;
+
+	spin_lock_irqsave(&c2k_gpio_lock, flags);
+
+	__c2k_gpio_set(chip, offset, value);
+
+	spin_unlock_irqrestore(&c2k_gpio_lock, flags);
+}
+
+static int c2k_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+	unsigned long flags;
+
+	if (offset > 63)
+		return -EINVAL;
+
+	if (c2k_is_gpio_rsvd(offset)) {
+		printk(KERN_ERR "GPIO-%d is reserved and cannot be used \n", offset);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&c2k_gpio_lock, flags);
+
+	if (offset < 32)
+		__raw_writel(__raw_readl(COMCERTO_GPIO_OE_REG) & ~(0x1 << offset), COMCERTO_GPIO_OE_REG);
+	else
+		__raw_writel(__raw_readl(COMCERTO_GPIO_63_32_PIN_OUTPUT_EN) & ~(0x1 << (offset - 32)), COMCERTO_GPIO_63_32_PIN_OUTPUT_EN);
+
+	spin_unlock_irqrestore(&c2k_gpio_lock, flags);
+
+	return 0;
+}
+
+static int c2k_direction_output(struct gpio_chip *chip, unsigned offset, int value)
+{
+	unsigned long flags;
+	u32 data;
+
+	if (offset > 63)
+		return -EINVAL;
+
+	if (c2k_is_gpio_rsvd(offset)) {
+		printk(KERN_ERR "GPIO-%d is reserved and cannot be used \n", offset);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&c2k_gpio_lock, flags);
+
+	if (offset < 32) {
+		__raw_writel(__raw_readl(COMCERTO_GPIO_OE_REG) | (0x1 << offset), COMCERTO_GPIO_OE_REG);
+		__c2k_gpio_set(chip, offset, value);
+	} else {
+		__raw_writel(__raw_readl(COMCERTO_GPIO_63_32_PIN_OUTPUT_EN) | (0x1 << (offset - 32)), COMCERTO_GPIO_63_32_PIN_OUTPUT_EN);
+		__c2k_gpio_set(chip, offset, value);
+	}
+
+	spin_unlock_irqrestore(&c2k_gpio_lock, flags);
+
+	return 0;
+}
+
+static struct c2k_gpio_chip c2k_gpio_chip = {
+	.chip = {
+		.label			= DRV_NAME,
+		.owner			= THIS_MODULE,
+		.direction_input	= c2k_direction_input,
+		.direction_output	= c2k_direction_output,
+		.set			= c2k_gpio_set,
+		.get			= c2k_gpio_get,
+		.base			= 0,
+		.ngpio			= C2K_GPIO_NR_GPIOS,
+	},
+};
+
+void __init c2k_init_gpio(void)
+{
+	int ret;
+
+	ret = gpiochip_add(&c2k_gpio_chip.chip);
+
+	if (ret)
+		printk(KERN_WARNING "C2K GPIO registration failed: %d\n", ret);
+}
+pure_initcall(c2k_init_gpio);
+
+MODULE_AUTHOR("Mindspeed Technologies");
+MODULE_DESCRIPTION("COMCERTO 2000 GPIO driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS(DRV_NAME);
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 5f13c62..3151581 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -44,7 +44,7 @@
 	  programs use the I2C bus.  Information on how to do this is
 	  contained in the file <file:Documentation/i2c/dev-interface>.
 
-	  This support is also available as a module.  If so, the module 
+	  This support is also available as a module.  If so, the module
 	  will be called i2c-dev.
 
 config I2C_MUX
@@ -86,6 +86,7 @@
 
 source drivers/i2c/algos/Kconfig
 source drivers/i2c/busses/Kconfig
+source drivers/i2c/chips/Kconfig
 
 config I2C_DEBUG_CORE
 	bool "I2C Core debugging messages"
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index beee6b2..a29d46d 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -7,7 +7,7 @@
 obj-$(CONFIG_I2C_SMBUS)		+= i2c-smbus.o
 obj-$(CONFIG_I2C_CHARDEV)	+= i2c-dev.o
 obj-$(CONFIG_I2C_MUX)		+= i2c-mux.o
-obj-y				+= algos/ busses/ muxes/
+obj-y				+= algos/ busses/ chips/ muxes/
 
 ccflags-$(CONFIG_I2C_DEBUG_CORE) := -DDEBUG
 CFLAGS_i2c-core.o := -Wno-deprecated-declarations
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index a3afac4..1010a44 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -308,6 +308,16 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-au1550.
 
+config I2C_COMCERTO
+	tristate "Comcerto I2C interface"
+	depends on I2C && (ARCH_COMCERTO)
+	help
+		If you say yes to this option, support will be included for the
+		Comcerto I2C interface.
+
+		This driver can also be built as a module.  If so, the module
+		will be called i2c-comcerto.
+
 config I2C_BLACKFIN_TWI
 	tristate "Blackfin TWI I2C support"
 	depends on BLACKFIN
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index fba6da6..f960665 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -31,6 +31,7 @@
 obj-$(CONFIG_I2C_AT91)		+= i2c-at91.o
 obj-$(CONFIG_I2C_AU1550)	+= i2c-au1550.o
 obj-$(CONFIG_I2C_BLACKFIN_TWI)	+= i2c-bfin-twi.o
+obj-$(CONFIG_I2C_COMCERTO)      += i2c-comcerto.o
 obj-$(CONFIG_I2C_CPM)		+= i2c-cpm.o
 obj-$(CONFIG_I2C_DAVINCI)	+= i2c-davinci.o
 obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM)	+= i2c-designware-platform.o
diff --git a/drivers/i2c/busses/i2c-comcerto.c b/drivers/i2c/busses/i2c-comcerto.c
new file mode 100644
index 0000000..c2c8649
--- /dev/null
+++ b/drivers/i2c/busses/i2c-comcerto.c
@@ -0,0 +1,744 @@
+/*
+ *  drivers/i2c/busses/i2c-comcerto.c
+ *
+ *  Copyright (C) 2008 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+#include <asm/sizes.h>
+#include <mach/i2c.h>
+#include <mach/irqs.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <mach/reset.h>
+
+MODULE_AUTHOR("Mindspeed Technologies, Inc.");
+MODULE_DESCRIPTION("Comcerto I2C bus driver");
+MODULE_LICENSE("GPL");
+
+#define SPEED_HIGH_KHZ		3400
+#define SPEED_FULL_KHZ		400
+#define SPEED_NORMAL_KHZ	100
+
+static int force_poll = 0;
+static struct clk *clk_i2c;
+module_param(force_poll, bool, S_IRUGO);
+MODULE_PARM_DESC(force_poll, "Force polling mode: 0=interrupt mode, polling mode otherwise");
+
+static int speed = 0;
+module_param(speed, int, S_IRUGO);
+MODULE_PARM_DESC(speed, "I2C speed: 0=standard, 1=fast, 2=high speed");
+
+struct comcerto_i2c
+{
+	struct i2c_adapter	*adapter;
+	struct device		*dev;
+	unsigned long		membase;
+	struct resource		*io;
+	int			irq;
+	u32			speed_khz;
+
+	wait_queue_head_t	wait;
+	struct i2c_msg		*msg;
+	int			msg_state;
+	int			msg_status;	/* < 0: error, == 0: success, > 0: message in progress */
+	int			msg_len;
+	int			msg_retries;
+};
+
+#define REG_ADDR(i2c, offset)		((i2c)->membase + (offset))
+#define RD_REG(i2c, offset)		__raw_readb(REG_ADDR(i2c, offset))
+#define WR_REG(i2c, offset, byte)	__raw_writeb(byte, REG_ADDR(i2c, offset))
+#define RD_DATA(i2c)			RD_REG(i2c, COMCERTO_I2C_DATA)
+#define WR_DATA(i2c, byte)		WR_REG(i2c, COMCERTO_I2C_DATA, byte)
+#define RD_CNTR(i2c)			RD_REG(i2c, COMCERTO_I2C_CNTR)
+#define WR_CNTR(i2c, byte)		WR_REG(i2c, COMCERTO_I2C_CNTR, byte)
+#define RD_STAT(i2c)			RD_REG(i2c, COMCERTO_I2C_STAT)
+#define WR_CCRFS(i2c, byte)		WR_REG(i2c, COMCERTO_I2C_CCRFS, byte)
+#define WR_CCRH(i2c, byte)		WR_REG(i2c, COMCERTO_I2C_CCRH, byte)
+#define WR_RESET(i2c, byte)		WR_REG(i2c, COMCERTO_I2C_RESET, byte)
+
+enum
+{
+	TR_IDLE = 0,
+	TR_START_ACK,
+	TR_ADDR_ACK,
+	TR_DATA_ACK,
+	RX_DATA_NACK,
+};
+
+static u8 comcerto_i2c_calculate_dividers(struct comcerto_i2c *i2c)
+{
+	int m, n, hz, speed_hz;
+	int saved_n, saved_m, saved_hz;
+	u8 dividers;
+	unsigned int i2c_clk;
+
+	/* Get the i2c clock rate */
+	i2c_clk = clk_get_rate(clk_i2c);
+
+	speed_hz = i2c->speed_khz * 1000;
+	saved_hz = saved_n = saved_m = 0;
+
+	for (m = 0; m < 16; m++) {
+		for (n = 0; n < 8; n++) {
+			hz = i2c_clk / ((1 << n) * (m + 1) * 10);
+			if (!saved_hz || abs(speed_hz - hz) < abs(speed_hz - saved_hz)) {
+				saved_n = n;
+				saved_m = m;
+				saved_hz = hz;
+			}
+		}
+	}
+
+	dividers = (saved_m << 3) | saved_n;
+	dev_dbg(i2c->dev, "%s: speed=%dkHz, M=%d, N=%d, dividers=0x%02x\n", __FUNCTION__,
+		saved_hz/1000, saved_m, saved_n, dividers);
+	printk("%s: speed=%dkHz, M=%d, N=%d, dividers=0x%02x\n", __FUNCTION__, saved_hz/1000, saved_m, saved_n, dividers);
+
+	return dividers;
+}
+
+/*
+ * Returns the timeout (in jiffies) for the given message.
+ */
+static int comcerto_i2c_calculate_timeout(struct comcerto_i2c *i2c, struct i2c_msg *msg)
+{
+	int timeout;
+
+	/* if no timeout was specified, calculate it */
+	if (i2c->adapter->timeout <= 0) {
+		if (i2c->irq >= 0) {
+			/* for the interrupt mode calculate timeout for 'full' message */
+			timeout = ((int)msg->len) * 10;	/* convert approx. to bits */
+			timeout /= i2c->speed_khz;	/* convert to bits per ms (note of kHz scale) */
+			timeout += timeout >> 1;	/* add 50% */
+			timeout = timeout*HZ / 1000;	/* convert to jiffies */
+			if (timeout < HZ / 5)		/* at least 200ms */
+				timeout = HZ / 5;
+		}
+		else
+			timeout = HZ;			/* 1 second for the polling mode */
+	}
+	else
+		timeout = i2c->adapter->timeout;
+
+	return timeout;
+}
+
+/*
+ * Initialize I2C core. Zero CNTR and DATA, try RESET. Short busy wait and check core status.
+ * After that set dividers for choosen speed.
+ */
+static void comcerto_i2c_reset(struct comcerto_i2c *i2c)
+{
+	u8 status, dividers;
+
+	dev_dbg(i2c->dev, "%s\n", __FUNCTION__);
+
+	WR_CNTR(i2c, 0);
+	WR_DATA(i2c, 0);
+	WR_RESET(i2c, 1);
+
+	udelay(10);
+
+	status = RD_STAT(i2c);
+	if (status != STAT_NO_RELEVANT_INFO)
+		dev_warn(i2c->dev, "%s: unexpected status after reset: 0x%02x\n", __FUNCTION__, status);
+
+	/* dividers should be placed in CCRH for high-sped mode and in CCRFS for standard/full modes */
+	dividers = comcerto_i2c_calculate_dividers(i2c);
+	if (i2c->speed_khz == SPEED_HIGH_KHZ)
+		WR_CCRH(i2c, dividers);
+	else
+		WR_CCRFS(i2c, dividers);
+}
+
+static inline void comcerto_i2c_message_complete(struct comcerto_i2c *i2c, int status)
+{
+	i2c->msg_status = status;
+	WR_CNTR(i2c, CNTR_STP);
+}
+
+static inline int comcerto_i2c_message_in_progress(struct comcerto_i2c *i2c)
+{
+	return i2c->msg_status > 0;
+}
+
+/*
+ * Wait event. This function sleeps in polling mode, in interrupt
+ * mode it enables IRQ from I2C core and exits immediately.
+ */
+static int comcerto_i2c_wait(struct comcerto_i2c *i2c, u8 cntr)
+{
+	cntr &= ~(CNTR_IFLG | CNTR_IEN);	/* clear both IFLG and IEN */
+
+	if (i2c->irq < 0) {
+		ulong jiffies_mark = jiffies + comcerto_i2c_calculate_timeout(i2c, i2c->msg);
+
+		WR_CNTR(i2c, cntr);
+		while ((RD_CNTR(i2c) & CNTR_IFLG) == 0) {
+			if (need_resched())
+				schedule();
+
+			if (time_after(jiffies, jiffies_mark)) {
+				dev_dbg(i2c->dev, "%s: polling transfer timeout\n", __FUNCTION__);
+				comcerto_i2c_message_complete(i2c, -ETIME);
+				comcerto_i2c_reset(i2c);
+				break;
+			}
+		}
+	}
+	else {
+		/* enable interrupt */
+		WR_CNTR(i2c, cntr | CNTR_IEN);
+	}
+
+	return 0;
+}
+
+static void comcerto_i2c_state_idle(struct comcerto_i2c *i2c, u8 *cntr)
+{
+	if (unlikely(i2c->msg->flags & I2C_M_NOSTART)) {
+		i2c->msg_state = TR_ADDR_ACK;
+	}
+	else {
+		*cntr = CNTR_STP|CNTR_STA;	/* SPT|STA to auto recover from bus error state transparently at the start of the transfer */
+		i2c->msg_state = TR_START_ACK;
+	}
+}
+
+static void comcerto_i2c_state_start_ack(struct comcerto_i2c *i2c, u8 *cntr)
+{
+	u8 status, addr;
+
+	*cntr = 0;	/* zero IFLG, IEN (for the interrupt mode it will be enabled in wait function) */
+
+	status = RD_STAT(i2c);
+
+	if (status == STAT_START || status == STAT_START_REPEATED) {
+		i2c->msg_state = TR_ADDR_ACK;
+
+		addr = i2c->msg->addr << 1;
+		if (i2c->msg->flags & I2C_M_RD)
+			addr |= 1;
+		if (i2c->msg->flags & I2C_M_REV_DIR_ADDR)
+			addr ^= 1;		/* invert RW bit if it's requested */
+
+		WR_DATA(i2c, addr);		/* write address and read/write bit */
+	} else {
+		dev_dbg(i2c->dev, "%s: unexpected state (%#x) on start phase, %s\n",
+			__FUNCTION__, status, i2c->msg_retries > 1 ? "retrying":"aborting");
+
+		if (--i2c->msg_retries < 0)
+			comcerto_i2c_message_complete(i2c, -1);
+		else
+			comcerto_i2c_state_idle(i2c, cntr);
+	}
+}
+
+static void comcerto_i2c_rx(struct comcerto_i2c *i2c)
+{
+	u8 status, cntr = 0;
+
+restart:
+	switch (i2c->msg_state) {
+	case TR_IDLE:
+		comcerto_i2c_state_idle(i2c, &cntr);
+		if (unlikely(i2c->msg->flags & I2C_M_NOSTART))
+			goto restart;	/* needed to avoid event loss in interrupt mode */
+		break;
+
+	case TR_START_ACK:
+		comcerto_i2c_state_start_ack(i2c, &cntr);
+		break;
+
+	case TR_ADDR_ACK:
+		if (unlikely(i2c->msg->flags & I2C_M_NOSTART)) {
+			/* we can enter this state if skip start/addr flag is set, so fake good ack */
+			status = STAT_ADDR_RD_ACK;
+		}
+		else {
+			status = RD_STAT(i2c);
+			/* check whether we should ignore NACK */
+			if (status == STAT_DATA_RD_NACK && (i2c->msg->flags & I2C_M_IGNORE_NAK))
+				status = STAT_DATA_RD_ACK;
+		}
+
+		if (likely(status == STAT_ADDR_RD_ACK)) {
+			/* start reception phase - wait until data is ready and loop in RX_DATA_ACK state
+			 * until we read all the data, sending ACK after each byte (but the last)
+			 */
+			i2c->msg_len = 0;
+			if (i2c->msg->len > 1) {
+				i2c->msg_state = TR_DATA_ACK;
+				cntr = CNTR_AAK;
+			}
+			else if (i2c->msg->len == 1) {
+				i2c->msg_state = RX_DATA_NACK;
+			}
+			else {	/* nothing to receive, send STOP and signal success */
+				comcerto_i2c_message_complete(i2c, 0);
+			}
+		}
+		else {
+			dev_dbg(i2c->dev, "%s: unexpected state (%#x) on address phase, %s\n",
+				__FUNCTION__, status, i2c->msg_retries > 1 ? "retrying":"aborting");
+
+			if (--i2c->msg_retries < 0)
+				comcerto_i2c_message_complete(i2c, -1);
+			else
+				comcerto_i2c_state_idle(i2c, &cntr);
+		}
+		break;
+
+	case TR_DATA_ACK:
+		status = RD_STAT(i2c);
+
+		if (likely(status == STAT_DATA_RD_ACK)) {
+			i2c->msg->buf[i2c->msg_len++] = RD_DATA(i2c);
+			if (likely(i2c->msg->len - i2c->msg_len > 1)) {
+				cntr = CNTR_AAK;
+			}
+			else {
+				i2c->msg_state = RX_DATA_NACK;
+				/* NACK should be transmitted on the last byte */
+			}
+		}
+		else {
+			dev_dbg(i2c->dev, "%s: unexpected state (%#x) on read phase\n", __FUNCTION__, status);
+			comcerto_i2c_message_complete(i2c, -1);
+		}
+		break;
+
+	case RX_DATA_NACK:
+		status = RD_STAT(i2c);
+		if (likely(status == STAT_DATA_RD_NACK)) {
+			i2c->msg->buf[i2c->msg_len++] = RD_DATA(i2c);
+			comcerto_i2c_message_complete(i2c, 0);
+		}
+		else {
+			dev_dbg(i2c->dev, "%s: unexpected state (%#x) on finishing read phase\n", __FUNCTION__, status);
+			comcerto_i2c_message_complete(i2c, -1);
+		}
+	}
+
+	/* no wait if we completed message */
+	if (comcerto_i2c_message_in_progress(i2c))
+		comcerto_i2c_wait(i2c, cntr);
+}
+
+static void comcerto_i2c_tx(struct comcerto_i2c *i2c)
+{
+	u8 status, cntr = 0;
+
+restart:
+	switch (i2c->msg_state) {
+	case TR_IDLE:
+		comcerto_i2c_state_idle(i2c, &cntr);
+		if (unlikely(i2c->msg->flags & I2C_M_NOSTART))
+			goto restart;	/* needed to avoid event loss in interrupt mode */
+		break;
+
+	case TR_START_ACK:
+		comcerto_i2c_state_start_ack(i2c, &cntr);
+		break;
+
+	case TR_ADDR_ACK:
+		if (unlikely(i2c->msg->flags & I2C_M_NOSTART)) {
+			/* we can enter this state if skip start/addr flag is set, so fake good ack */
+			status = STAT_ADDR_WR_ACK;
+		}
+		else {
+			status = RD_STAT(i2c);
+			if (status == STAT_DATA_WR_NACK && (i2c->msg->flags & I2C_M_IGNORE_NAK))
+				status = STAT_DATA_WR_ACK;
+		}
+
+		if (likely(status == STAT_ADDR_WR_ACK)) {
+			/* start reception phase - wait until data is ready and loop in TX_DATA_ACK state
+			 * until we read all the data, sending ACK after each byte (but the last)
+			 */
+			i2c->msg_state = TR_DATA_ACK;
+			i2c->msg_len = 0;
+			if (likely(i2c->msg->len != 0)) {
+				WR_DATA(i2c, i2c->msg->buf[i2c->msg_len++]);
+				//printk("comcerto_i2c_tx: i2c->msg->buf[i2c->msg_len - 1]=%d\n", i2c->msg->buf[i2c->msg_len - 1]);
+			}
+			else {
+				/* nothing to transmit, send STOP and signal success */
+				comcerto_i2c_message_complete(i2c, 0);
+			}
+		}
+		else {
+			dev_dbg(i2c->dev, "%s: unexpected state (%#x) on address phase, %s\n",
+				__FUNCTION__, status, i2c->msg_retries > 1 ? "retrying":"aborting");
+
+			if (--i2c->msg_retries < 0)
+				comcerto_i2c_message_complete(i2c, -1);
+			else
+				comcerto_i2c_state_idle(i2c, &cntr);
+		}
+		break;
+
+	case TR_DATA_ACK:
+		status = RD_STAT(i2c);
+		if (status == STAT_DATA_WR_NACK && (i2c->msg->flags & I2C_M_IGNORE_NAK))
+			status = STAT_DATA_WR_ACK;
+
+		if (likely(status == STAT_DATA_WR_ACK)) {
+			if (i2c->msg->len > i2c->msg_len)
+				WR_DATA(i2c, i2c->msg->buf[i2c->msg_len++]);
+			else
+				comcerto_i2c_message_complete(i2c, 0);
+		}
+		else {
+			dev_dbg(i2c->dev, "%s: unexpected state (%#x) on read data phase\n", __FUNCTION__, status);
+			comcerto_i2c_message_complete(i2c, -1);
+		}
+		break;
+	}
+
+	if (comcerto_i2c_message_in_progress(i2c))
+		comcerto_i2c_wait(i2c, cntr);
+}
+
+static irqreturn_t comcerto_i2c_interrupt(int irq, void *dev_id)
+{
+	struct comcerto_i2c *i2c = dev_id;
+
+	if (!(RD_CNTR(i2c) & CNTR_IFLG))
+		goto none;
+
+	/* IRQ enable/disable logic is hidden in state handlers, all we need is to wake
+	 * process when message completed.
+	 */
+	if (i2c->msg->flags & I2C_M_RD)
+		comcerto_i2c_rx(i2c);
+	else
+		comcerto_i2c_tx(i2c);
+
+	if (!comcerto_i2c_message_in_progress(i2c)) {
+		WR_CNTR(i2c, RD_CNTR(i2c) & ~CNTR_IEN);	/* disable interrupt unconditionally */
+		wake_up(&i2c->wait);
+	}
+
+	return IRQ_HANDLED;
+none:
+	return IRQ_NONE;
+}
+
+static void comcerto_i2c_message_process(struct comcerto_i2c *i2c, struct i2c_msg *msg)
+{
+	i2c->msg = msg;
+	i2c->msg_state = TR_IDLE;
+	i2c->msg_status = 1;
+	i2c->msg_retries = i2c->adapter->retries;
+
+polling_mode:
+	if (msg->flags & I2C_M_RD)
+		comcerto_i2c_rx(i2c);
+	else
+		comcerto_i2c_tx(i2c);
+
+	if (i2c->irq < 0) {
+		/*if (i2c->msg != NULL)*/
+			goto polling_mode;
+	}
+	else {
+		int timeout, res;
+		ulong flags;
+
+		timeout = comcerto_i2c_calculate_timeout(i2c, msg);
+
+		res = wait_event_timeout(i2c->wait, i2c->msg_status <= 0, timeout);
+
+		local_irq_save(flags);
+
+		/* check if we timed out and set respective error codes */
+		if (res == 0) {
+			if (comcerto_i2c_message_in_progress(i2c)) {
+				dev_dbg(i2c->dev, "%s: interrupt transfer timeout\n", __FUNCTION__);
+				comcerto_i2c_message_complete(i2c, -ETIME);
+				comcerto_i2c_reset(i2c);
+			}
+		}
+
+		local_irq_restore(flags);
+	}
+}
+
+/*
+ * Generic master transfer entrypoint.
+ * Returns the number of processed messages or error value
+ */
+static int comcerto_i2c_master_xfer(struct i2c_adapter *adapter, struct i2c_msg msgs[], int num)
+{
+	struct comcerto_i2c *i2c = i2c_get_adapdata(adapter);
+	int i;
+
+	dev_dbg(i2c->dev, "%s: %d messages to process\n", __FUNCTION__, num);
+
+	for (i = 0; i < num; i++) {
+		dev_dbg(i2c->dev, "%s: message #%d: addr=%#x, flags=%#x, len=%u\n", __FUNCTION__,
+			i, msgs[i].addr, msgs[i].flags, msgs[i].len);
+
+		comcerto_i2c_message_process(i2c, &msgs[i]);
+
+		if (i2c->msg_status < 0) {
+			dev_dbg(i2c->dev, "%s: transfer failed on message #%d (addr=%#x, flags=%#x, len=%u)\n",
+				__FUNCTION__, i, msgs[i].addr, msgs[i].flags, msgs[i].len);
+			break;
+		}
+	}
+
+	if (i2c->msg_status == -1)
+		i2c->msg_status = -EIO;
+
+	if (i2c->msg_status == 0)
+		i2c->msg_status = num;
+
+	return i2c->msg_status;
+}
+
+static u32 comcerto_i2c_functionality(struct i2c_adapter *adap)
+{
+	return (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL);
+}
+
+static struct i2c_algorithm comcerto_i2c_algo = {
+	.master_xfer	= comcerto_i2c_master_xfer,
+	.functionality	= comcerto_i2c_functionality,
+};
+
+static struct i2c_adapter comcerto_i2c_adapter = {
+	.name		= "comcerto_i2c",
+	.owner		= THIS_MODULE,
+	.algo		= &comcerto_i2c_algo,
+	.timeout	= 0,	/* <= zero means that we calculate timeout in run-time, can be changed with ioctl call */
+	.retries	= 0,	/* no retries by default - let the user decide what's the best, can be changed with ioctl call */
+};
+
+static int comcerto_i2c_probe(struct platform_device *pdev)
+{
+	struct comcerto_i2c *i2c;
+	struct resource *irq;
+	int res = -1;
+
+	dev_dbg(&pdev->dev, "%s\n", __FUNCTION__);
+	
+	/* Put the I2C device Out-Of-Reset*/
+	c2000_block_reset(COMPONENT_AXI_I2C,0);
+
+	/* Clock divider configuration, get the i2c clock*/
+	clk_i2c = clk_get(NULL, "spi_i2c");
+	if (IS_ERR(clk_i2c)){
+		pr_err("%s: Unable to obtain i2c clock: %ld\n", __func__, PTR_ERR(clk_i2c));
+		return PTR_ERR(clk_i2c);
+	}
+
+	/*Enable the i2c clock */
+	res = clk_enable(clk_i2c); 
+	if (res){
+		pr_err("%s: i2c clock failed to enable:\n", __func__);
+		goto err0;
+	}
+
+	i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
+	if (i2c == NULL) {
+		dev_err(&pdev->dev, "%s: failed allocate memory\n", __FUNCTION__);
+		res = -ENOMEM;
+		goto err0;
+	}
+
+	i2c->adapter = &comcerto_i2c_adapter;
+	i2c->adapter->dev.parent = &pdev->dev;
+	i2c->dev = &pdev->dev;
+
+	init_waitqueue_head(&i2c->wait);
+
+	platform_set_drvdata(pdev, i2c);
+	i2c_set_adapdata(&comcerto_i2c_adapter, i2c);
+
+	i2c->io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (i2c->io == NULL) {
+		dev_err(&pdev->dev, "%s: no IO region specified\n", __FUNCTION__);
+		res = -ENOENT;
+		goto err1;
+	}
+
+	if (!request_mem_region(i2c->io->start, i2c->io->end - i2c->io->start + 1, "I2C")) {
+		dev_err(i2c->dev, "%s: failed to request memory region\n", __FUNCTION__);
+		goto err1;
+	}
+
+	i2c->membase = APB_VADDR(i2c->io->start);
+
+	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (irq == NULL && !force_poll) {
+		dev_warn(i2c->dev, "%s: no IRQ specified in resources, polling mode forced\n", __FUNCTION__);
+		force_poll = 1;
+		i2c->irq = -1;
+	}
+
+	if (speed == 0) {
+		i2c->speed_khz = SPEED_NORMAL_KHZ;
+	}
+	else if (speed == 1) {
+		i2c->speed_khz = SPEED_FULL_KHZ;
+	}
+	else if (speed == 2) {
+		i2c->speed_khz = SPEED_HIGH_KHZ;
+	}
+	else {
+		dev_err(i2c->dev, "%s: invalid 'speed' module option provided (%d, must be 0,1,2 for normal/full/high modes)\n",
+			__FUNCTION__, speed);
+		goto err2;
+	}
+
+
+	comcerto_i2c_reset(i2c);
+
+	if (!force_poll) {
+		i2c->irq = irq->start;
+
+		res = request_irq(i2c->irq, comcerto_i2c_interrupt, IRQF_SHARED, "I2C", i2c);
+		if (res < 0) {
+			dev_warn(i2c->dev, "%s: failed to request IRQ%d, polling mode forced\n", __FUNCTION__, i2c->irq);
+			force_poll = 1;
+			i2c->irq = -1;
+		}
+	}
+	else
+		i2c->irq = -1;
+
+	if (i2c_add_adapter(&comcerto_i2c_adapter) != 0) {
+		dev_err(i2c->dev, "%s: failed to add I2C adapter\n", __FUNCTION__);
+		goto err3;
+	}
+
+	dev_dbg(&pdev->dev, "%s: I2C adapter registered\n", __FUNCTION__);
+
+	return 0;
+
+err3:
+	if (i2c->irq >= 0)
+		free_irq(i2c->irq, i2c);
+
+err2:
+	release_mem_region(i2c->io->start, i2c->io->end - i2c->io->end + 1);
+
+err1:
+	kfree(i2c);
+
+err0:
+	return res;
+}
+
+static int comcerto_i2c_remove(struct platform_device *pdev)
+{
+	struct comcerto_i2c *i2c = platform_get_drvdata(pdev);
+
+	dev_dbg(i2c->dev, "%s\n", __FUNCTION__);
+
+	platform_set_drvdata(pdev, NULL);
+
+	i2c_del_adapter(i2c->adapter);
+
+	if (i2c->irq >= 0)
+		free_irq(i2c->irq, i2c);
+
+	release_mem_region(i2c->io->start, i2c->io->end - i2c->io->start + 1);
+
+	kfree(i2c);
+
+	/* Disable the Clock */
+	clk_disable(clk_i2c);
+	clk_put(clk_i2c);
+
+	/* Put the I2C device in reset state*/
+	c2000_block_reset(COMPONENT_AXI_I2C,1);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int comcerto_i2c_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	/* No need to suspend client drivers here. Because clients are
+	 * children, client drivers get suspended before adapter driver
+	*/
+	
+	/* So do the Clock disable here , This clock is depends upon Legacy SPI*/
+	clk_disable(clk_i2c);
+	return 0;
+}
+	
+static int comcerto_i2c_resume(struct platform_device *pdev)
+{
+	int ret;
+	/* No need to suspend client drivers here. Because clients are
+	 * children, client drivers get suspended before adapter driver
+	*/
+
+	/* So do the Clock Enable here , This clock is depends upon Legacy SPI*/
+	ret = clk_enable(clk_i2c);
+	if (ret)
+	{
+		pr_err("%s: I2C clock enable failed \n",__func__);
+		return ret;
+	}
+	return 0;
+}
+#endif
+
+static struct platform_driver comcerto_i2c_driver = {
+	.driver = {
+		.name	= "comcerto_i2c",
+		.owner	= THIS_MODULE,
+	},
+	.probe	= comcerto_i2c_probe,
+	.remove	= comcerto_i2c_remove,
+#ifdef CONFIG_PM
+	.suspend = comcerto_i2c_suspend,
+	.resume  = comcerto_i2c_resume,
+#endif
+};
+
+static int __init comcerto_i2c_init(void)
+{
+	if (platform_driver_register(&comcerto_i2c_driver)) {
+		return -1;
+	}
+
+	return 0;
+}
+
+static void __exit comcerto_i2c_exit(void)
+{
+	platform_driver_unregister(&comcerto_i2c_driver);
+}
+
+module_init(comcerto_i2c_init);
+module_exit(comcerto_i2c_exit);
+
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
new file mode 100644
index 0000000..6b3e093
--- /dev/null
+++ b/drivers/i2c/chips/Kconfig
@@ -0,0 +1,15 @@
+#
+# Miscellaneous I2C chip drivers configuration
+#
+# *** DEPRECATED! Do not add new entries! See Makefile ***
+#
+
+menu "Miscellaneous I2C Chip support"
+
+config EEPROM_AT
+	tristate "I2c-eeprom-at"
+	depends on I2C
+	help
+	  This provides an interface to read and write the EEPROM and reset the chip.
+
+endmenu
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
new file mode 100644
index 0000000..6ca1e2a
--- /dev/null
+++ b/drivers/i2c/chips/Makefile
@@ -0,0 +1,18 @@
+#
+# Makefile for miscellaneous I2C chip drivers.
+#
+# Do not add new drivers to this directory! It is DEPRECATED.
+#
+# Device drivers are better grouped according to the functionality they
+# implement rather than to the bus they are connected to. In particular:
+# * Hardware monitoring chip drivers go to drivers/hwmon
+# * RTC chip drivers go to drivers/rtc
+# * I/O expander drivers go to drivers/gpio
+#
+
+obj-$(CONFIG_EEPROM_AT)	+= eeprom.o
+
+ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
+
diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c
new file mode 100644
index 0000000..73eaa5a
--- /dev/null
+++ b/drivers/i2c/chips/eeprom.c
@@ -0,0 +1,277 @@
+/*
+ *  Copyright (C) 2008 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+MODULE_AUTHOR("Mindspeed Technologies, Inc.");
+MODULE_DESCRIPTION("I2C EEPROM driver");
+MODULE_LICENSE("GPL");
+
+#define CONFIG_EEPROM_PAGE_SIZE 128
+#define CONFIG_EEPROM_CHIP_SIZE (512*1024)
+#define CONFIG_EEPROM_WRITE_TIME 5
+
+#define EEPROM_PAGE	(CONFIG_EEPROM_PAGE_SIZE)
+#define EEPROM_SIZE	(CONFIG_EEPROM_CHIP_SIZE)
+#define EEPROM_WAIT	(CONFIG_EEPROM_WRITE_TIME)
+
+#define DRV_NAME	"eeprom"
+
+struct i2c_client *eeprom_i2c_client;
+
+static inline int eeprom_set_address(struct i2c_msg *msg, u32 addr)
+{
+	int addr_len = 1;
+
+	msg->buf[0] = addr >> 8;
+	msg->len++;
+	if (EEPROM_SIZE > 256) {
+		msg->buf[1] = addr & 255;
+		msg->len++;
+		addr_len++;
+	}
+
+	return addr_len;
+}
+
+static int eeprom_set_pointer(struct i2c_client *client, u32 addr)
+{
+	int err;
+	u8 buf[2];
+	struct i2c_msg msg =
+	{
+		.addr = client->addr,
+		.flags = 0,
+		.len = 0,
+		.buf = buf,
+	};
+
+	eeprom_set_address(&msg, addr);
+	if ((err = i2c_transfer(client->adapter, &msg, 1)) != 1) {
+		dev_err(&client->dev, "read transaction failed - couldn't set address, code: %d\n", err);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int eeprom_read_data(struct i2c_client *client, void *buf, int len)
+{
+	int err, i = 0;
+	struct i2c_msg	msg =
+	{
+		.addr = client->addr,
+		.flags = I2C_M_RD,
+		.len = len,
+		.buf = buf,
+	};
+
+	if ((err = i2c_transfer(client->adapter, &msg, 1)) != 1) {
+		dev_err(&client->dev, "read transaction failed, code: %d\n", err);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int eeprom_write_data(struct i2c_client *client, u32 addr, void *buf, void *src, int len)
+{
+	int err;
+	struct i2c_msg msg =
+	{
+		.addr = client->addr,
+		.flags = 0,
+		.len = len,
+		.buf = buf,
+	};
+
+	/* set address and copy data just after address bytes */
+	memcpy(buf + eeprom_set_address(&msg, addr), src, len);
+
+	if ((err = i2c_transfer(client->adapter, &msg, 1)) != 1) {
+		dev_err(&client->dev, "write transaction failed, code: %d\n", err);
+		return -EIO;
+	}
+
+	mdelay(EEPROM_WAIT);
+
+	return 0;
+}
+
+static int eeprom_read_write(struct kobject *kobj, char *buf, loff_t offs, size_t len, int read)
+{
+	struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj));
+	int count;
+
+	if (offs + len > EEPROM_SIZE)
+		len = EEPROM_SIZE - offs;
+	if (len < 0)
+		return -EINVAL;
+	if (len == 0)
+		return 0;
+
+	if (read) {
+		count = eeprom_set_pointer(client, offs);	/* for the read transaction set address once at start */
+		if (count == 0)
+			count = eeprom_read_data(client, buf, len);
+		if (count == 0)
+			count = len;
+	}
+	else {
+		u8 *txbuf = kmalloc(EEPROM_PAGE + 2, GFP_KERNEL);
+		u32 tmp;
+		int req, err;
+
+		if (txbuf != NULL) {
+			/* write all data in no more than one page size transaction */
+			count = 0;
+
+			do {
+				tmp = (offs + count + EEPROM_PAGE) & ~(EEPROM_PAGE - 1);
+				req = tmp - offs - count;
+				if (req + count > len)
+					req = len - count;
+
+				err = eeprom_write_data(client, offs+count, txbuf, buf+count, req);
+				if (err < 0) {
+					count = err;
+					break;
+				}
+
+				count += req;
+			} while (count < len);
+
+			kfree(txbuf);
+		} else {
+			dev_err(&client->dev, "failed to allocate memory\n");
+			count = -ENOMEM;
+		}
+	}
+
+	return count;
+}
+
+static ssize_t eeprom_read(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int i = 0;
+	loff_t off = 0x50;
+	size_t ret, count = 4;
+
+	ret = eeprom_read_write(&dev->kobj, buf, off + i, count, 1);
+
+	return ret;
+}
+
+static ssize_t eeprom_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	loff_t off = 0x50;
+
+	return eeprom_read_write(&dev->kobj, buf, off, count, 0);
+}
+
+static struct device_attribute eeprom_attr = __ATTR(eeprom, 0644, eeprom_read, eeprom_write);
+
+int eeprom_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	int err = 0;
+
+	client = eeprom_i2c_client;
+
+	err = sysfs_create_file(&client->dev.kobj, &eeprom_attr);
+	if (err) {
+		dev_err(&client->dev, "failed to create sysfs node\n");
+		goto err;
+	}
+
+	return 0;
+
+err:
+	return err;
+}
+
+static int eeprom_remove(struct i2c_client *client)
+{
+	sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int eeprom_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	return 0;
+}
+
+static int eeprom_resume(struct i2c_client *client)
+{
+         return 0;
+}
+#else
+#define eeprom_suspend         NULL
+#define eeprom_resume          NULL
+#endif /* CONFIG_PM */
+
+static struct i2c_device_id eeprom_idtable[] = {
+	{ "eeprom", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, eeprom_idtable);
+
+static struct i2c_driver eeprom_driver = {
+	.id_table       = eeprom_idtable,
+	.probe		= eeprom_probe,
+	.remove 	= __devexit_p(eeprom_remove),
+	.suspend        = eeprom_suspend,
+	.resume         = eeprom_resume,
+	.driver = {
+		.name   = DRV_NAME,
+		.owner  =THIS_MODULE,
+	},
+};
+
+static unsigned short normal_i2c[] = { 0x50, I2C_CLIENT_END };
+
+static int eeprom_init(void)
+{
+	struct i2c_adapter *i2c_adap;
+	struct i2c_board_info i2c_info;
+
+	i2c_adap = i2c_get_adapter(0);
+	memset(&i2c_info, 0, sizeof(struct i2c_board_info));
+	strlcpy(i2c_info.type, "eeprom", I2C_NAME_SIZE);
+	eeprom_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info, normal_i2c, NULL);
+
+	i2c_put_adapter(i2c_adap);
+
+	i2c_add_driver(&eeprom_driver);
+
+	return 0;
+}
+
+static void eeprom_exit(void)
+{
+	i2c_del_driver(&eeprom_driver);
+}
+
+module_init(eeprom_init);
+module_exit(eeprom_exit);
+
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 58d8c6d..5040ce1 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -29,6 +29,16 @@
 
 #include <linux/device-mapper.h>
 
+#if defined(CONFIG_OCF_DM_CRYPT)
+#undef DM_DEBUG
+#ifdef DM_DEBUG
+#define dmprintk printk
+#else
+#define dmprintk(fmt,args...)
+#endif
+#include <linux/cryptodev.h>
+#endif /* CONFIG_OCF_DM_CRYPT */
+
 #define DM_MSG_PREFIX "crypt"
 
 /*
@@ -146,6 +156,10 @@
 	sector_t iv_offset;
 	unsigned int iv_size;
 
+#if defined(CONFIG_OCF_DM_CRYPT)
+	struct cryptoini	cr_dm;	/* OCF session */
+	uint64_t	ocf_cryptoid;	/* OCF sesssion ID */
+#endif
 	/*
 	 * Duplicated per cpu state. Access through
 	 * per_cpu_ptr() only.
@@ -269,7 +283,7 @@
 		return err;
 
 	for_each_possible_cpu(cpu) {
-		essiv_tfm = per_cpu_ptr(cc->cpu, cpu)->iv_private,
+		essiv_tfm = per_cpu_ptr(cc->cpu, cpu)->iv_private;
 
 		err = crypto_cipher_setkey(essiv_tfm, essiv->salt,
 				    crypto_hash_digestsize(essiv->hash_tfm));
@@ -305,7 +319,7 @@
 					     struct dm_target *ti,
 					     u8 *salt, unsigned saltsize)
 {
-	struct crypto_cipher *essiv_tfm;
+	struct crypto_cipher *essiv_tfm=NULL;
 	int err;
 
 	/* Setup the essiv_tfm with the given salt */
@@ -315,8 +329,12 @@
 		return essiv_tfm;
 	}
 
+#if  defined(CONFIG_OCF_DM_CRYPT)
+	if (crypto_cipher_blocksize(essiv_tfm) != cc->iv_size) {
+#else
 	if (crypto_cipher_blocksize(essiv_tfm) !=
 	    crypto_ablkcipher_ivsize(any_tfm(cc))) {
+#endif
 		ti->error = "Block size of ESSIV cipher does "
 			    "not match IV size of block cipher";
 		crypto_free_cipher(essiv_tfm);
@@ -419,6 +437,7 @@
 	return 0;
 }
 
+#if !defined(CONFIG_OCF_DM_CRYPT)
 static int crypt_iv_benbi_ctr(struct crypt_config *cc, struct dm_target *ti,
 			      const char *opts)
 {
@@ -459,6 +478,7 @@
 
 	return 0;
 }
+#endif
 
 static int crypt_iv_null_gen(struct crypt_config *cc, u8 *iv,
 			     struct dm_crypt_request *dmreq)
@@ -634,11 +654,13 @@
 	.generator = crypt_iv_essiv_gen
 };
 
+#if !defined(CONFIG_OCF_DM_CRYPT)
 static struct crypt_iv_operations crypt_iv_benbi_ops = {
 	.ctr	   = crypt_iv_benbi_ctr,
 	.dtr	   = crypt_iv_benbi_dtr,
 	.generator = crypt_iv_benbi_gen
 };
+#endif
 
 static struct crypt_iv_operations crypt_iv_null_ops = {
 	.generator = crypt_iv_null_gen
@@ -687,6 +709,275 @@
 		crypto_ablkcipher_alignmask(any_tfm(cc)) + 1);
 }
 
+static void kcryptd_crypt_read_done(struct dm_crypt_io *io);
+static void crypt_alloc_req(struct crypt_config *cc,
+			    struct convert_context *ctx);
+static void crypt_inc_pending(struct dm_crypt_io *io);
+static void crypt_dec_pending(struct dm_crypt_io *io);
+
+#if defined(CONFIG_OCF_DM_CRYPT)
+struct ocf_wr_priv {
+	u32			dm_ocf_wr_completed;	/* Num of wr completions */
+	u32			dm_ocf_wr_pending;	/* Num of wr pendings */
+	wait_queue_head_t	dm_ocf_wr_queue;	/* waiting Q, for wr completion */
+};
+
+struct ocf_rd_priv {
+	u32			dm_ocf_rd_completed;	/* Num of rd completions */
+	u32			dm_ocf_rd_pending;	/* Num of rd pendings */
+	wait_queue_head_t	dm_ocf_rd_queue;	/* waiting Q, for rd completion */
+};
+
+static int dm_ocf_wr_cb(struct cryptop *crp)
+{
+	struct ocf_wr_priv *ocf_wr_priv;
+
+	if(crp == NULL) {
+		printk("dm_ocf_wr_cb: crp is NULL!! \n");
+		return 0;
+	}
+
+	ocf_wr_priv = (struct ocf_wr_priv*)crp->crp_opaque;
+
+	ocf_wr_priv->dm_ocf_wr_completed++;
+
+	/* if no more pending for read, wake up the read task. */
+	if(ocf_wr_priv->dm_ocf_wr_completed == ocf_wr_priv->dm_ocf_wr_pending)
+		wake_up(&ocf_wr_priv->dm_ocf_wr_queue);
+
+	crypto_freereq(crp);
+	return 0;
+}
+
+static int dm_ocf_rd_cb(struct cryptop *crp)
+{
+	struct ocf_rd_priv *ocf_rd_priv;
+
+	if(crp == NULL) {
+		printk("dm_ocf_rd_cb: crp is NULL!! \n");
+		return 0;
+	}
+
+	ocf_rd_priv = (struct ocf_rd_priv*)crp->crp_opaque;
+
+	ocf_rd_priv->dm_ocf_rd_completed++;
+
+	/* if no more pending for read, wake up the read task. */
+	if(ocf_rd_priv->dm_ocf_rd_completed == ocf_rd_priv->dm_ocf_rd_pending)
+		wake_up(&ocf_rd_priv->dm_ocf_rd_queue);
+
+	crypto_freereq(crp);
+	return 0;
+}
+
+static inline int dm_ocf_process(struct crypt_config *cc, struct scatterlist *out,
+		struct scatterlist *in, unsigned int len, u8 *iv, int iv_size, int write, void *priv)
+{
+	struct cryptop *crp;
+	struct cryptodesc *crda = NULL;
+	struct page *in_page = sg_page(in);
+	struct page *out_page = sg_page(out);
+	int r=0;
+
+	if(!iv) {
+		printk("dm_ocf_process: only CBC mode is supported\n");
+		return -EPERM;
+	}
+
+	crp = crypto_getreq(1);  /* only encryption/decryption */
+	if (!crp) {
+		printk("\ndm_ocf_process: crypto_getreq failed!!\n");
+		return -ENOMEM;
+	}
+
+	crda = crp->crp_desc;
+
+	crda->crd_flags  = (write)? CRD_F_ENCRYPT: 0;
+	crda->crd_alg    = cc->cr_dm.cri_alg;
+	crda->crd_skip   = 0;
+	crda->crd_len    = len;
+	crda->crd_inject = 0; /* NA */
+	crda->crd_klen   = cc->cr_dm.cri_klen;
+	crda->crd_key    = cc->cr_dm.cri_key;
+
+	if (iv) {
+		//crda->crd_flags |= (CRD_F_IV_PRESENT);
+		crda->crd_flags |= (CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT);
+		if( iv_size > EALG_MAX_BLOCK_LEN ) {
+			printk("dm_ocf_process: iv is too big!!\n");
+		}
+		memcpy(&crda->crd_iv, iv, iv_size);
+	}
+
+
+	//dmprintk("len: %d\n",len);
+	crp->crp_ilen = len; /* Total input length */
+	//crp->crp_flags = CRYPTO_F_CBIMM;
+	crp->crp_flags = CRYPTO_F_CBIMM | CRYPTO_F_BATCH;
+	crp->crp_buf = page_address(in_page) + in->offset;
+	crp->crp_out_buf = page_address(out_page) + out->offset;
+	crp->crp_opaque = priv;
+	if(write) {
+		crp->crp_callback = dm_ocf_wr_cb;
+	}
+	else {
+		crp->crp_callback = dm_ocf_rd_cb;
+	}
+	crp->crp_sid = cc->ocf_cryptoid;
+	r = crypto_dispatch(crp);
+	if (r == ENOMEM) {
+		dmprintk("crypto_dispatch returned ENOMEM \n");
+	}
+	return r;
+}
+
+static int ocf_crypt_convert_block(struct crypt_config *cc,
+				struct convert_context *ctx,
+				struct ablkcipher_request *req,
+				int write, void *priv)
+{
+	struct bio_vec *bv_in = bio_iovec_idx(ctx->bio_in, ctx->idx_in);
+	struct bio_vec *bv_out = bio_iovec_idx(ctx->bio_out, ctx->idx_out);
+	struct dm_crypt_request *dmreq;
+	u8 iv[cc->iv_size];
+	int r = 0;
+
+	dmreq = dmreq_of_req(cc, req);
+	dmreq->iv_sector = ctx->sector;
+	dmreq->ctx = ctx;
+	sg_init_table(&dmreq->sg_in, 1);
+	sg_set_page(&dmreq->sg_in, bv_in->bv_page, 1 << SECTOR_SHIFT,
+		    bv_in->bv_offset + ctx->offset_in);
+
+	sg_init_table(&dmreq->sg_out, 1);
+	sg_set_page(&dmreq->sg_out, bv_out->bv_page, 1 << SECTOR_SHIFT,
+		    bv_out->bv_offset + ctx->offset_out);
+
+	ctx->offset_in += 1 << SECTOR_SHIFT;
+	if (ctx->offset_in >= bv_in->bv_len) {
+		ctx->offset_in = 0;
+		ctx->idx_in++;
+	}
+
+	ctx->offset_out += 1 << SECTOR_SHIFT;
+	if (ctx->offset_out >= bv_out->bv_len) {
+		ctx->offset_out = 0;
+		ctx->idx_out++;
+	}
+
+	if (cc->iv_gen_ops) {
+		r = cc->iv_gen_ops->generator(cc, iv, dmreq);
+		if (r < 0)
+			return r;
+		r = dm_ocf_process(cc, &dmreq->sg_out, &dmreq->sg_in, dmreq->sg_in.length, iv, cc->iv_size, write, priv);
+	} else {
+		r = dm_ocf_process(cc, &dmreq->sg_in, &dmreq->sg_in, dmreq->sg_in.length, NULL, 0, write, priv);
+	}
+
+	return r;
+}
+
+/*
+ * Encrypt / decrypt data from one bio to another one (can be the same one)
+ */
+static int ocf_crypt_convert(struct crypt_config *cc,
+			 struct convert_context *ctx, struct dm_crypt_io *io)
+{
+	int r = 0;
+	long wr_timeout = 300000;
+	long rd_timeout = 300000;
+	long wr_tm, rd_tm;
+	int num = 0, num1 =0;
+	void *priv = NULL;
+	struct ocf_wr_priv *ocf_wr_priv = NULL;
+	struct ocf_rd_priv *ocf_rd_priv = NULL;
+	int write=0;
+	struct crypt_cpu *this_cc = this_crypt_config(cc);
+
+	atomic_set(&ctx->pending, 1);
+
+
+	if(bio_data_dir(ctx->bio_in) == WRITE) {
+		write = 1;
+		ocf_wr_priv = kmalloc(sizeof(struct ocf_wr_priv),GFP_KERNEL);
+		if(!ocf_wr_priv) {
+			printk("ocf_crypt_convert: out of memory \n");
+			return -ENOMEM;
+		}
+		ocf_wr_priv->dm_ocf_wr_pending = 0;
+		ocf_wr_priv->dm_ocf_wr_completed = 0;
+		init_waitqueue_head(&ocf_wr_priv->dm_ocf_wr_queue);
+		priv = ocf_wr_priv;
+	}
+	else {
+		ocf_rd_priv = kmalloc(sizeof(struct ocf_rd_priv),GFP_KERNEL);
+		if(!ocf_rd_priv) {
+			printk("ocf_crypt_convert: out of memory \n");
+			return -ENOMEM;
+		}
+		ocf_rd_priv->dm_ocf_rd_pending = 0;
+		ocf_rd_priv->dm_ocf_rd_completed = 0;
+		init_waitqueue_head(&ocf_rd_priv->dm_ocf_rd_queue);
+		priv = ocf_rd_priv;
+	}
+
+	while(ctx->idx_in < ctx->bio_in->bi_vcnt &&
+	      ctx->idx_out < ctx->bio_out->bi_vcnt) {
+
+		crypt_alloc_req(cc, ctx);
+
+		atomic_inc(&ctx->pending);
+
+		if(bio_data_dir(ctx->bio_in) == WRITE) {
+			num++;
+		}
+		/* if last read in the context - send the io, so the OCF read callback will release the IO. */
+		else {
+			num1++;
+		}
+
+		r = ocf_crypt_convert_block(cc, ctx, this_cc->req, write, priv);
+
+		switch (r) {
+			case 0:
+				atomic_dec(&ctx->pending);
+				ctx->sector++;
+				//cond_resched();
+				continue;
+			/* error */
+			default:
+				atomic_dec(&ctx->pending);
+				//return r;
+		}
+	}
+
+	if(bio_data_dir(ctx->bio_in) == WRITE) {
+		ocf_wr_priv->dm_ocf_wr_pending += num;
+		wr_tm = wait_event_timeout(ocf_wr_priv->dm_ocf_wr_queue,
+					(ocf_wr_priv->dm_ocf_wr_pending == ocf_wr_priv->dm_ocf_wr_completed)
+										, msecs_to_jiffies(wr_timeout) );
+		if (!wr_tm) {
+			printk("ocf_crypt_convert: wr work was not finished in %ld msecs, %d pending %d completed.\n",
+					wr_timeout, ocf_wr_priv->dm_ocf_wr_pending, ocf_wr_priv->dm_ocf_wr_completed);
+		}
+		kfree(ocf_wr_priv);
+	}
+	else {
+		ocf_rd_priv->dm_ocf_rd_pending += num1;
+		rd_tm = wait_event_timeout(ocf_rd_priv->dm_ocf_rd_queue,
+					(ocf_rd_priv->dm_ocf_rd_pending == ocf_rd_priv->dm_ocf_rd_completed)
+										, msecs_to_jiffies(rd_timeout) );
+		if (!rd_tm) {
+			printk("ocf_crypt_convert: rd work was not finished in %ld msecs, %d pending %d completed.\n",
+					rd_timeout, ocf_rd_priv->dm_ocf_rd_pending, ocf_rd_priv->dm_ocf_rd_completed);
+		}
+		kfree(ocf_rd_priv);
+	}
+
+	return r;
+}
+#endif /*CONFIG_OCF_DM_CRYPT*/
+
 static int crypt_convert_block(struct crypt_config *cc,
 			       struct convert_context *ctx,
 			       struct ablkcipher_request *req)
@@ -749,15 +1040,19 @@
 			    struct convert_context *ctx)
 {
 	struct crypt_cpu *this_cc = this_crypt_config(cc);
+#if !defined(CONFIG_OCF_DM_CRYPT)
 	unsigned key_index = ctx->sector & (cc->tfms_count - 1);
+#endif
 
 	if (!this_cc->req)
 		this_cc->req = mempool_alloc(cc->req_pool, GFP_NOIO);
 
+#if !defined(CONFIG_OCF_DM_CRYPT)
 	ablkcipher_request_set_tfm(this_cc->req, this_cc->tfms[key_index]);
 	ablkcipher_request_set_callback(this_cc->req,
 	    CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
 	    kcryptd_async_done, dmreq_of_req(cc, this_cc->req));
+#endif
 }
 
 /*
@@ -1102,10 +1397,18 @@
 		sector += bio_sectors(clone);
 
 		crypt_inc_pending(io);
+#if defined(CONFIG_OCF_DM_CRYPT)
+		r = ocf_crypt_convert(cc, &io->ctx, io);
 
+		if(r < 0) {
+			printk("\n%s() ocf_crypt_convert failed\n",__FUNCTION__);
+			io->error = -EIO;
+		}
+#else
 		r = crypt_convert(cc, &io->ctx);
 		if (r < 0)
 			io->error = -EIO;
+#endif
 
 		crypt_finished = atomic_dec_and_test(&io->ctx.pending);
 
@@ -1177,9 +1480,17 @@
 	crypt_convert_init(cc, &io->ctx, io->base_bio, io->base_bio,
 			   io->sector);
 
+#if defined(CONFIG_OCF_DM_CRYPT)
+	r = ocf_crypt_convert(cc, &io->ctx, io);
+	if(r < 0) {
+		printk("\n%s() ocf_crypt_convert failed\n",__FUNCTION__);
+		io->error = -EIO;
+	}
+#else
 	r = crypt_convert(cc, &io->ctx);
 	if (r < 0)
 		io->error = -EIO;
+#endif
 
 	if (atomic_dec_and_test(&io->ctx.pending))
 		kcryptd_crypt_read_done(io);
@@ -1341,7 +1652,11 @@
 
 	set_bit(DM_CRYPT_KEY_VALID, &cc->flags);
 
+#if !defined(CONFIG_OCF_DM_CRYPT)
 	r = crypt_setkey_allcpus(cc);
+#else
+	r = 0;
+#endif
 
 out:
 	/* Hex key string not needed after here, so wipe it. */
@@ -1355,7 +1670,11 @@
 	clear_bit(DM_CRYPT_KEY_VALID, &cc->flags);
 	memset(&cc->key, 0, cc->key_size * sizeof(u8));
 
+#if !defined(CONFIG_OCF_DM_CRYPT)
 	return crypt_setkey_allcpus(cc);
+#else
+	return 0;
+#endif
 }
 
 static void crypt_dtr(struct dm_target *ti)
@@ -1379,8 +1698,14 @@
 			cpu_cc = per_cpu_ptr(cc->cpu, cpu);
 			if (cpu_cc->req)
 				mempool_free(cpu_cc->req, cc->req_pool);
+#if !defined(CONFIG_OCF_DM_CRYPT)
 			crypt_free_tfms(cc, cpu);
+#endif
 		}
+#if defined(CONFIG_OCF_DM_CRYPT)
+	if(cc->ocf_cryptoid)
+		crypto_freesession(cc->ocf_cryptoid);
+#endif
 
 	if (cc->bs)
 		bioset_free(cc->bs);
@@ -1414,7 +1739,11 @@
 	struct crypt_config *cc = ti->private;
 	char *tmp, *cipher, *chainmode, *ivmode, *ivopts, *keycount;
 	char *cipher_api = NULL;
+#if !defined(CONFIG_OCF_DM_CRYPT)
 	int cpu, ret = -EINVAL;
+#else
+	int ret = -EINVAL;
+#endif
 
 	/* Convert to crypto api definition? */
 	if (strchr(cipher_in, '(')) {
@@ -1487,6 +1816,40 @@
 		goto bad_mem;
 	}
 
+	/* Initialize and set key */
+	ret = crypt_set_key(cc, key);
+	if (ret < 0) {
+		ti->error = "Error decoding and setting key";
+		goto bad;
+	}
+
+#if defined(CONFIG_OCF_DM_CRYPT)
+	/* prepare a new OCF session */
+	memset(&cc->cr_dm, 0, sizeof(struct cryptoini));
+
+	if((strcmp(cipher,"aes") == 0) && (strcmp(chainmode, "cbc") == 0))
+		cc->cr_dm.cri_alg  = CRYPTO_AES_CBC;
+	else if((strcmp(cipher,"des") == 0) && (strcmp(chainmode, "cbc") == 0))
+		cc->cr_dm.cri_alg  = CRYPTO_DES_CBC;
+	else if((strcmp(cipher,"des3_ede") == 0) && (strcmp(chainmode, "cbc") == 0))
+		cc->cr_dm.cri_alg  = CRYPTO_3DES_CBC;
+	else {
+		dmprintk("\ncrypt_ctr: using OCF: unknown cipher or bad chain mode\n");
+		ti->error = DM_MSG_PREFIX "using OCF: unknown cipher or bad chain mode";
+		goto bad;
+	}
+
+	//dmprintk("key size is %d\n",cc->key_size);
+	cc->cr_dm.cri_klen = cc->key_size*8;
+	cc->cr_dm.cri_key  = cc->key;
+	cc->cr_dm.cri_next = NULL;
+
+	if(crypto_newsession(&cc->ocf_cryptoid, &cc->cr_dm, CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE)){
+		dmprintk("crypt_ctr: crypto_newsession failed\n");
+		ti->error = DM_MSG_PREFIX "crypto_newsession failed";
+		goto bad;
+	}
+#else
 	/* Allocate cipher */
 	for_each_possible_cpu(cpu) {
 		ret = crypt_alloc_tfms(cc, cpu, cipher_api);
@@ -1496,13 +1859,6 @@
 		}
 	}
 
-	/* Initialize and set key */
-	ret = crypt_set_key(cc, key);
-	if (ret < 0) {
-		ti->error = "Error decoding and setting key";
-		goto bad;
-	}
-
 	/* Initialize IV */
 	cc->iv_size = crypto_ablkcipher_ivsize(any_tfm(cc));
 	if (cc->iv_size)
@@ -1513,6 +1869,7 @@
 		DMWARN("Selected cipher does not support IVs");
 		ivmode = NULL;
 	}
+#endif/*CONFIG_OCF_DM_CRYPT*/
 
 	/* Choose ivmode, see comments at iv code. */
 	if (ivmode == NULL)
@@ -1523,8 +1880,10 @@
 		cc->iv_gen_ops = &crypt_iv_plain64_ops;
 	else if (strcmp(ivmode, "essiv") == 0)
 		cc->iv_gen_ops = &crypt_iv_essiv_ops;
+#if !defined(CONFIG_OCF_DM_CRYPT)
 	else if (strcmp(ivmode, "benbi") == 0)
 		cc->iv_gen_ops = &crypt_iv_benbi_ops;
+#endif
 	else if (strcmp(ivmode, "null") == 0)
 		cc->iv_gen_ops = &crypt_iv_null_ops;
 	else if (strcmp(ivmode, "lmk") == 0) {
@@ -1541,6 +1900,17 @@
 		goto bad;
 	}
 
+#if defined(CONFIG_OCF_DM_CRYPT)
+	switch (cc->cr_dm.cri_alg) {
+		case CRYPTO_AES_CBC:
+			cc->iv_size = 16;
+			break;
+		default:
+			cc->iv_size = 8;
+			break;
+	}
+#endif
+
 	/* Allocate IV */
 	if (cc->iv_gen_ops && cc->iv_gen_ops->ctr) {
 		ret = cc->iv_gen_ops->ctr(cc, ti, ivopts);
@@ -1550,6 +1920,7 @@
 		}
 	}
 
+#if !defined(CONFIG_OCF_DM_CRYPT)
 	/* Initialize IV (set keys for ESSIV etc) */
 	if (cc->iv_gen_ops && cc->iv_gen_ops->init) {
 		ret = cc->iv_gen_ops->init(cc);
@@ -1558,6 +1929,7 @@
 			goto bad;
 		}
 	}
+#endif
 
 	ret = 0;
 bad:
@@ -1613,10 +1985,12 @@
 	}
 
 	cc->dmreq_start = sizeof(struct ablkcipher_request);
+#if !defined(CONFIG_OCF_DM_CRYPT)
 	cc->dmreq_start += crypto_ablkcipher_reqsize(any_tfm(cc));
 	cc->dmreq_start = ALIGN(cc->dmreq_start, crypto_tfm_ctx_alignment());
 	cc->dmreq_start += crypto_ablkcipher_alignmask(any_tfm(cc)) &
 			   ~(crypto_tfm_ctx_alignment() - 1);
+#endif
 
 	cc->req_pool = mempool_create_kmalloc_pool(MIN_IOS, cc->dmreq_start +
 			sizeof(struct dm_crypt_request) + cc->iv_size);
@@ -1895,6 +2269,10 @@
 		kmem_cache_destroy(_crypt_io_pool);
 	}
 
+#ifdef CONFIG_OCF_DM_CRYPT
+	printk("dm_crypt using the OCF for crypto acceleration.\n");
+#endif
+
 	return r;
 }
 
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 2d97bf0..09846f0 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -571,12 +571,30 @@
 			best_good_sectors = sectors;
 
 		dist = abs(this_sector - conf->mirrors[disk].head_position);
+		/* Prefer idle disk, but still choose best if more than one idle disk:
+		 * We add an artifical, arbitrary (Max/2) weight to busy disks to favor 
+		 * idle disks. If the distance is greater than Max/2, then we make it
+		 * the maximum value. We may not choose the smaller distance if all disks
+		 * fall into that situation, but since all disks will have long seek times
+		 * we don't really care.
+		 * We may end up choosing a busy disk if idle disks have a very high 
+		 * distance, but this may actually be preferable to minimize seek times.
+		 * If dist == 0, we choose that disk even if it busy to again minimize seek
+		 * times, as it is likely a sequential read with a single pending request.
+		 * TODO: use per disk next_seq_sect to better detect sequential reads?
+		 */
+		if (dist == 0) {
+			best_disk = disk;
+			break;
+		}
+		if (atomic_read(&rdev->nr_pending) != 0) {
+			if (dist < MaxSector/2)
+				dist += MaxSector / 2; 
+			else dist = MaxSector - 1;
+		}
 		if (choose_first
 		    /* Don't change to another disk for sequential reads */
-		    || conf->next_seq_sect == this_sector
-		    || dist == 0
-		    /* If device is idle, use it */
-		    || atomic_read(&rdev->nr_pending) == 0) {
+		    || conf->next_seq_sect == this_sector) {
 			best_disk = disk;
 			break;
 		}
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 26ef63a..2316102 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -485,6 +485,28 @@
 static void
 raid5_end_write_request(struct bio *bi, int error);
 
+#ifdef CONFIG_RAID_ZERO_COPY
+static inline void r5dev_switch_page(struct r5dev *dev, struct page *page)
+{
+	BUG_ON(dev->page_save != NULL);
+	BUG_ON(dev->page != bio_iovec_idx(&dev->req, 0)->bv_page);
+	/* The pointer must be restored whenever the LOCKED gets cleared. */
+	dev->page_save = dev->page;
+	dev->page = bio_iovec_idx(&dev->req, 0)->bv_page = page;
+	kmap(dev->page); /* for sync_xor on 32-bit systems */
+}
+
+static inline void r5dev_restore_page(struct r5dev *dev)
+{
+	BUG_ON(dev->page_save == NULL);
+	BUG_ON(dev->page != bio_iovec_idx(&dev->req, 0)->bv_page);
+	BUG_ON(dev->page == dev->page_save);
+	kunmap(dev->page_save);
+	dev->page = bio_iovec_idx(&dev->req, 0)->bv_page = dev->page_save;
+	dev->page_save = NULL;
+}
+#endif
+
 static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
 {
 	struct r5conf *conf = sh->raid_conf;
@@ -585,6 +607,11 @@
 				set_bit(STRIPE_DEGRADED, &sh->state);
 			pr_debug("skip op %ld on disc %d for sector %llu\n",
 				bi->bi_rw, i, (unsigned long long)sh->sector);
+#ifdef CONFIG_RAID_ZERO_COPY
+                       if (test_bit(R5_DirectAccess, &sh->dev[i].flags)) {
+			       r5dev_restore_page(&sh->dev[i]);
+                       }
+#endif
 			clear_bit(R5_LOCKED, &sh->dev[i].flags);
 			set_bit(STRIPE_HANDLE, &sh->state);
 		}
@@ -781,9 +808,23 @@
 		__func__, (unsigned long long)sh->sector, target);
 	BUG_ON(!test_bit(R5_Wantcompute, &tgt->flags));
 
+#if 0
 	for (i = disks; i--; )
 		if (i != target)
 			xor_srcs[count++] = sh->dev[i].page;
+#else
+       for (i = disks; i--; ) {
+               struct r5dev *dev = &sh->dev[i];
+               struct page *pg = dev->page;
+               if (i != target) {
+#ifdef CONFIG_RAID_ZERO_COPY
+                       if (test_bit(R5_DirectAccess, &dev->flags))
+                               pg = dev->req.bi_io_vec[0].bv_page;
+#endif
+                       xor_srcs[count++] = pg;
+               }
+       }
+#endif
 
 	atomic_inc(&sh->count);
 
@@ -1020,8 +1061,19 @@
 	for (i = disks; i--; ) {
 		struct r5dev *dev = &sh->dev[i];
 		/* Only process blocks that are known to be uptodate */
+#if 0
 		if (test_bit(R5_Wantdrain, &dev->flags))
 			xor_srcs[count++] = dev->page;
+#else
+               if (test_bit(R5_Wantdrain, &dev->flags)) {
+                       struct page *pg = dev->page;
+#ifdef CONFIG_RAID_ZERO_COPY
+                       if (test_bit(R5_DirectAccess, &dev->flags))
+                               pg = dev->req.bi_io_vec[0].bv_page;
+#endif
+                       xor_srcs[count++] = pg;
+               }
+#endif
 	}
 
 	init_async_submit(&submit, ASYNC_TX_FENCE|ASYNC_TX_XOR_DROP_DST, tx,
@@ -1031,12 +1083,55 @@
 	return tx;
 }
 
+#ifdef CONFIG_RAID_ZERO_COPY
+static struct page *raid5_zero_copy(struct bio *bio, sector_t sector)
+{
+       sector_t bi_sector = bio->bi_sector;
+       struct page *page = NULL;
+       struct bio_vec *bv;
+       int i;
+
+       bio_for_each_segment(bv, bio, i) {
+               if (sector == bi_sector)
+                       page = bio_iovec_idx(bio, i)->bv_page;
+
+               bi_sector += bio_iovec_idx(bio, i)->bv_len >> 9;
+               if (bi_sector >= sector + STRIPE_SECTORS) {
+                       /* check if the stripe is covered by one page */
+                       if (page == bio_iovec_idx(bio, i)->bv_page) {
+                               SetPageConstant(page);
+                               return page;
+                       }
+                       return NULL;
+               }
+       }
+       return NULL;
+}
+#endif
+
+
+
 static struct dma_async_tx_descriptor *
 ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx)
 {
 	int disks = sh->disks;
 	int i;
 
+#ifdef CONFIG_RAID_ZERO_COPY
+//This is the workaround for the data corruption which happens in the read-modify-write writes scenario
+        int write_count = 0;
+        int do_zero_copy = 0;
+
+        for (i = disks; i--; )
+        {
+                struct r5dev *dev = &sh->dev[i];
+                if(dev->towrite)
+                        write_count++;
+        }
+        if(write_count == (disks-1))
+                do_zero_copy = 1;
+#endif
+
 	pr_debug("%s: stripe %llu\n", __func__,
 		(unsigned long long)sh->sector);
 
@@ -1052,10 +1147,30 @@
 			dev->towrite = NULL;
 			BUG_ON(dev->written);
 			wbi = dev->written = chosen;
-			spin_unlock_irq(&sh->raid_conf->device_lock);
+#ifdef CONFIG_RAID_ZERO_COPY
+                       set_bit(R5_LOCKED, &dev->flags);
+                       BUG_ON(test_bit(R5_DirectAccess, &dev->flags));
+		       spin_unlock_irq(&sh->raid_conf->device_lock);
+                       if (!wbi->bi_next && test_bit(R5_OVERWRITE, &dev->flags)
+                                       && test_bit(R5_Insync, &dev->flags) && do_zero_copy) {
+                               struct page *pg = raid5_zero_copy(wbi,
+                                                               dev->sector);
+                               if (pg) {
+                                       set_bit(R5_DirectAccess, &dev->flags);
+				       r5dev_switch_page(dev, pg);
+                                       clear_bit(R5_UPTODATE, &dev->flags);
+                                       clear_bit(R5_OVERWRITE, &dev->flags);
+				       continue;
+			       }
+		       }
 
-			while (wbi && wbi->bi_sector <
-				dev->sector + STRIPE_SECTORS) {
+		       clear_bit(R5_OVERWRITE, &dev->flags);
+		       set_bit(R5_UPTODATE, &dev->flags);
+#else
+		       spin_unlock_irq(&sh->raid_conf->device_lock);
+#endif
+		       while (wbi && wbi->bi_sector <
+				       dev->sector + STRIPE_SECTORS) {
 				if (wbi->bi_rw & REQ_FUA)
 					set_bit(R5_WantFUA, &dev->flags);
 				tx = async_copy_data(1, wbi, dev->page,
@@ -1086,13 +1201,17 @@
 	for (i = disks; i--; ) {
 		struct r5dev *dev = &sh->dev[i];
 
+#ifdef CONFIG_RAID_ZERO_COPY
+		if ((dev->written && !test_bit(R5_DirectAccess, &dev->flags)) || i == pd_idx || i == qd_idx) {
+#else
 		if (dev->written || i == pd_idx || i == qd_idx) {
+#endif
 			set_bit(R5_UPTODATE, &dev->flags);
 			if (fua)
 				set_bit(R5_WantFUA, &dev->flags);
 		}
 	}
-
+		
 	if (sh->reconstruct_state == reconstruct_state_drain_run)
 		sh->reconstruct_state = reconstruct_state_drain_result;
 	else if (sh->reconstruct_state == reconstruct_state_prexor_drain_run)
@@ -1129,15 +1248,39 @@
 		xor_dest = xor_srcs[count++] = sh->dev[pd_idx].page;
 		for (i = disks; i--; ) {
 			struct r5dev *dev = &sh->dev[i];
+#if 0
 			if (dev->written)
 				xor_srcs[count++] = dev->page;
+#else
+                       struct page *pg = dev->page;
+
+                       if (dev->written) {
+#ifdef CONFIG_RAID_ZERO_COPY
+                               if (test_bit(R5_DirectAccess, &dev->flags))
+                                       pg = dev->req.bi_io_vec[0].bv_page;
+#endif
+                               xor_srcs[count++] = pg;
+                       }
+#endif
 		}
 	} else {
 		xor_dest = sh->dev[pd_idx].page;
 		for (i = disks; i--; ) {
 			struct r5dev *dev = &sh->dev[i];
+#if 0
 			if (i != pd_idx)
 				xor_srcs[count++] = dev->page;
+#else
+                       struct page *pg = dev->page;
+
+                       if (i != pd_idx) {
+#ifdef CONFIG_RAID_ZERO_COPY
+                               if (test_bit(R5_DirectAccess, &dev->flags))
+                                       pg = dev->req.bi_io_vec[0].bv_page;
+#endif
+                               xor_srcs[count++] = pg;
+                       }
+#endif
 		}
 	}
 
@@ -1700,6 +1843,12 @@
 		set_bit(R5_MadeGood, &sh->dev[i].flags);
 
 	rdev_dec_pending(conf->disks[i].rdev, conf->mddev);
+
+#ifdef CONFIG_RAID_ZERO_COPY
+       if (test_bit(R5_DirectAccess, &sh->dev[i].flags)) {
+	       r5dev_restore_page(&sh->dev[i]);
+       }
+#endif
 	
 	clear_bit(R5_LOCKED, &sh->dev[i].flags);
 	set_bit(STRIPE_HANDLE, &sh->state);
@@ -2520,7 +2669,11 @@
 		if (sh->dev[i].written) {
 			dev = &sh->dev[i];
 			if (!test_bit(R5_LOCKED, &dev->flags) &&
-				test_bit(R5_UPTODATE, &dev->flags)) {
+				(test_bit(R5_UPTODATE, &dev->flags)
+#ifdef CONFIG_RAID_ZERO_COPY
+                               || test_bit(R5_DirectAccess, &dev->flags)
+#endif
+				)) {
 				/* We can return any write requests */
 				struct bio *wbi, *wbi2;
 				int bitmap_end = 0;
@@ -2528,6 +2681,9 @@
 				spin_lock_irq(&conf->device_lock);
 				wbi = dev->written;
 				dev->written = NULL;
+#ifdef CONFIG_RAID_ZERO_COPY
+                               clear_bit(R5_DirectAccess, &dev->flags);
+#endif
 				while (wbi && wbi->bi_sector <
 					dev->sector + STRIPE_SECTORS) {
 					wbi2 = r5_next_bio(wbi, dev->sector);
@@ -3227,7 +3383,11 @@
 		/* All the 'written' buffers and the parity block are ready to
 		 * be written back to disk
 		 */
+#ifdef CONFIG_RAID_ZERO_COPY
+		BUG_ON(!test_bit(R5_UPTODATE, &sh->dev[sh->pd_idx].flags) && !test_bit(R5_DirectAccess, &sh->dev[sh->pd_idx].flags));
+#else
 		BUG_ON(!test_bit(R5_UPTODATE, &sh->dev[sh->pd_idx].flags));
+#endif
 		BUG_ON(sh->qd_idx >= 0 &&
 		       !test_bit(R5_UPTODATE, &sh->dev[sh->qd_idx].flags));
 		for (i = disks; i--; ) {
diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h
index e10c553..9a1c2c4 100644
--- a/drivers/md/raid5.h
+++ b/drivers/md/raid5.h
@@ -208,6 +208,7 @@
 	atomic_t		count;	      /* nr of active thread/requests */
 	int			bm_seq;	/* sequence number for bitmap flushes */
 	int			disks;		/* disks in stripe */
+	int 		zero_copy_count;
 	enum check_states	check_state;
 	enum reconstruct_states reconstruct_state;
 	/**
@@ -228,10 +229,11 @@
 	struct r5dev {
 		struct bio	req;
 		struct bio_vec	vec;
-		struct page	*page;
+		struct page	*page, *page_save;;
 		struct bio	*toread, *read, *towrite, *written;
 		sector_t	sector;			/* sector of this page */
 		unsigned long	flags;
+		dma_addr_t	pg_dma;
 	} dev[1]; /* allocated with extra space depending of RAID geometry */
 };
 
@@ -275,6 +277,14 @@
 #define	R5_WantFUA	14	/* Write should be FUA */
 #define	R5_WriteError	15	/* got a write error - need to record it */
 #define	R5_MadeGood	16	/* A bad block has been fixed by writing to it*/
+
+#ifdef CONFIG_RAID_ZERO_COPY
+#define R5_DirectAccess 17 /* access cached pages directly instead of
+                                       * sh pages */
+#define R5_DirectAccessLock 18
+#endif
+
+
 /*
  * Write method
  */
@@ -306,6 +316,7 @@
 	STRIPE_BIOFILL_RUN,
 	STRIPE_COMPUTE_RUN,
 	STRIPE_OPS_REQ_PENDING,
+	STRIPE_ZERO_COPY_OPS,
 };
 
 /*
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index 283d887..b6d7e9a 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -98,7 +98,7 @@
 config M25PXX_USE_FAST_READ
 	bool "Use FAST_READ OPCode allowing SPI CLK <= 50MHz"
 	depends on MTD_M25P80
-	default y
+	default n
 	help
 	  This option enables FAST_READ access supported by ST M25Pxx.
 
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 9f9982f..0506d27 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -35,6 +35,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/flash.h>
 
+
 /* Flash opcodes. */
 #define	OPCODE_WREN		0x06	/* Write enable */
 #define	OPCODE_RDSR		0x05	/* Read status register */
@@ -100,6 +101,54 @@
 	return container_of(mtd, struct m25p, mtd);
 }
 
+
+int m25p80_write_then_read(struct spi_device *spi,
+		const void *txbuf, unsigned n_tx,
+		void *rxbuf, unsigned n_rx)
+{
+	static DEFINE_MUTEX(m25p80_lock);
+	int			status;
+	struct spi_message	message;
+	struct spi_transfer	x[2];
+	u8			*local_buf;
+	u_char rx_data[8];
+	int len_to_tx = 0;
+	int len_tx_total = 0;
+	int len_tx_done = 0;
+
+	/* Use preallocated DMA-safe buffer.  We can't avoid copying here,
+	 * (as a pure convenience thing), but we can keep heap costs
+	 * out of the hot path ...
+	 */
+	if ((n_tx + n_rx) > 8)
+	{
+		printk(KERN_ERR "##### %s: size greater than 8 #########\n",__func__);
+		return -EINVAL;
+	}
+
+	spi_message_init(&message);
+	memset(x, 0, sizeof x);
+
+	len_to_tx = n_tx + n_rx;
+
+	x[0].len = len_to_tx;
+	x[0].tx_buf = txbuf;
+	x[0].rx_buf = &rx_data[0];
+
+	spi_message_add_tail(&x[0], &message);
+
+	mutex_lock(&m25p80_lock);
+
+	/* do the i/o */
+	status = spi_sync(spi, &message);
+	if (status == 0)
+		memcpy(rxbuf, rx_data + n_tx, n_rx);
+
+	mutex_unlock(&m25p80_lock);
+
+	return status;
+}
+
 /****************************************************************************/
 
 /*
@@ -117,7 +166,7 @@
 	u8 code = OPCODE_RDSR;
 	u8 val;
 
-	retval = spi_write_then_read(flash->spi, &code, 1, &val, 1);
+	retval = m25p80_write_then_read(flash->spi, &code, 1, &val, 1);
 
 	if (retval < 0) {
 		dev_err(&flash->spi->dev, "error %d reading SR\n",
@@ -148,7 +197,7 @@
 {
 	u8	code = OPCODE_WREN;
 
-	return spi_write_then_read(flash->spi, &code, 1, NULL, 0);
+	return m25p80_write_then_read(flash->spi, &code, 1, NULL, 0);
 }
 
 /*
@@ -158,7 +207,7 @@
 {
 	u8	code = OPCODE_WRDI;
 
-	return spi_write_then_read(flash->spi, &code, 1, NULL, 0);
+	return m25p80_write_then_read(flash->spi, &code, 1, NULL, 0);
 }
 
 /*
@@ -249,8 +298,8 @@
  */
 static int erase_sector(struct m25p *flash, u32 offset)
 {
-	pr_debug("%s: %s %dKiB at 0x%08x\n", dev_name(&flash->spi->dev),
-			__func__, flash->mtd.erasesize / 1024, offset);
+	pr_debug("%s: %s %dKiB at 0x%08x cmdsz %d\n", dev_name(&flash->spi->dev),
+			__func__, flash->mtd.erasesize / 1024, offset, m25p_cmdsz(flash));
 
 	/* Wait until finished previous write command. */
 	if (wait_till_ready(flash))
@@ -339,6 +388,7 @@
  * Read an address range from the flash chip.  The address range
  * may be any size provided it is within the physical boundaries.
  */
+#if 0
 static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
 	size_t *retlen, u_char *buf)
 {
@@ -371,6 +421,8 @@
 	t[1].len = len;
 	spi_message_add_tail(&t[1], &m);
 
+	pr_debug("%s: t[0].len 0x%x t[1].len 0x%x\n",__func__, t[0].len, t[1].len);
+
 	/* Byte count starts at zero. */
 	*retlen = 0;
 
@@ -400,14 +452,95 @@
 
 	return 0;
 }
+#endif
+
+static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
+	size_t *retlen, u_char *buf)
+{
+	struct m25p *flash = mtd_to_m25p(mtd);
+	struct spi_transfer t[2];
+	struct spi_message m;
+	int len_to_tx = 0;
+	int len_tx_total = 0;
+	int len_tx_done = 0;
+	int i;
+	u_char rx_data[8];
+	int cmd_size = m25p_cmdsz(flash);
+	int max_data_len = 8 - m25p_cmdsz(flash);
+
+	pr_debug("%s: %s from 0x%08x,len %zd\n", dev_name(&flash->spi->dev),
+			__func__, (u32)from, len);
+
+	/* sanity checks */
+	if (!len)
+		return 0;
+
+	if (from + len > flash->mtd.size)
+		return -EINVAL;
+
+	while(len_tx_done < len)
+	{
+
+		spi_message_init(&m);
+		memset(t, 0, (sizeof t));
+
+		if((len - len_tx_done) < max_data_len)
+			len_to_tx = len - len_tx_done;
+		else
+			len_to_tx = max_data_len;
+		/* NOTE:
+		 * OPCODE_FAST_READ (if available) is faster.
+		 * Should add 1 byte DUMMY_BYTE.
+		 */
+		t[0].tx_buf = flash->command;
+		t[0].rx_buf = &rx_data[0] ;
+		t[0].len = cmd_size + len_to_tx;
+		spi_message_add_tail(&t[0], &m);
+
+
+		/* Byte count starts at zero. */
+		*retlen = 0;
+
+		mutex_lock(&flash->lock);
+
+		/* Wait till previous write/erase is done. */
+		if (wait_till_ready(flash)) {
+			/* REVISIT status return?? */
+			mutex_unlock(&flash->lock);
+			return 1;
+		}
+
+		/* FIXME switch to OPCODE_FAST_READ.  It's required for higher
+		 * clocks; and at this writing, every chip this driver handles
+		 * supports that opcode.
+		 */
+
+		/* Set up the write data buffer. */
+		flash->command[0] = OPCODE_READ;
+		m25p_addr2cmd(flash, from + len_tx_done, flash->command);
+
+		spi_sync(flash->spi, &m);
+
+		memcpy(buf + len_tx_done, &rx_data[cmd_size], len_to_tx);
+
+		len_tx_done += len_to_tx;//valid data which will be read out of 8 bytes
+
+		mutex_unlock(&flash->lock);
+	}
+
+	*retlen = len_tx_done;
+
+	return 0;
+}
 
 /*
  * Write an address range to the flash chip.  Data must be written in
  * FLASH_PAGESIZE chunks.  The address range may be any size provided
  * it is within the physical boundaries.
  */
+#if 0
 static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
-	size_t *retlen, const u_char *buf)
+		size_t *retlen, const u_char *buf)
 {
 	struct m25p *flash = mtd_to_m25p(mtd);
 	u32 page_offset, page_size;
@@ -496,6 +629,78 @@
 
 	return 0;
 }
+#endif
+
+static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
+		size_t *retlen, const u_char *buf)
+{
+	struct m25p *flash = mtd_to_m25p(mtd);
+	u32 page_offset, page_size;
+	struct spi_transfer t[2];
+	struct spi_message m;
+	u_char tx_buf[8];
+	int len_to_tx = 0;
+	int len_tx_total = 0;
+	int len_tx_done = 0;
+	int cmd_size = m25p_cmdsz(flash);
+	int max_data_len = 8 - m25p_cmdsz(flash);
+
+	pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
+			__func__, (u32)to, len);
+
+	*retlen = 0;
+
+	/* sanity checks */
+	if (!len)
+		return(0);
+
+	if (to + len > flash->mtd.size)
+		return -EINVAL;
+
+	mutex_lock(&flash->lock);
+
+	while(len_tx_done < len)
+	{
+
+		spi_message_init(&m);
+		memset(t, 0, (sizeof t));
+
+		if((len - len_tx_done) < max_data_len)
+			len_to_tx = len - len_tx_done;
+		else
+			len_to_tx = max_data_len;
+
+		/* Set up the opcode in the write buffer. */
+		flash->command[0] = OPCODE_PP;
+		m25p_addr2cmd(flash, to + len_tx_done, flash->command);
+		memcpy(&tx_buf[0], flash->command, cmd_size);
+		memcpy(&tx_buf[cmd_size], buf + len_tx_done, len_to_tx);
+
+		t[0].tx_buf = &tx_buf[0];
+		t[0].len = cmd_size + len_to_tx;
+
+		spi_message_add_tail(&t[0], &m);
+
+		/* Wait until finished previous write command. */
+		if (wait_till_ready(flash)) {
+			mutex_unlock(&flash->lock);
+			return 1;
+		}
+
+		write_enable(flash);
+
+		spi_sync(flash->spi, &m);
+
+		len_tx_done += len_to_tx;//valid data which sent out of 8 bytes
+	}
+
+	*retlen = len_tx_done;
+
+	mutex_unlock(&flash->lock);
+
+	return 0;
+}
+
 
 static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
 		size_t *retlen, const u_char *buf)
@@ -783,7 +988,7 @@
 	 * string for after vendor-specific data, after the three bytes
 	 * we use here.  Supporting some chips might require using it.
 	 */
-	tmp = spi_write_then_read(spi, &code, 1, id, 5);
+	tmp = m25p80_write_then_read(spi, &code, 1, id, 5);
 	if (tmp < 0) {
 		pr_debug("%s: error %d reading JEDEC ID\n",
 				dev_name(&spi->dev), tmp);
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index 45dcb8b..cebc106 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -58,3 +58,4 @@
 obj-$(CONFIG_MTD_BCM963XX)	+= bcm963xx-flash.o
 obj-$(CONFIG_MTD_LATCH_ADDR)	+= latch-addr-flash.o
 obj-$(CONFIG_MTD_LANTIQ)	+= lantiq-flash.o
+obj-$(CONFIG_MTD_COMCERTO_NOR)  += comcerto-nor.o
diff --git a/drivers/mtd/maps/comcerto-nor.c b/drivers/mtd/maps/comcerto-nor.c
new file mode 100644
index 0000000..fd097fd
--- /dev/null
+++ b/drivers/mtd/maps/comcerto-nor.c
@@ -0,0 +1,155 @@
+/*
+ *  linux/drivers/mtd/maps/comcerto-nor.c
+ *
+ *  Copyright (C) 2004,2008 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+#include <asm/mach/flash.h>
+
+static const char *part_probes[] = { "cmdlinepart", NULL };
+
+struct comcertoflash_info {
+	struct mtd_info *mtd;
+	struct map_info map;
+	struct resource *res;
+};
+
+static int __devinit comcertoflash_probe(struct platform_device *pdev)
+{
+	int err;
+	struct comcertoflash_info *info;
+	struct flash_platform_data *pdata = pdev->dev.platform_data;
+	struct resource *res = pdev->resource;
+	unsigned long size = res->end - res->start + 1;
+
+
+	info = kmalloc(sizeof(struct comcertoflash_info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	memset(info, 0, sizeof(struct comcertoflash_info));
+
+	if (!request_mem_region(res->start, size, "flash")) {
+		err = -EBUSY;
+		goto out_free_info;
+	}
+
+	info->map.virt = ioremap(res->start, size);
+	if (!info->map.virt) {
+		err = -ENOMEM;
+		goto out_release_mem_region;
+	}
+
+	info->map.name = dev_name(&pdev->dev);
+	info->map.phys = res->start;
+	info->map.size = size;
+	info->map.bankwidth = pdata->width;
+	// info->map.set_vpp  = comcerto_set_vpp;
+
+	simple_map_init(&info->map);
+
+	info->mtd = do_map_probe(pdata->map_name, &info->map);
+	if (!info->mtd) {
+		err = -EIO;
+		goto out_iounmap;
+	}
+	info->mtd->owner = THIS_MODULE;
+
+	platform_set_drvdata(pdev, info);
+
+        err = mtd_device_parse_register(info->mtd, part_probes, pdev->resource->start,
+                        pdata->parts, pdata->nr_parts);
+        if (err) {
+                printk(KERN_ERR "Could not parse partitions\n");
+                
+        }
+
+	return 0;
+
+      out_iounmap:
+	iounmap(info->map.virt);
+      out_release_mem_region:
+	release_mem_region(res->start, size);
+      out_free_info:
+	kfree(info);
+
+	return err;
+}
+
+static int __devexit comcertoflash_remove(struct platform_device *pdev)
+{
+	struct comcertoflash_info *info = platform_get_drvdata(pdev);
+        struct flash_platform_data *plat = pdev->dev.platform_data;
+
+	platform_set_drvdata(pdev, NULL);
+
+        if(!info)
+                return 0;
+
+        if (info->mtd) {
+                mtd_device_unregister(info->mtd);
+                map_destroy(info->mtd);
+        }
+        if (info->map.virt)
+                iounmap(info->map.virt);
+
+        if (info->res) {
+                release_resource(info->res);
+                kfree(info->res);
+        }
+
+        if (plat->exit)
+                plat->exit();
+
+	return 0;
+}
+
+static struct platform_driver comcertoflash_driver = {
+	.probe = comcertoflash_probe,
+	.remove = __devexit_p(comcertoflash_remove),
+	.driver = {
+		   .name = "comcertoflash",
+		   },
+};
+
+static int __init comcertoflash_init(void)
+{
+	return platform_driver_register(&comcertoflash_driver);
+}
+
+static void __exit comcertoflash_exit(void)
+{
+	platform_driver_unregister(&comcertoflash_driver);
+}
+
+module_init(comcertoflash_init);
+module_exit(comcertoflash_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MTD NOR map driver for Mindspeed Comcerto boards");
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index cce7b70..e7a9446d 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -46,6 +46,18 @@
 	  ECC codes. They are used with NAND devices requiring more than 1 bit
 	  of error correction.
 
+config NAND_COMCERTO_ECC_8_HW_BCH
+	bool
+	depends on MTD_NAND_COMCERTO
+	default n
+	prompt "Comcerto ECC-8 syndrome calculation using BCH"
+
+config NAND_COMCERTO_ECC_24_HW_BCH
+	bool
+	depends on MTD_NAND_COMCERTO
+	default y
+	prompt "Comcerto ECC-24 syndrome calculation using BCH"
+
 config MTD_SM_COMMON
 	tristate
 	default n
@@ -537,4 +549,10 @@
 	  Enables support for NAND Flash chips on the ST Microelectronics
 	  Flexible Static Memory Controller (FSMC)
 
+config MTD_NAND_COMCERTO
+        tristate "Comcerto NAND driver"
+	depends on MTD_NAND && (ARCH_COMCERTO)
+	help
+		Comcerto NAND Driver.
+
 endif # MTD_NAND
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 618f4ba..0763907 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -49,5 +49,6 @@
 obj-$(CONFIG_MTD_NAND_RICOH)		+= r852.o
 obj-$(CONFIG_MTD_NAND_JZ4740)		+= jz4740_nand.o
 obj-$(CONFIG_MTD_NAND_GPMI_NAND)	+= gpmi-nand/
+obj-$(CONFIG_MTD_NAND_COMCERTO)		+= comcerto_nand.o
 
 nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/comcerto_nand.c b/drivers/mtd/nand/comcerto_nand.c
new file mode 100644
index 0000000..c23439a
--- /dev/null
+++ b/drivers/mtd/nand/comcerto_nand.c
@@ -0,0 +1,759 @@
+/*
+ *  linux/drivers/mtd/nand/comcerto-nand.c
+ *
+ *  Copyright (C) Mindspeed Technologies, Inc.
+ *
+ * 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.
+ *
+ *  Overview:
+ *   This is a device driver for the NAND flash device found on the
+ *   Comcerto board which utilizes the Toshiba TC58V64AFT part. This is
+ *   a 128Mibit (8MiB x 8 bits) NAND flash device.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <mach/ecc.h>
+
+/*
+ * MTD structure for Comcerto board
+ */
+struct comcerto_nand_info {
+	struct mtd_partition	*parts;
+	struct mtd_info		*mtd;
+};
+
+static void __iomem *ecc_base_addr;
+
+/*
+ * Define partitions for flash device
+ */
+
+/* Partitions coming from command line*/
+static const char *part_probes[] = { "cmdlinepart", NULL };
+
+uint32_t COMCERTO_NAND_ALE = 0x00000200;
+uint32_t COMCERTO_NAND_CLE = 0x00000400;
+
+#ifdef CONFIG_NAND_COMCERTO_ECC_24_HW_BCH
+/*
+ * spare area layout for BCH ECC bytes calculated over 512-Bytes ECC block size
+ */
+static struct nand_ecclayout comcerto_ecc_info_512_bch = {
+	.eccbytes = 42,
+	.eccpos = {0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10,
+		  11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+		  21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+		  31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41},
+	.oobfree = {
+		{.offset = 43, .length = 13}
+	}
+};
+
+/*
+ * spare area layout for BCH ECC bytes calculated over 1024-Bytes ECC block size
+ */
+static struct nand_ecclayout comcerto_ecc_info_1024_bch = {
+	.eccbytes = 42,
+	.eccpos = {0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10,
+		  11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+		  21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+		  31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41},
+	.oobfree = {
+		{.offset = 43, .length = 13}
+	}
+};
+
+#elif CONFIG_NAND_COMCERTO_ECC_8_HW_BCH
+
+/*
+ * spare area layout for BCH ECC bytes calculated over 512-Bytes ECC block size
+ */
+static struct nand_ecclayout comcerto_ecc_info_512_bch = {
+	.eccbytes = 14,
+	.eccpos = {0, 1, 2, 3, 4, 5, 6,
+		   7, 8, 9, 10, 11, 12, 13},
+	.oobfree = {
+		{.offset = 15, .length = 1}
+	}
+};
+
+/*
+ * spare area layout for BCH ECC bytes calculated over 1024-Bytes ECC block size
+ */
+static struct nand_ecclayout comcerto_ecc_info_1024_bch = {
+	.eccbytes = 14,
+	.eccpos = {0, 1, 2, 3, 4, 5, 6,
+		   7, 8, 9, 10, 11, 12, 13},
+	.oobfree = {
+		{.offset = 15, .length = 17}
+	}
+};
+
+#else
+
+/*
+ * spare area layout for Hamming ECC bytes calculated over 512-Bytes ECC block
+ * size
+ */
+static struct nand_ecclayout comcerto_ecc_info_512_hamm = {
+	.eccbytes = 4,
+	.eccpos = {0, 1, 2, 3},
+	.oobfree = {
+		{.offset = 5, .length = 12}
+	}
+};
+
+/*
+ * spare area layout for Hamming ECC bytes calculated over 1024-Bytes ECC block
+ * size
+ */
+static struct nand_ecclayout comcerto_ecc_info_1024_hamm = {
+	.eccbytes = 4,
+	.eccpos = {0, 1, 2, 3},
+	.oobfree = {
+		{.offset = 5, .length = 28}
+	}
+};
+#endif
+
+static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' };
+static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' };
+
+static struct nand_bbt_descr bbt_main_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+		| NAND_BBT_8BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+	.offs = 44,
+	.len = 4,
+	.veroffs = 48,
+	.maxblocks = 8,
+	.pattern = bbt_pattern,
+};
+
+static struct nand_bbt_descr bbt_mirror_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+		| NAND_BBT_8BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+	.offs = 44,
+	.len = 4,
+	.veroffs = 48,
+	.maxblocks = 8,
+	.pattern = mirror_pattern,
+};
+
+static uint8_t scan_ff_pattern[] = { 0xff };
+
+#ifdef CONFIG_NAND_COMCERTO_ECC_24_HW_BCH
+static struct nand_bbt_descr c2000_badblock_pattern = {
+	.offs = 42,
+	.len = 1,
+	.pattern = scan_ff_pattern
+};
+#elif CONFIG_NAND_COMCERTO_ECC_8_HW_BCH
+static struct nand_bbt_descr c2000_badblock_pattern = {
+	.offs = 14,
+	.len = 1,
+	.pattern = scan_ff_pattern
+};
+#endif
+
+/** Disable/Enable shifting of data to parity module
+ *
+ * @param[in] en_dis_shift  Enable or disable shift to parity module.
+ *
+ */
+static void comcerto_ecc_shift(uint8_t en_dis_shift)
+{
+	writel_relaxed(en_dis_shift, ecc_base_addr + ECC_SHIFT_EN_CFG);
+}
+
+/** Initializes h/w ECC with proper configuration values.
+ *
+ * @param[in] mtd	MTD device structure
+ * @param[in] mode	Select between BCH and Hamming
+ *
+ */
+static void comcerto_enable_hw_ecc(struct mtd_info *mtd, int mode)
+{
+	struct nand_chip *nand_device = (struct nand_chip *)(mtd->priv);
+	uint32_t ecc_gen_cfg_val = 0;
+
+
+	/* CS4 will have the option for ECC calculation */
+	writel_relaxed(ECC_CS4_SEL, ecc_base_addr + ECC_CS_SEL_CFG);
+
+	/* parity calculation for write, syndrome calculation for read.*/
+	(mode == NAND_ECC_WRITE) ? (ecc_gen_cfg_val |= PRTY_CALC) : (ecc_gen_cfg_val &= SYNDROME_CALC);
+
+#if defined (CONFIG_NAND_COMCERTO_ECC_8_HW_BCH) || defined (CONFIG_NAND_COMCERTO_ECC_24_HW_BCH)
+	ecc_gen_cfg_val &= BCH_MODE;
+	ecc_gen_cfg_val = (ecc_gen_cfg_val & ~(ECC_LVL_MASK)) | (ECC_LVL_VAL << ECC_LVL_SHIFT);
+#else
+	ecc_gen_cfg_val |= HAMM_MODE;
+#endif
+
+	ecc_gen_cfg_val = (ecc_gen_cfg_val & ~(BLK_SIZE_MASK)) | nand_device->ecc.size;
+
+	writel_relaxed(ecc_gen_cfg_val, ecc_base_addr + ECC_GEN_CFG);
+	/* Reset parity module and latch configured values */
+	writel_relaxed(ECC_INIT, ecc_base_addr + ECC_INIT_CFG);
+	comcerto_ecc_shift(ECC_SHIFT_ENABLE);
+	return;
+}
+
+/** writes ECC bytes generated by the parity module into the flash
+ *
+ * @param[in] mtd	MTD device structure
+ * @param[in] dat	raw data
+ * @param[in] ecc_code	buffer for ECC
+ *
+ */
+static int comcerto_calculate_ecc(struct mtd_info *mtd,
+				  const uint8_t *dat,
+				  uint8_t *ecc_code)
+{
+	struct nand_chip *nand_device = mtd->priv;
+	uint32_t ecc_bytes = nand_device->ecc.bytes;
+	uint8_t dummy_var = 0xFF;
+	unsigned long timeo = jiffies + 2;
+
+	comcerto_ecc_shift(ECC_SHIFT_DISABLE);
+
+	do {
+		if ((readl_relaxed(ecc_base_addr + ECC_IDLE_STAT)) & ECC_IDLE)
+			break;
+		touch_softlockup_watchdog();
+	} while (time_before(jiffies, timeo));
+
+	comcerto_ecc_shift(ECC_SHIFT_ENABLE);
+
+	writel_relaxed(ECC_PARITY_OUT_EN, ecc_base_addr + ECC_PRTY_OUT_SEL_CFG);
+
+	/* Even though we do a dummy write to NAND flash, actual ECC bytes are
+	 * written to the ECC location in the flash. */
+	for ( ; ecc_bytes; ecc_bytes--)
+		writeb(dummy_var, nand_device->IO_ADDR_W);
+
+	comcerto_ecc_shift(ECC_SHIFT_DISABLE);
+	writel_relaxed(ECC_PARITY_OUT_DISABLE, ecc_base_addr + ECC_PRTY_OUT_SEL_CFG);
+
+	return 0;
+}
+
+/** Checks ECC registers for errors and will correct them, if correctable
+ *
+ * @param[in] mtd	MTD device structure
+ * @param[in] dat	raw data
+ * @param[in] read_ecc  ECC read out from flash
+ * @param[in] calc_ecc	ECC calculated over the raw data
+ *
+ */
+static int comcerto_correct_ecc(struct mtd_info *mtd, uint8_t *dat,
+		uint8_t *read_ecc, uint8_t *calc_ecc)
+{
+#if !defined (CONFIG_NAND_COMCERTO_ECC_8_HW_BCH) && !defined (CONFIG_NAND_COMCERTO_ECC_24_HW_BCH)
+	struct nand_chip *nand_device = mtd->priv;
+#else
+	uint8_t err_count = 0;
+	uint32_t err_corr_data_prev;
+#endif
+	uint32_t err_corr_data;
+	uint16_t mask, index;
+	uint32_t temp_nand_ecc_errors[4];
+	unsigned long timeo = jiffies + 2;
+
+	 /* Wait for syndrome calculation to complete */
+	do {
+		if ((readl_relaxed(ecc_base_addr + ECC_IDLE_STAT)) & ECC_IDLE)
+			break;
+		touch_softlockup_watchdog();
+	} while (time_before(jiffies, timeo));
+
+	 /* If no correction is required */
+	if (likely(!((readl_relaxed(ecc_base_addr + ECC_POLY_STAT)) & ECC_CORR_REQ))) {
+		return 0;
+	}
+ 
+	/* Error found! Correction required */
+#if defined (CONFIG_NAND_COMCERTO_ECC_8_HW_BCH) || defined (CONFIG_NAND_COMCERTO_ECC_24_HW_BCH)
+	/* Initiate correction operation */
+	writel_relaxed(ECC_POLY_START, ecc_base_addr + ECC_POLY_START_CFG);
+
+	udelay(25);
+
+	err_corr_data_prev = 0;
+	/* Read Correction data status register till header is 0x7FD */
+	do {
+		err_corr_data_prev = readl_relaxed(ecc_base_addr + ECC_CORR_DATA_STAT);
+		if ((err_corr_data_prev >> ECC_BCH_INDEX_SHIFT) == 0x87FD)
+			break;
+
+		touch_softlockup_watchdog();
+	} while (time_before(jiffies, timeo));
+
+	udelay(25);
+	err_corr_data = 0x0;
+	/* start reading error locations */
+	while (((err_corr_data >> 16) !=  0x87FE)) {
+		err_corr_data = readl_relaxed(ecc_base_addr + ECC_CORR_DATA_STAT);
+		if ((err_corr_data >> 16) ==  0x87FE)
+			break;
+		if (err_corr_data == err_corr_data_prev)
+			continue;
+		err_corr_data_prev = err_corr_data;
+		index = (err_corr_data >> 16) & 0x7FF;
+		mask = err_corr_data & 0xFFFF;
+		*((uint16_t *)(dat + (index * 2))) ^= mask;
+		while (mask) {
+			if (mask & 1)
+				err_count++;
+			mask >>= 1;
+		}
+	}
+
+	if (!((readl_relaxed(ecc_base_addr + ECC_CORR_DONE_STAT)) & ECC_DONE)) {
+		temp_nand_ecc_errors[0] += 1 ;
+		printk(KERN_WARNING "ECC: uncorrectable error 1 !!!\n");
+		return -1;
+	}
+
+	/* Check if the block has uncorrectable number of errors */
+	if ((readl_relaxed(ecc_base_addr + ECC_CORR_STAT)) & ECC_UNCORR) {
+		printk(KERN_WARNING "ECC: uncorrectable error  2 !!!\n");
+		temp_nand_ecc_errors[1] += 1 ;
+		return -EIO;
+	}
+
+	temp_nand_ecc_errors[3] += err_count;
+
+#else		/* Hamming Mode */
+		if (readl_relaxed(ecc_base_addr + ECC_POLY_STAT) == ECC_UNCORR_ERR_HAMM) {
+			/* 2 or more errors detected and hence cannot
+			be corrected */
+			return -1; /* uncorrectable */
+		} else {  /* 1-bit correctable error */
+			err_corr_data = readl_relaxed(ecc_base_addr + ECC_CORR_DATA_STAT);
+			index = (err_corr_data >> 16) & 0x1FF;
+
+			if (nand_device->options & NAND_BUSWIDTH_16) {
+				mask = 1 << (err_corr_data & 0xF);
+				*((uint16_t *)(dat + index)) ^= mask;
+			} else {
+				mask = 1 << (err_corr_data & 0x7);
+				*(dat + index) ^= mask;
+			}
+			return 1;
+
+		}
+#endif
+	return 0;
+}
+
+/** writes single page to the NAND device along with the ECC bytes
+ *
+ * @param[in] mtd	MTD device structure
+ * @param[in] chip      nand chip info structure
+ * @param[in] buf	data buffer
+ *
+ */
+static void comcerto_nand_write_page_hwecc(struct mtd_info *mtd,
+					struct nand_chip *chip,
+					const uint8_t *buf)
+{
+	int i, eccsize = chip->ecc.size;
+	int eccbytes = chip->ecc.bytes;
+	int eccsteps = chip->ecc.steps;
+	const uint8_t *p = buf;
+	uint8_t *oob = chip->oob_poi;
+
+	/* CS4 will have the option for ECC calculation */
+	writel_relaxed(ECC_CS4_SEL, ecc_base_addr + ECC_CS_SEL_CFG);
+
+	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+
+		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+		chip->write_buf(mtd, p, eccsize);
+
+		chip->ecc.calculate(mtd, p, oob);
+		oob += eccbytes;
+
+		if (chip->ecc.postpad) {
+			chip->write_buf(mtd, oob, chip->ecc.postpad);
+			oob += chip->ecc.postpad;
+		}
+	}
+
+	/* Calculate remaining oob bytes */
+	i = mtd->oobsize - (oob - chip->oob_poi);
+	if (i)
+		chip->write_buf(mtd, oob, i);
+}
+
+/** reads single page from the NAND device and will read ECC bytes from flash. A
+ * function call to comcerto_correct_ecc() will be used to validate the data.
+ *
+ * @param[in] mtd	MTD device structure
+ * @param[in] chip      nand chip info structure
+ * @param[in] buf	data buffer
+ *
+ */
+static int comcerto_nand_read_page_hwecc(struct mtd_info *mtd,
+		struct nand_chip *chip, uint8_t *buf, int page)
+{
+	struct nand_chip *nand_device = mtd->priv;
+	int i, eccsize = nand_device->ecc.size;
+	int eccbytes = nand_device->ecc.bytes;
+	int eccsteps = nand_device->ecc.steps;
+	uint8_t *p = buf;
+	uint8_t *ecc_code = nand_device->buffers->ecccode;
+	uint8_t ecc_bytes = nand_device->ecc.bytes;
+	uint8_t stat;
+	uint8_t *oob = nand_device->oob_poi;
+
+	for (; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+		chip->ecc.hwctl(mtd, NAND_ECC_READ);
+		chip->read_buf(mtd, p, eccsize);
+		chip->read_buf(mtd, ecc_code, ecc_bytes);
+
+		stat = chip->ecc.correct(mtd, p, oob, NULL);
+		if (stat < 0)
+			mtd->ecc_stats.failed++;
+		else
+			mtd->ecc_stats.corrected += stat;
+
+		comcerto_ecc_shift(ECC_SHIFT_DISABLE);
+
+		if (chip->ecc.postpad) {
+			chip->read_buf(mtd, oob, chip->ecc.postpad);
+			oob += chip->ecc.postpad;
+		}
+	}
+	/* Calculate remaining oob bytes */
+	i = mtd->oobsize - (oob - chip->oob_poi);
+	if (i)
+		chip->read_buf(mtd, oob, i);
+
+	return 0;
+}
+
+/*********************************************************************
+ * NAND Hardware functions
+ *
+ *********************************************************************/
+
+/*
+ *	hardware specific access to control-lines
+*/
+void comcerto_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+	struct nand_chip *chip = mtd->priv;
+
+
+	if (ctrl & NAND_CTRL_CHANGE) {
+		if (ctrl & NAND_NCE)
+			comcerto_gpio_set_0(COMCERTO_NAND_CE);
+		else
+			comcerto_gpio_set_1(COMCERTO_NAND_CE);
+	}
+
+	if (cmd == NAND_CMD_NONE)
+		return;
+
+	 if (ctrl & NAND_CLE)
+		 writeb(cmd, chip->IO_ADDR_W + COMCERTO_NAND_CLE);
+	 else if (ctrl & NAND_ALE)
+		writeb(cmd, chip->IO_ADDR_W + COMCERTO_NAND_ALE);
+	 else
+		return;
+
+}
+
+int comcerto_nand_ready(struct mtd_info *mtd)
+{
+	return comcerto_gpio_read(COMCERTO_NAND_BR) ? 1 : 0;
+}
+
+/*********************************************************************
+ * NAND Probe
+ *
+ *********************************************************************/
+static int comcerto_nand_probe(struct platform_device *pdev)
+{
+	struct comcerto_nand_info *info;
+	struct mtd_info *mtd;
+	struct nand_chip *nand_device;
+	int err = 0;
+
+	/* Allocate memory for info structure */
+	info = kmalloc(sizeof(struct comcerto_nand_info), GFP_KERNEL);
+	if (!info) {
+		printk(KERN_ERR
+		       "comcerto nand: unable to allocate info structure\n");
+		err = -ENOMEM;
+		goto out;
+	}
+	memset(info, 0, sizeof(struct comcerto_nand_info));
+
+	/* Allocate memory for MTD device structure */
+	mtd = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+	if (!mtd) {
+		printk(KERN_ERR
+		       "comcerto nand: unable to allocate mtd info structure\n");
+		err = -ENOMEM;
+		goto out_info;
+	}
+	memset(mtd, 0, sizeof(struct mtd_info));
+
+	/* Link the private data with the MTD structure */
+	info->mtd = mtd;
+	mtd->owner = THIS_MODULE;
+
+	/* Allocate pointer to nand_device data */
+	nand_device = kmalloc(sizeof(struct nand_chip), GFP_KERNEL);
+	if (!nand_device) {
+		printk(KERN_ERR
+		       "comcerto nand: unable to allocate nand chip structure\n");
+		err = -ENOMEM;
+		goto out_mtd;
+	}
+	memset(nand_device, 0, sizeof(struct nand_chip));
+
+	/* Link the private data with the MTD structure */
+	mtd->priv = nand_device;
+
+	printk(KERN_INFO "pdev->resource->start = %x, pdev->resource->end = %x\n", pdev->resource->start, pdev->resource->end);
+
+	/*Map physical address of nand into virtual space */
+	nand_device->IO_ADDR_R = ioremap_nocache(pdev->resource->start, pdev->resource->end - pdev->resource->start + 1);
+	if (nand_device->IO_ADDR_R == NULL) {
+		printk(KERN_ERR "comcerto nand: cannot map nand memory\n");
+		err = -EIO;
+		goto out_ior;
+	}
+
+	ecc_base_addr = ioremap(COMCERTO_AXI_EXP_ECC_BASE, 0xFFFF);
+	if (!ecc_base_addr) {
+		printk(KERN_ERR "comcerto nand: cannot map ecc config\n");
+		err = -EIO;
+		goto out_ior;
+	}
+
+	/* This is the same address to read and write */
+	nand_device->IO_ADDR_W = nand_device->IO_ADDR_R;
+
+	printk(KERN_INFO "nand_probe: %s base: 0x%08x \n", pdev->name, (resource_size_t) nand_device->IO_ADDR_R);
+
+	/* Set address of hardware control function */
+	nand_device->cmd_ctrl = comcerto_nand_hwcontrol;
+	nand_device->dev_ready = comcerto_nand_ready;
+
+	/* 20 us command delay time */
+	nand_device->chip_delay = 20;
+
+	nand_device->ecc.mode = NAND_ECC_HW_SYNDROME;
+//	nand_device->ecc.mode = NAND_ECC_SOFT_BCH;
+
+#if defined(CONFIG_C2K_ASIC) && defined(CONFIG_NAND_TYPE_SLC)
+	nand_device->options = NAND_BUSWIDTH_16;
+#else
+	nand_device->options = 0;
+#endif
+
+	/* Scan to find existence of the device */
+	if (nand_scan_ident(mtd, 1, NULL)) {
+		err = -ENXIO;
+		goto out_nand;
+	}
+
+#if 1
+	if (nand_device->ecc.mode == NAND_ECC_HW_SYNDROME) {
+		nand_device->ecc.hwctl = comcerto_enable_hw_ecc;
+		nand_device->ecc.write_page = comcerto_nand_write_page_hwecc;
+		nand_device->ecc.read_page = comcerto_nand_read_page_hwecc;
+		nand_device->ecc.calculate = comcerto_calculate_ecc;
+		nand_device->ecc.correct = comcerto_correct_ecc;
+
+		switch (mtd->writesize) {
+		case 512:
+			nand_device->ecc.size = mtd->writesize;
+#if defined (CONFIG_NAND_COMCERTO_ECC_24_HW_BCH)
+			nand_device->ecc.layout = &comcerto_ecc_info_512_bch;
+			nand_device->ecc.bytes = 42;
+			nand_device->ecc.prepad = 0;
+			nand_device->ecc.postpad = 14;
+#elif defined (CONFIG_NAND_COMCERTO_ECC_8_HW_BCH)
+			nand_device->ecc.layout = &comcerto_ecc_info_512_bch;
+			nand_device->ecc.bytes = 14;
+			nand_device->ecc.prepad = 0;
+			nand_device->ecc.postpad = 2;
+#else
+			nand_device->ecc.layout = &comcerto_ecc_info_512_hamm;
+			nand_device->ecc.bytes = 4;
+			nand_device->ecc.prepad = 0;
+			nand_device->ecc.postpad = 2;
+#endif
+			break;
+		case 1024:
+			nand_device->ecc.size = mtd->writesize;
+#ifdef CONFIG_NAND_COMCERTO_ECC_24_HW_BCH
+			nand_device->ecc.layout = &comcerto_ecc_info_1024_bch;
+			nand_device->ecc.bytes = 42;
+			nand_device->ecc.prepad = 0;
+			nand_device->ecc.postpad = 14;
+#elif CONFIG_NAND_COMCERTO_ECC_8_HW_BCH
+			nand_device->ecc.layout = &comcerto_ecc_info_1024_bch;
+			nand_device->ecc.bytes = 14;
+			nand_device->ecc.prepad = 0;
+			nand_device->ecc.postpad = 18;
+#else
+			nand_device->ecc.layout = &comcerto_ecc_info_1024_hamm;
+			nand_device->ecc.bytes = 4;
+			nand_device->ecc.prepad = 0;
+			nand_device->ecc.postpad = 18;
+#endif
+			break;
+		default:
+			printk(KERN_ERR "Using default values for hw ecc\n");
+			nand_device->ecc.size =  1024;
+#ifdef CONFIG_NAND_COMCERTO_ECC_24_HW_BCH
+			nand_device->ecc.layout = &comcerto_ecc_info_1024_bch;
+			nand_device->ecc.bytes = 42;
+			nand_device->ecc.prepad = 0;
+			nand_device->ecc.postpad = 14;
+#elif CONFIG_NAND_COMCERTO_ECC_8_HW_BCH
+			nand_device->ecc.layout = &comcerto_ecc_info_1024_bch;
+			nand_device->ecc.bytes = 14;
+			nand_device->ecc.prepad = 0;
+			nand_device->ecc.postpad = 18;
+#else
+			nand_device->ecc.layout = &comcerto_ecc_info_1024_hamm;
+			nand_device->ecc.bytes = 4;
+			nand_device->ecc.prepad = 0;
+			nand_device->ecc.postpad = 18;
+#endif
+			break;
+		}
+	nand_device->ecc.steps = mtd->writesize / nand_device->ecc.size;
+	if(nand_device->ecc.steps * nand_device->ecc.size != mtd->writesize) {
+		printk(KERN_ERR "Invalid ecc parameters\n");
+		BUG();
+	}
+	nand_device->ecc.total = nand_device->ecc.steps * nand_device->ecc.bytes;
+
+
+	nand_device->bbt_td = &bbt_main_descr;
+	nand_device->bbt_md = &bbt_mirror_descr;
+	nand_device->badblock_pattern = &c2000_badblock_pattern;
+	nand_device->bbt_options |= NAND_BBT_USE_FLASH;
+
+	} else {
+		nand_device->ecc.mode = NAND_ECC_SOFT;
+	}
+
+#endif
+
+	nand_device->options |= NAND_NO_SUBPAGE_WRITE;
+
+	if(nand_scan_tail(mtd)) {
+		printk(KERN_ERR "nand_scan_tail returned error\n");
+		err = -ENXIO;
+		goto out_ior;
+	}
+
+	/*Name of the mtd device */
+	mtd->name = dev_name(&pdev->dev);
+
+	/* Link the info stucture with platform_device */
+	platform_set_drvdata(pdev, info);
+
+	err = mtd_device_parse_register(mtd, part_probes, NULL, NULL, 4);
+
+	if (err) {
+                printk(KERN_ERR "Could not parse partitions\n");
+		return err;
+	}
+
+
+	goto out;
+
+      out_ior:
+	iounmap(nand_device->IO_ADDR_R);
+	iounmap(ecc_base_addr);
+      out_nand:
+	kfree(nand_device);
+      out_mtd:
+	kfree(mtd);
+      out_info:
+	kfree(info);
+      out:
+	return err;
+}
+
+/*********************************************************************
+ * NAND Remove
+ *
+ *********************************************************************/
+static int comcerto_nand_remove(struct platform_device *pdev)
+{
+	struct comcerto_nand_info *info =
+	    (struct comcerto_nand_info *)platform_get_drvdata(pdev);
+	struct mtd_info *mtd = info->mtd;
+	struct nand_chip *nand_device = (struct nand_chip *)mtd->priv;
+
+	platform_set_drvdata(pdev, NULL);
+
+	/* Release resources, unregister device */
+	nand_release(info->mtd);
+
+	/*Deregister virtual address */
+	iounmap(nand_device->IO_ADDR_R);
+	iounmap(ecc_base_addr);
+
+	kfree(nand_device);
+
+	/* Free the MTD device structure */
+	kfree(mtd);
+
+	kfree(info);
+
+	return 0;
+}
+
+/*********************************************************************
+ * Driver Registration
+ *
+ *********************************************************************/
+
+static struct platform_driver comcerto_nand_driver = {
+	.probe = comcerto_nand_probe,
+	.remove = __devexit_p(comcerto_nand_remove),
+	.driver = {
+		   .name = "comcertonand",
+		   },
+};
+
+int __init comcerto_nand_init(void)
+{
+	return platform_driver_register(&comcerto_nand_driver);
+}
+
+static void __exit comcerto_nand_exit(void)
+{
+	platform_driver_unregister(&comcerto_nand_driver);
+}
+
+module_init(comcerto_nand_init);
+module_exit(comcerto_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on Comcerto board");
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 3ed9c5e..ed4d76d 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -3262,6 +3262,9 @@
 		case 128:
 			chip->ecc.layout = &nand_oob_128;
 			break;
+		case 224:
+			chip->ecc.layout = &nand_oob_128;
+			break;
 		default:
 			pr_warn("No oob scheme defined for oobsize %d\n",
 				   mtd->oobsize);
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index a702443..cd082ad 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -19,6 +19,11 @@
 	tristate "Drivers for Marvell PHYs"
 	---help---
 	  Currently has a driver for the 88E1011S
+
+config ATHEROS_PHY
+	tristate "Drivers for Atheros PHYs"
+	---help---
+	  Currently supports AR8035 and AR8327
 	
 config DAVICOM_PHY
 	tristate "Drivers for Davicom PHYs"
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 2333215..a00faff 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -4,6 +4,7 @@
 
 obj-$(CONFIG_PHYLIB)		+= libphy.o
 obj-$(CONFIG_MARVELL_PHY)	+= marvell.o
+obj-$(CONFIG_ATHEROS_PHY)	+= atheros.o
 obj-$(CONFIG_DAVICOM_PHY)	+= davicom.o
 obj-$(CONFIG_CICADA_PHY)	+= cicada.o
 obj-$(CONFIG_LXT_PHY)		+= lxt.o
diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c
new file mode 100644
index 0000000..ef238ca
--- /dev/null
+++ b/drivers/net/phy/atheros.c
@@ -0,0 +1,185 @@
+/*
+ * Driver for Atheros PHYs
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+/* Atheros PHY registers*/
+#define AR8x_INTR_EN			0x12
+#define AR8x_INTR_STS			0x13
+#define AR8x_DEBUG_PORT_ADDR		0x1D
+#define AR8x_DEBUG_PORT_DATA		0x1E
+
+/* Interrupt mask */
+#define AR8x_INTR_MASK			0xfc03
+
+/* Atheros PHY registers on debug port */
+/* RGMII Rx clock control */
+#define AR8x_DBG_RGMII_RXCLK_CTRL	0x00
+#define AR8x_DBG_RGMII_RXCLK_MASK	0x8000
+
+/*RGMII Tx clock control */
+#define AR8x_DBG_RGMII_TXCLK_CTRL	0x05
+#define AR8x_DBG_RGMII_TXCLK_MASK	0x0100
+
+#define PHY_ID_AR8035			0x004dd072
+#define PHY_ID_AR8033			0x004dd074
+#define PHY_ID_AR8327			0x004dd033
+
+MODULE_DESCRIPTION("Atheros PHY driver");
+MODULE_LICENSE("GPL");
+
+static int ar8x_phy_dbg_read(struct phy_device *phydev, int reg_addr)
+{
+	phy_write(phydev, AR8x_DEBUG_PORT_ADDR, reg_addr);
+	return  phy_read(phydev, AR8x_DEBUG_PORT_DATA);
+}
+
+static void ar8x_phy_dbg_write(struct phy_device *phydev,  int reg_addr, u32 val)
+{
+	phy_write(phydev, AR8x_DEBUG_PORT_ADDR, reg_addr);
+	phy_write(phydev, AR8x_DEBUG_PORT_DATA, val);
+}
+
+int ar8x_add_skew(struct phy_device *phydev)
+{
+	int tmp, err;
+
+	/* Enable Rx delay */
+	tmp = ar8x_phy_dbg_read(phydev, AR8x_DBG_RGMII_RXCLK_CTRL);
+	tmp |= AR8x_DBG_RGMII_RXCLK_MASK;
+	ar8x_phy_dbg_write(phydev, AR8x_DBG_RGMII_RXCLK_CTRL, tmp);
+	/* Enable Tx delay */
+	tmp = ar8x_phy_dbg_read(phydev, AR8x_DBG_RGMII_TXCLK_CTRL);
+	tmp |= AR8x_DBG_RGMII_TXCLK_MASK;
+	ar8x_phy_dbg_write(phydev, AR8x_DBG_RGMII_TXCLK_CTRL, tmp);
+
+	err = genphy_restart_aneg(phydev);
+
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+EXPORT_SYMBOL(ar8x_add_skew);
+
+static int ar8x_config_init(struct phy_device *phydev)
+{
+	int err = 0;
+
+	if (phydev->interface == PHY_INTERFACE_MODE_RGMII)
+		err = ar8x_add_skew(phydev);
+
+	return err;
+
+}
+
+
+static int ar8x_ack_interrupt(struct phy_device *phydev)
+{
+	int err = 0;
+
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		err = phy_read(phydev, AR8x_INTR_STS);
+
+	return (err < 0) ? err : 0;
+}
+
+static int ar8x_config_intr(struct phy_device *phydev)
+{
+	int err;
+
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		err = phy_write(phydev, AR8x_INTR_EN, AR8x_INTR_MASK);
+	else {
+		/* Clear the interrupts */
+		err = phy_read(phydev, AR8x_INTR_STS);
+
+		if (err < 0)
+			return err;
+
+		err = phy_write(phydev, AR8x_INTR_EN, 0);
+	}
+
+	return err;
+}
+
+/* Atheros Ar8035 */
+static struct phy_driver ar8035_driver = {
+	.phy_id		= PHY_ID_AR8035,
+	.name		= "Atheros AR8035",
+	.phy_id_mask	= 0xffffff00,
+	.features	= PHY_GBIT_FEATURES,
+	.flags		= PHY_HAS_INTERRUPT,
+	.config_init	= &ar8x_config_init,
+	.config_aneg	= &genphy_config_aneg,
+	.read_status	= &genphy_read_status,
+	.ack_interrupt	= &ar8x_ack_interrupt,
+	.config_intr	= &ar8x_config_intr,
+#ifdef CONFIG_PM
+	.suspend	= &genphy_suspend,
+	.resume		= &genphy_resume,
+#endif
+	.driver 	= { .owner = THIS_MODULE,},
+};
+
+/* Atheros Ar8327 */
+static struct phy_driver ar8327_driver = {
+	.phy_id		= PHY_ID_AR8327,
+	.name		= "Atheros AR8327",
+	.phy_id_mask	= 0xffffff00,
+	.features	= PHY_GBIT_FEATURES,
+	.flags		= PHY_HAS_INTERRUPT,
+	.config_init	= &ar8x_config_init,
+	.config_aneg	= &genphy_config_aneg,
+	.read_status	= &genphy_read_status,
+	.ack_interrupt	= &ar8x_ack_interrupt,
+	.config_intr	= &ar8x_config_intr,
+#ifdef CONFIG_PM
+	.suspend	= &genphy_suspend,
+	.resume		= &genphy_resume,
+#endif
+	.driver 	= { .owner = THIS_MODULE,},
+};
+
+static int __init ar8x_init(void)
+{
+	int err;
+
+	err = phy_driver_register(&ar8035_driver);
+	if (err < 0)
+		return err;
+
+	err = phy_driver_register(&ar8327_driver);
+	if (err < 0)
+		phy_driver_unregister(&ar8035_driver);
+
+	return err;
+}
+
+static void __exit ar8x_exit(void)
+{
+	phy_driver_unregister(&ar8035_driver);
+	phy_driver_unregister(&ar8327_driver);
+}
+
+module_init(ar8x_init);
+module_exit(ar8x_exit);
+
+static struct mdio_device_id __maybe_unused atheros_tbl[] = {
+	{ PHY_ID_AR8035, 0xffffff00 },
+	{ PHY_ID_AR8327, 0xffffff00 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(mdio, atheros_tbl);
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 83a5a5a..0a728ad 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -35,6 +35,11 @@
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 
+#ifdef CONFIG_ARCH_M86XXX
+#include <mach/comcerto-2000/pm.h>
+#endif
+
+
 MODULE_DESCRIPTION("PHY library");
 MODULE_AUTHOR("Andy Fleming");
 MODULE_LICENSE("GPL");
@@ -885,7 +890,17 @@
 int genphy_suspend(struct phy_device *phydev)
 {
 	int value;
-
+#ifdef CONFIG_ARCH_M86XXX
+	/* Check for the Bit_Mask bit for WoL, if it is enabled
+	 * then we are not going suspend the WoL device , as by
+	 * this device , we will wake from System Resume.
+	 */
+	if ( !(host_utilpe_shared_pmu_bitmask & WOL_IRQ )){
+		/* We will just return
+		 */
+		return 0;
+	}
+#endif
 	mutex_lock(&phydev->lock);
 
 	value = phy_read(phydev, MII_BMCR);
@@ -900,7 +915,17 @@
 int genphy_resume(struct phy_device *phydev)
 {
 	int value;
-
+#ifdef CONFIG_ARCH_M86XXX
+	/* Check for the Bit_Mask bit for WoL, if it is enabled
+	 * then we are not going suspend the WoL device , as by
+	 * this device , we will wake from System Resume.
+	 */
+	if ( !(host_utilpe_shared_pmu_bitmask & WOL_IRQ )){
+		/* We will just return
+		 */
+		return 0;
+	}
+#endif
 	mutex_lock(&phydev->lock);
 
 	value = phy_read(phydev, MII_BMCR);
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index 3ed983c..f035281 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -53,6 +53,9 @@
 #include <linux/nsproxy.h>
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
+#if defined(CONFIG_COMCERTO_FP)
+#include <linux/jiffies.h>
+#endif
 
 #define PPP_VERSION	"2.4.2"
 
@@ -559,6 +562,9 @@
 	struct ppp *ppp;
 	int err = -EFAULT, val, val2, i;
 	struct ppp_idle idle;
+#if defined(CONFIG_COMCERTO_FP)
+        struct ppp_idle fppidle;
+#endif
 	struct npioctl npi;
 	int unit, cflags;
 	struct slcompress *vj;
@@ -738,6 +744,30 @@
 		err = 0;
 		break;
 
+#if defined(CONFIG_COMCERTO_FP)
+	case PPPIOCSFPPIDLE:
+		if (copy_from_user(&fppidle, argp, sizeof(fppidle)))
+			break;
+
+		ppp_xmit_lock(ppp);
+
+		if (time_after((jiffies - (fppidle.xmit_idle * HZ)) , ppp->last_xmit))
+			ppp->last_xmit = (jiffies - fppidle.xmit_idle * HZ);
+
+		ppp_xmit_unlock(ppp);
+
+		ppp_recv_lock(ppp);
+
+		if (time_after((jiffies - (fppidle.recv_idle * HZ)) , ppp->last_recv))
+			ppp->last_recv = (jiffies - fppidle.recv_idle * HZ);
+
+		ppp_recv_unlock(ppp);
+
+		err = 0;
+		break;
+#endif
+
+
 #ifdef CONFIG_PPP_FILTER
 	case PPPIOCSPASS:
 	{
@@ -2825,8 +2855,10 @@
 		goto out;
 	write_lock_bh(&pch->upl);
 	ret = -EINVAL;
-	if (pch->ppp)
-		goto outl;
+	if (pch->ppp) {
+		write_unlock_bh(&pch->upl);
+		goto out;
+	}
 
 	ppp_lock(ppp);
 	if (pch->file.hdrlen > ppp->file.hdrlen)
@@ -2839,10 +2871,21 @@
 	pch->ppp = ppp;
 	atomic_inc(&ppp->file.refcnt);
 	ppp_unlock(ppp);
-	ret = 0;
 
- outl:
 	write_unlock_bh(&pch->upl);
+
+/*We need to revisit below changes when PPPoE automode is introduced to C2K*/
+#if 0
+#if defined(CONFIG_COMCERTO_FP)
+	if ((ppp->dev) && (!ppp->closing)) {
+		rtnl_lock();
+		rtmsg_ifinfo(RTM_NEWLINK, ppp->dev, 0);
+		rtnl_unlock();
+	}
+#endif
+#endif
+
+	ret = 0;
  out:
 	mutex_unlock(&pn->all_ppp_mutex);
 	return ret;
@@ -2868,6 +2911,18 @@
 		if (--ppp->n_channels == 0)
 			wake_up_interruptible(&ppp->file.rwait);
 		ppp_unlock(ppp);
+
+/*We need to revisit below changes when PPPoE automode is introduced to C2K*/
+#if 0
+#if defined(CONFIG_COMCERTO_FP)
+		if ((ppp->dev) && (!ppp->closing)) {
+			rtnl_lock();
+			rtmsg_ifinfo(RTM_NEWLINK, ppp->dev, 0);
+			rtnl_unlock();
+		}
+#endif
+#endif
+
 		if (atomic_dec_and_test(&ppp->file.refcnt))
 			ppp_destroy_interface(ppp);
 		err = 0;
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index 49c6da9..53cc103 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -940,8 +940,16 @@
 
 	skb->protocol = cpu_to_be16(ETH_P_PPP_SES);
 	skb->dev = dev;
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)	
+	if((skb->ipsec_offload == 1) && (!skb->sp))
+	{
+		  dev_hard_header(skb, dev, ETH_P_PPP_SES,
+			 dev->dev_addr, po->pppoe_pa.remote, data_len);
 
-	dev_hard_header(skb, dev, ETH_P_PPP_SES,
+	}
+	else
+#endif
+		dev_hard_header(skb, dev, ETH_P_PPP_SES,
 			po->pppoe_pa.remote, NULL, data_len);
 
 	dev_queue_xmit(skb);
@@ -1004,17 +1012,33 @@
 {
 	struct pppox_sock *po;
 	char *dev_name;
+#if defined(CONFIG_COMCERTO_FP)
+	char *ppp_name;
+#endif
 
 	if (v == SEQ_START_TOKEN) {
-		seq_puts(seq, "Id       Address              Device\n");
+#if defined(CONFIG_COMCERTO_FP)
+		seq_puts(seq, "Id       Address              Device  PPPDevice\n");
+#else
+ 		seq_puts(seq, "Id       Address              Device\n");
+#endif
 		goto out;
 	}
 
 	po = v;
 	dev_name = po->pppoe_pa.dev;
 
-	seq_printf(seq, "%08X %pM %8s\n",
-		po->pppoe_pa.sid, po->pppoe_pa.remote, dev_name);
+#if defined(CONFIG_COMCERTO_FP)
+	ppp_name = ppp_dev_name(&po->chan);
+	if (!ppp_name)
+		goto out;
+
+	seq_printf(seq, "%04X %pM %8s       %s\n",
+		ntohs(po->pppoe_pa.sid), po->pppoe_pa.remote, dev_name, ppp_name);
+#else
+ 	seq_printf(seq, "%08X %pM %8s\n",
+ 		po->pppoe_pa.sid, po->pppoe_pa.remote, dev_name);
+#endif
 out:
 	return 0;
 }
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index b873b5d..2864780 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -49,6 +49,14 @@
 
 #define DRIVER_VERSION		"22-Aug-2005"
 
+#ifdef CONFIG_ARCH_M86XXX
+/* 
+ * We alllocate extra 64 Bytes to reserve headroom in the sk_buff 
+ * To be used by Fast Path (Head Room must be 4 Byte aligned 
+ * because USB 2.0 controller doesn't support 2 byte alignment
+ */
+#define C2K_USBNET_SKB_HEADROOM_FAST_PATH 64
+#endif
 
 /*-------------------------------------------------------------------------*/
 
@@ -344,13 +352,26 @@
 	unsigned long		lockflags;
 	size_t			size = dev->rx_urb_size;
 
+#ifdef CONFIG_ARCH_M86XXX
+    /* 
+     * We alllocate extra 64 Bytes to reserve headroom in the sk_buff 
+     * To be used by Fast Path (Head Room must be 4 Byte aligned 
+     * because USB 2.0 controller doesn't support 2 byte alignment
+     */
+	if ((skb = alloc_skb (size + C2K_USBNET_SKB_HEADROOM_FAST_PATH, flags)) == NULL) {
+#else
 	if ((skb = alloc_skb (size + NET_IP_ALIGN, flags)) == NULL) {
+#endif        
 		netif_dbg(dev, rx_err, dev->net, "no rx skb\n");
 		usbnet_defer_kevent (dev, EVENT_RX_MEMORY);
 		usb_free_urb (urb);
 		return -ENOMEM;
 	}
+#ifdef CONFIG_ARCH_M86XXX
+	skb_reserve (skb, C2K_USBNET_SKB_HEADROOM_FAST_PATH);
+#else
 	skb_reserve (skb, NET_IP_ALIGN);
+#endif        
 
 	entry = (struct skb_data *) skb->cb;
 	entry->urb = urb;
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 53eb4e5..c76b916 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -762,6 +762,13 @@
 	  This driver can also be build as a module. If so, the module
 	  will be called rtc-s3c.
 
+config RTC_DRV_C2K
+	tristate "Mindspeed C2000 SoC RTC"
+	depends on ARCH_M86XXX
+	default y
+	help
+		Comcerto C2000 RTC (Realtime Clock) driver.
+
 config RTC_DRV_EP93XX
 	tristate "Cirrus Logic EP93XX"
 	depends on ARCH_EP93XX
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 6e69823..fae32d3 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -91,6 +91,7 @@
 obj-$(CONFIG_RTC_DRV_RX8581)	+= rtc-rx8581.o
 obj-$(CONFIG_RTC_DRV_S35390A)	+= rtc-s35390a.o
 obj-$(CONFIG_RTC_DRV_S3C)	+= rtc-s3c.o
+obj-$(CONFIG_RTC_DRV_C2K)      += rtc-c2k.o
 obj-$(CONFIG_RTC_DRV_SA1100)	+= rtc-sa1100.o
 obj-$(CONFIG_RTC_DRV_SH)	+= rtc-sh.o
 obj-$(CONFIG_RTC_DRV_SPEAR)	+= rtc-spear.o
diff --git a/drivers/rtc/rtc-c2k.c b/drivers/rtc/rtc-c2k.c
new file mode 100644
index 0000000..2af8618
--- /dev/null
+++ b/drivers/rtc/rtc-c2k.c
@@ -0,0 +1,530 @@
+/* 
+ * drivers/rtc/rtc-c2k.c
+ *
+ * Copyright (c) 2010 Mindspeed Technologies Co., Ltd.
+ *		http://www.mindspeed.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/module.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/clk.h>
+#include <linux/log2.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include <mach/hardware.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <linux/rtc/rtc-c2k.h>
+
+/* Initial by default values */
+#define	YEAR		112 /* 2012 */ 
+#define	MONTH		6 /* 6 */
+#define	DATE		12 /* 18 */ 
+#define	DAY		3 //0:SUNDAY 1:MONDAY 2:TUESDAY 3:WEDNESDAY 4:THURSDAY 5:FRIDAY 6:SATURDAY
+#define	HOUR		18 //24 hours time format
+#define	MIN		25
+#define	SEC		1
+/*End*/
+
+#define	C2K_RTC_RTCALM_SECEN	0x81
+#define	C2K_RTC_RTCALM_MINEN	0x82
+#define	C2K_RTC_RTCALM_HOUREN	0x84
+#define	C2K_RTC_RTCALM_DATEEN	0x88
+#define	C2K_RTC_RTCALM_DAYEN	0x90
+#define	C2K_RTC_RTCALM_MONEN	0xA0
+#define	C2K_RTC_RTCALM_YEAREN	0xC0
+#define	C2K_RTC_RTCALM_GLOBALEN	0x80
+
+#define	C2K_RTC_RTCALM_ALMEN	0xff
+#define	DISABLE_ALL_ALAM	0x0
+
+#define	C2K_RTCALM_ALMEN	(0x3<<0)
+
+static struct resource *c2k_rtc_mem;
+static volatile char __iomem *c2k_rtc_base;
+static int rtc_alarmno;
+
+#define writel_rtc(v,a)		(*(int *)(a) = (v))
+#define readl_rtc(a)		(*(int *)(a))
+
+void rtc_reg_write(unsigned int WrData, volatile char *WrAd)
+{ 
+	unsigned int WrAddr = (unsigned int)WrAd;
+	unsigned int WriteData;
+
+	WriteData = (0x0000FFFF & WrData);
+
+	/* The core APB runs at 250Hz ,where as the RTC APB runs at 50MHz.
+	 * So the delay need to be inserted between two APB requests, other
+	 * wise transaction gets dropped.
+	 * Each Core time unit = 4000ps , RTC time unit = 20000ps. 5 times 
+	 * core time unit = RTC time unit. 
+	 */
+
+	writel_rtc(WriteData, WrAddr);
+
+	udelay(5);
+
+	return;
+}
+
+int rtc_reg_read(volatile char *RdAd)
+{ 
+	unsigned int *RdAddr = (unsigned int*)RdAd; 
+	unsigned int WriteData,ReadData;
+
+	WriteData = 0x00010000;
+
+	/* The core APB runs at 250Hz ,where as the RTC APB runs at 50MHz.
+	 * So the delay need to be inserted between two APB requests, other
+	 * wise transaction gets dropped.
+	 * Each Core time unit = 4000ps , RTC time unit = 20000ps. 5 times 
+	 * core time unit = RTC time unit.
+	 */
+
+	writel_rtc(WriteData, RdAddr);
+
+	/* The core APB runs at 250Hz ,where as the RTC APB runs at 50MHz.
+	 * So the delay need to be inserted between two APB requests, other
+	 * wise transaction gets dropped.
+	 * Each Core time unit = 4000ps , RTC time unit = 20000ps. 5 times 
+	 * core time unit = RTC time unit. 
+	 */
+
+	udelay(5);
+
+	ReadData = readl_rtc(RdAddr);
+
+	while ( (0x00010000 & ReadData) != 0x10000)
+	{
+		udelay(5);
+		ReadData = readl_rtc(RdAddr);
+	}
+
+	return((0x0000FFFF & ReadData));    
+}
+
+void dbg_rtc_time(struct rtc_time *rtc_tm)
+{
+	printk ("\n%s: \
+			\n\trtc_tm->tm_sec=%d \
+			\n\trtc_tm->tm_min=%d \
+			\n\trtc_tm->tm_hour=%d \
+			\n\trtc_tm->tm_mday=%d \
+			\n\trtc_tm->tm_wday=%d \
+			\n\trtc_tm->tm_mon=%d \
+			\n\trtc_tm->tm_year=%d \n\n", __func__, \
+			rtc_tm->tm_sec, rtc_tm->tm_min, rtc_tm->tm_hour, rtc_tm->tm_mday,\
+			rtc_tm->tm_wday, rtc_tm->tm_mon, rtc_tm->tm_year);
+}
+
+/* IRQ Handlers */
+
+static irqreturn_t c2k_rtc_alarmirq(int irq, void *id)
+{
+	struct rtc_device *rdev = id;
+
+	pr_debug ("%s: irq=%d: Alaram Rang ..............!!!\n \
+			\n\t*(0x%x)=0x%x \
+			\n\t*(0x%x)=0x%x \n", __func__, irq, \
+			(unsigned int)(c2k_rtc_base + C2K_RTC_RTCALM), rtc_reg_read(c2k_rtc_base + C2K_RTC_RTCALM),\
+			(unsigned int)(c2k_rtc_base + C2K_RTC_RTCIM), rtc_reg_read(c2k_rtc_base + C2K_RTC_RTCIM));
+
+	rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF);
+	/*-------------------------
+	 * DISBABLING alarm
+	 *------------------------
+	 */
+	rtc_reg_write(DISABLE_ALL_ALAM, c2k_rtc_base + C2K_RTC_RTCALM);
+
+	/*-------------------------
+	 * DISBABLING the alarm interrupt
+	 *------------------------
+	 */
+	rtc_reg_write(DISABLE_ALL_ALAM, c2k_rtc_base + C2K_RTC_RTCIM);
+
+	/*-------------------------
+	 * DISBABLING the alarm PENDING bit
+	 *------------------------
+	 */
+	rtc_reg_write(DISABLE_ALL_ALAM, c2k_rtc_base + C2K_RTC_RTCPEND);
+
+	return IRQ_HANDLED;
+}
+
+/* Time read/write */
+static int c2k_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
+{
+	rtc_tm->tm_year = rtc_reg_read(c2k_rtc_base + C2K_RTC_BCDYEAR);
+	rtc_tm->tm_mon = rtc_reg_read(c2k_rtc_base + C2K_RTC_BCDMON);
+	rtc_tm->tm_mday = rtc_reg_read(c2k_rtc_base + C2K_RTC_BCDDATE);
+	rtc_tm->tm_wday = rtc_reg_read(c2k_rtc_base + C2K_RTC_BCDDAY);
+	rtc_tm->tm_hour = rtc_reg_read(c2k_rtc_base + C2K_RTC_BCDHOUR);
+	rtc_tm->tm_min  = rtc_reg_read(c2k_rtc_base + C2K_RTC_BCDMIN);
+	rtc_tm->tm_sec  = rtc_reg_read(c2k_rtc_base + C2K_RTC_BCDSEC);
+
+	pr_debug("%s: BCD:\n \
+			\n\tyear.mon.date.day hr:min:sec\n \
+			\n\t0x%x.0x%x.0x%x.0x%x 0x%x:0x%x:0x%x\n",__func__,\
+			rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,rtc_tm->tm_wday,\
+			rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
+
+	rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
+	rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
+	rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
+	rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);
+	rtc_tm->tm_wday = bcd2bin(rtc_tm->tm_wday);
+	rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon);
+	rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);
+
+	rtc_tm->tm_year += 100;
+
+	rtc_tm->tm_mon -= 1;
+
+	return rtc_valid_tm(rtc_tm);
+}
+
+#define	C2K_RTC_RTCCON_STARTB	(0x1<<0) /* RTC Halt */
+#define	C2K_RTC_RTCCON_RTCEN	(0x1<<1) /* RTC Write Enable */
+#define	C2K_RTC_RTCCON_CLKRST	(0x1<<2) /* RTC RESET */
+
+static int c2k_rtc_settime(struct device *dev, struct rtc_time *tm)
+{
+	int year = tm->tm_year - 100;
+
+	pr_debug("%s: Will set:\
+			\n%04d.%02d.%02d %02d:%02d:%02d\n",__func__,\
+			tm->tm_year+1900, tm->tm_mon, tm->tm_mday, \
+			tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+	if (year < 0 || year >= 100) {
+		dev_err(dev, "rtc only supports 100 years\n");
+		return -EINVAL;
+	}
+
+	rtc_reg_write((C2K_RTC_RTCCON_STARTB | C2K_RTC_RTCCON_RTCEN | C2K_RTC_RTCCON_CLKRST), \
+			c2k_rtc_base + C2K_RTC_RTCCON);
+
+	rtc_reg_write(bin2bcd(tm->tm_min), c2k_rtc_base + C2K_RTC_BCDMIN);
+	rtc_reg_write(bin2bcd(tm->tm_hour), c2k_rtc_base + C2K_RTC_BCDHOUR);
+	rtc_reg_write(bin2bcd(tm->tm_mday), c2k_rtc_base + C2K_RTC_BCDDATE);
+	rtc_reg_write(bin2bcd(tm->tm_wday), c2k_rtc_base + C2K_RTC_BCDDAY);
+	rtc_reg_write(bin2bcd(tm->tm_mon+1), c2k_rtc_base + C2K_RTC_BCDMON);
+	rtc_reg_write(bin2bcd(year), c2k_rtc_base + C2K_RTC_BCDYEAR);
+	rtc_reg_write(bin2bcd(tm->tm_sec), c2k_rtc_base + C2K_RTC_BCDSEC);
+
+	rtc_reg_write((C2K_RTC_RTCCON_RTCEN | C2K_RTC_RTCCON_CLKRST), c2k_rtc_base + C2K_RTC_RTCCON);
+
+	return 0;
+}
+
+static int c2k_rtc_setaie(struct device *dev, unsigned int enabled)
+{
+	unsigned int tmp;
+
+	pr_debug ("%s: aie=%d\n", __func__, enabled);
+
+	tmp = rtc_reg_read(c2k_rtc_base + C2K_RTC_RTCIM) & ~C2K_RTCALM_ALMEN;
+
+	if (enabled)
+		tmp |= C2K_RTCALM_ALMEN;
+
+	rtc_reg_write(tmp, c2k_rtc_base + C2K_RTC_RTCIM);
+
+	return 0;
+}
+
+static int c2k_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct rtc_time *alm_tm = &alrm->time;
+	unsigned int alm_en;
+
+	alm_tm->tm_sec  = rtc_reg_read(c2k_rtc_base + C2K_RTC_ALMSEC);
+	alm_tm->tm_min  = rtc_reg_read(c2k_rtc_base + C2K_RTC_ALMMIN);
+	alm_tm->tm_hour = rtc_reg_read(c2k_rtc_base + C2K_RTC_ALMHOUR);
+	alm_tm->tm_mon  = rtc_reg_read(c2k_rtc_base + C2K_RTC_ALMMON);
+	alm_tm->tm_mday = rtc_reg_read(c2k_rtc_base + C2K_RTC_ALMDATE);
+	alm_tm->tm_wday = rtc_reg_read(c2k_rtc_base + C2K_RTC_ALMDAY);
+	alm_tm->tm_year = rtc_reg_read(c2k_rtc_base + C2K_RTC_ALMYEAR);
+
+	alm_en = rtc_reg_read(c2k_rtc_base + C2K_RTC_RTCALM);
+
+	alrm->enabled = (alm_en & C2K_RTC_RTCALM_ALMEN) ? 1 : 0;
+
+	pr_debug("%s: alm_en=%d, %04d.%02d.%02d.%02d  %02d:%02d:%02d\n",__func__,
+			alm_en,
+			1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
+			alm_tm->tm_wday, alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
+
+	/* decode the alarm enable field */
+
+	if (alm_en & C2K_RTC_RTCALM_SECEN)
+		alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec);
+	else
+		alm_tm->tm_sec = -1;
+
+	if (alm_en & C2K_RTC_RTCALM_MINEN)
+		alm_tm->tm_min = bcd2bin(alm_tm->tm_min);
+	else
+		alm_tm->tm_min = -1;
+
+	if (alm_en & C2K_RTC_RTCALM_HOUREN)
+		alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);
+	else
+		alm_tm->tm_hour = -1;
+
+	if (alm_en & C2K_RTC_RTCALM_DAYEN)
+		alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday);
+	else
+		alm_tm->tm_mday = -1;
+
+	if (alm_en & C2K_RTC_RTCALM_MONEN) {
+		alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon);
+		alm_tm->tm_mon -= 1;
+	} else {
+		alm_tm->tm_mon = -1;
+	}
+
+	if (alm_en & C2K_RTC_RTCALM_YEAREN){
+		alm_tm->tm_year = bcd2bin(alm_tm->tm_year);
+		alm_tm->tm_year += 100;
+	}
+	else
+		alm_tm->tm_year = -1;
+
+	return 0;
+}
+
+static int c2k_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct rtc_time *tm = &alrm->time;
+
+	pr_debug("%s: %d, %04d.%02d.%02d %02d:%02d:%02d\n",__func__,
+			alrm->enabled,
+			1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
+			tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+	rtc_reg_write(0x3, (c2k_rtc_base + C2K_RTC_RTCIM)); //enable alarm interrupt mode
+	rtc_reg_write(0xff, (c2k_rtc_base + C2K_RTC_RTCALM)); //enable all alarms.
+
+	if (tm->tm_sec < 60 && tm->tm_sec >= 0) {
+		rtc_reg_write(bin2bcd(tm->tm_sec), c2k_rtc_base + C2K_RTC_ALMSEC);
+	}
+
+	if (tm->tm_min < 60 && tm->tm_min >= 0) {
+		rtc_reg_write(bin2bcd(tm->tm_min), c2k_rtc_base + C2K_RTC_ALMMIN);
+	}
+
+	if (tm->tm_hour < 24 && tm->tm_hour >= 0) {
+		rtc_reg_write(bin2bcd(tm->tm_hour), c2k_rtc_base + C2K_RTC_ALMHOUR);
+	}
+
+	if (tm->tm_mday < 32 && tm->tm_mday >= 1) {
+		rtc_reg_write(bin2bcd(tm->tm_mday), c2k_rtc_base + C2K_RTC_ALMDATE);
+	}
+
+	if (tm->tm_wday < 7 && tm->tm_wday >= 0) {
+		rtc_reg_write(bin2bcd(tm->tm_wday), c2k_rtc_base + C2K_RTC_ALMDAY);
+	}
+
+	if (tm->tm_mon < 12 && tm->tm_mon >= 0) {
+		rtc_reg_write(bin2bcd(tm->tm_mon+1), c2k_rtc_base + C2K_RTC_ALMMON);
+	}
+
+	if (tm->tm_year >= 1) {
+		int year = tm->tm_year - 100;
+
+		if (year < 0 || year >= 100) {
+			dev_err(dev, "rtc only supports 100 years\n");
+			return -EINVAL;
+		}
+
+		rtc_reg_write(bin2bcd(year), c2k_rtc_base + C2K_RTC_ALMYEAR);
+	}
+
+	c2k_rtc_setaie(dev, alrm->enabled);
+
+	return 0;
+}
+
+static const struct rtc_class_ops c2k_rtcops = {
+	.read_time	= c2k_rtc_gettime,
+	.set_time	= c2k_rtc_settime,
+	.read_alarm	= c2k_rtc_getalarm,
+	.set_alarm	= c2k_rtc_setalarm,
+	.alarm_irq_enable = c2k_rtc_setaie,
+};
+
+static int __devexit c2k_rtc_remove(struct platform_device *dev)
+{
+	struct rtc_device *rtc = platform_get_drvdata(dev);
+
+	free_irq(rtc_alarmno, rtc);
+
+	platform_set_drvdata(dev, NULL);
+	rtc_device_unregister(rtc);
+
+	c2k_rtc_setaie(&dev->dev, 0);
+
+	iounmap(c2k_rtc_base);
+	release_resource(c2k_rtc_mem);
+	kfree(c2k_rtc_mem);
+
+	return 0;
+}
+
+static char __initdata banner[] = "C2000 RTC, (c) 2012 Mindspeed Technologies\n";
+
+static int __devinit c2k_rtc_probe(struct platform_device *pdev)
+{
+	struct rtc_device *rtc;
+	struct rtc_time rtc_tm;
+	struct resource *res;
+	int ret;
+
+	rtc_alarmno = platform_get_irq(pdev, 0);
+	if (rtc_alarmno < 0) {
+		dev_err(&pdev->dev, "no irq for alarm\n");
+		return -ENOENT;
+	}
+
+	/* get the memory region */
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "failed to get memory region resource\n");
+		return -ENOENT;
+	}
+
+	pr_debug ("%s: alarm irq=%d res->start=0x%x res->end=0x%x\n", __func__, \
+			rtc_alarmno, res->start, res->end);
+
+	c2k_rtc_mem = request_mem_region(res->start, resource_size(res),
+			pdev->name);
+	if (c2k_rtc_mem == NULL) {
+		printk("%s: failed to reserve memory region\n", __func__);
+		ret = -ENOENT;
+		goto err_nores;
+	}
+
+	c2k_rtc_base = ioremap(res->start, resource_size(res));
+	if (c2k_rtc_base == NULL) {
+		printk ("%s: failed ioremap()\n", __func__);
+		ret = -EINVAL;
+		goto err_nomap;
+	}
+
+	device_init_wakeup(&pdev->dev, 1);
+
+	/* register RTC and exit */
+
+	rtc = rtc_device_register("c2k", &pdev->dev, &c2k_rtcops,
+			THIS_MODULE);
+	if (IS_ERR(rtc)) {
+		dev_err(&pdev->dev, "cannot attach rtc\n");
+		ret = PTR_ERR(rtc);
+		goto err_nortc;
+	} else
+		printk(banner);
+
+	/* Check RTC Time */
+	c2k_rtc_gettime(NULL, &rtc_tm);
+
+	if (rtc_valid_tm(&rtc_tm)) {
+		rtc_tm.tm_year	= YEAR;
+		rtc_tm.tm_mon	= MONTH;
+		rtc_tm.tm_mday	= DATE;
+		rtc_tm.tm_wday	= DAY;
+		rtc_tm.tm_hour	= HOUR;
+		rtc_tm.tm_min	= MIN;
+		rtc_tm.tm_sec	= SEC;
+
+		c2k_rtc_settime(NULL, &rtc_tm);
+
+		dev_warn(&pdev->dev, "Warning: Invalid RTC value so initializing it\n");
+	}
+
+	platform_set_drvdata(pdev, rtc);
+
+	ret = request_irq(rtc_alarmno, c2k_rtc_alarmirq,
+			IRQF_DISABLED,  "rtc-alarm", rtc);
+	if (ret) {
+		dev_err(&pdev->dev, "IRQ%d error %d\n", rtc_alarmno, ret);
+		goto err_alarm_irq;
+	}
+
+	return 0;
+
+err_alarm_irq:
+	platform_set_drvdata(pdev, NULL);
+	rtc_device_unregister(rtc);
+
+err_nortc:
+	iounmap(c2k_rtc_base);
+
+err_nomap:
+	release_resource(c2k_rtc_mem);
+
+err_nores:
+	return ret;
+}
+
+#ifdef CONFIG_PM
+
+/* RTC Power management control */
+static int c2k_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	return 0;
+}
+
+static int c2k_rtc_resume(struct platform_device *pdev)
+{
+	return 0;
+}
+#else
+#define c2k_rtc_suspend NULL
+#define c2k_rtc_resume  NULL
+#endif
+
+static struct platform_driver c2k_rtc_driver = {
+	.probe		= c2k_rtc_probe,
+	.remove		= __devexit_p(c2k_rtc_remove),
+	.suspend	= c2k_rtc_suspend,
+	.resume		= c2k_rtc_resume,
+	.driver		= {
+		.name	= "c2k-rtc",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init c2k_rtc_init(void)
+{
+	return platform_driver_register(&c2k_rtc_driver);
+}
+
+static void __exit c2k_rtc_exit(void)
+{
+	platform_driver_unregister(&c2k_rtc_driver);
+}
+
+module_init(c2k_rtc_init);
+module_exit(c2k_rtc_exit);
+
+MODULE_DESCRIPTION("Mindspeed RTC Driver");
+MODULE_AUTHOR("Satendra Pratap <satendra.pratap@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:c2k-rtc");
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 7587796..7aea2c0 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -373,6 +373,20 @@
 
 	  Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)"
 
+config SPI_MSPD_LOW_SPEED
+	tristate "MSPD SPI low-speed controller module"
+	select SPI_DESIGNWARE
+	default SPI_MASTER
+	help
+		This exposes the MSPD SPI low-speed controller.
+
+config SPI_MSPD_HIGH_SPEED
+	tristate "MSPD SPI high-speed controller module"
+	select SPI_DESIGNWARE
+	default SPI_MASTER
+	help
+		This exposes the MSPD SPI high-speed controller.
+
 config SPI_NUC900
 	tristate "Nuvoton NUC900 series SPI"
 	depends on ARCH_W90X900 && EXPERIMENTAL
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 61c3261..41c6530 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -19,8 +19,26 @@
 obj-$(CONFIG_SPI_BITBANG)		+= spi-bitbang.o
 obj-$(CONFIG_SPI_BUTTERFLY)		+= spi-butterfly.o
 obj-$(CONFIG_SPI_COLDFIRE_QSPI)		+= spi-coldfire-qspi.o
+
+SPI_MSPD=n
+ifeq ($(CONFIG_SPI_MSPD_HIGH_SPEED),m)
+    SPI_MSPD=m
+endif
+ifeq ($(CONFIG_SPI_MSPD_LOW_SPEED),m)
+    SPI_MSPD=m
+endif
+ifeq ($(CONFIG_SPI_MSPD_HIGH_SPEED),y)
+    SPI_MSPD=y
+endif
+ifeq ($(CONFIG_SPI_MSPD_LOW_SPEED),y)
+    SPI_MSPD=y
+endif
+#obj-$(SPI_MSPD)				+= spi-c2000-dma.o
+#obj-$(SPI_MSPD)				+= spi-c2000.o
+
 obj-$(CONFIG_SPI_DAVINCI)		+= spi-davinci.o
-obj-$(CONFIG_SPI_DESIGNWARE)		+= spi-dw.o
+obj-$(CONFIG_SPI_DESIGNWARE)		+= designware_spi.o
+#obj-$(CONFIG_SPI_DESIGNWARE)		+= spi-dw.o
 obj-$(CONFIG_SPI_DW_MMIO)		+= spi-dw-mmio.o
 obj-$(CONFIG_SPI_DW_PCI)		+= spi-dw-midpci.o
 spi-dw-midpci-objs			:= spi-dw-pci.o spi-dw-mid.o
diff --git a/drivers/spi/comcerto_spi.c b/drivers/spi/comcerto_spi.c
new file mode 100644
index 0000000..7b537af
--- /dev/null
+++ b/drivers/spi/comcerto_spi.c
@@ -0,0 +1,640 @@
+/*
+ * Mindspeed SPI controller driver (master mode only)
+ *
+ * Author: Satendra Pratap
+ *	satendra.pratap@mindspeed.com
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/io.h>
+
+#include <linux/spi/comcerto_spi.h>
+
+#define SPI_VERSION             "0.0.1"
+
+#define spi_err(dev, fmt, args...)      dev_err(dev, "%s: " fmt, __FUNCTION__, ##args)
+#define spi_dbg(dev, fmt, args...)      dev_dbg(dev, "%s: " fmt, __FUNCTION__, ##args)
+#define spi_warn(dev, fmt, args...)     dev_warn(dev, "%s: " fmt, __FUNCTION__, ##args)
+         
+struct comcerto_spi {
+	/* bitbang has to be first */
+	struct spi_bitbang bitbang;
+    struct platform_device *dev;
+	struct completion done;
+	struct resource mem; /* phys mem */
+	void __iomem	*regs;	/* virt. address of the control registers */
+
+	u32		irq;
+
+	u8 *rx_ptr;		/* pointer in the Tx buffer */
+	const u8 *tx_ptr;	/* pointer in the Rx buffer */
+	int remaining_bytes;	/* the number of bytes left to transfer */
+	u8 bits_per_word;
+
+    int (*do_read8)(void __iomem *, u8 *buf, unsigned int *len);
+    int (*do_write8)(void __iomem *, u8 *buf, unsigned int *len);
+
+    int (*do_read16)(void __iomem *, u16 *buf, unsigned int *len);
+    int (*do_write16)(void __iomem *, u16 *buf, unsigned int *len);
+
+    int (*do_write_read)(void __iomem *, u8 fs, u8 *wbuf, unsigned int *wlen, u8 *rbuf, unsigned int *rlen);
+};
+
+static int do_write_read_transfer(void __iomem *reg_base, u8 fs, u8 *wbuf, unsigned int *wlen, u8 *rbuf, unsigned int *rlen)
+{
+    u32 sr, dr;
+    unsigned int wlen_now = 0, rlen_now = 0;
+    int rc = 0;
+
+    while (wlen_now < *wlen) {
+        sr = __raw_readl(reg_base + COMCERTO_SPI_SR);
+
+        if (sr & TFNF) {
+            if (wlen_now < *wlen) {
+                __raw_writew(cpu_to_le16((u16) *wbuf), reg_base + COMCERTO_SPI_DR);
+                wbuf++;
+                wlen_now++;
+            }
+        }
+    }
+
+    while (rlen_now < *rlen) {
+        sr = __raw_readl(reg_base + COMCERTO_SPI_SR);
+
+        if (sr & (RFF | DCOL)) {
+            rc = -1;
+            goto out;
+        }
+
+        if (sr & RFNE) {
+            dr = __raw_readw(reg_base + COMCERTO_SPI_DR);
+            if (rlen_now < *rlen) {
+                *rbuf = (u8) (le16_to_cpu(dr) & 0xff);
+                rbuf++;
+                rlen_now++;
+            } else {
+                rc = -1;
+                goto out;
+            }
+        }
+    }
+
+out:
+    *rlen = rlen_now;
+    *wlen = wlen_now;
+
+    return rc;
+}
+
+/**
+ *  * do_write_only_transfer8 -
+ *   *
+ *    *
+ *     */
+static int do_write_only_transfer8(void __iomem *reg_base, u8 *buf, unsigned int *len)
+{
+    unsigned int len_now;
+    int rc = 0;
+    unsigned int tmp = *len;
+    u32 dr = (u32)reg_base + COMCERTO_SPI_DR;
+    u32 txflr = (u32)reg_base + COMCERTO_SPI_TXFLR;
+
+    while (tmp)
+    {
+        len_now = 8 - __raw_readl(txflr);
+        if (len_now > tmp)
+            len_now = tmp;
+
+        tmp -= len_now;
+
+        /* warm-up
+         * write
+         * fifo
+         * to
+         * avoid
+         * underruns
+         * */
+        while (len_now--)
+            __raw_writew(cpu_to_le16((u16) *buf++), dr);
+    }
+
+    *len -= tmp;
+
+    return rc;
+}
+
+/**
+ *  * do_write_only_transfer -
+ *   *
+ *    *
+ *     */
+
+static int do_write_only_transfer16(void __iomem *reg_base, u16 *buf, unsigned int *len)
+{
+    unsigned int len_now;
+    int rc = 0;
+    unsigned int tmp = *len;
+    u32 dr = (u32)reg_base + COMCERTO_SPI_DR;
+    u32 txflr = (u32)reg_base + COMCERTO_SPI_TXFLR;
+
+    while (tmp)
+    {
+        len_now = 8 - __raw_readl(txflr);
+        if (len_now > tmp)
+            len_now = tmp;
+
+        tmp -= len_now;
+
+        /* warm-up
+         * write
+         * fifo
+         * to
+         * avoid
+         * underruns
+         * */
+        while (len_now--)
+            __raw_writew(cpu_to_le16(*buf++), dr);
+    }
+
+    *len -= tmp;
+
+    return rc;
+}
+
+
+/**
+ *  * do_read_only_transfer -
+ *   *
+ *    *
+ *     */
+static int do_read_only_transfer8(void __iomem *reg_base, u8 *buf, unsigned int *len)
+{
+    unsigned int len_now;
+    int rc = 0;
+    unsigned int tmp = *len;
+    u32 dr = (u32)reg_base + COMCERTO_SPI_DR;
+    u32 rxflr = (u32)reg_base + COMCERTO_SPI_RXFLR;
+
+    /* start the serial clock */
+    __raw_writew(0, dr);
+
+    while (tmp)
+    {
+        len_now = __raw_readl(rxflr);
+        if (len_now > tmp)
+            len_now = tmp;
+
+        tmp -= len_now;
+
+        while (len_now--) {
+            *buf = (u8) (le16_to_cpu(__raw_readw(dr)) & 0xff);
+            buf++;
+        }
+    }
+
+    *len -= tmp;
+
+    return rc;
+}
+
+/**
+ *  * do_read_only_transfer -
+ *   *
+ *    *
+ *     */
+static int do_read_only_transfer16(void __iomem *reg_base, u16 *buf, unsigned int *len)
+{
+    unsigned int len_now;
+    int rc = 0;
+    unsigned int tmp = *len;
+    u32 dr = (u32)reg_base + COMCERTO_SPI_DR;
+    u32 rxflr = (u32)reg_base + COMCERTO_SPI_RXFLR;
+
+    /* start the serial clock */
+    __raw_writew(0, dr);
+
+    while (tmp)
+    {
+        len_now = __raw_readl(rxflr);
+        if (len_now > tmp)
+            len_now = tmp;
+
+        tmp -= len_now;
+
+        while (len_now--) {
+            *buf = le16_to_cpu(__raw_readw(dr));
+            buf++;
+        }
+    }
+
+    *len -= tmp;
+
+    return rc;
+}
+
+
+
+int comcerto_spi_do_transfer(struct comcerto_spi *xspi, struct spi_client_conf *cconf, struct comcerto_transfer *transfer)
+{
+    u32 ctrlr0, ctrlr1, baudr = 0, ser = 0;
+    int rc;
+    void __iomem *reg_base = xspi->regs;
+
+    baudr = transfer->baudr;
+    ser = transfer->ser;
+    /* make sure last transaction is finished */
+    while (__raw_readl(reg_base + COMCERTO_SPI_SR) & BUSY) ;
+
+    ctrlr0 = transfer->ctrlr0;
+
+    __raw_writel(0, reg_base + COMCERTO_SPI_SSIENR);
+
+    switch (transfer->mode & 0x0f) {
+        default:
+            rc = -1;
+            break;
+
+        case SPI_TRANSFER_MODE_WRITE_ONLY:
+            ctrlr0 |= (0x0001 << 8);
+
+            __raw_writel(ctrlr0, reg_base + COMCERTO_SPI_CTRLR0);
+            __raw_writel(baudr, reg_base + COMCERTO_SPI_BAUDR);
+            __raw_writel(ser, reg_base + COMCERTO_SPI_SER);
+            __raw_writel(8, reg_base + COMCERTO_SPI_RXFTLR);
+            __raw_writel(0, reg_base + COMCERTO_SPI_TXFTLR);
+            __raw_writel(0, reg_base + COMCERTO_SPI_IMR);
+            __raw_writel(1, reg_base + COMCERTO_SPI_SSIENR);
+
+            if (transfer->fs <= 8)
+                rc = xspi->do_write8(reg_base, transfer->wbuf, &transfer->wlen);
+            else
+                rc = xspi->do_write16(reg_base, (u16 *) transfer->wbuf, &transfer->wlen);
+
+            break;
+
+        case SPI_TRANSFER_MODE_READ_ONLY:
+            ctrlr0 |= (0x0002 << 8);
+            ctrlr1 = transfer->rlen - 1;
+
+            __raw_writel(ctrlr0, reg_base + COMCERTO_SPI_CTRLR0);
+
+            __raw_writel(ctrlr1, reg_base + COMCERTO_SPI_CTRLR1);
+            __raw_writel(baudr, reg_base + COMCERTO_SPI_BAUDR);
+            __raw_writel(ser, reg_base + COMCERTO_SPI_SER);
+            __raw_writel(8, reg_base + COMCERTO_SPI_RXFTLR);
+            __raw_writel(0, reg_base + COMCERTO_SPI_TXFTLR);
+            __raw_writel(0, reg_base + COMCERTO_SPI_IMR);
+            __raw_writel(1, reg_base + COMCERTO_SPI_SSIENR);
+
+            if (transfer->fs <= 8)
+                rc = xspi->do_read8(reg_base, transfer->rbuf, &transfer->rlen);
+            else
+                rc = xspi->do_read16(reg_base, (u16 *) transfer->rbuf, &transfer->rlen);
+
+            break;
+
+        case SPI_TRANSFER_MODE_WRITE_READ:
+            ctrlr0 |= (0x0000 << 8);
+
+            __raw_writel(ctrlr0, reg_base + COMCERTO_SPI_CTRLR0);
+            __raw_writel(baudr, reg_base + COMCERTO_SPI_BAUDR);
+            __raw_writel(ser, reg_base + COMCERTO_SPI_SER);
+            __raw_writel(8, reg_base + COMCERTO_SPI_RXFTLR);
+            __raw_writel(0, reg_base + COMCERTO_SPI_TXFTLR);
+            __raw_writel(0, reg_base + COMCERTO_SPI_IMR);
+            __raw_writel(1, reg_base + COMCERTO_SPI_SSIENR);
+
+            rc = xspi->do_write_read(reg_base, transfer->fs, transfer->wbuf, &transfer->wlen, transfer->rbuf, &transfer->rlen);
+
+            break;
+    }
+
+    return rc;
+}
+
+static int comcerto_spi_setup(struct spi_device *spi)
+{
+    int rc = 0;
+
+    spi_dbg(&spi->dev, "bits per word %u, max speed %uHz, mode %#x\n",
+            spi->bits_per_word, spi->max_speed_hz, spi->mode);
+
+    if (!spi->bits_per_word)
+        spi->bits_per_word = 8;
+
+    if (spi->bits_per_word < SPI_FRAME_SIZE_MIN || spi->bits_per_word > SPI_FRAME_SIZE_MAX) {
+        spi_err(&spi->dev, "bits per word (frame size) %u out of range %u..%u\n",
+                spi->max_speed_hz, SPI_FRAME_SIZE_MIN, SPI_FRAME_SIZE_MAX);
+        rc = -EINVAL;
+        goto err;
+    }
+
+    if (spi->max_speed_hz < SPI_SPEED_MIN) {
+        spi_err(&spi->dev, "such low speed %u isn't supported, min is %u\n",
+                spi->max_speed_hz, SPI_SPEED_MIN);
+        rc = -EINVAL;
+        goto err;
+    }
+
+    if (spi->max_speed_hz > SPI_SPEED_MAX) {
+        spi_warn(&spi->dev, "decreasing speed %u to max supported %u\n",
+                spi->max_speed_hz, SPI_SPEED_MAX);
+        spi->max_speed_hz = SPI_SPEED_MAX;
+    }
+
+    if (spi->chip_select > SPI_CHIP_SELECT_MAX) {
+        spi_err(&spi->dev, "chip select %u out of range 0..%u\n",
+                spi->max_speed_hz, SPI_CHIP_SELECT_MAX);
+        rc = -EINVAL;
+        goto err;
+    }
+
+    if (spi->mode & SPI_CS_HIGH) {
+        spi_err(&spi->dev, "chip select active high isn't supported\n");
+        rc = -EINVAL;
+        goto err;
+    }
+
+    if (spi->mode & SPI_LSB_FIRST) {
+        spi_err(&spi->dev, "LSB first mode isn't supported\n");
+        rc = -EINVAL;
+        goto err;
+    }
+
+err:
+    return rc;
+	return 0;
+}
+
+static void spi_set_control (struct comcerto_spi *xspi, struct spi_client_conf *cconf, struct comcerto_transfer *ct)
+{
+    u32 ctrlr0;
+    struct spi_master *master;
+    struct comcerto_spi_platform *pdata = (struct comcerto_spi_platform *)xspi->dev->dev.platform_data;
+    struct spi_client_conf *scc = (struct spi_client_conf *)pdata->devices->platform_data;
+
+    master = xspi->bitbang.master;
+
+    cconf->cs_msk = scc->cs_msk;
+    cconf->sc_polarity = scc->sc_polarity;
+    cconf->sc_phase = scc->sc_phase;
+    cconf->sc_rate = scc->sc_rate;
+    cconf->cs_delay = scc->cs_delay;
+
+    ctrlr0 = ((cconf->sc_polarity & 0x1) << 7) | ((cconf->sc_phase & 0x1) << 6) | (((ct->fs - 1) & 0xf) << 0);
+
+    ct->ctrlr0 = ctrlr0;
+    ct->mode = master->mode_bits;
+
+    /* FIXME: this will be fixed after clock PLL implementation done.*/
+    ct->baudr = pdata->clock_rate / cconf->sc_rate;
+    ct->ser = cconf->cs_msk & pdata->cs_msk;
+}
+
+int comcerto_spi_transfer(struct spi_device *spi,
+                        struct spi_message *mesg)
+{
+    struct spi_transfer     *t = NULL;
+    struct comcerto_transfer     ct;
+    struct spi_client_conf cconf;
+    int ret = 0;
+    struct comcerto_spi *xspi = spi_master_get_devdata(spi->master);
+
+    ct.fs = 8;
+
+    spi_set_control(xspi, &cconf, &ct);
+
+    list_for_each_entry (t, &mesg->transfers, transfer_list) {
+        ct.wbuf = (u8 *)t->tx_buf;
+        ct.rbuf = (u8 *)t->rx_buf;
+        ct.wlen = t->len;
+        ct.rlen = t->len;
+
+        ret = comcerto_spi_do_transfer(xspi, &cconf, &ct);
+
+        if (ret == -1)
+            return -1;
+    }
+
+    return 0;
+}
+
+static void comcerto_spi_hw_init(struct comcerto_spi *xspi)
+{
+    void __iomem *reg_base = xspi->regs;
+
+    /* enable SPI bus : FIXME */
+    //comcerto_gpio_ctrl(0x1 << 9, 0x1 << 9);
+
+
+    /* disable SPI operation */
+    writel(0, reg_base + COMCERTO_SPI_SSIENR);
+
+    /* mask all SPI irq's */
+    writel(0, reg_base + COMCERTO_SPI_IMR);
+}
+
+struct spi_master *comcerto_spi_init(struct platform_device *pdev, struct resource *mem,
+	u32 irq, s16 bus_num, int num_cs)
+{
+    struct device *dev = &pdev->dev;
+	struct spi_master *master;
+	struct comcerto_spi *xspi;
+
+	master = spi_alloc_master(dev, sizeof(struct comcerto_spi));
+	if (!master)
+		return NULL;
+
+	/* the spi->mode bits understood by this driver: */
+	master->mode_bits = SPI_CPOL | SPI_CPHA;
+
+	xspi = spi_master_get_devdata(master);
+    //memcpy(&(xspi->dev), pdev, sizeof(struct platform_device));
+    xspi->dev = pdev;
+	xspi->bitbang.master = spi_master_get(master);
+	xspi->bitbang.master->setup = comcerto_spi_setup;
+	xspi->bitbang.master->transfer = comcerto_spi_transfer;
+	xspi->bitbang.master->cleanup = NULL;
+
+	init_completion(&xspi->done);
+
+	if (!request_mem_region(mem->start, resource_size(mem),
+		comcerto_SPI_NAME))
+		goto put_master;
+
+	xspi->regs = ioremap(mem->start, resource_size(mem));
+	if (xspi->regs == NULL) {
+		dev_warn(dev, "ioremap failure\n");
+		goto map_failed;
+	}
+
+	master->bus_num = bus_num;
+	master->num_chipselect = num_cs;
+	master->dev.of_node = dev->of_node;
+
+	xspi->mem = *mem;
+	xspi->irq = irq;
+
+	xspi->do_read8 = do_read_only_transfer8;
+	xspi->do_write8 = do_write_only_transfer8;
+
+	xspi->do_read16 = do_read_only_transfer16;
+	xspi->do_write16 = do_write_only_transfer16;
+
+    xspi->do_write_read = do_write_read_transfer;
+
+	/* SPI controller initializations */
+	comcerto_spi_hw_init(xspi);
+
+	/* Register for SPI Interrupt : FIXME*/
+    /*
+	ret = request_irq(xspi->irq, comcerto_spi_irq, 0, comcerto_SPI_NAME, xspi);
+	if (ret)
+		goto unmap_io;
+    
+
+	ret = spi_bitbang_start(&xspi->bitbang);
+	if (ret) {
+		dev_err(dev, "spi_bitbang_start FAILED\n");
+		goto free_irq;
+	}
+    */
+	dev_info(dev, "at 0x%08llX mapped to 0x%p, irq=%d\n",
+		(unsigned long long)mem->start, xspi->regs, xspi->irq);
+	return master;
+
+/* FIXME */
+//free_irq:
+	//free_irq(xspi->irq, xspi);
+	//iounmap(xspi->regs);
+map_failed:
+	release_mem_region(mem->start, resource_size(mem));
+put_master:
+	spi_master_put(master);
+	return NULL;
+}
+EXPORT_SYMBOL(comcerto_spi_init);
+
+void comcerto_spi_deinit(struct spi_master *master)
+{
+	struct comcerto_spi *xspi;
+
+	xspi = spi_master_get_devdata(master);
+
+	//FIXME spi_bitbang_stop(&xspi->bitbang);
+	//free_irq(xspi->irq, xspi);
+	iounmap(xspi->regs);
+
+	release_mem_region(xspi->mem.start, resource_size(&xspi->mem));
+	spi_master_put(xspi->bitbang.master);
+
+     spi_unregister_master(master);
+}
+EXPORT_SYMBOL(comcerto_spi_deinit);
+
+static int __devinit comcerto_spi_probe(struct platform_device *dev)
+{
+	struct comcerto_spi_platform *pdata;
+	struct resource *r;
+	int irq, num_cs = 0;
+	struct spi_master *master;
+    int rc = -EINVAL;
+    int i;
+
+	pdata = (struct comcerto_spi_platform *)dev->dev.platform_data;
+
+	if (pdata) {
+		num_cs = pdata->num_chipselect;
+	}
+
+	if (!num_cs) {
+		dev_err(&dev->dev, "Missing slave select configuration data\n");
+		return -EINVAL;
+	}
+
+
+	r = platform_get_resource(dev, IORESOURCE_MEM, dev->num_resources);
+	if (!r)
+		return -ENODEV;
+
+	irq = platform_get_irq(dev, 0);
+	if (irq < 0)
+		return -ENXIO;
+
+	master = comcerto_spi_init(dev, r, irq, dev->id, num_cs);
+
+	if (!master)
+		return -ENODEV;
+
+	if (pdata) {
+		for (i = 0; i < pdata->num_devices; i++)
+			spi_new_device(master, pdata->devices + i);
+	}
+
+	platform_set_drvdata(dev, master);
+
+    rc = spi_register_master(master);
+
+    if (rc != 0) {
+        spi_err(&dev->dev, "error registering SPI master\n");
+        goto err1;
+    }
+
+	return 0;
+
+err1:
+    spi_master_put(master);
+
+    return rc;
+}
+
+static int __devexit comcerto_spi_remove(struct platform_device *dev)
+{
+	comcerto_spi_deinit(platform_get_drvdata(dev));
+
+	platform_set_drvdata(dev, 0);
+
+	return 0;
+}
+
+static struct platform_driver comcerto_spi_driver = {
+	.probe = comcerto_spi_probe,
+	.remove = __devexit_p(comcerto_spi_remove),
+	.driver = {
+		.name = comcerto_SPI_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init comcerto_spi_pltfm_init(void)
+{
+    printk(KERN_INFO "c2k-spi: %s: loaded version %s\n", __FUNCTION__, SPI_VERSION);
+
+	if(platform_driver_register(&comcerto_spi_driver)) {
+        printk(KERN_ERR "c2k-spi: %s: error registering driver\n", __FUNCTION__);
+        goto err0;
+    }
+
+    return 0;
+
+err0:
+    return -1;
+}
+module_init(comcerto_spi_pltfm_init);
+
+static void __exit comcerto_spi_pltfm_exit(void)
+{
+	platform_driver_unregister(&comcerto_spi_driver);
+}
+module_exit(comcerto_spi_pltfm_exit);
+
+MODULE_AUTHOR("Satendra Pratap");
+MODULE_DESCRIPTION("Mindspeed SPI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c
new file mode 100644
index 0000000..5e2046b
--- /dev/null
+++ b/drivers/spi/designware_spi.c
@@ -0,0 +1,793 @@
+/*
+ * designware_spi.c
+ *
+ * Synopsys DesignWare AMBA SPI controller driver (master mode only)
+ *
+ * Author: Baruch Siach, Tk Open Systems
+ *	baruch-NswTu9S1W3P6gbPvEgmw2w@...org
+ *
+ * Base on the Xilinx SPI controller driver by MontaVista
+ *
+ * 2002-2007 (c) MontaVista Software, Inc.  This file is licensed under the
+ * terms of the GNU General Public License version 2.  This program is licensed
+ * "as is" without any warranty of any kind, whether express or implied.
+ *
+ * 2008, 2009 (c) Provigent Ltd.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/designware.h>
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <mach/reset.h>
+
+#define DESIGNWARE_SPI_NAME "comcerto_spi"
+
+/* Register definitions as per "DesignWare DW_apb_ssi Databook", Capture 6. */
+
+#define DWSPI_CTRLR0        0x00
+#define DWSPI_CTRLR1        0x04
+#define DWSPI_SSIENR        0x08
+#define DWSPI_MWCR          0x0C
+#define DWSPI_SER           0x10
+#define DWSPI_BAUDR         0x14
+#define DWSPI_TXFTLR        0x18
+#define DWSPI_RXFTLR        0x1C
+#define DWSPI_TXFLR         0x20
+#define DWSPI_RXFLR         0x24
+#define DWSPI_SR            0x28
+#define DWSPI_IMR           0x2C
+#define DWSPI_ISR           0x30
+#define DWSPI_RISR          0x34
+#define DWSPI_TXOICR        0x38
+#define DWSPI_RXOICR        0x3C
+#define DWSPI_RXUICR        0x40
+#define DWSPI_ICR           0x44
+#define DWSPI_DMACR         0x4C
+#define DWSPI_DMATDLR       0x50
+#define DWSPI_DMARDLR       0x54
+#define DWSPI_IDR           0x58
+#define DWSPI_SSI_COMP_VERSION 0x5C
+#define DWSPI_DR            0x60
+
+#define DWSPI_CTRLR0_DFS_MASK	0x000f
+#define DWSPI_CTRLR0_SCPOL	0x0080
+#define DWSPI_CTRLR0_SCPH	0x0040
+#define DWSPI_CTRLR0_TMOD_MASK	0x0300
+
+#define DWSPI_SR_BUSY_MASK	0x01
+#define DWSPI_SR_TFNF_MASK	0x02
+#define DWSPI_SR_TFE_MASK	0x04
+#define DWSPI_SR_RFNE_MASK	0x08
+#define DWSPI_SR_RFF_MASK	0x10
+
+#define DWSPI_ISR_TXEIS_MASK	0x01
+#define DWSPI_ISR_RXFIS_MASK	0x10
+
+#define DWSPI_IMR_TXEIM_MASK	0x01
+#define DWSPI_IMR_RXFIM_MASK	0x10
+
+struct designware_spi {
+	struct device *dev;
+	struct workqueue_struct *workqueue;
+	struct work_struct   work;
+
+	struct tasklet_struct pump_transfers;
+
+	struct mutex         lock; /* lock this struct except from queue */
+	struct list_head     queue; /* spi_message queue */
+	spinlock_t           qlock; /* lock the queue */
+
+	void __iomem	*regs;	/* virt. address of the control registers */
+	unsigned int ssi_clk;	/* clock in Hz */
+	unsigned int tx_fifo_depth; /* bytes in TX FIFO */
+	unsigned int rx_fifo_depth; /* bytes in RX FIFO */
+
+	u32		irq;
+
+	u8 bits_per_word;	/* current data frame size */
+	struct spi_transfer *tx_t; /* current tx transfer */
+	struct spi_transfer *rx_t; /* current rx transfer */
+	const u8 *tx_ptr;       /* current tx buffer */
+	u8 *rx_ptr;             /* current rx buffer */
+	int remaining_tx_bytes;	/* bytes left to tx in the current transfer */
+	int remaining_rx_bytes;	/* bytes left to rx in the current transfer */
+	int status;             /* status of the current spi_transfer */
+
+	struct completion done; /* signal the end of tx for current sequence */
+
+	struct spi_device *spi; /* current spi slave device */
+	struct clk	*clk_spi;
+	struct list_head *transfers_list; /* head of the current sequence */
+	unsigned int tx_count, rx_count; /* bytes in the current sequence */
+};
+
+static void dwspi_init_hw(struct designware_spi *dwspi)
+{
+	u16 ctrlr0;
+
+	/* Disable the SPI master */
+	writel(0, dwspi->regs + DWSPI_SSIENR);
+	/* Disable all the interrupts just in case */
+	writel(0, dwspi->regs + DWSPI_IMR);
+	/* Set TX empty IRQ threshold */
+	writew(dwspi->tx_fifo_depth / 2, dwspi->regs + DWSPI_TXFTLR);
+
+    /* Set transmit & receive mode */
+	ctrlr0 = readw(dwspi->regs + DWSPI_CTRLR0);
+    ctrlr0 &= ~DWSPI_CTRLR0_TMOD_MASK;
+	writew(ctrlr0, dwspi->regs + DWSPI_CTRLR0);
+}
+
+static void dwspi_baudcfg(struct designware_spi *dwspi, u32 speed_hz)
+{
+	u16 div = (speed_hz) ? dwspi->ssi_clk/speed_hz : 0xffff;
+
+	writew(div, dwspi->regs + DWSPI_BAUDR);
+}
+
+static void dwspi_enable(struct designware_spi *dwspi, int on)
+{
+	writel(on ? 1 : 0, dwspi->regs + DWSPI_SSIENR);
+}
+
+static void designware_spi_chipselect(struct spi_device *spi, int on)
+{
+	struct designware_spi *dwspi = spi_master_get_devdata(spi->master);
+#if 0
+	long gpio = (long) spi->controller_data;
+	unsigned active = spi->mode & SPI_CS_HIGH;
+#endif
+	/*
+	 * Note, the SPI controller must have been enabled at this point, i.e.
+	 * SSIENR == 1
+	 */
+
+	if (on) {
+	#if 0
+
+		/* Turn the actual chip select on for GPIO chip selects */
+		if (gpio >= 0)
+			gpio_set_value(gpio, active);
+	#endif
+		/* Activate slave on the SPI controller */
+		writel(1 << spi->chip_select, dwspi->regs + DWSPI_SER);
+	} else {
+		/* Deselect the slave on the SPI bus */
+		writel(0, dwspi->regs + DWSPI_SER);
+	#if 0
+		if (gpio >= 0)
+			gpio_set_value(gpio, !active);
+	#endif
+	}
+}
+
+static int designware_spi_setup_transfer(struct spi_device *spi,
+		struct spi_transfer *t)
+{
+	u8 bits_per_word;
+	u32 hz;
+	struct designware_spi *dwspi = spi_master_get_devdata(spi->master);
+	u16 ctrlr0 = readw(dwspi->regs + DWSPI_CTRLR0);
+
+	bits_per_word = (t) ? (t->bits_per_word ? t->bits_per_word : spi->bits_per_word) : spi->bits_per_word;
+	hz = (t) ? (t->speed_hz ? t->speed_hz : spi->max_speed_hz) : spi->max_speed_hz;
+
+	if (bits_per_word < 4 || bits_per_word > 16) {
+		dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
+			__func__, bits_per_word);
+		return -EINVAL;
+	} else {
+		ctrlr0 &= ~DWSPI_CTRLR0_DFS_MASK;
+		ctrlr0 |= bits_per_word - 1;
+
+		dwspi->bits_per_word = bits_per_word;
+	}
+
+	/* Set the SPI clock phase and polarity */
+	if (spi->mode & SPI_CPHA)
+		ctrlr0 |= DWSPI_CTRLR0_SCPH;
+	else
+		ctrlr0 &= ~DWSPI_CTRLR0_SCPH;
+	if (spi->mode & SPI_CPOL)
+		ctrlr0 |= DWSPI_CTRLR0_SCPOL;
+	else
+		ctrlr0 &= ~DWSPI_CTRLR0_SCPOL;
+
+	writew(ctrlr0, dwspi->regs + DWSPI_CTRLR0);
+
+	/* set speed */
+	dwspi_baudcfg(dwspi, hz);
+
+	return 0;
+}
+
+/* the spi->mode bits currently understood by this driver: */
+#define MODEBITS (SPI_CPOL | SPI_CPHA)
+
+static int designware_spi_setup(struct spi_device *spi)
+{
+	struct designware_spi *dwspi;
+	int retval;
+
+	dwspi = spi_master_get_devdata(spi->master);
+
+	if (!spi->bits_per_word)
+		spi->bits_per_word = 8;
+
+	if (spi->mode & ~MODEBITS) {
+		dev_err(&spi->dev, "%s, SP unsupported mode bits %x\n",
+			__func__, spi->mode & ~MODEBITS);
+		return -EINVAL;
+	}
+
+	if (spi->chip_select > spi->master->num_chipselect) {
+		dev_err(&spi->dev,
+				"setup: invalid chipselect %u (%u defined)\n",
+				spi->chip_select, spi->master->num_chipselect);
+		return -EINVAL;
+	}
+
+	retval = designware_spi_setup_transfer(spi, NULL);
+	if (retval < 0)
+		return retval;
+
+	dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n",
+		__func__, spi->mode & MODEBITS, spi->bits_per_word, 0);
+
+	return 0;
+}
+
+static void designware_spi_do_tx(struct designware_spi *dwspi)
+{
+	u8 sr;
+	int bytes_to_tx = dwspi->remaining_tx_bytes;
+	u8 valid_tx_fifo_bytes = readb(dwspi->regs + DWSPI_TXFLR);
+	u8 valid_rx_fifo_bytes = readb(dwspi->regs + DWSPI_RXFLR);
+	int tx_limit = min(dwspi->tx_fifo_depth - valid_tx_fifo_bytes,\
+			dwspi->rx_fifo_depth - valid_rx_fifo_bytes);
+
+	/* Fill the Tx FIFO with as many bytes as possible */
+	sr = readb(dwspi->regs + DWSPI_SR);
+	while ((sr & DWSPI_SR_TFNF_MASK) && dwspi->remaining_tx_bytes > 0) {
+		if (dwspi->bits_per_word <= 8) {
+			u8 dr = (dwspi->tx_ptr) ? *dwspi->tx_ptr++ : 0;
+
+			writeb(dr, dwspi->regs + DWSPI_DR);
+			dwspi->remaining_tx_bytes--;
+		} else {
+			u16 dr = (dwspi->tx_ptr) ? *(u16 *) dwspi->tx_ptr : 0;
+
+			dwspi->tx_ptr += 2;
+			writew(dr, dwspi->regs + DWSPI_DR);
+			dwspi->remaining_tx_bytes -= 2;
+		}
+
+		if(dwspi->bits_per_word <= 8){
+			--tx_limit;
+		}else{
+			tx_limit -= 2;
+		}
+
+		if (tx_limit <= 0)
+			break;
+
+		sr = readb(dwspi->regs + DWSPI_SR);
+	}
+
+	dwspi->tx_count += bytes_to_tx - dwspi->remaining_tx_bytes;
+}
+
+/* Return 1 when done, 0 otherwise */
+static int designware_spi_fill_tx_fifo(struct designware_spi *dwspi)
+{
+	unsigned cs_change = 0;
+	unsigned int ser;
+
+	ser = readw(dwspi->regs + DWSPI_SER);
+
+	list_for_each_entry_from(dwspi->tx_t, dwspi->transfers_list,
+		transfer_list) {
+		if (dwspi->remaining_tx_bytes == 0) {
+			/* Initialize new spi_transfer */
+			dwspi->tx_ptr = dwspi->tx_t->tx_buf;
+			dwspi->remaining_tx_bytes = dwspi->tx_t->len;
+			dwspi->status = 0;
+
+			if (!dwspi->tx_t->tx_buf && !dwspi->tx_t->rx_buf
+					&& dwspi->tx_t->len) {
+				dwspi->status = -EINVAL;
+				break;
+			}
+
+			if (cs_change)
+				break;
+		}
+
+		designware_spi_do_tx(dwspi);
+
+		/* Don't advance dwspi->tx_t, we'll get back to this
+		 * spi_transfer later
+		 */
+		if (dwspi->remaining_tx_bytes > 0)
+		{
+			return 0;
+		}
+
+		cs_change = dwspi->tx_t->cs_change;
+	}
+
+	complete(&dwspi->done);
+
+	return 1;
+}
+
+static void designware_spi_do_rx(struct designware_spi *dwspi)
+{
+	u8 sr;
+	int bytes_to_rx = dwspi->remaining_rx_bytes;
+
+	sr = readb(dwspi->regs + DWSPI_SR);
+
+	if (sr & DWSPI_SR_RFF_MASK) {
+	#if 0
+		dev_err(dwspi->dev, "%s: RX FIFO overflow\n", __func__);
+		dwspi->status = -EIO;
+	#endif
+	}
+
+	/* Read as long as RX FIFO is not empty */
+	while ((sr & DWSPI_SR_RFNE_MASK) != 0
+			&& dwspi->remaining_rx_bytes > 0) {
+		int rx_level = readl(dwspi->regs + DWSPI_RXFLR);
+
+		while (rx_level-- && dwspi->remaining_rx_bytes > 0) {
+			if (dwspi->bits_per_word <= 8) {
+				u8 data;
+
+				data = readb(dwspi->regs + DWSPI_DR);
+				dwspi->remaining_rx_bytes--;
+				if (dwspi->rx_ptr)
+					*dwspi->rx_ptr++ = data;
+			} else {
+				u16 data;
+
+				data = readw(dwspi->regs + DWSPI_DR);
+				dwspi->remaining_rx_bytes -= 2;
+				if (dwspi->rx_ptr) {
+					*(u16 *) dwspi->rx_ptr = data;
+					dwspi->rx_ptr += 2;
+				}
+			}
+		}
+		sr = readb(dwspi->regs + DWSPI_SR);
+	}
+
+	dwspi->rx_count += (bytes_to_rx - dwspi->remaining_rx_bytes);
+}
+
+/* return 1 if cs_change is true, 0 otherwise */
+static int designware_spi_read_rx_fifo(struct designware_spi *dwspi)
+{
+	unsigned cs_change = 0;
+	unsigned int ser;
+
+	ser = readw(dwspi->regs + DWSPI_SER);
+
+	list_for_each_entry_from(dwspi->rx_t, dwspi->transfers_list,
+			transfer_list) {
+		if (dwspi->remaining_rx_bytes == 0) {
+			dwspi->rx_ptr = dwspi->rx_t->rx_buf;
+			dwspi->remaining_rx_bytes = dwspi->rx_t->len;
+
+			if (cs_change)
+				return 1;
+		}
+
+		designware_spi_do_rx(dwspi);
+
+		/* The rx buffer is filling up with more bytes. Don't advance
+		 * dwspi->rx_t, as we have more bytes to read in this
+		 * spi_transfer.
+		 */
+		if (dwspi->remaining_rx_bytes > 0)
+			return 0;
+
+		cs_change = dwspi->rx_t->cs_change;
+	}
+
+	return 0;
+}
+
+/* interate through the list of spi_transfer elements.
+ * stop at the end of the list or when t->cs_change is true.
+ */
+static void designware_spi_do_transfers(struct designware_spi *dwspi)
+{
+	int tx_done, cs_change;
+
+	init_completion(&dwspi->done);
+
+	/* transfer kickoff */
+	tx_done = designware_spi_fill_tx_fifo(dwspi);
+	designware_spi_chipselect(dwspi->spi, 1);
+
+	if (!tx_done) {
+		/* Enable the transmit empty interrupt, which we use to
+		 * determine progress on the transmission in case we're
+		 * not done yet.
+		 */
+		writeb(DWSPI_IMR_TXEIM_MASK, dwspi->regs + DWSPI_IMR);
+
+		/* wait for tx completion */
+		wait_for_completion(&dwspi->done);
+	}
+
+	/* This delay should be good enough for 100KHz spi transfers. Slower
+	 * transfers may need a longer delay.
+	 */
+	udelay(10);
+
+	/* get remaining rx bytes */
+    do {
+		cs_change = designware_spi_read_rx_fifo(dwspi);
+	} while (readb(dwspi->regs + DWSPI_SR) &
+			(DWSPI_SR_BUSY_MASK | DWSPI_SR_RFNE_MASK));
+
+	/* transaction is done */
+	designware_spi_chipselect(dwspi->spi, 0);
+
+	if (dwspi->status < 0)
+		return;
+
+	if (!cs_change && (dwspi->remaining_rx_bytes > 0 ||
+			dwspi->remaining_tx_bytes > 0)) {
+	#if 0
+		dev_err(dwspi->dev, "%s: remaining_rx_bytes = %d, "
+				"remaining_tx_bytes = %d\n",
+				__func__,  dwspi->remaining_rx_bytes,
+				dwspi->remaining_tx_bytes);
+	#endif
+		dwspi->status = -EIO;
+    }
+
+	if (dwspi->rx_count != dwspi->tx_count) {
+	#if 0
+		dev_err(dwspi->dev, "%s: rx_count == %d, tx_count == %d\n",
+				__func__, dwspi->rx_count, dwspi->tx_count);
+	#endif
+		dwspi->status = -EIO;
+    }
+}
+
+static int designware_spi_transfer(struct spi_device *spi,
+		struct spi_message *mesg)
+{
+	struct designware_spi *dwspi = spi_master_get_devdata(spi->master);
+
+	mesg->actual_length = 0;
+	mesg->status = -EINPROGRESS;
+
+	/* we can't block here, so we use a spinlock
+	 * here instead of the global mutex
+	 */
+	spin_lock(&dwspi->qlock);
+	list_add_tail(&mesg->queue, &dwspi->queue);
+	queue_work(dwspi->workqueue, &dwspi->work);
+	spin_unlock(&dwspi->qlock);
+
+	return 0;
+}
+
+static void designware_work(struct work_struct *work)
+{
+	struct designware_spi *dwspi = container_of(work,
+			struct designware_spi, work);
+
+	mutex_lock(&dwspi->lock);
+	spin_lock(&dwspi->qlock);
+
+	while (!list_empty(&dwspi->queue)) {
+		struct spi_message *m;
+
+		m = container_of(dwspi->queue.next, struct spi_message, queue);
+		list_del_init(&m->queue);
+		spin_unlock(&dwspi->qlock);
+
+		dwspi->spi = m->spi;
+		dwspi->tx_t = dwspi->rx_t =
+			list_first_entry(&m->transfers, struct spi_transfer,
+					transfer_list);
+
+		/*
+		 * Interate through groups of spi_transfer structs
+		 * that are separated by cs_change being true
+		 */
+		dwspi->transfers_list = &m->transfers;
+		do {
+			dwspi->remaining_tx_bytes =
+				dwspi->remaining_rx_bytes = 0;
+			dwspi->tx_count = dwspi->rx_count = 0;
+			designware_spi_setup_transfer(m->spi, dwspi->tx_t);
+			dwspi_enable(dwspi, 1);
+			designware_spi_do_transfers(dwspi);
+			dwspi_enable(dwspi, 0);
+			if (dwspi->status < 0)
+				break;
+			m->actual_length +=
+				dwspi->tx_count; /* same as rx_count */
+		} while (&dwspi->tx_t->transfer_list != &m->transfers);
+
+		m->status = dwspi->status;
+		m->complete(m->context);
+		spin_lock(&dwspi->qlock);
+	}
+	spin_unlock(&dwspi->qlock);
+	mutex_unlock(&dwspi->lock);
+}
+
+static void designware_pump_transfers(unsigned long data)
+{
+	struct designware_spi *dwspi = (struct designware_spi *) data;
+
+	designware_spi_read_rx_fifo(dwspi);
+	if (!designware_spi_fill_tx_fifo(dwspi))
+		/* reenable the interrupt */
+		writeb(DWSPI_IMR_TXEIM_MASK, dwspi->regs + DWSPI_IMR);
+}
+
+static irqreturn_t designware_spi_irq(int irq, void *dev_id)
+{
+	struct designware_spi *dwspi = dev_id;
+
+	tasklet_schedule(&dwspi->pump_transfers);
+	/* disable the interrupt for now */
+	writeb(0, dwspi->regs + DWSPI_IMR);
+
+	return IRQ_HANDLED;
+}
+
+static void designware_spi_cleanup(struct spi_device *spi)
+{
+}
+
+static int __init designware_spi_probe(struct platform_device *dev)
+{
+	int ret = 0;
+	struct spi_master *master;
+	struct designware_spi *dwspi;
+	//struct designware_platform_data *pdata;
+	struct spi_controller_pdata *pdata;
+	struct resource *r;
+	struct clk *clk_spi;
+
+	pdata = dev->dev.platform_data;
+	if (pdata == NULL) {
+		dev_err(&dev->dev, "no device data specified\n");
+		return -EINVAL;
+	}
+
+        if(memcmp(pdata->clk_name, "DUS", 3))
+                c2000_block_reset(COMPONENT_AXI_LEGACY_SPI, 0);
+        else
+                c2000_block_reset(COMPONENT_AXI_FAST_SPI, 0);
+
+	clk_spi = clk_get(NULL,pdata->clk_name);
+	if (IS_ERR(clk_spi)) {
+		ret = PTR_ERR(clk_spi);
+		pr_err("%s:Unable to obtain spi clock: %d\n",\
+				__func__, ret);
+		goto err_clk;
+	}
+
+	clk_enable(clk_spi);
+
+	printk ("%s:Initializing SPI Controller : Using dma=%d CLK(%s)=%ld Hz\n", __func__, \
+			pdata->use_dma, pdata->clk_name, clk_get_rate(clk_spi));
+
+	/* Get resources(memory, IRQ) associated with the device */
+	master = spi_alloc_master(&dev->dev, sizeof(struct designware_spi));
+	if (master == NULL) {
+		ret = -ENOMEM;
+		goto err_nomem;
+	}
+
+	master->mode_bits = SPI_CPOL | SPI_CPHA;
+	master->bus_num = pdata->bus_num;
+	master->num_chipselect = pdata->num_chipselects;
+	master->setup = designware_spi_setup;
+	master->transfer = designware_spi_transfer;
+	master->cleanup = designware_spi_cleanup;
+	platform_set_drvdata(dev, master);
+
+	r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	if (r == NULL) {
+		ret = -ENODEV;
+		goto put_master;
+	}
+
+	dwspi = spi_master_get_devdata(master);
+	dwspi->clk_spi = clk_spi;
+	dwspi->ssi_clk = clk_get_rate(dwspi->clk_spi);
+	//dwspi->ssi_clk = pdata->max_freq;
+	dwspi->tx_fifo_depth = TX_FIFO_DEPTH;
+	dwspi->rx_fifo_depth = RX_FIFO_DEPTH;
+#if 0
+	dwspi->tx_fifo_depth = pdata->tx_fifo_depth;
+	dwspi->rx_fifo_depth = pdata->rx_fifo_depth;
+#endif
+	dwspi->dev = &dev->dev;
+	spin_lock_init(&dwspi->qlock);
+	mutex_init(&dwspi->lock);
+	INIT_LIST_HEAD(&dwspi->queue);
+	INIT_WORK(&dwspi->work, designware_work);
+	dwspi->workqueue =
+		create_singlethread_workqueue(dev_name(master->dev.parent));
+	
+	if (dwspi->workqueue == NULL) {
+		ret = -EBUSY;
+		goto put_master;
+	}
+	tasklet_init(&dwspi->pump_transfers, designware_pump_transfers,
+			(unsigned long) dwspi);
+
+	if (!request_mem_region(r->start,
+			r->end - r->start + 1, DESIGNWARE_SPI_NAME)) {
+		ret = -ENXIO;
+		goto destroy_wq;
+	}
+
+	dwspi->regs = ioremap(r->start, r->end - r->start + 1);
+	if (dwspi->regs == NULL) {
+		ret = -ENOMEM;
+		goto destroy_wq;
+	}
+
+	dwspi->irq = platform_get_irq(dev, 0);
+	if (dwspi->irq < 0) {
+		ret = -ENXIO;
+		goto unmap_io;
+	}
+
+	/* SPI controller initializations */
+	dwspi_init_hw(dwspi);
+
+	/* Register for SPI Interrupt */
+	ret = request_irq(dwspi->irq, designware_spi_irq, 0,
+			DESIGNWARE_SPI_NAME, dwspi);
+	if (ret != 0)
+		goto unmap_io;
+
+	ret = spi_register_master(master);
+    if (ret < 0)
+		goto free_irq;
+
+	dev_info(&dev->dev, "at 0x%08X mapped to 0x%08X, irq=%d\n",
+			r->start, (u32)dwspi->regs, dwspi->irq);
+
+	return ret;
+
+free_irq:
+	free_irq(dwspi->irq, dwspi);
+unmap_io:
+	iounmap(dwspi->regs);
+destroy_wq:
+	destroy_workqueue(dwspi->workqueue);
+put_master:
+	spi_master_put(master);
+err_nomem:
+	clk_disable(clk_spi);
+	clk_put(clk_spi);
+err_clk:
+        if(memcmp(pdata->clk_name, "DUS", 3))
+                c2000_block_reset(COMPONENT_AXI_LEGACY_SPI, 1);
+        else
+                c2000_block_reset(COMPONENT_AXI_FAST_SPI, 1);
+
+	return ret;
+}
+
+static int __devexit designware_spi_remove(struct platform_device *dev)
+{
+	struct designware_spi *dwspi;
+	struct spi_master *master;
+	struct spi_controller_pdata *pdata;
+
+	master = platform_get_drvdata(dev);
+	dwspi = spi_master_get_devdata(master);
+
+	free_irq(dwspi->irq, dwspi);
+	iounmap(dwspi->regs);
+	destroy_workqueue(dwspi->workqueue);
+	tasklet_kill(&dwspi->pump_transfers);
+	platform_set_drvdata(dev, 0);
+	spi_master_put(master);
+	clk_disable(dwspi->clk_spi);
+	clk_put(dwspi->clk_spi);
+
+        pdata = dev->dev.platform_data;
+        if(!pdata)
+        {
+                return -EINVAL;
+        }
+
+        if(memcmp(pdata->clk_name, "DUS", 3))
+                c2000_block_reset(COMPONENT_AXI_LEGACY_SPI, 1);
+        else
+                c2000_block_reset(COMPONENT_AXI_FAST_SPI, 1);
+
+	return 0;
+}
+
+#if CONFIG_PM
+static int designware_spi_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct designware_spi *dwspi;
+	struct spi_master *master;
+
+	master = platform_get_drvdata(pdev);
+	dwspi = spi_master_get_devdata(master);
+
+        /* Disable the SPI master */
+        writel(0, dwspi->regs + DWSPI_SSIENR);
+
+        clk_disable(dwspi->clk_spi);
+
+        return 0;
+
+}
+
+static int designware_spi_resume(struct platform_device *pdev)
+{
+	struct designware_spi *dwspi;
+	struct spi_master *master;
+
+	master = platform_get_drvdata(pdev);
+	dwspi = spi_master_get_devdata(master);
+
+        clk_enable(dwspi->clk_spi);
+	dwspi_init_hw(dwspi);
+
+        return 0;
+}
+#endif
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:" DESIGNWARE_SPI_NAME);
+
+static struct platform_driver designware_spi_driver = {
+	.probe  = designware_spi_probe,
+	.remove	= __devexit_p(designware_spi_remove),
+#if CONFIG_PM
+        .suspend        = designware_spi_suspend,
+        .resume         = designware_spi_resume,
+#endif
+	.driver = {
+		.name = DESIGNWARE_SPI_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init designware_spi_init(void)
+{
+	return platform_driver_register(&designware_spi_driver);
+}
+module_init(designware_spi_init);
+
+static void __exit designware_spi_exit(void)
+{
+	platform_driver_unregister(&designware_spi_driver);
+}
+module_exit(designware_spi_exit);
+
+MODULE_AUTHOR("Baruch Siach <baruch-NswTu9S1W3P6gbPvEgmw2w@...org>");
+MODULE_DESCRIPTION("Synopsys DesignWare SPI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-c2000-dma.c b/drivers/spi/spi-c2000-dma.c
new file mode 100644
index 0000000..3292922
--- /dev/null
+++ b/drivers/spi/spi-c2000-dma.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2012, Mindspeed Technologies.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+
+#include "spi-dw.h"
+
+#include "spi-c2000-dma.h"
+
+struct spi_dma {
+        struct spi_dma_slave      dmas_tx;
+        struct spi_dma_slave      dmas_rx;
+};
+
+/* optional */
+static bool spi_dma_chan_filter(struct dma_chan *chan, void *param)
+{
+        struct dw_spi *dws = param;
+
+        return dws->master && (&dws->master->dev == chan->device->dev);
+}
+
+static int spi_dma_init(struct dw_spi *dws)
+{
+        struct spi_dma *dw_dma = dws->dma_priv;
+        struct spi_dma_slave *rxs, *txs;
+        dma_cap_mask_t mask;
+
+        dma_cap_zero(mask);
+        dma_cap_set(DMA_SLAVE, mask);
+
+        /* 1. Init rx channel */
+        dws->rxchan = dma_request_channel(mask, spi_dma_chan_filter, dws);
+        if (!dws->rxchan)
+                goto err_exit;
+        rxs = &dw_dma->dmas_rx;
+        rxs->hs_mode = LNW_DMA_HW_HS;
+        rxs->cfg_mode = LNW_DMA_PER_TO_MEM;
+        dws->rxchan->private = rxs;
+
+        /* 2. Init tx channel */
+        dws->txchan = dma_request_channel(mask, spi_dma_chan_filter, dws);
+        if (!dws->txchan)
+                goto free_rxchan;
+        txs = &dw_dma->dmas_tx;
+        txs->hs_mode = LNW_DMA_HW_HS;
+        txs->cfg_mode = LNW_DMA_MEM_TO_PER;
+        dws->txchan->private = txs;
+
+        dws->dma_inited = 1;
+        return 0;
+
+free_rxchan:
+        dma_release_channel(dws->rxchan);
+err_exit:
+        return -1;
+
+}
+
+static void spi_dma_exit(struct dw_spi *dws)
+{
+        dma_release_channel(dws->txchan);
+        dma_release_channel(dws->rxchan);
+}
+
+/*
+ * dws->dma_chan_done is cleared before the dma transfer starts,
+ * callback for rx/tx channel will each increment it by 1.
+ * Reaching 2 means the whole spi transaction is done.
+ */
+static void dw_spi_dma_done(void *arg)
+{
+        struct dw_spi *dws = arg;
+
+        if (++dws->dma_chan_done != 2)
+                return;
+        dw_spi_xfer_done(dws);
+}
+
+static int spi_dma_transfer(struct dw_spi *dws, int cs_change)
+{
+        struct dma_async_tx_descriptor *txdesc = NULL, *rxdesc = NULL;
+        struct dma_chan *txchan, *rxchan;
+        struct dma_slave_config txconf, rxconf;
+        u16 dma_ctrl = 0;
+
+        /* 1. setup DMA related registers */
+        if (cs_change) {
+                spi_enable_chip(dws, 0);
+                dw_writew(dws, DW_SPI_DMARDLR, 0xf);
+                dw_writew(dws, DW_SPI_DMATDLR, 0x10);
+                if (dws->tx_dma)
+                        dma_ctrl |= 0x2;
+                if (dws->rx_dma)
+                        dma_ctrl |= 0x1;
+                dw_writew(dws, DW_SPI_DMACR, dma_ctrl);
+                spi_enable_chip(dws, 1);
+        }
+
+        dws->dma_chan_done = 0;
+        txchan = dws->txchan;
+        rxchan = dws->rxchan;
+
+        /* 2. Prepare the TX dma transfer */
+        txconf.direction = DMA_TO_DEVICE;
+        txconf.dst_addr = dws->dma_addr;
+        txconf.dst_maxburst = LNW_DMA_MSIZE_16;
+        txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+        txconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+
+        txchan->device->device_control(txchan, DMA_SLAVE_CONFIG,
+                                       (unsigned long) &txconf);
+
+        memset(&dws->tx_sgl, 0, sizeof(dws->tx_sgl));
+        dws->tx_sgl.dma_address = dws->tx_dma;
+        dws->tx_sgl.length = dws->len;
+
+        txdesc = txchan->device->device_prep_slave_sg(txchan,
+                                &dws->tx_sgl,
+                                1,
+                                DMA_TO_DEVICE,
+                                DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_DEST_UNMAP);
+        txdesc->callback = dw_spi_dma_done;
+        txdesc->callback_param = dws;
+
+        /* 3. Prepare the RX dma transfer */
+        rxconf.direction = DMA_FROM_DEVICE;
+        rxconf.src_addr = dws->dma_addr;
+        rxconf.src_maxburst = LNW_DMA_MSIZE_16;
+        rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+        rxconf.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+
+        rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG,
+                                       (unsigned long) &rxconf);
+
+        memset(&dws->rx_sgl, 0, sizeof(dws->rx_sgl));
+        dws->rx_sgl.dma_address = dws->rx_dma;
+        dws->rx_sgl.length = dws->len;
+
+        rxdesc = rxchan->device->device_prep_slave_sg(rxchan,
+                                &dws->rx_sgl,
+                                1,
+                                DMA_FROM_DEVICE,
+                                DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_DEST_UNMAP);
+        rxdesc->callback = dw_spi_dma_done;
+        rxdesc->callback_param = dws;
+
+        /* rx must be started before tx due to spi instinct */
+        rxdesc->tx_submit(rxdesc);
+        txdesc->tx_submit(txdesc);
+        return 0;
+}
+
+static struct dw_spi_dma_ops spi_dma_ops = {
+        .dma_init       = spi_dma_init,
+        .dma_exit       = spi_dma_exit,
+        .dma_transfer   = spi_dma_transfer,
+};
+
+int dw_spi_dma_init(struct dw_spi *dws)
+{
+        dws->dma_priv = kzalloc(sizeof(struct spi_dma), GFP_KERNEL);
+        if (!dws->dma_priv)
+                return -ENOMEM;
+
+        dws->dma_ops = &spi_dma_ops;
+
+        return 0;
+}
diff --git a/drivers/spi/spi-c2000-dma.h b/drivers/spi/spi-c2000-dma.h
new file mode 100644
index 0000000..751daea
--- /dev/null
+++ b/drivers/spi/spi-c2000-dma.h
@@ -0,0 +1,74 @@
+/*
+ *  spi-c2000-dma.h 
+ *
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *
+ */
+#ifndef __SPI_C2000_DMA_H__
+#define __SPI_C2000_DMA_H___
+
+#include <linux/dmaengine.h>
+
+#define DMA_PREP_CIRCULAR_LIST		(1 << 10)
+
+/*DMA mode configurations*/
+enum spi_dma_mode {
+	LNW_DMA_PER_TO_MEM = 0, /*periphral to memory configuration*/
+	LNW_DMA_MEM_TO_PER,	/*memory to periphral configuration*/
+	LNW_DMA_MEM_TO_MEM,	/*mem to mem confg (testing only)*/
+};
+
+/*DMA handshaking*/
+enum spi_dma_hs_mode {
+	LNW_DMA_HW_HS = 0,	/*HW Handshaking only*/
+	LNW_DMA_SW_HS = 1,	/*SW Handshaking not recommended*/
+};
+
+/*Burst size configuration*/
+enum spi_dma_msize {
+	LNW_DMA_MSIZE_1 = 0x0,
+	LNW_DMA_MSIZE_4 = 0x1,
+	LNW_DMA_MSIZE_8 = 0x2,
+	LNW_DMA_MSIZE_16 = 0x3,
+	LNW_DMA_MSIZE_32 = 0x4,
+	LNW_DMA_MSIZE_64 = 0x5,
+};
+
+/**
+ * struct spi_dma_slave - DMA slave structure
+ *
+ * @dirn: DMA trf direction
+ * @src_width: tx register width
+ * @dst_width: rx register width
+ * @hs_mode: HW/SW handshaking mode
+ * @cfg_mode: DMA data transfer mode (per-per/mem-per/mem-mem)
+ * @src_msize: Source DMA burst size
+ * @dst_msize: Dst DMA burst size
+ * @per_addr: Periphral address
+ * @device_instance: DMA peripheral device instance, we can have multiple
+ *		peripheral device connected to single DMAC
+ */
+struct spi_dma_slave {
+	enum spi_dma_hs_mode	hs_mode;  /*handshaking*/
+	enum spi_dma_mode		cfg_mode; /*mode configuration*/
+	unsigned int		device_instance; /*0, 1 for periphral instance*/
+	struct dma_slave_config		dma_slave;
+};
+
+#endif /*__SPI_C2000_DMA_H__*/
diff --git a/drivers/spi/spi-c2000.c b/drivers/spi/spi-c2000.c
new file mode 100644
index 0000000..c970a3d
--- /dev/null
+++ b/drivers/spi/spi-c2000.c
@@ -0,0 +1,214 @@
+/*
+ * Memory-mapped interface driver for DW SPI Core
+ * Author: Satendra Pratap <satendra.pratap@gmail.com>
+ * Copyright (c) 2012, Mindspeed Technologies.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/scatterlist.h>
+#include <linux/module.h>
+#include <mach/reset.h>
+
+#include "spi-dw.h"
+
+#define DRIVER_NAME "comcerto_spi"
+
+extern int dw_spi_dma_init(struct dw_spi *dws);
+
+#define	CLK_NAME	10
+struct spi_controller_pdata {
+        int use_dma;
+        int num_chipselects;
+	int bus_num;
+	u32 max_freq;
+	char clk_name[CLK_NAME];
+};
+
+struct dw_spi_c2000 {
+	struct dw_spi  dws;
+};
+
+static int __devinit dw_spi_c2000_probe(struct platform_device *pdev)
+{
+	struct dw_spi_c2000 *dwsmmio;
+	struct dw_spi *dws;
+	struct resource *mem, *ioarea;
+	struct spi_controller_pdata *pdata;
+	struct clk *clk_spi;
+	int ret;
+
+	pdata = pdev->dev.platform_data;
+	if(!pdata)
+	{
+		ret = -EINVAL;
+		goto err_end;
+	}
+
+	dwsmmio = kzalloc(sizeof(struct dw_spi_c2000), GFP_KERNEL);
+	if (!dwsmmio) {
+		ret = -ENOMEM;
+		goto err_end;
+	}
+
+	dws = &dwsmmio->dws;
+
+	clk_spi = clk_get(NULL,pdata->clk_name);
+	if (IS_ERR(clk_spi)) {
+		ret = PTR_ERR(clk_spi);
+		pr_err("%s:Unable to obtain spi clock: %d\n",\
+			__func__, ret);
+		goto err_kfree;
+	}
+	dws->clk_spi=clk_spi;
+
+	dws->max_freq = clk_get_rate(dws->clk_spi);
+
+	printk ("%s:Initializing SPI Controller : use_dma=%d CLK(%s)=%d Hz\n", __func__, \
+			pdata->use_dma, pdata->clk_name, dws->max_freq);
+
+	if(memcmp(pdata->clk_name, "DUS", 3))
+		c2000_block_reset(COMPONENT_AXI_LEGACY_SPI, 0);
+	else	
+		c2000_block_reset(COMPONENT_AXI_FAST_SPI, 0);
+	
+	if(pdata->use_dma) /* DMA */
+	{
+		ret = dw_spi_dma_init(dws);
+		if (ret)
+			goto err_clk;
+	}
+
+	dws->bus_num = pdata->bus_num;
+	dws->num_cs = pdata->num_chipselects;
+
+	/* Get basic io resource and map it */
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem) {
+		dev_err(&pdev->dev, "no mem resource?\n");
+		ret = -EINVAL;
+		goto err_clk;
+	}
+
+	ioarea = request_mem_region(mem->start, resource_size(mem),
+			pdev->name);
+	if (!ioarea) {
+		dev_err(&pdev->dev, "SPI region already claimed\n");
+		ret = -EBUSY;
+		goto err_clk;
+	}
+
+	dws->regs = ioremap_nocache(mem->start, resource_size(mem));
+	if (!dws->regs) {
+		dev_err(&pdev->dev, "SPI region already mapped\n");
+		ret = -ENOMEM;
+		goto err_release_reg;
+	}
+
+	dws->irq = platform_get_irq(pdev, 0);
+	if (dws->irq < 0) {
+		dev_err(&pdev->dev, "no irq resource?\n");
+		ret = dws->irq; /* -ENXIO */
+		goto err_unmap;
+	}
+
+	dws->parent_dev = &pdev->dev;
+
+	ret = dw_spi_add_host(dws);
+	if (ret)
+		goto err_unmap;
+
+	platform_set_drvdata(pdev, dwsmmio);
+	return 0;
+
+err_unmap:
+	iounmap(dws->regs);
+err_release_reg:
+	release_mem_region(mem->start, resource_size(mem));
+err_clk:
+	if(memcmp(pdata->clk_name, "DUS", 3))
+		c2000_block_reset(COMPONENT_AXI_LEGACY_SPI, 1);
+	else	
+		c2000_block_reset(COMPONENT_AXI_FAST_SPI, 1);
+	
+	clk_put(dws->clk_spi);
+err_kfree:
+	kfree(dwsmmio);
+err_end:
+	return ret;
+}
+
+static int __devexit dw_spi_c2000_remove(struct platform_device *pdev)
+{
+	struct dw_spi_c2000 *dwsmmio = platform_get_drvdata(pdev);
+	struct spi_controller_pdata *pdata;
+	struct resource *mem;
+
+	platform_set_drvdata(pdev, NULL);
+
+	dw_spi_remove_host(&dwsmmio->dws);
+	iounmap(dwsmmio->dws.regs);
+
+	clk_put(dwsmmio->dws.clk_spi);
+	kfree(dwsmmio);
+
+	pdata = pdev->dev.platform_data;
+	if(!pdata)
+	{
+		return -EINVAL;
+	}
+
+	if(memcmp(pdata->clk_name, "DUS", 3))
+		c2000_block_reset(COMPONENT_AXI_LEGACY_SPI, 1);
+	else	
+		c2000_block_reset(COMPONENT_AXI_FAST_SPI, 1);
+	
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(mem->start, resource_size(mem));
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int c2000_spi_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct dw_spi_c2000 *dwsmmio = platform_get_drvdata(pdev);
+	struct dw_spi *dws = &dwsmmio->dws;
+
+	return dw_spi_suspend_host(dws);
+}
+
+static int c2000_spi_resume(struct platform_device *pdev)
+{
+	struct dw_spi_c2000 *dwsmmio = platform_get_drvdata(pdev);
+	struct dw_spi *dws = &dwsmmio->dws;
+
+	return dw_spi_resume_host(dws);
+}
+#endif
+
+static struct platform_driver dw_spi_c2000_driver = {
+	.probe		= dw_spi_c2000_probe,
+	.remove		= __devexit_p(dw_spi_c2000_remove),
+#ifdef CONFIG_PM
+	.suspend        = c2000_spi_suspend,
+	.resume         = c2000_spi_resume,
+#endif
+	.driver		= {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+module_platform_driver(dw_spi_c2000_driver);
+
+MODULE_AUTHOR("Satendra Pratap <satendra.pratap@gmail.com>");
+MODULE_DESCRIPTION("Memory-mapped I/O interface driver for DW SPI Core");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c
index 082458d..2c0806b 100644
--- a/drivers/spi/spi-dw.c
+++ b/drivers/spi/spi-dw.c
@@ -24,6 +24,12 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/spi/spi.h>
+#include <linux/clk.h>
+
+#ifdef CONFIG_C2K_DEVFREQ_DW
+	#include <linux/c2k-devfreq.h>
+	#include <linux/devfreq.h>
+#endif
 
 #include "spi-dw.h"
 
@@ -62,6 +68,48 @@
 	void (*cs_control)(u32 command);
 };
 
+#ifdef CONFIG_C2K_DEVFREQ_DW
+static devfreq_counters dc;
+
+static int set_spi_freq(struct c2k_devfreq_data *data, unsigned long *freq)
+{
+	struct spi_device *spi = container_of(data->dev, struct spi_device, dev);
+	struct dw_spi *dws = container_of(&spi, struct dw_spi, cur_dev);
+	struct chip_data *chip;
+	u32 clk_div;
+
+	/* Only alloc on first setup */
+	chip = spi_get_ctldata(spi);
+
+	if (!chip)
+	{
+		chip = spi_get_ctldata(spi);
+		if (!chip) {
+			chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
+			if (!chip)
+				return -ENOMEM;
+		}
+	}
+
+	if ((*freq <= data->max_freq) && (*freq >= data->min_freq))
+	{
+		chip->speed_hz = (u32)*freq;
+		clk_div = dws->max_freq / chip->speed_hz;
+		clk_div = (clk_div + 1) & 0xfffe;
+
+		chip->clk_div = clk_div;
+		spi_set_clk(dws, chip->clk_div);
+	}
+	else
+	{
+		printk (KERN_ERR "%s: Trying to set out of range spi freq: %lu\n\
+			", __func__, *freq);
+	}
+
+	return 0;
+}
+#endif
+
 #ifdef CONFIG_DEBUG_FS
 static int spi_show_regs_open(struct inode *inode, struct file *file)
 {
@@ -394,6 +442,10 @@
 	u32 speed = 0;
 	u32 cr0 = 0;
 
+#ifdef CONFIG_C2K_DEVFREQ_DW
+	devfreq_func_start(&dc);
+#endif
+
 	/* Get current state information */
 	message = dws->cur_msg;
 	transfer = dws->cur_transfer;
@@ -548,6 +600,10 @@
 	if (chip->poll_mode)
 		poll_transfer(dws);
 
+#ifdef CONFIG_C2K_DEVFREQ_DW
+	devfreq_func_end(&dc);
+#endif
+
 	return;
 
 early_exit:
@@ -598,6 +654,9 @@
 {
 	struct dw_spi *dws = spi_master_get_devdata(spi->master);
 	unsigned long flags;
+#ifdef CONFIG_C2K_DEVFREQ_DW
+	devfreq_func_start(&dc);
+#endif
 
 	spin_lock_irqsave(&dws->lock, flags);
 
@@ -626,6 +685,9 @@
 	}
 
 	spin_unlock_irqrestore(&dws->lock, flags);
+#ifdef CONFIG_C2K_DEVFREQ_DW
+	devfreq_func_end(&dc);
+#endif
 	return 0;
 }
 
@@ -801,6 +863,49 @@
 	}
 }
 
+#ifdef CONFIG_C2K_DEVFREQ_DW
+#define	SPI_MAXFREQ_MHZ	2000000
+#define	SPI_MINFREQ_MHZ	1000000
+#define	POLLING_MS	1000
+#define	OPP_TABLE_SIZE	4
+
+struct devfreq_dev_profile spi_devfreq_profile; 
+struct c2k_devfreq_data devfreq_spi_data;
+static struct c2k_devfreq_opp_table spi_opp_tbl[OPP_TABLE_SIZE];
+
+/* 
+ * intialize OPP table, profile data (initial freq, polling interval),
+ * max/min freq supported by SPI controller.
+ */
+static void init_spi_devfreq_data(struct dw_spi *dws)
+{
+	int i = 0;
+	struct c2k_devfreq_opp_table opp_tbl[OPP_TABLE_SIZE] = {
+		{1, 1000000, 0},
+		{2, 2000000, 0},
+		{3, 4000000, 0},
+		{0, 0, 0},
+	};
+
+	while (i < sizeof(opp_tbl))
+	{
+		spi_opp_tbl[i].idx = opp_tbl[i].idx;
+		spi_opp_tbl[i].freq = opp_tbl[i].freq;
+		spi_opp_tbl[i].volt = opp_tbl[i].volt;
+		i++;
+	}
+
+	spi_devfreq_profile.initial_freq = dws->max_freq;
+	spi_devfreq_profile.polling_ms = POLLING_MS;
+
+	devfreq_spi_data.devfreq_profile = &spi_devfreq_profile;
+	devfreq_spi_data.opp_table = &spi_opp_tbl[0];
+	devfreq_spi_data.set_freq = set_spi_freq;
+	devfreq_spi_data.max_freq = SPI_MAXFREQ_MHZ;
+	devfreq_spi_data.min_freq = SPI_MINFREQ_MHZ;
+}
+#endif
+
 int __devinit dw_spi_add_host(struct dw_spi *dws)
 {
 	struct spi_master *master;
@@ -814,6 +919,8 @@
 		goto exit;
 	}
 
+	clk_enable(dws->clk_spi);
+
 	dws->master = master;
 	dws->type = SSI_MOTO_SPI;
 	dws->prev_chip = NULL;
@@ -867,6 +974,14 @@
 	}
 
 	mrst_spi_debugfs_init(dws);
+
+#ifdef CONFIG_C2K_DEVFREQ_DW
+	init_spi_devfreq_data(dws);
+
+	ret = c2k_driver_devfreq(&master->dev, &devfreq_spi_data);
+	if(ret < 0)
+		goto err_queue_alloc;
+#endif
 	return 0;
 
 err_queue_alloc:
@@ -877,6 +992,7 @@
 	spi_enable_chip(dws, 0);
 	free_irq(dws->irq, dws);
 err_free_master:
+	clk_disable(dws->clk_spi);
 	spi_master_put(master);
 exit:
 	return ret;
@@ -900,12 +1016,12 @@
 	if (dws->dma_ops && dws->dma_ops->dma_exit)
 		dws->dma_ops->dma_exit(dws);
 	spi_enable_chip(dws, 0);
-	/* Disable clk */
-	spi_set_clk(dws, 0);
 	free_irq(dws->irq, dws);
 
 	/* Disconnect from the SPI framework */
 	spi_unregister_master(dws->master);
+	/* Disable clk */
+	clk_disable(dws->clk_spi);
 }
 EXPORT_SYMBOL_GPL(dw_spi_remove_host);
 
@@ -917,7 +1033,9 @@
 	if (ret)
 		return ret;
 	spi_enable_chip(dws, 0);
-	spi_set_clk(dws, 0);
+
+	clk_disable(dws->clk_spi);
+
 	return ret;
 }
 EXPORT_SYMBOL_GPL(dw_spi_suspend_host);
@@ -926,6 +1044,7 @@
 {
 	int ret;
 
+	clk_enable(dws->clk_spi);
 	spi_hw_init(dws);
 	ret = start_queue(dws);
 	if (ret)
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 9c57c07..b4bd29b 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -92,6 +92,7 @@
 struct dw_spi {
 	struct spi_master	*master;
 	struct spi_device	*cur_dev;
+	struct clk		*clk_spi;
 	struct device		*parent_dev;
 	enum dw_ssi_type	type;
 	char			name[16];
diff --git a/drivers/spi2/Kconfig b/drivers/spi2/Kconfig
new file mode 100644
index 0000000..cab6011
--- /dev/null
+++ b/drivers/spi2/Kconfig
@@ -0,0 +1,15 @@
+#
+# Character device configuration
+#
+
+menu "SPI2 support"
+	depends on (ARCH_COMCERTO)
+config SPI2
+	tristate "Mindspeed SPI support"
+	help
+	  Mindspeed SPI (Serial Pheripheral Interface bus) core support
+
+source drivers/spi2/busses/Kconfig
+
+endmenu
+
diff --git a/drivers/spi2/Makefile b/drivers/spi2/Makefile
new file mode 100644
index 0000000..84b51f2
--- /dev/null
+++ b/drivers/spi2/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the spi core.
+#
+
+obj-$(CONFIG_SPI2) += spi-core.o
+obj-y		  += busses/
+
diff --git a/drivers/spi2/busses/Kconfig b/drivers/spi2/busses/Kconfig
new file mode 100644
index 0000000..e13f420
--- /dev/null
+++ b/drivers/spi2/busses/Kconfig
@@ -0,0 +1,15 @@
+
+menu "SPI Hardware Bus support"
+	depends on SPI2
+
+config SPI2_MSPD_LOW_SPEED
+	tristate "Comcerto Low-speed"
+	depends on SPI2
+	default y
+
+config SPI2_MSPD_HIGH_SPEED
+	tristate "Comcerto High-speed"
+	depends on SPI2
+	default y
+
+endmenu
diff --git a/drivers/spi2/busses/Makefile b/drivers/spi2/busses/Makefile
new file mode 100644
index 0000000..de53bd2
--- /dev/null
+++ b/drivers/spi2/busses/Makefile
@@ -0,0 +1,15 @@
+SPI2_MSPD=n
+ifeq ($(CONFIG_SPI2_MSPD_HIGH_SPEED),m)
+    SPI2_MSPD=m
+endif
+ifeq ($(CONFIG_SPI2_MSPD_LOW_SPEED),m)
+    SPI2_MSPD=m
+endif
+ifeq ($(CONFIG_SPI2_MSPD_HIGH_SPEED),y)
+    SPI2_MSPD=y
+endif
+ifeq ($(CONFIG_SPI2_MSPD_LOW_SPEED),y)
+    SPI2_MSPD=y
+endif
+
+obj-$(SPI2_MSPD)        += comcerto_spi.o
diff --git a/drivers/spi2/busses/comcerto_spi.c b/drivers/spi2/busses/comcerto_spi.c
new file mode 100644
index 0000000..d8e2d6f
--- /dev/null
+++ b/drivers/spi2/busses/comcerto_spi.c
@@ -0,0 +1,772 @@
+/*
+ *  drivers/spi2/busses/comcerto_spi.c
+ *
+ *  Copyright (C) 2004,2005 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/version.h>
+#if !defined (AUTOCONF_INCLUDED)
+#if 0
+	#include <linux/config.h>
+#endif
+#endif
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <asm/sizes.h>
+#include <mach/irqs.h>
+#include <linux/delay.h>
+
+#include <linux/platform_device.h>
+#include "comcerto_spi.h"
+
+/**/
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+/**/
+
+/**
+ * do_write_read_transfer8 -
+ *
+ *
+ */
+static int do_write_read_transfer8(struct comcerto_spi *spi, u8 *wbuf, unsigned int *wlen, u8 *rbuf, unsigned int *rlen, u32 ser_reg)
+{
+	unsigned int len_now;
+	int rc = 0;
+	unsigned int wtmp = *wlen, rtmp = *rlen;
+	u32 dr = spi->membase + COMCERTO_SPI_DR;
+	u32 txflr = spi->membase + COMCERTO_SPI_TXFLR;
+	u32 rxflr = spi->membase + COMCERTO_SPI_RXFLR;
+	int ser_done = 0;
+
+//	printk(KERN_INFO "do_write_read_transfer(%#lx, %#lx, %d, %#lx, %d)\n", (unsigned long)spi,
+//                                                                      (unsigned long)wbuf, *wlen,
+//                                                                      (unsigned long)rbuf, *rlen);
+
+	while (wtmp || rtmp) {
+		len_now = 8 - __raw_readl(txflr);
+		if (len_now > wtmp)
+			len_now = wtmp;
+
+		wtmp -= len_now;
+
+		/* warm-up write fifo to avoid underruns */
+		while (len_now--)
+			__raw_writew(cpu_to_le16((u16) *wbuf++), dr);
+
+		if (!ser_done){
+			__raw_writel(ser_reg, spi->membase + COMCERTO_SPI_SER);
+			ser_done = 1;
+		}
+
+		len_now = __raw_readl(rxflr);
+		if (len_now > rtmp)
+			len_now = rtmp;
+
+		rtmp -= len_now;
+
+		while (len_now--) {
+			*rbuf = (u8) (le16_to_cpu(__raw_readw(dr)) & 0xff);
+			rbuf++;
+		}
+	}
+
+	*rlen -= rtmp;
+	*wlen -= wtmp;
+
+	return rc;
+}
+
+/**
+ * do_write_read_transfer16 -
+ *
+ */
+static int do_write_read_transfer16(struct comcerto_spi *spi, u16 *wbuf, unsigned int *wlen, u16 *rbuf, unsigned int *rlen, u32 ser_reg)
+{
+	unsigned int len_now;
+	int rc = 0;
+	unsigned int wtmp = *wlen, rtmp = *rlen;
+	unsigned int wpadding, rpadding;
+	u32 dr = spi->membase + COMCERTO_SPI_DR;
+	u32 txflr = spi->membase + COMCERTO_SPI_TXFLR;
+	u32 rxflr = spi->membase + COMCERTO_SPI_RXFLR;
+	int ser_done = 0;
+
+//	printk(KERN_INFO "do_write_read_transfer(%#lx, %#lx, %d, %#lx, %d)\n", (unsigned long)spi
+//                                                                      (unsigned long)wbuf, *wlen,
+//                                                                      (unsigned long)rbuf, *rlen);
+
+	if (wtmp > rtmp) {
+		wpadding  = 0;
+		rpadding = wtmp - rtmp;
+	} else {
+		wpadding = rtmp - wtmp;
+		rpadding = 0;
+	}
+
+	while (wtmp || rtmp) {
+		len_now = 8 - __raw_readl(txflr);
+
+		if (wtmp) {
+			if (len_now > wtmp)
+				len_now = wtmp;
+
+			wtmp -= len_now;
+
+			while (len_now--)
+				__raw_writew(cpu_to_le16(*wbuf++), dr);
+
+		} else if (wpadding) {
+			if (len_now > wpadding)
+				len_now = wpadding;
+
+			wpadding -= len_now;
+
+			while (len_now--)
+				__raw_writew(0, dr);
+		}
+
+		if (!ser_done){
+			__raw_writel(ser_reg, spi->membase + COMCERTO_SPI_SER);
+			ser_done = 1;
+		}
+
+		len_now = __raw_readl(rxflr);
+		if (rtmp) {
+			if (len_now > rtmp)
+				len_now = rtmp;
+
+			rtmp -= len_now;
+
+			while (len_now--) {
+				*rbuf = le16_to_cpu(__raw_readw(dr));
+				rbuf++;
+			}
+		} else if (rpadding) {
+			if (len_now > rpadding)
+				len_now = rpadding;
+
+			rpadding -= len_now;
+
+			while (len_now--)
+				__raw_readw(dr);
+		}
+	}
+
+	*rlen -= rtmp;
+	*wlen -= wtmp;
+
+	return rc;
+}
+
+
+/**
+ * do_write_only_transfer8 -
+ *
+ *
+ */
+static int do_write_only_transfer8(struct comcerto_spi *spi, u8 *buf, unsigned int *len, u32 ser_reg)
+{
+	unsigned int len_now;
+	int rc = 0;
+	unsigned int tmp = *len;
+	u32 dr = spi->membase + COMCERTO_SPI_DR;
+	u32 txflr = spi->membase + COMCERTO_SPI_TXFLR;
+	int ser_done = 0;
+
+//	printk(KERN_INFO "do_write_only_transfer8(%#lx, %#lx, %d)\n", (unsigned long)spi, (unsigned long)buf, *len);
+
+	while (tmp) {
+		len_now = 8 - __raw_readl(txflr);
+		if (len_now > tmp)
+			len_now = tmp;
+
+		tmp -= len_now;
+
+		while (len_now--)
+			__raw_writew(cpu_to_le16((u16) *buf++), dr);
+
+		if (!ser_done)
+		{
+			__raw_writel(ser_reg, spi->membase + COMCERTO_SPI_SER);
+			ser_done = 1;
+		}
+	}
+
+	*len -= tmp;
+
+//      printk(KERN_INFO "exit do_write_only_transfer(%d, %d)\n", *len, rc);
+
+	return rc;
+}
+
+/**
+ * do_write_only_transfer -
+ *
+ *
+ */
+static int do_write_only_transfer16(struct comcerto_spi *spi, u16 *buf, unsigned int *len, u32 ser_reg)
+{
+	unsigned int len_now;
+	int rc = 0;
+	unsigned int tmp = *len;
+	u32 dr = spi->membase + COMCERTO_SPI_DR;
+	u32 txflr = spi->membase + COMCERTO_SPI_TXFLR;
+	int ser_done = 0;
+
+//      printk(KERN_INFO "do_write_only_transfer(%#lx, %#lx, %d)\n", (unsigned long)spi, (unsigned long)buf, *len);
+
+	while (tmp) {
+		len_now = 8 - __raw_readl(txflr);
+		if (len_now > tmp)
+			len_now = tmp;
+
+		tmp -= len_now;
+
+		while (len_now--)
+			__raw_writew(cpu_to_le16(*buf++), dr);
+
+		if (!ser_done)
+		{
+			__raw_writel(ser_reg, spi->membase + COMCERTO_SPI_SER);
+			ser_done = 1;
+		}
+	}
+
+	*len -= tmp;
+
+//      printk(KERN_INFO "exit do_write_only_transfer(%d, %d)\n", *len, rc);
+
+	return rc;
+}
+
+
+/**
+ * do_read_only_transfer -
+ *
+ *
+ */
+static int do_read_only_transfer8(struct comcerto_spi *spi, u8 *buf, unsigned int *len)
+{
+	unsigned int len_now;
+	int rc = 0;
+	unsigned int tmp = *len;
+	u32 dr = spi->membase + COMCERTO_SPI_DR;
+	u32 rxflr = spi->membase + COMCERTO_SPI_RXFLR;
+
+//	printk(KERN_INFO "do_read_only_transfer8(%#lx, %#lx, %d)\n", (unsigned long)spi, (unsigned long)buf, *len);
+
+	/* start the serial clock */
+	__raw_writew(0, dr);
+
+	while (tmp) {
+		len_now = __raw_readl(rxflr);
+		if (len_now > tmp)
+			len_now = tmp;
+
+		tmp -= len_now;
+
+		while (len_now--) {
+			*buf = (u8) (le16_to_cpu(__raw_readw(dr)) & 0xff);
+			buf++;
+		}
+	}
+
+	*len -= tmp;
+
+	return rc;
+}
+
+/**
+ * do_read_only_transfer -
+ *
+ *
+ */
+static int do_read_only_transfer16(struct comcerto_spi *spi, u16 *buf, unsigned int *len)
+{
+	unsigned int len_now;
+	int rc = 0;
+	unsigned int tmp = *len;
+	u32 dr = spi->membase + COMCERTO_SPI_DR;
+	u32 rxflr = spi->membase + COMCERTO_SPI_RXFLR;
+
+//      printk(KERN_INFO "do_read_only_transfer(%#lx, %#lx, %d)\n", (unsigned long)spi, (unsigned long)buf, *len);
+
+	/* start the serial clock */
+	__raw_writew(0, dr);
+
+	while (tmp) {
+		len_now = __raw_readl(rxflr);
+		if (len_now > tmp)
+			len_now = tmp;
+
+		tmp -= len_now;
+
+		while (len_now--) {
+			*buf = le16_to_cpu(__raw_readw(dr));
+			buf++;
+		}
+	}
+
+	*len -= tmp;
+
+	return rc;
+}
+
+
+/**
+ * comcerto_spi_do_transfer -
+ *
+ *
+ */
+static int comcerto_spi_do_transfer(struct spi_adapter *adapter, struct spi_transfer *transfer, struct spi_client_config *config)
+{
+	struct comcerto_spi *spi = (struct comcerto_spi *)adapter->data;
+	u32 ctrlr0, ctrlr1, baudr, ser;
+	int rc;
+
+//      printk(KERN_INFO "comcerto_spi_do_transfer(%#lx, %#lx, %#lx)\n", (unsigned long) adapter, (unsigned long) transfer, (unsigned long) config);
+
+	/* make sure last transaction is finished */
+	while (__raw_readl(spi->membase + COMCERTO_SPI_SR) & BUSY) ;
+
+	if (config->ba_delay)
+		udelay(config->ba_delay);
+
+	ctrlr0 = ((config->sc_polarity & 0x1) << 7) | ((config->sc_phase & 0x1) << 6) | (((transfer->fs - 1) & 0xf) << 0);
+
+	baudr = spi->clock_rate / config->sc_rate;
+
+	ser = config->cs_msk & adapter->caps.cs_msk;
+
+	__raw_writel(0, spi->membase + COMCERTO_SPI_SSIENR);
+
+	switch (transfer->mode & 0x0f) {
+	default:
+		rc = -1;
+		break;
+
+	case SPI_TRANSFER_MODE_WRITE_ONLY:
+		ctrlr0 |= (0x0001 << 8);
+
+		__raw_writel(ctrlr0, spi->membase + COMCERTO_SPI_CTRLR0);
+		__raw_writel(baudr, spi->membase + COMCERTO_SPI_BAUDR);
+		//__raw_writel(ser, spi->membase + COMCERTO_SPI_SER);
+		__raw_writel(8, spi->membase + COMCERTO_SPI_RXFTLR);
+		__raw_writel(0, spi->membase + COMCERTO_SPI_TXFTLR);
+		__raw_writel(0, spi->membase + COMCERTO_SPI_IMR);
+		__raw_writel(1, spi->membase + COMCERTO_SPI_SSIENR);
+
+		if (transfer->fs <= 8)
+			rc = do_write_only_transfer8(spi, transfer->wbuf, &transfer->wlen, ser);
+		else
+			rc = do_write_only_transfer16(spi, (u16 *) transfer->wbuf, &transfer->wlen, ser);
+
+		break;
+
+	case SPI_TRANSFER_MODE_READ_ONLY:
+		ctrlr0 |= (0x0002 << 8);
+		ctrlr1 = transfer->rlen - 1;
+
+		__raw_writel(ctrlr0, spi->membase + COMCERTO_SPI_CTRLR0);
+		__raw_writel(ctrlr1, spi->membase + COMCERTO_SPI_CTRLR1);
+		__raw_writel(baudr, spi->membase + COMCERTO_SPI_BAUDR);
+		__raw_writel(ser, spi->membase + COMCERTO_SPI_SER);
+		__raw_writel(8, spi->membase + COMCERTO_SPI_RXFTLR);
+		__raw_writel(0, spi->membase + COMCERTO_SPI_TXFTLR);
+		__raw_writel(0, spi->membase + COMCERTO_SPI_IMR);
+		__raw_writel(1, spi->membase + COMCERTO_SPI_SSIENR);
+
+		if (transfer->fs <= 8)
+			rc = do_read_only_transfer8(spi, transfer->rbuf, &transfer->rlen);
+		else
+			rc = do_read_only_transfer16(spi, (u16 *) transfer->rbuf, &transfer->rlen);
+	
+		break;
+
+	case SPI_TRANSFER_MODE_WRITE_READ:
+		ctrlr0 |= (0x0000 << 8);
+
+		__raw_writel(ctrlr0, spi->membase + COMCERTO_SPI_CTRLR0);
+		__raw_writel(baudr, spi->membase + COMCERTO_SPI_BAUDR);
+	//	__raw_writel(ser, spi->membase + COMCERTO_SPI_SER);
+		__raw_writel(8, spi->membase + COMCERTO_SPI_RXFTLR);
+		__raw_writel(0, spi->membase + COMCERTO_SPI_TXFTLR);
+		__raw_writel(0, spi->membase + COMCERTO_SPI_IMR);
+		__raw_writel(1, spi->membase + COMCERTO_SPI_SSIENR);
+
+		if (transfer->fs <= 8)
+		rc = do_write_read_transfer8(spi, transfer->wbuf, &transfer->wlen, transfer->rbuf, &transfer->rlen, ser);
+		else
+		rc = do_write_read_transfer16(spi, (u16 *) transfer->wbuf, &transfer->wlen, (u16 *) transfer->rbuf, &transfer->rlen, ser);
+
+		break;
+	}
+
+	if (config->ba_delay) {
+		udelay(config->ba_delay);
+	        /* make sure this transaction is finished */
+        	while (__raw_readl(spi->membase + COMCERTO_SPI_SR) & BUSY) ;
+	}
+
+	__raw_writel(0, spi->membase + COMCERTO_SPI_SER);
+
+	return rc;
+}
+
+#if 0
+/**
+ * comcerto_spi_irq_handler -
+ *
+ *
+ */
+irqreturn_t comcerto_spi_irq_handler(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct comcerto_spi *spi = (struct comcerto_spi *)dev_id;
+	struct spi_adapter *adapter = spi->adapter;
+	u32 callback_status = 0;
+	u32 status;
+	u32 imr;
+	irqreturn_t ret = IRQ_NONE;
+
+	printk(KERN_INFO "comcerto_spi_irq_handler(%d, %#lx, %#lx)\n", irq, (unsigned long)dev_id, (unsigned long)regs);
+
+	status = readl(spi->membase + COMCERTO_SPI_ISR);
+	if (!status)
+		goto out;
+
+	printk(KERN_INFO "status %x\n", status);
+
+	ret = IRQ_HANDLED;
+
+	if (status & TXEIS) {
+		callback_status |= SPI_WRITE_DONE;
+
+		printk(KERN_INFO "%x %x\n", readl(spi->membase + COMCERTO_SPI_SR), readl(spi->membase + COMCERTO_SPI_TXFLR));
+
+		/* disable fifo empty interrupt */
+		imr = readl(spi->membase + COMCERTO_SPI_IMR) & ~(TXEIM);
+		writel(imr, spi->membase + COMCERTO_SPI_IMR);
+	}
+
+	if (status & TXOIS) {
+		callback_status |= SPI_WRITE_ERROR;
+	}
+
+	if (status & RXUIS) {
+		callback_status |= SPI_READ_ERROR;
+	}
+
+	if (status & RXOIS) {
+		callback_status |= SPI_READ_ERROR;
+	}
+
+	if (status & RXFIS) {
+		callback_status |= SPI_DATA_AVAILABLE;
+	}
+
+	spi_callback(adapter, callback_status);
+
+	/* clear all interrupts */
+	readl(spi->membase + COMCERTO_SPI_ICR);
+
+      out:
+	return ret;
+}
+#endif
+
+/**
+ * comcerto_spi_hw_init -
+ *
+ *
+ */
+static void comcerto_spi_hw_init(struct comcerto_spi *spi)
+{
+//	printk(KERN_INFO "comcerto_spi_hw_init(%#lx)\n", (unsigned long)spi);
+
+#ifndef CONFIG_ARCH_M83XXX
+	/* enable SPI bus: not needed for c2k */
+	//comcerto_gpio_ctrl(0x3 << 4, 0x3 << 4);
+#endif
+
+	/* disable SPI operation */
+	writel(0, spi->membase + COMCERTO_SPI_SSIENR);
+
+	/* mask all SPI irq's */
+	writel(0, spi->membase + COMCERTO_SPI_IMR);
+}
+
+/**
+ * comcerto_spi_hw_reset -
+ *
+ *
+ */
+static void comcerto_spi_hw_reset(struct comcerto_spi *spi)
+{
+	/* disable SPI operation */
+	writel(0, spi->membase + COMCERTO_SPI_SSIENR);
+
+	/* mask all SPI irq's */
+	writel(0, spi->membase + COMCERTO_SPI_IMR);
+
+#ifndef CONFIG_ARCH_M83XXX
+	/* disable SPI bus: not needed for c2k */
+	//comcerto_gpio_ctrl(0x0 << 4, 0x3 << 4);
+#endif
+}
+#if 0
+struct spi_adapter comcerto_spi_adapter = {
+	.name = "comcerto_spi",
+	.do_transfer = comcerto_spi_do_transfer,
+};
+#endif
+
+#define        SPI2_DRV_NAME_LEN       15
+char spi2_drv_name[SPI2_DRV_NAME_LEN] = "comcerto_spi";
+
+/**
+* comcerto_spi_probe -
+ *
+ *
+ */
+static int __init comcerto_spi_probe(struct platform_device *pdev)
+{
+	struct comcerto_spi *spi;
+	struct spi_adapter *ladapter;
+	unsigned long base, len;
+
+//	printk(KERN_INFO "comcerto_spi_probe(%#lx)\n", (unsigned long) pdev);
+	printk(KERN_INFO "%s: comcerto_spi_probe(%#lx)\
+			\npdev->resource[0].start=0x%x\
+			\npdev->resource[0].end=0x%x\
+			\npdev->name=%s\
+			\npdev->id=%d\n", __func__, (unsigned long) pdev, \
+			pdev->resource[0].start, pdev->resource[0].end, pdev->name, pdev->id);
+
+
+	spi = kmalloc(sizeof(struct comcerto_spi), GFP_KERNEL);
+	if (spi == NULL) {
+		printk(KERN_INFO "comcerto_spi: error allocating memory");
+		goto err0;
+	}
+
+	ladapter = kmalloc(sizeof(struct spi_adapter), GFP_KERNEL);
+	if (ladapter == NULL) {
+		printk(KERN_INFO "%s: Error allocating memory: ladapter=0x%x", __func__,\
+				(unsigned int)ladapter);
+		goto err1;
+	}
+
+	base = pdev->resource[0].start;
+	len = pdev->resource[0].end - pdev->resource[0].start + 1;
+
+	if (!request_mem_region(base, len, COMCERTO_SPI_DRIVER_NAME)) {
+		printk(KERN_INFO "comcerto_spi: error requesting memory region %#lx - %#lx", base, base + len);
+		goto err2;
+	}
+
+	/* io-remaped in arch/arm/mm.c */
+	if(pdev->id == 0)
+		spi->membase = APB_VADDR(pdev->resource[0].start);
+	else
+		if(pdev->id == 1)
+			spi->membase = AXI_VADDR(pdev->resource[0].start);
+		else
+		{
+			printk (KERN_INFO "%s: No support for pdev->id = %d\n",\
+					__func__, pdev->id);
+			goto err3;
+		}
+
+	printk (KERN_INFO "%s: pdev->id=%d spi->membase=0x%x\n", __func__,\
+			pdev->id, (unsigned int)spi->membase);
+	//spi->membase = ioremap(pdev->resource[0].start, len);
+	spi->irq = pdev->resource[1].start;
+
+	//pratapc pwr_mgmt_clk_restore(COMPONENT_SPI);
+
+	comcerto_spi_hw_init(spi);
+#if 0
+	if (request_irq(spi->irq, comcerto_spi_irq_handler, SA_SHIRQ, COMCERTO_SPI_DRIVER_NAME, spi)) {
+		printk(KERN_INFO "comcerto_spi: error requesting irq %d\n", IRQ_SPI);
+		goto err2;
+	}
+#endif
+	spi->adapter = ladapter;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+	ladapter->dev.parent = &pdev->dev;
+#endif
+	ladapter->name = spi2_drv_name;
+	ladapter->do_transfer = comcerto_spi_do_transfer;
+	ladapter->data = spi;
+	ladapter->caps.max_sc_rate = COMCERTO_DEFAULTAXICLK / 2;
+	ladapter->caps.min_sc_rate = COMCERTO_DEFAULTAXICLK / 0xffff;
+	ladapter->caps.max_fs = 16;
+	ladapter->caps.min_fs = 4;
+	ladapter->caps.max_nframe = 0xffff;
+	ladapter->caps.min_nframe = 1;
+	ladapter->caps.cs_msk = 0xf;
+	ladapter->bus_num = pdev->id;
+
+	printk ("%s: ladapter->bus_num=0x%x\n", __func__,\
+			ladapter->bus_num);
+
+	if (spi_add_adapter(ladapter)) {
+		printk(KERN_INFO "%s:error adding adapter\n", __func__);
+		goto err3;
+	}
+
+	spi->clock_rate = COMCERTO_DEFAULTAXICLK;
+	platform_set_drvdata(pdev, spi);
+
+	return 0;
+
+err3:
+#if 0
+	free_irq(spi->irq, spi);
+
+      err2:
+#endif
+	release_mem_region(base, len);
+err2:
+	kfree(ladapter);
+
+err1:
+	kfree(spi);
+
+      err0:
+	return -1;
+}
+
+/**
+ * comcerto_spi_remove -
+ *
+ *
+ */
+static int comcerto_spi_remove(struct platform_device *pdev)
+{
+	struct comcerto_spi *spi = platform_get_drvdata(pdev);
+	unsigned long base, len;
+
+	platform_set_drvdata(pdev, NULL);
+
+	spi_del_adapter(spi->adapter);
+
+	comcerto_spi_hw_reset(spi);
+
+	//pratapc pwr_mgmt_clk_down(COMPONENT_SPI);
+
+//      free_irq(spi->irq, spi);
+
+	base = pdev->resource[0].start;
+	len = pdev->resource[0].end - pdev->resource[0].start + 1;
+
+	release_mem_region(base, len);
+
+	kfree(spi->adapter);
+	kfree(spi);
+
+	return 0;
+}
+
+/* FIXME:  we are not supporting Power management in SPI-2 driver */
+#if 0
+#ifdef CONFIG_PM
+static int spi_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	int ret;
+	struct spi_client *client;
+	struct list_head *item, *_n;
+	struct comcerto_spi *spi = platform_get_drvdata(pdev);
+	state.event = PM_EVENT_SUSPEND;
+	list_for_each_safe(item, _n, &spi->adapter->clients) {
+		client = list_entry(item, struct spi_client, list);
+		if(client->driver->suspend != NULL)
+			ret = client->driver->suspend(client,state);
+		}
+
+	if(ret == 0)
+		pwr_mgmt_clk_down(COMPONENT_SPI);
+
+	return 0;
+}
+
+static int spi_resume(struct platform_device *pdev)
+{
+	struct spi_client *client;
+	struct list_head *item, *_n;
+	struct comcerto_spi *spi = platform_get_drvdata(pdev);
+	
+	pwr_mgmt_clk_restore(COMPONENT_SPI);
+
+	list_for_each_safe(item, _n, &spi->adapter->clients) {
+		client = list_entry(item, struct spi_client, list);
+		if(client->driver->resume != NULL)
+			client->driver->resume(client);
+		}
+
+	return 0;
+}
+#endif
+#endif
+
+static struct platform_driver comcerto_spi_driver = {
+	.probe = comcerto_spi_probe,
+	.remove = comcerto_spi_remove,
+#if 0
+#ifdef CONFIG_PM
+	.suspend	= spi_suspend,
+	.resume		= spi_resume,
+#endif
+#endif
+	.driver = {
+		.name = "comcerto_spi",
+	},
+};
+
+/**
+ * comcerto_spi_init -
+ *
+ *
+ */
+static int __init comcerto_spi_init(void)
+{
+//	printk(KERN_INFO "comcerto_spi_init()\n");
+
+	return platform_driver_register(&comcerto_spi_driver);
+}
+
+/**
+ * comcerto_spi_exit -
+ *
+ *
+ */
+static void __exit comcerto_spi_exit(void)
+{
+	platform_driver_unregister(&comcerto_spi_driver);
+}
+
+MODULE_AUTHOR("Mindspeed Technologies, Inc.");
+MODULE_DESCRIPTION("Comcerto SPI bus driver");
+MODULE_LICENSE("GPL");
+
+module_init(comcerto_spi_init);
+module_exit(comcerto_spi_exit);
diff --git a/drivers/spi2/busses/comcerto_spi.h b/drivers/spi2/busses/comcerto_spi.h
new file mode 100644
index 0000000..38ef6c2b
--- /dev/null
+++ b/drivers/spi2/busses/comcerto_spi.h
@@ -0,0 +1,99 @@
+/*
+ *  linux/drivers/spi2/busses/comcerto_spi.h
+ *
+ *  Copyright (C) Mindspeed Technologies
+ *
+ * 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.
+ *
+ */
+#ifndef _COMCERTO_SPI_H
+#define _COMCERTO_SPI_H
+
+#include <linux/version.h>
+#include <linux/spi2/spi.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+#include <linux/ioport.h>
+
+struct platform_device {
+	char            *name;
+	u32             id;
+	u32             num_resources;
+	struct resource *resource;
+
+	unsigned long data;
+};
+#endif
+
+#define COMCERTO_SPI_DRIVER_NAME	"Comcerto SPI"
+
+
+#define COMCERTO_SPI_CTRLR0               0x00
+#define COMCERTO_SPI_CTRLR1               0x04
+#define COMCERTO_SPI_SSIENR               0x08
+#define COMCERTO_SPI_MWCR                 0x0C
+#define COMCERTO_SPI_SER                  0x10
+#define COMCERTO_SPI_BAUDR                0x14
+#define COMCERTO_SPI_TXFTLR               0x18
+#define COMCERTO_SPI_RXFTLR               0x1C
+#define COMCERTO_SPI_TXFLR                0x20
+#define COMCERTO_SPI_RXFLR                0x24
+#define COMCERTO_SPI_SR                   0x28
+#define COMCERTO_SPI_IMR                  0x2C
+#define COMCERTO_SPI_ISR                  0x30
+#define COMCERTO_SPI_RISR                 0x34
+#define COMCERTO_SPI_TXOICR               0x38
+#define COMCERTO_SPI_RXOICR               0x3C
+#define COMCERTO_SPI_RXUICR               0x40
+#define COMCERTO_SPI_MSTICR               0x44
+#define COMCERTO_SPI_ICR                  0x48
+#define COMCERTO_SPI_IDR                  0x58
+#define COMCERTO_SPI_DR                   0x60
+
+
+/* SR - status register bits */
+#define BUSY		(1<<0)	/* SSI busy flag, serial transfer in progress */
+#define TFNF		(1<<1)	/* Transmit FIFO not full */
+#define TFE		(1<<2)	/* Transmit FIFO empty */
+#define RFNE		(1<<3)	/* Receive FIFO not empty */
+#define RFF		(1<<4)	/* Receive FIFO full */
+#define TXE		(1<<5)	/* Transmission error */
+#define DCOL		(1<<6)	/* Data collision error */
+
+/* Interrupt status after being masked */
+#define TXEIS		(1<<0)	/* Transmit FIFO empty interrupt status */
+#define TXOIS		(1<<1)	/* Transmit FIFO overflow interrupt status */
+#define RXUIS		(1<<2)	/* Receive FIFO underflow interrupt status */
+#define RXOIS		(1<<3)	/* Receive FIFO overflow interrupt status */
+#define RXFIS		(1<<4)	/* Receive FIFO full interrupt status */
+#define MSTIS		(1<<5)	/* Multi-Master contention interrupt status */
+
+/* Interrupt status before being masked */
+#define TXEIR		(1<<0)	/* Transmit FIFO empty interrupt status */
+#define TXOIR		(1<<1)	/* Transmit FIFO overflow interrupt status */
+#define RXUIR		(1<<2)	/* Receive FIFO underflow interrupt status */
+#define RXOIR		(1<<3)	/* Receive FIFO overflow interrupt status */
+#define RXFIR		(1<<4)	/* Receive FIFO full interrupt status */
+#define MSTIR		(1<<5)	/* Multi-Master contention interrupt status */
+
+
+/* Interrupt mask register */
+#define TXEIM		(1<<0)	/* Transmit FIFO empty interrupt status */
+#define TXOIM		(1<<1)	/* Transmit FIFO overflow interrupt status */
+#define RXUIM		(1<<2)	/* Receive FIFO underflow interrupt status */
+#define RXOIM		(1<<3)	/* Receive FIFO overflow interrupt status */
+#define RXFIM		(1<<4)	/* Receive FIFO full interrupt status */
+#define MSTIM		(1<<5)	/* Multi-Master contention interrupt status */
+
+struct comcerto_spi
+{
+	struct spi_adapter *adapter;
+	unsigned long membase;
+	int irq;
+	unsigned long clock_rate;
+};
+
+
+#endif /* _COMCERTO_SPI_H */
diff --git a/drivers/spi2/spi-core.c b/drivers/spi2/spi-core.c
new file mode 100644
index 0000000..9b17c08
--- /dev/null
+++ b/drivers/spi2/spi-core.c
@@ -0,0 +1,523 @@
+/*
+ *  linux/drivers/spi2/spi-core.c
+ *
+ *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+ 
+
+#if !defined (AUTOCONF_INCLUDED)
+#if 0
+	#include <linux/config.h>
+#endif
+#endif
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+#include <asm/delay.h>
+
+#include <linux/spi2/spi.h>
+
+static LIST_HEAD(spi_adapters);
+static LIST_HEAD(spi_drivers);
+
+/**
+ * spi_write_mem -
+ *
+ *
+ */
+int spi_write_mem(struct spi_client *client, u8 fs, u8 *buffer, int len)
+{
+	struct spi_transfer transfer;
+	struct spi_adapter *adapter = client->adapter;
+	unsigned long flags;
+	int rc;
+
+	memset(&transfer, 0, sizeof (struct spi_transfer));
+
+	transfer.fs = fs;
+	transfer.mode = SPI_TRANSFER_MODE_WRITE_ONLY;
+	transfer.wbuf = buffer;
+	transfer.wlen = len;
+
+	spin_lock_irqsave(&adapter->lock, flags);
+	rc = adapter->do_transfer(adapter, &transfer, &client->config);
+	spin_unlock_irqrestore(&adapter->lock, flags);
+
+	/* deassert the chip select at least for this long */
+	udelay (1 + ((1000000 * client->config.cs_delay) / client->config.sc_rate));
+
+	return rc;
+}
+
+
+/**
+ * spi_write_single -
+ *
+ *
+ */
+int spi_write_single(struct spi_client *client, u8 fs, u16 value)
+{
+	return spi_write_mem(client, fs, (u8 *)&value, 1);
+}
+
+/**
+ * spi_writen -
+ *
+ *
+ */
+int spi_writen(struct spi_client *client, u4 value)
+{
+	return spi_write_mem(client, 4, (u8 *)&value, 1);
+}
+
+
+/**
+ * spi_writeb -
+ *
+ *
+ */
+int spi_writeb(struct spi_client *client, u8 value)
+{
+	return spi_write_mem(client, 8, &value, 1);
+}
+
+
+/**
+ * spi_writew -
+ *
+ *
+ */
+int spi_writew(struct spi_client *client, u16 value)
+{
+	return spi_write_mem(client, 16, (u8 *)&value, 1);
+}
+
+/**
+ * spi_read_mem -
+ *
+ *
+ */
+int spi_read_mem(struct spi_client *client, u8 fs, u8 *buffer, int len)
+{
+	struct spi_transfer transfer;
+	struct spi_adapter *adapter = client->adapter;
+	unsigned long flags;
+	int rc;
+
+	memset(&transfer, 0, sizeof (struct spi_transfer));
+
+	transfer.fs = fs;
+	transfer.mode = SPI_TRANSFER_MODE_READ_ONLY;
+	transfer.rbuf = buffer;
+	transfer.rlen = len;
+
+	spin_lock_irqsave(&adapter->lock, flags);
+	rc = adapter->do_transfer(adapter, &transfer, &client->config);
+	spin_unlock_irqrestore(&adapter->lock, flags);
+
+	/* deassert the chip select at least for this long */
+	udelay (1 + ((1000000 * client->config.cs_delay) / client->config.sc_rate));
+
+	return rc;
+}
+
+
+/**
+ * spi_read_single -
+ *
+ *
+ */
+int spi_read_single(struct spi_client *client, u8 fs, u16 *value)
+{
+	return spi_read_mem(client, fs, (u8 *) value, 1);
+}
+
+/**
+ * spi_readn -
+ *
+ *
+ */
+int spi_readn(struct spi_client *client, u4 *value)
+{
+	return spi_read_mem(client, 4, (u8 *)value, 1);
+}
+
+
+/**
+ * spi_readb -
+ *
+ *
+ */
+int spi_readb(struct spi_client *client, u8 *value)
+{
+	return spi_read_mem(client, 8, value, 1);
+}
+
+
+/**
+ * spi_readw -
+ *
+ *
+ */
+int spi_readw(struct spi_client *client, u16 *value)
+{
+	return spi_read_mem(client, 16, (u8 *)value, 1);
+}
+
+
+/**
+ * spi_read_mem -
+ *
+ *
+ */
+int spi_writeread_mem(struct spi_client *client, u8 fs, u8 *rbuffer, int rlen, u8 *wbuffer, int wlen)
+{
+	struct spi_transfer transfer;
+	struct spi_adapter *adapter = client->adapter;
+	unsigned long flags;
+	int rc;
+
+	memset(&transfer, 0, sizeof (struct spi_transfer));
+
+	transfer.fs = fs;
+	transfer.mode = SPI_TRANSFER_MODE_WRITE_READ;
+	transfer.rbuf = rbuffer;
+	transfer.rlen = rlen;
+	transfer.wbuf = wbuffer;
+	transfer.wlen = wlen;
+
+	spin_lock_irqsave(&adapter->lock, flags);
+	rc = adapter->do_transfer(adapter, &transfer, &client->config);
+	spin_unlock_irqrestore(&adapter->lock, flags);
+
+	/* deassert the chip select at least for this long */
+	udelay (1 + ((1000000 * client->config.cs_delay) / client->config.sc_rate));
+
+	return rc;
+}
+/**
+ * spi_add_adapter -
+ *
+ *
+ */
+int spi_add_adapter(struct spi_adapter *adapter)
+{
+	struct spi_driver *driver;
+	struct list_head *item;
+
+	printk(KERN_INFO "SPI core: add adapter %s\n", adapter->name);
+
+#ifdef _USE_DRIVER_MODEL_
+	sprintf(adapter->dev.bus_id, "spi-%d", adapter->nr);
+	adapter->dev.driver = &spi_adapter_driver;
+	adapter->dev.release = &spi_adapter_dev_release;
+	device_register(&adapter->dev);
+#endif
+
+	list_add(&adapter->list, &spi_adapters);
+	INIT_LIST_HEAD(&adapter->clients);
+
+	//adapter->lock = SPIN_LOCK_UNLOCKED;
+	//Above method is obsolete and new is used below.
+	spin_lock_init(&adapter->lock); 
+
+	list_for_each(item, &spi_drivers) {
+		driver = list_entry(item, struct spi_driver, list);
+		printk ("%s: Matching: adapter->bus_num=0x%x driver->bus_id 0x%x\n", __func__,\
+				adapter->bus_num, driver->bus_id);
+		if (driver->bus_id == adapter->bus_num)
+		{
+			printk ("%s: Found adapter 0x%x \n", __func__, adapter->bus_num);
+			/* We ignore the return code; if it fails, too bad */
+			driver->attach_adapter(adapter);
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * spi_del_adapter -
+ *
+ *
+ */
+int spi_del_adapter(struct spi_adapter *adapter)
+{
+	struct spi_client *client;
+	struct list_head *item, *_n;
+
+	printk(KERN_INFO "SPI core: del adapter %s\n", adapter->name);
+
+	list_for_each_safe(item, _n, &adapter->clients) {
+		client = list_entry(item, struct spi_client, list);
+
+		if (client->driver->detach_client(client))
+			goto out;
+	}
+
+	list_del(&adapter->list);
+
+#ifdef _USE_DRIVER_MODEL_
+	device_unregister(&adapter->dev);
+#endif
+
+      out:
+	return 0;
+}
+
+/**
+ * spi_attach_client -
+ *
+ *
+ */
+int spi_attach_client(struct spi_client *client)
+{
+	struct spi_adapter *adapter = client->adapter;
+	struct spi_client_config *config = &client->config;
+	struct spi_adapter_caps *caps = &adapter->caps;
+
+	printk(KERN_INFO "SPI core: attach client to adapter %s\n", client->adapter->name);
+
+	if ((config->sc_rate >= caps->max_sc_rate) || (config->sc_rate < caps->min_sc_rate)) {
+		printk(KERN_INFO "SPI core: client serial clock rate %ld out of range [%ld, %ld]", config->sc_rate,
+		       caps->min_sc_rate, caps->max_sc_rate);
+
+		goto err;
+	}
+
+	if (config->cs_msk & ~caps->cs_msk) {
+		printk(KERN_INFO "SPI core: client cs mask %#x not supported %#x", config->cs_msk,
+		       caps->cs_msk);
+
+		goto err;
+	}
+
+#ifdef _USE_DRIVER_MODEL_
+	device_register(&client->device);
+#endif
+	list_add(&client->list, &adapter->clients);
+
+	return 0;
+
+      err:
+	return -1;
+}
+
+/**
+ * spi_dettach_client -
+ *
+ *
+ */
+int spi_detach_client(struct spi_client *client)
+{
+	printk(KERN_INFO "SPI core: client detach from adapter %s\n", client->adapter->name);
+
+	list_del(&client->list);
+
+#ifdef _USE_DRIVER_MODEL_
+	device_unregister(&client->dev);
+#endif
+	return 0;
+}
+
+/**
+ * spi_add_driver -
+ *
+ *
+ */
+int spi_add_driver(struct spi_driver *driver)
+{
+	struct spi_adapter *adapter;
+	struct list_head *item;
+
+	printk(KERN_INFO "SPI core: add driver %s\n", driver->name);
+
+#ifdef _USE_DRIVER_MODEL_
+	driver->driver.name = driver->name;
+	driver->driver.bus = &spi2_bus_type;
+	driver->driver.probe = spi_device_probe;
+	driver->driver.remove = spi_device_remove;
+
+	if (driver_register(&driver->driver))
+		goto err;
+#endif
+	list_add(&driver->list, &spi_drivers);
+
+	list_for_each(item, &spi_adapters) {
+		adapter = list_entry(item, struct spi_adapter, list);
+		printk ("%s: Checking: adapter bus_num=0x%x driver bus_id=0x%x\n",\
+				__func__, adapter->bus_num, driver->bus_id);
+		if (driver->bus_id == adapter->bus_num)
+		{
+			printk ("%s: Found adapter 0x%x\n", __func__, adapter->bus_num);
+			driver->attach_adapter(adapter);
+			break;
+		}
+	}
+
+	return 0;
+
+#ifdef _USE_DRIVER_MODEL_
+      err:
+	return -1;
+#endif
+}
+
+/**
+ * spi_del_driver -
+ *
+ *
+ */
+int spi_del_driver(struct spi_driver *driver)
+{
+	struct list_head *item1, *item2, *_n;
+	struct spi_adapter *adapter;
+	struct spi_client *client;
+
+	printk(KERN_INFO "SPI core: delete driver %s\n", driver->name);
+
+	list_for_each(item1, &spi_adapters) {
+		adapter = list_entry(item1, struct spi_adapter, list);
+
+		list_for_each_safe(item2, _n, &adapter->clients) {
+			client = list_entry(item2, struct spi_client, list);
+			if (client->driver != driver)
+				continue;
+
+			if (driver->detach_client(client))
+				goto err;
+		}
+	}
+#ifdef _USE_DRIVER_MODEL_
+	driver_unregister(&driver->driver);
+#endif
+	list_del(&driver->list);
+
+	return 0;
+
+      err:
+	return -1;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+/* match always succeeds, as we want the probe() to tell if we really accept this match */
+static int spi2_device_match(struct device *dev, struct device_driver *drv)
+{
+	return 1;
+}
+
+struct bus_type spi2_bus_type = {
+	.name = "spi2",
+	.match = spi2_device_match,
+};
+
+/**
+ * spi_driver_init -
+ *
+ *
+ */
+static int __init spi_driver_init(void)
+{
+	int retval;
+
+	printk(KERN_INFO "SPI core: loaded version 0.2\n");
+
+	retval = bus_register(&spi2_bus_type);
+	if (retval)
+		goto err0;
+
+#ifdef _USE_DRIVER_MODEL_
+	retval = driver_register(&spi_driver);
+	if (retval)
+		goto err1;
+#endif
+
+	return 0;
+
+#ifdef _USE_DRIVER_MODEL_
+  err1:
+	bus_unregister(&spi2_bus_type);
+#endif
+
+  err0:
+	return retval;
+}
+
+/**
+ * spi_driver_exit -
+ *
+ *
+ */
+static void __exit spi_driver_exit(void)
+{
+#ifdef _USE_DRIVER_MODEL_
+	driver_unregister(&spi_driver);
+#endif
+	bus_unregister(&spi2_bus_type);
+}
+
+subsys_initcall(spi_driver_init);
+#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) */
+
+static int __init spi_driver_init(void)
+{
+	printk(KERN_INFO "SPI core: loaded version 0.2\n");
+
+	return 0;
+}
+
+static void __exit spi_driver_exit(void)
+{
+
+}
+
+module_init(spi_driver_init);
+
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) */
+
+module_exit(spi_driver_exit);
+
+EXPORT_SYMBOL(spi_add_driver);
+EXPORT_SYMBOL(spi_del_driver);
+
+EXPORT_SYMBOL(spi_add_adapter);
+EXPORT_SYMBOL(spi_del_adapter);
+
+EXPORT_SYMBOL(spi_attach_client);
+EXPORT_SYMBOL(spi_detach_client);
+
+EXPORT_SYMBOL(spi_write_single);
+EXPORT_SYMBOL(spi_write_mem);
+
+EXPORT_SYMBOL(spi_writen);
+EXPORT_SYMBOL(spi_writeb);
+EXPORT_SYMBOL(spi_writew);
+
+EXPORT_SYMBOL(spi_read_mem);
+EXPORT_SYMBOL(spi_read_single);
+EXPORT_SYMBOL(spi_writeread_mem);
+
+EXPORT_SYMBOL(spi_readn);
+EXPORT_SYMBOL(spi_readb);
+EXPORT_SYMBOL(spi_readw);
+
+MODULE_AUTHOR("Rui Sousa <rui.sousa@mindspeed.com>");
+MODULE_DESCRIPTION("SPI core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig
index 830cd62..bfb5415 100644
--- a/drivers/tty/Kconfig
+++ b/drivers/tty/Kconfig
@@ -1,6 +1,6 @@
 config VT
 	bool "Virtual terminal" if EXPERT
-	depends on !S390 && !UML
+	depends on !S390 && !UML && !ARCH_COMCERTO
 	select INPUT
 	default y
 	---help---
diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c
index 70585b6..ad90014 100644
--- a/drivers/tty/serial/8250.c
+++ b/drivers/tty/serial/8250.c
@@ -48,6 +48,12 @@
 #include "suncore.h"
 #endif
 
+#ifdef CONFIG_ARCH_M86XXX
+#include <linux/clk.h>
+#include <mach/reset.h>
+static struct clk *uart_clk;     /*UART Clock(DUS) depends upon the AXI*/
+#endif 
+
 /*
  * Configuration:
  *   share_irqs - whether we pass IRQF_SHARED to request_irq().  This option
@@ -420,10 +426,36 @@
 	return readb(p->membase + offset);
 }
 
+#ifdef CONFIG_ARCH_M86XXX
+void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p);
+
+void dw8250_force_idle(struct uart_port *p)
+{
+	struct uart_8250_port *up = container_of(p, struct uart_8250_port, port);
+
+	serial8250_clear_and_reinit_fifos(up);
+	(void)p->serial_in(p, UART_RX);
+}
+#endif
+
 static void mem_serial_out(struct uart_port *p, int offset, int value)
 {
-	offset = map_8250_out_reg(p, offset) << p->regshift;
-	writeb(value, p->membase + offset);
+	int offset1 = map_8250_out_reg(p, offset) << p->regshift;
+	writeb(value, p->membase + offset1);
+
+#ifdef CONFIG_ARCH_M86XXX
+	/* Make sure LCR write wasn't ignored */
+	if (offset == UART_LCR) {
+		int tries = 1000;
+		while (tries--) {
+			if (value == p->serial_in(p, UART_LCR))
+				return;
+			dw8250_force_idle(p);
+			writeb(value, p->membase + offset1);
+		}
+		dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+	}
+#endif
 }
 
 static void mem32_serial_out(struct uart_port *p, int offset, int value)
@@ -616,6 +648,17 @@
 	}
 }
 
+#ifdef CONFIG_ARCH_M86XXX
+void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p)
+{
+         unsigned char fcr;
+
+         serial8250_clear_fifos(p);
+         fcr = uart_config[p->port.type].fcr;
+         serial_outp(p, UART_FCR, fcr);
+}
+#endif
+
 /*
  * IER sleep support.  UARTs which have EFRs need the "extended
  * capability" bit enabled.  Note that on XR16C850s, we need to
@@ -2342,11 +2385,17 @@
 	 * have sufficient FIFO entries for the latency of the remote
 	 * UART to respond.  IOW, at least 32 bytes of FIFO.
 	 */
+#ifdef CONFIG_ARCH_M86XXX
+	up->mcr &= ~UART_MCR_AFE;
+        if (termios->c_cflag & CRTSCTS)
+               up->mcr |= UART_MCR_AFE;
+#else
 	if (up->capabilities & UART_CAP_AFE && up->port.fifosize >= 32) {
 		up->mcr &= ~UART_MCR_AFE;
 		if (termios->c_cflag & CRTSCTS)
 			up->mcr |= UART_MCR_AFE;
 	}
+#endif
 
 	/*
 	 * Ok, we're now changing the port state.  Do it with
@@ -3055,6 +3104,31 @@
 	struct uart_port port;
 	int ret, i, irqflag = 0;
 
+#ifdef CONFIG_ARCH_M86XXX
+	unsigned long uart_rate;
+
+	/* Take the Fast-UART device Out-Of-Reset*/
+	c2000_block_reset(COMPONENT_AXI_FAST_UART,0);
+
+	/* Get the FAST-UART clk structure from DUS */	
+	uart_clk = clk_get(NULL,"DUS");
+	
+	if (IS_ERR(uart_clk)) {
+		pr_err("%s: Unable to get UART clock: %ld\n",__func__,PTR_ERR(uart_clk));
+		return PTR_ERR(uart_clk);
+        }
+	
+	/* Enable the FAST-UART Clock */
+	ret = clk_enable(uart_clk);
+	if (ret){
+                pr_err("%s: UART clock failed to enable:\n",__func__);
+		return  ret;       
+	}
+	
+	/* Get the UART Clock in Hz */
+	uart_rate = clk_get_rate(uart_clk);
+#endif
+
 	memset(&port, 0, sizeof(struct uart_port));
 
 	if (share_irqs)
@@ -3065,7 +3139,11 @@
 		port.membase		= p->membase;
 		port.irq		= p->irq;
 		port.irqflags		= p->irqflags;
-		port.uartclk		= p->uartclk;
+#ifdef CONFIG_ARCH_M86XXX
+		port.uartclk		= uart_rate;    /* Assigning the rate value to the ports */
+#else	
+		port.uartclk		= p->uartclk;   /* Assigning the rate value got from Platfrom device*/
+#endif
 		port.regshift		= p->regshift;
 		port.iotype		= p->iotype;
 		port.flags		= p->flags;
@@ -3088,6 +3166,7 @@
 				p->irq, ret);
 		}
 	}
+
 	return 0;
 }
 
@@ -3104,9 +3183,19 @@
 		if (up->port.dev == &dev->dev)
 			serial8250_unregister_port(i);
 	}
+#ifdef CONFIG_ARCH_M86XXX
+	/*Disable the Fast-UART clock here*/
+	clk_disable(uart_clk);	
+	clk_put(uart_clk);
+
+	/* Put the  Fast-UART device in Reset*/
+	c2000_block_reset(COMPONENT_AXI_FAST_UART,1);
+#endif
+
 	return 0;
 }
 
+#if CONFIG_PM
 static int serial8250_suspend(struct platform_device *dev, pm_message_t state)
 {
 	int i;
@@ -3118,6 +3207,16 @@
 			uart_suspend_port(&serial8250_reg, &up->port);
 	}
 
+#ifdef CONFIG_ARCH_M86XXX
+	/* Now Do the FAST_UART_CLOCK gating here, be sure no other devices
+	 * are using the DUS clock to shutdown the clock. 
+	 * Here above clock is derived from DUS , henece it will be not
+	 * gated , unless and until DMA/FAST-SPI will disable the DUS clock 
+	 * to make the usecount 0.
+	*/
+	clk_disable(uart_clk);
+#endif
+
 	return 0;
 }
 
@@ -3125,6 +3224,20 @@
 {
 	int i;
 
+#ifdef CONFIG_ARCH_M86XXX
+	/* Now Enable the FAST_UART_CLOCK here , before 
+	 * before resuming any opertions.
+	 */
+	if (clk_enable(uart_clk)){
+                pr_err("%s: Unable to enable FAST-UART clock: \n",__func__);
+		/* Here we are not able to enable the FAST-UART clock , 
+		 * beacause of clk_disable unable to shutdown( usecount is 
+		 * not zero ,due to dependancy with DMA and FAST-SPI) clock
+		 * so Let resume the port only .
+		 */ 
+        }
+#endif
+
 	for (i = 0; i < UART_NR; i++) {
 		struct uart_8250_port *up = &serial8250_ports[i];
 
@@ -3134,12 +3247,15 @@
 
 	return 0;
 }
+#endif
 
 static struct platform_driver serial8250_isa_driver = {
 	.probe		= serial8250_probe,
 	.remove		= __devexit_p(serial8250_remove),
+#if CONFIG_PM
 	.suspend	= serial8250_suspend,
 	.resume		= serial8250_resume,
+#endif
 	.driver		= {
 		.name	= "serial8250",
 		.owner	= THIS_MODULE,
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 791f11b..e5d25bb 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -80,7 +80,8 @@
 # some non-PCI HCDs implement xHCI
 config USB_ARCH_HAS_XHCI
 	boolean
-	default PCI
+        default y
+#	default PCI
 
 # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
 config USB
@@ -181,4 +182,6 @@
 
 source "drivers/usb/otg/Kconfig"
 
+source "drivers/usb/dwc_otg/Kconfig"
+
 endif # USB_SUPPORT
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 75eca76..ff19eba 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -49,6 +49,8 @@
 obj-$(CONFIG_USB_ATM)		+= atm/
 obj-$(CONFIG_USB_SPEEDTOUCH)	+= atm/
 
+obj-$(CONFIG_DWC_OTG)		+= dwc_otg/
+
 obj-$(CONFIG_USB_MUSB_HDRC)	+= musb/
 obj-$(CONFIG_USB_RENESAS_USBHS)	+= renesas_usbhs/
 obj-$(CONFIG_USB_OTG_UTILS)	+= otg/
diff --git a/drivers/usb/dwc_otg/Kconfig b/drivers/usb/dwc_otg/Kconfig
new file mode 100644
index 0000000..2868292
--- /dev/null
+++ b/drivers/usb/dwc_otg/Kconfig
@@ -0,0 +1,37 @@
+config DWC_OTG
+        tristate "Synopsis DWC_OTG support"
+        depends on USB_SUPPORT
+        help
+          This driver supports Synopsis DWC_OTG IP core
+		  embebbed on many SOCs (ralink, infineon, etc)
+
+choice
+        prompt "USB Operation Mode"
+        depends on DWC_OTG
+        default DWC_OTG_HOST_ONLY
+
+config DWC_OTG_HOST_ONLY
+        bool "HOST ONLY MODE"
+        depends on DWC_OTG
+
+config DWC_OTG_DEVICE_ONLY
+        bool "DEVICE ONLY MODE"
+        depends on DWC_OTG
+endchoice
+
+choice
+        prompt "Platform"
+        depends on DWC_OTG
+        default DWC_OTG_COMCERTO
+
+config DWC_OTG_COMCERTO
+        bool "Comcerto 2000"
+        depends on ARCH_COMCERTO
+        help
+          USB 2.0 USB Host Controller
+		  platform support
+endchoice
+
+config DWC_OTG_DEBUG
+        bool "Enable debug mode"
+        depends on DWC_OTG
diff --git a/drivers/usb/dwc_otg/Makefile b/drivers/usb/dwc_otg/Makefile
new file mode 100644
index 0000000..6cc1e97
--- /dev/null
+++ b/drivers/usb/dwc_otg/Makefile
@@ -0,0 +1,28 @@
+#
+# Makefile for DWC_otg Highspeed USB controller driver
+#
+
+ifeq ($(CONFIG_DWC_OTG_DEBUG),y)
+endif
+
+# Use one of the following flags to compile the software in host-only or
+# device-only mode.
+ifeq ($(CONFIG_DWC_OTG_HOST_ONLY),y)
+EXTRA_CFLAGS   += -DDWC_HOST_ONLY
+EXTRA_CFLAGS   += -DDWC_EN_ISOC
+EXTRA_CFLAGS   += -DDWC_LINUX
+EXTRA_CFLAGS	+= -DDWC_LIBMODULE
+endif
+
+ifeq ($(CONFIG_DWC_OTG_DEVICE_ONLY),y)
+EXTRA_CFLAGS   += -DDWC_DEVICE_ONLY
+endif
+
+obj-$(CONFIG_DWC_OTG)	:= dwc_otg.o
+
+dwc_otg-objs	:= dwc_otg_driver.o dwc_otg_attr.o
+dwc_otg-objs	+= dwc_otg_cil.o dwc_otg_cil_intr.o
+dwc_otg-objs	+= dwc_otg_hcd_linux.o dwc_otg_adp.o dwc_otg_cfi.o 
+dwc_otg-objs	+= dwc_otg_hcd_ddma.o
+dwc_otg-objs	+= dwc_otg_hcd.o dwc_otg_hcd_intr.o dwc_otg_hcd_queue.o
+dwc_otg-objs	+= dwc_common_linux.o dwc_mem.o
diff --git a/drivers/usb/dwc_otg/dwc_cc.c b/drivers/usb/dwc_otg/dwc_cc.c
new file mode 100644
index 0000000..327b21e
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_cc.c
@@ -0,0 +1,532 @@
+/* =========================================================================
+ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.c $
+ * $Revision: #4 $
+ * $Date: 2010/11/04 $
+ * $Change: 1621692 $
+ *
+ * Synopsys Portability Library Software and documentation
+ * (hereinafter, "Software") is an Unsupported proprietary work of
+ * Synopsys, Inc. unless otherwise expressly agreed to in writing
+ * between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product
+ * under any End User Software License Agreement or Agreement for
+ * Licensed Product with Synopsys or any supplement thereto. You are
+ * permitted to use and redistribute this Software in source and binary
+ * forms, with or without modification, provided that redistributions
+ * of source code must retain this notice. You may not view, use,
+ * disclose, copy or distribute this file or any information contained
+ * herein except pursuant to this license grant from Synopsys. If you
+ * do not agree with this notice, including the disclaimer below, then
+ * you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
+ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
+ * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================= */
+#ifdef DWC_CCLIB
+
+#include "dwc_cc.h"
+
+typedef struct dwc_cc
+{
+	uint32_t uid;
+	uint8_t chid[16];
+	uint8_t cdid[16];
+	uint8_t ck[16];
+	uint8_t *name;
+	uint8_t length;
+        DWC_CIRCLEQ_ENTRY(dwc_cc) list_entry;
+} dwc_cc_t;
+
+DWC_CIRCLEQ_HEAD(context_list, dwc_cc);
+
+/** The main structure for CC management.  */
+struct dwc_cc_if
+{
+	dwc_mutex_t *mutex;
+	char *filename;
+
+	unsigned is_host:1;
+
+	dwc_notifier_t *notifier;
+
+	struct context_list list;
+};
+
+#ifdef DEBUG
+static inline void dump_bytes(char *name, uint8_t *bytes, int len)
+{
+	int i;
+	DWC_PRINTF("%s: ", name);
+	for (i=0; i<len; i++) {
+		DWC_PRINTF("%02x ", bytes[i]);
+	}
+	DWC_PRINTF("\n");
+}
+#else
+#define dump_bytes(x...)
+#endif
+
+static dwc_cc_t *alloc_cc(void *mem_ctx, uint8_t *name, uint32_t length)
+{
+	dwc_cc_t *cc = dwc_alloc(mem_ctx, sizeof(dwc_cc_t));
+	if (!cc) {
+		return NULL;
+	}
+	DWC_MEMSET(cc, 0, sizeof(dwc_cc_t));
+
+	if (name) {
+		cc->length = length;
+		cc->name = dwc_alloc(mem_ctx, length);
+		if (!cc->name) {
+			dwc_free(mem_ctx, cc);
+			return NULL;
+		}
+
+		DWC_MEMCPY(cc->name, name, length);
+	}
+
+	return cc;
+}
+
+static void free_cc(void *mem_ctx, dwc_cc_t *cc)
+{
+	if (cc->name) {
+		dwc_free(mem_ctx, cc->name);
+	}
+	dwc_free(mem_ctx, cc);
+}
+
+static uint32_t next_uid(dwc_cc_if_t *cc_if)
+{
+	uint32_t uid = 0;
+	dwc_cc_t *cc;
+	DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
+		if (cc->uid > uid) {
+			uid = cc->uid;
+		}
+	}
+
+	if (uid == 0) {
+		uid = 255;
+	}
+
+	return uid + 1;
+}
+
+static dwc_cc_t *cc_find(dwc_cc_if_t *cc_if, uint32_t uid)
+{
+	dwc_cc_t *cc;
+	DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
+		if (cc->uid == uid) {
+			return cc;
+		}
+	}
+	return NULL;
+}
+
+static unsigned int cc_data_size(dwc_cc_if_t *cc_if)
+{
+	unsigned int size = 0;
+	dwc_cc_t *cc;
+	DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
+		size += (48 + 1);
+		if (cc->name) {
+			size += cc->length;
+		}
+	}
+	return size;
+}
+
+static uint32_t cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
+{
+	uint32_t uid = 0;
+	dwc_cc_t *cc;
+
+	DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
+		if (DWC_MEMCMP(cc->chid, chid, 16) == 0) {
+			uid = cc->uid;
+			break;
+		}
+	}
+	return uid;
+}
+static uint32_t cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
+{
+	uint32_t uid = 0;
+	dwc_cc_t *cc;
+
+	DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
+		if (DWC_MEMCMP(cc->cdid, cdid, 16) == 0) {
+			uid = cc->uid;
+			break;
+		}
+	}
+	return uid;
+}
+
+/* Internal cc_add */
+static int32_t cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
+		      uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
+{
+	dwc_cc_t *cc;
+	uint32_t uid;
+
+	if (cc_if->is_host) {
+		uid = cc_match_cdid(cc_if, cdid);
+	}
+	else {
+		uid = cc_match_chid(cc_if, chid);
+	}
+
+	if (uid) {
+		DWC_DEBUG("Replacing previous connection context id=%d name=%p name_len=%d", uid, name, length);
+		cc = cc_find(cc_if, uid);
+	}
+	else {
+		cc = alloc_cc(mem_ctx, name, length);
+		cc->uid = next_uid(cc_if);
+		DWC_CIRCLEQ_INSERT_TAIL(&cc_if->list, cc, list_entry);
+	}
+
+	DWC_MEMCPY(&(cc->chid[0]), chid, 16);
+	DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
+	DWC_MEMCPY(&(cc->ck[0]), ck, 16);
+
+	DWC_DEBUG("Added connection context id=%d name=%p name_len=%d", cc->uid, name, length);
+	dump_bytes("CHID", cc->chid, 16);
+	dump_bytes("CDID", cc->cdid, 16);
+	dump_bytes("CK", cc->ck, 16);
+	return cc->uid;
+}
+
+/* Internal cc_clear */
+static void cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
+{
+	while (!DWC_CIRCLEQ_EMPTY(&cc_if->list)) {
+		dwc_cc_t *cc = DWC_CIRCLEQ_FIRST(&cc_if->list);
+		DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
+		free_cc(mem_ctx, cc);
+	}
+}
+
+dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx, 
+			     dwc_notifier_t *notifier, unsigned is_host)
+{
+	dwc_cc_if_t *cc_if = NULL;
+
+	/* Allocate a common_cc_if structure */
+	cc_if = dwc_alloc(mem_ctx, sizeof(dwc_cc_if_t));
+
+	if (!cc_if)
+		return NULL;
+
+#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
+	DWC_MUTEX_ALLOC_LINUX_DEBUG(cc_if->mutex);
+#else
+	cc_if->mutex = dwc_mutex_alloc(mtx_ctx);
+#endif
+	if (!cc_if->mutex) {
+		dwc_free(mem_ctx, cc_if);
+		return NULL;
+	}
+
+	DWC_CIRCLEQ_INIT(&cc_if->list);
+	cc_if->is_host = is_host;
+	cc_if->notifier = notifier;
+	return cc_if;
+}
+
+void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if)
+{
+#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
+	DWC_MUTEX_FREE(cc_if->mutex);
+#else
+	dwc_mutex_free(mtx_ctx, cc_if->mutex);
+#endif
+	cc_clear(mem_ctx, cc_if);
+	dwc_free(mem_ctx, cc_if);
+}
+
+static void cc_changed(dwc_cc_if_t *cc_if)
+{
+	if (cc_if->notifier) {
+		dwc_notify(cc_if->notifier, DWC_CC_LIST_CHANGED_NOTIFICATION, cc_if);
+	}
+}
+
+void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
+{
+	DWC_MUTEX_LOCK(cc_if->mutex);
+	cc_clear(mem_ctx, cc_if);
+	DWC_MUTEX_UNLOCK(cc_if->mutex);
+	cc_changed(cc_if);
+}
+
+int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
+		   uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
+{
+	uint32_t uid;
+
+	DWC_MUTEX_LOCK(cc_if->mutex);
+	uid = cc_add(mem_ctx, cc_if, chid, cdid, ck, name, length);
+	DWC_MUTEX_UNLOCK(cc_if->mutex);
+	cc_changed(cc_if);
+
+	return uid;
+}
+
+void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id, uint8_t *chid,
+		   uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
+{
+	dwc_cc_t* cc;
+
+	DWC_DEBUG("Change connection context %d", id);
+
+	DWC_MUTEX_LOCK(cc_if->mutex);
+	cc = cc_find(cc_if, id);
+	if (!cc) {
+		DWC_ERROR("Uid %d not found in cc list\n", id);
+		DWC_MUTEX_UNLOCK(cc_if->mutex);
+		return;
+	}
+
+	if (chid) {
+		DWC_MEMCPY(&(cc->chid[0]), chid, 16);
+	}
+	if (cdid) {
+		DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
+	}
+	if (ck) {
+		DWC_MEMCPY(&(cc->ck[0]), ck, 16);
+	}
+
+	if (name) {
+		if (cc->name) {
+			dwc_free(mem_ctx, cc->name);
+		}
+		cc->name = dwc_alloc(mem_ctx, length);
+		if (!cc->name) {
+			DWC_ERROR("Out of memory in dwc_cc_change()\n");
+			DWC_MUTEX_UNLOCK(cc_if->mutex);
+			return;
+		}
+		cc->length = length;
+		DWC_MEMCPY(cc->name, name, length);
+	}
+
+	DWC_MUTEX_UNLOCK(cc_if->mutex);
+
+	cc_changed(cc_if);
+
+	DWC_DEBUG("Changed connection context id=%d\n", id);
+	dump_bytes("New CHID", cc->chid, 16);
+	dump_bytes("New CDID", cc->cdid, 16);
+	dump_bytes("New CK", cc->ck, 16);
+}
+
+void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id)
+{
+	dwc_cc_t *cc;
+
+	DWC_DEBUG("Removing connection context %d", id);
+
+	DWC_MUTEX_LOCK(cc_if->mutex);
+	cc = cc_find(cc_if, id);
+	if (!cc) {
+		DWC_ERROR("Uid %d not found in cc list\n", id);
+		DWC_MUTEX_UNLOCK(cc_if->mutex);
+		return;
+	}
+
+	DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
+	DWC_MUTEX_UNLOCK(cc_if->mutex);
+	free_cc(mem_ctx, cc);
+
+	cc_changed(cc_if);
+}
+
+uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if, unsigned int *length)
+{
+	uint8_t *buf, *x;
+	uint8_t zero = 0;
+	dwc_cc_t *cc;
+
+	DWC_MUTEX_LOCK(cc_if->mutex);
+	*length = cc_data_size(cc_if);
+	if (!(*length)) {
+		DWC_MUTEX_UNLOCK(cc_if->mutex);
+		return NULL;
+	}
+
+	DWC_DEBUG("Creating data for saving (length=%d)", *length);
+
+	buf = dwc_alloc(mem_ctx, *length);
+	if (!buf) {
+		*length = 0;
+		DWC_MUTEX_UNLOCK(cc_if->mutex);
+		return NULL;
+	}
+
+	x = buf;
+	DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
+		DWC_MEMCPY(x, cc->chid, 16);
+		x += 16;
+		DWC_MEMCPY(x, cc->cdid, 16);
+		x += 16;
+		DWC_MEMCPY(x, cc->ck, 16);
+		x += 16;
+		if (cc->name) {
+			DWC_MEMCPY(x, &cc->length, 1);
+			x += 1;
+			DWC_MEMCPY(x, cc->name, cc->length);
+			x += cc->length;
+		}
+		else {
+			DWC_MEMCPY(x, &zero, 1);
+			x += 1;
+		}
+	}
+	DWC_MUTEX_UNLOCK(cc_if->mutex);
+
+	return buf;
+}
+
+void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *data, uint32_t length)
+{
+	uint8_t name_length;
+	uint8_t *name;
+	uint8_t *chid;
+	uint8_t *cdid;
+	uint8_t *ck;
+	uint32_t i = 0;
+
+	DWC_MUTEX_LOCK(cc_if->mutex);
+	cc_clear(mem_ctx, cc_if);
+
+	while (i < length) {
+		chid = &data[i];
+		i += 16;
+		cdid = &data[i];
+		i += 16;
+		ck = &data[i];
+		i += 16;
+
+		name_length = data[i];
+		i ++;
+
+		if (name_length) {
+			name = &data[i];
+			i += name_length;
+		}
+		else {
+			name = NULL;
+		}
+
+		/* check to see if we haven't overflown the buffer */
+		if (i > length) {
+			DWC_ERROR("Data format error while attempting to load CCs "
+				  "(nlen=%d, iter=%d, buflen=%d).\n", name_length, i, length);
+			break;
+		}
+
+		cc_add(mem_ctx, cc_if, chid, cdid, ck, name, name_length);
+	}
+	DWC_MUTEX_UNLOCK(cc_if->mutex);
+
+	cc_changed(cc_if);
+}
+
+uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
+{
+	uint32_t uid = 0;
+
+	DWC_MUTEX_LOCK(cc_if->mutex);
+	uid = cc_match_chid(cc_if, chid);
+	DWC_MUTEX_UNLOCK(cc_if->mutex);
+	return uid;
+}
+uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
+{
+	uint32_t uid = 0;
+
+	DWC_MUTEX_LOCK(cc_if->mutex);
+	uid = cc_match_cdid(cc_if, cdid);
+	DWC_MUTEX_UNLOCK(cc_if->mutex);
+	return uid;
+}
+
+uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id)
+{
+	uint8_t *ck = NULL;
+	dwc_cc_t *cc;
+
+	DWC_MUTEX_LOCK(cc_if->mutex);
+	cc = cc_find(cc_if, id);
+	if (cc) {
+		ck = cc->ck;
+	}
+	DWC_MUTEX_UNLOCK(cc_if->mutex);
+
+	return ck;
+
+}
+
+uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id)
+{
+	uint8_t *retval = NULL;
+	dwc_cc_t *cc;
+
+	DWC_MUTEX_LOCK(cc_if->mutex);
+	cc = cc_find(cc_if, id);
+	if (cc) {
+		retval = cc->chid;
+	}
+	DWC_MUTEX_UNLOCK(cc_if->mutex);
+
+	return retval;
+}
+
+uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id)
+{
+	uint8_t *retval = NULL;
+	dwc_cc_t *cc;
+
+	DWC_MUTEX_LOCK(cc_if->mutex);
+	cc = cc_find(cc_if, id);
+	if (cc) {
+		retval = cc->cdid;
+	}
+	DWC_MUTEX_UNLOCK(cc_if->mutex);
+
+	return retval;
+}
+
+uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length)
+{
+	uint8_t *retval = NULL;
+	dwc_cc_t *cc;
+
+	DWC_MUTEX_LOCK(cc_if->mutex);
+	*length = 0;
+	cc = cc_find(cc_if, id);
+	if (cc) {
+		*length = cc->length;
+		retval = cc->name;
+	}
+	DWC_MUTEX_UNLOCK(cc_if->mutex);
+
+	return retval;
+}
+
+#endif	/* DWC_CCLIB */
diff --git a/drivers/usb/dwc_otg/dwc_cc.h b/drivers/usb/dwc_otg/dwc_cc.h
new file mode 100644
index 0000000..6b2bbaf
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_cc.h
@@ -0,0 +1,225 @@
+/* =========================================================================
+ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.h $
+ * $Revision: #4 $
+ * $Date: 2010/09/28 $
+ * $Change: 1596182 $
+ *
+ * Synopsys Portability Library Software and documentation
+ * (hereinafter, "Software") is an Unsupported proprietary work of
+ * Synopsys, Inc. unless otherwise expressly agreed to in writing
+ * between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product
+ * under any End User Software License Agreement or Agreement for
+ * Licensed Product with Synopsys or any supplement thereto. You are
+ * permitted to use and redistribute this Software in source and binary
+ * forms, with or without modification, provided that redistributions
+ * of source code must retain this notice. You may not view, use,
+ * disclose, copy or distribute this file or any information contained
+ * herein except pursuant to this license grant from Synopsys. If you
+ * do not agree with this notice, including the disclaimer below, then
+ * you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
+ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
+ * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================= */
+#ifndef _DWC_CC_H_
+#define _DWC_CC_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @file
+ *
+ * This file defines the Context Context library.
+ *
+ * The main data structure is dwc_cc_if_t which is returned by either the
+ * dwc_cc_if_alloc function or returned by the module to the user via a provided
+ * function. The data structure is opaque and should only be manipulated via the
+ * functions provied in this API.
+ *
+ * It manages a list of connection contexts and operations can be performed to
+ * add, remove, query, search, and change, those contexts.  Additionally,
+ * a dwc_notifier_t object can be requested from the manager so that
+ * the user can be notified whenever the context list has changed.
+ */
+
+#include "dwc_os.h"
+#include "dwc_list.h"
+#include "dwc_notifier.h"
+
+
+/* Notifications */
+#define DWC_CC_LIST_CHANGED_NOTIFICATION "DWC_CC_LIST_CHANGED_NOTIFICATION"
+
+struct dwc_cc_if;
+typedef struct dwc_cc_if dwc_cc_if_t;
+
+
+/** @name Connection Context Operations */
+/** @{ */
+
+/** This function allocates memory for a dwc_cc_if_t structure, initializes
+ * fields to default values, and returns a pointer to the structure or NULL on
+ * error. */
+extern dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx,
+				    dwc_notifier_t *notifier, unsigned is_host);
+
+/** Frees the memory for the specified CC structure allocated from
+ * dwc_cc_if_alloc(). */
+extern void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if);
+
+/** Removes all contexts from the connection context list */
+extern void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if);
+
+/** Adds a connection context (CHID, CK, CDID, Name) to the connection context list.
+ * If a CHID already exists, the CK and name are overwritten.  Statistics are
+ * not overwritten.
+ *
+ * @param cc_if The cc_if structure.
+ * @param chid A pointer to the 16-byte CHID.  This value will be copied.
+ * @param ck A pointer to the 16-byte CK.  This value will be copied.
+ * @param cdid A pointer to the 16-byte CDID.  This value will be copied.
+ * @param name An optional host friendly name as defined in the association model
+ * spec.  Must be a UTF16-LE unicode string.  Can be NULL to indicated no name.
+ * @param length The length othe unicode string.
+ * @return A unique identifier used to refer to this context that is valid for
+ * as long as this context is still in the list. */
+extern int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
+			  uint8_t *cdid, uint8_t *ck, uint8_t *name,
+			  uint8_t length);
+
+/** Changes the CHID, CK, CDID, or Name values of a connection context in the
+ * list, preserving any accumulated statistics.  This would typically be called
+ * if the host decideds to change the context with a SET_CONNECTION request.
+ *
+ * @param cc_if The cc_if structure.
+ * @param id The identifier of the connection context.
+ * @param chid A pointer to the 16-byte CHID.  This value will be copied.  NULL
+ * indicates no change.
+ * @param cdid A pointer to the 16-byte CDID.  This value will be copied.  NULL
+ * indicates no change.
+ * @param ck A pointer to the 16-byte CK.  This value will be copied.  NULL
+ * indicates no change.
+ * @param name Host friendly name UTF16-LE.  NULL indicates no change.
+ * @param length Length of name. */
+extern void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id,
+			  uint8_t *chid, uint8_t *cdid, uint8_t *ck,
+			  uint8_t *name, uint8_t length);
+
+/** Remove the specified connection context.
+ * @param cc_if The cc_if structure.
+ * @param id The identifier of the connection context to remove. */
+extern void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id);
+
+/** Get a binary block of data for the connection context list and attributes.
+ * This data can be used by the OS specific driver to save the connection
+ * context list into non-volatile memory.
+ *
+ * @param cc_if The cc_if structure.
+ * @param length Return the length of the data buffer.
+ * @return A pointer to the data buffer.  The memory for this buffer should be
+ * freed with DWC_FREE() after use. */
+extern uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if,
+				     unsigned int *length);
+
+/** Restore the connection context list from the binary data that was previously
+ * returned from a call to dwc_cc_data_for_save.  This can be used by the OS specific
+ * driver to load a connection context list from non-volatile memory.
+ *
+ * @param cc_if The cc_if structure.
+ * @param data The data bytes as returned from dwc_cc_data_for_save.
+ * @param length The length of the data. */
+extern void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if,
+				     uint8_t *data, unsigned int length);
+
+/** Find the connection context from the specified CHID.
+ *
+ * @param cc_if The cc_if structure.
+ * @param chid A pointer to the CHID data.
+ * @return A non-zero identifier of the connection context if the CHID matches.
+ * Otherwise returns 0. */
+extern uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid);
+
+/** Find the connection context from the specified CDID.
+ *
+ * @param cc_if The cc_if structure.
+ * @param cdid A pointer to the CDID data.
+ * @return A non-zero identifier of the connection context if the CHID matches.
+ * Otherwise returns 0. */
+extern uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid);
+
+/** Retrieve the CK from the specified connection context.
+ *
+ * @param cc_if The cc_if structure.
+ * @param id The identifier of the connection context.
+ * @return A pointer to the CK data.  The memory does not need to be freed. */
+extern uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id);
+
+/** Retrieve the CHID from the specified connection context.
+ *
+ * @param cc_if The cc_if structure.
+ * @param id The identifier of the connection context.
+ * @return A pointer to the CHID data.  The memory does not need to be freed. */
+extern uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id);
+
+/** Retrieve the CDID from the specified connection context.
+ *
+ * @param cc_if The cc_if structure.
+ * @param id The identifier of the connection context.
+ * @return A pointer to the CDID data.  The memory does not need to be freed. */
+extern uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id);
+
+extern uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length);
+
+/** Checks a buffer for non-zero.
+ * @param id A pointer to a 16 byte buffer. 
+ * @return true if the 16 byte value is non-zero. */
+static inline unsigned dwc_assoc_is_not_zero_id(uint8_t *id) {
+	int i;
+	for (i=0; i<16; i++) {
+		if (id[i]) return 1;
+	}
+	return 0;
+}
+
+/** Checks a buffer for zero.
+ * @param id A pointer to a 16 byte buffer. 
+ * @return true if the 16 byte value is zero. */
+static inline unsigned dwc_assoc_is_zero_id(uint8_t *id) {
+	return !dwc_assoc_is_not_zero_id(id);
+}
+
+/** Prints an ASCII representation for the 16-byte chid, cdid, or ck, into
+ * buffer. */
+static inline int dwc_print_id_string(char *buffer, uint8_t *id) {
+	char *ptr = buffer;
+	int i;
+	for (i=0; i<16; i++) {
+		ptr += DWC_SPRINTF(ptr, "%02x", id[i]);
+		if (i < 15) {
+			ptr += DWC_SPRINTF(ptr, " ");
+		}
+	}
+	return ptr - buffer;
+}
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DWC_CC_H_ */
+
diff --git a/drivers/usb/dwc_otg/dwc_cfi_common.h b/drivers/usb/dwc_otg/dwc_cfi_common.h
new file mode 100644
index 0000000..be56af4
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_cfi_common.h
@@ -0,0 +1,142 @@
+/* ==========================================================================
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ * 
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ * 
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+#if !defined(__DWC_CFI_COMMON_H__)
+#define __DWC_CFI_COMMON_H__
+
+//#include <linux/types.h>
+
+/**
+ * @file 
+ *
+ * This file contains the CFI specific common constants, interfaces
+ * (functions and macros) and structures for Linux. No PCD specific
+ * data structure or definition is to be included in this file.
+ *
+ */
+
+/** This is a request for all Core Features */
+#define VEN_CORE_GET_FEATURES		0xB1
+
+/** This is a request to get the value of a specific Core Feature */
+#define VEN_CORE_GET_FEATURE		0xB2
+
+/** This command allows the host to set the value of a specific Core Feature */
+#define VEN_CORE_SET_FEATURE		0xB3
+
+/** This command allows the host to set the default values of 
+ * either all or any specific Core Feature 
+ */
+#define VEN_CORE_RESET_FEATURES		0xB4
+
+/** This command forces the PCD to write the deferred values of a Core Features */
+#define VEN_CORE_ACTIVATE_FEATURES	0xB5
+
+/** This request reads a DWORD value from a register at the specified offset */
+#define VEN_CORE_READ_REGISTER		0xB6
+
+/** This request writes a DWORD value into a register at the specified offset */
+#define VEN_CORE_WRITE_REGISTER		0xB7
+
+/** This structure is the header of the Core Features dataset returned to 
+ *  the Host
+ */
+struct cfi_all_features_header {
+/** The features header structure length is */
+#define CFI_ALL_FEATURES_HDR_LEN		8
+	/**
+	 * The total length of the features dataset returned to the Host 
+	 */
+	uint16_t wTotalLen;
+
+	/**
+	 * CFI version number inBinary-Coded Decimal (i.e., 1.00 is 100H).
+	 * This field identifies the version of the CFI Specification with which 
+	 * the device is compliant.
+	 */
+	uint16_t wVersion;
+
+	/** The ID of the Core */
+	uint16_t wCoreID;
+#define CFI_CORE_ID_UDC		1
+#define CFI_CORE_ID_OTG		2
+#define CFI_CORE_ID_WUDEV	3
+
+	/** Number of features returned by VEN_CORE_GET_FEATURES request */
+	uint16_t wNumFeatures;
+} UPACKED;
+
+typedef struct cfi_all_features_header cfi_all_features_header_t;
+
+/** This structure is a header of the Core Feature descriptor dataset returned to 
+ *  the Host after the VEN_CORE_GET_FEATURES request
+ */
+struct cfi_feature_desc_header {
+#define CFI_FEATURE_DESC_HDR_LEN	8
+
+	/** The feature ID */
+	uint16_t wFeatureID;
+
+	/** Length of this feature descriptor in bytes - including the
+	 * length of the feature name string
+	 */
+	uint16_t wLength;
+
+	/** The data length of this feature in bytes */
+	uint16_t wDataLength;
+
+	/** 
+	 * Attributes of this features 
+	 * D0: Access rights
+	 * 0 - Read/Write
+	 * 1 - Read only
+	 */
+	uint8_t bmAttributes;
+#define CFI_FEATURE_ATTR_RO		1
+#define CFI_FEATURE_ATTR_RW		0
+
+	/** Length of the feature name in bytes */
+	uint8_t bNameLen;
+
+	/** The feature name buffer */
+	//uint8_t *name;
+} UPACKED;
+
+typedef struct cfi_feature_desc_header cfi_feature_desc_header_t;
+
+/**
+ * This structure describes a NULL terminated string referenced by its id field.
+ * It is very similar to usb_string structure but has the id field type set to 16-bit.
+ */
+struct cfi_string {
+	uint16_t id;
+	const uint8_t *s;
+};
+typedef struct cfi_string cfi_string_t;
+
+#endif
diff --git a/drivers/usb/dwc_otg/dwc_common_fbsd.c b/drivers/usb/dwc_otg/dwc_common_fbsd.c
new file mode 100644
index 0000000..6dd04b5
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_common_fbsd.c
@@ -0,0 +1,1308 @@
+#include "dwc_os.h"
+#include "dwc_list.h"
+
+#ifdef DWC_CCLIB
+# include "dwc_cc.h"
+#endif
+
+#ifdef DWC_CRYPTOLIB
+# include "dwc_modpow.h"
+# include "dwc_dh.h"
+# include "dwc_crypto.h"
+#endif
+
+#ifdef DWC_NOTIFYLIB
+# include "dwc_notifier.h"
+#endif
+
+/* OS-Level Implementations */
+
+/* This is the FreeBSD 7.0 kernel implementation of the DWC platform library. */
+
+
+/* MISC */
+
+void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
+{
+	return memset(dest, byte, size);
+}
+
+void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
+{
+	return memcpy(dest, src, size);
+}
+
+void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
+{
+	bcopy(src, dest, size);
+	return dest;
+}
+
+int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
+{
+	return memcmp(m1, m2, size);
+}
+
+int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
+{
+	return strncmp(s1, s2, size);
+}
+
+int DWC_STRCMP(void *s1, void *s2)
+{
+	return strcmp(s1, s2);
+}
+
+int DWC_STRLEN(char const *str)
+{
+	return strlen(str);
+}
+
+char *DWC_STRCPY(char *to, char const *from)
+{
+	return strcpy(to, from);
+}
+
+char *DWC_STRDUP(char const *str)
+{
+	int len = DWC_STRLEN(str) + 1;
+	char *new = DWC_ALLOC_ATOMIC(len);
+
+	if (!new) {
+		return NULL;
+	}
+
+	DWC_MEMCPY(new, str, len);
+	return new;
+}
+
+int DWC_ATOI(char *str, int32_t *value)
+{
+	char *end = NULL;
+
+	*value = strtol(str, &end, 0);
+	if (*end == '\0') {
+		return 0;
+	}
+
+	return -1;
+}
+
+int DWC_ATOUI(char *str, uint32_t *value)
+{
+	char *end = NULL;
+
+	*value = strtoul(str, &end, 0);
+	if (*end == '\0') {
+		return 0;
+	}
+
+	return -1;
+}
+
+
+#ifdef DWC_UTFLIB
+/* From usbstring.c */
+
+int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
+{
+	int	count = 0;
+	u8	c;
+	u16	uchar;
+
+	/* this insists on correct encodings, though not minimal ones.
+	 * BUT it currently rejects legit 4-byte UTF-8 code points,
+	 * which need surrogate pairs.  (Unicode 3.1 can use them.)
+	 */
+	while (len != 0 && (c = (u8) *s++) != 0) {
+		if (unlikely(c & 0x80)) {
+			// 2-byte sequence:
+			// 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
+			if ((c & 0xe0) == 0xc0) {
+				uchar = (c & 0x1f) << 6;
+
+				c = (u8) *s++;
+				if ((c & 0xc0) != 0xc0)
+					goto fail;
+				c &= 0x3f;
+				uchar |= c;
+
+			// 3-byte sequence (most CJKV characters):
+			// zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
+			} else if ((c & 0xf0) == 0xe0) {
+				uchar = (c & 0x0f) << 12;
+
+				c = (u8) *s++;
+				if ((c & 0xc0) != 0xc0)
+					goto fail;
+				c &= 0x3f;
+				uchar |= c << 6;
+
+				c = (u8) *s++;
+				if ((c & 0xc0) != 0xc0)
+					goto fail;
+				c &= 0x3f;
+				uchar |= c;
+
+				/* no bogus surrogates */
+				if (0xd800 <= uchar && uchar <= 0xdfff)
+					goto fail;
+
+			// 4-byte sequence (surrogate pairs, currently rare):
+			// 11101110wwwwzzzzyy + 110111yyyyxxxxxx
+			//     = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
+			// (uuuuu = wwww + 1)
+			// FIXME accept the surrogate code points (only)
+			} else
+				goto fail;
+		} else
+			uchar = c;
+		put_unaligned (cpu_to_le16 (uchar), cp++);
+		count++;
+		len--;
+	}
+	return count;
+fail:
+	return -1;
+}
+
+#endif	/* DWC_UTFLIB */
+
+
+/* dwc_debug.h */
+
+dwc_bool_t DWC_IN_IRQ(void)
+{
+//	return in_irq();
+	return 0;
+}
+
+dwc_bool_t DWC_IN_BH(void)
+{
+//	return in_softirq();
+	return 0;
+}
+
+void DWC_VPRINTF(char *format, va_list args)
+{
+	vprintf(format, args);
+}
+
+int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
+{
+	return vsnprintf(str, size, format, args);
+}
+
+void DWC_PRINTF(char *format, ...)
+{
+	va_list args;
+
+	va_start(args, format);
+	DWC_VPRINTF(format, args);
+	va_end(args);
+}
+
+int DWC_SPRINTF(char *buffer, char *format, ...)
+{
+	int retval;
+	va_list args;
+
+	va_start(args, format);
+	retval = vsprintf(buffer, format, args);
+	va_end(args);
+	return retval;
+}
+
+int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
+{
+	int retval;
+	va_list args;
+
+	va_start(args, format);
+	retval = vsnprintf(buffer, size, format, args);
+	va_end(args);
+	return retval;
+}
+
+void __DWC_WARN(char *format, ...)
+{
+	va_list args;
+
+	va_start(args, format);
+	DWC_VPRINTF(format, args);
+	va_end(args);
+}
+
+void __DWC_ERROR(char *format, ...)
+{
+	va_list args;
+
+	va_start(args, format);
+	DWC_VPRINTF(format, args);
+	va_end(args);
+}
+
+void DWC_EXCEPTION(char *format, ...)
+{
+	va_list args;
+
+	va_start(args, format);
+	DWC_VPRINTF(format, args);
+	va_end(args);
+//	BUG_ON(1);	???
+}
+
+#ifdef DEBUG
+void __DWC_DEBUG(char *format, ...)
+{
+	va_list args;
+
+	va_start(args, format);
+	DWC_VPRINTF(format, args);
+	va_end(args);
+}
+#endif
+
+
+/* dwc_mem.h */
+
+#if 0
+dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
+				uint32_t align,
+				uint32_t alloc)
+{
+	struct dma_pool *pool = dma_pool_create("Pool", NULL,
+						size, align, alloc);
+	return (dwc_pool_t *)pool;
+}
+
+void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
+{
+	dma_pool_destroy((struct dma_pool *)pool);
+}
+
+void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
+{
+//	return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
+	return dma_pool_alloc((struct dma_pool *)pool, M_WAITOK, dma_addr);
+}
+
+void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
+{
+	void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
+	memset(..);
+}
+
+void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
+{
+	dma_pool_free(pool, vaddr, daddr);
+}
+#endif
+
+static void dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+	if (error)
+		return;
+	*(bus_addr_t *)arg = segs[0].ds_addr;
+}
+
+void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
+{
+	dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
+	int error;
+
+	error = bus_dma_tag_create(
+#if __FreeBSD_version >= 700000
+			bus_get_dma_tag(dma->dev),	/* parent */
+#else
+			NULL,				/* parent */
+#endif
+			4, 0,				/* alignment, bounds */
+			BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
+			BUS_SPACE_MAXADDR,		/* highaddr */
+			NULL, NULL,			/* filter, filterarg */
+			size,				/* maxsize */
+			1,				/* nsegments */
+			size,				/* maxsegsize */
+			0,				/* flags */
+			NULL,				/* lockfunc */
+			NULL,				/* lockarg */
+			&dma->dma_tag);
+	if (error) {
+		device_printf(dma->dev, "%s: bus_dma_tag_create failed: %d\n",
+			      __func__, error);
+		goto fail_0;
+	}
+
+	error = bus_dmamem_alloc(dma->dma_tag, &dma->dma_vaddr,
+				 BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &dma->dma_map);
+	if (error) {
+		device_printf(dma->dev, "%s: bus_dmamem_alloc(%ju) failed: %d\n",
+			      __func__, (uintmax_t)size, error);
+		goto fail_1;
+	}
+
+	dma->dma_paddr = 0;
+	error = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr, size,
+				dmamap_cb, &dma->dma_paddr, BUS_DMA_NOWAIT);
+	if (error || dma->dma_paddr == 0) {
+		device_printf(dma->dev, "%s: bus_dmamap_load failed: %d\n",
+			      __func__, error);
+		goto fail_2;
+	}
+
+	*dma_addr = dma->dma_paddr;
+	return dma->dma_vaddr;
+
+fail_2:
+	bus_dmamap_unload(dma->dma_tag, dma->dma_map);
+fail_1:
+	bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
+	bus_dma_tag_destroy(dma->dma_tag);
+fail_0:
+	dma->dma_map = NULL;
+	dma->dma_tag = NULL;
+
+	return NULL;
+}
+
+void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
+{
+	dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
+
+	if (dma->dma_tag == NULL)
+		return;
+	if (dma->dma_map != NULL) {
+		bus_dmamap_sync(dma->dma_tag, dma->dma_map,
+				BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+		bus_dmamap_unload(dma->dma_tag, dma->dma_map);
+		bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
+		dma->dma_map = NULL;
+	}
+
+	bus_dma_tag_destroy(dma->dma_tag);
+	dma->dma_tag = NULL;
+}
+
+void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
+{
+	return malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
+}
+
+void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
+{
+	return malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
+}
+
+void __DWC_FREE(void *mem_ctx, void *addr)
+{
+	free(addr, M_DEVBUF);
+}
+
+
+#ifdef DWC_CRYPTOLIB
+/* dwc_crypto.h */
+
+void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
+{
+	get_random_bytes(buffer, length);
+}
+
+int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
+{
+	struct crypto_blkcipher *tfm;
+	struct blkcipher_desc desc;
+	struct scatterlist sgd;
+	struct scatterlist sgs;
+
+	tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
+	if (tfm == NULL) {
+		printk("failed to load transform for aes CBC\n");
+		return -1;
+	}
+
+	crypto_blkcipher_setkey(tfm, key, keylen);
+	crypto_blkcipher_set_iv(tfm, iv, 16);
+
+	sg_init_one(&sgd, out, messagelen);
+	sg_init_one(&sgs, message, messagelen);
+
+	desc.tfm = tfm;
+	desc.flags = 0;
+
+	if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
+		crypto_free_blkcipher(tfm);
+		DWC_ERROR("AES CBC encryption failed");
+		return -1;
+	}
+
+	crypto_free_blkcipher(tfm);
+	return 0;
+}
+
+int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
+{
+	struct crypto_hash *tfm;
+	struct hash_desc desc;
+	struct scatterlist sg;
+
+	tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(tfm)) {
+		DWC_ERROR("Failed to load transform for sha256: %ld", PTR_ERR(tfm));
+		return 0;
+	}
+	desc.tfm = tfm;
+	desc.flags = 0;
+
+	sg_init_one(&sg, message, len);
+	crypto_hash_digest(&desc, &sg, len, out);
+	crypto_free_hash(tfm);
+
+	return 1;
+}
+
+int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
+		    uint8_t *key, uint32_t keylen, uint8_t *out)
+{
+	struct crypto_hash *tfm;
+	struct hash_desc desc;
+	struct scatterlist sg;
+
+	tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(tfm)) {
+		DWC_ERROR("Failed to load transform for hmac(sha256): %ld", PTR_ERR(tfm));
+		return 0;
+	}
+	desc.tfm = tfm;
+	desc.flags = 0;
+
+	sg_init_one(&sg, message, messagelen);
+	crypto_hash_setkey(tfm, key, keylen);
+	crypto_hash_digest(&desc, &sg, messagelen, out);
+	crypto_free_hash(tfm);
+
+	return 1;
+}
+
+#endif	/* DWC_CRYPTOLIB */
+
+
+/* Byte Ordering Conversions */
+
+uint32_t DWC_CPU_TO_LE32(uint32_t *p)
+{
+#ifdef __LITTLE_ENDIAN
+	return *p;
+#else
+	uint8_t *u_p = (uint8_t *)p;
+
+	return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
+#endif
+}
+
+uint32_t DWC_CPU_TO_BE32(uint32_t *p)
+{
+#ifdef __BIG_ENDIAN
+	return *p;
+#else
+	uint8_t *u_p = (uint8_t *)p;
+
+	return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
+#endif
+}
+
+uint32_t DWC_LE32_TO_CPU(uint32_t *p)
+{
+#ifdef __LITTLE_ENDIAN
+	return *p;
+#else
+	uint8_t *u_p = (uint8_t *)p;
+
+	return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
+#endif
+}
+
+uint32_t DWC_BE32_TO_CPU(uint32_t *p)
+{
+#ifdef __BIG_ENDIAN
+	return *p;
+#else
+	uint8_t *u_p = (uint8_t *)p;
+
+	return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
+#endif
+}
+
+uint16_t DWC_CPU_TO_LE16(uint16_t *p)
+{
+#ifdef __LITTLE_ENDIAN
+	return *p;
+#else
+	uint8_t *u_p = (uint8_t *)p;
+	return (u_p[1] | (u_p[0] << 8));
+#endif
+}
+
+uint16_t DWC_CPU_TO_BE16(uint16_t *p)
+{
+#ifdef __BIG_ENDIAN
+	return *p;
+#else
+	uint8_t *u_p = (uint8_t *)p;
+	return (u_p[1] | (u_p[0] << 8));
+#endif
+}
+
+uint16_t DWC_LE16_TO_CPU(uint16_t *p)
+{
+#ifdef __LITTLE_ENDIAN
+	return *p;
+#else
+	uint8_t *u_p = (uint8_t *)p;
+	return (u_p[1] | (u_p[0] << 8));
+#endif
+}
+
+uint16_t DWC_BE16_TO_CPU(uint16_t *p)
+{
+#ifdef __BIG_ENDIAN
+	return *p;
+#else
+	uint8_t *u_p = (uint8_t *)p;
+	return (u_p[1] | (u_p[0] << 8));
+#endif
+}
+
+
+/* Registers */
+
+uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg)
+{
+	dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
+	bus_size_t ior = (bus_size_t)reg;
+
+	return bus_space_read_4(io->iot, io->ioh, ior);
+}
+
+#if 0
+uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg)
+{
+	dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
+	bus_size_t ior = (bus_size_t)reg;
+
+	return bus_space_read_8(io->iot, io->ioh, ior);
+}
+#endif
+
+void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value)
+{
+	dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
+	bus_size_t ior = (bus_size_t)reg;
+
+	bus_space_write_4(io->iot, io->ioh, ior, value);
+}
+
+#if 0
+void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value)
+{
+	dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
+	bus_size_t ior = (bus_size_t)reg;
+
+	bus_space_write_8(io->iot, io->ioh, ior, value);
+}
+#endif
+
+void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask,
+		      uint32_t set_mask)
+{
+	dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
+	bus_size_t ior = (bus_size_t)reg;
+
+	bus_space_write_4(io->iot, io->ioh, ior,
+			  (bus_space_read_4(io->iot, io->ioh, ior) &
+			   ~clear_mask) | set_mask);
+}
+
+#if 0
+void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask,
+		      uint64_t set_mask)
+{
+	dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
+	bus_size_t ior = (bus_size_t)reg;
+
+	bus_space_write_8(io->iot, io->ioh, ior,
+			  (bus_space_read_8(io->iot, io->ioh, ior) &
+			   ~clear_mask) | set_mask);
+}
+#endif
+
+
+/* Locking */
+
+dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
+{
+	struct mtx *sl = DWC_ALLOC(sizeof(*sl));
+
+	if (!sl) {
+		DWC_ERROR("Cannot allocate memory for spinlock");
+		return NULL;
+	}
+
+	mtx_init(sl, "dw3spn", NULL, MTX_SPIN);
+	return (dwc_spinlock_t *)sl;
+}
+
+void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
+{
+	struct mtx *sl = (struct mtx *)lock;
+
+	mtx_destroy(sl);
+	DWC_FREE(sl);
+}
+
+void DWC_SPINLOCK(dwc_spinlock_t *lock)
+{
+	mtx_lock_spin((struct mtx *)lock);	// ???
+}
+
+void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
+{
+	mtx_unlock_spin((struct mtx *)lock);	// ???
+}
+
+void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
+{
+	mtx_lock_spin((struct mtx *)lock);
+}
+
+void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
+{
+	mtx_unlock_spin((struct mtx *)lock);
+}
+
+dwc_mutex_t *DWC_MUTEX_ALLOC(void)
+{
+	struct mtx *m;
+	dwc_mutex_t *mutex = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mtx));
+
+	if (!mutex) {
+		DWC_ERROR("Cannot allocate memory for mutex");
+		return NULL;
+	}
+
+	m = (struct mtx *)mutex;
+	mtx_init(m, "dw3mtx", NULL, MTX_DEF);
+	return mutex;
+}
+
+#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
+#else
+void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
+{
+	mtx_destroy((struct mtx *)mutex);
+	DWC_FREE(mutex);
+}
+#endif
+
+void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
+{
+	struct mtx *m = (struct mtx *)mutex;
+
+	mtx_lock(m);
+}
+
+int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
+{
+	struct mtx *m = (struct mtx *)mutex;
+
+	return mtx_trylock(m);
+}
+
+void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
+{
+	struct mtx *m = (struct mtx *)mutex;
+
+	mtx_unlock(m);
+}
+
+
+/* Timing */
+
+void DWC_UDELAY(uint32_t usecs)
+{
+	DELAY(usecs);
+}
+
+void DWC_MDELAY(uint32_t msecs)
+{
+	do {
+		DELAY(1000);
+	} while (--msecs);
+}
+
+void DWC_MSLEEP(uint32_t msecs)
+{
+	struct timeval tv;
+
+	tv.tv_sec = msecs / 1000;
+	tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
+	pause("dw3slp", tvtohz(&tv));
+}
+
+uint32_t DWC_TIME(void)
+{
+	struct timeval tv;
+
+	microuptime(&tv);	// or getmicrouptime? (less precise, but faster)
+	return tv.tv_sec * 1000 + tv.tv_usec / 1000;
+}
+
+
+/* Timers */
+
+struct dwc_timer {
+	struct callout t;
+	char *name;
+	dwc_spinlock_t *lock;
+	dwc_timer_callback_t cb;
+	void *data;
+};
+
+dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
+{
+	dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
+
+	if (!t) {
+		DWC_ERROR("Cannot allocate memory for timer");
+		return NULL;
+	}
+
+	callout_init(&t->t, 1);
+
+	t->name = DWC_STRDUP(name);
+	if (!t->name) {
+		DWC_ERROR("Cannot allocate memory for timer->name");
+		goto no_name;
+	}
+
+	t->lock = DWC_SPINLOCK_ALLOC();
+	if (!t->lock) {
+		DWC_ERROR("Cannot allocate memory for lock");
+		goto no_lock;
+	}
+
+	t->cb = cb;
+	t->data = data;
+
+	return t;
+
+ no_lock:
+	DWC_FREE(t->name);
+ no_name:
+	DWC_FREE(t);
+
+	return NULL;
+}
+
+void DWC_TIMER_FREE(dwc_timer_t *timer)
+{
+	callout_stop(&timer->t);
+	DWC_SPINLOCK_FREE(timer->lock);
+	DWC_FREE(timer->name);
+	DWC_FREE(timer);
+}
+
+void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
+{
+	struct timeval tv;
+
+	tv.tv_sec = time / 1000;
+	tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
+	callout_reset(&timer->t, tvtohz(&tv), timer->cb, timer->data);
+}
+
+void DWC_TIMER_CANCEL(dwc_timer_t *timer)
+{
+	callout_stop(&timer->t);
+}
+
+
+/* Wait Queues */
+
+struct dwc_waitq {
+	struct mtx lock;
+	int abort;
+};
+
+dwc_waitq_t *DWC_WAITQ_ALLOC(void)
+{
+	dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
+
+	if (!wq) {
+		DWC_ERROR("Cannot allocate memory for waitqueue");
+		return NULL;
+	}
+
+	mtx_init(&wq->lock, "dw3wtq", NULL, MTX_DEF);
+	wq->abort = 0;
+
+	return wq;
+}
+
+void DWC_WAITQ_FREE(dwc_waitq_t *wq)
+{
+	mtx_destroy(&wq->lock);
+	DWC_FREE(wq);
+}
+
+int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
+{
+//	intrmask_t ipl;
+	int result = 0;
+
+	mtx_lock(&wq->lock);
+//	ipl = splbio();
+
+	/* Skip the sleep if already aborted or triggered */
+	if (!wq->abort && !cond(data)) {
+//		splx(ipl);
+		result = msleep(wq, &wq->lock, PCATCH, "dw3wat", 0); // infinite timeout
+//		ipl = splbio();
+	}
+
+	if (result == ERESTART) {	// signaled - restart
+		result = -DWC_E_RESTART;
+
+	} else if (result == EINTR) {	// signaled - interrupt
+		result = -DWC_E_ABORT;
+
+	} else if (wq->abort) {
+		result = -DWC_E_ABORT;
+
+	} else {
+		result = 0;
+	}
+
+	wq->abort = 0;
+//	splx(ipl);
+	mtx_unlock(&wq->lock);
+	return result;
+}
+
+int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
+			       void *data, int32_t msecs)
+{
+	struct timeval tv, tv1, tv2;
+//	intrmask_t ipl;
+	int result = 0;
+
+	tv.tv_sec = msecs / 1000;
+	tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
+
+	mtx_lock(&wq->lock);
+//	ipl = splbio();
+
+	/* Skip the sleep if already aborted or triggered */
+	if (!wq->abort && !cond(data)) {
+//		splx(ipl);
+		getmicrouptime(&tv1);
+		result = msleep(wq, &wq->lock, PCATCH, "dw3wto", tvtohz(&tv));
+		getmicrouptime(&tv2);
+//		ipl = splbio();
+	}
+
+	if (result == 0) {			// awoken
+		if (wq->abort) {
+			result = -DWC_E_ABORT;
+		} else {
+			tv2.tv_usec -= tv1.tv_usec;
+			if (tv2.tv_usec < 0) {
+				tv2.tv_usec += 1000000;
+				tv2.tv_sec--;
+			}
+
+			tv2.tv_sec -= tv1.tv_sec;
+			result = tv2.tv_sec * 1000 + tv2.tv_usec / 1000;
+			result = msecs - result;
+			if (result <= 0)
+				result = 1;
+		}
+	} else if (result == ERESTART) {	// signaled - restart
+		result = -DWC_E_RESTART;
+
+	} else if (result == EINTR) {		// signaled - interrupt
+		result = -DWC_E_ABORT;
+
+	} else {				// timed out
+		result = -DWC_E_TIMEOUT;
+	}
+
+	wq->abort = 0;
+//	splx(ipl);
+	mtx_unlock(&wq->lock);
+	return result;
+}
+
+void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
+{
+	wakeup(wq);
+}
+
+void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
+{
+//	intrmask_t ipl;
+
+	mtx_lock(&wq->lock);
+//	ipl = splbio();
+	wq->abort = 1;
+	wakeup(wq);
+//	splx(ipl);
+	mtx_unlock(&wq->lock);
+}
+
+
+/* Threading */
+
+struct dwc_thread {
+	struct proc *proc;
+	int abort;
+};
+
+dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
+{
+	int retval;
+	dwc_thread_t *thread = DWC_ALLOC(sizeof(*thread));
+
+	if (!thread) {
+		return NULL;
+	}
+
+	thread->abort = 0;
+	retval = kthread_create((void (*)(void *))func, data, &thread->proc,
+				RFPROC | RFNOWAIT, 0, "%s", name);
+	if (retval) {
+		DWC_FREE(thread);
+		return NULL;
+	}
+
+	return thread;
+}
+
+int DWC_THREAD_STOP(dwc_thread_t *thread)
+{
+	int retval;
+
+	thread->abort = 1;
+	retval = tsleep(&thread->abort, 0, "dw3stp", 60 * hz);
+
+	if (retval == 0) {
+		/* DWC_THREAD_EXIT() will free the thread struct */
+		return 0;
+	}
+
+	/* NOTE: We leak the thread struct if thread doesn't die */
+
+	if (retval == EWOULDBLOCK) {
+		return -DWC_E_TIMEOUT;
+	}
+
+	return -DWC_E_UNKNOWN;
+}
+
+dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread)
+{
+	return thread->abort;
+}
+
+void DWC_THREAD_EXIT(dwc_thread_t *thread)
+{
+	wakeup(&thread->abort);
+	DWC_FREE(thread);
+	kthread_exit(0);
+}
+
+
+/* tasklets
+ - Runs in interrupt context (cannot sleep)
+ - Each tasklet runs on a single CPU [ How can we ensure this on FreeBSD? Does it matter? ]
+ - Different tasklets can be running simultaneously on different CPUs [ shouldn't matter ]
+ */
+struct dwc_tasklet {
+	struct task t;
+	dwc_tasklet_callback_t cb;
+	void *data;
+};
+
+static void tasklet_callback(void *data, int pending)	// what to do with pending ???
+{
+	dwc_tasklet_t *task = (dwc_tasklet_t *)data;
+
+	task->cb(task->data);
+}
+
+dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
+{
+	dwc_tasklet_t *task = DWC_ALLOC(sizeof(*task));
+
+	if (task) {
+		task->cb = cb;
+		task->data = data;
+		TASK_INIT(&task->t, 0, tasklet_callback, task);
+	} else {
+		DWC_ERROR("Cannot allocate memory for tasklet");
+	}
+
+	return task;
+}
+
+void DWC_TASK_FREE(dwc_tasklet_t *task)
+{
+	taskqueue_drain(taskqueue_fast, &task->t);	// ???
+	DWC_FREE(task);
+}
+
+void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
+{
+	/* Uses predefined system queue */
+	taskqueue_enqueue_fast(taskqueue_fast, &task->t);
+}
+
+
+/* workqueues
+ - Runs in process context (can sleep)
+ */
+typedef struct work_container {
+	dwc_work_callback_t cb;
+	void *data;
+	dwc_workq_t *wq;
+	char *name;
+	int hz;
+
+#ifdef DEBUG
+	DWC_CIRCLEQ_ENTRY(work_container) entry;
+#endif
+	struct task task;
+} work_container_t;
+
+#ifdef DEBUG
+DWC_CIRCLEQ_HEAD(work_container_queue, work_container);
+#endif
+
+struct dwc_workq {
+	struct taskqueue *taskq;
+	dwc_spinlock_t *lock;
+	dwc_waitq_t *waitq;
+	int pending;
+
+#ifdef DEBUG
+	struct work_container_queue entries;
+#endif
+};
+
+static void do_work(void *data, int pending)	// what to do with pending ???
+{
+	work_container_t *container = (work_container_t *)data;
+	dwc_workq_t *wq = container->wq;
+	dwc_irqflags_t flags;
+
+	if (container->hz) {
+		pause("dw3wrk", container->hz);
+	}
+
+	container->cb(container->data);
+	DWC_DEBUG("Work done: %s, container=%p", container->name, container);
+
+	DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
+
+#ifdef DEBUG
+	DWC_CIRCLEQ_REMOVE(&wq->entries, container, entry);
+#endif
+	if (container->name)
+		DWC_FREE(container->name);
+	DWC_FREE(container);
+	wq->pending--;
+	DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
+	DWC_WAITQ_TRIGGER(wq->waitq);
+}
+
+static int work_done(void *data)
+{
+	dwc_workq_t *workq = (dwc_workq_t *)data;
+
+	return workq->pending == 0;
+}
+
+int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
+{
+	return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
+}
+
+dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
+{
+	dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
+
+	if (!wq) {
+		DWC_ERROR("Cannot allocate memory for workqueue");
+		return NULL;
+	}
+
+	wq->taskq = taskqueue_create(name, M_NOWAIT, taskqueue_thread_enqueue, &wq->taskq);
+	if (!wq->taskq) {
+		DWC_ERROR("Cannot allocate memory for taskqueue");
+		goto no_taskq;
+	}
+
+	wq->pending = 0;
+
+	wq->lock = DWC_SPINLOCK_ALLOC();
+	if (!wq->lock) {
+		DWC_ERROR("Cannot allocate memory for spinlock");
+		goto no_lock;
+	}
+
+	wq->waitq = DWC_WAITQ_ALLOC();
+	if (!wq->waitq) {
+		DWC_ERROR("Cannot allocate memory for waitqueue");
+		goto no_waitq;
+	}
+
+	taskqueue_start_threads(&wq->taskq, 1, PWAIT, "%s taskq", "dw3tsk");
+
+#ifdef DEBUG
+	DWC_CIRCLEQ_INIT(&wq->entries);
+#endif
+	return wq;
+
+ no_waitq:
+	DWC_SPINLOCK_FREE(wq->lock);
+ no_lock:
+	taskqueue_free(wq->taskq);
+ no_taskq:
+	DWC_FREE(wq);
+
+	return NULL;
+}
+
+void DWC_WORKQ_FREE(dwc_workq_t *wq)
+{
+#ifdef DEBUG
+	dwc_irqflags_t flags;
+
+	DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
+
+	if (wq->pending != 0) {
+		struct work_container *container;
+
+		DWC_ERROR("Destroying work queue with pending work");
+
+		DWC_CIRCLEQ_FOREACH(container, &wq->entries, entry) {
+			DWC_ERROR("Work %s still pending", container->name);
+		}
+	}
+
+	DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
+#endif
+	DWC_WAITQ_FREE(wq->waitq);
+	DWC_SPINLOCK_FREE(wq->lock);
+	taskqueue_free(wq->taskq);
+	DWC_FREE(wq);
+}
+
+void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
+			char *format, ...)
+{
+	dwc_irqflags_t flags;
+	work_container_t *container;
+	static char name[128];
+	va_list args;
+
+	va_start(args, format);
+	DWC_VSNPRINTF(name, 128, format, args);
+	va_end(args);
+
+	DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
+	wq->pending++;
+	DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
+	DWC_WAITQ_TRIGGER(wq->waitq);
+
+	container = DWC_ALLOC_ATOMIC(sizeof(*container));
+	if (!container) {
+		DWC_ERROR("Cannot allocate memory for container");
+		return;
+	}
+
+	container->name = DWC_STRDUP(name);
+	if (!container->name) {
+		DWC_ERROR("Cannot allocate memory for container->name");
+		DWC_FREE(container);
+		return;
+	}
+
+	container->cb = cb;
+	container->data = data;
+	container->wq = wq;
+	container->hz = 0;
+
+	DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
+
+	TASK_INIT(&container->task, 0, do_work, container);
+
+#ifdef DEBUG
+	DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
+#endif
+	taskqueue_enqueue_fast(wq->taskq, &container->task);
+}
+
+void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
+				void *data, uint32_t time, char *format, ...)
+{
+	dwc_irqflags_t flags;
+	work_container_t *container;
+	static char name[128];
+	struct timeval tv;
+	va_list args;
+
+	va_start(args, format);
+	DWC_VSNPRINTF(name, 128, format, args);
+	va_end(args);
+
+	DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
+	wq->pending++;
+	DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
+	DWC_WAITQ_TRIGGER(wq->waitq);
+
+	container = DWC_ALLOC_ATOMIC(sizeof(*container));
+	if (!container) {
+		DWC_ERROR("Cannot allocate memory for container");
+		return;
+	}
+
+	container->name = DWC_STRDUP(name);
+	if (!container->name) {
+		DWC_ERROR("Cannot allocate memory for container->name");
+		DWC_FREE(container);
+		return;
+	}
+
+	container->cb = cb;
+	container->data = data;
+	container->wq = wq;
+
+	tv.tv_sec = time / 1000;
+	tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
+	container->hz = tvtohz(&tv);
+
+	DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
+
+	TASK_INIT(&container->task, 0, do_work, container);
+
+#ifdef DEBUG
+	DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
+#endif
+	taskqueue_enqueue_fast(wq->taskq, &container->task);
+}
+
+int DWC_WORKQ_PENDING(dwc_workq_t *wq)
+{
+	return wq->pending;
+}
diff --git a/drivers/usb/dwc_otg/dwc_common_linux.c b/drivers/usb/dwc_otg/dwc_common_linux.c
new file mode 100644
index 0000000..c2ba7e3
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_common_linux.c
@@ -0,0 +1,1421 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+
+#ifdef DWC_CCLIB
+# include "dwc_cc.h"
+#endif
+
+#ifdef DWC_CRYPTOLIB
+# include "dwc_modpow.h"
+# include "dwc_dh.h"
+# include "dwc_crypto.h"
+#endif
+
+#ifdef DWC_NOTIFYLIB
+# include "dwc_notifier.h"
+#endif
+
+/* OS-Level Implementations */
+
+/* This is the Linux kernel implementation of the DWC platform library. */
+#include <linux/moduleparam.h>
+#include <linux/ctype.h>
+#include <linux/crypto.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/cdev.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/random.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/usb.h>
+
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+# include <linux/usb/gadget.h>
+#else
+# include <linux/usb_gadget.h>
+#endif
+
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+
+#include "dwc_os.h"
+#include "dwc_list.h"
+
+
+/* MISC */
+
+void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
+{
+	return memset(dest, byte, size);
+}
+
+void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
+{
+	return memcpy(dest, src, size);
+}
+
+void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
+{
+	return memmove(dest, src, size);
+}
+
+int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
+{
+	return memcmp(m1, m2, size);
+}
+
+int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
+{
+	return strncmp(s1, s2, size);
+}
+
+int DWC_STRCMP(void *s1, void *s2)
+{
+	return strcmp(s1, s2);
+}
+
+int DWC_STRLEN(char const *str)
+{
+	return strlen(str);
+}
+
+char *DWC_STRCPY(char *to, char const *from)
+{
+	return strcpy(to, from);
+}
+
+char *DWC_STRDUP(char const *str)
+{
+	int len = DWC_STRLEN(str) + 1;
+	char *new = DWC_ALLOC_ATOMIC(len);
+
+	if (!new) {
+		return NULL;
+	}
+
+	DWC_MEMCPY(new, str, len);
+	return new;
+}
+
+int DWC_ATOI(const char *str, int32_t *value)
+{
+	char *end = NULL;
+
+	*value = simple_strtol(str, &end, 0);
+	if (*end == '\0') {
+		return 0;
+	}
+
+	return -1;
+}
+
+int DWC_ATOUI(const char *str, uint32_t *value)
+{
+	char *end = NULL;
+
+	*value = simple_strtoul(str, &end, 0);
+	if (*end == '\0') {
+		return 0;
+	}
+
+	return -1;
+}
+
+
+#ifdef DWC_UTFLIB
+/* From usbstring.c */
+
+int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
+{
+	int	count = 0;
+	u8	c;
+	u16	uchar;
+
+	/* this insists on correct encodings, though not minimal ones.
+	 * BUT it currently rejects legit 4-byte UTF-8 code points,
+	 * which need surrogate pairs.  (Unicode 3.1 can use them.)
+	 */
+	while (len != 0 && (c = (u8) *s++) != 0) {
+		if (unlikely(c & 0x80)) {
+			// 2-byte sequence:
+			// 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
+			if ((c & 0xe0) == 0xc0) {
+				uchar = (c & 0x1f) << 6;
+
+				c = (u8) *s++;
+				if ((c & 0xc0) != 0xc0)
+					goto fail;
+				c &= 0x3f;
+				uchar |= c;
+
+			// 3-byte sequence (most CJKV characters):
+			// zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
+			} else if ((c & 0xf0) == 0xe0) {
+				uchar = (c & 0x0f) << 12;
+
+				c = (u8) *s++;
+				if ((c & 0xc0) != 0xc0)
+					goto fail;
+				c &= 0x3f;
+				uchar |= c << 6;
+
+				c = (u8) *s++;
+				if ((c & 0xc0) != 0xc0)
+					goto fail;
+				c &= 0x3f;
+				uchar |= c;
+
+				/* no bogus surrogates */
+				if (0xd800 <= uchar && uchar <= 0xdfff)
+					goto fail;
+
+			// 4-byte sequence (surrogate pairs, currently rare):
+			// 11101110wwwwzzzzyy + 110111yyyyxxxxxx
+			//     = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
+			// (uuuuu = wwww + 1)
+			// FIXME accept the surrogate code points (only)
+			} else
+				goto fail;
+		} else
+			uchar = c;
+		put_unaligned (cpu_to_le16 (uchar), cp++);
+		count++;
+		len--;
+	}
+	return count;
+fail:
+	return -1;
+}
+#endif	/* DWC_UTFLIB */
+
+
+/* dwc_debug.h */
+
+dwc_bool_t DWC_IN_IRQ(void)
+{
+	return in_irq();
+}
+
+dwc_bool_t DWC_IN_BH(void)
+{
+	return in_softirq();
+}
+
+void DWC_VPRINTF(char *format, va_list args)
+{
+	vprintk(format, args);
+}
+
+int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
+{
+	return vsnprintf(str, size, format, args);
+}
+
+void DWC_PRINTF(char *format, ...)
+{
+	va_list args;
+
+	va_start(args, format);
+	DWC_VPRINTF(format, args);
+	va_end(args);
+}
+
+int DWC_SPRINTF(char *buffer, char *format, ...)
+{
+	int retval;
+	va_list args;
+
+	va_start(args, format);
+	retval = vsprintf(buffer, format, args);
+	va_end(args);
+	return retval;
+}
+
+int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
+{
+	int retval;
+	va_list args;
+
+	va_start(args, format);
+	retval = vsnprintf(buffer, size, format, args);
+	va_end(args);
+	return retval;
+}
+
+void __DWC_WARN(char *format, ...)
+{
+	va_list args;
+
+	va_start(args, format);
+	DWC_PRINTF(KERN_WARNING);
+	DWC_VPRINTF(format, args);
+	va_end(args);
+}
+
+void __DWC_ERROR(char *format, ...)
+{
+	va_list args;
+
+	va_start(args, format);
+	DWC_PRINTF(KERN_ERR);
+	DWC_VPRINTF(format, args);
+	va_end(args);
+}
+
+void DWC_EXCEPTION(char *format, ...)
+{
+	va_list args;
+
+	va_start(args, format);
+	DWC_PRINTF(KERN_ERR);
+	DWC_VPRINTF(format, args);
+	va_end(args);
+	BUG_ON(1);
+}
+
+#ifdef DEBUG
+void __DWC_DEBUG(char *format, ...)
+{
+	va_list args;
+
+	va_start(args, format);
+	DWC_PRINTF(KERN_DEBUG);
+	DWC_VPRINTF(format, args);
+	va_end(args);
+}
+#endif
+
+
+/* dwc_mem.h */
+
+#if 0
+dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
+				uint32_t align,
+				uint32_t alloc)
+{
+	struct dma_pool *pool = dma_pool_create("Pool", NULL,
+						size, align, alloc);
+	return (dwc_pool_t *)pool;
+}
+
+void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
+{
+	dma_pool_destroy((struct dma_pool *)pool);
+}
+
+void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
+{
+	return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
+}
+
+void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
+{
+	void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
+	memset(..);
+}
+
+void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
+{
+	dma_pool_free(pool, vaddr, daddr);
+}
+#endif
+
+void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
+{
+#ifdef xxCOSIM /* Only works for 32-bit cosim */
+	void *buf = dma_alloc_coherent(dma_ctx, (size_t)size, dma_addr, GFP_KERNEL);
+#else
+	void *buf = dma_alloc_coherent(dma_ctx, (size_t)size, dma_addr, GFP_KERNEL);
+#endif
+	if (!buf) {
+		return NULL;
+	}
+
+	memset(buf, 0, (size_t)size);
+	return buf;
+}
+
+void *__DWC_DMA_ALLOC_ATOMIC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
+{
+	void *buf = dma_alloc_coherent(NULL, (size_t)size, dma_addr, GFP_ATOMIC);
+	if (!buf) {
+		return NULL;
+	}
+	memset(buf, 0, (size_t)size);
+	return buf;
+}
+
+void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
+{
+	dma_free_coherent(dma_ctx, size, virt_addr, dma_addr);
+}
+
+void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
+{
+	return kzalloc(size, GFP_KERNEL);
+}
+
+void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
+{
+	return kzalloc(size, GFP_ATOMIC);
+}
+
+void __DWC_FREE(void *mem_ctx, void *addr)
+{
+	kfree(addr);
+}
+
+
+#ifdef DWC_CRYPTOLIB
+/* dwc_crypto.h */
+
+void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
+{
+	get_random_bytes(buffer, length);
+}
+
+int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
+{
+	struct crypto_blkcipher *tfm;
+	struct blkcipher_desc desc;
+	struct scatterlist sgd;
+	struct scatterlist sgs;
+
+	tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
+	if (tfm == NULL) {
+		printk("failed to load transform for aes CBC\n");
+		return -1;
+	}
+
+	crypto_blkcipher_setkey(tfm, key, keylen);
+	crypto_blkcipher_set_iv(tfm, iv, 16);
+
+	sg_init_one(&sgd, out, messagelen);
+	sg_init_one(&sgs, message, messagelen);
+
+	desc.tfm = tfm;
+	desc.flags = 0;
+
+	if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
+		crypto_free_blkcipher(tfm);
+		DWC_ERROR("AES CBC encryption failed");
+		return -1;
+	}
+
+	crypto_free_blkcipher(tfm);
+	return 0;
+}
+
+int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
+{
+	struct crypto_hash *tfm;
+	struct hash_desc desc;
+	struct scatterlist sg;
+
+	tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(tfm)) {
+		DWC_ERROR("Failed to load transform for sha256: %ld\n", PTR_ERR(tfm));
+		return 0;
+	}
+	desc.tfm = tfm;
+	desc.flags = 0;
+
+	sg_init_one(&sg, message, len);
+	crypto_hash_digest(&desc, &sg, len, out);
+	crypto_free_hash(tfm);
+
+	return 1;
+}
+
+int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
+		    uint8_t *key, uint32_t keylen, uint8_t *out)
+{
+	struct crypto_hash *tfm;
+	struct hash_desc desc;
+	struct scatterlist sg;
+
+	tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(tfm)) {
+		DWC_ERROR("Failed to load transform for hmac(sha256): %ld\n", PTR_ERR(tfm));
+		return 0;
+	}
+	desc.tfm = tfm;
+	desc.flags = 0;
+
+	sg_init_one(&sg, message, messagelen);
+	crypto_hash_setkey(tfm, key, keylen);
+	crypto_hash_digest(&desc, &sg, messagelen, out);
+	crypto_free_hash(tfm);
+
+	return 1;
+}
+#endif	/* DWC_CRYPTOLIB */
+
+
+/* Byte Ordering Conversions */
+
+uint32_t DWC_CPU_TO_LE32(uint32_t *p)
+{
+#ifdef __LITTLE_ENDIAN
+	return *p;
+#else
+	uint8_t *u_p = (uint8_t *)p;
+
+	return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
+#endif
+}
+
+uint32_t DWC_CPU_TO_BE32(uint32_t *p)
+{
+#ifdef __BIG_ENDIAN
+	return *p;
+#else
+	uint8_t *u_p = (uint8_t *)p;
+
+	return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
+#endif
+}
+
+uint32_t DWC_LE32_TO_CPU(uint32_t *p)
+{
+#ifdef __LITTLE_ENDIAN
+	return *p;
+#else
+	uint8_t *u_p = (uint8_t *)p;
+
+	return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
+#endif
+}
+
+uint32_t DWC_BE32_TO_CPU(uint32_t *p)
+{
+#ifdef __BIG_ENDIAN
+	return *p;
+#else
+	uint8_t *u_p = (uint8_t *)p;
+
+	return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
+#endif
+}
+
+uint16_t DWC_CPU_TO_LE16(uint16_t *p)
+{
+#ifdef __LITTLE_ENDIAN
+	return *p;
+#else
+	uint8_t *u_p = (uint8_t *)p;
+	return (u_p[1] | (u_p[0] << 8));
+#endif
+}
+
+uint16_t DWC_CPU_TO_BE16(uint16_t *p)
+{
+#ifdef __BIG_ENDIAN
+	return *p;
+#else
+	uint8_t *u_p = (uint8_t *)p;
+	return (u_p[1] | (u_p[0] << 8));
+#endif
+}
+
+uint16_t DWC_LE16_TO_CPU(uint16_t *p)
+{
+#ifdef __LITTLE_ENDIAN
+	return *p;
+#else
+	uint8_t *u_p = (uint8_t *)p;
+	return (u_p[1] | (u_p[0] << 8));
+#endif
+}
+
+uint16_t DWC_BE16_TO_CPU(uint16_t *p)
+{
+#ifdef __BIG_ENDIAN
+	return *p;
+#else
+	uint8_t *u_p = (uint8_t *)p;
+	return (u_p[1] | (u_p[0] << 8));
+#endif
+}
+
+
+/* Registers */
+
+uint32_t DWC_READ_REG32(uint32_t volatile *reg)
+{
+	return readl(reg);
+}
+
+#if 0
+uint64_t DWC_READ_REG64(uint64_t volatile *reg)
+{
+}
+#endif
+
+void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value)
+{
+	writel(value, reg);
+}
+
+#if 0
+void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value)
+{
+}
+#endif
+
+void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask)
+{
+	writel((readl(reg) & ~clear_mask) | set_mask, reg);
+}
+
+#if 0
+void DWC_MODIFY_REG64(uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask)
+{
+}
+#endif
+
+
+/* Locking */
+
+dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
+{
+	spinlock_t *sl = (spinlock_t *)1;
+
+#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
+	sl = DWC_ALLOC(sizeof(*sl));
+	if (!sl) {
+		DWC_ERROR("Cannot allocate memory for spinlock\n");
+		return NULL;
+	}
+
+	spin_lock_init(sl);
+#endif
+	return (dwc_spinlock_t *)sl;
+}
+
+void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
+{
+#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
+	DWC_FREE(lock);
+#endif
+}
+
+void DWC_SPINLOCK(dwc_spinlock_t *lock)
+{
+#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
+	spin_lock((spinlock_t *)lock);
+#endif
+}
+
+void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
+{
+#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
+	spin_unlock((spinlock_t *)lock);
+#endif
+}
+
+void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
+{
+	dwc_irqflags_t f;
+
+#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
+	spin_lock_irqsave((spinlock_t *)lock, f);
+#else
+	local_irq_save(f);
+#endif
+	*flags = f;
+}
+
+void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
+{
+#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
+	spin_unlock_irqrestore((spinlock_t *)lock, flags);
+#else
+	local_irq_restore(flags);
+#endif
+}
+
+dwc_mutex_t *DWC_MUTEX_ALLOC(void)
+{
+	struct mutex *m;
+	dwc_mutex_t *mutex = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mutex));
+
+	if (!mutex) {
+		DWC_ERROR("Cannot allocate memory for mutex\n");
+		return NULL;
+	}
+
+	m = (struct mutex *)mutex;
+	mutex_init(m);
+	return mutex;
+}
+
+#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
+#else
+void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
+{
+	mutex_destroy((struct mutex *)mutex);
+	DWC_FREE(mutex);
+}
+#endif
+
+void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
+{
+	struct mutex *m = (struct mutex *)mutex;
+	mutex_lock(m);
+}
+
+int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
+{
+	struct mutex *m = (struct mutex *)mutex;
+	return mutex_trylock(m);
+}
+
+void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
+{
+	struct mutex *m = (struct mutex *)mutex;
+	mutex_unlock(m);
+}
+
+
+/* Timing */
+
+void DWC_UDELAY(uint32_t usecs)
+{
+	udelay(usecs);
+}
+
+void DWC_MDELAY(uint32_t msecs)
+{
+	mdelay(msecs);
+}
+
+void DWC_MSLEEP(uint32_t msecs)
+{
+	msleep(msecs);
+}
+
+uint32_t DWC_TIME(void)
+{
+	return jiffies_to_msecs(jiffies);
+}
+
+
+/* Timers */
+
+struct dwc_timer {
+	struct timer_list *t;
+	char *name;
+	dwc_timer_callback_t cb;
+	void *data;
+	uint8_t scheduled;
+	dwc_spinlock_t *lock;
+};
+
+static void timer_callback(unsigned long data)
+{
+	dwc_timer_t *timer = (dwc_timer_t *)data;
+	dwc_irqflags_t flags;
+
+	DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
+	timer->scheduled = 0;
+	DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
+	DWC_DEBUG("Timer %s callback", timer->name);
+	timer->cb(timer->data);
+}
+
+dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
+{
+	dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
+
+	if (!t) {
+		DWC_ERROR("Cannot allocate memory for timer");
+		return NULL;
+	}
+
+	t->t = DWC_ALLOC(sizeof(*t->t));
+	if (!t->t) {
+		DWC_ERROR("Cannot allocate memory for timer->t");
+		goto no_timer;
+	}
+
+	t->name = DWC_STRDUP(name);
+	if (!t->name) {
+		DWC_ERROR("Cannot allocate memory for timer->name");
+		goto no_name;
+	}
+
+	t->lock = DWC_SPINLOCK_ALLOC();
+	if (!t->lock) {
+		DWC_ERROR("Cannot allocate memory for lock");
+		goto no_lock;
+	}
+
+	t->scheduled = 0;
+	t->t->base = &boot_tvec_bases;
+	t->t->expires = jiffies;
+	setup_timer(t->t, timer_callback, (unsigned long)t);
+
+	t->cb = cb;
+	t->data = data;
+
+	return t;
+
+ no_lock:
+	DWC_FREE(t->name);
+ no_name:
+	DWC_FREE(t->t);
+ no_timer:
+	DWC_FREE(t);
+	return NULL;
+}
+
+void DWC_TIMER_FREE(dwc_timer_t *timer)
+{
+	dwc_irqflags_t flags;
+
+	DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
+
+	if (timer->scheduled) {
+		del_timer(timer->t);
+		timer->scheduled = 0;
+	}
+
+	DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
+	DWC_SPINLOCK_FREE(timer->lock);
+	DWC_FREE(timer->t);
+	DWC_FREE(timer->name);
+	DWC_FREE(timer);
+}
+
+void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
+{
+	dwc_irqflags_t flags;
+
+	DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
+
+	if (!timer->scheduled) {
+		timer->scheduled = 1;
+		DWC_DEBUG("Scheduling timer %s to expire in +%d msec", timer->name, time);
+		timer->t->expires = jiffies + msecs_to_jiffies(time);
+		add_timer(timer->t);
+	} else {
+		DWC_DEBUG("Modifying timer %s to expire in +%d msec", timer->name, time);
+		mod_timer(timer->t, jiffies + msecs_to_jiffies(time));
+	}
+
+	DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
+}
+
+void DWC_TIMER_CANCEL(dwc_timer_t *timer)
+{
+	del_timer(timer->t);
+}
+
+
+/* Wait Queues */
+
+struct dwc_waitq {
+	wait_queue_head_t queue;
+	int abort;
+};
+
+dwc_waitq_t *DWC_WAITQ_ALLOC(void)
+{
+	dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
+
+	if (!wq) {
+		DWC_ERROR("Cannot allocate memory for waitqueue\n");
+		return NULL;
+	}
+
+	init_waitqueue_head(&wq->queue);
+	wq->abort = 0;
+	return wq;
+}
+
+void DWC_WAITQ_FREE(dwc_waitq_t *wq)
+{
+	DWC_FREE(wq);
+}
+
+int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
+{
+	int result = wait_event_interruptible(wq->queue,
+					      cond(data) || wq->abort);
+	if (result == -ERESTARTSYS) {
+		wq->abort = 0;
+		return -DWC_E_RESTART;
+	}
+
+	if (wq->abort == 1) {
+		wq->abort = 0;
+		return -DWC_E_ABORT;
+	}
+
+	wq->abort = 0;
+
+	if (result == 0) {
+		return 0;
+	}
+
+	return -DWC_E_UNKNOWN;
+}
+
+int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
+			       void *data, int32_t msecs)
+{
+	int32_t tmsecs;
+	int result = wait_event_interruptible_timeout(wq->queue,
+						      cond(data) || wq->abort,
+						      msecs_to_jiffies(msecs));
+	if (result == -ERESTARTSYS) {
+		wq->abort = 0;
+		return -DWC_E_RESTART;
+	}
+
+	if (wq->abort == 1) {
+		wq->abort = 0;
+		return -DWC_E_ABORT;
+	}
+
+	wq->abort = 0;
+
+	if (result > 0) {
+		tmsecs = jiffies_to_msecs(result);
+		if (!tmsecs) {
+			return 1;
+		}
+
+		return tmsecs;
+	}
+
+	if (result == 0) {
+		return -DWC_E_TIMEOUT;
+	}
+
+	return -DWC_E_UNKNOWN;
+}
+
+void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
+{
+	wq->abort = 0;
+	wake_up_interruptible(&wq->queue);
+}
+
+void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
+{
+	wq->abort = 1;
+	wake_up_interruptible(&wq->queue);
+}
+
+
+/* Threading */
+
+dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
+{
+	struct task_struct *thread = kthread_run(func, data, name);
+
+	if (thread == ERR_PTR(-ENOMEM)) {
+		return NULL;
+	}
+
+	return (dwc_thread_t *)thread;
+}
+
+int DWC_THREAD_STOP(dwc_thread_t *thread)
+{
+	return kthread_stop((struct task_struct *)thread);
+}
+
+dwc_bool_t DWC_THREAD_SHOULD_STOP(void)
+{
+	return kthread_should_stop();
+}
+
+
+/* tasklets
+ - run in interrupt context (cannot sleep)
+ - each tasklet runs on a single CPU
+ - different tasklets can be running simultaneously on different CPUs
+ */
+struct dwc_tasklet {
+	struct tasklet_struct t;
+	dwc_tasklet_callback_t cb;
+	void *data;
+};
+
+static void tasklet_callback(unsigned long data)
+{
+	dwc_tasklet_t *t = (dwc_tasklet_t *)data;
+	t->cb(t->data);
+}
+
+dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
+{
+	dwc_tasklet_t *t = DWC_ALLOC(sizeof(*t));
+
+	if (t) {
+		t->cb = cb;
+		t->data = data;
+		tasklet_init(&t->t, tasklet_callback, (unsigned long)t);
+	} else {
+		DWC_ERROR("Cannot allocate memory for tasklet\n");
+	}
+
+	return t;
+}
+
+void DWC_TASK_FREE(dwc_tasklet_t *task)
+{
+	DWC_FREE(task);
+}
+
+void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
+{
+	tasklet_schedule(&task->t);
+}
+
+
+/* workqueues
+ - run in process context (can sleep)
+ */
+typedef struct work_container {
+	dwc_work_callback_t cb;
+	void *data;
+	dwc_workq_t *wq;
+	char *name;
+
+#ifdef DEBUG
+	DWC_CIRCLEQ_ENTRY(work_container) entry;
+#endif
+	struct delayed_work work;
+} work_container_t;
+
+#ifdef DEBUG
+DWC_CIRCLEQ_HEAD(work_container_queue, work_container);
+#endif
+
+struct dwc_workq {
+	struct workqueue_struct *wq;
+	dwc_spinlock_t *lock;
+	dwc_waitq_t *waitq;
+	int pending;
+
+#ifdef DEBUG
+	struct work_container_queue entries;
+#endif
+};
+
+static void do_work(struct work_struct *work)
+{
+	dwc_irqflags_t flags;
+	struct delayed_work *dw = container_of(work, struct delayed_work, work);
+	work_container_t *container = container_of(dw, struct work_container, work);
+	dwc_workq_t *wq = container->wq;
+
+	container->cb(container->data);
+
+#ifdef DEBUG
+	DWC_CIRCLEQ_REMOVE(&wq->entries, container, entry);
+#endif
+	DWC_DEBUG("Work done: %s, container=%p", container->name, container);
+	if (container->name) {
+		DWC_FREE(container->name);
+	}
+	DWC_FREE(container);
+
+	DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
+	wq->pending--;
+	DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
+	DWC_WAITQ_TRIGGER(wq->waitq);
+}
+
+static int work_done(void *data)
+{
+	dwc_workq_t *workq = (dwc_workq_t *)data;
+	return workq->pending == 0;
+}
+
+int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
+{
+	return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
+}
+
+dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
+{
+	dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
+
+	if (!wq) {
+		return NULL;
+	}
+
+	wq->wq = create_singlethread_workqueue(name);
+	if (!wq->wq) {
+		goto no_wq;
+	}
+
+	wq->pending = 0;
+
+	wq->lock = DWC_SPINLOCK_ALLOC();
+	if (!wq->lock) {
+		goto no_lock;
+	}
+
+	wq->waitq = DWC_WAITQ_ALLOC();
+	if (!wq->waitq) {
+		goto no_waitq;
+	}
+
+#ifdef DEBUG
+	DWC_CIRCLEQ_INIT(&wq->entries);
+#endif
+	return wq;
+
+ no_waitq:
+	DWC_SPINLOCK_FREE(wq->lock);
+ no_lock:
+	destroy_workqueue(wq->wq);
+ no_wq:
+	DWC_FREE(wq);
+
+	return NULL;
+}
+
+void DWC_WORKQ_FREE(dwc_workq_t *wq)
+{
+#ifdef DEBUG
+	if (wq->pending != 0) {
+		struct work_container *wc;
+		DWC_ERROR("Destroying work queue with pending work");
+		DWC_CIRCLEQ_FOREACH(wc, &wq->entries, entry) {
+			DWC_ERROR("Work %s still pending", wc->name);
+		}
+	}
+#endif
+	destroy_workqueue(wq->wq);
+	DWC_SPINLOCK_FREE(wq->lock);
+	DWC_WAITQ_FREE(wq->waitq);
+	DWC_FREE(wq);
+}
+
+void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
+			char *format, ...)
+{
+	dwc_irqflags_t flags;
+	work_container_t *container;
+	static char name[128];
+	va_list args;
+
+	va_start(args, format);
+	DWC_VSNPRINTF(name, 128, format, args);
+	va_end(args);
+
+	DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
+	wq->pending++;
+	DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
+	DWC_WAITQ_TRIGGER(wq->waitq);
+
+	container = DWC_ALLOC_ATOMIC(sizeof(*container));
+	if (!container) {
+		DWC_ERROR("Cannot allocate memory for container\n");
+		return;
+	}
+
+	container->name = DWC_STRDUP(name);
+	if (!container->name) {
+		DWC_ERROR("Cannot allocate memory for container->name\n");
+		DWC_FREE(container);
+		return;
+	}
+
+	container->cb = cb;
+	container->data = data;
+	container->wq = wq;
+	DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
+	INIT_WORK(&container->work.work, do_work);
+
+#ifdef DEBUG
+	DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
+#endif
+	queue_work(wq->wq, &container->work.work);
+}
+
+void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
+				void *data, uint32_t time, char *format, ...)
+{
+	dwc_irqflags_t flags;
+	work_container_t *container;
+	static char name[128];
+	va_list args;
+
+	va_start(args, format);
+	DWC_VSNPRINTF(name, 128, format, args);
+	va_end(args);
+
+	DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
+	wq->pending++;
+	DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
+	DWC_WAITQ_TRIGGER(wq->waitq);
+
+	container = DWC_ALLOC_ATOMIC(sizeof(*container));
+	if (!container) {
+		DWC_ERROR("Cannot allocate memory for container\n");
+		return;
+	}
+
+	container->name = DWC_STRDUP(name);
+	if (!container->name) {
+		DWC_ERROR("Cannot allocate memory for container->name\n");
+		DWC_FREE(container);
+		return;
+	}
+
+	container->cb = cb;
+	container->data = data;
+	container->wq = wq;
+	DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
+	INIT_DELAYED_WORK(&container->work, do_work);
+
+#ifdef DEBUG
+	DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
+#endif
+	queue_delayed_work(wq->wq, &container->work, msecs_to_jiffies(time));
+}
+
+int DWC_WORKQ_PENDING(dwc_workq_t *wq)
+{
+	return wq->pending;
+}
+
+
+#ifdef DWC_LIBMODULE
+
+#ifdef DWC_CCLIB
+/* CC */
+EXPORT_SYMBOL(dwc_cc_if_alloc);
+EXPORT_SYMBOL(dwc_cc_if_free);
+EXPORT_SYMBOL(dwc_cc_clear);
+EXPORT_SYMBOL(dwc_cc_add);
+EXPORT_SYMBOL(dwc_cc_remove);
+EXPORT_SYMBOL(dwc_cc_change);
+EXPORT_SYMBOL(dwc_cc_data_for_save);
+EXPORT_SYMBOL(dwc_cc_restore_from_data);
+EXPORT_SYMBOL(dwc_cc_match_chid);
+EXPORT_SYMBOL(dwc_cc_match_cdid);
+EXPORT_SYMBOL(dwc_cc_ck);
+EXPORT_SYMBOL(dwc_cc_chid);
+EXPORT_SYMBOL(dwc_cc_cdid);
+EXPORT_SYMBOL(dwc_cc_name);
+#endif	/* DWC_CCLIB */
+
+#ifdef DWC_CRYPTOLIB
+# ifndef CONFIG_MACH_IPMATE
+/* Modpow */
+EXPORT_SYMBOL(dwc_modpow);
+
+/* DH */
+EXPORT_SYMBOL(dwc_dh_modpow);
+EXPORT_SYMBOL(dwc_dh_derive_keys);
+EXPORT_SYMBOL(dwc_dh_pk);
+# endif	/* CONFIG_MACH_IPMATE */
+
+/* Crypto */
+EXPORT_SYMBOL(dwc_wusb_aes_encrypt);
+EXPORT_SYMBOL(dwc_wusb_cmf);
+EXPORT_SYMBOL(dwc_wusb_prf);
+EXPORT_SYMBOL(dwc_wusb_fill_ccm_nonce);
+EXPORT_SYMBOL(dwc_wusb_gen_nonce);
+EXPORT_SYMBOL(dwc_wusb_gen_key);
+EXPORT_SYMBOL(dwc_wusb_gen_mic);
+#endif	/* DWC_CRYPTOLIB */
+
+/* Notification */
+#ifdef DWC_NOTIFYLIB
+EXPORT_SYMBOL(dwc_alloc_notification_manager);
+EXPORT_SYMBOL(dwc_free_notification_manager);
+EXPORT_SYMBOL(dwc_register_notifier);
+EXPORT_SYMBOL(dwc_unregister_notifier);
+EXPORT_SYMBOL(dwc_add_observer);
+EXPORT_SYMBOL(dwc_remove_observer);
+EXPORT_SYMBOL(dwc_notify);
+#endif
+
+/* Memory Debugging Routines */
+#ifdef DWC_DEBUG_MEMORY
+EXPORT_SYMBOL(dwc_alloc_debug);
+EXPORT_SYMBOL(dwc_alloc_atomic_debug);
+EXPORT_SYMBOL(dwc_free_debug);
+EXPORT_SYMBOL(dwc_dma_alloc_debug);
+EXPORT_SYMBOL(dwc_dma_free_debug);
+#endif
+
+EXPORT_SYMBOL(DWC_MEMSET);
+EXPORT_SYMBOL(DWC_MEMCPY);
+EXPORT_SYMBOL(DWC_MEMMOVE);
+EXPORT_SYMBOL(DWC_MEMCMP);
+EXPORT_SYMBOL(DWC_STRNCMP);
+EXPORT_SYMBOL(DWC_STRCMP);
+EXPORT_SYMBOL(DWC_STRLEN);
+EXPORT_SYMBOL(DWC_STRCPY);
+EXPORT_SYMBOL(DWC_STRDUP);
+EXPORT_SYMBOL(DWC_ATOI);
+EXPORT_SYMBOL(DWC_ATOUI);
+
+#ifdef DWC_UTFLIB
+EXPORT_SYMBOL(DWC_UTF8_TO_UTF16LE);
+#endif	/* DWC_UTFLIB */
+
+EXPORT_SYMBOL(DWC_IN_IRQ);
+EXPORT_SYMBOL(DWC_IN_BH);
+EXPORT_SYMBOL(DWC_VPRINTF);
+EXPORT_SYMBOL(DWC_VSNPRINTF);
+EXPORT_SYMBOL(DWC_PRINTF);
+EXPORT_SYMBOL(DWC_SPRINTF);
+EXPORT_SYMBOL(DWC_SNPRINTF);
+EXPORT_SYMBOL(__DWC_WARN);
+EXPORT_SYMBOL(__DWC_ERROR);
+EXPORT_SYMBOL(DWC_EXCEPTION);
+
+#ifdef DEBUG
+EXPORT_SYMBOL(__DWC_DEBUG);
+#endif
+
+EXPORT_SYMBOL(__DWC_DMA_ALLOC);
+EXPORT_SYMBOL(__DWC_DMA_ALLOC_ATOMIC);
+EXPORT_SYMBOL(__DWC_DMA_FREE);
+EXPORT_SYMBOL(__DWC_ALLOC);
+EXPORT_SYMBOL(__DWC_ALLOC_ATOMIC);
+EXPORT_SYMBOL(__DWC_FREE);
+
+#ifdef DWC_CRYPTOLIB
+EXPORT_SYMBOL(DWC_RANDOM_BYTES);
+EXPORT_SYMBOL(DWC_AES_CBC);
+EXPORT_SYMBOL(DWC_SHA256);
+EXPORT_SYMBOL(DWC_HMAC_SHA256);
+#endif
+
+EXPORT_SYMBOL(DWC_CPU_TO_LE32);
+EXPORT_SYMBOL(DWC_CPU_TO_BE32);
+EXPORT_SYMBOL(DWC_LE32_TO_CPU);
+EXPORT_SYMBOL(DWC_BE32_TO_CPU);
+EXPORT_SYMBOL(DWC_CPU_TO_LE16);
+EXPORT_SYMBOL(DWC_CPU_TO_BE16);
+EXPORT_SYMBOL(DWC_LE16_TO_CPU);
+EXPORT_SYMBOL(DWC_BE16_TO_CPU);
+EXPORT_SYMBOL(DWC_READ_REG32);
+EXPORT_SYMBOL(DWC_WRITE_REG32);
+EXPORT_SYMBOL(DWC_MODIFY_REG32);
+
+#if 0
+EXPORT_SYMBOL(DWC_READ_REG64);
+EXPORT_SYMBOL(DWC_WRITE_REG64);
+EXPORT_SYMBOL(DWC_MODIFY_REG64);
+#endif
+
+EXPORT_SYMBOL(DWC_SPINLOCK_ALLOC);
+EXPORT_SYMBOL(DWC_SPINLOCK_FREE);
+EXPORT_SYMBOL(DWC_SPINLOCK);
+EXPORT_SYMBOL(DWC_SPINUNLOCK);
+EXPORT_SYMBOL(DWC_SPINLOCK_IRQSAVE);
+EXPORT_SYMBOL(DWC_SPINUNLOCK_IRQRESTORE);
+EXPORT_SYMBOL(DWC_MUTEX_ALLOC);
+
+#if (!defined(DWC_LINUX) || !defined(CONFIG_DEBUG_MUTEXES))
+EXPORT_SYMBOL(DWC_MUTEX_FREE);
+#endif
+
+EXPORT_SYMBOL(DWC_MUTEX_LOCK);
+EXPORT_SYMBOL(DWC_MUTEX_TRYLOCK);
+EXPORT_SYMBOL(DWC_MUTEX_UNLOCK);
+EXPORT_SYMBOL(DWC_UDELAY);
+EXPORT_SYMBOL(DWC_MDELAY);
+EXPORT_SYMBOL(DWC_MSLEEP);
+EXPORT_SYMBOL(DWC_TIME);
+EXPORT_SYMBOL(DWC_TIMER_ALLOC);
+EXPORT_SYMBOL(DWC_TIMER_FREE);
+EXPORT_SYMBOL(DWC_TIMER_SCHEDULE);
+EXPORT_SYMBOL(DWC_TIMER_CANCEL);
+EXPORT_SYMBOL(DWC_WAITQ_ALLOC);
+EXPORT_SYMBOL(DWC_WAITQ_FREE);
+EXPORT_SYMBOL(DWC_WAITQ_WAIT);
+EXPORT_SYMBOL(DWC_WAITQ_WAIT_TIMEOUT);
+EXPORT_SYMBOL(DWC_WAITQ_TRIGGER);
+EXPORT_SYMBOL(DWC_WAITQ_ABORT);
+EXPORT_SYMBOL(DWC_THREAD_RUN);
+EXPORT_SYMBOL(DWC_THREAD_STOP);
+EXPORT_SYMBOL(DWC_THREAD_SHOULD_STOP);
+EXPORT_SYMBOL(DWC_TASK_ALLOC);
+EXPORT_SYMBOL(DWC_TASK_FREE);
+EXPORT_SYMBOL(DWC_TASK_SCHEDULE);
+EXPORT_SYMBOL(DWC_WORKQ_WAIT_WORK_DONE);
+EXPORT_SYMBOL(DWC_WORKQ_ALLOC);
+EXPORT_SYMBOL(DWC_WORKQ_FREE);
+EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE);
+EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE_DELAYED);
+EXPORT_SYMBOL(DWC_WORKQ_PENDING);
+
+static int dwc_common_port_init_module(void)
+{
+	int result = 0;
+
+	printk(KERN_DEBUG "Module dwc_common_port init\n" );
+
+#ifdef DWC_DEBUG_MEMORY
+	result = dwc_memory_debug_start(NULL);
+	if (result) {
+		printk(KERN_ERR
+		       "dwc_memory_debug_start() failed with error %d\n",
+		       result);
+		return result;
+	}
+#endif
+
+#ifdef DWC_NOTIFYLIB
+	result = dwc_alloc_notification_manager(NULL, NULL);
+	if (result) {
+		printk(KERN_ERR
+		       "dwc_alloc_notification_manager() failed with error %d\n",
+		       result);
+		return result;
+	}
+#endif
+	return result;
+}
+
+static void dwc_common_port_exit_module(void)
+{
+	printk(KERN_DEBUG "Module dwc_common_port exit\n" );
+
+#ifdef DWC_NOTIFYLIB
+	dwc_free_notification_manager();
+#endif
+
+#ifdef DWC_DEBUG_MEMORY
+	dwc_memory_debug_stop();
+#endif
+}
+
+module_init(dwc_common_port_init_module);
+module_exit(dwc_common_port_exit_module);
+
+MODULE_DESCRIPTION("DWC Common Library - Portable version");
+MODULE_AUTHOR("Synopsys Inc.");
+MODULE_LICENSE ("GPL");
+
+#endif	/* DWC_LIBMODULE */
diff --git a/drivers/usb/dwc_otg/dwc_common_nbsd.c b/drivers/usb/dwc_otg/dwc_common_nbsd.c
new file mode 100644
index 0000000..49b07e1
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_common_nbsd.c
@@ -0,0 +1,1275 @@
+#include "dwc_os.h"
+#include "dwc_list.h"
+
+#ifdef DWC_CCLIB
+# include "dwc_cc.h"
+#endif
+
+#ifdef DWC_CRYPTOLIB
+# include "dwc_modpow.h"
+# include "dwc_dh.h"
+# include "dwc_crypto.h"
+#endif
+
+#ifdef DWC_NOTIFYLIB
+# include "dwc_notifier.h"
+#endif
+
+/* OS-Level Implementations */
+
+/* This is the NetBSD 4.0.1 kernel implementation of the DWC platform library. */
+
+
+/* MISC */
+
+void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
+{
+	return memset(dest, byte, size);
+}
+
+void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
+{
+	return memcpy(dest, src, size);
+}
+
+void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
+{
+	bcopy(src, dest, size);
+	return dest;
+}
+
+int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
+{
+	return memcmp(m1, m2, size);
+}
+
+int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
+{
+	return strncmp(s1, s2, size);
+}
+
+int DWC_STRCMP(void *s1, void *s2)
+{
+	return strcmp(s1, s2);
+}
+
+int DWC_STRLEN(char const *str)
+{
+	return strlen(str);
+}
+
+char *DWC_STRCPY(char *to, char const *from)
+{
+	return strcpy(to, from);
+}
+
+char *DWC_STRDUP(char const *str)
+{
+	int len = DWC_STRLEN(str) + 1;
+	char *new = DWC_ALLOC_ATOMIC(len);
+
+	if (!new) {
+		return NULL;
+	}
+
+	DWC_MEMCPY(new, str, len);
+	return new;
+}
+
+int DWC_ATOI(char *str, int32_t *value)
+{
+	char *end = NULL;
+
+	/* NetBSD doesn't have 'strtol' in the kernel, but 'strtoul'
+	 * should be equivalent on 2's complement machines
+	 */
+	*value = strtoul(str, &end, 0);
+	if (*end == '\0') {
+		return 0;
+	}
+
+	return -1;
+}
+
+int DWC_ATOUI(char *str, uint32_t *value)
+{
+	char *end = NULL;
+
+	*value = strtoul(str, &end, 0);
+	if (*end == '\0') {
+		return 0;
+	}
+
+	return -1;
+}
+
+
+#ifdef DWC_UTFLIB
+/* From usbstring.c */
+
+int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
+{
+	int	count = 0;
+	u8	c;
+	u16	uchar;
+
+	/* this insists on correct encodings, though not minimal ones.
+	 * BUT it currently rejects legit 4-byte UTF-8 code points,
+	 * which need surrogate pairs.  (Unicode 3.1 can use them.)
+	 */
+	while (len != 0 && (c = (u8) *s++) != 0) {
+		if (unlikely(c & 0x80)) {
+			// 2-byte sequence:
+			// 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
+			if ((c & 0xe0) == 0xc0) {
+				uchar = (c & 0x1f) << 6;
+
+				c = (u8) *s++;
+				if ((c & 0xc0) != 0xc0)
+					goto fail;
+				c &= 0x3f;
+				uchar |= c;
+
+			// 3-byte sequence (most CJKV characters):
+			// zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
+			} else if ((c & 0xf0) == 0xe0) {
+				uchar = (c & 0x0f) << 12;
+
+				c = (u8) *s++;
+				if ((c & 0xc0) != 0xc0)
+					goto fail;
+				c &= 0x3f;
+				uchar |= c << 6;
+
+				c = (u8) *s++;
+				if ((c & 0xc0) != 0xc0)
+					goto fail;
+				c &= 0x3f;
+				uchar |= c;
+
+				/* no bogus surrogates */
+				if (0xd800 <= uchar && uchar <= 0xdfff)
+					goto fail;
+
+			// 4-byte sequence (surrogate pairs, currently rare):
+			// 11101110wwwwzzzzyy + 110111yyyyxxxxxx
+			//     = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
+			// (uuuuu = wwww + 1)
+			// FIXME accept the surrogate code points (only)
+			} else
+				goto fail;
+		} else
+			uchar = c;
+		put_unaligned (cpu_to_le16 (uchar), cp++);
+		count++;
+		len--;
+	}
+	return count;
+fail:
+	return -1;
+}
+
+#endif	/* DWC_UTFLIB */
+
+
+/* dwc_debug.h */
+
+dwc_bool_t DWC_IN_IRQ(void)
+{
+//	return in_irq();
+	return 0;
+}
+
+dwc_bool_t DWC_IN_BH(void)
+{
+//	return in_softirq();
+	return 0;
+}
+
+void DWC_VPRINTF(char *format, va_list args)
+{
+	vprintf(format, args);
+}
+
+int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
+{
+	return vsnprintf(str, size, format, args);
+}
+
+void DWC_PRINTF(char *format, ...)
+{
+	va_list args;
+
+	va_start(args, format);
+	DWC_VPRINTF(format, args);
+	va_end(args);
+}
+
+int DWC_SPRINTF(char *buffer, char *format, ...)
+{
+	int retval;
+	va_list args;
+
+	va_start(args, format);
+	retval = vsprintf(buffer, format, args);
+	va_end(args);
+	return retval;
+}
+
+int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
+{
+	int retval;
+	va_list args;
+
+	va_start(args, format);
+	retval = vsnprintf(buffer, size, format, args);
+	va_end(args);
+	return retval;
+}
+
+void __DWC_WARN(char *format, ...)
+{
+	va_list args;
+
+	va_start(args, format);
+	DWC_VPRINTF(format, args);
+	va_end(args);
+}
+
+void __DWC_ERROR(char *format, ...)
+{
+	va_list args;
+
+	va_start(args, format);
+	DWC_VPRINTF(format, args);
+	va_end(args);
+}
+
+void DWC_EXCEPTION(char *format, ...)
+{
+	va_list args;
+
+	va_start(args, format);
+	DWC_VPRINTF(format, args);
+	va_end(args);
+//	BUG_ON(1);	???
+}
+
+#ifdef DEBUG
+void __DWC_DEBUG(char *format, ...)
+{
+	va_list args;
+
+	va_start(args, format);
+	DWC_VPRINTF(format, args);
+	va_end(args);
+}
+#endif
+
+
+/* dwc_mem.h */
+
+#if 0
+dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
+				uint32_t align,
+				uint32_t alloc)
+{
+	struct dma_pool *pool = dma_pool_create("Pool", NULL,
+						size, align, alloc);
+	return (dwc_pool_t *)pool;
+}
+
+void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
+{
+	dma_pool_destroy((struct dma_pool *)pool);
+}
+
+void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
+{
+//	return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
+	return dma_pool_alloc((struct dma_pool *)pool, M_WAITOK, dma_addr);
+}
+
+void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
+{
+	void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
+	memset(..);
+}
+
+void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
+{
+	dma_pool_free(pool, vaddr, daddr);
+}
+#endif
+
+void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
+{
+	dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
+	int error;
+
+	error = bus_dmamem_alloc(dma->dma_tag, size, 1, size, dma->segs,
+				 sizeof(dma->segs) / sizeof(dma->segs[0]),
+				 &dma->nsegs, BUS_DMA_NOWAIT);
+	if (error) {
+		printf("%s: bus_dmamem_alloc(%ju) failed: %d\n", __func__,
+		       (uintmax_t)size, error);
+		goto fail_0;
+	}
+
+	error = bus_dmamem_map(dma->dma_tag, dma->segs, dma->nsegs, size,
+			       (caddr_t *)&dma->dma_vaddr,
+			       BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
+	if (error) {
+		printf("%s: bus_dmamem_map failed: %d\n", __func__, error);
+		goto fail_1;
+	}
+
+	error = bus_dmamap_create(dma->dma_tag, size, 1, size, 0,
+				  BUS_DMA_NOWAIT, &dma->dma_map);
+	if (error) {
+		printf("%s: bus_dmamap_create failed: %d\n", __func__, error);
+		goto fail_2;
+	}
+
+	error = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr,
+				size, NULL, BUS_DMA_NOWAIT);
+	if (error) {
+		printf("%s: bus_dmamap_load failed: %d\n", __func__, error);
+		goto fail_3;
+	}
+
+	dma->dma_paddr = (bus_addr_t)dma->segs[0].ds_addr;
+	*dma_addr = dma->dma_paddr;
+	return dma->dma_vaddr;
+
+fail_3:
+	bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
+fail_2:
+	bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, size);
+fail_1:
+	bus_dmamem_free(dma->dma_tag, dma->segs, dma->nsegs);
+fail_0:
+	dma->dma_map = NULL;
+	dma->dma_vaddr = NULL;
+	dma->nsegs = 0;
+
+	return NULL;
+}
+
+void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
+{
+	dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
+
+	if (dma->dma_map != NULL) {
+		bus_dmamap_sync(dma->dma_tag, dma->dma_map, 0, size,
+				BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+		bus_dmamap_unload(dma->dma_tag, dma->dma_map);
+		bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
+		bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, size);
+		bus_dmamem_free(dma->dma_tag, dma->segs, dma->nsegs);
+		dma->dma_paddr = 0;
+		dma->dma_map = NULL;
+		dma->dma_vaddr = NULL;
+		dma->nsegs = 0;
+	}
+}
+
+void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
+{
+	return malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
+}
+
+void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
+{
+	return malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
+}
+
+void __DWC_FREE(void *mem_ctx, void *addr)
+{
+	free(addr, M_DEVBUF);
+}
+
+
+#ifdef DWC_CRYPTOLIB
+/* dwc_crypto.h */
+
+void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
+{
+	get_random_bytes(buffer, length);
+}
+
+int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
+{
+	struct crypto_blkcipher *tfm;
+	struct blkcipher_desc desc;
+	struct scatterlist sgd;
+	struct scatterlist sgs;
+
+	tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
+	if (tfm == NULL) {
+		printk("failed to load transform for aes CBC\n");
+		return -1;
+	}
+
+	crypto_blkcipher_setkey(tfm, key, keylen);
+	crypto_blkcipher_set_iv(tfm, iv, 16);
+
+	sg_init_one(&sgd, out, messagelen);
+	sg_init_one(&sgs, message, messagelen);
+
+	desc.tfm = tfm;
+	desc.flags = 0;
+
+	if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
+		crypto_free_blkcipher(tfm);
+		DWC_ERROR("AES CBC encryption failed");
+		return -1;
+	}
+
+	crypto_free_blkcipher(tfm);
+	return 0;
+}
+
+int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
+{
+	struct crypto_hash *tfm;
+	struct hash_desc desc;
+	struct scatterlist sg;
+
+	tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(tfm)) {
+		DWC_ERROR("Failed to load transform for sha256: %ld", PTR_ERR(tfm));
+		return 0;
+	}
+	desc.tfm = tfm;
+	desc.flags = 0;
+
+	sg_init_one(&sg, message, len);
+	crypto_hash_digest(&desc, &sg, len, out);
+	crypto_free_hash(tfm);
+
+	return 1;
+}
+
+int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
+		    uint8_t *key, uint32_t keylen, uint8_t *out)
+{
+	struct crypto_hash *tfm;
+	struct hash_desc desc;
+	struct scatterlist sg;
+
+	tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(tfm)) {
+		DWC_ERROR("Failed to load transform for hmac(sha256): %ld", PTR_ERR(tfm));
+		return 0;
+	}
+	desc.tfm = tfm;
+	desc.flags = 0;
+
+	sg_init_one(&sg, message, messagelen);
+	crypto_hash_setkey(tfm, key, keylen);
+	crypto_hash_digest(&desc, &sg, messagelen, out);
+	crypto_free_hash(tfm);
+
+	return 1;
+}
+
+#endif	/* DWC_CRYPTOLIB */
+
+
+/* Byte Ordering Conversions */
+
+uint32_t DWC_CPU_TO_LE32(uint32_t *p)
+{
+#ifdef __LITTLE_ENDIAN
+	return *p;
+#else
+	uint8_t *u_p = (uint8_t *)p;
+
+	return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
+#endif
+}
+
+uint32_t DWC_CPU_TO_BE32(uint32_t *p)
+{
+#ifdef __BIG_ENDIAN
+	return *p;
+#else
+	uint8_t *u_p = (uint8_t *)p;
+
+	return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
+#endif
+}
+
+uint32_t DWC_LE32_TO_CPU(uint32_t *p)
+{
+#ifdef __LITTLE_ENDIAN
+	return *p;
+#else
+	uint8_t *u_p = (uint8_t *)p;
+
+	return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
+#endif
+}
+
+uint32_t DWC_BE32_TO_CPU(uint32_t *p)
+{
+#ifdef __BIG_ENDIAN
+	return *p;
+#else
+	uint8_t *u_p = (uint8_t *)p;
+
+	return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
+#endif
+}
+
+uint16_t DWC_CPU_TO_LE16(uint16_t *p)
+{
+#ifdef __LITTLE_ENDIAN
+	return *p;
+#else
+	uint8_t *u_p = (uint8_t *)p;
+	return (u_p[1] | (u_p[0] << 8));
+#endif
+}
+
+uint16_t DWC_CPU_TO_BE16(uint16_t *p)
+{
+#ifdef __BIG_ENDIAN
+	return *p;
+#else
+	uint8_t *u_p = (uint8_t *)p;
+	return (u_p[1] | (u_p[0] << 8));
+#endif
+}
+
+uint16_t DWC_LE16_TO_CPU(uint16_t *p)
+{
+#ifdef __LITTLE_ENDIAN
+	return *p;
+#else
+	uint8_t *u_p = (uint8_t *)p;
+	return (u_p[1] | (u_p[0] << 8));
+#endif
+}
+
+uint16_t DWC_BE16_TO_CPU(uint16_t *p)
+{
+#ifdef __BIG_ENDIAN
+	return *p;
+#else
+	uint8_t *u_p = (uint8_t *)p;
+	return (u_p[1] | (u_p[0] << 8));
+#endif
+}
+
+
+/* Registers */
+
+uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg)
+{
+	dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
+	bus_size_t ior = (bus_size_t)reg;
+
+	return bus_space_read_4(io->iot, io->ioh, ior);
+}
+
+#if 0
+uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg)
+{
+	dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
+	bus_size_t ior = (bus_size_t)reg;
+
+	return bus_space_read_8(io->iot, io->ioh, ior);
+}
+#endif
+
+void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value)
+{
+	dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
+	bus_size_t ior = (bus_size_t)reg;
+
+	bus_space_write_4(io->iot, io->ioh, ior, value);
+}
+
+#if 0
+void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value)
+{
+	dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
+	bus_size_t ior = (bus_size_t)reg;
+
+	bus_space_write_8(io->iot, io->ioh, ior, value);
+}
+#endif
+
+void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask,
+		      uint32_t set_mask)
+{
+	dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
+	bus_size_t ior = (bus_size_t)reg;
+
+	bus_space_write_4(io->iot, io->ioh, ior,
+			  (bus_space_read_4(io->iot, io->ioh, ior) &
+			   ~clear_mask) | set_mask);
+}
+
+#if 0
+void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask,
+		      uint64_t set_mask)
+{
+	dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
+	bus_size_t ior = (bus_size_t)reg;
+
+	bus_space_write_8(io->iot, io->ioh, ior,
+			  (bus_space_read_8(io->iot, io->ioh, ior) &
+			   ~clear_mask) | set_mask);
+}
+#endif
+
+
+/* Locking */
+
+dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
+{
+	struct simplelock *sl = DWC_ALLOC(sizeof(*sl));
+
+	if (!sl) {
+		DWC_ERROR("Cannot allocate memory for spinlock");
+		return NULL;
+	}
+
+	simple_lock_init(sl);
+	return (dwc_spinlock_t *)sl;
+}
+
+void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
+{
+	struct simplelock *sl = (struct simplelock *)lock;
+
+	DWC_FREE(sl);
+}
+
+void DWC_SPINLOCK(dwc_spinlock_t *lock)
+{
+	simple_lock((struct simplelock *)lock);
+}
+
+void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
+{
+	simple_unlock((struct simplelock *)lock);
+}
+
+void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
+{
+	simple_lock((struct simplelock *)lock);
+	*flags = splbio();
+}
+
+void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
+{
+	splx(flags);
+	simple_unlock((struct simplelock *)lock);
+}
+
+dwc_mutex_t *DWC_MUTEX_ALLOC(void)
+{
+	dwc_mutex_t *mutex = DWC_ALLOC(sizeof(struct lock));
+
+	if (!mutex) {
+		DWC_ERROR("Cannot allocate memory for mutex");
+		return NULL;
+	}
+
+	lockinit((struct lock *)mutex, 0, "dw3mtx", 0, 0);
+	return mutex;
+}
+
+#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
+#else
+void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
+{
+	DWC_FREE(mutex);
+}
+#endif
+
+void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
+{
+	lockmgr((struct lock *)mutex, LK_EXCLUSIVE, NULL);
+}
+
+int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
+{
+	int status;
+
+	status = lockmgr((struct lock *)mutex, LK_EXCLUSIVE | LK_NOWAIT, NULL);
+	return status == 0;
+}
+
+void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
+{
+	lockmgr((struct lock *)mutex, LK_RELEASE, NULL);
+}
+
+
+/* Timing */
+
+void DWC_UDELAY(uint32_t usecs)
+{
+	DELAY(usecs);
+}
+
+void DWC_MDELAY(uint32_t msecs)
+{
+	do {
+		DELAY(1000);
+	} while (--msecs);
+}
+
+void DWC_MSLEEP(uint32_t msecs)
+{
+	struct timeval tv;
+
+	tv.tv_sec = msecs / 1000;
+	tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
+	tsleep(&tv, 0, "dw3slp", tvtohz(&tv));
+}
+
+uint32_t DWC_TIME(void)
+{
+	struct timeval tv;
+
+	microuptime(&tv);	// or getmicrouptime? (less precise, but faster)
+	return tv.tv_sec * 1000 + tv.tv_usec / 1000;
+}
+
+
+/* Timers */
+
+struct dwc_timer {
+	struct callout t;
+	char *name;
+	dwc_spinlock_t *lock;
+	dwc_timer_callback_t cb;
+	void *data;
+};
+
+dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
+{
+	dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
+
+	if (!t) {
+		DWC_ERROR("Cannot allocate memory for timer");
+		return NULL;
+	}
+
+	callout_init(&t->t);
+
+	t->name = DWC_STRDUP(name);
+	if (!t->name) {
+		DWC_ERROR("Cannot allocate memory for timer->name");
+		goto no_name;
+	}
+
+	t->lock = DWC_SPINLOCK_ALLOC();
+	if (!t->lock) {
+		DWC_ERROR("Cannot allocate memory for timer->lock");
+		goto no_lock;
+	}
+
+	t->cb = cb;
+	t->data = data;
+
+	return t;
+
+ no_lock:
+	DWC_FREE(t->name);
+ no_name:
+	DWC_FREE(t);
+
+	return NULL;
+}
+
+void DWC_TIMER_FREE(dwc_timer_t *timer)
+{
+	callout_stop(&timer->t);
+	DWC_SPINLOCK_FREE(timer->lock);
+	DWC_FREE(timer->name);
+	DWC_FREE(timer);
+}
+
+void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
+{
+	struct timeval tv;
+
+	tv.tv_sec = time / 1000;
+	tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
+	callout_reset(&timer->t, tvtohz(&tv), timer->cb, timer->data);
+}
+
+void DWC_TIMER_CANCEL(dwc_timer_t *timer)
+{
+	callout_stop(&timer->t);
+}
+
+
+/* Wait Queues */
+
+struct dwc_waitq {
+	struct simplelock lock;
+	int abort;
+};
+
+dwc_waitq_t *DWC_WAITQ_ALLOC(void)
+{
+	dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
+
+	if (!wq) {
+		DWC_ERROR("Cannot allocate memory for waitqueue");
+		return NULL;
+	}
+
+	simple_lock_init(&wq->lock);
+	wq->abort = 0;
+
+	return wq;
+}
+
+void DWC_WAITQ_FREE(dwc_waitq_t *wq)
+{
+	DWC_FREE(wq);
+}
+
+int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
+{
+	int ipl;
+	int result = 0;
+
+	simple_lock(&wq->lock);
+	ipl = splbio();
+
+	/* Skip the sleep if already aborted or triggered */
+	if (!wq->abort && !cond(data)) {
+		splx(ipl);
+		result = ltsleep(wq, PCATCH, "dw3wat", 0, &wq->lock); // infinite timeout
+		ipl = splbio();
+	}
+
+	if (result == 0) {			// awoken
+		if (wq->abort) {
+			wq->abort = 0;
+			result = -DWC_E_ABORT;
+		} else {
+			result = 0;
+		}
+
+		splx(ipl);
+		simple_unlock(&wq->lock);
+	} else {
+		wq->abort = 0;
+		splx(ipl);
+		simple_unlock(&wq->lock);
+
+		if (result == ERESTART) {	// signaled - restart
+			result = -DWC_E_RESTART;
+		} else {			// signaled - must be EINTR
+			result = -DWC_E_ABORT;
+		}
+	}
+
+	return result;
+}
+
+int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
+			       void *data, int32_t msecs)
+{
+	struct timeval tv, tv1, tv2;
+	int ipl;
+	int result = 0;
+
+	tv.tv_sec = msecs / 1000;
+	tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
+
+	simple_lock(&wq->lock);
+	ipl = splbio();
+
+	/* Skip the sleep if already aborted or triggered */
+	if (!wq->abort && !cond(data)) {
+		splx(ipl);
+		getmicrouptime(&tv1);
+		result = ltsleep(wq, PCATCH, "dw3wto", tvtohz(&tv), &wq->lock);
+		getmicrouptime(&tv2);
+		ipl = splbio();
+	}
+
+	if (result == 0) {			// awoken
+		if (wq->abort) {
+			wq->abort = 0;
+			splx(ipl);
+			simple_unlock(&wq->lock);
+			result = -DWC_E_ABORT;
+		} else {
+			splx(ipl);
+			simple_unlock(&wq->lock);
+
+			tv2.tv_usec -= tv1.tv_usec;
+			if (tv2.tv_usec < 0) {
+				tv2.tv_usec += 1000000;
+				tv2.tv_sec--;
+			}
+
+			tv2.tv_sec -= tv1.tv_sec;
+			result = tv2.tv_sec * 1000 + tv2.tv_usec / 1000;
+			result = msecs - result;
+			if (result <= 0)
+				result = 1;
+		}
+	} else {
+		wq->abort = 0;
+		splx(ipl);
+		simple_unlock(&wq->lock);
+
+		if (result == ERESTART) {	// signaled - restart
+			result = -DWC_E_RESTART;
+
+		} else if (result == EINTR) {		// signaled - interrupt
+			result = -DWC_E_ABORT;
+
+		} else {				// timed out
+			result = -DWC_E_TIMEOUT;
+		}
+	}
+
+	return result;
+}
+
+void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
+{
+	wakeup(wq);
+}
+
+void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
+{
+	int ipl;
+
+	simple_lock(&wq->lock);
+	ipl = splbio();
+	wq->abort = 1;
+	wakeup(wq);
+	splx(ipl);
+	simple_unlock(&wq->lock);
+}
+
+
+/* Threading */
+
+struct dwc_thread {
+	struct proc *proc;
+	int abort;
+};
+
+dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
+{
+	int retval;
+	dwc_thread_t *thread = DWC_ALLOC(sizeof(*thread));
+
+	if (!thread) {
+		return NULL;
+	}
+
+	thread->abort = 0;
+	retval = kthread_create1((void (*)(void *))func, data, &thread->proc,
+				 "%s", name);
+	if (retval) {
+		DWC_FREE(thread);
+		return NULL;
+	}
+
+	return thread;
+}
+
+int DWC_THREAD_STOP(dwc_thread_t *thread)
+{
+	int retval;
+
+	thread->abort = 1;
+	retval = tsleep(&thread->abort, 0, "dw3stp", 60 * hz);
+
+	if (retval == 0) {
+		/* DWC_THREAD_EXIT() will free the thread struct */
+		return 0;
+	}
+
+	/* NOTE: We leak the thread struct if thread doesn't die */
+
+	if (retval == EWOULDBLOCK) {
+		return -DWC_E_TIMEOUT;
+	}
+
+	return -DWC_E_UNKNOWN;
+}
+
+dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread)
+{
+	return thread->abort;
+}
+
+void DWC_THREAD_EXIT(dwc_thread_t *thread)
+{
+	wakeup(&thread->abort);
+	DWC_FREE(thread);
+	kthread_exit(0);
+}
+
+/* tasklets
+ - Runs in interrupt context (cannot sleep)
+ - Each tasklet runs on a single CPU
+ - Different tasklets can be running simultaneously on different CPUs
+ [ On NetBSD there is no corresponding mechanism, drivers don't have bottom-
+   halves. So we just call the callback directly from DWC_TASK_SCHEDULE() ]
+ */
+struct dwc_tasklet {
+	dwc_tasklet_callback_t cb;
+	void *data;
+};
+
+static void tasklet_callback(void *data)
+{
+	dwc_tasklet_t *task = (dwc_tasklet_t *)data;
+
+	task->cb(task->data);
+}
+
+dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
+{
+	dwc_tasklet_t *task = DWC_ALLOC(sizeof(*task));
+
+	if (task) {
+		task->cb = cb;
+		task->data = data;
+	} else {
+		DWC_ERROR("Cannot allocate memory for tasklet");
+	}
+
+	return task;
+}
+
+void DWC_TASK_FREE(dwc_tasklet_t *task)
+{
+	DWC_FREE(task);
+}
+
+void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
+{
+	tasklet_callback(task);
+}
+
+
+/* workqueues
+ - Runs in process context (can sleep)
+ */
+typedef struct work_container {
+	dwc_work_callback_t cb;
+	void *data;
+	dwc_workq_t *wq;
+	char *name;
+	int hz;
+	struct work task;
+} work_container_t;
+
+struct dwc_workq {
+	struct workqueue *taskq;
+	dwc_spinlock_t *lock;
+	dwc_waitq_t *waitq;
+	int pending;
+	struct work_container *container;
+};
+
+static void do_work(struct work *task, void *data)
+{
+	dwc_workq_t *wq = (dwc_workq_t *)data;
+	work_container_t *container = wq->container;
+	dwc_irqflags_t flags;
+
+	if (container->hz) {
+		tsleep(container, 0, "dw3wrk", container->hz);
+	}
+
+	container->cb(container->data);
+	DWC_DEBUG("Work done: %s, container=%p", container->name, container);
+
+	DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
+	if (container->name)
+		DWC_FREE(container->name);
+	DWC_FREE(container);
+	wq->pending--;
+	DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
+	DWC_WAITQ_TRIGGER(wq->waitq);
+}
+
+static int work_done(void *data)
+{
+	dwc_workq_t *workq = (dwc_workq_t *)data;
+
+	return workq->pending == 0;
+}
+
+int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
+{
+	return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
+}
+
+dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
+{
+	int result;
+	dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
+
+	if (!wq) {
+		DWC_ERROR("Cannot allocate memory for workqueue");
+		return NULL;
+	}
+
+	result = workqueue_create(&wq->taskq, name, do_work, wq, 0 /*PWAIT*/,
+				  IPL_BIO, 0);
+	if (result) {
+		DWC_ERROR("Cannot create workqueue");
+		goto no_taskq;
+	}
+
+	wq->pending = 0;
+
+	wq->lock = DWC_SPINLOCK_ALLOC();
+	if (!wq->lock) {
+		DWC_ERROR("Cannot allocate memory for spinlock");
+		goto no_lock;
+	}
+
+	wq->waitq = DWC_WAITQ_ALLOC();
+	if (!wq->waitq) {
+		DWC_ERROR("Cannot allocate memory for waitqueue");
+		goto no_waitq;
+	}
+
+	return wq;
+
+ no_waitq:
+	DWC_SPINLOCK_FREE(wq->lock);
+ no_lock:
+	workqueue_destroy(wq->taskq);
+ no_taskq:
+	DWC_FREE(wq);
+
+	return NULL;
+}
+
+void DWC_WORKQ_FREE(dwc_workq_t *wq)
+{
+#ifdef DEBUG
+	dwc_irqflags_t flags;
+
+	DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
+
+	if (wq->pending != 0) {
+		struct work_container *container = wq->container;
+
+		DWC_ERROR("Destroying work queue with pending work");
+
+		if (container && container->name) {
+			DWC_ERROR("Work %s still pending", container->name);
+		}
+	}
+
+	DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
+#endif
+	DWC_WAITQ_FREE(wq->waitq);
+	DWC_SPINLOCK_FREE(wq->lock);
+	workqueue_destroy(wq->taskq);
+	DWC_FREE(wq);
+}
+
+void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
+			char *format, ...)
+{
+	dwc_irqflags_t flags;
+	work_container_t *container;
+	static char name[128];
+	va_list args;
+
+	va_start(args, format);
+	DWC_VSNPRINTF(name, 128, format, args);
+	va_end(args);
+
+	DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
+	wq->pending++;
+	DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
+	DWC_WAITQ_TRIGGER(wq->waitq);
+
+	container = DWC_ALLOC_ATOMIC(sizeof(*container));
+	if (!container) {
+		DWC_ERROR("Cannot allocate memory for container");
+		return;
+	}
+
+	container->name = DWC_STRDUP(name);
+	if (!container->name) {
+		DWC_ERROR("Cannot allocate memory for container->name");
+		DWC_FREE(container);
+		return;
+	}
+
+	container->cb = cb;
+	container->data = data;
+	container->wq = wq;
+	container->hz = 0;
+	wq->container = container;
+
+	DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
+	workqueue_enqueue(wq->taskq, &container->task);
+}
+
+void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
+				void *data, uint32_t time, char *format, ...)
+{
+	dwc_irqflags_t flags;
+	work_container_t *container;
+	static char name[128];
+	struct timeval tv;
+	va_list args;
+
+	va_start(args, format);
+	DWC_VSNPRINTF(name, 128, format, args);
+	va_end(args);
+
+	DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
+	wq->pending++;
+	DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
+	DWC_WAITQ_TRIGGER(wq->waitq);
+
+	container = DWC_ALLOC_ATOMIC(sizeof(*container));
+	if (!container) {
+		DWC_ERROR("Cannot allocate memory for container");
+		return;
+	}
+
+	container->name = DWC_STRDUP(name);
+	if (!container->name) {
+		DWC_ERROR("Cannot allocate memory for container->name");
+		DWC_FREE(container);
+		return;
+	}
+
+	container->cb = cb;
+	container->data = data;
+	container->wq = wq;
+	tv.tv_sec = time / 1000;
+	tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
+	container->hz = tvtohz(&tv);
+	wq->container = container;
+
+	DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
+	workqueue_enqueue(wq->taskq, &container->task);
+}
+
+int DWC_WORKQ_PENDING(dwc_workq_t *wq)
+{
+	return wq->pending;
+}
diff --git a/drivers/usb/dwc_otg/dwc_crypto.c b/drivers/usb/dwc_otg/dwc_crypto.c
new file mode 100644
index 0000000..3b03532
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_crypto.c
@@ -0,0 +1,308 @@
+/* =========================================================================
+ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_crypto.c $
+ * $Revision: #5 $
+ * $Date: 2010/09/28 $
+ * $Change: 1596182 $
+ *
+ * Synopsys Portability Library Software and documentation
+ * (hereinafter, "Software") is an Unsupported proprietary work of
+ * Synopsys, Inc. unless otherwise expressly agreed to in writing
+ * between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product
+ * under any End User Software License Agreement or Agreement for
+ * Licensed Product with Synopsys or any supplement thereto. You are
+ * permitted to use and redistribute this Software in source and binary
+ * forms, with or without modification, provided that redistributions
+ * of source code must retain this notice. You may not view, use,
+ * disclose, copy or distribute this file or any information contained
+ * herein except pursuant to this license grant from Synopsys. If you
+ * do not agree with this notice, including the disclaimer below, then
+ * you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
+ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
+ * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================= */
+
+/** @file
+ * This file contains the WUSB cryptographic routines.
+ */
+
+#ifdef DWC_CRYPTOLIB
+
+#include "dwc_crypto.h"
+#include "usb.h"
+
+#ifdef DEBUG
+static inline void dump_bytes(char *name, uint8_t *bytes, int len)
+{
+	int i;
+	DWC_PRINTF("%s: ", name);
+	for (i=0; i<len; i++) {
+		DWC_PRINTF("%02x ", bytes[i]);
+	}
+	DWC_PRINTF("\n");
+}
+#else
+#define dump_bytes(x...)
+#endif
+
+/* Display a block */
+void show_block(const u8 *blk, const char *prefix, const char *suffix, int a)
+{
+#ifdef DWC_DEBUG_CRYPTO
+	int i, blksize = 16;
+
+	DWC_DEBUG("%s", prefix);
+
+	if (suffix == NULL) {
+		suffix = "\n";
+		blksize = a;
+	}
+
+	for (i = 0; i < blksize; i++)
+		DWC_PRINT("%02x%s", *blk++, ((i & 3) == 3) ? "  " : " ");
+	DWC_PRINT(suffix);
+#endif
+}
+
+/**
+ * Encrypts an array of bytes using the AES encryption engine.
+ * If <code>dst</code> == <code>src</code>, then the bytes will be encrypted
+ * in-place.
+ *
+ * @return  0 on success, negative error code on error.
+ */
+int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst)
+{
+	u8 block_t[16];
+	DWC_MEMSET(block_t, 0, 16);
+
+	return DWC_AES_CBC(src, 16, key, 16, block_t, dst);
+}
+
+/**
+ * The CCM-MAC-FUNCTION described in section 6.5 of the WUSB spec.
+ * This function takes a data string and returns the encrypted CBC
+ * Counter-mode MIC.
+ *
+ * @param key     The 128-bit symmetric key.
+ * @param nonce   The CCM nonce.
+ * @param label   The unique 14-byte ASCII text label.
+ * @param bytes   The byte array to be encrypted.
+ * @param len     Length of the byte array.
+ * @param result  Byte array to receive the 8-byte encrypted MIC.
+ */
+void dwc_wusb_cmf(u8 *key, u8 *nonce,
+		  char *label, u8 *bytes, int len, u8 *result)
+{
+	u8 block_m[16];
+	u8 block_x[16];
+	u8 block_t[8];
+	int idx, blkNum;
+	u16 la = (u16)(len + 14);
+
+	/* Set the AES-128 key */
+	//dwc_aes_setkey(tfm, key, 16);
+
+	/* Fill block B0 from flags = 0x59, N, and l(m) = 0 */
+	block_m[0] = 0x59;
+	for (idx = 0; idx < 13; idx++)
+		block_m[idx + 1] = nonce[idx];
+	block_m[14] = 0;
+	block_m[15] = 0;
+
+	/* Produce the CBC IV */
+	dwc_wusb_aes_encrypt(block_m, key, block_x);
+	show_block(block_m, "CBC IV in: ", "\n", 0);
+	show_block(block_x, "CBC IV out:", "\n", 0);
+
+	/* Fill block B1 from l(a) = Blen + 14, and A */
+	block_x[0] ^= (u8)(la >> 8);
+	block_x[1] ^= (u8)la;
+	for (idx = 0; idx < 14; idx++)
+		block_x[idx + 2] ^= label[idx];
+	show_block(block_x, "After xor: ", "b1\n", 16);
+
+	dwc_wusb_aes_encrypt(block_x, key, block_x);
+	show_block(block_x, "After AES: ", "b1\n", 16);
+
+	idx = 0;
+	blkNum = 0;
+
+	/* Fill remaining blocks with B */
+	while (len-- > 0) {
+		block_x[idx] ^= *bytes++;
+		if (++idx >= 16) {
+			idx = 0;
+			show_block(block_x, "After xor: ", "\n", blkNum);
+			dwc_wusb_aes_encrypt(block_x, key, block_x);
+			show_block(block_x, "After AES: ", "\n", blkNum);
+			blkNum++;
+		}
+	}
+
+	/* Handle partial last block */
+	if (idx > 0) {
+		show_block(block_x, "After xor: ", "\n", blkNum);
+		dwc_wusb_aes_encrypt(block_x, key, block_x);
+		show_block(block_x, "After AES: ", "\n", blkNum);
+	}
+
+	/* Save the MIC tag */
+	DWC_MEMCPY(block_t, block_x, 8);
+	show_block(block_t, "MIC tag  : ", NULL, 8);
+
+	/* Fill block A0 from flags = 0x01, N, and counter = 0 */
+	block_m[0] = 0x01;
+	block_m[14] = 0;
+	block_m[15] = 0;
+
+	/* Encrypt the counter */
+	dwc_wusb_aes_encrypt(block_m, key, block_x);
+	show_block(block_x, "CTR[MIC] : ", NULL, 8);
+
+	/* XOR with MIC tag */
+	for (idx = 0; idx < 8; idx++) {
+		block_t[idx] ^= block_x[idx];
+	}
+
+	/* Return result to caller */
+	DWC_MEMCPY(result, block_t, 8);
+	show_block(result, "CCM-MIC  : ", NULL, 8);
+
+}
+
+/**
+ * The PRF function described in section 6.5 of the WUSB spec. This function
+ * concatenates MIC values returned from dwc_cmf() to create a value of
+ * the requested length.
+ *
+ * @param prf_len  Length of the PRF function in bits (64, 128, or 256).
+ * @param key, nonce, label, bytes, len  Same as for dwc_cmf().
+ * @param result   Byte array to receive the result.
+ */
+void dwc_wusb_prf(int prf_len, u8 *key,
+		  u8 *nonce, char *label, u8 *bytes, int len, u8 *result)
+{
+	int i;
+
+	nonce[0] = 0;
+	for (i = 0; i < prf_len >> 6; i++, nonce[0]++) {
+		dwc_wusb_cmf(key, nonce, label, bytes, len, result);
+		result += 8;
+	}
+}
+
+/**
+ * Fills in CCM Nonce per the WUSB spec.
+ *
+ * @param[in] haddr Host address.
+ * @param[in] daddr Device address.
+ * @param[in] tkid Session Key(PTK) identifier.
+ * @param[out] nonce Pointer to where the CCM Nonce output is to be written.
+ */
+void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid,
+			     uint8_t *nonce)
+{
+
+	DWC_DEBUG("%s %x %x\n", __func__, daddr, haddr);
+
+	DWC_MEMSET(&nonce[0], 0, 16);
+
+	DWC_MEMCPY(&nonce[6], tkid, 3);
+	nonce[9] = daddr & 0xFF;
+	nonce[10] = (daddr >> 8) & 0xFF;
+	nonce[11] = haddr & 0xFF;
+	nonce[12] = (haddr >> 8) & 0xFF;
+
+	dump_bytes("CCM nonce", nonce, 16);
+}
+
+/**
+ * Generates a 16-byte cryptographic-grade random number for the Host/Device
+ * Nonce.
+ */
+void dwc_wusb_gen_nonce(uint16_t addr, uint8_t *nonce)
+{
+	uint8_t inonce[16];
+	uint32_t temp[4];
+
+	/* Fill in the Nonce */
+	DWC_MEMSET(&inonce[0], 0, sizeof(inonce));
+	inonce[9] = addr & 0xFF;
+	inonce[10] = (addr >> 8) & 0xFF;
+	inonce[11] = inonce[9];
+	inonce[12] = inonce[10];
+
+	/* Collect "randomness samples" */
+	DWC_RANDOM_BYTES((uint8_t *)temp, 16);
+
+	dwc_wusb_prf_128((uint8_t *)temp, nonce,
+			 "Random Numbers", (uint8_t *)temp, sizeof(temp),
+			 nonce);
+}
+
+/**
+ * Generates the Session Key (PTK) and Key Confirmation Key (KCK) per the
+ * WUSB spec.
+ *
+ * @param[in] ccm_nonce Pointer to CCM Nonce.
+ * @param[in] mk Master Key to derive the session from
+ * @param[in] hnonce Pointer to Host Nonce.
+ * @param[in] dnonce Pointer to Device Nonce.
+ * @param[out] kck Pointer to where the KCK output is to be written.
+ * @param[out] ptk Pointer to where the PTK output is to be written.
+ */
+void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk, uint8_t *hnonce,
+		      uint8_t *dnonce, uint8_t *kck, uint8_t *ptk)
+{
+	uint8_t idata[32];
+	uint8_t odata[32];
+
+	dump_bytes("ck", mk, 16);
+	dump_bytes("hnonce", hnonce, 16);
+	dump_bytes("dnonce", dnonce, 16);
+
+	/* The data is the HNonce and DNonce concatenated */
+	DWC_MEMCPY(&idata[0], hnonce, 16);
+	DWC_MEMCPY(&idata[16], dnonce, 16);
+
+	dwc_wusb_prf_256(mk, ccm_nonce, "Pair-wise keys", idata, 32, odata);
+
+	/* Low 16 bytes of the result is the KCK, high 16 is the PTK */
+	DWC_MEMCPY(kck, &odata[0], 16);
+	DWC_MEMCPY(ptk, &odata[16], 16);
+
+	dump_bytes("kck", kck, 16);
+	dump_bytes("ptk", ptk, 16);
+}
+
+/**
+ * Generates the Message Integrity Code over the Handshake data per the
+ * WUSB spec.
+ *
+ * @param ccm_nonce Pointer to CCM Nonce.
+ * @param kck   Pointer to Key Confirmation Key.
+ * @param data  Pointer to Handshake data to be checked.
+ * @param mic   Pointer to where the MIC output is to be written.
+ */
+void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t *kck,
+		      uint8_t *data, uint8_t *mic)
+{
+
+	dwc_wusb_prf_64(kck, ccm_nonce, "out-of-bandMIC",
+			data, WUSB_HANDSHAKE_LEN_FOR_MIC, mic);
+}
+
+#endif	/* DWC_CRYPTOLIB */
diff --git a/drivers/usb/dwc_otg/dwc_crypto.h b/drivers/usb/dwc_otg/dwc_crypto.h
new file mode 100644
index 0000000..26fcddc
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_crypto.h
@@ -0,0 +1,111 @@
+/* =========================================================================
+ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_crypto.h $
+ * $Revision: #3 $
+ * $Date: 2010/09/28 $
+ * $Change: 1596182 $
+ *
+ * Synopsys Portability Library Software and documentation
+ * (hereinafter, "Software") is an Unsupported proprietary work of
+ * Synopsys, Inc. unless otherwise expressly agreed to in writing
+ * between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product
+ * under any End User Software License Agreement or Agreement for
+ * Licensed Product with Synopsys or any supplement thereto. You are
+ * permitted to use and redistribute this Software in source and binary
+ * forms, with or without modification, provided that redistributions
+ * of source code must retain this notice. You may not view, use,
+ * disclose, copy or distribute this file or any information contained
+ * herein except pursuant to this license grant from Synopsys. If you
+ * do not agree with this notice, including the disclaimer below, then
+ * you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
+ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
+ * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================= */
+
+#ifndef _DWC_CRYPTO_H_
+#define _DWC_CRYPTO_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @file
+ *
+ * This file contains declarations for the WUSB Cryptographic routines as
+ * defined in the WUSB spec.  They are only to be used internally by the DWC UWB
+ * modules.
+ */
+
+#include "dwc_os.h"
+
+int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst);
+
+void dwc_wusb_cmf(u8 *key, u8 *nonce,
+		  char *label, u8 *bytes, int len, u8 *result);
+void dwc_wusb_prf(int prf_len, u8 *key,
+		  u8 *nonce, char *label, u8 *bytes, int len, u8 *result);
+
+/**
+ * The PRF-64 function described in section 6.5 of the WUSB spec.
+ *
+ * @param key, nonce, label, bytes, len, result  Same as for dwc_prf().
+ */
+static inline void dwc_wusb_prf_64(u8 *key, u8 *nonce,
+				   char *label, u8 *bytes, int len, u8 *result)
+{
+	dwc_wusb_prf(64, key, nonce, label, bytes, len, result);
+}
+
+/**
+ * The PRF-128 function described in section 6.5 of the WUSB spec.
+ *
+ * @param key, nonce, label, bytes, len, result  Same as for dwc_prf().
+ */
+static inline void dwc_wusb_prf_128(u8 *key, u8 *nonce,
+				    char *label, u8 *bytes, int len, u8 *result)
+{
+	dwc_wusb_prf(128, key, nonce, label, bytes, len, result);
+}
+
+/**
+ * The PRF-256 function described in section 6.5 of the WUSB spec.
+ *
+ * @param key, nonce, label, bytes, len, result  Same as for dwc_prf().
+ */
+static inline void dwc_wusb_prf_256(u8 *key, u8 *nonce,
+				    char *label, u8 *bytes, int len, u8 *result)
+{
+	dwc_wusb_prf(256, key, nonce, label, bytes, len, result);
+}
+
+
+void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid,
+			       uint8_t *nonce);
+void dwc_wusb_gen_nonce(uint16_t addr,
+			  uint8_t *nonce);
+
+void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk,
+			uint8_t *hnonce, uint8_t *dnonce,
+			uint8_t *kck, uint8_t *ptk);
+
+
+void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t
+			*kck, uint8_t *data, uint8_t *mic);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DWC_CRYPTO_H_ */
diff --git a/drivers/usb/dwc_otg/dwc_dh.c b/drivers/usb/dwc_otg/dwc_dh.c
new file mode 100644
index 0000000..997f753
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_dh.c
@@ -0,0 +1,291 @@
+/* =========================================================================
+ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_dh.c $
+ * $Revision: #3 $
+ * $Date: 2010/09/28 $
+ * $Change: 1596182 $
+ *
+ * Synopsys Portability Library Software and documentation
+ * (hereinafter, "Software") is an Unsupported proprietary work of
+ * Synopsys, Inc. unless otherwise expressly agreed to in writing
+ * between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product
+ * under any End User Software License Agreement or Agreement for
+ * Licensed Product with Synopsys or any supplement thereto. You are
+ * permitted to use and redistribute this Software in source and binary
+ * forms, with or without modification, provided that redistributions
+ * of source code must retain this notice. You may not view, use,
+ * disclose, copy or distribute this file or any information contained
+ * herein except pursuant to this license grant from Synopsys. If you
+ * do not agree with this notice, including the disclaimer below, then
+ * you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
+ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
+ * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================= */
+#ifdef DWC_CRYPTOLIB
+
+#ifndef CONFIG_MACH_IPMATE
+
+#include "dwc_dh.h"
+#include "dwc_modpow.h"
+
+#ifdef DEBUG
+/* This function prints out a buffer in the format described in the Association
+ * Model specification. */
+static void dh_dump(char *str, void *_num, int len)
+{
+	uint8_t *num = _num;
+	int i;
+	DWC_PRINTF("%s\n", str);
+	for (i = 0; i < len; i ++) {
+		DWC_PRINTF("%02x", num[i]);
+		if (((i + 1) % 2) == 0) DWC_PRINTF(" ");
+		if (((i + 1) % 26) == 0) DWC_PRINTF("\n");
+	}
+
+	DWC_PRINTF("\n");
+}
+#else
+#define dh_dump(_x...) do {; } while(0)
+#endif
+
+/* Constant g value */
+static __u32 dh_g[] = {
+	0x02000000,
+};
+
+/* Constant p value */
+static __u32 dh_p[] = {
+	0xFFFFFFFF, 0xFFFFFFFF, 0xA2DA0FC9, 0x34C26821, 0x8B62C6C4, 0xD11CDC80, 0x084E0229, 0x74CC678A,
+	0xA6BE0B02, 0x229B133B, 0x79084A51, 0xDD04348E, 0xB31995EF, 0x1B433ACD, 0x6D0A2B30, 0x37145FF2,
+	0x6D35E14F, 0x45C2516D, 0x76B585E4, 0xC67E5E62, 0xE9424CF4, 0x6BED37A6, 0xB65CFF0B, 0xEDB706F4,
+	0xFB6B38EE, 0xA59F895A, 0x11249FAE, 0xE61F4B7C, 0x51662849, 0x3D5BE4EC, 0xB87C00C2, 0x05BF63A1,
+	0x3648DA98, 0x9AD3551C, 0xA83F1669, 0x5FCF24FD, 0x235D6583, 0x96ADA3DC, 0x56F3621C, 0xBB528520,
+	0x0729D59E, 0x6D969670, 0x4E350C67, 0x0498BC4A, 0x086C74F1, 0x7C2118CA, 0x465E9032, 0x3BCE362E,
+	0x2C779EE3, 0x03860E18, 0xA283279B, 0x8FA207EC, 0xF05DC5B5, 0xC9524C6F, 0xF6CB2BDE, 0x18175895,
+	0x7C499539, 0xE56A95EA, 0x1826D215, 0x1005FA98, 0x5A8E7215, 0x2DC4AA8A, 0x0D1733AD, 0x337A5004,
+	0xAB2155A8, 0x64BA1CDF, 0x0485FBEC, 0x0AEFDB58, 0x5771EA8A, 0x7D0C065D, 0x850F97B3, 0xC7E4E1A6,
+	0x8CAEF5AB, 0xD73309DB, 0xE0948C1E, 0x9D61254A, 0x26D2E3CE, 0x6BEED21A, 0x06FA2FF1, 0x64088AD9,
+	0x730276D8, 0x646AC83E, 0x182B1F52, 0x0C207B17, 0x5717E1BB, 0x6C5D617A, 0xC0880977, 0xE246D9BA,
+	0xA04FE208, 0x31ABE574, 0xFC5BDB43, 0x8E10FDE0, 0x20D1824B, 0xCAD23AA9, 0xFFFFFFFF, 0xFFFFFFFF,
+};
+
+static void dh_swap_bytes(void *_in, void *_out, uint32_t len)
+{
+	uint8_t *in = _in;
+	uint8_t *out = _out;
+	int i;
+	for (i=0; i<len; i++) {
+		out[i] = in[len-1-i];
+	}
+}
+
+/* Computes the modular exponentiation (num^exp % mod).  num, exp, and mod are
+ * big endian numbers of size len, in bytes.  Each len value must be a multiple
+ * of 4. */
+int dwc_dh_modpow(void *mem_ctx, void *num, uint32_t num_len,
+		  void *exp, uint32_t exp_len,
+		  void *mod, uint32_t mod_len,
+		  void *out)
+{
+	/* modpow() takes little endian numbers.  AM uses big-endian.  This
+	 * function swaps bytes of numbers before passing onto modpow. */
+
+	int retval = 0;
+	uint32_t *result;
+
+	uint32_t *bignum_num = dwc_alloc(mem_ctx, num_len + 4);
+	uint32_t *bignum_exp = dwc_alloc(mem_ctx, exp_len + 4);
+	uint32_t *bignum_mod = dwc_alloc(mem_ctx, mod_len + 4);
+
+	dh_swap_bytes(num, &bignum_num[1], num_len);
+	bignum_num[0] = num_len / 4;
+
+	dh_swap_bytes(exp, &bignum_exp[1], exp_len);
+	bignum_exp[0] = exp_len / 4;
+
+	dh_swap_bytes(mod, &bignum_mod[1], mod_len);
+	bignum_mod[0] = mod_len / 4;
+
+	result = dwc_modpow(mem_ctx, bignum_num, bignum_exp, bignum_mod);
+	if (!result) {
+		retval = -1;
+		goto dh_modpow_nomem;
+	}
+
+	dh_swap_bytes(&result[1], out, result[0] * 4);
+	dwc_free(mem_ctx, result);
+
+ dh_modpow_nomem:
+	dwc_free(mem_ctx, bignum_num);
+	dwc_free(mem_ctx, bignum_exp);
+	dwc_free(mem_ctx, bignum_mod);
+	return retval;
+}
+
+
+int dwc_dh_pk(void *mem_ctx, uint8_t nd, uint8_t *exp, uint8_t *pk, uint8_t *hash)
+{
+	int retval;
+	uint8_t m3[385];
+
+#ifndef DH_TEST_VECTORS
+	DWC_RANDOM_BYTES(exp, 32);
+#endif
+
+	/* Compute the pkd */
+	if ((retval = dwc_dh_modpow(mem_ctx, dh_g, 4,
+				    exp, 32,
+				    dh_p, 384, pk))) {
+		return retval;
+	}
+
+	m3[384] = nd;
+	DWC_MEMCPY(&m3[0], pk, 384);
+	DWC_SHA256(m3, 385, hash);
+
+ 	dh_dump("PK", pk, 384);
+ 	dh_dump("SHA-256(M3)", hash, 32);
+	return 0;
+}
+
+int dwc_dh_derive_keys(void *mem_ctx, uint8_t nd, uint8_t *pkh, uint8_t *pkd,
+		       uint8_t *exp, int is_host,
+		       char *dd, uint8_t *ck, uint8_t *kdk)
+{
+	int retval;
+	uint8_t mv[784];
+	uint8_t sha_result[32];
+	uint8_t dhkey[384];
+	uint8_t shared_secret[384];
+	char *message;
+	uint32_t vd;
+
+	uint8_t *pk;
+
+	if (is_host) {
+		pk = pkd;
+	}
+	else {
+		pk = pkh;
+	}
+
+	if ((retval = dwc_dh_modpow(mem_ctx, pk, 384,
+				    exp, 32,
+				    dh_p, 384, shared_secret))) {
+		return retval;
+	}
+	dh_dump("Shared Secret", shared_secret, 384);
+
+	DWC_SHA256(shared_secret, 384, dhkey);
+	dh_dump("DHKEY", dhkey, 384);
+
+	DWC_MEMCPY(&mv[0], pkd, 384);
+	DWC_MEMCPY(&mv[384], pkh, 384);
+	DWC_MEMCPY(&mv[768], "displayed digest", 16);
+	dh_dump("MV", mv, 784);
+
+	DWC_SHA256(mv, 784, sha_result);
+	dh_dump("SHA-256(MV)", sha_result, 32);
+	dh_dump("First 32-bits of SHA-256(MV)", sha_result, 4);
+
+	dh_swap_bytes(sha_result, &vd, 4);
+#ifdef DEBUG
+	DWC_PRINTF("Vd (decimal) = %d\n", vd);
+#endif
+
+	switch (nd) {
+	case 2:
+		vd = vd % 100;
+		DWC_SPRINTF(dd, "%02d", vd);
+		break;
+	case 3:
+		vd = vd % 1000;
+		DWC_SPRINTF(dd, "%03d", vd);
+		break;
+	case 4:
+		vd = vd % 10000;
+		DWC_SPRINTF(dd, "%04d", vd);
+		break;
+	}
+#ifdef DEBUG
+	DWC_PRINTF("Display Digits: %s\n", dd);
+#endif
+
+	message = "connection key";
+	DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
+ 	dh_dump("HMAC(SHA-256, DHKey, connection key)", sha_result, 32);
+	DWC_MEMCPY(ck, sha_result, 16);
+
+	message = "key derivation key";
+	DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
+ 	dh_dump("HMAC(SHA-256, DHKey, key derivation key)", sha_result, 32);
+	DWC_MEMCPY(kdk, sha_result, 32);
+
+	return 0;
+}
+
+
+#ifdef DH_TEST_VECTORS
+
+static __u8 dh_a[] = {
+	0x44, 0x00, 0x51, 0xd6,
+	0xf0, 0xb5, 0x5e, 0xa9,
+	0x67, 0xab, 0x31, 0xc6,
+	0x8a, 0x8b, 0x5e, 0x37,
+	0xd9, 0x10, 0xda, 0xe0,
+	0xe2, 0xd4, 0x59, 0xa4,
+	0x86, 0x45, 0x9c, 0xaa,
+	0xdf, 0x36, 0x75, 0x16,
+};
+
+static __u8 dh_b[] = {
+	0x5d, 0xae, 0xc7, 0x86,
+	0x79, 0x80, 0xa3, 0x24,
+	0x8c, 0xe3, 0x57, 0x8f,
+	0xc7, 0x5f, 0x1b, 0x0f,
+	0x2d, 0xf8, 0x9d, 0x30,
+	0x6f, 0xa4, 0x52, 0xcd,
+	0xe0, 0x7a, 0x04, 0x8a,
+	0xde, 0xd9, 0x26, 0x56,
+};
+
+void dwc_run_dh_test_vectors(void *mem_ctx)
+{
+	uint8_t pkd[384];
+	uint8_t pkh[384];
+	uint8_t hashd[32];
+	uint8_t hashh[32];
+	uint8_t ck[16];
+	uint8_t kdk[32];
+	char dd[5];
+
+	DWC_PRINTF("\n\n\nDH_TEST_VECTORS\n\n");
+
+	/* compute the PKd and SHA-256(PKd || Nd) */
+	DWC_PRINTF("Computing PKd\n");
+	dwc_dh_pk(mem_ctx, 2, dh_a, pkd, hashd);
+
+	/* compute the PKd and SHA-256(PKh || Nd) */
+	DWC_PRINTF("Computing PKh\n");
+	dwc_dh_pk(mem_ctx, 2, dh_b, pkh, hashh);
+
+	/* compute the dhkey */
+	dwc_dh_derive_keys(mem_ctx, 2, pkh, pkd, dh_a, 0, dd, ck, kdk);
+}
+#endif /* DH_TEST_VECTORS */
+
+#endif /* !CONFIG_MACH_IPMATE */
+
+#endif /* DWC_CRYPTOLIB */
diff --git a/drivers/usb/dwc_otg/dwc_dh.h b/drivers/usb/dwc_otg/dwc_dh.h
new file mode 100644
index 0000000..25c1cc0
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_dh.h
@@ -0,0 +1,106 @@
+/* =========================================================================
+ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_dh.h $
+ * $Revision: #4 $
+ * $Date: 2010/09/28 $
+ * $Change: 1596182 $
+ *
+ * Synopsys Portability Library Software and documentation
+ * (hereinafter, "Software") is an Unsupported proprietary work of
+ * Synopsys, Inc. unless otherwise expressly agreed to in writing
+ * between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product
+ * under any End User Software License Agreement or Agreement for
+ * Licensed Product with Synopsys or any supplement thereto. You are
+ * permitted to use and redistribute this Software in source and binary
+ * forms, with or without modification, provided that redistributions
+ * of source code must retain this notice. You may not view, use,
+ * disclose, copy or distribute this file or any information contained
+ * herein except pursuant to this license grant from Synopsys. If you
+ * do not agree with this notice, including the disclaimer below, then
+ * you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
+ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
+ * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================= */
+#ifndef _DWC_DH_H_
+#define _DWC_DH_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "dwc_os.h"
+
+/** @file
+ *
+ * This file defines the common functions on device and host for performing
+ * numeric association as defined in the WUSB spec.  They are only to be
+ * used internally by the DWC UWB modules. */
+
+extern int dwc_dh_sha256(uint8_t *message, uint32_t len, uint8_t *out);
+extern int dwc_dh_hmac_sha256(uint8_t *message, uint32_t messagelen,
+			      uint8_t *key, uint32_t keylen,
+			      uint8_t *out);
+extern int dwc_dh_modpow(void *mem_ctx, void *num, uint32_t num_len,
+			 void *exp, uint32_t exp_len,
+			 void *mod, uint32_t mod_len,
+			 void *out);
+
+/** Computes PKD or PKH, and SHA-256(PKd || Nd)
+ *
+ * PK = g^exp mod p.
+ *
+ * Input:
+ * Nd = Number of digits on the device.
+ *
+ * Output:
+ * exp = A 32-byte buffer to be filled with a randomly generated number.
+ *       used as either A or B.
+ * pk = A 384-byte buffer to be filled with the PKH or PKD.
+ * hash = A 32-byte buffer to be filled with SHA-256(PK || ND).
+ */
+extern int dwc_dh_pk(void *mem_ctx, uint8_t nd, uint8_t *exp, uint8_t *pkd, uint8_t *hash);
+
+/** Computes the DHKEY, and VD.
+ *
+ * If called from host, then it will comput DHKEY=PKD^exp % p.
+ * If called from device, then it will comput DHKEY=PKH^exp % p.
+ *
+ * Input:
+ * pkd = The PKD value.
+ * pkh = The PKH value.
+ * exp = The A value (if device) or B value (if host) generated in dwc_wudev_dh_pk.
+ * is_host = Set to non zero if a WUSB host is calling this function.
+ *
+ * Output:
+
+ * dd = A pointer to an buffer to be set to the displayed digits string to be shown
+ *      to the user.  This buffer should be at 5 bytes long to hold 4 digits plus a
+ *      null termination character.  This buffer can be used directly for display.
+ * ck = A 16-byte buffer to be filled with the CK.
+ * kdk = A 32-byte buffer to be filled with the KDK.
+ */
+extern int dwc_dh_derive_keys(void *mem_ctx, uint8_t nd, uint8_t *pkh, uint8_t *pkd,
+			      uint8_t *exp, int is_host,
+			      char *dd, uint8_t *ck, uint8_t *kdk);
+
+#ifdef DH_TEST_VECTORS
+extern void dwc_run_dh_test_vectors(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DWC_DH_H_ */
diff --git a/drivers/usb/dwc_otg/dwc_list.h b/drivers/usb/dwc_otg/dwc_list.h
new file mode 100644
index 0000000..89cc325
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_list.h
@@ -0,0 +1,594 @@
+/*	$OpenBSD: queue.h,v 1.26 2004/05/04 16:59:32 grange Exp $	*/
+/*	$NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $	*/
+
+/*
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)queue.h	8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef _DWC_LIST_H_
+#define _DWC_LIST_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @file
+ *
+ * This file defines linked list operations.  It is derived from BSD with
+ * only the MACRO names being prefixed with DWC_.  This is because a few of
+ * these names conflict with those on Linux.  For documentation on use, see the
+ * inline comments in the source code.  The original license for this source
+ * code applies and is preserved in the dwc_list.h source file.
+ */
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * lists, simple queues, tail queues, and circular queues.
+ *
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction.  Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A simple queue is headed by a pair of pointers, one the head of the
+ * list and the other to the tail of the list. The elements are singly
+ * linked to save space, so elements can only be removed from the
+ * head of the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A simple queue may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+/*
+ * Double-linked List.
+ */
+
+typedef struct dwc_list_link {
+	struct dwc_list_link *next;
+	struct dwc_list_link *prev;
+} dwc_list_link_t;
+
+#define DWC_LIST_INIT(link) do {	\
+	(link)->next = (link);		\
+	(link)->prev = (link);		\
+} while (0)
+
+#define DWC_LIST_FIRST(link)	((link)->next)
+#define DWC_LIST_LAST(link)	((link)->prev)
+#define DWC_LIST_END(link)	(link)
+#define DWC_LIST_NEXT(link)	((link)->next)
+#define DWC_LIST_PREV(link)	((link)->prev)
+#define DWC_LIST_EMPTY(link)	\
+	(DWC_LIST_FIRST(link) == DWC_LIST_END(link))
+#define DWC_LIST_ENTRY(link, type, field)			\
+	(type *)((uint8_t *)(link) - (size_t)(&((type *)0)->field))
+
+#if 0
+#define DWC_LIST_INSERT_HEAD(list, link) do {			\
+	(link)->next = (list)->next;				\
+	(link)->prev = (list);					\
+	(list)->next->prev = (link);				\
+	(list)->next = (link);					\
+} while (0)
+
+#define DWC_LIST_INSERT_TAIL(list, link) do {			\
+	(link)->next = (list);					\
+	(link)->prev = (list)->prev;				\
+	(list)->prev->next = (link);				\
+	(list)->prev = (link);					\
+} while (0)
+#else
+#define DWC_LIST_INSERT_HEAD(list, link) do {			\
+	dwc_list_link_t *__next__ = (list)->next;		\
+	__next__->prev = (link);				\
+	(link)->next = __next__;				\
+	(link)->prev = (list);					\
+	(list)->next = (link);					\
+} while (0)
+
+#define DWC_LIST_INSERT_TAIL(list, link) do {			\
+	dwc_list_link_t *__prev__ = (list)->prev;		\
+	(list)->prev = (link);					\
+	(link)->next = (list);					\
+	(link)->prev = __prev__;				\
+	__prev__->next = (link);				\
+} while (0)
+#endif
+
+#if 0
+static inline void __list_add(struct list_head *new,
+                              struct list_head *prev,
+                              struct list_head *next)
+{
+        next->prev = new;
+        new->next = next;
+        new->prev = prev;
+        prev->next = new;
+}
+
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+        __list_add(new, head, head->next);
+}
+
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+        __list_add(new, head->prev, head);
+}
+
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+        next->prev = prev;
+        prev->next = next;
+}
+
+static inline void list_del(struct list_head *entry)
+{
+        __list_del(entry->prev, entry->next);
+        entry->next = LIST_POISON1;
+        entry->prev = LIST_POISON2;
+}
+#endif
+
+#define DWC_LIST_REMOVE(link) do {				\
+	(link)->next->prev = (link)->prev;			\
+	(link)->prev->next = (link)->next;			\
+} while (0)
+
+#define DWC_LIST_REMOVE_INIT(link) do {				\
+	DWC_LIST_REMOVE(link);					\
+	DWC_LIST_INIT(link);					\
+} while (0)
+
+#define DWC_LIST_MOVE_HEAD(list, link) do {			\
+	DWC_LIST_REMOVE(link);					\
+	DWC_LIST_INSERT_HEAD(list, link);			\
+} while (0)
+
+#define DWC_LIST_MOVE_TAIL(list, link) do {			\
+	DWC_LIST_REMOVE(link);					\
+	DWC_LIST_INSERT_TAIL(list, link);			\
+} while (0)
+
+#define DWC_LIST_FOREACH(var, list)				\
+	for((var) = DWC_LIST_FIRST(list);			\
+	    (var) != DWC_LIST_END(list);			\
+	    (var) = DWC_LIST_NEXT(var))
+
+#define DWC_LIST_FOREACH_SAFE(var, var2, list)			\
+	for((var) = DWC_LIST_FIRST(list), (var2) = DWC_LIST_NEXT(var);	\
+	    (var) != DWC_LIST_END(list);			\
+	    (var) = (var2), (var2) = DWC_LIST_NEXT(var2))
+
+#define DWC_LIST_FOREACH_REVERSE(var, list)			\
+	for((var) = DWC_LIST_LAST(list);			\
+	    (var) != DWC_LIST_END(list);			\
+	    (var) = DWC_LIST_PREV(var))
+
+/*
+ * Singly-linked List definitions.
+ */
+#define DWC_SLIST_HEAD(name, type)					\
+struct name {								\
+	struct type *slh_first;	/* first element */			\
+}
+
+#define DWC_SLIST_HEAD_INITIALIZER(head)				\
+	{ NULL }
+
+#define DWC_SLIST_ENTRY(type)						\
+struct {								\
+	struct type *sle_next;	/* next element */			\
+}
+
+/*
+ * Singly-linked List access methods.
+ */
+#define DWC_SLIST_FIRST(head)	((head)->slh_first)
+#define DWC_SLIST_END(head)		NULL
+#define DWC_SLIST_EMPTY(head)	(SLIST_FIRST(head) == SLIST_END(head))
+#define DWC_SLIST_NEXT(elm, field)	((elm)->field.sle_next)
+
+#define DWC_SLIST_FOREACH(var, head, field)				\
+	for((var) = SLIST_FIRST(head);					\
+	    (var) != SLIST_END(head);					\
+	    (var) = SLIST_NEXT(var, field))
+
+#define DWC_SLIST_FOREACH_PREVPTR(var, varp, head, field)		\
+	for((varp) = &SLIST_FIRST((head));				\
+	    ((var) = *(varp)) != SLIST_END(head);			\
+	    (varp) = &SLIST_NEXT((var), field))
+
+/*
+ * Singly-linked List functions.
+ */
+#define DWC_SLIST_INIT(head) {						\
+	SLIST_FIRST(head) = SLIST_END(head);				\
+}
+
+#define DWC_SLIST_INSERT_AFTER(slistelm, elm, field) do {		\
+	(elm)->field.sle_next = (slistelm)->field.sle_next;		\
+	(slistelm)->field.sle_next = (elm);				\
+} while (0)
+
+#define DWC_SLIST_INSERT_HEAD(head, elm, field) do {			\
+	(elm)->field.sle_next = (head)->slh_first;			\
+	(head)->slh_first = (elm);					\
+} while (0)
+
+#define DWC_SLIST_REMOVE_NEXT(head, elm, field) do {			\
+	(elm)->field.sle_next = (elm)->field.sle_next->field.sle_next;	\
+} while (0)
+
+#define DWC_SLIST_REMOVE_HEAD(head, field) do {				\
+	(head)->slh_first = (head)->slh_first->field.sle_next;		\
+} while (0)
+
+#define DWC_SLIST_REMOVE(head, elm, type, field) do {			\
+	if ((head)->slh_first == (elm)) {				\
+		SLIST_REMOVE_HEAD((head), field);			\
+	}								\
+	else {								\
+		struct type *curelm = (head)->slh_first;		\
+		while( curelm->field.sle_next != (elm) )		\
+			curelm = curelm->field.sle_next;		\
+		curelm->field.sle_next =				\
+		    curelm->field.sle_next->field.sle_next;		\
+	}								\
+} while (0)
+
+/*
+ * Simple queue definitions.
+ */
+#define DWC_SIMPLEQ_HEAD(name, type)					\
+struct name {								\
+	struct type *sqh_first;	/* first element */			\
+	struct type **sqh_last;	/* addr of last next element */		\
+}
+
+#define DWC_SIMPLEQ_HEAD_INITIALIZER(head)				\
+	{ NULL, &(head).sqh_first }
+
+#define DWC_SIMPLEQ_ENTRY(type)						\
+struct {								\
+	struct type *sqe_next;	/* next element */			\
+}
+
+/*
+ * Simple queue access methods.
+ */
+#define DWC_SIMPLEQ_FIRST(head)	    ((head)->sqh_first)
+#define DWC_SIMPLEQ_END(head)	    NULL
+#define DWC_SIMPLEQ_EMPTY(head)	    (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
+#define DWC_SIMPLEQ_NEXT(elm, field)    ((elm)->field.sqe_next)
+
+#define DWC_SIMPLEQ_FOREACH(var, head, field)				\
+	for((var) = SIMPLEQ_FIRST(head);				\
+	    (var) != SIMPLEQ_END(head);					\
+	    (var) = SIMPLEQ_NEXT(var, field))
+
+/*
+ * Simple queue functions.
+ */
+#define DWC_SIMPLEQ_INIT(head) do {					\
+	(head)->sqh_first = NULL;					\
+	(head)->sqh_last = &(head)->sqh_first;				\
+} while (0)
+
+#define DWC_SIMPLEQ_INSERT_HEAD(head, elm, field) do {			\
+	if (((elm)->field.sqe_next = (head)->sqh_first) == NULL)	\
+		(head)->sqh_last = &(elm)->field.sqe_next;		\
+	(head)->sqh_first = (elm);					\
+} while (0)
+
+#define DWC_SIMPLEQ_INSERT_TAIL(head, elm, field) do {			\
+	(elm)->field.sqe_next = NULL;					\
+	*(head)->sqh_last = (elm);					\
+	(head)->sqh_last = &(elm)->field.sqe_next;			\
+} while (0)
+
+#define DWC_SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {	\
+	if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+		(head)->sqh_last = &(elm)->field.sqe_next;		\
+	(listelm)->field.sqe_next = (elm);				\
+} while (0)
+
+#define DWC_SIMPLEQ_REMOVE_HEAD(head, field) do {			\
+	if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
+		(head)->sqh_last = &(head)->sqh_first;			\
+} while (0)
+
+/*
+ * Tail queue definitions.
+ */
+#define DWC_TAILQ_HEAD(name, type)					\
+struct name {								\
+	struct type *tqh_first;	/* first element */			\
+	struct type **tqh_last;	/* addr of last next element */		\
+}
+
+#define DWC_TAILQ_HEAD_INITIALIZER(head)				\
+	{ NULL, &(head).tqh_first }
+
+#define DWC_TAILQ_ENTRY(type)						\
+struct {								\
+	struct type *tqe_next;	/* next element */			\
+	struct type **tqe_prev;	/* address of previous next element */	\
+}
+
+/*
+ * tail queue access methods
+ */
+#define DWC_TAILQ_FIRST(head)		((head)->tqh_first)
+#define DWC_TAILQ_END(head)		NULL
+#define DWC_TAILQ_NEXT(elm, field)	((elm)->field.tqe_next)
+#define DWC_TAILQ_LAST(head, headname)					\
+	(*(((struct headname *)((head)->tqh_last))->tqh_last))
+/* XXX */
+#define DWC_TAILQ_PREV(elm, headname, field)				\
+	(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+#define DWC_TAILQ_EMPTY(head)						\
+	(TAILQ_FIRST(head) == TAILQ_END(head))
+
+#define DWC_TAILQ_FOREACH(var, head, field)				\
+	for((var) = TAILQ_FIRST(head);					\
+	    (var) != TAILQ_END(head);					\
+	    (var) = TAILQ_NEXT(var, field))
+
+#define DWC_TAILQ_FOREACH_REVERSE(var, head, headname, field)		\
+	for((var) = TAILQ_LAST(head, headname);				\
+	    (var) != TAILQ_END(head);					\
+	    (var) = TAILQ_PREV(var, headname, field))
+
+/*
+ * Tail queue functions.
+ */
+#define DWC_TAILQ_INIT(head) do {					\
+	(head)->tqh_first = NULL;					\
+	(head)->tqh_last = &(head)->tqh_first;				\
+} while (0)
+
+#define DWC_TAILQ_INSERT_HEAD(head, elm, field) do {			\
+	if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)	\
+		(head)->tqh_first->field.tqe_prev =			\
+		    &(elm)->field.tqe_next;				\
+	else								\
+		(head)->tqh_last = &(elm)->field.tqe_next;		\
+	(head)->tqh_first = (elm);					\
+	(elm)->field.tqe_prev = &(head)->tqh_first;			\
+} while (0)
+
+#define DWC_TAILQ_INSERT_TAIL(head, elm, field) do {			\
+	(elm)->field.tqe_next = NULL;					\
+	(elm)->field.tqe_prev = (head)->tqh_last;			\
+	*(head)->tqh_last = (elm);					\
+	(head)->tqh_last = &(elm)->field.tqe_next;			\
+} while (0)
+
+#define DWC_TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+		(elm)->field.tqe_next->field.tqe_prev =			\
+		    &(elm)->field.tqe_next;				\
+	else								\
+		(head)->tqh_last = &(elm)->field.tqe_next;		\
+	(listelm)->field.tqe_next = (elm);				\
+	(elm)->field.tqe_prev = &(listelm)->field.tqe_next;		\
+} while (0)
+
+#define DWC_TAILQ_INSERT_BEFORE(listelm, elm, field) do {		\
+	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
+	(elm)->field.tqe_next = (listelm);				\
+	*(listelm)->field.tqe_prev = (elm);				\
+	(listelm)->field.tqe_prev = &(elm)->field.tqe_next;		\
+} while (0)
+
+#define DWC_TAILQ_REMOVE(head, elm, field) do {				\
+	if (((elm)->field.tqe_next) != NULL)				\
+		(elm)->field.tqe_next->field.tqe_prev =			\
+		    (elm)->field.tqe_prev;				\
+	else								\
+		(head)->tqh_last = (elm)->field.tqe_prev;		\
+	*(elm)->field.tqe_prev = (elm)->field.tqe_next;			\
+} while (0)
+
+#define DWC_TAILQ_REPLACE(head, elm, elm2, field) do {			\
+	if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL)	\
+		(elm2)->field.tqe_next->field.tqe_prev =		\
+		    &(elm2)->field.tqe_next;				\
+	else								\
+		(head)->tqh_last = &(elm2)->field.tqe_next;		\
+	(elm2)->field.tqe_prev = (elm)->field.tqe_prev;			\
+	*(elm2)->field.tqe_prev = (elm2);				\
+} while (0)
+
+/*
+ * Circular queue definitions.
+ */
+#define DWC_CIRCLEQ_HEAD(name, type)					\
+struct name {								\
+	struct type *cqh_first;		/* first element */		\
+	struct type *cqh_last;		/* last element */		\
+}
+
+#define DWC_CIRCLEQ_HEAD_INITIALIZER(head)				\
+	{ DWC_CIRCLEQ_END(&head), DWC_CIRCLEQ_END(&head) }
+
+#define DWC_CIRCLEQ_ENTRY(type)						\
+struct {								\
+	struct type *cqe_next;		/* next element */		\
+	struct type *cqe_prev;		/* previous element */		\
+}
+
+/*
+ * Circular queue access methods
+ */
+#define DWC_CIRCLEQ_FIRST(head)		((head)->cqh_first)
+#define DWC_CIRCLEQ_LAST(head)		((head)->cqh_last)
+#define DWC_CIRCLEQ_END(head)		((void *)(head))
+#define DWC_CIRCLEQ_NEXT(elm, field)	((elm)->field.cqe_next)
+#define DWC_CIRCLEQ_PREV(elm, field)	((elm)->field.cqe_prev)
+#define DWC_CIRCLEQ_EMPTY(head)						\
+	(DWC_CIRCLEQ_FIRST(head) == DWC_CIRCLEQ_END(head))
+
+#define DWC_CIRCLEQ_EMPTY_ENTRY(elm, field) (((elm)->field.cqe_next == NULL) && ((elm)->field.cqe_prev == NULL))
+
+#define DWC_CIRCLEQ_FOREACH(var, head, field)				\
+	for((var) = DWC_CIRCLEQ_FIRST(head);				\
+	    (var) != DWC_CIRCLEQ_END(head);				\
+	    (var) = DWC_CIRCLEQ_NEXT(var, field))
+
+#define DWC_CIRCLEQ_FOREACH_SAFE(var, var2, head, field)			\
+	for((var) = DWC_CIRCLEQ_FIRST(head), var2 = DWC_CIRCLEQ_NEXT(var, field); \
+	    (var) != DWC_CIRCLEQ_END(head);					\
+	    (var) = var2, var2 = DWC_CIRCLEQ_NEXT(var, field))
+
+#define DWC_CIRCLEQ_FOREACH_REVERSE(var, head, field)			\
+	for((var) = DWC_CIRCLEQ_LAST(head);				\
+	    (var) != DWC_CIRCLEQ_END(head);				\
+	    (var) = DWC_CIRCLEQ_PREV(var, field))
+
+/*
+ * Circular queue functions.
+ */
+#define DWC_CIRCLEQ_INIT(head) do {					\
+	(head)->cqh_first = DWC_CIRCLEQ_END(head);			\
+	(head)->cqh_last = DWC_CIRCLEQ_END(head);			\
+} while (0)
+
+#define DWC_CIRCLEQ_INIT_ENTRY(elm, field) do {				\
+	(elm)->field.cqe_next = NULL;					\
+	(elm)->field.cqe_prev = NULL;					\
+} while (0)
+
+#define DWC_CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do {	\
+	(elm)->field.cqe_next = (listelm)->field.cqe_next;		\
+	(elm)->field.cqe_prev = (listelm);				\
+	if ((listelm)->field.cqe_next == DWC_CIRCLEQ_END(head))		\
+		(head)->cqh_last = (elm);				\
+	else								\
+		(listelm)->field.cqe_next->field.cqe_prev = (elm);	\
+	(listelm)->field.cqe_next = (elm);				\
+} while (0)
+
+#define DWC_CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do {	\
+	(elm)->field.cqe_next = (listelm);				\
+	(elm)->field.cqe_prev = (listelm)->field.cqe_prev;		\
+	if ((listelm)->field.cqe_prev == DWC_CIRCLEQ_END(head))		\
+		(head)->cqh_first = (elm);				\
+	else								\
+		(listelm)->field.cqe_prev->field.cqe_next = (elm);	\
+	(listelm)->field.cqe_prev = (elm);				\
+} while (0)
+
+#define DWC_CIRCLEQ_INSERT_HEAD(head, elm, field) do {			\
+	(elm)->field.cqe_next = (head)->cqh_first;			\
+	(elm)->field.cqe_prev = DWC_CIRCLEQ_END(head);			\
+	if ((head)->cqh_last == DWC_CIRCLEQ_END(head))			\
+		(head)->cqh_last = (elm);				\
+	else								\
+		(head)->cqh_first->field.cqe_prev = (elm);		\
+	(head)->cqh_first = (elm);					\
+} while (0)
+
+#define DWC_CIRCLEQ_INSERT_TAIL(head, elm, field) do {			\
+	(elm)->field.cqe_next = DWC_CIRCLEQ_END(head);			\
+	(elm)->field.cqe_prev = (head)->cqh_last;			\
+	if ((head)->cqh_first == DWC_CIRCLEQ_END(head))			\
+		(head)->cqh_first = (elm);				\
+	else								\
+		(head)->cqh_last->field.cqe_next = (elm);		\
+	(head)->cqh_last = (elm);					\
+} while (0)
+
+#define DWC_CIRCLEQ_REMOVE(head, elm, field) do {			\
+	if ((elm)->field.cqe_next == DWC_CIRCLEQ_END(head))		\
+		(head)->cqh_last = (elm)->field.cqe_prev;		\
+	else								\
+		(elm)->field.cqe_next->field.cqe_prev =			\
+		    (elm)->field.cqe_prev;				\
+	if ((elm)->field.cqe_prev == DWC_CIRCLEQ_END(head))		\
+		(head)->cqh_first = (elm)->field.cqe_next;		\
+	else								\
+		(elm)->field.cqe_prev->field.cqe_next =			\
+		    (elm)->field.cqe_next;				\
+} while (0)
+
+#define DWC_CIRCLEQ_REMOVE_INIT(head, elm, field) do {			\
+	DWC_CIRCLEQ_REMOVE(head, elm, field);				\
+	DWC_CIRCLEQ_INIT_ENTRY(elm, field);				\
+} while (0)
+
+#define DWC_CIRCLEQ_REPLACE(head, elm, elm2, field) do {		\
+	if (((elm2)->field.cqe_next = (elm)->field.cqe_next) ==		\
+	    DWC_CIRCLEQ_END(head))					\
+		(head).cqh_last = (elm2);				\
+	else								\
+		(elm2)->field.cqe_next->field.cqe_prev = (elm2);	\
+	if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) ==		\
+	    DWC_CIRCLEQ_END(head))					\
+		(head).cqh_first = (elm2);				\
+	else								\
+		(elm2)->field.cqe_prev->field.cqe_next = (elm2);	\
+} while (0)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DWC_LIST_H_ */
diff --git a/drivers/usb/dwc_otg/dwc_mem.c b/drivers/usb/dwc_otg/dwc_mem.c
new file mode 100644
index 0000000..ad645ff
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_mem.c
@@ -0,0 +1,245 @@
+/* Memory Debugging */
+#ifdef DWC_DEBUG_MEMORY
+
+#include "dwc_os.h"
+#include "dwc_list.h"
+
+struct allocation {
+	void *addr;
+	void *ctx;
+	char *func;
+	int line;
+	uint32_t size;
+	int dma;
+	DWC_CIRCLEQ_ENTRY(allocation) entry;
+};
+
+DWC_CIRCLEQ_HEAD(allocation_queue, allocation);
+
+struct allocation_manager {
+	void *mem_ctx;
+	struct allocation_queue allocations;
+
+	/* statistics */
+	int num;
+	int num_freed;
+	int num_active;
+	uint32_t total;
+	uint32_t cur;
+	uint32_t max;
+};
+
+static struct allocation_manager *manager = NULL;
+
+static int add_allocation(void *ctx, uint32_t size, char const *func, int line, void *addr,
+			  int dma)
+{
+	struct allocation *a;
+
+	DWC_ASSERT(manager != NULL, "manager not allocated");
+
+	a = __DWC_ALLOC_ATOMIC(manager->mem_ctx, sizeof(*a));
+	if (!a) {
+		return -DWC_E_NO_MEMORY;
+	}
+
+	a->func = __DWC_ALLOC_ATOMIC(manager->mem_ctx, DWC_STRLEN(func) + 1);
+	if (!a->func) {
+		__DWC_FREE(manager->mem_ctx, a);
+		return -DWC_E_NO_MEMORY;
+	}
+
+	DWC_MEMCPY(a->func, func, DWC_STRLEN(func) + 1);
+	a->addr = addr;
+	a->ctx = ctx;
+	a->line = line;
+	a->size = size;
+	a->dma = dma;
+	DWC_CIRCLEQ_INSERT_TAIL(&manager->allocations, a, entry);
+
+	/* Update stats */
+	manager->num++;
+	manager->num_active++;
+	manager->total += size;
+	manager->cur += size;
+
+	if (manager->max < manager->cur) {
+		manager->max = manager->cur;
+	}
+
+	return 0;
+}
+
+static struct allocation *find_allocation(void *ctx, void *addr)
+{
+	struct allocation *a;
+
+	DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
+		if (a->ctx == ctx && a->addr == addr) {
+			return a;
+		}
+	}
+
+	return NULL;
+}
+
+static void free_allocation(void *ctx, void *addr, char const *func, int line)
+{
+	struct allocation *a = find_allocation(ctx, addr);
+
+	if (!a) {
+		DWC_ASSERT(0,
+			   "Free of address %p that was never allocated or already freed %s:%d",
+			   addr, func, line);
+		return;
+	}
+
+	DWC_CIRCLEQ_REMOVE(&manager->allocations, a, entry);
+
+	manager->num_active--;
+	manager->num_freed++;
+	manager->cur -= a->size;
+	__DWC_FREE(manager->mem_ctx, a->func);
+	__DWC_FREE(manager->mem_ctx, a);
+}
+
+int dwc_memory_debug_start(void *mem_ctx)
+{
+	DWC_ASSERT(manager == NULL, "Memory debugging has already started\n");
+
+	if (manager) {
+		return -DWC_E_BUSY;
+	}
+
+	manager = __DWC_ALLOC(mem_ctx, sizeof(*manager));
+	if (!manager) {
+		return -DWC_E_NO_MEMORY;
+	}
+
+	DWC_CIRCLEQ_INIT(&manager->allocations);
+	manager->mem_ctx = mem_ctx;
+	manager->num = 0;
+	manager->num_freed = 0;
+	manager->num_active = 0;
+	manager->total = 0;
+	manager->cur = 0;
+	manager->max = 0;
+
+	return 0;
+}
+
+void dwc_memory_debug_stop(void)
+{
+	struct allocation *a;
+
+	dwc_memory_debug_report();
+
+	DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
+		DWC_ERROR("Memory leaked from %s:%d\n", a->func, a->line);
+		free_allocation(a->ctx, a->addr, NULL, -1);
+	}
+
+	__DWC_FREE(manager->mem_ctx, manager);
+}
+
+void dwc_memory_debug_report(void)
+{
+	struct allocation *a;
+
+	DWC_PRINTF("\n\n\n----------------- Memory Debugging Report -----------------\n\n");
+	DWC_PRINTF("Num Allocations = %d\n", manager->num);
+	DWC_PRINTF("Freed = %d\n", manager->num_freed);
+	DWC_PRINTF("Active = %d\n", manager->num_active);
+	DWC_PRINTF("Current Memory Used = %d\n", manager->cur);
+	DWC_PRINTF("Total Memory Used = %d\n", manager->total);
+	DWC_PRINTF("Maximum Memory Used at Once = %d\n", manager->max);
+	DWC_PRINTF("Unfreed allocations:\n");
+
+	DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
+		DWC_PRINTF("    addr=%p, size=%d from %s:%d, DMA=%d\n",
+			   a->addr, a->size, a->func, a->line, a->dma);
+	}
+}
+
+/* The replacement functions */
+void *dwc_alloc_debug(void *mem_ctx, uint32_t size, char const *func, int line)
+{
+	void *addr = __DWC_ALLOC(mem_ctx, size);
+
+	if (!addr) {
+		return NULL;
+	}
+
+	if (add_allocation(mem_ctx, size, func, line, addr, 0)) {
+		__DWC_FREE(mem_ctx, addr);
+		return NULL;
+	}
+
+	return addr;
+}
+
+void *dwc_alloc_atomic_debug(void *mem_ctx, uint32_t size, char const *func,
+			     int line)
+{
+	void *addr = __DWC_ALLOC_ATOMIC(mem_ctx, size);
+
+	if (!addr) {
+		return NULL;
+	}
+
+	if (add_allocation(mem_ctx, size, func, line, addr, 0)) {
+		__DWC_FREE(mem_ctx, addr);
+		return NULL;
+	}
+
+	return addr;
+}
+
+void dwc_free_debug(void *mem_ctx, void *addr, char const *func, int line)
+{
+	free_allocation(mem_ctx, addr, func, line);
+	__DWC_FREE(mem_ctx, addr);
+}
+
+void *dwc_dma_alloc_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
+			  char const *func, int line)
+{
+	void *addr = __DWC_DMA_ALLOC(dma_ctx, size, dma_addr);
+
+	if (!addr) {
+		return NULL;
+	}
+
+	if (add_allocation(dma_ctx, size, func, line, addr, 1)) {
+		__DWC_DMA_FREE(dma_ctx, size, addr, *dma_addr);
+		return NULL;
+	}
+
+	return addr;
+}
+
+void *dwc_dma_alloc_atomic_debug(void *dma_ctx, uint32_t size,
+				 dwc_dma_t *dma_addr, char const *func, int line)
+{
+	void *addr = __DWC_DMA_ALLOC_ATOMIC(dma_ctx, size, dma_addr);
+
+	if (!addr) {
+		return NULL;
+	}
+
+	if (add_allocation(dma_ctx, size, func, line, addr, 1)) {
+		__DWC_DMA_FREE(dma_ctx, size, addr, *dma_addr);
+		return NULL;
+	}
+
+	return addr;
+}
+
+void dwc_dma_free_debug(void *dma_ctx, uint32_t size, void *virt_addr,
+			dwc_dma_t dma_addr, char const *func, int line)
+{
+	free_allocation(dma_ctx, virt_addr, func, line);
+	__DWC_DMA_FREE(dma_ctx, size, virt_addr, dma_addr);
+}
+
+#endif /* DWC_DEBUG_MEMORY */
diff --git a/drivers/usb/dwc_otg/dwc_modpow.c b/drivers/usb/dwc_otg/dwc_modpow.c
new file mode 100644
index 0000000..f410f6e
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_modpow.c
@@ -0,0 +1,633 @@
+/* Bignum routines adapted from PUTTY sources.  PuTTY copyright notice follows.
+ *
+ * PuTTY is copyright 1997-2007 Simon Tatham.
+ *
+ * Portions copyright Robert de Bath, Joris van Rantwijk, Delian
+ * Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry,
+ * Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus
+ * Kuhn, and CORE SDI S.A.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
+ * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifdef DWC_CRYPTOLIB
+
+#ifndef CONFIG_MACH_IPMATE
+
+#include "dwc_modpow.h"
+
+#define BIGNUM_INT_MASK  0xFFFFFFFFUL
+#define BIGNUM_TOP_BIT   0x80000000UL
+#define BIGNUM_INT_BITS  32
+
+
+static void *snmalloc(void *mem_ctx, size_t n, size_t size)
+{
+    void *p;
+    size *= n;
+    if (size == 0) size = 1;
+    p = dwc_alloc(mem_ctx, size);
+    return p;
+}
+
+#define snewn(ctx, n, type) ((type *)snmalloc((ctx), (n), sizeof(type)))
+#define sfree dwc_free
+
+/*
+ * Usage notes:
+ *  * Do not call the DIVMOD_WORD macro with expressions such as array
+ *    subscripts, as some implementations object to this (see below).
+ *  * Note that none of the division methods below will cope if the
+ *    quotient won't fit into BIGNUM_INT_BITS. Callers should be careful
+ *    to avoid this case.
+ *    If this condition occurs, in the case of the x86 DIV instruction,
+ *    an overflow exception will occur, which (according to a correspondent)
+ *    will manifest on Windows as something like
+ *      0xC0000095: Integer overflow
+ *    The C variant won't give the right answer, either.
+ */
+
+#define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2)
+
+#if defined __GNUC__ && defined __i386__
+#define DIVMOD_WORD(q, r, hi, lo, w) \
+    __asm__("div %2" : \
+	    "=d" (r), "=a" (q) : \
+	    "r" (w), "d" (hi), "a" (lo))
+#else
+#define DIVMOD_WORD(q, r, hi, lo, w) do { \
+    BignumDblInt n = (((BignumDblInt)hi) << BIGNUM_INT_BITS) | lo; \
+    q = n / w; \
+    r = n % w; \
+} while (0)
+#endif
+
+#define BIGNUM_INT_BYTES (BIGNUM_INT_BITS / 8)
+
+#define BIGNUM_INTERNAL
+
+static Bignum newbn(void *mem_ctx, int length)
+{
+    Bignum b = snewn(mem_ctx, length + 1, BignumInt);
+    //if (!b)
+    //abort();		       /* FIXME */
+    DWC_MEMSET(b, 0, (length + 1) * sizeof(*b));
+    b[0] = length;
+    return b;
+}
+
+void freebn(void *mem_ctx, Bignum b)
+{
+    /*
+     * Burn the evidence, just in case.
+     */
+    DWC_MEMSET(b, 0, sizeof(b[0]) * (b[0] + 1));
+    sfree(mem_ctx, b);
+}
+
+/*
+ * Compute c = a * b.
+ * Input is in the first len words of a and b.
+ * Result is returned in the first 2*len words of c.
+ */
+static void internal_mul(BignumInt *a, BignumInt *b,
+			 BignumInt *c, int len)
+{
+    int i, j;
+    BignumDblInt t;
+
+    for (j = 0; j < 2 * len; j++)
+	c[j] = 0;
+
+    for (i = len - 1; i >= 0; i--) {
+	t = 0;
+	for (j = len - 1; j >= 0; j--) {
+	    t += MUL_WORD(a[i], (BignumDblInt) b[j]);
+	    t += (BignumDblInt) c[i + j + 1];
+	    c[i + j + 1] = (BignumInt) t;
+	    t = t >> BIGNUM_INT_BITS;
+	}
+	c[i] = (BignumInt) t;
+    }
+}
+
+static void internal_add_shifted(BignumInt *number,
+				 unsigned n, int shift)
+{
+    int word = 1 + (shift / BIGNUM_INT_BITS);
+    int bshift = shift % BIGNUM_INT_BITS;
+    BignumDblInt addend;
+
+    addend = (BignumDblInt)n << bshift;
+
+    while (addend) {
+	addend += number[word];
+	number[word] = (BignumInt) addend & BIGNUM_INT_MASK;
+	addend >>= BIGNUM_INT_BITS;
+	word++;
+    }
+}
+
+/*
+ * Compute a = a % m.
+ * Input in first alen words of a and first mlen words of m.
+ * Output in first alen words of a
+ * (of which first alen-mlen words will be zero).
+ * The MSW of m MUST have its high bit set.
+ * Quotient is accumulated in the `quotient' array, which is a Bignum
+ * rather than the internal bigendian format. Quotient parts are shifted
+ * left by `qshift' before adding into quot.
+ */
+static void internal_mod(BignumInt *a, int alen,
+			 BignumInt *m, int mlen,
+			 BignumInt *quot, int qshift)
+{
+    BignumInt m0, m1;
+    unsigned int h;
+    int i, k;
+
+    m0 = m[0];
+    if (mlen > 1)
+	m1 = m[1];
+    else
+	m1 = 0;
+
+    for (i = 0; i <= alen - mlen; i++) {
+	BignumDblInt t;
+	unsigned int q, r, c, ai1;
+
+	if (i == 0) {
+	    h = 0;
+	} else {
+	    h = a[i - 1];
+	    a[i - 1] = 0;
+	}
+
+	if (i == alen - 1)
+	    ai1 = 0;
+	else
+	    ai1 = a[i + 1];
+
+	/* Find q = h:a[i] / m0 */
+	if (h >= m0) {
+	    /*
+	     * Special case.
+	     * 
+	     * To illustrate it, suppose a BignumInt is 8 bits, and
+	     * we are dividing (say) A1:23:45:67 by A1:B2:C3. Then
+	     * our initial division will be 0xA123 / 0xA1, which
+	     * will give a quotient of 0x100 and a divide overflow.
+	     * However, the invariants in this division algorithm
+	     * are not violated, since the full number A1:23:... is
+	     * _less_ than the quotient prefix A1:B2:... and so the
+	     * following correction loop would have sorted it out.
+	     * 
+	     * In this situation we set q to be the largest
+	     * quotient we _can_ stomach (0xFF, of course).
+	     */
+	    q = BIGNUM_INT_MASK;
+	} else {
+	    /* Macro doesn't want an array subscript expression passed
+	     * into it (see definition), so use a temporary. */
+	    BignumInt tmplo = a[i];
+	    DIVMOD_WORD(q, r, h, tmplo, m0);
+
+	    /* Refine our estimate of q by looking at
+	     h:a[i]:a[i+1] / m0:m1 */
+	    t = MUL_WORD(m1, q);
+	    if (t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) {
+		q--;
+		t -= m1;
+		r = (r + m0) & BIGNUM_INT_MASK;     /* overflow? */
+		if (r >= (BignumDblInt) m0 &&
+		    t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) q--;
+	    }
+	}
+
+	/* Subtract q * m from a[i...] */
+	c = 0;
+	for (k = mlen - 1; k >= 0; k--) {
+	    t = MUL_WORD(q, m[k]);
+	    t += c;
+	    c = (unsigned)(t >> BIGNUM_INT_BITS);
+	    if ((BignumInt) t > a[i + k])
+		c++;
+	    a[i + k] -= (BignumInt) t;
+	}
+
+	/* Add back m in case of borrow */
+	if (c != h) {
+	    t = 0;
+	    for (k = mlen - 1; k >= 0; k--) {
+		t += m[k];
+		t += a[i + k];
+		a[i + k] = (BignumInt) t;
+		t = t >> BIGNUM_INT_BITS;
+	    }
+	    q--;
+	}
+	if (quot)
+	    internal_add_shifted(quot, q, qshift + BIGNUM_INT_BITS * (alen - mlen - i));
+    }
+}
+
+/*
+ * Compute p % mod.
+ * The most significant word of mod MUST be non-zero.
+ * We assume that the result array is the same size as the mod array.
+ * We optionally write out a quotient if `quotient' is non-NULL.
+ * We can avoid writing out the result if `result' is NULL.
+ */
+void bigdivmod(void *mem_ctx, Bignum p, Bignum mod, Bignum result, Bignum quotient)
+{
+    BignumInt *n, *m;
+    int mshift;
+    int plen, mlen, i, j;
+
+    /* Allocate m of size mlen, copy mod to m */
+    /* We use big endian internally */
+    mlen = mod[0];
+    m = snewn(mem_ctx, mlen, BignumInt);
+    //if (!m)
+    //abort();		       /* FIXME */
+    for (j = 0; j < mlen; j++)
+	m[j] = mod[mod[0] - j];
+
+    /* Shift m left to make msb bit set */
+    for (mshift = 0; mshift < BIGNUM_INT_BITS-1; mshift++)
+	if ((m[0] << mshift) & BIGNUM_TOP_BIT)
+	    break;
+    if (mshift) {
+	for (i = 0; i < mlen - 1; i++)
+	    m[i] = (m[i] << mshift) | (m[i + 1] >> (BIGNUM_INT_BITS - mshift));
+	m[mlen - 1] = m[mlen - 1] << mshift;
+    }
+
+    plen = p[0];
+    /* Ensure plen > mlen */
+    if (plen <= mlen)
+	plen = mlen + 1;
+
+    /* Allocate n of size plen, copy p to n */
+    n = snewn(mem_ctx, plen, BignumInt);
+    //if (!n)
+    //abort();		       /* FIXME */
+    for (j = 0; j < plen; j++)
+	n[j] = 0;
+    for (j = 1; j <= (int)p[0]; j++)
+	n[plen - j] = p[j];
+
+    /* Main computation */
+    internal_mod(n, plen, m, mlen, quotient, mshift);
+
+    /* Fixup result in case the modulus was shifted */
+    if (mshift) {
+	for (i = plen - mlen - 1; i < plen - 1; i++)
+	    n[i] = (n[i] << mshift) | (n[i + 1] >> (BIGNUM_INT_BITS - mshift));
+	n[plen - 1] = n[plen - 1] << mshift;
+	internal_mod(n, plen, m, mlen, quotient, 0);
+	for (i = plen - 1; i >= plen - mlen; i--)
+	    n[i] = (n[i] >> mshift) | (n[i - 1] << (BIGNUM_INT_BITS - mshift));
+    }
+
+    /* Copy result to buffer */
+    if (result) {
+	for (i = 1; i <= (int)result[0]; i++) {
+	    int j = plen - i;
+	    result[i] = j >= 0 ? n[j] : 0;
+	}
+    }
+
+    /* Free temporary arrays */
+    for (i = 0; i < mlen; i++)
+	m[i] = 0;
+    sfree(mem_ctx, m);
+    for (i = 0; i < plen; i++)
+	n[i] = 0;
+    sfree(mem_ctx, n);
+}
+
+/*
+ * Simple remainder.
+ */
+Bignum bigmod(void *mem_ctx, Bignum a, Bignum b)
+{
+    Bignum r = newbn(mem_ctx, b[0]);
+    bigdivmod(mem_ctx, a, b, r, NULL);
+    return r;
+}
+
+/*
+ * Compute (base ^ exp) % mod.
+ */
+Bignum dwc_modpow(void *mem_ctx, Bignum base_in, Bignum exp, Bignum mod)
+{
+    BignumInt *a, *b, *n, *m;
+    int mshift;
+    int mlen, i, j;
+    Bignum base, result;
+
+    /*
+     * The most significant word of mod needs to be non-zero. It
+     * should already be, but let's make sure.
+     */
+    //assert(mod[mod[0]] != 0);
+
+    /*
+     * Make sure the base is smaller than the modulus, by reducing
+     * it modulo the modulus if not.
+     */
+    base = bigmod(mem_ctx, base_in, mod);
+
+    /* Allocate m of size mlen, copy mod to m */
+    /* We use big endian internally */
+    mlen = mod[0];
+    m = snewn(mem_ctx, mlen, BignumInt);
+    //if (!m)
+    //abort();		       /* FIXME */
+    for (j = 0; j < mlen; j++)
+	m[j] = mod[mod[0] - j];
+
+    /* Shift m left to make msb bit set */
+    for (mshift = 0; mshift < BIGNUM_INT_BITS - 1; mshift++)
+	if ((m[0] << mshift) & BIGNUM_TOP_BIT)
+	    break;
+    if (mshift) {
+	for (i = 0; i < mlen - 1; i++)
+	    m[i] =
+		(m[i] << mshift) | (m[i + 1] >>
+				    (BIGNUM_INT_BITS - mshift));
+	m[mlen - 1] = m[mlen - 1] << mshift;
+    }
+
+    /* Allocate n of size mlen, copy base to n */
+    n = snewn(mem_ctx, mlen, BignumInt);
+    //if (!n)
+    //abort();		       /* FIXME */
+    i = mlen - base[0];
+    for (j = 0; j < i; j++)
+	n[j] = 0;
+    for (j = 0; j < base[0]; j++)
+	n[i + j] = base[base[0] - j];
+
+    /* Allocate a and b of size 2*mlen. Set a = 1 */
+    a = snewn(mem_ctx, 2 * mlen, BignumInt);
+    //if (!a)
+    //abort();		       /* FIXME */
+    b = snewn(mem_ctx, 2 * mlen, BignumInt);
+    //if (!b)
+    //abort();		       /* FIXME */
+    for (i = 0; i < 2 * mlen; i++)
+	a[i] = 0;
+    a[2 * mlen - 1] = 1;
+
+    /* Skip leading zero bits of exp. */
+    i = 0;
+    j = BIGNUM_INT_BITS - 1;
+    while (i < exp[0] && (exp[exp[0] - i] & (1 << j)) == 0) {
+	j--;
+	if (j < 0) {
+	    i++;
+	    j = BIGNUM_INT_BITS - 1;
+	}
+    }
+
+    /* Main computation */
+    while (i < exp[0]) {
+	while (j >= 0) {
+	    internal_mul(a + mlen, a + mlen, b, mlen);
+	    internal_mod(b, mlen * 2, m, mlen, NULL, 0);
+	    if ((exp[exp[0] - i] & (1 << j)) != 0) {
+		internal_mul(b + mlen, n, a, mlen);
+		internal_mod(a, mlen * 2, m, mlen, NULL, 0);
+	    } else {
+		BignumInt *t;
+		t = a;
+		a = b;
+		b = t;
+	    }
+	    j--;
+	}
+	i++;
+	j = BIGNUM_INT_BITS - 1;
+    }
+
+    /* Fixup result in case the modulus was shifted */
+    if (mshift) {
+	for (i = mlen - 1; i < 2 * mlen - 1; i++)
+	    a[i] =
+		(a[i] << mshift) | (a[i + 1] >>
+				    (BIGNUM_INT_BITS - mshift));
+	a[2 * mlen - 1] = a[2 * mlen - 1] << mshift;
+	internal_mod(a, mlen * 2, m, mlen, NULL, 0);
+	for (i = 2 * mlen - 1; i >= mlen; i--)
+	    a[i] =
+		(a[i] >> mshift) | (a[i - 1] <<
+				    (BIGNUM_INT_BITS - mshift));
+    }
+
+    /* Copy result to buffer */
+    result = newbn(mem_ctx, mod[0]);
+    for (i = 0; i < mlen; i++)
+	result[result[0] - i] = a[i + mlen];
+    while (result[0] > 1 && result[result[0]] == 0)
+	result[0]--;
+
+    /* Free temporary arrays */
+    for (i = 0; i < 2 * mlen; i++)
+	a[i] = 0;
+    sfree(mem_ctx, a);
+    for (i = 0; i < 2 * mlen; i++)
+	b[i] = 0;
+    sfree(mem_ctx, b);
+    for (i = 0; i < mlen; i++)
+	m[i] = 0;
+    sfree(mem_ctx, m);
+    for (i = 0; i < mlen; i++)
+	n[i] = 0;
+    sfree(mem_ctx, n);
+
+    freebn(mem_ctx, base);
+
+    return result;
+}
+
+
+#ifdef UNITTEST
+
+static __u32 dh_p[] = {
+	96,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+	0xA93AD2CA,
+	0x4B82D120,
+	0xE0FD108E,
+	0x43DB5BFC,
+	0x74E5AB31,
+	0x08E24FA0,
+	0xBAD946E2,
+	0x770988C0,
+	0x7A615D6C,
+	0xBBE11757,
+	0x177B200C,
+	0x521F2B18,
+	0x3EC86A64,
+	0xD8760273,
+	0xD98A0864,
+	0xF12FFA06,
+	0x1AD2EE6B,
+	0xCEE3D226,
+	0x4A25619D,
+	0x1E8C94E0,
+	0xDB0933D7,
+	0xABF5AE8C,
+	0xA6E1E4C7,
+	0xB3970F85,
+	0x5D060C7D,
+	0x8AEA7157,
+	0x58DBEF0A,
+	0xECFB8504,
+	0xDF1CBA64,
+	0xA85521AB,
+	0x04507A33,
+	0xAD33170D,
+	0x8AAAC42D,
+	0x15728E5A,
+	0x98FA0510,
+	0x15D22618,
+	0xEA956AE5,
+	0x3995497C,
+	0x95581718,
+	0xDE2BCBF6,
+	0x6F4C52C9,
+	0xB5C55DF0,
+	0xEC07A28F,
+	0x9B2783A2,
+	0x180E8603,
+	0xE39E772C,
+	0x2E36CE3B,
+	0x32905E46,
+	0xCA18217C,
+	0xF1746C08,
+	0x4ABC9804,
+	0x670C354E,
+	0x7096966D,
+	0x9ED52907,
+	0x208552BB,
+	0x1C62F356,
+	0xDCA3AD96,
+	0x83655D23,
+	0xFD24CF5F,
+	0x69163FA8,
+	0x1C55D39A,
+	0x98DA4836,
+	0xA163BF05,
+	0xC2007CB8,
+	0xECE45B3D,
+	0x49286651,
+	0x7C4B1FE6,
+	0xAE9F2411,
+	0x5A899FA5,
+	0xEE386BFB,
+	0xF406B7ED,
+	0x0BFF5CB6,
+	0xA637ED6B,
+	0xF44C42E9,
+	0x625E7EC6,
+	0xE485B576,
+	0x6D51C245,
+	0x4FE1356D,
+	0xF25F1437,
+	0x302B0A6D,
+	0xCD3A431B,
+	0xEF9519B3,
+	0x8E3404DD,
+	0x514A0879,
+	0x3B139B22,
+	0x020BBEA6,
+	0x8A67CC74,
+	0x29024E08,
+	0x80DC1CD1,
+	0xC4C6628B,
+	0x2168C234,
+	0xC90FDAA2,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+};
+
+static __u32 dh_a[] = {
+	8,
+	0xdf367516,
+	0x86459caa,
+	0xe2d459a4,
+	0xd910dae0,
+	0x8a8b5e37,
+	0x67ab31c6,
+	0xf0b55ea9,
+	0x440051d6,
+};
+
+static __u32 dh_b[] = {
+	8,
+	0xded92656,
+	0xe07a048a,
+	0x6fa452cd,
+	0x2df89d30,
+	0xc75f1b0f,
+	0x8ce3578f, 
+	0x7980a324,
+	0x5daec786,
+};
+
+static __u32 dh_g[] = {
+	1,
+	2,
+};
+
+int main(void)
+{
+	int i;
+	__u32 *k;
+	k = dwc_modpow(NULL, dh_g, dh_a, dh_p);
+
+	printf("\n\n");
+	for (i=0; i<k[0]; i++) {
+		__u32 word32 = k[k[0] - i];
+		__u16 l = word32 & 0xffff;
+		__u16 m = (word32 & 0xffff0000) >> 16;
+		printf("%04x %04x ", m, l);
+		if (!((i + 1)%13)) printf("\n");
+	}
+	printf("\n\n");
+
+	if ((k[0] == 0x60) && (k[1] == 0x28e490e5) && (k[0x60] == 0x5a0d3d4e)) {
+		printf("PASS\n\n");
+	}
+	else {
+		printf("FAIL\n\n");
+	}
+
+}
+
+#endif /* UNITTEST */
+
+#endif /* CONFIG_MACH_IPMATE */
+
+#endif /*DWC_CRYPTOLIB */
diff --git a/drivers/usb/dwc_otg/dwc_modpow.h b/drivers/usb/dwc_otg/dwc_modpow.h
new file mode 100644
index 0000000..64f00c2
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_modpow.h
@@ -0,0 +1,34 @@
+/*
+ * dwc_modpow.h
+ * See dwc_modpow.c for license and changes
+ */
+#ifndef _DWC_MODPOW_H
+#define _DWC_MODPOW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "dwc_os.h"
+
+/** @file
+ *
+ * This file defines the module exponentiation function which is only used
+ * internally by the DWC UWB modules for calculation of PKs during numeric
+ * association.  The routine is taken from the PUTTY, an open source terminal
+ * emulator.  The PUTTY License is preserved in the dwc_modpow.c file.
+ *
+ */
+
+typedef uint32_t BignumInt;
+typedef uint64_t BignumDblInt;
+typedef BignumInt *Bignum;
+
+/* Compute modular exponentiaion */
+extern Bignum dwc_modpow(void *mem_ctx, Bignum base_in, Bignum exp, Bignum mod);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LINUX_BIGNUM_H */
diff --git a/drivers/usb/dwc_otg/dwc_notifier.c b/drivers/usb/dwc_otg/dwc_notifier.c
new file mode 100644
index 0000000..d3dadce
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_notifier.c
@@ -0,0 +1,319 @@
+#ifdef DWC_NOTIFYLIB
+
+#include "dwc_notifier.h"
+#include "dwc_list.h"
+
+typedef struct dwc_observer {
+	void *observer;
+	dwc_notifier_callback_t callback;
+	void *data;
+	char *notification;
+	DWC_CIRCLEQ_ENTRY(dwc_observer) list_entry;
+} observer_t;
+
+DWC_CIRCLEQ_HEAD(observer_queue, dwc_observer);
+
+typedef struct dwc_notifier {
+	void *mem_ctx;
+	void *object;
+	struct observer_queue observers;
+	DWC_CIRCLEQ_ENTRY(dwc_notifier) list_entry;
+} notifier_t;
+
+DWC_CIRCLEQ_HEAD(notifier_queue, dwc_notifier);
+
+typedef struct manager {
+	void *mem_ctx;
+	void *wkq_ctx;
+	dwc_workq_t *wq;
+//	dwc_mutex_t *mutex;
+	struct notifier_queue notifiers;
+} manager_t;
+
+static manager_t *manager = NULL;
+
+static int create_manager(void *mem_ctx, void *wkq_ctx)
+{
+	manager = dwc_alloc(mem_ctx, sizeof(manager_t));
+	if (!manager) {
+		return -DWC_E_NO_MEMORY;
+	}
+
+	DWC_CIRCLEQ_INIT(&manager->notifiers);
+
+	manager->wq = dwc_workq_alloc(wkq_ctx, "DWC Notification WorkQ");
+	if (!manager->wq) {
+		return -DWC_E_NO_MEMORY;
+	}
+
+	return 0;
+}
+
+static void free_manager(void)
+{
+	dwc_workq_free(manager->wq);
+
+	/* All notifiers must have unregistered themselves before this module
+	 * can be removed.  Hitting this assertion indicates a programmer
+	 * error. */
+	DWC_ASSERT(DWC_CIRCLEQ_EMPTY(&manager->notifiers),
+		   "Notification manager being freed before all notifiers have been removed");
+	dwc_free(manager->mem_ctx, manager);
+}
+
+#ifdef DEBUG
+static void dump_manager(void)
+{
+	notifier_t *n;
+	observer_t *o;
+
+	DWC_ASSERT(manager, "Notification manager not found");
+
+	DWC_DEBUG("List of all notifiers and observers:\n");
+	DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) {
+		DWC_DEBUG("Notifier %p has observers:\n", n->object);
+		DWC_CIRCLEQ_FOREACH(o, &n->observers, list_entry) {
+			DWC_DEBUG("    %p watching %s\n", o->observer, o->notification);
+		}
+	}
+}
+#else
+#define dump_manager(...)
+#endif
+
+static observer_t *alloc_observer(void *mem_ctx, void *observer, char *notification,
+				  dwc_notifier_callback_t callback, void *data)
+{
+	observer_t *new_observer = dwc_alloc(mem_ctx, sizeof(observer_t));
+
+	if (!new_observer) {
+		return NULL;
+	}
+
+	DWC_CIRCLEQ_INIT_ENTRY(new_observer, list_entry);
+	new_observer->observer = observer;
+	new_observer->notification = notification;
+	new_observer->callback = callback;
+	new_observer->data = data;
+	return new_observer;
+}
+
+static void free_observer(void *mem_ctx, observer_t *observer)
+{
+	dwc_free(mem_ctx, observer);
+}
+
+static notifier_t *alloc_notifier(void *mem_ctx, void *object)
+{
+	notifier_t *notifier;
+
+	if (!object) {
+		return NULL;
+	}
+
+	notifier = dwc_alloc(mem_ctx, sizeof(notifier_t));
+	if (!notifier) {
+		return NULL;
+	}
+
+	DWC_CIRCLEQ_INIT(&notifier->observers);
+	DWC_CIRCLEQ_INIT_ENTRY(notifier, list_entry);
+
+	notifier->mem_ctx = mem_ctx;
+	notifier->object = object;
+	return notifier;
+}
+
+static void free_notifier(notifier_t *notifier)
+{
+	observer_t *observer;
+
+	DWC_CIRCLEQ_FOREACH(observer, &notifier->observers, list_entry) {
+		free_observer(notifier->mem_ctx, observer);
+	}
+
+	dwc_free(notifier->mem_ctx, notifier);
+}
+
+static notifier_t *find_notifier(void *object)
+{
+	notifier_t *notifier;
+
+	DWC_ASSERT(manager, "Notification manager not found");
+
+	if (!object) {
+		return NULL;
+	}
+
+	DWC_CIRCLEQ_FOREACH(notifier, &manager->notifiers, list_entry) {
+		if (notifier->object == object) {
+			return notifier;
+		}
+	}
+
+	return NULL;
+}
+
+int dwc_alloc_notification_manager(void *mem_ctx, void *wkq_ctx)
+{
+	return create_manager(mem_ctx, wkq_ctx);
+}
+
+void dwc_free_notification_manager(void)
+{
+	free_manager();
+}
+
+dwc_notifier_t *dwc_register_notifier(void *mem_ctx, void *object)
+{
+	notifier_t *notifier;
+
+	DWC_ASSERT(manager, "Notification manager not found");
+
+	notifier = find_notifier(object);
+	if (notifier) {
+		DWC_ERROR("Notifier %p is already registered\n", object);
+		return NULL;
+	}
+
+	notifier = alloc_notifier(mem_ctx, object);
+	if (!notifier) {
+		return NULL;
+	}
+
+	DWC_CIRCLEQ_INSERT_TAIL(&manager->notifiers, notifier, list_entry);
+
+	DWC_INFO("Notifier %p registered", object);
+	dump_manager();
+
+	return notifier;
+}
+
+void dwc_unregister_notifier(dwc_notifier_t *notifier)
+{
+	DWC_ASSERT(manager, "Notification manager not found");
+
+	if (!DWC_CIRCLEQ_EMPTY(&notifier->observers)) {
+		observer_t *o;
+
+		DWC_ERROR("Notifier %p has active observers when removing\n", notifier->object);
+		DWC_CIRCLEQ_FOREACH(o, &notifier->observers, list_entry) {
+			DWC_DEBUG("    %p watching %s\n", o->observer, o->notification);
+		}
+
+		DWC_ASSERT(DWC_CIRCLEQ_EMPTY(&notifier->observers),
+			   "Notifier %p has active observers when removing", notifier);
+	}
+
+	DWC_CIRCLEQ_REMOVE_INIT(&manager->notifiers, notifier, list_entry);
+	free_notifier(notifier);
+
+	DWC_INFO("Notifier unregistered");
+	dump_manager();
+}
+
+/* Add an observer to observe the notifier for a particular state, event, or notification. */
+int dwc_add_observer(void *observer, void *object, char *notification,
+		     dwc_notifier_callback_t callback, void *data)
+{
+	notifier_t *notifier = find_notifier(object);
+	observer_t *new_observer;
+
+	if (!notifier) {
+		DWC_ERROR("Notifier %p is not found when adding observer\n", object);
+		return -DWC_E_INVALID;
+	}
+
+	new_observer = alloc_observer(notifier->mem_ctx, observer, notification, callback, data);
+	if (!new_observer) {
+		return -DWC_E_NO_MEMORY;
+	}
+
+	DWC_CIRCLEQ_INSERT_TAIL(&notifier->observers, new_observer, list_entry);
+
+	DWC_INFO("Added observer %p to notifier %p observing notification %s, callback=%p, data=%p",
+		 observer, object, notification, callback, data);
+
+	dump_manager();
+	return 0;
+}
+
+int dwc_remove_observer(void *observer)
+{
+	notifier_t *n;
+
+	DWC_ASSERT(manager, "Notification manager not found");
+
+	DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) {
+		observer_t *o;
+		observer_t *o2;
+
+		DWC_CIRCLEQ_FOREACH_SAFE(o, o2, &n->observers, list_entry) {
+			if (o->observer == observer) {
+				DWC_CIRCLEQ_REMOVE_INIT(&n->observers, o, list_entry);
+				DWC_INFO("Removing observer %p from notifier %p watching notification %s:",
+					 o->observer, n->object, o->notification);
+				free_observer(n->mem_ctx, o);
+			}
+		}
+	}
+
+	dump_manager();
+	return 0;
+}
+
+typedef struct callback_data {
+	void *mem_ctx;
+	dwc_notifier_callback_t cb;
+	void *observer;
+	void *data;
+	void *object;
+	char *notification;
+	void *notification_data;
+} cb_data_t;
+
+static void cb_task(void *data)
+{
+	cb_data_t *cb = (cb_data_t *)data;
+
+	cb->cb(cb->object, cb->notification, cb->observer, cb->notification_data, cb->data);
+	dwc_free(cb->mem_ctx, cb);
+}
+
+void dwc_notify(dwc_notifier_t *notifier, char *notification, void *notification_data)
+{
+	observer_t *o;
+
+	DWC_ASSERT(manager, "Notification manager not found");
+
+	DWC_CIRCLEQ_FOREACH(o, &notifier->observers, list_entry) {
+		int len = DWC_STRLEN(notification);
+
+		if (DWC_STRLEN(o->notification) != len) {
+			continue;
+		}
+
+		if (DWC_STRNCMP(o->notification, notification, len) == 0) {
+			cb_data_t *cb_data = dwc_alloc(notifier->mem_ctx, sizeof(cb_data_t));
+
+			if (!cb_data) {
+				DWC_ERROR("Failed to allocate callback data\n");
+				return;
+			}
+
+			cb_data->mem_ctx = notifier->mem_ctx;
+			cb_data->cb = o->callback;
+			cb_data->observer = o->observer;
+			cb_data->data = o->data;
+			cb_data->object = notifier->object;
+			cb_data->notification = notification;
+			cb_data->notification_data = notification_data;
+			DWC_DEBUG("Observer found %p for notification %s\n", o->observer, notification);
+			DWC_WORKQ_SCHEDULE(manager->wq, cb_task, cb_data,
+					   "Notify callback from %p for Notification %s, to observer %p",
+					   cb_data->object, notification, cb_data->observer);
+		}
+	}
+}
+
+#endif	/* DWC_NOTIFYLIB */
diff --git a/drivers/usb/dwc_otg/dwc_notifier.h b/drivers/usb/dwc_otg/dwc_notifier.h
new file mode 100644
index 0000000..4a8cdfe
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_notifier.h
@@ -0,0 +1,122 @@
+
+#ifndef __DWC_NOTIFIER_H__
+#define __DWC_NOTIFIER_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "dwc_os.h"
+
+/** @file
+ *
+ * A simple implementation of the Observer pattern.  Any "module" can
+ * register as an observer or notifier.  The notion of "module" is abstract and
+ * can mean anything used to identify either an observer or notifier.  Usually
+ * it will be a pointer to a data structure which contains some state, ie an
+ * object.
+ *
+ * Before any notifiers can be added, the global notification manager must be
+ * brought up with dwc_alloc_notification_manager().
+ * dwc_free_notification_manager() will bring it down and free all resources.
+ * These would typically be called upon module load and unload.  The
+ * notification manager is a single global instance that handles all registered
+ * observable modules and observers so this should be done only once.
+ *
+ * A module can be observable by using Notifications to publicize some general
+ * information about it's state or operation.  It does not care who listens, or
+ * even if anyone listens, or what they do with the information.  The observable
+ * modules do not need to know any information about it's observers or their
+ * interface, or their state or data.
+ *
+ * Any module can register to emit Notifications.  It should publish a list of
+ * notifications that it can emit and their behavior, such as when they will get
+ * triggered, and what information will be provided to the observer.  Then it
+ * should register itself as an observable module. See dwc_register_notifier().
+ *
+ * Any module can observe any observable, registered module, provided it has a
+ * handle to the other module and knows what notifications to observe.  See
+ * dwc_add_observer().
+ *
+ * A function of type dwc_notifier_callback_t is called whenever a notification
+ * is triggered with one or more observers observing it.  This function is
+ * called in it's own process so it may sleep or block if needed.  It is
+ * guaranteed to be called sometime after the notification has occurred and will
+ * be called once per each time the notification is triggered.  It will NOT be
+ * called in the same process context used to trigger the notification.
+ *
+ * @section Limitiations
+ *
+ * Keep in mind that Notifications that can be triggered in rapid sucession may
+ * schedule too many processes too handle.  Be aware of this limitation when
+ * designing to use notifications, and only add notifications for appropriate
+ * observable information.
+ *
+ * Also Notification callbacks are not synchronous.  If you need to synchronize
+ * the behavior between module/observer you must use other means.  And perhaps
+ * that will mean Notifications are not the proper solution.
+ */
+
+struct dwc_notifier;
+typedef struct dwc_notifier dwc_notifier_t;
+
+/** The callback function must be of this type.
+ *
+ * @param object This is the object that is being observed.
+ * @param notification This is the notification that was triggered.
+ * @param observer This is the observer
+ * @param notification_data This is notification-specific data that the notifier
+ * has included in this notification.  The value of this should be published in
+ * the documentation of the observable module with the notifications.
+ * @param user_data This is any custom data that the observer provided when
+ * adding itself as an observer to the notification. */
+typedef void (*dwc_notifier_callback_t)(void *object, char *notification, void *observer,
+					void *notification_data, void *user_data);
+
+/** Brings up the notification manager. */
+extern int dwc_alloc_notification_manager(void *mem_ctx, void *wkq_ctx);
+/** Brings down the notification manager. */
+extern void dwc_free_notification_manager(void);
+
+/** This function registers an observable module.  A dwc_notifier_t object is
+ * returned to the observable module.  This is an opaque object that is used by
+ * the observable module to trigger notifications.  This object should only be
+ * accessible to functions that are authorized to trigger notifications for this
+ * module.  Observers do not need this object. */
+extern dwc_notifier_t *dwc_register_notifier(void *mem_ctx, void *object);
+
+/** This function unregisters an observable module.  All observers have to be
+ * removed prior to unregistration. */
+extern void dwc_unregister_notifier(dwc_notifier_t *notifier);
+
+/** Add a module as an observer to the observable module.  The observable module
+ * needs to have previously registered with the notification manager.
+ *
+ * @param observer The observer module
+ * @param object The module to observe
+ * @param notification The notification to observe
+ * @param callback The callback function to call
+ * @param user_data Any additional user data to pass into the callback function */
+extern int dwc_add_observer(void *observer, void *object, char *notification,
+			    dwc_notifier_callback_t callback, void *user_data);
+
+/** Removes the specified observer from all notifications that it is currently
+ * observing. */
+extern int dwc_remove_observer(void *observer);
+
+/** This function triggers a Notification.  It should be called by the
+ * observable module, or any module or library which the observable module
+ * allows to trigger notification on it's behalf.  Such as the dwc_cc_t.
+ *
+ * dwc_notify is a non-blocking function.  Callbacks are scheduled called in
+ * their own process context for each trigger.  Callbacks can be blocking.
+ * dwc_notify can be called from interrupt context if needed.
+ *
+ */
+void dwc_notify(dwc_notifier_t *notifier, char *notification, void *notification_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DWC_NOTIFIER_H__ */
diff --git a/drivers/usb/dwc_otg/dwc_os.h b/drivers/usb/dwc_otg/dwc_os.h
new file mode 100644
index 0000000..fa9d5c6
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_os.h
@@ -0,0 +1,1237 @@
+/* =========================================================================
+ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_os.h $
+ * $Revision: #14 $
+ * $Date: 2010/11/04 $
+ * $Change: 1621695 $
+ *
+ * Synopsys Portability Library Software and documentation
+ * (hereinafter, "Software") is an Unsupported proprietary work of
+ * Synopsys, Inc. unless otherwise expressly agreed to in writing
+ * between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product
+ * under any End User Software License Agreement or Agreement for
+ * Licensed Product with Synopsys or any supplement thereto. You are
+ * permitted to use and redistribute this Software in source and binary
+ * forms, with or without modification, provided that redistributions
+ * of source code must retain this notice. You may not view, use,
+ * disclose, copy or distribute this file or any information contained
+ * herein except pursuant to this license grant from Synopsys. If you
+ * do not agree with this notice, including the disclaimer below, then
+ * you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
+ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
+ * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================= */
+#ifndef _DWC_OS_H_
+#define _DWC_OS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @file
+ *
+ * DWC portability library, low level os-wrapper functions
+ *
+ */
+
+/* These basic types need to be defined by some OS header file or custom header
+ * file for your specific target architecture.
+ *
+ * uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t
+ *
+ * Any custom or alternate header file must be added and enabled here.
+ */
+
+#ifdef DWC_LINUX
+# include <linux/types.h>
+# ifdef CONFIG_DEBUG_MUTEXES
+#  include <linux/mutex.h>
+# endif
+# include <linux/errno.h>
+# include <stdarg.h>
+#endif
+
+#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
+# include <os_dep.h>
+#endif
+
+
+/** @name Primitive Types and Values */
+
+/** We define a boolean type for consistency.  Can be either YES or NO */
+typedef uint8_t dwc_bool_t;
+#define YES  1
+#define NO   0
+
+#ifdef DWC_LINUX
+
+/** @name Error Codes */
+#define DWC_E_INVALID		EINVAL
+#define DWC_E_NO_MEMORY		ENOMEM
+#define DWC_E_NO_DEVICE		ENODEV
+#define DWC_E_NOT_SUPPORTED	EOPNOTSUPP
+#define DWC_E_TIMEOUT		ETIMEDOUT
+#define DWC_E_BUSY		EBUSY
+#define DWC_E_AGAIN		EAGAIN
+#define DWC_E_RESTART		ERESTART
+#define DWC_E_ABORT		ECONNABORTED
+#define DWC_E_SHUTDOWN		ESHUTDOWN
+#define DWC_E_NO_DATA		ENODATA
+#define DWC_E_DISCONNECT	ECONNRESET
+#define DWC_E_UNKNOWN		EINVAL
+#define DWC_E_NO_STREAM_RES	ENOSR
+#define DWC_E_COMMUNICATION	ECOMM
+#define DWC_E_OVERFLOW		EOVERFLOW
+#define DWC_E_PROTOCOL		EPROTO
+#define DWC_E_IN_PROGRESS	EINPROGRESS
+#define DWC_E_PIPE		EPIPE
+#define DWC_E_IO		EIO
+#define DWC_E_NO_SPACE		ENOSPC
+
+#else
+
+/** @name Error Codes */
+#define DWC_E_INVALID		1001
+#define DWC_E_NO_MEMORY		1002
+#define DWC_E_NO_DEVICE		1003
+#define DWC_E_NOT_SUPPORTED	1004
+#define DWC_E_TIMEOUT		1005
+#define DWC_E_BUSY		1006
+#define DWC_E_AGAIN		1007
+#define DWC_E_RESTART		1008
+#define DWC_E_ABORT		1009
+#define DWC_E_SHUTDOWN		1010
+#define DWC_E_NO_DATA		1011
+#define DWC_E_DISCONNECT	2000
+#define DWC_E_UNKNOWN		3000
+#define DWC_E_NO_STREAM_RES	4001
+#define DWC_E_COMMUNICATION	4002
+#define DWC_E_OVERFLOW		4003
+#define DWC_E_PROTOCOL		4004
+#define DWC_E_IN_PROGRESS	4005
+#define DWC_E_PIPE		4006
+#define DWC_E_IO		4007
+#define DWC_E_NO_SPACE		4008
+
+#endif
+
+
+/** @name Tracing/Logging Functions
+ *
+ * These function provide the capability to add tracing, debugging, and error
+ * messages, as well exceptions as assertions.  The WUDEV uses these
+ * extensively.  These could be logged to the main console, the serial port, an
+ * internal buffer, etc.  These functions could also be no-op if they are too
+ * expensive on your system.  By default undefining the DEBUG macro already
+ * no-ops some of these functions. */
+
+/** Returns non-zero if in interrupt context. */
+extern dwc_bool_t DWC_IN_IRQ(void);
+#define dwc_in_irq DWC_IN_IRQ
+
+/** Returns "IRQ" if DWC_IN_IRQ is true. */
+static inline char *dwc_irq(void) {
+	return DWC_IN_IRQ() ? "IRQ" : "";
+}
+
+/** Returns non-zero if in bottom-half context. */
+extern dwc_bool_t DWC_IN_BH(void);
+#define dwc_in_bh DWC_IN_BH
+
+/** Returns "BH" if DWC_IN_BH is true. */
+static inline char *dwc_bh(void) {
+	return DWC_IN_BH() ? "BH" : "";
+}
+
+/**
+ * A vprintf() clone.  Just call vprintf if you've got it.
+ */
+extern void DWC_VPRINTF(char *format, va_list args);
+#define dwc_vprintf DWC_VPRINTF
+
+/**
+ * A vsnprintf() clone.  Just call vprintf if you've got it.
+ */
+extern int DWC_VSNPRINTF(char *str, int size, char *format, va_list args);
+#define dwc_vsnprintf DWC_VSNPRINTF
+
+/**
+ * printf() clone.  Just call printf if you've go it.
+ */
+extern void DWC_PRINTF(char *format, ...)
+/* This provides compiler level static checking of the parameters if you're
+ * using GCC. */
+#ifdef __GNUC__
+	__attribute__ ((format(printf, 1, 2)));
+#else
+	;
+#endif
+#define dwc_printf DWC_PRINTF
+
+/**
+ * sprintf() clone.  Just call sprintf if you've got it.
+ */
+extern int DWC_SPRINTF(char *string, char *format, ...)
+#ifdef __GNUC__
+	__attribute__ ((format(printf, 2, 3)));
+#else
+	;
+#endif
+#define dwc_sprintf DWC_SPRINTF
+
+/**
+ * snprintf() clone.  Just call snprintf if you've got it.
+ */
+extern int DWC_SNPRINTF(char *string, int size, char *format, ...)
+#ifdef __GNUC__
+	__attribute__ ((format(printf, 3, 4)));
+#else
+	;
+#endif
+#define dwc_snprintf DWC_SNPRINTF
+
+/**
+ * Prints a WARNING message.  On systems that don't differentiate between
+ * warnings and regular log messages, just print it.  Indicates that something
+ * may be wrong with the driver.  Works like printf().
+ *
+ * Use the DWC_WARN macro to call this function.
+ */
+extern void __DWC_WARN(char *format, ...)
+#ifdef __GNUC__
+	__attribute__ ((format(printf, 1, 2)));
+#else
+	;
+#endif
+
+/**
+ * Prints an error message.  On systems that don't differentiate between errors
+ * and regular log messages, just print it.  Indicates that something went wrong
+ * with the driver.  Works like printf().
+ *
+ * Use the DWC_ERROR macro to call this function.
+ */
+extern void __DWC_ERROR(char *format, ...)
+#ifdef __GNUC__
+	__attribute__ ((format(printf, 1, 2)));
+#else
+	;
+#endif
+
+/**
+ * Prints an exception error message and takes some user-defined action such as
+ * print out a backtrace or trigger a breakpoint.  Indicates that something went
+ * abnormally wrong with the driver such as programmer error, or other
+ * exceptional condition.  It should not be ignored so even on systems without
+ * printing capability, some action should be taken to notify the developer of
+ * it.  Works like printf().
+ */
+extern void DWC_EXCEPTION(char *format, ...)
+#ifdef __GNUC__
+	__attribute__ ((format(printf, 1, 2)));
+#else
+	;
+#endif
+#define dwc_exception DWC_EXCEPTION
+
+#ifdef DEBUG
+/**
+ * Prints out a debug message.  Used for logging/trace messages.
+ *
+ * Use the DWC_DEBUG macro to call this function
+ */
+extern void __DWC_DEBUG(char *format, ...)
+#ifdef __GNUC__
+	__attribute__ ((format(printf, 1, 2)));
+#else
+	;
+#endif
+#else
+#define __DWC_DEBUG(...)
+#endif
+
+/**
+ * Prints out a Debug message.
+ */
+#define DWC_DEBUG(_format, _args...) __DWC_DEBUG("DEBUG:%s:%s: " _format "\n", \
+						 __func__, dwc_irq(), ## _args)
+#define dwc_debug DWC_DEBUG
+/**
+ * Prints out an informative message.
+ */
+#define DWC_INFO(_format, _args...) DWC_PRINTF("INFO:%s: " _format "\n", \
+					       dwc_irq(), ## _args)
+#define dwc_info DWC_INFO
+/**
+ * Prints out a warning message.
+ */
+#define DWC_WARN(_format, _args...) __DWC_WARN("WARN:%s:%s:%d: " _format "\n", \
+					dwc_irq(), __func__, __LINE__, ## _args)
+#define dwc_warn DWC_WARN
+/**
+ * Prints out an error message.
+ */
+#define DWC_ERROR(_format, _args...) __DWC_ERROR("ERROR:%s:%s:%d: " _format "\n", \
+					dwc_irq(), __func__, __LINE__, ## _args)
+#define dwc_error DWC_ERROR
+
+#define DWC_PROTO_ERROR(_format, _args...) __DWC_WARN("ERROR:%s:%s:%d: " _format "\n", \
+						dwc_irq(), __func__, __LINE__, ## _args)
+#define dwc_proto_error DWC_PROTO_ERROR
+
+#ifdef DEBUG
+/** Prints out a exception error message if the _expr expression fails.  Disabled
+ * if DEBUG is not enabled. */
+#define DWC_ASSERT(_expr, _format, _args...) do { \
+	if (!(_expr)) { DWC_EXCEPTION("%s:%s:%d: " _format "\n", dwc_irq(), \
+				      __FILE__, __LINE__, ## _args); } \
+	} while (0)
+#else
+#define DWC_ASSERT(_x...)
+#endif
+#define dwc_assert DWC_ASSERT
+
+
+/** @name Byte Ordering
+ * The following functions are for conversions between processor's byte ordering
+ * and specific ordering you want.
+ */
+
+/** Converts 32 bit data in CPU byte ordering to little endian. */
+extern uint32_t DWC_CPU_TO_LE32(uint32_t *p);
+#define dwc_cpu_to_le32 DWC_CPU_TO_LE32
+
+/** Converts 32 bit data in CPU byte orderint to big endian. */
+extern uint32_t DWC_CPU_TO_BE32(uint32_t *p);
+#define dwc_cpu_to_be32 DWC_CPU_TO_BE32
+
+/** Converts 32 bit little endian data to CPU byte ordering. */
+extern uint32_t DWC_LE32_TO_CPU(uint32_t *p);
+#define dwc_le32_to_cpu DWC_LE32_TO_CPU
+
+/** Converts 32 bit big endian data to CPU byte ordering. */
+extern uint32_t DWC_BE32_TO_CPU(uint32_t *p);
+#define dwc_be32_to_cpu DWC_BE32_TO_CPU
+
+/** Converts 16 bit data in CPU byte ordering to little endian. */
+extern uint16_t DWC_CPU_TO_LE16(uint16_t *p);
+#define dwc_cpu_to_le16 DWC_CPU_TO_LE16
+
+/** Converts 16 bit data in CPU byte orderint to big endian. */
+extern uint16_t DWC_CPU_TO_BE16(uint16_t *p);
+#define dwc_cpu_to_be16 DWC_CPU_TO_BE16
+
+/** Converts 16 bit little endian data to CPU byte ordering. */
+extern uint16_t DWC_LE16_TO_CPU(uint16_t *p);
+#define dwc_le16_to_cpu DWC_LE16_TO_CPU
+
+/** Converts 16 bit bi endian data to CPU byte ordering. */
+extern uint16_t DWC_BE16_TO_CPU(uint16_t *p);
+#define dwc_be16_to_cpu DWC_BE16_TO_CPU
+
+
+/** @name Register Read/Write
+ *
+ * The following six functions should be implemented to read/write registers of
+ * 32-bit and 64-bit sizes.  All modules use this to read/write register values.
+ * The reg value is a pointer to the register calculated from the void *base
+ * variable passed into the driver when it is started.  */
+
+#ifdef DWC_LINUX
+/* Linux doesn't need any extra parameters for register read/write, so we
+ * just throw away the IO context parameter.
+ */
+/** Reads the content of a 32-bit register. */
+extern uint32_t DWC_READ_REG32(uint32_t volatile *reg);
+#define dwc_read_reg32(_ctx_,_reg_) DWC_READ_REG32(_reg_)
+
+/** Reads the content of a 64-bit register. */
+extern uint64_t DWC_READ_REG64(uint64_t volatile *reg);
+#define dwc_read_reg64(_ctx_,_reg_) DWC_READ_REG64(_reg_)
+
+/** Writes to a 32-bit register. */
+extern void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value);
+#define dwc_write_reg32(_ctx_,_reg_,_val_) DWC_WRITE_REG32(_reg_, _val_)
+
+/** Writes to a 64-bit register. */
+extern void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value);
+#define dwc_write_reg64(_ctx_,_reg_,_val_) DWC_WRITE_REG64(_reg_, _val_)
+
+/**
+ * Modify bit values in a register.  Using the
+ * algorithm: (reg_contents & ~clear_mask) | set_mask.
+ */
+extern void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask);
+#define dwc_modify_reg32(_ctx_,_reg_,_cmsk_,_smsk_) DWC_MODIFY_REG32(_reg_,_cmsk_,_smsk_)
+extern void DWC_MODIFY_REG64(uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask);
+#define dwc_modify_reg64(_ctx_,_reg_,_cmsk_,_smsk_) DWC_MODIFY_REG64(_reg_,_cmsk_,_smsk_)
+
+#endif	/* DWC_LINUX */
+
+#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
+typedef struct dwc_ioctx {
+	struct device *dev;
+	bus_space_tag_t iot;
+	bus_space_handle_t ioh;
+} dwc_ioctx_t;
+
+/** BSD needs two extra parameters for register read/write, so we pass
+ * them in using the IO context parameter.
+ */
+/** Reads the content of a 32-bit register. */
+extern uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg);
+#define dwc_read_reg32 DWC_READ_REG32
+
+/** Reads the content of a 64-bit register. */
+extern uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg);
+#define dwc_read_reg64 DWC_READ_REG64
+
+/** Writes to a 32-bit register. */
+extern void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value);
+#define dwc_write_reg32 DWC_WRITE_REG32
+
+/** Writes to a 64-bit register. */
+extern void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value);
+#define dwc_write_reg64 DWC_WRITE_REG64
+
+/**
+ * Modify bit values in a register.  Using the
+ * algorithm: (reg_contents & ~clear_mask) | set_mask.
+ */
+extern void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask);
+#define dwc_modify_reg32 DWC_MODIFY_REG32
+extern void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask);
+#define dwc_modify_reg64 DWC_MODIFY_REG64
+
+#endif	/* DWC_FREEBSD || DWC_NETBSD */
+
+/** @cond */
+
+/** @name Some convenience MACROS used internally.  Define DWC_DEBUG_REGS to log the
+ * register writes. */
+
+#ifdef DWC_LINUX
+
+# ifdef DWC_DEBUG_REGS
+
+#define dwc_define_read_write_reg_n(_reg,_container_type) \
+static inline uint32_t dwc_read_##_reg##_n(_container_type *container, int num) { \
+	return DWC_READ_REG32(&container->regs->_reg[num]); \
+} \
+static inline void dwc_write_##_reg##_n(_container_type *container, int num, uint32_t data) { \
+	DWC_DEBUG("WRITING %8s[%d]: %p: %08x", #_reg, num, \
+		  &(((uint32_t*)container->regs->_reg)[num]), data); \
+	DWC_WRITE_REG32(&(((uint32_t*)container->regs->_reg)[num]), data); \
+}
+
+#define dwc_define_read_write_reg(_reg,_container_type) \
+static inline uint32_t dwc_read_##_reg(_container_type *container) { \
+	return DWC_READ_REG32(&container->regs->_reg); \
+} \
+static inline void dwc_write_##_reg(_container_type *container, uint32_t data) { \
+	DWC_DEBUG("WRITING %11s: %p: %08x", #_reg, &container->regs->_reg, data); \
+	DWC_WRITE_REG32(&container->regs->_reg, data); \
+}
+
+# else	/* DWC_DEBUG_REGS */
+
+#define dwc_define_read_write_reg_n(_reg,_container_type) \
+static inline uint32_t dwc_read_##_reg##_n(_container_type *container, int num) { \
+	return DWC_READ_REG32(&container->regs->_reg[num]); \
+} \
+static inline void dwc_write_##_reg##_n(_container_type *container, int num, uint32_t data) { \
+	DWC_WRITE_REG32(&(((uint32_t*)container->regs->_reg)[num]), data); \
+}
+
+#define dwc_define_read_write_reg(_reg,_container_type) \
+static inline uint32_t dwc_read_##_reg(_container_type *container) { \
+	return DWC_READ_REG32(&container->regs->_reg); \
+} \
+static inline void dwc_write_##_reg(_container_type *container, uint32_t data) { \
+	DWC_WRITE_REG32(&container->regs->_reg, data); \
+}
+
+# endif	/* DWC_DEBUG_REGS */
+
+#endif	/* DWC_LINUX */
+
+#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
+
+# ifdef DWC_DEBUG_REGS
+
+#define dwc_define_read_write_reg_n(_reg,_container_type) \
+static inline uint32_t dwc_read_##_reg##_n(void *io_ctx, _container_type *container, int num) { \
+	return DWC_READ_REG32(io_ctx, &container->regs->_reg[num]); \
+} \
+static inline void dwc_write_##_reg##_n(void *io_ctx, _container_type *container, int num, uint32_t data) { \
+	DWC_DEBUG("WRITING %8s[%d]: %p: %08x", #_reg, num, \
+		  &(((uint32_t*)container->regs->_reg)[num]), data); \
+	DWC_WRITE_REG32(io_ctx, &(((uint32_t*)container->regs->_reg)[num]), data); \
+}
+
+#define dwc_define_read_write_reg(_reg,_container_type) \
+static inline uint32_t dwc_read_##_reg(void *io_ctx, _container_type *container) { \
+	return DWC_READ_REG32(io_ctx, &container->regs->_reg); \
+} \
+static inline void dwc_write_##_reg(void *io_ctx, _container_type *container, uint32_t data) { \
+	DWC_DEBUG("WRITING %11s: %p: %08x", #_reg, &container->regs->_reg, data); \
+	DWC_WRITE_REG32(io_ctx, &container->regs->_reg, data); \
+}
+
+# else	/* DWC_DEBUG_REGS */
+
+#define dwc_define_read_write_reg_n(_reg,_container_type) \
+static inline uint32_t dwc_read_##_reg##_n(void *io_ctx, _container_type *container, int num) { \
+	return DWC_READ_REG32(io_ctx, &container->regs->_reg[num]); \
+} \
+static inline void dwc_write_##_reg##_n(void *io_ctx, _container_type *container, int num, uint32_t data) { \
+	DWC_WRITE_REG32(io_ctx, &(((uint32_t*)container->regs->_reg)[num]), data); \
+}
+
+#define dwc_define_read_write_reg(_reg,_container_type) \
+static inline uint32_t dwc_read_##_reg(void *io_ctx, _container_type *container) { \
+	return DWC_READ_REG32(io_ctx, &container->regs->_reg); \
+} \
+static inline void dwc_write_##_reg(void *io_ctx, _container_type *container, uint32_t data) { \
+	DWC_WRITE_REG32(io_ctx, &container->regs->_reg, data); \
+}
+
+# endif	/* DWC_DEBUG_REGS */
+
+#endif	/* DWC_FREEBSD || DWC_NETBSD */
+
+/** @endcond */
+
+
+#ifdef DWC_CRYPTOLIB
+/** @name Crypto Functions
+ *
+ * These are the low-level cryptographic functions used by the driver. */
+
+/** Perform AES CBC */
+extern int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out);
+#define dwc_aes_cbc DWC_AES_CBC
+
+/** Fill the provided buffer with random bytes.  These should be cryptographic grade random numbers. */
+extern void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length);
+#define dwc_random_bytes DWC_RANDOM_BYTES
+
+/** Perform the SHA-256 hash function */
+extern int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out);
+#define dwc_sha256 DWC_SHA256
+
+/** Calculated the HMAC-SHA256 */
+extern int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t *out);
+#define dwc_hmac_sha256 DWC_HMAC_SHA256
+
+#endif	/* DWC_CRYPTOLIB */
+
+
+/** @name Memory Allocation
+ *
+ * These function provide access to memory allocation.  There are only 2 DMA
+ * functions and 3 Regular memory functions that need to be implemented.  None
+ * of the memory debugging routines need to be implemented.  The allocation
+ * routines all ZERO the contents of the memory.
+ *
+ * Defining DWC_DEBUG_MEMORY turns on memory debugging and statistic gathering.
+ * This checks for memory leaks, keeping track of alloc/free pairs.  It also
+ * keeps track of how much memory the driver is using at any given time. */
+
+#define DWC_PAGE_SIZE 4096
+#define DWC_PAGE_OFFSET(addr) (((uint32_t)addr) & 0xfff)
+#define DWC_PAGE_ALIGNED(addr) ((((uint32_t)addr) & 0xfff) == 0)
+
+#define DWC_INVALID_DMA_ADDR 0x0
+
+#ifdef DWC_LINUX
+/** Type for a DMA address */
+typedef dma_addr_t dwc_dma_t;
+#endif
+
+#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
+typedef bus_addr_t dwc_dma_t;
+#endif
+
+#ifdef DWC_FREEBSD
+typedef struct dwc_dmactx {
+	struct device *dev;
+	bus_dma_tag_t dma_tag;
+	bus_dmamap_t dma_map;
+	bus_addr_t dma_paddr;
+	void *dma_vaddr;
+} dwc_dmactx_t;
+#endif
+
+#ifdef DWC_NETBSD
+typedef struct dwc_dmactx {
+	struct device *dev;
+	bus_dma_tag_t dma_tag;
+	bus_dmamap_t dma_map;
+	bus_dma_segment_t segs[1];
+	int nsegs;
+	bus_addr_t dma_paddr;
+	void *dma_vaddr;
+} dwc_dmactx_t;
+#endif
+
+/* @todo these functions will be added in the future */
+#if 0
+/**
+ * Creates a DMA pool from which you can allocate DMA buffers.  Buffers
+ * allocated from this pool will be guaranteed to meet the size, alignment, and
+ * boundary requirements specified.
+ *
+ * @param[in] size Specifies the size of the buffers that will be allocated from
+ * this pool.
+ * @param[in] align Specifies the byte alignment requirements of the buffers
+ * allocated from this pool.  Must be a power of 2.
+ * @param[in] boundary Specifies the N-byte boundary that buffers allocated from
+ * this pool must not cross.
+ *
+ * @returns A pointer to an internal opaque structure which is not to be
+ * accessed outside of these library functions.  Use this handle to specify
+ * which pools to allocate/free DMA buffers from and also to destroy the pool,
+ * when you are done with it.
+ */
+extern dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size, uint32_t align, uint32_t boundary);
+
+/**
+ * Destroy a DMA pool.  All buffers allocated from that pool must be freed first.
+ */
+extern void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool);
+
+/**
+ * Allocate a buffer from the specified DMA pool and zeros its contents.
+ */
+extern void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr);
+
+/**
+ * Free a previously allocated buffer from the DMA pool.
+ */
+extern void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr);
+#endif
+
+/** Allocates a DMA capable buffer and zeroes its contents. */
+extern void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr);
+
+/** Allocates a DMA capable buffer and zeroes its contents in atomic contest */
+extern void *__DWC_DMA_ALLOC_ATOMIC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr);
+
+/** Frees a previously allocated buffer. */
+extern void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr);
+
+/** Allocates a block of memory and zeroes its contents. */
+extern void *__DWC_ALLOC(void *mem_ctx, uint32_t size);
+
+/** Allocates a block of memory and zeroes its contents, in an atomic manner
+ * which can be used inside interrupt context.  The size should be sufficiently
+ * small, a few KB at most, such that failures are not likely to occur.  Can just call
+ * __DWC_ALLOC if it is atomic. */
+extern void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size);
+
+/** Frees a previously allocated buffer. */
+extern void __DWC_FREE(void *mem_ctx, void *addr);
+
+#ifndef DWC_DEBUG_MEMORY
+
+#define DWC_ALLOC(_size_) __DWC_ALLOC(NULL, _size_)
+#define DWC_ALLOC_ATOMIC(_size_) __DWC_ALLOC_ATOMIC(NULL, _size_)
+#define DWC_FREE(_addr_) __DWC_FREE(NULL, _addr_)
+
+# ifdef DWC_LINUX
+#define DWC_DMA_ALLOC(_size_,_dma_) __DWC_DMA_ALLOC(NULL, _size_, _dma_)
+#define DWC_DMA_ALLOC_ATOMIC(_size_,_dma_) __DWC_DMA_ALLOC_ATOMIC(NULL, _size_,_dma_)
+#define DWC_DMA_FREE(_size_,_virt_,_dma_) __DWC_DMA_FREE(NULL, _size_, _virt_, _dma_)
+# endif
+
+# if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
+#define DWC_DMA_ALLOC __DWC_DMA_ALLOC
+#define DWC_DMA_FREE __DWC_DMA_FREE
+# endif
+
+#else	/* DWC_DEBUG_MEMORY */
+
+extern void *dwc_alloc_debug(void *mem_ctx, uint32_t size, char const *func, int line);
+extern void *dwc_alloc_atomic_debug(void *mem_ctx, uint32_t size, char const *func, int line);
+extern void dwc_free_debug(void *mem_ctx, void *addr, char const *func, int line);
+extern void *dwc_dma_alloc_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
+				 char const *func, int line);
+extern void *dwc_dma_alloc_atomic_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr, 
+				char const *func, int line);
+extern void dwc_dma_free_debug(void *dma_ctx, uint32_t size, void *virt_addr,
+			       dwc_dma_t dma_addr, char const *func, int line);
+
+extern int dwc_memory_debug_start(void *mem_ctx);
+extern void dwc_memory_debug_stop(void);
+extern void dwc_memory_debug_report(void);
+
+#define DWC_ALLOC(_size_) dwc_alloc_debug(NULL, _size_, __func__, __LINE__)
+#define DWC_ALLOC_ATOMIC(_size_) dwc_alloc_atomic_debug(NULL, _size_, \
+							__func__, __LINE__)
+#define DWC_FREE(_addr_) dwc_free_debug(NULL, _addr_, __func__, __LINE__)
+
+# ifdef DWC_LINUX
+#define DWC_DMA_ALLOC(_size_,_dma_) dwc_dma_alloc_debug(NULL, _size_, \
+						_dma_, __func__, __LINE__)
+#define DWC_DMA_ALLOC_ATOMIC(_size_,_dma_) dwc_dma_alloc_atomic_debug(NULL, _size_, \
+						_dma_, __func__, __LINE__)
+#define DWC_DMA_FREE(_size_,_virt_,_dma_) dwc_dma_free_debug(NULL, _size_, \
+						_virt_, _dma_, __func__, __LINE__)
+# endif
+
+# if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
+#define DWC_DMA_ALLOC(_ctx_,_size_,_dma_) dwc_dma_alloc_debug(_ctx_, _size_, \
+						_dma_, __func__, __LINE__)
+#define DWC_DMA_FREE(_ctx_,_size_,_virt_,_dma_) dwc_dma_free_debug(_ctx_, _size_, \
+						 _virt_, _dma_, __func__, __LINE__)
+# endif
+
+#endif /* DWC_DEBUG_MEMORY */
+
+#define dwc_alloc(_ctx_,_size_) DWC_ALLOC(_size_)
+#define dwc_alloc_atomic(_ctx_,_size_) DWC_ALLOC_ATOMIC(_size_)
+#define dwc_free(_ctx_,_addr_) DWC_FREE(_addr_)
+
+#ifdef DWC_LINUX
+/* Linux doesn't need any extra parameters for DMA buffer allocation, so we
+ * just throw away the DMA context parameter.
+ */
+#define dwc_dma_alloc(_ctx_,_size_,_dma_) DWC_DMA_ALLOC(_size_, _dma_)
+#define dwc_dma_alloc_atomic(_ctx_,_size_,_dma_) DWC_DMA_ALLOC_ATOMIC(_size_, _dma_)
+#define dwc_dma_free(_ctx_,_size_,_virt_,_dma_) DWC_DMA_FREE(_size_, _virt_, _dma_)
+#endif
+
+#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
+/** BSD needs several extra parameters for DMA buffer allocation, so we pass
+ * them in using the DMA context parameter.
+ */
+#define dwc_dma_alloc DWC_DMA_ALLOC
+#define dwc_dma_free DWC_DMA_FREE
+#endif
+
+
+/** @name Memory and String Processing */
+
+/** memset() clone */
+extern void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size);
+#define dwc_memset DWC_MEMSET
+
+/** memcpy() clone */
+extern void *DWC_MEMCPY(void *dest, void const *src, uint32_t size);
+#define dwc_memcpy DWC_MEMCPY
+
+/** memmove() clone */
+extern void *DWC_MEMMOVE(void *dest, void *src, uint32_t size);
+#define dwc_memmove DWC_MEMMOVE
+
+/** memcmp() clone */
+extern int DWC_MEMCMP(void *m1, void *m2, uint32_t size);
+#define dwc_memcmp DWC_MEMCMP
+
+/** strcmp() clone */
+extern int DWC_STRCMP(void *s1, void *s2);
+#define dwc_strcmp DWC_STRCMP
+
+/** strncmp() clone */
+extern int DWC_STRNCMP(void *s1, void *s2, uint32_t size);
+#define dwc_strncmp DWC_STRNCMP
+
+/** strlen() clone, for NULL terminated ASCII strings */
+extern int DWC_STRLEN(char const *str);
+#define dwc_strlen DWC_STRLEN
+
+/** strcpy() clone, for NULL terminated ASCII strings */
+extern char *DWC_STRCPY(char *to, const char *from);
+#define dwc_strcpy DWC_STRCPY
+
+/** strdup() clone.  If you wish to use memory allocation debugging, this
+ * implementation of strdup should use the DWC_* memory routines instead of
+ * calling a predefined strdup.  Otherwise the memory allocated by this routine
+ * will not be seen by the debugging routines. */
+extern char *DWC_STRDUP(char const *str);
+#define dwc_strdup(_ctx_,_str_) DWC_STRDUP(_str_)
+
+/** NOT an atoi() clone.  Read the description carefully.  Returns an integer
+ * converted from the string str in base 10 unless the string begins with a "0x"
+ * in which case it is base 16.  String must be a NULL terminated sequence of
+ * ASCII characters and may optionally begin with whitespace, a + or -, and a
+ * "0x" prefix if base 16.  The remaining characters must be valid digits for
+ * the number and end with a NULL character.  If any invalid characters are
+ * encountered or it returns with a negative error code and the results of the
+ * conversion are undefined.  On sucess it returns 0.  Overflow conditions are
+ * undefined.  An example implementation using atoi() can be referenced from the
+ * Linux implementation. */
+extern int DWC_ATOI(const char *str, int32_t *value);
+#define dwc_atoi DWC_ATOI
+
+/** Same as above but for unsigned. */
+extern int DWC_ATOUI(const char *str, uint32_t *value);
+#define dwc_atoui DWC_ATOUI
+
+#ifdef DWC_UTFLIB
+/** This routine returns a UTF16LE unicode encoded string from a UTF8 string. */
+extern int DWC_UTF8_TO_UTF16LE(uint8_t const *utf8string, uint16_t *utf16string, unsigned len);
+#define dwc_utf8_to_utf16le DWC_UTF8_TO_UTF16LE
+#endif
+
+
+/** @name Wait queues
+ *
+ * Wait queues provide a means of synchronizing between threads or processes.  A
+ * process can block on a waitq if some condition is not true, waiting for it to
+ * become true.  When the waitq is triggered all waiting process will get
+ * unblocked and the condition will be check again.  Waitqs should be triggered
+ * every time a condition can potentially change.*/
+struct dwc_waitq;
+
+/** Type for a waitq */
+typedef struct dwc_waitq dwc_waitq_t;
+
+/** The type of waitq condition callback function.  This is called every time
+ * condition is evaluated. */
+typedef int (*dwc_waitq_condition_t)(void *data);
+
+/** Allocate a waitq */
+extern dwc_waitq_t *DWC_WAITQ_ALLOC(void);
+#define dwc_waitq_alloc(_ctx_) DWC_WAITQ_ALLOC()
+
+/** Free a waitq */
+extern void DWC_WAITQ_FREE(dwc_waitq_t *wq);
+#define dwc_waitq_free DWC_WAITQ_FREE
+
+/** Check the condition and if it is false, block on the waitq.  When unblocked, check the
+ * condition again.  The function returns when the condition becomes true.  The return value
+ * is 0 on condition true, DWC_WAITQ_ABORTED on abort or killed, or DWC_WAITQ_UNKNOWN on error. */
+extern int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data);
+#define dwc_waitq_wait DWC_WAITQ_WAIT
+
+/** Check the condition and if it is false, block on the waitq.  When unblocked,
+ * check the condition again.  The function returns when the condition become
+ * true or the timeout has passed.  The return value is 0 on condition true or
+ * DWC_TIMED_OUT on timeout, or DWC_WAITQ_ABORTED, or DWC_WAITQ_UNKNOWN on
+ * error. */
+extern int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
+				      void *data, int32_t msecs);
+#define dwc_waitq_wait_timeout DWC_WAITQ_WAIT_TIMEOUT
+
+/** Trigger a waitq, unblocking all processes.  This should be called whenever a condition
+ * has potentially changed. */
+extern void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq);
+#define dwc_waitq_trigger DWC_WAITQ_TRIGGER
+
+/** Unblock all processes waiting on the waitq with an ABORTED result. */
+extern void DWC_WAITQ_ABORT(dwc_waitq_t *wq);
+#define dwc_waitq_abort DWC_WAITQ_ABORT
+
+
+/** @name Threads
+ *
+ * A thread must be explicitly stopped.  It must check DWC_THREAD_SHOULD_STOP
+ * whenever it is woken up, and then return.  The DWC_THREAD_STOP function
+ * returns the value from the thread.
+ */
+
+struct dwc_thread;
+
+/** Type for a thread */
+typedef struct dwc_thread dwc_thread_t;
+
+/** The thread function */
+typedef int (*dwc_thread_function_t)(void *data);
+
+/** Create a thread and start it running the thread_function.  Returns a handle
+ * to the thread */
+extern dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data);
+#define dwc_thread_run(_ctx_,_func_,_name_,_data_) DWC_THREAD_RUN(_func_, _name_, _data_)
+
+/** Stops a thread.  Return the value returned by the thread.  Or will return
+ * DWC_ABORT if the thread never started. */
+extern int DWC_THREAD_STOP(dwc_thread_t *thread);
+#define dwc_thread_stop DWC_THREAD_STOP
+
+/** Signifies to the thread that it must stop. */
+#ifdef DWC_LINUX
+/* Linux doesn't need any parameters for kthread_should_stop() */
+extern dwc_bool_t DWC_THREAD_SHOULD_STOP(void);
+#define dwc_thread_should_stop(_thrd_) DWC_THREAD_SHOULD_STOP()
+
+/* No thread_exit function in Linux */
+#define dwc_thread_exit(_thrd_)
+#endif
+
+#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
+/** BSD needs the thread pointer for kthread_suspend_check() */
+extern dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread);
+#define dwc_thread_should_stop DWC_THREAD_SHOULD_STOP
+
+/** The thread must call this to exit. */
+extern void DWC_THREAD_EXIT(dwc_thread_t *thread);
+#define dwc_thread_exit DWC_THREAD_EXIT
+#endif
+
+
+/** @name Work queues
+ *
+ * Workqs are used to queue a callback function to be called at some later time,
+ * in another thread. */
+struct dwc_workq;
+
+/** Type for a workq */
+typedef struct dwc_workq dwc_workq_t;
+
+/** The type of the callback function to be called. */
+typedef void (*dwc_work_callback_t)(void *data);
+
+/** Allocate a workq */
+extern dwc_workq_t *DWC_WORKQ_ALLOC(char *name);
+#define dwc_workq_alloc(_ctx_,_name_) DWC_WORKQ_ALLOC(_name_)
+
+/** Free a workq.  All work must be completed before being freed. */
+extern void DWC_WORKQ_FREE(dwc_workq_t *workq);
+#define dwc_workq_free DWC_WORKQ_FREE
+
+/** Schedule a callback on the workq, passing in data.  The function will be
+ * scheduled at some later time. */
+extern void DWC_WORKQ_SCHEDULE(dwc_workq_t *workq, dwc_work_callback_t cb,
+			       void *data, char *format, ...)
+#ifdef __GNUC__
+	__attribute__ ((format(printf, 4, 5)));
+#else
+	;
+#endif
+#define dwc_workq_schedule DWC_WORKQ_SCHEDULE
+
+/** Schedule a callback on the workq, that will be called until at least
+ * given number miliseconds have passed. */
+extern void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *workq, dwc_work_callback_t cb,
+				       void *data, uint32_t time, char *format, ...)
+#ifdef __GNUC__
+	__attribute__ ((format(printf, 5, 6)));
+#else
+	;
+#endif
+#define dwc_workq_schedule_delayed DWC_WORKQ_SCHEDULE_DELAYED
+
+/** The number of processes in the workq */
+extern int DWC_WORKQ_PENDING(dwc_workq_t *workq);
+#define dwc_workq_pending DWC_WORKQ_PENDING
+
+/** Blocks until all the work in the workq is complete or timed out.  Returns <
+ * 0 on timeout. */
+extern int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout);
+#define dwc_workq_wait_work_done DWC_WORKQ_WAIT_WORK_DONE
+
+
+/** @name Tasklets
+ *
+ */
+struct dwc_tasklet;
+
+/** Type for a tasklet */
+typedef struct dwc_tasklet dwc_tasklet_t;
+
+/** The type of the callback function to be called */
+typedef void (*dwc_tasklet_callback_t)(void *data);
+
+/** Allocates a tasklet */
+extern dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data);
+#define dwc_task_alloc(_ctx_,_name_,_cb_,_data_) DWC_TASK_ALLOC(_name_, _cb_, _data_)
+
+/** Frees a tasklet */
+extern void DWC_TASK_FREE(dwc_tasklet_t *task);
+#define dwc_task_free DWC_TASK_FREE
+
+/** Schedules a tasklet to run */
+extern void DWC_TASK_SCHEDULE(dwc_tasklet_t *task);
+#define dwc_task_schedule DWC_TASK_SCHEDULE
+
+
+/** @name Timer
+ *
+ * Callbacks must be small and atomic.
+ */
+struct dwc_timer;
+
+/** Type for a timer */
+typedef struct dwc_timer dwc_timer_t;
+
+/** The type of the callback function to be called */
+typedef void (*dwc_timer_callback_t)(void *data);
+
+/** Allocates a timer */
+extern dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data);
+#define dwc_timer_alloc(_ctx_,_name_,_cb_,_data_) DWC_TIMER_ALLOC(_name_,_cb_,_data_)
+
+/** Frees a timer */
+extern void DWC_TIMER_FREE(dwc_timer_t *timer);
+#define dwc_timer_free DWC_TIMER_FREE
+
+/** Schedules the timer to run at time ms from now.  And will repeat at every
+ * repeat_interval msec therafter
+ *
+ * Modifies a timer that is still awaiting execution to a new expiration time.
+ * The mod_time is added to the old time.  */
+extern void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time);
+#define dwc_timer_schedule DWC_TIMER_SCHEDULE
+
+/** Disables the timer from execution. */
+extern void DWC_TIMER_CANCEL(dwc_timer_t *timer);
+#define dwc_timer_cancel DWC_TIMER_CANCEL
+
+
+/** @name Spinlocks
+ *
+ * These locks are used when the work between the lock/unlock is atomic and
+ * short.  Interrupts are also disabled during the lock/unlock and thus they are
+ * suitable to lock between interrupt/non-interrupt context.  They also lock
+ * between processes if you have multiple CPUs or Preemption.  If you don't have
+ * multiple CPUS or Preemption, then the you can simply implement the
+ * DWC_SPINLOCK and DWC_SPINUNLOCK to disable and enable interrupts.  Because
+ * the work between the lock/unlock is atomic, the process context will never
+ * change, and so you never have to lock between processes.  */
+
+struct dwc_spinlock;
+
+/** Type for a spinlock */
+typedef struct dwc_spinlock dwc_spinlock_t;
+
+/** Type for the 'flags' argument to spinlock funtions */
+typedef unsigned long dwc_irqflags_t;
+
+/** Returns an initialized lock variable.  This function should allocate and
+ * initialize the OS-specific data structure used for locking.  This data
+ * structure is to be used for the DWC_LOCK and DWC_UNLOCK functions and should
+ * be freed by the DWC_FREE_LOCK when it is no longer used. */
+extern dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void);
+#define dwc_spinlock_alloc(_ctx_) DWC_SPINLOCK_ALLOC()
+
+/** Frees an initialized lock variable. */
+extern void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock);
+#define dwc_spinlock_free(_ctx_,_lock_) DWC_SPINLOCK_FREE(_lock_)
+
+/** Disables interrupts and blocks until it acquires the lock.
+ *
+ * @param lock Pointer to the spinlock.
+ * @param flags Unsigned long for irq flags storage.
+ */
+extern void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags);
+#define dwc_spinlock_irqsave DWC_SPINLOCK_IRQSAVE
+
+/** Re-enables the interrupt and releases the lock.
+ *
+ * @param lock Pointer to the spinlock.
+ * @param flags Unsigned long for irq flags storage.  Must be the same as was
+ * passed into DWC_LOCK.
+ */
+extern void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags);
+#define dwc_spinunlock_irqrestore DWC_SPINUNLOCK_IRQRESTORE
+
+/** Blocks until it acquires the lock.
+ *
+ * @param lock Pointer to the spinlock.
+ */
+extern void DWC_SPINLOCK(dwc_spinlock_t *lock);
+#define dwc_spinlock DWC_SPINLOCK
+
+/** Releases the lock.
+ *
+ * @param lock Pointer to the spinlock.
+ */
+extern void DWC_SPINUNLOCK(dwc_spinlock_t *lock);
+#define dwc_spinunlock DWC_SPINUNLOCK
+
+
+/** @name Mutexes
+ *
+ * Unlike spinlocks Mutexes lock only between processes and the work between the
+ * lock/unlock CAN block, therefore it CANNOT be called from interrupt context.
+ */
+
+struct dwc_mutex;
+
+/** Type for a mutex */
+typedef struct dwc_mutex dwc_mutex_t;
+
+/* For Linux Mutex Debugging make it inline because the debugging routines use
+ * the symbol to determine recursive locking.  This makes it falsely think
+ * recursive locking occurs. */
+#if defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)
+#define DWC_MUTEX_ALLOC_LINUX_DEBUG(__mutexp) ({ \
+	__mutexp = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mutex)); \
+	mutex_init((struct mutex *)__mutexp); \
+})
+#endif
+
+/** Allocate a mutex */
+extern dwc_mutex_t *DWC_MUTEX_ALLOC(void);
+#define dwc_mutex_alloc(_ctx_) DWC_MUTEX_ALLOC()
+
+/* For memory leak debugging when using Linux Mutex Debugging */
+#if defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)
+#define DWC_MUTEX_FREE(__mutexp) do { \
+	mutex_destroy((struct mutex *)__mutexp); \
+	DWC_FREE(__mutexp); \
+} while(0)
+#else
+/** Free a mutex */
+extern void DWC_MUTEX_FREE(dwc_mutex_t *mutex);
+#define dwc_mutex_free(_ctx_,_mutex_) DWC_MUTEX_FREE(_mutex_)
+#endif
+
+/** Lock a mutex */
+extern void DWC_MUTEX_LOCK(dwc_mutex_t *mutex);
+#define dwc_mutex_lock DWC_MUTEX_LOCK
+
+/** Non-blocking lock returns 1 on successful lock. */
+extern int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex);
+#define dwc_mutex_trylock DWC_MUTEX_TRYLOCK
+
+/** Unlock a mutex */
+extern void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex);
+#define dwc_mutex_unlock DWC_MUTEX_UNLOCK
+
+
+/** @name Time */
+
+/** Microsecond delay.
+ *
+ * @param usecs  Microseconds to delay.
+ */
+extern void DWC_UDELAY(uint32_t usecs);
+#define dwc_udelay DWC_UDELAY
+
+/** Millisecond delay.
+ *
+ * @param msecs  Milliseconds to delay.
+ */
+extern void DWC_MDELAY(uint32_t msecs);
+#define dwc_mdelay DWC_MDELAY
+
+/** Non-busy waiting.
+ * Sleeps for specified number of milliseconds.
+ *
+ * @param msecs Milliseconds to sleep.
+ */
+extern void DWC_MSLEEP(uint32_t msecs);
+#define dwc_msleep DWC_MSLEEP
+
+/**
+ * Returns number of milliseconds since boot.
+ */
+extern uint32_t DWC_TIME(void);
+#define dwc_time DWC_TIME
+
+
+
+
+/* @mainpage DWC Portability and Common Library
+ *
+ * This is the documentation for the DWC Portability and Common Library.
+ *
+ * @section intro Introduction
+ *
+ * The DWC Portability library consists of wrapper calls and data structures to
+ * all low-level functions which are typically provided by the OS.  The WUDEV
+ * driver uses only these functions.  In order to port the WUDEV driver, only
+ * the functions in this library need to be re-implemented, with the same
+ * behavior as documented here.
+ *
+ * The Common library consists of higher level functions, which rely only on
+ * calling the functions from the DWC Portability library.  These common
+ * routines are shared across modules.  Some of the common libraries need to be
+ * used directly by the driver programmer when porting WUDEV.  Such as the
+ * parameter and notification libraries.
+ *
+ * @section low Portability Library OS Wrapper Functions
+ *
+ * Any function starting with DWC and in all CAPS is a low-level OS-wrapper that
+ * needs to be implemented when porting, for example DWC_MUTEX_ALLOC().  All of
+ * these functions are included in the dwc_os.h file.
+ *
+ * There are many functions here covering a wide array of OS services.  Please
+ * see dwc_os.h for details, and implementation notes for each function.
+ *
+ * @section common Common Library Functions
+ *
+ * Any function starting with dwc and in all lowercase is a common library
+ * routine.  These functions have a portable implementation and do not need to
+ * be reimplemented when porting.  The common routines can be used by any
+ * driver, and some must be used by the end user to control the drivers.  For
+ * example, you must use the Parameter common library in order to set the
+ * parameters in the WUDEV module.
+ *
+ * The common libraries consist of the following:
+ *
+ * - Connection Contexts - Used internally and can be used by end-user.  See dwc_cc.h
+ * - Parameters - Used internally and can be used by end-user.  See dwc_params.h
+ * - Notifications - Used internally and can be used by end-user.  See dwc_notifier.h
+ * - Lists - Used internally and can be used by end-user.  See dwc_list.h
+ * - Memory Debugging - Used internally and can be used by end-user.  See dwc_os.h
+ * - Modpow - Used internally only.  See dwc_modpow.h
+ * - DH - Used internally only.  See dwc_dh.h
+ * - Crypto - Used internally only.  See dwc_crypto.h
+ *
+ *
+ * @section prereq Prerequistes For dwc_os.h
+ * @subsection types Data Types
+ *
+ * The dwc_os.h file assumes that several low-level data types are pre defined for the
+ * compilation environment.  These data types are:
+ *
+ * - uint8_t - unsigned 8-bit data type
+ * - int8_t - signed 8-bit data type
+ * - uint16_t - unsigned 16-bit data type
+ * - int16_t - signed 16-bit data type
+ * - uint32_t - unsigned 32-bit data type
+ * - int32_t - signed 32-bit data type
+ * - uint64_t - unsigned 64-bit data type
+ * - int64_t - signed 64-bit data type
+ *
+ * Ensure that these are defined before using dwc_os.h.  The easiest way to do
+ * that is to modify the top of the file to include the appropriate header.
+ * This is already done for the Linux environment.  If the DWC_LINUX macro is
+ * defined, the correct header will be added.  A standard header <stdint.h> is
+ * also used for environments where standard C headers are available.
+ *
+ * @subsection stdarg Variable Arguments
+ *
+ * Variable arguments are provided by a standard C header <stdarg.h>.  it is
+ * available in Both the Linux and ANSI C enviornment.  An equivalent must be
+ * provided in your enviornment in order to use dwc_os.h with the debug and
+ * tracing message functionality.
+ *
+ * @subsection thread Threading
+ *
+ * WUDEV Core must be run on an operating system that provides for multiple
+ * threads/processes.  Threading can be implemented in many ways, even in
+ * embedded systems without an operating system.  At the bare minimum, the
+ * system should be able to start any number of processes at any time to handle
+ * special work.  It need not be a pre-emptive system.  Process context can
+ * change upon a call to a blocking function.  The hardware interrupt context
+ * that calls the module's ISR() function must be differentiable from process
+ * context, even if your processes are impemented via a hardware interrupt.
+ * Further locking mechanism between process must exist (or be implemented), and
+ * process context must have a way to disable interrupts for a period of time to
+ * lock them out.  If all of this exists, the functions in dwc_os.h related to
+ * threading should be able to be implemented with the defined behavior.
+ *
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DWC_OS_H_ */
diff --git a/drivers/usb/dwc_otg/dwc_otg_adp.c b/drivers/usb/dwc_otg/dwc_otg_adp.c
new file mode 100644
index 0000000..0877472
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_adp.c
@@ -0,0 +1,854 @@
+/* ==========================================================================
+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_adp.c $
+ * $Revision: #12 $
+ * $Date: 2011/10/26 $
+ * $Change: 1873028 $
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+#include "dwc_os.h"
+#include "dwc_otg_regs.h"
+#include "dwc_otg_cil.h"
+#include "dwc_otg_adp.h"
+
+/** @file
+ *
+ * This file contains the most of the Attach Detect Protocol implementation for
+ * the driver to support OTG Rev2.0.
+ *
+ */
+
+void dwc_otg_adp_write_reg(dwc_otg_core_if_t * core_if, uint32_t value)
+{
+	adpctl_data_t adpctl;
+
+	adpctl.d32 = value;
+	adpctl.b.ar = 0x2;
+
+	DWC_WRITE_REG32(&core_if->core_global_regs->adpctl, adpctl.d32);
+
+	while (adpctl.b.ar) {
+		adpctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->adpctl);
+	}
+
+}
+
+/**
+ * Function is called to read ADP registers
+ */
+uint32_t dwc_otg_adp_read_reg(dwc_otg_core_if_t * core_if)
+{
+	adpctl_data_t adpctl;
+
+	adpctl.d32 = 0;
+	adpctl.b.ar = 0x1;
+
+	DWC_WRITE_REG32(&core_if->core_global_regs->adpctl, adpctl.d32);
+
+	while (adpctl.b.ar) {
+		adpctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->adpctl);
+	}
+
+	return adpctl.d32;
+}
+
+/**
+ * Function is called to read ADPCTL register and filter Write-clear bits
+ */
+uint32_t dwc_otg_adp_read_reg_filter(dwc_otg_core_if_t * core_if)
+{
+	adpctl_data_t adpctl;
+
+	adpctl.d32 = dwc_otg_adp_read_reg(core_if);
+	adpctl.b.adp_tmout_int = 0;
+	adpctl.b.adp_prb_int = 0;
+	adpctl.b.adp_tmout_int = 0;
+		
+	return adpctl.d32;
+}
+
+/**
+ * Function is called to write ADP registers
+ */
+void dwc_otg_adp_modify_reg(dwc_otg_core_if_t * core_if, uint32_t clr,
+			    uint32_t set)
+{
+	dwc_otg_adp_write_reg(core_if,
+			      (dwc_otg_adp_read_reg(core_if) & (~clr)) | set);
+}
+
+static void adp_sense_timeout(void *ptr)
+{
+	dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
+	core_if->adp.sense_timer_started = 0;
+	DWC_PRINTF("ADP SENSE TIMEOUT\n");
+	if (core_if->adp_enable) {
+		dwc_otg_adp_sense_stop(core_if);
+		dwc_otg_adp_probe_start(core_if);
+	}
+}
+
+/**
+ * This function is called when the ADP vbus timer expires. Timeout is 1.1s.
+ */
+static void adp_vbuson_timeout(void *ptr)
+{
+	gpwrdn_data_t gpwrdn;
+	dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
+	hprt0_data_t hprt0 = {.d32 = 0 };
+	pcgcctl_data_t pcgcctl = {.d32 = 0 };
+	DWC_PRINTF("%s: 1.1 seconds expire after turning on VBUS\n",__FUNCTION__);
+	if (core_if) {
+		core_if->adp.vbuson_timer_started = 0;
+		/* Turn off vbus */
+		hprt0.b.prtpwr = 1;
+		DWC_MODIFY_REG32(core_if->host_if->hprt0, hprt0.d32, 0);
+		gpwrdn.d32 = 0;
+
+		/* Power off the core */
+		if (core_if->power_down == 2) {
+			/* Enable Wakeup Logic */
+//                      gpwrdn.b.wkupactiv = 1;
+			gpwrdn.b.pmuactv = 0;
+			gpwrdn.b.pwrdnrstn = 1;
+			gpwrdn.b.pwrdnclmp = 1;
+			DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
+					 gpwrdn.d32);
+
+			/* Suspend the Phy Clock */
+			pcgcctl.b.stoppclk = 1;
+			DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
+
+			/* Switch on VDD */
+//                      gpwrdn.b.wkupactiv = 1;
+			gpwrdn.b.pmuactv = 1;
+			gpwrdn.b.pwrdnrstn = 1;
+			gpwrdn.b.pwrdnclmp = 1;
+			DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
+					 gpwrdn.d32);
+		} else {
+			/* Enable Power Down Logic */
+			gpwrdn.b.pmuintsel = 1;
+			gpwrdn.b.pmuactv = 1;
+			DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
+		}
+
+		/* Power off the core */
+		if (core_if->power_down == 2) {
+			gpwrdn.d32 = 0;
+			gpwrdn.b.pwrdnswtch = 1;
+			DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn,
+					 gpwrdn.d32, 0);
+		}
+
+		/* Unmask SRP detected interrupt from Power Down Logic */
+		gpwrdn.d32 = 0;
+		gpwrdn.b.srp_det_msk = 1;
+		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
+
+		dwc_otg_adp_probe_start(core_if);
+		dwc_otg_dump_global_registers(core_if);
+		dwc_otg_dump_host_registers(core_if);
+	}
+
+}
+
+/**
+ * Start the ADP Initial Probe timer to detect if Port Connected interrupt is 
+ * not asserted within 1.1 seconds.
+ *
+ * @param core_if the pointer to core_if strucure.
+ */
+void dwc_otg_adp_vbuson_timer_start(dwc_otg_core_if_t * core_if)
+{
+	core_if->adp.vbuson_timer_started = 1;
+	if (core_if->adp.vbuson_timer)
+	{
+		DWC_PRINTF("SCHEDULING VBUSON TIMER\n");
+		/* 1.1 secs + 60ms necessary for cil_hcd_start*/
+		DWC_TIMER_SCHEDULE(core_if->adp.vbuson_timer, 1160);
+	} else {
+		DWC_WARN("VBUSON_TIMER = %p\n",core_if->adp.vbuson_timer);
+	}
+}
+
+#if 0
+/**
+ * Masks all DWC OTG core interrupts
+ *
+ */
+static void mask_all_interrupts(dwc_otg_core_if_t * core_if)
+{
+	int i;
+	gahbcfg_data_t ahbcfg = {.d32 = 0 };
+
+	/* Mask Host Interrupts */
+
+	/* Clear and disable HCINTs */
+	for (i = 0; i < core_if->core_params->host_channels; i++) {
+		DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcintmsk, 0);
+		DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcint, 0xFFFFFFFF);
+
+	}
+
+	/* Clear and disable HAINT */
+	DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haintmsk, 0x0000);
+	DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haint, 0xFFFFFFFF);
+
+	/* Mask Device Interrupts */
+	if (!core_if->multiproc_int_enable) {
+		/* Clear and disable IN Endpoint interrupts */
+		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->diepmsk, 0);
+		for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
+			DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->
+					diepint, 0xFFFFFFFF);
+		}
+
+		/* Clear and disable OUT Endpoint interrupts */
+		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->doepmsk, 0);
+		for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
+			DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->
+					doepint, 0xFFFFFFFF);
+		}
+
+		/* Clear and disable DAINT */
+		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daint,
+				0xFFFFFFFF);
+		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daintmsk, 0);
+	} else {
+		for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
+			DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
+					diepeachintmsk[i], 0);
+			DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->
+					diepint, 0xFFFFFFFF);
+		}
+
+		for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
+			DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
+					doepeachintmsk[i], 0);
+			DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->
+					doepint, 0xFFFFFFFF);
+		}
+
+		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->deachintmsk,
+				0);
+		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->deachint,
+				0xFFFFFFFF);
+
+	}
+
+	/* Disable interrupts */
+	ahbcfg.b.glblintrmsk = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);
+
+	/* Disable all interrupts. */
+	DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0);
+
+	/* Clear any pending interrupts */
+	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
+
+	/* Clear any pending OTG Interrupts */
+	DWC_WRITE_REG32(&core_if->core_global_regs->gotgint, 0xFFFFFFFF);
+}
+
+/**
+ * Unmask Port Connection Detected interrupt
+ *
+ */
+static void unmask_conn_det_intr(dwc_otg_core_if_t * core_if)
+{
+	gintmsk_data_t gintmsk = {.d32 = 0,.b.portintr = 1 };
+
+	DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32);
+}
+#endif
+
+/**
+ * Starts the ADP Probing
+ *
+ * @param core_if the pointer to core_if structure.
+ */
+uint32_t dwc_otg_adp_probe_start(dwc_otg_core_if_t * core_if)
+{
+
+	adpctl_data_t adpctl = {.d32 = 0};
+	gpwrdn_data_t gpwrdn;
+#if 0
+	adpctl_data_t adpctl_int = {.d32 = 0, .b.adp_prb_int = 1,
+								.b.adp_sns_int = 1, b.adp_tmout_int};
+#endif
+	dwc_otg_disable_global_interrupts(core_if);
+	DWC_PRINTF("ADP Probe Start\n");
+	core_if->adp.probe_enabled = 1;
+
+	adpctl.b.adpres = 1;
+	dwc_otg_adp_write_reg(core_if, adpctl.d32);
+
+	while (adpctl.b.adpres) {
+		adpctl.d32 = dwc_otg_adp_read_reg(core_if);
+	}
+
+	adpctl.d32 = 0;
+	gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
+
+	/* In Host mode unmask SRP detected interrupt */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.sts_chngint_msk = 1;
+	if (!gpwrdn.b.idsts) {
+		gpwrdn.b.srp_det_msk = 1;
+	}
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
+
+	adpctl.b.adp_tmout_int_msk = 1;
+	adpctl.b.adp_prb_int_msk = 1;
+	adpctl.b.prb_dschg = 1;
+	adpctl.b.prb_delta = 1;
+	adpctl.b.prb_per = 1;
+	adpctl.b.adpen = 1;
+	adpctl.b.enaprb = 1;
+
+	dwc_otg_adp_write_reg(core_if, adpctl.d32);
+	DWC_PRINTF("ADP Probe Finish\n");
+	return 0;
+}
+
+/**
+ * Starts the ADP Sense timer to detect if ADP Sense interrupt is not asserted 
+ * within 3 seconds.
+ *
+ * @param core_if the pointer to core_if strucure.
+ */
+void dwc_otg_adp_sense_timer_start(dwc_otg_core_if_t * core_if)
+{
+	core_if->adp.sense_timer_started = 1;
+	DWC_TIMER_SCHEDULE(core_if->adp.sense_timer, 3000 /* 3 secs */ );
+}
+
+/**
+ * Starts the ADP Sense
+ *
+ * @param core_if the pointer to core_if strucure.
+ */
+uint32_t dwc_otg_adp_sense_start(dwc_otg_core_if_t * core_if)
+{
+	adpctl_data_t adpctl;
+
+	DWC_PRINTF("ADP Sense Start\n");
+
+	/* Unmask ADP sense interrupt and mask all other from the core */
+	adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
+	adpctl.b.adp_sns_int_msk = 1;
+	dwc_otg_adp_write_reg(core_if, adpctl.d32);
+	dwc_otg_disable_global_interrupts(core_if); // vahrama 
+
+	/* Set ADP reset bit*/
+	adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
+	adpctl.b.adpres = 1;
+	dwc_otg_adp_write_reg(core_if, adpctl.d32);
+
+	while (adpctl.b.adpres) {
+		adpctl.d32 = dwc_otg_adp_read_reg(core_if);
+	}
+
+	adpctl.b.adpres = 0;
+	adpctl.b.adpen = 1;
+	adpctl.b.enasns = 1;
+	dwc_otg_adp_write_reg(core_if, adpctl.d32);
+
+	dwc_otg_adp_sense_timer_start(core_if);
+
+	return 0;
+}
+
+/**
+ * Stops the ADP Probing
+ *
+ * @param core_if the pointer to core_if strucure.
+ */
+uint32_t dwc_otg_adp_probe_stop(dwc_otg_core_if_t * core_if)
+{
+
+	adpctl_data_t adpctl;
+	DWC_PRINTF("Stop ADP probe\n");
+	core_if->adp.probe_enabled = 0;
+	core_if->adp.probe_counter = 0;
+	adpctl.d32 = dwc_otg_adp_read_reg(core_if);
+
+	adpctl.b.adpen = 0;
+	adpctl.b.adp_prb_int = 1;
+	adpctl.b.adp_tmout_int = 1;
+	adpctl.b.adp_sns_int = 1;
+	dwc_otg_adp_write_reg(core_if, adpctl.d32);
+
+	return 0;
+}
+
+/**
+ * Stops the ADP Sensing
+ *
+ * @param core_if the pointer to core_if strucure.
+ */
+uint32_t dwc_otg_adp_sense_stop(dwc_otg_core_if_t * core_if)
+{
+	adpctl_data_t adpctl;
+
+	core_if->adp.sense_enabled = 0;
+
+	adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
+	adpctl.b.enasns = 0;
+	adpctl.b.adp_sns_int = 1;
+	dwc_otg_adp_write_reg(core_if, adpctl.d32);
+
+	return 0;
+}
+
+/**
+ * Called to turn on the VBUS after initial ADP probe in host mode.
+ * If port power was already enabled in cil_hcd_start function then
+ * only schedule a timer.
+ *
+ * @param core_if the pointer to core_if structure.
+ */
+void dwc_otg_adp_turnon_vbus(dwc_otg_core_if_t * core_if)
+{
+	hprt0_data_t hprt0 = {.d32 = 0 };
+	hprt0.d32 = dwc_otg_read_hprt0(core_if);
+	DWC_PRINTF("Turn on VBUS for 1.1s, port power is %d\n", hprt0.b.prtpwr);
+
+	if (hprt0.b.prtpwr == 0) {
+		hprt0.b.prtpwr = 1;
+		//DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+	}
+	
+	dwc_otg_adp_vbuson_timer_start(core_if);
+}
+
+/**
+ * Called right after driver is loaded
+ * to perform initial actions for ADP
+ *
+ * @param core_if the pointer to core_if structure.
+ * @param is_host - flag for current mode of operation either from GINTSTS or GPWRDN
+ */
+void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host)
+{
+	gpwrdn_data_t gpwrdn;
+
+	DWC_PRINTF("ADP Initial Start\n");
+	core_if->adp.adp_started = 1;
+
+	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
+	dwc_otg_disable_global_interrupts(core_if);
+	if (is_host) {
+		DWC_PRINTF("HOST MODE\n");
+		/* Enable Power Down Logic Interrupt*/
+		gpwrdn.d32 = 0;
+		gpwrdn.b.pmuintsel = 1;
+		gpwrdn.b.pmuactv = 1;
+		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
+		/* Initialize first ADP probe to obtain Ramp Time value */
+		core_if->adp.initial_probe = 1;
+		dwc_otg_adp_probe_start(core_if);
+	} else {
+		gotgctl_data_t gotgctl;
+		gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
+		DWC_PRINTF("DEVICE MODE\n");
+		if (gotgctl.b.bsesvld == 0) {
+			/* Enable Power Down Logic Interrupt*/
+			gpwrdn.d32 = 0;
+			DWC_PRINTF("VBUS is not valid - start ADP probe\n");
+			gpwrdn.b.pmuintsel = 1;
+			gpwrdn.b.pmuactv = 1;
+			DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
+			core_if->adp.initial_probe = 1;
+			dwc_otg_adp_probe_start(core_if);
+		} else {
+			DWC_PRINTF("VBUS is valid - initialize core as a Device\n");
+			core_if->op_state = B_PERIPHERAL;
+			dwc_otg_core_init(core_if);
+			dwc_otg_enable_global_interrupts(core_if);
+			cil_pcd_start(core_if);
+			dwc_otg_dump_global_registers(core_if);
+			dwc_otg_dump_dev_registers(core_if);
+		}
+	}
+}
+
+void dwc_otg_adp_init(dwc_otg_core_if_t * core_if)
+{
+	core_if->adp.adp_started = 0;
+	core_if->adp.initial_probe = 0;
+	core_if->adp.probe_timer_values[0] = -1;
+	core_if->adp.probe_timer_values[1] = -1;
+	core_if->adp.probe_enabled = 0;
+	core_if->adp.sense_enabled = 0;
+	core_if->adp.sense_timer_started = 0;
+	core_if->adp.vbuson_timer_started = 0;
+	core_if->adp.probe_counter = 0;
+	core_if->adp.gpwrdn = 0;
+	core_if->adp.attached = DWC_OTG_ADP_UNKOWN;
+	/* Initialize timers */
+	core_if->adp.sense_timer =
+	    DWC_TIMER_ALLOC("ADP SENSE TIMER", adp_sense_timeout, core_if);
+	core_if->adp.vbuson_timer =
+	    DWC_TIMER_ALLOC("ADP VBUS ON TIMER", adp_vbuson_timeout, core_if);
+	if (!core_if->adp.sense_timer || !core_if->adp.vbuson_timer)
+	{
+		DWC_ERROR("Could not allocate memory for ADP timers\n");
+	}
+}
+
+void dwc_otg_adp_remove(dwc_otg_core_if_t * core_if)
+{
+	gpwrdn_data_t gpwrdn = { .d32 = 0 };
+	gpwrdn.b.pmuintsel = 1;
+	gpwrdn.b.pmuactv = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+
+	if (core_if->adp.probe_enabled)		
+		dwc_otg_adp_probe_stop(core_if);
+	if (core_if->adp.sense_enabled)		
+		dwc_otg_adp_sense_stop(core_if);
+	if (core_if->adp.sense_timer_started)		
+		DWC_TIMER_CANCEL(core_if->adp.sense_timer);
+	if (core_if->adp.vbuson_timer_started)		
+		DWC_TIMER_CANCEL(core_if->adp.vbuson_timer);
+	DWC_TIMER_FREE(core_if->adp.sense_timer);
+	DWC_TIMER_FREE(core_if->adp.vbuson_timer);
+}
+
+/////////////////////////////////////////////////////////////////////
+////////////// ADP Interrupt Handlers ///////////////////////////////
+/////////////////////////////////////////////////////////////////////
+/**
+ * This function sets Ramp Timer values
+ */
+static uint32_t set_timer_value(dwc_otg_core_if_t * core_if, uint32_t val)
+{
+	if (core_if->adp.probe_timer_values[0] == -1) {
+		core_if->adp.probe_timer_values[0] = val;
+		core_if->adp.probe_timer_values[1] = -1;
+		return 1;
+	} else {
+		core_if->adp.probe_timer_values[1] =
+		    core_if->adp.probe_timer_values[0];
+		core_if->adp.probe_timer_values[0] = val;
+		return 0;
+	}
+}
+
+/**
+ * This function compares Ramp Timer values
+ */
+static uint32_t compare_timer_values(dwc_otg_core_if_t * core_if)
+{
+	uint32_t diff;
+	if (core_if->adp.probe_timer_values[0]>=core_if->adp.probe_timer_values[1])
+			diff = core_if->adp.probe_timer_values[0]-core_if->adp.probe_timer_values[1];
+	else
+			diff = core_if->adp.probe_timer_values[1]-core_if->adp.probe_timer_values[0];   	
+	if(diff < 2) {
+		return 0;
+	} else {
+		return 1;
+	}
+}
+
+/**
+ * This function handles ADP Probe Interrupts
+ */
+static int32_t dwc_otg_adp_handle_prb_intr(dwc_otg_core_if_t * core_if,
+						 uint32_t val)
+{
+	adpctl_data_t adpctl = {.d32 = 0 };
+	gpwrdn_data_t gpwrdn, temp;
+	adpctl.d32 = val;
+
+	temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
+	core_if->adp.probe_counter++;
+	core_if->adp.gpwrdn = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
+	if (adpctl.b.rtim == 0 && !temp.b.idsts){
+		DWC_PRINTF("RTIM value is 0\n");	
+		goto exit;
+	}
+	if (set_timer_value(core_if, adpctl.b.rtim) &&
+	    core_if->adp.initial_probe) {
+		core_if->adp.initial_probe = 0;
+		dwc_otg_adp_probe_stop(core_if);
+		gpwrdn.d32 = 0;
+		gpwrdn.b.pmuactv = 1;
+		gpwrdn.b.pmuintsel = 1;
+		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+		DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
+
+		/* check which value is for device mode and which for Host mode */
+		if (!temp.b.idsts) {	/* considered host mode value is 0 */
+			/*
+			 * Turn on VBUS after initial ADP probe.
+			 */
+			core_if->op_state = A_HOST;
+			dwc_otg_enable_global_interrupts(core_if);
+			DWC_SPINUNLOCK(core_if->lock);
+			cil_hcd_start(core_if);
+			dwc_otg_adp_turnon_vbus(core_if);
+			DWC_SPINLOCK(core_if->lock);
+		} else {
+			/*
+			 * Initiate SRP after initial ADP probe.
+			 */
+			dwc_otg_enable_global_interrupts(core_if);
+			dwc_otg_initiate_srp(core_if);
+		}
+	} else if (core_if->adp.probe_counter > 2){
+		gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
+		if (compare_timer_values(core_if)) {
+			DWC_PRINTF("Difference in timer values !!! \n");
+//                      core_if->adp.attached = DWC_OTG_ADP_ATTACHED;
+			dwc_otg_adp_probe_stop(core_if);
+
+			/* Power on the core */
+			if (core_if->power_down == 2) {
+				gpwrdn.b.pwrdnswtch = 1;
+				DWC_MODIFY_REG32(&core_if->core_global_regs->
+						 gpwrdn, 0, gpwrdn.d32);
+			}
+
+			/* check which value is for device mode and which for Host mode */
+			if (!temp.b.idsts) {	/* considered host mode value is 0 */
+				/* Disable Interrupt from Power Down Logic */
+				gpwrdn.d32 = 0;
+				gpwrdn.b.pmuintsel = 1;
+				gpwrdn.b.pmuactv = 1;
+				DWC_MODIFY_REG32(&core_if->core_global_regs->
+						 gpwrdn, gpwrdn.d32, 0);
+
+				/*
+				 * Initialize the Core for Host mode.
+				 */
+				core_if->op_state = A_HOST;
+				dwc_otg_core_init(core_if);
+				dwc_otg_enable_global_interrupts(core_if);
+				cil_hcd_start(core_if);
+			} else {
+				gotgctl_data_t gotgctl;
+				/* Mask SRP detected interrupt from Power Down Logic */
+				gpwrdn.d32 = 0;
+				gpwrdn.b.srp_det_msk = 1;
+				DWC_MODIFY_REG32(&core_if->core_global_regs->
+						 gpwrdn, gpwrdn.d32, 0);
+
+				/* Disable Power Down Logic */
+				gpwrdn.d32 = 0;
+				gpwrdn.b.pmuintsel = 1;
+				gpwrdn.b.pmuactv = 1;
+				DWC_MODIFY_REG32(&core_if->core_global_regs->
+						 gpwrdn, gpwrdn.d32, 0);
+
+				/*
+				 * Initialize the Core for Device mode.
+				 */
+				core_if->op_state = B_PERIPHERAL;
+				dwc_otg_core_init(core_if);
+				dwc_otg_enable_global_interrupts(core_if);
+				cil_pcd_start(core_if);
+
+				gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
+				if (!gotgctl.b.bsesvld) {
+					dwc_otg_initiate_srp(core_if);
+				}
+			}
+		}
+		if (core_if->power_down == 2) {
+			if (gpwrdn.b.bsessvld) {
+				/* Mask SRP detected interrupt from Power Down Logic */
+				gpwrdn.d32 = 0;
+				gpwrdn.b.srp_det_msk = 1;
+				DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+				
+				/* Disable Power Down Logic */
+				gpwrdn.d32 = 0;
+				gpwrdn.b.pmuactv = 1;
+				DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+
+				/*
+				 * Initialize the Core for Device mode.
+				 */
+				core_if->op_state = B_PERIPHERAL;
+				dwc_otg_core_init(core_if);
+				dwc_otg_enable_global_interrupts(core_if);
+				cil_pcd_start(core_if);
+			}
+		}
+	}
+exit:
+	/* Clear interrupt */
+	adpctl.d32 = dwc_otg_adp_read_reg(core_if);
+	adpctl.b.adp_prb_int = 1;
+	dwc_otg_adp_write_reg(core_if, adpctl.d32);
+
+	return 0;
+}
+
+/**
+ * This function hadles ADP Sense Interrupt
+ */
+static int32_t dwc_otg_adp_handle_sns_intr(dwc_otg_core_if_t * core_if)
+{
+	adpctl_data_t adpctl;
+	/* Stop ADP Sense timer */
+	DWC_TIMER_CANCEL(core_if->adp.sense_timer);
+
+	/* Restart ADP Sense timer */
+	dwc_otg_adp_sense_timer_start(core_if);
+	
+	/* Clear interrupt */
+	adpctl.d32 = dwc_otg_adp_read_reg(core_if);
+	adpctl.b.adp_sns_int = 1;
+	dwc_otg_adp_write_reg(core_if, adpctl.d32);
+
+	return 0;
+}
+
+/**
+ * This function handles ADP Probe Interrupts
+ */
+static int32_t dwc_otg_adp_handle_prb_tmout_intr(dwc_otg_core_if_t * core_if,
+						 uint32_t val)
+{
+	adpctl_data_t adpctl = {.d32 = 0 };
+	adpctl.d32 = val;
+	set_timer_value(core_if, adpctl.b.rtim);
+	
+	/* Clear interrupt */
+	adpctl.d32 = dwc_otg_adp_read_reg(core_if);
+	adpctl.b.adp_tmout_int = 1;
+	dwc_otg_adp_write_reg(core_if, adpctl.d32);
+
+	return 0;
+}
+
+/**
+ * ADP Interrupt handler.
+ *
+ */
+int32_t dwc_otg_adp_handle_intr(dwc_otg_core_if_t * core_if)
+{
+	int retval = 0;
+	adpctl_data_t adpctl = {.d32 = 0};
+
+	adpctl.d32 = dwc_otg_adp_read_reg(core_if);
+	DWC_PRINTF("ADPCTL = %08x\n",adpctl.d32);
+
+	if (adpctl.b.adp_sns_int & adpctl.b.adp_sns_int_msk) {
+		DWC_PRINTF("ADP Sense interrupt\n");
+		retval |= dwc_otg_adp_handle_sns_intr(core_if);
+	}
+	if (adpctl.b.adp_tmout_int & adpctl.b.adp_tmout_int_msk) {
+		DWC_PRINTF("ADP timeout interrupt\n");
+		retval |= dwc_otg_adp_handle_prb_tmout_intr(core_if, adpctl.d32);
+	}
+	if (adpctl.b.adp_prb_int & adpctl.b.adp_prb_int_msk) {
+		DWC_PRINTF("ADP Probe interrupt\n");
+		adpctl.b.adp_prb_int = 1;	
+		retval |= dwc_otg_adp_handle_prb_intr(core_if, adpctl.d32);
+	}
+
+//	dwc_otg_adp_modify_reg(core_if, adpctl.d32, 0);
+	//dwc_otg_adp_write_reg(core_if, adpctl.d32);
+	DWC_PRINTF("RETURN FROM ADP ISR\n");
+
+	return retval;
+}
+
+/**
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ */
+int32_t dwc_otg_adp_handle_srp_intr(dwc_otg_core_if_t * core_if)
+{
+
+#ifndef DWC_HOST_ONLY
+	hprt0_data_t hprt0;
+	gpwrdn_data_t gpwrdn;
+	DWC_DEBUGPL(DBG_ANY, "++ Power Down Logic Session Request Interrupt++\n");
+
+	gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
+	/* check which value is for device mode and which for Host mode */
+	if (!gpwrdn.b.idsts) {	/* considered host mode value is 0 */
+		DWC_PRINTF("SRP: Host mode\n");
+
+		if (core_if->adp_enable) {
+			dwc_otg_adp_probe_stop(core_if);
+
+			/* Power on the core */
+			if (core_if->power_down == 2) {
+				gpwrdn.b.pwrdnswtch = 1;
+				DWC_MODIFY_REG32(&core_if->core_global_regs->
+						 gpwrdn, 0, gpwrdn.d32);
+			}
+
+			core_if->op_state = A_HOST;
+			dwc_otg_core_init(core_if);
+			dwc_otg_enable_global_interrupts(core_if);
+			cil_hcd_start(core_if);
+		}
+
+		/* Turn on the port power bit. */
+		hprt0.d32 = dwc_otg_read_hprt0(core_if);
+		hprt0.b.prtpwr = 1;
+		DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+
+		/* Start the Connection timer. So a message can be displayed
+		 * if connect does not occur within 10 seconds. */
+		cil_hcd_session_start(core_if);
+	} else {
+		DWC_PRINTF("SRP: Device mode %s\n", __FUNCTION__);
+		if (core_if->adp_enable) {
+			dwc_otg_adp_probe_stop(core_if);
+
+			/* Power on the core */
+			if (core_if->power_down == 2) {
+				gpwrdn.b.pwrdnswtch = 1;
+				DWC_MODIFY_REG32(&core_if->core_global_regs->
+						 gpwrdn, 0, gpwrdn.d32);
+			}
+
+			gpwrdn.d32 = 0;
+			gpwrdn.b.pmuactv = 0;
+			DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
+					 gpwrdn.d32);
+
+			core_if->op_state = B_PERIPHERAL;
+			dwc_otg_core_init(core_if);
+			dwc_otg_enable_global_interrupts(core_if);
+			cil_pcd_start(core_if);
+		}
+	}
+#endif
+	return 1;
+}
diff --git a/drivers/usb/dwc_otg/dwc_otg_adp.h b/drivers/usb/dwc_otg/dwc_otg_adp.h
new file mode 100644
index 0000000..d8c3f85
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_adp.h
@@ -0,0 +1,80 @@
+/* ==========================================================================
+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_adp.h $
+ * $Revision: #7 $
+ * $Date: 2011/10/24 $
+ * $Change: 1871159 $
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+#ifndef __DWC_OTG_ADP_H__
+#define __DWC_OTG_ADP_H__
+
+/**
+ * @file
+ *
+ * This file contains the Attach Detect Protocol interfaces and defines
+ * (functions) and structures for Linux.
+ *
+ */
+
+#define DWC_OTG_ADP_UNATTACHED	0
+#define DWC_OTG_ADP_ATTACHED	1
+#define DWC_OTG_ADP_UNKOWN	2
+
+typedef struct dwc_otg_adp {
+	uint32_t adp_started;	
+	uint32_t initial_probe;
+	int32_t probe_timer_values[2];
+	uint32_t probe_enabled;
+	uint32_t sense_enabled;
+	dwc_timer_t *sense_timer;
+	uint32_t sense_timer_started;
+	dwc_timer_t *vbuson_timer;
+	uint32_t vbuson_timer_started;
+	uint32_t attached;
+	uint32_t probe_counter;
+	uint32_t gpwrdn;
+} dwc_otg_adp_t;
+
+/**
+ * Attach Detect Protocol functions
+ */
+
+extern void dwc_otg_adp_write_reg(dwc_otg_core_if_t * core_if, uint32_t value);
+extern uint32_t dwc_otg_adp_read_reg(dwc_otg_core_if_t * core_if);
+extern uint32_t dwc_otg_adp_probe_start(dwc_otg_core_if_t * core_if);
+extern uint32_t dwc_otg_adp_sense_start(dwc_otg_core_if_t * core_if);
+extern uint32_t dwc_otg_adp_probe_stop(dwc_otg_core_if_t * core_if);
+extern uint32_t dwc_otg_adp_sense_stop(dwc_otg_core_if_t * core_if);
+extern void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host);
+extern void dwc_otg_adp_init(dwc_otg_core_if_t * core_if);
+extern void dwc_otg_adp_remove(dwc_otg_core_if_t * core_if);
+extern int32_t dwc_otg_adp_handle_intr(dwc_otg_core_if_t * core_if);
+extern int32_t dwc_otg_adp_handle_srp_intr(dwc_otg_core_if_t * core_if);
+
+#endif //__DWC_OTG_ADP_H__
diff --git a/drivers/usb/dwc_otg/dwc_otg_attr.c b/drivers/usb/dwc_otg/dwc_otg_attr.c
new file mode 100644
index 0000000..17b0c23
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_attr.c
@@ -0,0 +1,1433 @@
+/* ==========================================================================
+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_attr.c $
+ * $Revision: #44 $
+ * $Date: 2010/11/29 $
+ * $Change: 1636033 $
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+/** @file
+ *
+ * The diagnostic interface will provide access to the controller for
+ * bringing up the hardware and testing.  The Linux driver attributes
+ * feature will be used to provide the Linux Diagnostic
+ * Interface. These attributes are accessed through sysfs.
+ */
+
+/** @page "Linux Module Attributes"
+ *
+ * The Linux module attributes feature is used to provide the Linux
+ * Diagnostic Interface.  These attributes are accessed through sysfs.
+ * The diagnostic interface will provide access to the controller for
+ * bringing up the hardware and testing.
+
+ The following table shows the attributes.
+ <table>
+ <tr>
+ <td><b> Name</b></td>
+ <td><b> Description</b></td>
+ <td><b> Access</b></td>
+ </tr>
+
+ <tr>
+ <td> mode </td>
+ <td> Returns the current mode: 0 for device mode, 1 for host mode</td>
+ <td> Read</td>
+ </tr>
+
+ <tr>
+ <td> hnpcapable </td>
+ <td> Gets or sets the "HNP-capable" bit in the Core USB Configuraton Register.
+ Read returns the current value.</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> srpcapable </td>
+ <td> Gets or sets the "SRP-capable" bit in the Core USB Configuraton Register.
+ Read returns the current value.</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> hsic_connect </td>
+ <td> Gets or sets the "HSIC-Connect" bit in the GLPMCFG Register.
+ Read returns the current value.</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> inv_sel_hsic </td>
+ <td> Gets or sets the "Invert Select HSIC" bit in the GLPMFG Register.
+ Read returns the current value.</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> hnp </td>
+ <td> Initiates the Host Negotiation Protocol.  Read returns the status.</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> srp </td>
+ <td> Initiates the Session Request Protocol.  Read returns the status.</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> buspower </td>
+ <td> Gets or sets the Power State of the bus (0 - Off or 1 - On)</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> bussuspend </td>
+ <td> Suspends the USB bus.</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> busconnected </td>
+ <td> Gets the connection status of the bus</td>
+ <td> Read</td>
+ </tr>
+
+ <tr>
+ <td> gotgctl </td>
+ <td> Gets or sets the Core Control Status Register.</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> gusbcfg </td>
+ <td> Gets or sets the Core USB Configuration Register</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> grxfsiz </td>
+ <td> Gets or sets the Receive FIFO Size Register</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> gnptxfsiz </td>
+ <td> Gets or sets the non-periodic Transmit Size Register</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> gpvndctl </td>
+ <td> Gets or sets the PHY Vendor Control Register</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> ggpio </td>
+ <td> Gets the value in the lower 16-bits of the General Purpose IO Register
+ or sets the upper 16 bits.</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> guid </td>
+ <td> Gets or sets the value of the User ID Register</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> gsnpsid </td>
+ <td> Gets the value of the Synopsys ID Regester</td>
+ <td> Read</td>
+ </tr>
+
+ <tr>
+ <td> devspeed </td>
+ <td> Gets or sets the device speed setting in the DCFG register</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> enumspeed </td>
+ <td> Gets the device enumeration Speed.</td>
+ <td> Read</td>
+ </tr>
+
+ <tr>
+ <td> hptxfsiz </td>
+ <td> Gets the value of the Host Periodic Transmit FIFO</td>
+ <td> Read</td>
+ </tr>
+
+ <tr>
+ <td> hprt0 </td>
+ <td> Gets or sets the value in the Host Port Control and Status Register</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> regoffset </td>
+ <td> Sets the register offset for the next Register Access</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> regvalue </td>
+ <td> Gets or sets the value of the register at the offset in the regoffset attribute.</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> remote_wakeup </td>
+ <td> On read, shows the status of Remote Wakeup. On write, initiates a remote
+ wakeup of the host. When bit 0 is 1 and Remote Wakeup is enabled, the Remote
+ Wakeup signalling bit in the Device Control Register is set for 1
+ milli-second.</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> rem_wakeup_pwrdn </td>
+ <td> On read, shows the status core - hibernated or not. On write, initiates
+ a remote wakeup of the device from Hibernation. </td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> mode_ch_tim_en </td>
+ <td> This bit is used to enable or disable the host core to wait for 200 PHY
+ clock cycles at the end of Resume to change the opmode signal to the PHY to 00
+ after Suspend or LPM. </td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> fr_interval </td>
+ <td> On read, shows the value of HFIR Frame Interval. On write, dynamically
+ reload HFIR register during runtime. The application can write a value to this
+ register only after the Port Enable bit of the Host Port Control and Status
+ register (HPRT.PrtEnaPort) has been set </td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> disconnect_us </td>
+ <td> On read, shows the status of disconnect_device_us. On write, sets disconnect_us
+ which causes soft disconnect for 100us. Applicable only for device mode of operation.</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> regdump </td>
+ <td> Dumps the contents of core registers.</td>
+ <td> Read</td>
+ </tr>
+
+ <tr>
+ <td> spramdump </td>
+ <td> Dumps the contents of core registers.</td>
+ <td> Read</td>
+ </tr>
+
+ <tr>
+ <td> hcddump </td>
+ <td> Dumps the current HCD state.</td>
+ <td> Read</td>
+ </tr>
+
+ <tr>
+ <td> hcd_frrem </td>
+ <td> Shows the average value of the Frame Remaining
+ field in the Host Frame Number/Frame Remaining register when an SOF interrupt
+ occurs. This can be used to determine the average interrupt latency. Also
+ shows the average Frame Remaining value for start_transfer and the "a" and
+ "b" sample points. The "a" and "b" sample points may be used during debugging
+ bto determine how long it takes to execute a section of the HCD code.</td>
+ <td> Read</td>
+ </tr>
+
+ <tr>
+ <td> rd_reg_test </td>
+ <td> Displays the time required to read the GNPTXFSIZ register many times
+ (the output shows the number of times the register is read).
+ <td> Read</td>
+ </tr>
+
+ <tr>
+ <td> wr_reg_test </td>
+ <td> Displays the time required to write the GNPTXFSIZ register many times
+ (the output shows the number of times the register is written).
+ <td> Read</td>
+ </tr>
+
+ <tr>
+ <td> lpm_response </td>
+ <td> Gets or sets lpm_response mode. Applicable only in device mode.
+ <td> Write</td>
+ </tr>
+
+ <tr>
+ <td> sleep_status </td>
+ <td> Shows sleep status of device.
+ <td> Read</td>
+ </tr>
+
+ </table>
+
+ Example usage:
+ To get the current mode:
+ cat /sys/devices/lm0/mode
+
+ To power down the USB:
+ echo 0 > /sys/devices/lm0/buspower
+ */
+
+#include "dwc_otg_os_dep.h"
+#include "dwc_os.h"
+#include "dwc_otg_driver.h"
+#include "dwc_otg_attr.h"
+#include "dwc_otg_core_if.h"
+#include "dwc_otg_pcd_if.h"
+#include "dwc_otg_hcd_if.h"
+
+/*
+ * MACROs for defining sysfs attribute
+ */
+#ifdef LM_INTERFACE
+
+#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
+static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
+{ \
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);		\
+	uint32_t val; \
+	val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
+	return sprintf (buf, "%s = 0x%x\n", _string_, val); \
+}
+#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
+static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
+					const char *buf, size_t count) \
+{ \
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
+	uint32_t set = simple_strtoul(buf, NULL, 16); \
+	dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
+	return count; \
+}
+
+#elif defined(PCI_INTERFACE)
+
+#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
+static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
+{ \
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);	\
+	uint32_t val; \
+	val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
+	return sprintf (buf, "%s = 0x%x\n", _string_, val); \
+}
+#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
+static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
+					const char *buf, size_t count) \
+{ \
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);  \
+	uint32_t set = simple_strtoul(buf, NULL, 16); \
+	dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
+	return count; \
+}
+#else
+
+#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
+static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
+{ \
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);		\
+	uint32_t val; \
+	val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
+	return sprintf (buf, "%s = 0x%x\n", _string_, val); \
+}
+#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
+static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
+					const char *buf, size_t count) \
+{ \
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev); \
+	uint32_t set = simple_strtoul(buf, NULL, 16); \
+	dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
+	return count; \
+}
+
+
+#endif
+
+/*
+ * MACROs for defining sysfs attribute for 32-bit registers
+ */
+#ifdef LM_INTERFACE
+#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
+static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
+{ \
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
+	uint32_t val; \
+	val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
+	return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
+}
+#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
+static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
+					const char *buf, size_t count) \
+{ \
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
+	uint32_t val = simple_strtoul(buf, NULL, 16); \
+	dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
+	return count; \
+}
+#elif defined(PCI_INTERFACE)
+#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
+static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
+{ \
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);  \
+	uint32_t val; \
+	val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
+	return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
+}
+#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
+static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
+					const char *buf, size_t count) \
+{ \
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);  \
+	uint32_t val = simple_strtoul(buf, NULL, 16); \
+	dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
+	return count; \
+}
+#else
+#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
+static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
+{ \
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev); \
+	uint32_t val; \
+	val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
+	return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
+}
+#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
+static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
+					const char *buf, size_t count) \
+{ \
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev); \
+	uint32_t val = simple_strtoul(buf, NULL, 16); \
+	dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
+	return count; \
+}
+#endif
+
+#define DWC_OTG_DEVICE_ATTR_BITFIELD_RW(_otg_attr_name_,_string_) \
+DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
+DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
+DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
+
+#define DWC_OTG_DEVICE_ATTR_BITFIELD_RO(_otg_attr_name_,_string_) \
+DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
+DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
+
+#define DWC_OTG_DEVICE_ATTR_REG32_RW(_otg_attr_name_,_addr_,_string_) \
+DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
+DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
+DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
+
+#define DWC_OTG_DEVICE_ATTR_REG32_RO(_otg_attr_name_,_addr_,_string_) \
+DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
+DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
+
+/** @name Functions for Show/Store of Attributes */
+/**@{*/
+
+/**
+ * Show the register offset of the Register Access.
+ */
+static ssize_t regoffset_show(struct device *_dev,
+			      struct device_attribute *attr, char *buf)
+{
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+
+	return snprintf(buf, sizeof("0xFFFFFFFF\n") + 1, "0x%08x\n",
+			otg_dev->os_dep.reg_offset);
+}
+
+/**
+ * Set the register offset for the next Register Access 	Read/Write
+ */
+static ssize_t regoffset_store(struct device *_dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+
+	uint32_t offset = simple_strtoul(buf, NULL, 16);
+#ifdef LM_INTERFACE
+	if (offset < SZ_256K) {
+#elif  defined(PCI_INTERFACE)
+	if (offset < 0x00040000) {
+#else
+	if (offset < 0x00040000) {
+#endif
+		otg_dev->os_dep.reg_offset = offset;
+	} else {
+		dev_err(_dev, "invalid offset\n");
+	}
+
+	return count;
+}
+
+DEVICE_ATTR(regoffset, S_IRUGO | S_IWUSR, regoffset_show, regoffset_store);
+
+/**
+ * Show the value of the register at the offset in the reg_offset
+ * attribute.
+ */
+static ssize_t regvalue_show(struct device *_dev,
+			     struct device_attribute *attr, char *buf)
+{
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+
+	uint32_t val;
+	volatile uint32_t *addr;
+
+	if (otg_dev->os_dep.reg_offset != 0xFFFFFFFF && 0 != otg_dev->os_dep.base) {
+		/* Calculate the address */
+		addr = (uint32_t *) (otg_dev->os_dep.reg_offset +
+				     (uint8_t *) otg_dev->os_dep.base);
+		val = DWC_READ_REG32(addr);
+		return snprintf(buf,
+				sizeof("Reg@0xFFFFFFFF = 0xFFFFFFFF\n") + 1,
+				"Reg@0x%06x = 0x%08x\n", otg_dev->os_dep.reg_offset,
+				val);
+	} else {
+		dev_err(_dev, "Invalid offset (0x%0x)\n", otg_dev->os_dep.reg_offset);
+		return sprintf(buf, "invalid offset\n");
+	}
+}
+
+/**
+ * Store the value in the register at the offset in the reg_offset
+ * attribute.
+ *
+ */
+static ssize_t regvalue_store(struct device *_dev,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+
+	volatile uint32_t *addr;
+	uint32_t val = simple_strtoul(buf, NULL, 16);
+	//dev_dbg(_dev, "Offset=0x%08x Val=0x%08x\n", otg_dev->reg_offset, val);
+	if (otg_dev->os_dep.reg_offset != 0xFFFFFFFF && 0 != otg_dev->os_dep.base) {
+		/* Calculate the address */
+		addr = (uint32_t *) (otg_dev->os_dep.reg_offset +
+				     (uint8_t *) otg_dev->os_dep.base);
+		DWC_WRITE_REG32(addr, val);
+	} else {
+		dev_err(_dev, "Invalid Register Offset (0x%08x)\n",
+			otg_dev->os_dep.reg_offset);
+	}
+	return count;
+}
+
+DEVICE_ATTR(regvalue, S_IRUGO | S_IWUSR, regvalue_show, regvalue_store);
+
+/*
+ * Attributes
+ */
+DWC_OTG_DEVICE_ATTR_BITFIELD_RO(mode, "Mode");
+DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hnpcapable, "HNPCapable");
+DWC_OTG_DEVICE_ATTR_BITFIELD_RW(srpcapable, "SRPCapable");
+DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hsic_connect, "HSIC Connect");
+DWC_OTG_DEVICE_ATTR_BITFIELD_RW(inv_sel_hsic, "Invert Select HSIC");
+
+//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(buspower,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode");
+//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(bussuspend,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode");
+DWC_OTG_DEVICE_ATTR_BITFIELD_RO(busconnected, "Bus Connected");
+
+DWC_OTG_DEVICE_ATTR_REG32_RW(gotgctl, 0, "GOTGCTL");
+DWC_OTG_DEVICE_ATTR_REG32_RW(gusbcfg,
+			     &(otg_dev->core_if->core_global_regs->gusbcfg),
+			     "GUSBCFG");
+DWC_OTG_DEVICE_ATTR_REG32_RW(grxfsiz,
+			     &(otg_dev->core_if->core_global_regs->grxfsiz),
+			     "GRXFSIZ");
+DWC_OTG_DEVICE_ATTR_REG32_RW(gnptxfsiz,
+			     &(otg_dev->core_if->core_global_regs->gnptxfsiz),
+			     "GNPTXFSIZ");
+DWC_OTG_DEVICE_ATTR_REG32_RW(gpvndctl,
+			     &(otg_dev->core_if->core_global_regs->gpvndctl),
+			     "GPVNDCTL");
+DWC_OTG_DEVICE_ATTR_REG32_RW(ggpio,
+			     &(otg_dev->core_if->core_global_regs->ggpio),
+			     "GGPIO");
+DWC_OTG_DEVICE_ATTR_REG32_RW(guid, &(otg_dev->core_if->core_global_regs->guid),
+			     "GUID");
+DWC_OTG_DEVICE_ATTR_REG32_RO(gsnpsid,
+			     &(otg_dev->core_if->core_global_regs->gsnpsid),
+			     "GSNPSID");
+DWC_OTG_DEVICE_ATTR_BITFIELD_RW(devspeed, "Device Speed");
+DWC_OTG_DEVICE_ATTR_BITFIELD_RO(enumspeed, "Device Enumeration Speed");
+
+DWC_OTG_DEVICE_ATTR_REG32_RO(hptxfsiz,
+			     &(otg_dev->core_if->core_global_regs->hptxfsiz),
+			     "HPTXFSIZ");
+DWC_OTG_DEVICE_ATTR_REG32_RW(hprt0, otg_dev->core_if->host_if->hprt0, "HPRT0");
+
+/**
+ * @todo Add code to initiate the HNP.
+ */
+/**
+ * Show the HNP status bit
+ */
+static ssize_t hnp_show(struct device *_dev,
+			struct device_attribute *attr, char *buf)
+{
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+	return sprintf(buf, "HstNegScs = 0x%x\n",
+		       dwc_otg_get_hnpstatus(otg_dev->core_if));
+}
+
+/**
+ * Set the HNP Request bit
+ */
+static ssize_t hnp_store(struct device *_dev,
+			 struct device_attribute *attr,
+			 const char *buf, size_t count)
+{
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+	uint32_t in = simple_strtoul(buf, NULL, 16);
+	dwc_otg_set_hnpreq(otg_dev->core_if, in);
+	return count;
+}
+
+DEVICE_ATTR(hnp, 0644, hnp_show, hnp_store);
+
+/**
+ * @todo Add code to initiate the SRP.
+ */
+/**
+ * Show the SRP status bit
+ */
+static ssize_t srp_show(struct device *_dev,
+			struct device_attribute *attr, char *buf)
+{
+#ifndef DWC_HOST_ONLY
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+	return sprintf(buf, "SesReqScs = 0x%x\n",
+		       dwc_otg_get_srpstatus(otg_dev->core_if));
+#else
+	return sprintf(buf, "Host Only Mode!\n");
+#endif
+}
+
+/**
+ * Set the SRP Request bit
+ */
+static ssize_t srp_store(struct device *_dev,
+			 struct device_attribute *attr,
+			 const char *buf, size_t count)
+{
+#ifndef DWC_HOST_ONLY
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+	dwc_otg_pcd_initiate_srp(otg_dev->pcd);
+#endif
+	return count;
+}
+
+DEVICE_ATTR(srp, 0644, srp_show, srp_store);
+
+/**
+ * @todo Need to do more for power on/off?
+ */
+/**
+ * Show the Bus Power status
+ */
+static ssize_t buspower_show(struct device *_dev,
+			     struct device_attribute *attr, char *buf)
+{
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+	return sprintf(buf, "Bus Power = 0x%x\n",
+		       dwc_otg_get_prtpower(otg_dev->core_if));
+}
+
+/**
+ * Set the Bus Power status
+ */
+static ssize_t buspower_store(struct device *_dev,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+	uint32_t on = simple_strtoul(buf, NULL, 16);
+	dwc_otg_set_prtpower(otg_dev->core_if, on);
+	return count;
+}
+
+DEVICE_ATTR(buspower, 0644, buspower_show, buspower_store);
+
+/**
+ * @todo Need to do more for suspend?
+ */
+/**
+ * Show the Bus Suspend status
+ */
+static ssize_t bussuspend_show(struct device *_dev,
+			       struct device_attribute *attr, char *buf)
+{
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+
+	return sprintf(buf, "Bus Suspend = 0x%x\n",
+		       dwc_otg_get_prtsuspend(otg_dev->core_if));
+}
+
+/**
+ * Set the Bus Suspend status
+ */
+static ssize_t bussuspend_store(struct device *_dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+
+	uint32_t in = simple_strtoul(buf, NULL, 16);
+	dwc_otg_set_prtsuspend(otg_dev->core_if, in);
+	return count;
+}
+
+DEVICE_ATTR(bussuspend, 0644, bussuspend_show, bussuspend_store);
+
+/**
+ * Show the Mode Change Ready Timer status
+ */
+static ssize_t mode_ch_tim_en_show(struct device *_dev,
+				   struct device_attribute *attr, char *buf)
+{
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+
+	return sprintf(buf, "Mode Change Ready Timer Enable = 0x%x\n",
+		       dwc_otg_get_mode_ch_tim(otg_dev->core_if));
+}
+
+/**
+ * Set the Mode Change Ready Timer status
+ */
+static ssize_t mode_ch_tim_en_store(struct device *_dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+
+	uint32_t in = simple_strtoul(buf, NULL, 16);
+	dwc_otg_set_mode_ch_tim(otg_dev->core_if, in);
+	return count;
+}
+
+DEVICE_ATTR(mode_ch_tim_en, 0644, mode_ch_tim_en_show, mode_ch_tim_en_store);
+
+/**
+ * Show the value of HFIR Frame Interval bitfield
+ */
+static ssize_t fr_interval_show(struct device *_dev,
+				struct device_attribute *attr, char *buf)
+{
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+
+	return sprintf(buf, "Frame Interval = 0x%x\n",
+		       dwc_otg_get_fr_interval(otg_dev->core_if));
+}
+
+/**
+ * Set the HFIR Frame Interval value
+ */
+static ssize_t fr_interval_store(struct device *_dev,
+				 struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+
+	uint32_t in = simple_strtoul(buf, NULL, 10);
+	dwc_otg_set_fr_interval(otg_dev->core_if, in);
+	return count;
+}
+
+DEVICE_ATTR(fr_interval, 0644, fr_interval_show, fr_interval_store);
+
+/**
+ * Show the status of Remote Wakeup.
+ */
+static ssize_t remote_wakeup_show(struct device *_dev,
+				  struct device_attribute *attr, char *buf)
+{
+#ifndef DWC_HOST_ONLY
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+
+	return sprintf(buf,
+		       "Remote Wakeup Sig = %d Enabled = %d LPM Remote Wakeup = %d\n",
+		       dwc_otg_get_remotewakesig(otg_dev->core_if),
+		       dwc_otg_pcd_get_rmwkup_enable(otg_dev->pcd),
+		       dwc_otg_get_lpm_remotewakeenabled(otg_dev->core_if));
+#else
+	return sprintf(buf, "Host Only Mode!\n");
+#endif /* DWC_HOST_ONLY */
+}
+
+/**
+ * Initiate a remote wakeup of the host.  The Device control register
+ * Remote Wakeup Signal bit is written if the PCD Remote wakeup enable
+ * flag is set.
+ *
+ */
+static ssize_t remote_wakeup_store(struct device *_dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+#ifndef DWC_HOST_ONLY
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+
+	uint32_t val = simple_strtoul(buf, NULL, 16);
+
+	if (val & 1) {
+		dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 1);
+	} else {
+		dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 0);
+	}
+#endif /* DWC_HOST_ONLY */
+	return count;
+}
+
+DEVICE_ATTR(remote_wakeup, S_IRUGO | S_IWUSR, remote_wakeup_show,
+	    remote_wakeup_store);
+
+/**
+ * Show the whether core is hibernated or not.
+ */
+static ssize_t rem_wakeup_pwrdn_show(struct device *_dev,
+				     struct device_attribute *attr, char *buf)
+{
+#ifndef DWC_HOST_ONLY
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+	if (dwc_otg_get_core_state(otg_dev->core_if)) {
+		DWC_PRINTF("Core is in hibernation\n");
+	} else {
+		DWC_PRINTF("Core is not in hibernation\n");
+	}
+#endif /* DWC_HOST_ONLY */
+	return 0;
+}
+
+extern int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
+					      int rem_wakeup, int reset);
+
+/**
+ * Initiate a remote wakeup of the device to exit from hibernation.
+ */
+static ssize_t rem_wakeup_pwrdn_store(struct device *_dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t count)
+{
+#ifndef DWC_HOST_ONLY
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+	dwc_otg_device_hibernation_restore(otg_dev->core_if, 1, 0);
+#endif
+	return count;
+}
+
+DEVICE_ATTR(rem_wakeup_pwrdn, S_IRUGO | S_IWUSR, rem_wakeup_pwrdn_show,
+	    rem_wakeup_pwrdn_store);
+
+static ssize_t disconnect_us(struct device *_dev,
+			     struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+
+#ifndef DWC_HOST_ONLY
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+	uint32_t val = simple_strtoul(buf, NULL, 16);
+	DWC_PRINTF("The Passed value is %04x\n", val);
+
+	dwc_otg_pcd_disconnect_us(otg_dev->pcd, 50);
+
+#endif /* DWC_HOST_ONLY */
+	return count;
+}
+
+DEVICE_ATTR(disconnect_us, S_IWUSR, 0, disconnect_us);
+
+/**
+ * Dump global registers and either host or device registers (depending on the
+ * current mode of the core).
+ */
+static ssize_t regdump_show(struct device *_dev,
+			    struct device_attribute *attr, char *buf)
+{
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+
+	dwc_otg_dump_global_registers(otg_dev->core_if);
+	if (dwc_otg_is_host_mode(otg_dev->core_if)) {
+		dwc_otg_dump_host_registers(otg_dev->core_if);
+	} else {
+		dwc_otg_dump_dev_registers(otg_dev->core_if);
+
+	}
+	return sprintf(buf, "Register Dump\n");
+}
+
+DEVICE_ATTR(regdump, S_IRUGO | S_IWUSR, regdump_show, 0);
+
+/**
+ * Dump global registers and either host or device registers (depending on the
+ * current mode of the core).
+ */
+static ssize_t spramdump_show(struct device *_dev,
+			      struct device_attribute *attr, char *buf)
+{
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+
+	dwc_otg_dump_spram(otg_dev->core_if);
+
+	return sprintf(buf, "SPRAM Dump\n");
+}
+
+DEVICE_ATTR(spramdump, S_IRUGO | S_IWUSR, spramdump_show, 0);
+
+/**
+ * Dump the current hcd state.
+ */
+static ssize_t hcddump_show(struct device *_dev,
+			    struct device_attribute *attr, char *buf)
+{
+#ifndef DWC_DEVICE_ONLY
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+
+	dwc_otg_hcd_dump_state(otg_dev->hcd);
+#endif /* DWC_DEVICE_ONLY */
+	return sprintf(buf, "HCD Dump\n");
+}
+
+DEVICE_ATTR(hcddump, S_IRUGO | S_IWUSR, hcddump_show, 0);
+
+/**
+ * Dump the average frame remaining at SOF. This can be used to
+ * determine average interrupt latency. Frame remaining is also shown for
+ * start transfer and two additional sample points.
+ */
+static ssize_t hcd_frrem_show(struct device *_dev,
+			      struct device_attribute *attr, char *buf)
+{
+#ifndef DWC_DEVICE_ONLY
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+
+	dwc_otg_hcd_dump_frrem(otg_dev->hcd);
+#endif /* DWC_DEVICE_ONLY */
+	return sprintf(buf, "HCD Dump Frame Remaining\n");
+}
+
+DEVICE_ATTR(hcd_frrem, S_IRUGO | S_IWUSR, hcd_frrem_show, 0);
+
+/**
+ * Displays the time required to read the GNPTXFSIZ register many times (the
+ * output shows the number of times the register is read).
+ */
+#define RW_REG_COUNT 10000000
+#define MSEC_PER_JIFFIE 1000/HZ
+static ssize_t rd_reg_test_show(struct device *_dev,
+				struct device_attribute *attr, char *buf)
+{
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+
+	int i;
+	int time;
+	int start_jiffies;
+
+	printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
+	       HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
+	start_jiffies = jiffies;
+	for (i = 0; i < RW_REG_COUNT; i++) {
+		dwc_otg_get_gnptxfsiz(otg_dev->core_if);
+	}
+	time = jiffies - start_jiffies;
+	return sprintf(buf,
+		       "Time to read GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
+		       RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
+}
+
+DEVICE_ATTR(rd_reg_test, S_IRUGO | S_IWUSR, rd_reg_test_show, 0);
+
+/**
+ * Displays the time required to write the GNPTXFSIZ register many times (the
+ * output shows the number of times the register is written).
+ */
+static ssize_t wr_reg_test_show(struct device *_dev,
+				struct device_attribute *attr, char *buf)
+{
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+
+
+	uint32_t reg_val;
+	int i;
+	int time;
+	int start_jiffies;
+
+	printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
+	       HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
+	reg_val = dwc_otg_get_gnptxfsiz(otg_dev->core_if);
+	start_jiffies = jiffies;
+	for (i = 0; i < RW_REG_COUNT; i++) {
+		dwc_otg_set_gnptxfsiz(otg_dev->core_if, reg_val);
+	}
+	time = jiffies - start_jiffies;
+	return sprintf(buf,
+		       "Time to write GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
+		       RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
+}
+
+DEVICE_ATTR(wr_reg_test, S_IRUGO | S_IWUSR, wr_reg_test_show, 0);
+
+#ifdef CONFIG_USB_DWC_OTG_LPM
+
+/**
+* Show the lpm_response attribute.
+*/
+static ssize_t lpmresp_show(struct device *_dev,
+			    struct device_attribute *attr, char *buf)
+{
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+
+
+	if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if))
+		return sprintf(buf, "** LPM is DISABLED **\n");
+
+	if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
+		return sprintf(buf, "** Current mode is not device mode\n");
+	}
+	return sprintf(buf, "lpm_response = %d\n",
+		       dwc_otg_get_lpmresponse(otg_dev->core_if));
+}
+
+/**
+* Store the lpm_response attribute.
+*/
+static ssize_t lpmresp_store(struct device *_dev,
+			     struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+
+
+	uint32_t val = simple_strtoul(buf, NULL, 16);
+
+	if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if)) {
+		return 0;
+	}
+
+	if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
+		return 0;
+	}
+
+	dwc_otg_set_lpmresponse(otg_dev->core_if, val);
+	return count;
+}
+
+DEVICE_ATTR(lpm_response, S_IRUGO | S_IWUSR, lpmresp_show, lpmresp_store);
+
+/**
+* Show the sleep_status attribute.
+*/
+static ssize_t sleepstatus_show(struct device *_dev,
+				struct device_attribute *attr, char *buf)
+{
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+
+
+	return sprintf(buf, "Sleep Status = %d\n",
+		       dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if));
+}
+
+/**
+ * Store the sleep_status attribure.
+ */
+static ssize_t sleepstatus_store(struct device *_dev,
+				 struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+#ifdef LM_INTERFACE
+	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = dev_get_platdata(_dev);
+#endif
+
+
+	dwc_otg_core_if_t *core_if = otg_dev->core_if;
+
+	if (dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if)) {
+		if (dwc_otg_is_host_mode(core_if)) {
+
+			DWC_PRINTF("Host initiated resume\n");
+			dwc_otg_set_prtresume(otg_dev->core_if, 1);
+		}
+	}
+
+	return count;
+}
+
+DEVICE_ATTR(sleep_status, S_IRUGO | S_IWUSR, sleepstatus_show,
+	    sleepstatus_store);
+
+#endif /* CONFIG_USB_DWC_OTG_LPM_ENABLE */
+
+/**@}*/
+
+/**
+ * Create the device files
+ */
+void dwc_otg_attr_create(
+#ifdef LM_INTERFACE
+				struct lm_device *dev
+#elif  defined(PCI_INTERFACE)
+				struct pci_dev *dev
+#else
+//				struct device *dev
+				struct platform_device *dev
+#endif
+
+    )
+{
+	int error;
+
+	error = device_create_file(&dev->dev, &dev_attr_regoffset);
+	error = device_create_file(&dev->dev, &dev_attr_regvalue);
+	error = device_create_file(&dev->dev, &dev_attr_mode);
+	error = device_create_file(&dev->dev, &dev_attr_hnpcapable);
+	error = device_create_file(&dev->dev, &dev_attr_srpcapable);
+	error = device_create_file(&dev->dev, &dev_attr_hsic_connect);
+	error = device_create_file(&dev->dev, &dev_attr_inv_sel_hsic);
+	error = device_create_file(&dev->dev, &dev_attr_hnp);
+	error = device_create_file(&dev->dev, &dev_attr_srp);
+	error = device_create_file(&dev->dev, &dev_attr_buspower);
+	error = device_create_file(&dev->dev, &dev_attr_bussuspend);
+	error = device_create_file(&dev->dev, &dev_attr_mode_ch_tim_en);
+	error = device_create_file(&dev->dev, &dev_attr_fr_interval);
+	error = device_create_file(&dev->dev, &dev_attr_busconnected);
+	error = device_create_file(&dev->dev, &dev_attr_gotgctl);
+	error = device_create_file(&dev->dev, &dev_attr_gusbcfg);
+	error = device_create_file(&dev->dev, &dev_attr_grxfsiz);
+	error = device_create_file(&dev->dev, &dev_attr_gnptxfsiz);
+	error = device_create_file(&dev->dev, &dev_attr_gpvndctl);
+	error = device_create_file(&dev->dev, &dev_attr_ggpio);
+	error = device_create_file(&dev->dev, &dev_attr_guid);
+	error = device_create_file(&dev->dev, &dev_attr_gsnpsid);
+	error = device_create_file(&dev->dev, &dev_attr_devspeed);
+	error = device_create_file(&dev->dev, &dev_attr_enumspeed);
+	error = device_create_file(&dev->dev, &dev_attr_hptxfsiz);
+	error = device_create_file(&dev->dev, &dev_attr_hprt0);
+	error = device_create_file(&dev->dev, &dev_attr_remote_wakeup);
+	error = device_create_file(&dev->dev, &dev_attr_rem_wakeup_pwrdn);
+	error = device_create_file(&dev->dev, &dev_attr_disconnect_us);
+	error = device_create_file(&dev->dev, &dev_attr_regdump);
+	error = device_create_file(&dev->dev, &dev_attr_spramdump);
+	error = device_create_file(&dev->dev, &dev_attr_hcddump);
+	error = device_create_file(&dev->dev, &dev_attr_hcd_frrem);
+	error = device_create_file(&dev->dev, &dev_attr_rd_reg_test);
+	error = device_create_file(&dev->dev, &dev_attr_wr_reg_test);
+#ifdef CONFIG_USB_DWC_OTG_LPM
+	error = device_create_file(&dev->dev, &dev_attr_lpm_response);
+	error = device_create_file(&dev->dev, &dev_attr_sleep_status);
+#endif
+}
+
+/**
+ * Remove the device files
+ */
+void dwc_otg_attr_remove(
+#ifdef LM_INTERFACE
+				struct lm_device *dev
+#elif  defined(PCI_INTERFACE)
+				struct pci_dev *dev
+#else
+				//struct device *dev
+				struct platform_device *dev
+#endif
+
+    )
+{
+	device_remove_file(&dev->dev, &dev_attr_regoffset);
+	device_remove_file(&dev->dev, &dev_attr_regvalue);
+	device_remove_file(&dev->dev, &dev_attr_mode);
+	device_remove_file(&dev->dev, &dev_attr_hnpcapable);
+	device_remove_file(&dev->dev, &dev_attr_srpcapable);
+	device_remove_file(&dev->dev, &dev_attr_hsic_connect);
+	device_remove_file(&dev->dev, &dev_attr_inv_sel_hsic);
+	device_remove_file(&dev->dev, &dev_attr_hnp);
+	device_remove_file(&dev->dev, &dev_attr_srp);
+	device_remove_file(&dev->dev, &dev_attr_buspower);
+	device_remove_file(&dev->dev, &dev_attr_bussuspend);
+	device_remove_file(&dev->dev, &dev_attr_mode_ch_tim_en);
+	device_remove_file(&dev->dev, &dev_attr_fr_interval);
+	device_remove_file(&dev->dev, &dev_attr_busconnected);
+	device_remove_file(&dev->dev, &dev_attr_gotgctl);
+	device_remove_file(&dev->dev, &dev_attr_gusbcfg);
+	device_remove_file(&dev->dev, &dev_attr_grxfsiz);
+	device_remove_file(&dev->dev, &dev_attr_gnptxfsiz);
+	device_remove_file(&dev->dev, &dev_attr_gpvndctl);
+	device_remove_file(&dev->dev, &dev_attr_ggpio);
+	device_remove_file(&dev->dev, &dev_attr_guid);
+	device_remove_file(&dev->dev, &dev_attr_gsnpsid);
+	device_remove_file(&dev->dev, &dev_attr_devspeed);
+	device_remove_file(&dev->dev, &dev_attr_enumspeed);
+	device_remove_file(&dev->dev, &dev_attr_hptxfsiz);
+	device_remove_file(&dev->dev, &dev_attr_hprt0);
+	device_remove_file(&dev->dev, &dev_attr_remote_wakeup);
+	device_remove_file(&dev->dev, &dev_attr_rem_wakeup_pwrdn);
+	device_remove_file(&dev->dev, &dev_attr_disconnect_us);
+	device_remove_file(&dev->dev, &dev_attr_regdump);
+	device_remove_file(&dev->dev, &dev_attr_spramdump);
+	device_remove_file(&dev->dev, &dev_attr_hcddump);
+	device_remove_file(&dev->dev, &dev_attr_hcd_frrem);
+	device_remove_file(&dev->dev, &dev_attr_rd_reg_test);
+	device_remove_file(&dev->dev, &dev_attr_wr_reg_test);
+#ifdef CONFIG_USB_DWC_OTG_LPM
+	device_remove_file(&dev->dev, &dev_attr_lpm_response);
+	device_remove_file(&dev->dev, &dev_attr_sleep_status);
+#endif
+}
diff --git a/drivers/usb/dwc_otg/dwc_otg_attr.h b/drivers/usb/dwc_otg/dwc_otg_attr.h
new file mode 100644
index 0000000..9479e6c
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_attr.h
@@ -0,0 +1,89 @@
+/* ==========================================================================
+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_attr.h $
+ * $Revision: #13 $
+ * $Date: 2010/06/21 $
+ * $Change: 1532021 $
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ * 
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ * 
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+#if !defined(__DWC_OTG_ATTR_H__)
+#define __DWC_OTG_ATTR_H__
+
+/** @file
+ * This file contains the interface to the Linux device attributes.
+ */
+extern struct device_attribute dev_attr_regoffset;
+extern struct device_attribute dev_attr_regvalue;
+
+extern struct device_attribute dev_attr_mode;
+extern struct device_attribute dev_attr_hnpcapable;
+extern struct device_attribute dev_attr_srpcapable;
+extern struct device_attribute dev_attr_hnp;
+extern struct device_attribute dev_attr_srp;
+extern struct device_attribute dev_attr_buspower;
+extern struct device_attribute dev_attr_bussuspend;
+extern struct device_attribute dev_attr_mode_ch_tim_en;
+extern struct device_attribute dev_attr_fr_interval;
+extern struct device_attribute dev_attr_busconnected;
+extern struct device_attribute dev_attr_gotgctl;
+extern struct device_attribute dev_attr_gusbcfg;
+extern struct device_attribute dev_attr_grxfsiz;
+extern struct device_attribute dev_attr_gnptxfsiz;
+extern struct device_attribute dev_attr_gpvndctl;
+extern struct device_attribute dev_attr_ggpio;
+extern struct device_attribute dev_attr_guid;
+extern struct device_attribute dev_attr_gsnpsid;
+extern struct device_attribute dev_attr_devspeed;
+extern struct device_attribute dev_attr_enumspeed;
+extern struct device_attribute dev_attr_hptxfsiz;
+extern struct device_attribute dev_attr_hprt0;
+#ifdef CONFIG_USB_DWC_OTG_LPM
+extern struct device_attribute dev_attr_lpm_response;
+extern struct device_attribute devi_attr_sleep_status;
+#endif
+
+void dwc_otg_attr_create(
+#ifdef LM_INTERFACE
+				struct lm_device *dev
+#elif  PCI_INTERFACE
+				struct pci_dev *dev
+#else				
+				struct platform_device *dev
+#endif
+    );
+
+void dwc_otg_attr_remove(
+#ifdef LM_INTERFACE
+				struct lm_device *dev
+#elif  PCI_INTERFACE
+				struct pci_dev *dev
+#else				
+				struct platform_device *dev
+#endif
+    );
+#endif
diff --git a/drivers/usb/dwc_otg/dwc_otg_cfi.c b/drivers/usb/dwc_otg/dwc_otg_cfi.c
new file mode 100644
index 0000000..9c6fe15
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_cfi.c
@@ -0,0 +1,1876 @@
+/* ==========================================================================
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ * 
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ * 
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+/** @file 
+ *
+ * This file contains the most of the CFI(Core Feature Interface) 
+ * implementation for the OTG. 
+ */
+
+#ifdef DWC_UTE_CFI
+
+#include "dwc_otg_pcd.h"
+#include "dwc_otg_cfi.h"
+
+/** This definition should actually migrate to the Portability Library */
+#define DWC_CONSTANT_CPU_TO_LE16(x) (x)
+
+extern dwc_otg_pcd_ep_t *get_ep_by_addr(dwc_otg_pcd_t * pcd, u16 wIndex);
+
+static int cfi_core_features_buf(uint8_t * buf, uint16_t buflen);
+static int cfi_get_feature_value(uint8_t * buf, uint16_t buflen,
+				 struct dwc_otg_pcd *pcd,
+				 struct cfi_usb_ctrlrequest *ctrl_req);
+static int cfi_set_feature_value(struct dwc_otg_pcd *pcd);
+static int cfi_ep_get_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
+			     struct cfi_usb_ctrlrequest *req);
+static int cfi_ep_get_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
+				 struct cfi_usb_ctrlrequest *req);
+static int cfi_ep_get_align_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
+				struct cfi_usb_ctrlrequest *req);
+static int cfi_preproc_reset(struct dwc_otg_pcd *pcd,
+			     struct cfi_usb_ctrlrequest *req);
+static void cfi_free_ep_bs_dyn_data(cfi_ep_t * cfiep);
+
+static uint16_t get_dfifo_size(dwc_otg_core_if_t * core_if);
+static int32_t get_rxfifo_size(dwc_otg_core_if_t * core_if, uint16_t wValue);
+static int32_t get_txfifo_size(struct dwc_otg_pcd *pcd, uint16_t wValue);
+
+static uint8_t resize_fifos(dwc_otg_core_if_t * core_if);
+
+/** This is the header of the all features descriptor */
+static cfi_all_features_header_t all_props_desc_header = {
+	.wVersion = DWC_CONSTANT_CPU_TO_LE16(0x100),
+	.wCoreID = DWC_CONSTANT_CPU_TO_LE16(CFI_CORE_ID_OTG),
+	.wNumFeatures = DWC_CONSTANT_CPU_TO_LE16(9),
+};
+
+/** This is an array of statically allocated feature descriptors */
+static cfi_feature_desc_header_t prop_descs[] = {
+
+	/* FT_ID_DMA_MODE */
+	{
+	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_MODE),
+	 .bmAttributes = CFI_FEATURE_ATTR_RW,
+	 .wDataLength = DWC_CONSTANT_CPU_TO_LE16(1),
+	 },
+
+	/* FT_ID_DMA_BUFFER_SETUP */
+	{
+	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_BUFFER_SETUP),
+	 .bmAttributes = CFI_FEATURE_ATTR_RW,
+	 .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
+	 },
+
+	/* FT_ID_DMA_BUFF_ALIGN */
+	{
+	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_BUFF_ALIGN),
+	 .bmAttributes = CFI_FEATURE_ATTR_RW,
+	 .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
+	 },
+
+	/* FT_ID_DMA_CONCAT_SETUP */
+	{
+	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_CONCAT_SETUP),
+	 .bmAttributes = CFI_FEATURE_ATTR_RW,
+	 //.wDataLength  = DWC_CONSTANT_CPU_TO_LE16(6),
+	 },
+
+	/* FT_ID_DMA_CIRCULAR */
+	{
+	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_CIRCULAR),
+	 .bmAttributes = CFI_FEATURE_ATTR_RW,
+	 .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
+	 },
+
+	/* FT_ID_THRESHOLD_SETUP */
+	{
+	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_THRESHOLD_SETUP),
+	 .bmAttributes = CFI_FEATURE_ATTR_RW,
+	 .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
+	 },
+
+	/* FT_ID_DFIFO_DEPTH */
+	{
+	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DFIFO_DEPTH),
+	 .bmAttributes = CFI_FEATURE_ATTR_RO,
+	 .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
+	 },
+
+	/* FT_ID_TX_FIFO_DEPTH */
+	{
+	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_TX_FIFO_DEPTH),
+	 .bmAttributes = CFI_FEATURE_ATTR_RW,
+	 .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
+	 },
+
+	/* FT_ID_RX_FIFO_DEPTH */
+	{
+	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_RX_FIFO_DEPTH),
+	 .bmAttributes = CFI_FEATURE_ATTR_RW,
+	 .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
+	 }
+};
+
+/** The table of feature names */
+cfi_string_t prop_name_table[] = {
+	{FT_ID_DMA_MODE, "dma_mode"},
+	{FT_ID_DMA_BUFFER_SETUP, "buffer_setup"},
+	{FT_ID_DMA_BUFF_ALIGN, "buffer_align"},
+	{FT_ID_DMA_CONCAT_SETUP, "concat_setup"},
+	{FT_ID_DMA_CIRCULAR, "buffer_circular"},
+	{FT_ID_THRESHOLD_SETUP, "threshold_setup"},
+	{FT_ID_DFIFO_DEPTH, "dfifo_depth"},
+	{FT_ID_TX_FIFO_DEPTH, "txfifo_depth"},
+	{FT_ID_RX_FIFO_DEPTH, "rxfifo_depth"},
+	{}
+};
+
+/************************************************************************/
+
+/** 
+ * Returns the name of the feature by its ID 
+ * or NULL if no featute ID matches.
+ * 
+ */
+const uint8_t *get_prop_name(uint16_t prop_id, int *len)
+{
+	cfi_string_t *pstr;
+	*len = 0;
+
+	for (pstr = prop_name_table; pstr && pstr->s; pstr++) {
+		if (pstr->id == prop_id) {
+			*len = DWC_STRLEN(pstr->s);
+			return pstr->s;
+		}
+	}
+	return NULL;
+}
+
+/**
+ * This function handles all CFI specific control requests.
+ * 
+ * Return a negative value to stall the DCE.
+ */
+int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl)
+{
+	int retval = 0;
+	dwc_otg_pcd_ep_t *ep = NULL;
+	cfiobject_t *cfi = pcd->cfi;
+	struct dwc_otg_core_if *coreif = GET_CORE_IF(pcd);
+	uint16_t wLen = DWC_LE16_TO_CPU(&ctrl->wLength);
+	uint16_t wValue = DWC_LE16_TO_CPU(&ctrl->wValue);
+	uint16_t wIndex = DWC_LE16_TO_CPU(&ctrl->wIndex);
+	uint32_t regaddr = 0;
+	uint32_t regval = 0;
+
+	/* Save this Control Request in the CFI object. 
+	 * The data field will be assigned in the data stage completion CB function.
+	 */
+	cfi->ctrl_req = *ctrl;
+	cfi->ctrl_req.data = NULL;
+
+	cfi->need_gadget_att = 0;
+	cfi->need_status_in_complete = 0;
+
+	switch (ctrl->bRequest) {
+	case VEN_CORE_GET_FEATURES:
+		retval = cfi_core_features_buf(cfi->buf_in.buf, CFI_IN_BUF_LEN);
+		if (retval >= 0) {
+			//dump_msg(cfi->buf_in.buf, retval);
+			ep = &pcd->ep0;
+
+			retval = min((uint16_t) retval, wLen);
+			/* Transfer this buffer to the host through the EP0-IN EP */
+			ep->dwc_ep.dma_addr = cfi->buf_in.addr;
+			ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
+			ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
+			ep->dwc_ep.xfer_len = retval;
+			ep->dwc_ep.xfer_count = 0;
+			ep->dwc_ep.sent_zlp = 0;
+			ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
+
+			pcd->ep0_pending = 1;
+			dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
+		}
+		retval = 0;
+		break;
+
+	case VEN_CORE_GET_FEATURE:
+		CFI_INFO("VEN_CORE_GET_FEATURE\n");
+		retval = cfi_get_feature_value(cfi->buf_in.buf, CFI_IN_BUF_LEN,
+					       pcd, ctrl);
+		if (retval >= 0) {
+			ep = &pcd->ep0;
+
+			retval = min((uint16_t) retval, wLen);
+			/* Transfer this buffer to the host through the EP0-IN EP */
+			ep->dwc_ep.dma_addr = cfi->buf_in.addr;
+			ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
+			ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
+			ep->dwc_ep.xfer_len = retval;
+			ep->dwc_ep.xfer_count = 0;
+			ep->dwc_ep.sent_zlp = 0;
+			ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
+
+			pcd->ep0_pending = 1;
+			dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
+		}
+		CFI_INFO("VEN_CORE_GET_FEATURE=%d\n", retval);
+		dump_msg(cfi->buf_in.buf, retval);
+		break;
+
+	case VEN_CORE_SET_FEATURE:
+		CFI_INFO("VEN_CORE_SET_FEATURE\n");
+		/* Set up an XFER to get the data stage of the control request,
+		 * which is the new value of the feature to be modified.
+		 */
+		ep = &pcd->ep0;
+		ep->dwc_ep.is_in = 0;
+		ep->dwc_ep.dma_addr = cfi->buf_out.addr;
+		ep->dwc_ep.start_xfer_buff = cfi->buf_out.buf;
+		ep->dwc_ep.xfer_buff = cfi->buf_out.buf;
+		ep->dwc_ep.xfer_len = wLen;
+		ep->dwc_ep.xfer_count = 0;
+		ep->dwc_ep.sent_zlp = 0;
+		ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
+
+		pcd->ep0_pending = 1;
+		/* Read the control write's data stage */
+		dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
+		retval = 0;
+		break;
+
+	case VEN_CORE_RESET_FEATURES:
+		CFI_INFO("VEN_CORE_RESET_FEATURES\n");
+		cfi->need_gadget_att = 1;
+		cfi->need_status_in_complete = 1;
+		retval = cfi_preproc_reset(pcd, ctrl);
+		CFI_INFO("VEN_CORE_RESET_FEATURES = (%d)\n", retval);
+		break;
+
+	case VEN_CORE_ACTIVATE_FEATURES:
+		CFI_INFO("VEN_CORE_ACTIVATE_FEATURES\n");
+		break;
+
+	case VEN_CORE_READ_REGISTER:
+		CFI_INFO("VEN_CORE_READ_REGISTER\n");
+		/* wValue optionally contains the HI WORD of the register offset and
+		 * wIndex contains the LOW WORD of the register offset 
+		 */
+		if (wValue == 0) {
+			/* @TODO - MAS - fix the access to the base field */
+			regaddr = 0;
+			//regaddr = (uint32_t) pcd->otg_dev->os_dep.base;
+			//GET_CORE_IF(pcd)->co
+			regaddr |= wIndex;
+		} else {
+			regaddr = (wValue << 16) | wIndex;
+		}
+
+		/* Read a 32-bit value of the memory at the regaddr */
+		regval = DWC_READ_REG32((uint32_t *) regaddr);
+
+		ep = &pcd->ep0;
+		dwc_memcpy(cfi->buf_in.buf, &regval, sizeof(uint32_t));
+		ep->dwc_ep.is_in = 1;
+		ep->dwc_ep.dma_addr = cfi->buf_in.addr;
+		ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
+		ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
+		ep->dwc_ep.xfer_len = wLen;
+		ep->dwc_ep.xfer_count = 0;
+		ep->dwc_ep.sent_zlp = 0;
+		ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
+
+		pcd->ep0_pending = 1;
+		dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
+		cfi->need_gadget_att = 0;
+		retval = 0;
+		break;
+
+	case VEN_CORE_WRITE_REGISTER:
+		CFI_INFO("VEN_CORE_WRITE_REGISTER\n");
+		/* Set up an XFER to get the data stage of the control request,
+		 * which is the new value of the register to be modified.
+		 */
+		ep = &pcd->ep0;
+		ep->dwc_ep.is_in = 0;
+		ep->dwc_ep.dma_addr = cfi->buf_out.addr;
+		ep->dwc_ep.start_xfer_buff = cfi->buf_out.buf;
+		ep->dwc_ep.xfer_buff = cfi->buf_out.buf;
+		ep->dwc_ep.xfer_len = wLen;
+		ep->dwc_ep.xfer_count = 0;
+		ep->dwc_ep.sent_zlp = 0;
+		ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
+
+		pcd->ep0_pending = 1;
+		/* Read the control write's data stage */
+		dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
+		retval = 0;
+		break;
+
+	default:
+		retval = -DWC_E_NOT_SUPPORTED;
+		break;
+	}
+
+	return retval;
+}
+
+/**
+ * This function prepares the core features descriptors and copies its
+ * raw representation into the buffer <buf>.
+ * 
+ * The buffer structure is as follows:
+ *	all_features_header (8 bytes)
+ *	features_#1 (8 bytes + feature name string length)
+ *	features_#2 (8 bytes + feature name string length)
+ *	.....
+ *	features_#n - where n=the total count of feature descriptors
+ */
+static int cfi_core_features_buf(uint8_t * buf, uint16_t buflen)
+{
+	cfi_feature_desc_header_t *prop_hdr = prop_descs;
+	cfi_feature_desc_header_t *prop;
+	cfi_all_features_header_t *all_props_hdr = &all_props_desc_header;
+	cfi_all_features_header_t *tmp;
+	uint8_t *tmpbuf = buf;
+	const uint8_t *pname = NULL;
+	int i, j, namelen = 0, totlen;
+
+	/* Prepare and copy the core features into the buffer */
+	CFI_INFO("%s:\n", __func__);
+
+	tmp = (cfi_all_features_header_t *) tmpbuf;
+	*tmp = *all_props_hdr;
+	tmpbuf += CFI_ALL_FEATURES_HDR_LEN;
+
+	j = sizeof(prop_descs) / sizeof(cfi_all_features_header_t);
+	for (i = 0; i < j; i++, prop_hdr++) {
+		pname = get_prop_name(prop_hdr->wFeatureID, &namelen);
+		prop = (cfi_feature_desc_header_t *) tmpbuf;
+		*prop = *prop_hdr;
+
+		prop->bNameLen = namelen;
+		prop->wLength =
+		    DWC_CONSTANT_CPU_TO_LE16(CFI_FEATURE_DESC_HDR_LEN +
+					     namelen);
+
+		tmpbuf += CFI_FEATURE_DESC_HDR_LEN;
+		dwc_memcpy(tmpbuf, pname, namelen);
+		tmpbuf += namelen;
+	}
+
+	totlen = tmpbuf - buf;
+
+	if (totlen > 0) {
+		tmp = (cfi_all_features_header_t *) buf;
+		tmp->wTotalLen = DWC_CONSTANT_CPU_TO_LE16(totlen);
+	}
+
+	return totlen;
+}
+
+/**
+ * This function releases all the dynamic memory in the CFI object.
+ */
+static void cfi_release(cfiobject_t * cfiobj)
+{
+	cfi_ep_t *cfiep;
+	dwc_list_link_t *tmp;
+
+	CFI_INFO("%s\n", __func__);
+
+	if (cfiobj->buf_in.buf) {
+		DWC_DMA_FREE(CFI_IN_BUF_LEN, cfiobj->buf_in.buf,
+			     cfiobj->buf_in.addr);
+		cfiobj->buf_in.buf = NULL;
+	}
+
+	if (cfiobj->buf_out.buf) {
+		DWC_DMA_FREE(CFI_OUT_BUF_LEN, cfiobj->buf_out.buf,
+			     cfiobj->buf_out.addr);
+		cfiobj->buf_out.buf = NULL;
+	}
+
+	/* Free the Buffer Setup values for each EP */
+	//list_for_each_entry(cfiep, &cfiobj->active_eps, lh) {
+	DWC_LIST_FOREACH(tmp, &cfiobj->active_eps) {
+		cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
+		cfi_free_ep_bs_dyn_data(cfiep);
+	}
+}
+
+/**
+ * This function frees the dynamically allocated EP buffer setup data.
+ */
+static void cfi_free_ep_bs_dyn_data(cfi_ep_t * cfiep)
+{
+	if (cfiep->bm_sg) {
+		DWC_FREE(cfiep->bm_sg);
+		cfiep->bm_sg = NULL;
+	}
+
+	if (cfiep->bm_align) {
+		DWC_FREE(cfiep->bm_align);
+		cfiep->bm_align = NULL;
+	}
+
+	if (cfiep->bm_concat) {
+		if (NULL != cfiep->bm_concat->wTxBytes) {
+			DWC_FREE(cfiep->bm_concat->wTxBytes);
+			cfiep->bm_concat->wTxBytes = NULL;
+		}
+		DWC_FREE(cfiep->bm_concat);
+		cfiep->bm_concat = NULL;
+	}
+}
+
+/**
+ * This function initializes the default values of the features
+ * for a specific endpoint and should be called only once when
+ * the EP is enabled first time.
+ */
+static int cfi_ep_init_defaults(struct dwc_otg_pcd *pcd, cfi_ep_t * cfiep)
+{
+	int retval = 0;
+
+	cfiep->bm_sg = DWC_ALLOC(sizeof(ddma_sg_buffer_setup_t));
+	if (NULL == cfiep->bm_sg) {
+		CFI_INFO("Failed to allocate memory for SG feature value\n");
+		return -DWC_E_NO_MEMORY;
+	}
+	dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
+
+	/* For the Concatenation feature's default value we do not allocate
+	 * memory for the wTxBytes field - it will be done in the set_feature_value
+	 * request handler.
+	 */
+	cfiep->bm_concat = DWC_ALLOC(sizeof(ddma_concat_buffer_setup_t));
+	if (NULL == cfiep->bm_concat) {
+		CFI_INFO
+		    ("Failed to allocate memory for CONCATENATION feature value\n");
+		DWC_FREE(cfiep->bm_sg);
+		return -DWC_E_NO_MEMORY;
+	}
+	dwc_memset(cfiep->bm_concat, 0, sizeof(ddma_concat_buffer_setup_t));
+
+	cfiep->bm_align = DWC_ALLOC(sizeof(ddma_align_buffer_setup_t));
+	if (NULL == cfiep->bm_align) {
+		CFI_INFO
+		    ("Failed to allocate memory for Alignment feature value\n");
+		DWC_FREE(cfiep->bm_sg);
+		DWC_FREE(cfiep->bm_concat);
+		return -DWC_E_NO_MEMORY;
+	}
+	dwc_memset(cfiep->bm_align, 0, sizeof(ddma_align_buffer_setup_t));
+
+	return retval;
+}
+
+/**
+ * The callback function that notifies the CFI on the activation of
+ * an endpoint in the PCD. The following steps are done in this function:
+ *
+ *	Create a dynamically allocated cfi_ep_t object (a CFI wrapper to the PCD's 
+ *		active endpoint)
+ *	Create MAX_DMA_DESCS_PER_EP count DMA Descriptors for the EP
+ *	Set the Buffer Mode to standard
+ *	Initialize the default values for all EP modes (SG, Circular, Concat, Align)
+ *	Add the cfi_ep_t object to the list of active endpoints in the CFI object
+ */
+static int cfi_ep_enable(struct cfiobject *cfi, struct dwc_otg_pcd *pcd,
+			 struct dwc_otg_pcd_ep *ep)
+{
+	cfi_ep_t *cfiep;
+	int retval = -DWC_E_NOT_SUPPORTED;
+
+	CFI_INFO("%s: epname=%s; epnum=0x%02x\n", __func__,
+		 "EP_" /*ep->ep.name */ , ep->desc->bEndpointAddress);
+	/* MAS - Check whether this endpoint already is in the list */
+	cfiep = get_cfi_ep_by_pcd_ep(cfi, ep);
+
+	if (NULL == cfiep) {
+		/* Allocate a cfi_ep_t object */
+		cfiep = DWC_ALLOC(sizeof(cfi_ep_t));
+		if (NULL == cfiep) {
+			CFI_INFO
+			    ("Unable to allocate memory for <cfiep> in function %s\n",
+			     __func__);
+			return -DWC_E_NO_MEMORY;
+		}
+		dwc_memset(cfiep, 0, sizeof(cfi_ep_t));
+
+		/* Save the dwc_otg_pcd_ep pointer in the cfiep object */
+		cfiep->ep = ep;
+
+		/* Allocate the DMA Descriptors chain of MAX_DMA_DESCS_PER_EP count */
+		ep->dwc_ep.descs =
+		    DWC_DMA_ALLOC(MAX_DMA_DESCS_PER_EP *
+				  sizeof(dwc_otg_dma_desc_t),
+				  &ep->dwc_ep.descs_dma_addr);
+
+		if (NULL == ep->dwc_ep.descs) {
+			DWC_FREE(cfiep);
+			return -DWC_E_NO_MEMORY;
+		}
+
+		DWC_LIST_INIT(&cfiep->lh);
+
+		/* Set the buffer mode to BM_STANDARD. It will be modified 
+		 * when building descriptors for a specific buffer mode */
+		ep->dwc_ep.buff_mode = BM_STANDARD;
+
+		/* Create and initialize the default values for this EP's Buffer modes */
+		if ((retval = cfi_ep_init_defaults(pcd, cfiep)) < 0)
+			return retval;
+
+		/* Add the cfi_ep_t object to the CFI object's list of active endpoints */
+		DWC_LIST_INSERT_TAIL(&cfi->active_eps, &cfiep->lh);
+		retval = 0;
+	} else {		/* The sought EP already is in the list */
+		CFI_INFO("%s: The sought EP already is in the list\n",
+			 __func__);
+	}
+
+	return retval;
+}
+
+/**
+ * This function is called when the data stage of a 3-stage Control Write request
+ * is complete.
+ * 
+ */
+static int cfi_ctrl_write_complete(struct cfiobject *cfi,
+				   struct dwc_otg_pcd *pcd)
+{
+	uint32_t addr, reg_value;
+	uint16_t wIndex, wValue;
+	uint8_t bRequest;
+	uint8_t *buf = cfi->buf_out.buf;
+	//struct usb_ctrlrequest *ctrl_req = &cfi->ctrl_req_saved;
+	struct cfi_usb_ctrlrequest *ctrl_req = &cfi->ctrl_req;
+	int retval = -DWC_E_NOT_SUPPORTED;
+
+	CFI_INFO("%s\n", __func__);
+
+	bRequest = ctrl_req->bRequest;
+	wIndex = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wIndex);
+	wValue = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wValue);
+
+	/* 
+	 * Save the pointer to the data stage in the ctrl_req's <data> field.
+	 * The request should be already saved in the command stage by now.
+	 */
+	ctrl_req->data = cfi->buf_out.buf;
+	cfi->need_status_in_complete = 0;
+	cfi->need_gadget_att = 0;
+
+	switch (bRequest) {
+	case VEN_CORE_WRITE_REGISTER:
+		/* The buffer contains raw data of the new value for the register */
+		reg_value = *((uint32_t *) buf);
+		if (wValue == 0) {
+			addr = 0;
+			//addr = (uint32_t) pcd->otg_dev->os_dep.base;
+			addr += wIndex;
+		} else {
+			addr = (wValue << 16) | wIndex;
+		}
+
+		//writel(reg_value, addr);
+
+		retval = 0;
+		cfi->need_status_in_complete = 1;
+		break;
+
+	case VEN_CORE_SET_FEATURE:
+		/* The buffer contains raw data of the new value of the feature */
+		retval = cfi_set_feature_value(pcd);
+		if (retval < 0)
+			return retval;
+
+		cfi->need_status_in_complete = 1;
+		break;
+
+	default:
+		break;
+	}
+
+	return retval;
+}
+
+/**
+ * This function builds the DMA descriptors for the SG buffer mode.
+ */
+static void cfi_build_sg_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
+			       dwc_otg_pcd_request_t * req)
+{
+	struct dwc_otg_pcd_ep *ep = cfiep->ep;
+	ddma_sg_buffer_setup_t *sgval = cfiep->bm_sg;
+	struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
+	struct dwc_otg_dma_desc *desc_last = cfiep->ep->dwc_ep.descs;
+	dma_addr_t buff_addr = req->dma;
+	int i;
+	uint32_t txsize, off;
+
+	txsize = sgval->wSize;
+	off = sgval->bOffset;
+
+//      CFI_INFO("%s: %s TXSIZE=0x%08x; OFFSET=0x%08x\n", 
+//              __func__, cfiep->ep->ep.name, txsize, off);
+
+	for (i = 0; i < sgval->bCount; i++) {
+		desc->status.b.bs = BS_HOST_BUSY;
+		desc->buf = buff_addr;
+		desc->status.b.l = 0;
+		desc->status.b.ioc = 0;
+		desc->status.b.sp = 0;
+		desc->status.b.bytes = txsize;
+		desc->status.b.bs = BS_HOST_READY;
+
+		/* Set the next address of the buffer */
+		buff_addr += txsize + off;
+		desc_last = desc;
+		desc++;
+	}
+
+	/* Set the last, ioc and sp bits on the Last DMA Descriptor */
+	desc_last->status.b.l = 1;
+	desc_last->status.b.ioc = 1;
+	desc_last->status.b.sp = ep->dwc_ep.sent_zlp;
+	/* Save the last DMA descriptor pointer */
+	cfiep->dma_desc_last = desc_last;
+	cfiep->desc_count = sgval->bCount;
+}
+
+/**
+ * This function builds the DMA descriptors for the Concatenation buffer mode.
+ */
+static void cfi_build_concat_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
+				   dwc_otg_pcd_request_t * req)
+{
+	struct dwc_otg_pcd_ep *ep = cfiep->ep;
+	ddma_concat_buffer_setup_t *concatval = cfiep->bm_concat;
+	struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
+	struct dwc_otg_dma_desc *desc_last = cfiep->ep->dwc_ep.descs;
+	dma_addr_t buff_addr = req->dma;
+	int i;
+	uint16_t *txsize;
+
+	txsize = concatval->wTxBytes;
+
+	for (i = 0; i < concatval->hdr.bDescCount; i++) {
+		desc->buf = buff_addr;
+		desc->status.b.bs = BS_HOST_BUSY;
+		desc->status.b.l = 0;
+		desc->status.b.ioc = 0;
+		desc->status.b.sp = 0;
+		desc->status.b.bytes = *txsize;
+		desc->status.b.bs = BS_HOST_READY;
+
+		txsize++;
+		/* Set the next address of the buffer */
+		buff_addr += UGETW(ep->desc->wMaxPacketSize);
+		desc_last = desc;
+		desc++;
+	}
+
+	/* Set the last, ioc and sp bits on the Last DMA Descriptor */
+	desc_last->status.b.l = 1;
+	desc_last->status.b.ioc = 1;
+	desc_last->status.b.sp = ep->dwc_ep.sent_zlp;
+	cfiep->dma_desc_last = desc_last;
+	cfiep->desc_count = concatval->hdr.bDescCount;
+}
+
+/**
+ * This function builds the DMA descriptors for the Circular buffer mode
+ */
+static void cfi_build_circ_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
+				 dwc_otg_pcd_request_t * req)
+{
+	/* @todo: MAS - add implementation when this feature needs to be tested */
+}
+
+/**
+ * This function builds the DMA descriptors for the Alignment buffer mode
+ */
+static void cfi_build_align_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
+				  dwc_otg_pcd_request_t * req)
+{
+	struct dwc_otg_pcd_ep *ep = cfiep->ep;
+	ddma_align_buffer_setup_t *alignval = cfiep->bm_align;
+	struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
+	dma_addr_t buff_addr = req->dma;
+
+	desc->status.b.bs = BS_HOST_BUSY;
+	desc->status.b.l = 1;
+	desc->status.b.ioc = 1;
+	desc->status.b.sp = ep->dwc_ep.sent_zlp;
+	desc->status.b.bytes = req->length;
+	/* Adjust the buffer alignment */
+	desc->buf = (buff_addr + alignval->bAlign);
+	desc->status.b.bs = BS_HOST_READY;
+	cfiep->dma_desc_last = desc;
+	cfiep->desc_count = 1;
+}
+
+/**
+ * This function builds the DMA descriptors chain for different modes of the
+ * buffer setup of an endpoint.
+ */
+static void cfi_build_descriptors(struct cfiobject *cfi,
+				  struct dwc_otg_pcd *pcd,
+				  struct dwc_otg_pcd_ep *ep,
+				  dwc_otg_pcd_request_t * req)
+{
+	cfi_ep_t *cfiep;
+
+	/* Get the cfiep by the dwc_otg_pcd_ep */
+	cfiep = get_cfi_ep_by_pcd_ep(cfi, ep);
+	if (NULL == cfiep) {
+		CFI_INFO("%s: Unable to find a matching active endpoint\n",
+			 __func__);
+		return;
+	}
+
+	cfiep->xfer_len = req->length;
+
+	/* Iterate through all the DMA descriptors */
+	switch (cfiep->ep->dwc_ep.buff_mode) {
+	case BM_SG:
+		cfi_build_sg_descs(cfi, cfiep, req);
+		break;
+
+	case BM_CONCAT:
+		cfi_build_concat_descs(cfi, cfiep, req);
+		break;
+
+	case BM_CIRCULAR:
+		cfi_build_circ_descs(cfi, cfiep, req);
+		break;
+
+	case BM_ALIGN:
+		cfi_build_align_descs(cfi, cfiep, req);
+		break;
+
+	default:
+		break;
+	}
+}
+
+/**
+ * Allocate DMA buffer for different Buffer modes.
+ */
+static void *cfi_ep_alloc_buf(struct cfiobject *cfi, struct dwc_otg_pcd *pcd,
+			      struct dwc_otg_pcd_ep *ep, dma_addr_t * dma,
+			      unsigned size, gfp_t flags)
+{
+	return DWC_DMA_ALLOC(size, dma);
+}
+
+/**
+ * This function initializes the CFI object.
+ */
+int init_cfi(cfiobject_t * cfiobj)
+{
+	CFI_INFO("%s\n", __func__);
+
+	/* Allocate a buffer for IN XFERs */
+	cfiobj->buf_in.buf =
+	    DWC_DMA_ALLOC(CFI_IN_BUF_LEN, &cfiobj->buf_in.addr);
+	if (NULL == cfiobj->buf_in.buf) {
+		CFI_INFO("Unable to allocate buffer for INs\n");
+		return -DWC_E_NO_MEMORY;
+	}
+
+	/* Allocate a buffer for OUT XFERs */
+	cfiobj->buf_out.buf =
+	    DWC_DMA_ALLOC(CFI_OUT_BUF_LEN, &cfiobj->buf_out.addr);
+	if (NULL == cfiobj->buf_out.buf) {
+		CFI_INFO("Unable to allocate buffer for OUT\n");
+		return -DWC_E_NO_MEMORY;
+	}
+
+	/* Initialize the callback function pointers */
+	cfiobj->ops.release = cfi_release;
+	cfiobj->ops.ep_enable = cfi_ep_enable;
+	cfiobj->ops.ctrl_write_complete = cfi_ctrl_write_complete;
+	cfiobj->ops.build_descriptors = cfi_build_descriptors;
+	cfiobj->ops.ep_alloc_buf = cfi_ep_alloc_buf;
+
+	/* Initialize the list of active endpoints in the CFI object */
+	DWC_LIST_INIT(&cfiobj->active_eps);
+
+	return 0;
+}
+
+/**
+ * This function reads the required feature's current value into the buffer
+ *
+ * @retval: Returns negative as error, or the data length of the feature  
+ */
+static int cfi_get_feature_value(uint8_t * buf, uint16_t buflen,
+				 struct dwc_otg_pcd *pcd,
+				 struct cfi_usb_ctrlrequest *ctrl_req)
+{
+	int retval = -DWC_E_NOT_SUPPORTED;
+	struct dwc_otg_core_if *coreif = GET_CORE_IF(pcd);
+	uint16_t dfifo, rxfifo, txfifo;
+
+	switch (ctrl_req->wIndex) {
+		/* Whether the DDMA is enabled or not */
+	case FT_ID_DMA_MODE:
+		*buf = (coreif->dma_enable && coreif->dma_desc_enable) ? 1 : 0;
+		retval = 1;
+		break;
+
+	case FT_ID_DMA_BUFFER_SETUP:
+		retval = cfi_ep_get_sg_val(buf, pcd, ctrl_req);
+		break;
+
+	case FT_ID_DMA_BUFF_ALIGN:
+		retval = cfi_ep_get_align_val(buf, pcd, ctrl_req);
+		break;
+
+	case FT_ID_DMA_CONCAT_SETUP:
+		retval = cfi_ep_get_concat_val(buf, pcd, ctrl_req);
+		break;
+
+	case FT_ID_DMA_CIRCULAR:
+		CFI_INFO("GetFeature value (FT_ID_DMA_CIRCULAR)\n");
+		break;
+
+	case FT_ID_THRESHOLD_SETUP:
+		CFI_INFO("GetFeature value (FT_ID_THRESHOLD_SETUP)\n");
+		break;
+
+	case FT_ID_DFIFO_DEPTH:
+		dfifo = get_dfifo_size(coreif);
+		*((uint16_t *) buf) = dfifo;
+		retval = sizeof(uint16_t);
+		break;
+
+	case FT_ID_TX_FIFO_DEPTH:
+		retval = get_txfifo_size(pcd, ctrl_req->wValue);
+		if (retval >= 0) {
+			txfifo = retval;
+			*((uint16_t *) buf) = txfifo;
+			retval = sizeof(uint16_t);
+		}
+		break;
+
+	case FT_ID_RX_FIFO_DEPTH:
+		retval = get_rxfifo_size(coreif, ctrl_req->wValue);
+		if (retval >= 0) {
+			rxfifo = retval;
+			*((uint16_t *) buf) = rxfifo;
+			retval = sizeof(uint16_t);
+		}
+		break;
+	}
+
+	return retval;
+}
+
+/**
+ * This function resets the SG for the specified EP to its default value
+ */
+static int cfi_reset_sg_val(cfi_ep_t * cfiep)
+{
+	dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
+	return 0;
+}
+
+/**
+ * This function resets the Alignment for the specified EP to its default value
+ */
+static int cfi_reset_align_val(cfi_ep_t * cfiep)
+{
+	dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
+	return 0;
+}
+
+/**
+ * This function resets the Concatenation for the specified EP to its default value
+ * This function will also set the value of the wTxBytes field to NULL after 
+ * freeing the memory previously allocated for this field.
+ */
+static int cfi_reset_concat_val(cfi_ep_t * cfiep)
+{
+	/* First we need to free the wTxBytes field */
+	if (cfiep->bm_concat->wTxBytes) {
+		DWC_FREE(cfiep->bm_concat->wTxBytes);
+		cfiep->bm_concat->wTxBytes = NULL;
+	}
+
+	dwc_memset(cfiep->bm_concat, 0, sizeof(ddma_concat_buffer_setup_t));
+	return 0;
+}
+
+/**
+ * This function resets all the buffer setups of the specified endpoint
+ */
+static int cfi_ep_reset_all_setup_vals(cfi_ep_t * cfiep)
+{
+	cfi_reset_sg_val(cfiep);
+	cfi_reset_align_val(cfiep);
+	cfi_reset_concat_val(cfiep);
+	return 0;
+}
+
+static int cfi_handle_reset_fifo_val(struct dwc_otg_pcd *pcd, uint8_t ep_addr,
+				     uint8_t rx_rst, uint8_t tx_rst)
+{
+	int retval = -DWC_E_INVALID;
+	uint16_t tx_siz[15];
+	uint16_t rx_siz = 0;
+	dwc_otg_pcd_ep_t *ep = NULL;
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+	dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
+
+	if (rx_rst) {
+		rx_siz = params->dev_rx_fifo_size;
+		params->dev_rx_fifo_size = GET_CORE_IF(pcd)->init_rxfsiz;
+	}
+
+	if (tx_rst) {
+		if (ep_addr == 0) {
+			int i;
+
+			for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
+				tx_siz[i] =
+				    core_if->core_params->dev_tx_fifo_size[i];
+				core_if->core_params->dev_tx_fifo_size[i] =
+				    core_if->init_txfsiz[i];
+			}
+		} else {
+
+			ep = get_ep_by_addr(pcd, ep_addr);
+
+			if (NULL == ep) {
+				CFI_INFO
+				    ("%s: Unable to get the endpoint addr=0x%02x\n",
+				     __func__, ep_addr);
+				return -DWC_E_INVALID;
+			}
+
+			tx_siz[0] =
+			    params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num -
+						     1];
+			params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] =
+			    GET_CORE_IF(pcd)->init_txfsiz[ep->
+							  dwc_ep.tx_fifo_num -
+							  1];
+		}
+	}
+
+	if (resize_fifos(GET_CORE_IF(pcd))) {
+		retval = 0;
+	} else {
+		CFI_INFO
+		    ("%s: Error resetting the feature Reset All(FIFO size)\n",
+		     __func__);
+		if (rx_rst) {
+			params->dev_rx_fifo_size = rx_siz;
+		}
+
+		if (tx_rst) {
+			if (ep_addr == 0) {
+				int i;
+				for (i = 0; i < core_if->hwcfg4.b.num_in_eps;
+				     i++) {
+					core_if->
+					    core_params->dev_tx_fifo_size[i] =
+					    tx_siz[i];
+				}
+			} else {
+				params->dev_tx_fifo_size[ep->
+							 dwc_ep.tx_fifo_num -
+							 1] = tx_siz[0];
+			}
+		}
+		retval = -DWC_E_INVALID;
+	}
+	return retval;
+}
+
+static int cfi_handle_reset_all(struct dwc_otg_pcd *pcd, uint8_t addr)
+{
+	int retval = 0;
+	cfi_ep_t *cfiep;
+	cfiobject_t *cfi = pcd->cfi;
+	dwc_list_link_t *tmp;
+
+	retval = cfi_handle_reset_fifo_val(pcd, addr, 1, 1);
+	if (retval < 0) {
+		return retval;
+	}
+
+	/* If the EP address is known then reset the features for only that EP */
+	if (addr) {
+		cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
+		if (NULL == cfiep) {
+			CFI_INFO("%s: Error getting the EP address 0x%02x\n",
+				 __func__, addr);
+			return -DWC_E_INVALID;
+		}
+		retval = cfi_ep_reset_all_setup_vals(cfiep);
+		cfiep->ep->dwc_ep.buff_mode = BM_STANDARD;
+	}
+	/* Otherwise (wValue == 0), reset all features of all EP's */
+	else {
+		/* Traverse all the active EP's and reset the feature(s) value(s) */
+		//list_for_each_entry(cfiep, &cfi->active_eps, lh) {
+		DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
+			cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
+			retval = cfi_ep_reset_all_setup_vals(cfiep);
+			cfiep->ep->dwc_ep.buff_mode = BM_STANDARD;
+			if (retval < 0) {
+				CFI_INFO
+				    ("%s: Error resetting the feature Reset All\n",
+				     __func__);
+				return retval;
+			}
+		}
+	}
+	return retval;
+}
+
+static int cfi_handle_reset_dma_buff_setup(struct dwc_otg_pcd *pcd,
+					   uint8_t addr)
+{
+	int retval = 0;
+	cfi_ep_t *cfiep;
+	cfiobject_t *cfi = pcd->cfi;
+	dwc_list_link_t *tmp;
+
+	/* If the EP address is known then reset the features for only that EP */
+	if (addr) {
+		cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
+		if (NULL == cfiep) {
+			CFI_INFO("%s: Error getting the EP address 0x%02x\n",
+				 __func__, addr);
+			return -DWC_E_INVALID;
+		}
+		retval = cfi_reset_sg_val(cfiep);
+	}
+	/* Otherwise (wValue == 0), reset all features of all EP's */
+	else {
+		/* Traverse all the active EP's and reset the feature(s) value(s) */
+		//list_for_each_entry(cfiep, &cfi->active_eps, lh) {
+		DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
+			cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
+			retval = cfi_reset_sg_val(cfiep);
+			if (retval < 0) {
+				CFI_INFO
+				    ("%s: Error resetting the feature Buffer Setup\n",
+				     __func__);
+				return retval;
+			}
+		}
+	}
+	return retval;
+}
+
+static int cfi_handle_reset_concat_val(struct dwc_otg_pcd *pcd, uint8_t addr)
+{
+	int retval = 0;
+	cfi_ep_t *cfiep;
+	cfiobject_t *cfi = pcd->cfi;
+	dwc_list_link_t *tmp;
+
+	/* If the EP address is known then reset the features for only that EP */
+	if (addr) {
+		cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
+		if (NULL == cfiep) {
+			CFI_INFO("%s: Error getting the EP address 0x%02x\n",
+				 __func__, addr);
+			return -DWC_E_INVALID;
+		}
+		retval = cfi_reset_concat_val(cfiep);
+	}
+	/* Otherwise (wValue == 0), reset all features of all EP's */
+	else {
+		/* Traverse all the active EP's and reset the feature(s) value(s) */
+		//list_for_each_entry(cfiep, &cfi->active_eps, lh) {
+		DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
+			cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
+			retval = cfi_reset_concat_val(cfiep);
+			if (retval < 0) {
+				CFI_INFO
+				    ("%s: Error resetting the feature Concatenation Value\n",
+				     __func__);
+				return retval;
+			}
+		}
+	}
+	return retval;
+}
+
+static int cfi_handle_reset_align_val(struct dwc_otg_pcd *pcd, uint8_t addr)
+{
+	int retval = 0;
+	cfi_ep_t *cfiep;
+	cfiobject_t *cfi = pcd->cfi;
+	dwc_list_link_t *tmp;
+
+	/* If the EP address is known then reset the features for only that EP */
+	if (addr) {
+		cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
+		if (NULL == cfiep) {
+			CFI_INFO("%s: Error getting the EP address 0x%02x\n",
+				 __func__, addr);
+			return -DWC_E_INVALID;
+		}
+		retval = cfi_reset_align_val(cfiep);
+	}
+	/* Otherwise (wValue == 0), reset all features of all EP's */
+	else {
+		/* Traverse all the active EP's and reset the feature(s) value(s) */
+		//list_for_each_entry(cfiep, &cfi->active_eps, lh) {
+		DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
+			cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
+			retval = cfi_reset_align_val(cfiep);
+			if (retval < 0) {
+				CFI_INFO
+				    ("%s: Error resetting the feature Aliignment Value\n",
+				     __func__);
+				return retval;
+			}
+		}
+	}
+	return retval;
+
+}
+
+static int cfi_preproc_reset(struct dwc_otg_pcd *pcd,
+			     struct cfi_usb_ctrlrequest *req)
+{
+	int retval = 0;
+
+	switch (req->wIndex) {
+	case 0:
+		/* Reset all features */
+		retval = cfi_handle_reset_all(pcd, req->wValue & 0xff);
+		break;
+
+	case FT_ID_DMA_BUFFER_SETUP:
+		/* Reset the SG buffer setup */
+		retval =
+		    cfi_handle_reset_dma_buff_setup(pcd, req->wValue & 0xff);
+		break;
+
+	case FT_ID_DMA_CONCAT_SETUP:
+		/* Reset the Concatenation buffer setup */
+		retval = cfi_handle_reset_concat_val(pcd, req->wValue & 0xff);
+		break;
+
+	case FT_ID_DMA_BUFF_ALIGN:
+		/* Reset the Alignment buffer setup */
+		retval = cfi_handle_reset_align_val(pcd, req->wValue & 0xff);
+		break;
+
+	case FT_ID_TX_FIFO_DEPTH:
+		retval =
+		    cfi_handle_reset_fifo_val(pcd, req->wValue & 0xff, 0, 1);
+		pcd->cfi->need_gadget_att = 0;
+		break;
+
+	case FT_ID_RX_FIFO_DEPTH:
+		retval = cfi_handle_reset_fifo_val(pcd, 0, 1, 0);
+		pcd->cfi->need_gadget_att = 0;
+		break;
+	default:
+		break;
+	}
+	return retval;
+}
+
+/**
+ * This function sets a new value for the SG buffer setup.
+ */
+static int cfi_ep_set_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
+{
+	uint8_t inaddr, outaddr;
+	cfi_ep_t *epin, *epout;
+	ddma_sg_buffer_setup_t *psgval;
+	uint32_t desccount, size;
+
+	CFI_INFO("%s\n", __func__);
+
+	psgval = (ddma_sg_buffer_setup_t *) buf;
+	desccount = (uint32_t) psgval->bCount;
+	size = (uint32_t) psgval->wSize;
+
+	/* Check the DMA descriptor count */
+	if ((desccount > MAX_DMA_DESCS_PER_EP) || (desccount == 0)) {
+		CFI_INFO
+		    ("%s: The count of DMA Descriptors should be between 1 and %d\n",
+		     __func__, MAX_DMA_DESCS_PER_EP);
+		return -DWC_E_INVALID;
+	}
+
+	/* Check the DMA descriptor count */
+
+	if (size == 0) {
+
+		CFI_INFO("%s: The transfer size should be at least 1 byte\n",
+			 __func__);
+
+		return -DWC_E_INVALID;
+
+	}
+
+	inaddr = psgval->bInEndpointAddress;
+	outaddr = psgval->bOutEndpointAddress;
+
+	epin = get_cfi_ep_by_addr(pcd->cfi, inaddr);
+	epout = get_cfi_ep_by_addr(pcd->cfi, outaddr);
+
+	if (NULL == epin || NULL == epout) {
+		CFI_INFO
+		    ("%s: Unable to get the endpoints inaddr=0x%02x outaddr=0x%02x\n",
+		     __func__, inaddr, outaddr);
+		return -DWC_E_INVALID;
+	}
+
+	epin->ep->dwc_ep.buff_mode = BM_SG;
+	dwc_memcpy(epin->bm_sg, psgval, sizeof(ddma_sg_buffer_setup_t));
+
+	epout->ep->dwc_ep.buff_mode = BM_SG;
+	dwc_memcpy(epout->bm_sg, psgval, sizeof(ddma_sg_buffer_setup_t));
+
+	return 0;
+}
+
+/**
+ * This function sets a new value for the buffer Alignment setup.
+ */
+static int cfi_ep_set_alignment_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
+{
+	cfi_ep_t *ep;
+	uint8_t addr;
+	ddma_align_buffer_setup_t *palignval;
+
+	palignval = (ddma_align_buffer_setup_t *) buf;
+	addr = palignval->bEndpointAddress;
+
+	ep = get_cfi_ep_by_addr(pcd->cfi, addr);
+
+	if (NULL == ep) {
+		CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
+			 __func__, addr);
+		return -DWC_E_INVALID;
+	}
+
+	ep->ep->dwc_ep.buff_mode = BM_ALIGN;
+	dwc_memcpy(ep->bm_align, palignval, sizeof(ddma_align_buffer_setup_t));
+
+	return 0;
+}
+
+/**
+ * This function sets a new value for the Concatenation buffer setup.
+ */
+static int cfi_ep_set_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
+{
+	uint8_t addr;
+	cfi_ep_t *ep;
+	struct _ddma_concat_buffer_setup_hdr *pConcatValHdr;
+	uint16_t *pVals;
+	uint32_t desccount;
+	int i;
+	uint16_t mps;
+
+	pConcatValHdr = (struct _ddma_concat_buffer_setup_hdr *)buf;
+	desccount = (uint32_t) pConcatValHdr->bDescCount;
+	pVals = (uint16_t *) (buf + BS_CONCAT_VAL_HDR_LEN);
+
+	/* Check the DMA descriptor count */
+	if (desccount > MAX_DMA_DESCS_PER_EP) {
+		CFI_INFO("%s: Maximum DMA Descriptor count should be %d\n",
+			 __func__, MAX_DMA_DESCS_PER_EP);
+		return -DWC_E_INVALID;
+	}
+
+	addr = pConcatValHdr->bEndpointAddress;
+	ep = get_cfi_ep_by_addr(pcd->cfi, addr);
+	if (NULL == ep) {
+		CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
+			 __func__, addr);
+		return -DWC_E_INVALID;
+	}
+
+	mps = UGETW(ep->ep->desc->wMaxPacketSize);
+
+#if 0
+	for (i = 0; i < desccount; i++) {
+		CFI_INFO("%s: wTxSize[%d]=0x%04x\n", __func__, i, pVals[i]);
+	}
+	CFI_INFO("%s: epname=%s; mps=%d\n", __func__, ep->ep->ep.name, mps);
+#endif
+
+	/* Check the wTxSizes to be less than or equal to the mps */
+	for (i = 0; i < desccount; i++) {
+		if (pVals[i] > mps) {
+			CFI_INFO
+			    ("%s: ERROR - the wTxSize[%d] should be <= MPS (wTxSize=%d)\n",
+			     __func__, i, pVals[i]);
+			return -DWC_E_INVALID;
+		}
+	}
+
+	ep->ep->dwc_ep.buff_mode = BM_CONCAT;
+	dwc_memcpy(ep->bm_concat, pConcatValHdr, BS_CONCAT_VAL_HDR_LEN);
+
+	/* Free the previously allocated storage for the wTxBytes */
+	if (ep->bm_concat->wTxBytes) {
+		DWC_FREE(ep->bm_concat->wTxBytes);
+	}
+
+	/* Allocate a new storage for the wTxBytes field */
+	ep->bm_concat->wTxBytes =
+	    DWC_ALLOC(sizeof(uint16_t) * pConcatValHdr->bDescCount);
+	if (NULL == ep->bm_concat->wTxBytes) {
+		CFI_INFO("%s: Unable to allocate memory\n", __func__);
+		return -DWC_E_NO_MEMORY;
+	}
+
+	/* Copy the new values into the wTxBytes filed */
+	dwc_memcpy(ep->bm_concat->wTxBytes, buf + BS_CONCAT_VAL_HDR_LEN,
+		   sizeof(uint16_t) * pConcatValHdr->bDescCount);
+
+	return 0;
+}
+
+/**
+ * This function calculates the total of all FIFO sizes
+ * 
+ * @param core_if Programming view of DWC_otg controller
+ *
+ * @return The total of data FIFO sizes.
+ *
+ */
+static uint16_t get_dfifo_size(dwc_otg_core_if_t * core_if)
+{
+	dwc_otg_core_params_t *params = core_if->core_params;
+	uint16_t dfifo_total = 0;
+	int i;
+
+	/* The shared RxFIFO size */
+	dfifo_total =
+	    params->dev_rx_fifo_size + params->dev_nperio_tx_fifo_size;
+
+	/* Add up each TxFIFO size to the total */
+	for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
+		dfifo_total += params->dev_tx_fifo_size[i];
+	}
+
+	return dfifo_total;
+}
+
+/**
+ * This function returns Rx FIFO size
+ * 
+ * @param core_if Programming view of DWC_otg controller
+ *
+ * @return The total of data FIFO sizes.
+ *
+ */
+static int32_t get_rxfifo_size(dwc_otg_core_if_t * core_if, uint16_t wValue)
+{
+	switch (wValue >> 8) {
+	case 0:
+		return (core_if->pwron_rxfsiz <
+			32768) ? core_if->pwron_rxfsiz : 32768;
+		break;
+	case 1:
+		return core_if->core_params->dev_rx_fifo_size;
+		break;
+	default:
+		return -DWC_E_INVALID;
+		break;
+	}
+}
+
+/**
+ * This function returns Tx FIFO size for IN EP
+ * 
+ * @param core_if Programming view of DWC_otg controller
+ *
+ * @return The total of data FIFO sizes.
+ *
+ */
+static int32_t get_txfifo_size(struct dwc_otg_pcd *pcd, uint16_t wValue)
+{
+	dwc_otg_pcd_ep_t *ep;
+
+	ep = get_ep_by_addr(pcd, wValue & 0xff);
+
+	if (NULL == ep) {
+		CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
+			 __func__, wValue & 0xff);
+		return -DWC_E_INVALID;
+	}
+
+	if (!ep->dwc_ep.is_in) {
+		CFI_INFO
+		    ("%s: No Tx FIFO assingned to the Out endpoint addr=0x%02x\n",
+		     __func__, wValue & 0xff);
+		return -DWC_E_INVALID;
+	}
+
+	switch (wValue >> 8) {
+	case 0:
+		return (GET_CORE_IF(pcd)->pwron_txfsiz
+			[ep->dwc_ep.tx_fifo_num - 1] <
+			768) ? GET_CORE_IF(pcd)->pwron_txfsiz[ep->
+							      dwc_ep.tx_fifo_num
+							      - 1] : 32768;
+		break;
+	case 1:
+		return GET_CORE_IF(pcd)->core_params->
+		    dev_tx_fifo_size[ep->dwc_ep.num - 1];
+		break;
+	default:
+		return -DWC_E_INVALID;
+		break;
+	}
+}
+
+/**
+ * This function checks if the submitted combination of 
+ * device mode FIFO sizes is possible or not.
+ * 
+ * @param core_if Programming view of DWC_otg controller
+ *
+ * @return 1 if possible, 0 otherwise.
+ *
+ */
+static uint8_t check_fifo_sizes(dwc_otg_core_if_t * core_if)
+{
+	uint16_t dfifo_actual = 0;
+	dwc_otg_core_params_t *params = core_if->core_params;
+	uint16_t start_addr = 0;
+	int i;
+
+	dfifo_actual =
+	    params->dev_rx_fifo_size + params->dev_nperio_tx_fifo_size;
+
+	for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
+		dfifo_actual += params->dev_tx_fifo_size[i];
+	}
+
+	if (dfifo_actual > core_if->total_fifo_size) {
+		return 0;
+	}
+
+	if (params->dev_rx_fifo_size > 32768 || params->dev_rx_fifo_size < 16)
+		return 0;
+
+	if (params->dev_nperio_tx_fifo_size > 32768
+	    || params->dev_nperio_tx_fifo_size < 16)
+		return 0;
+
+	for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
+
+		if (params->dev_tx_fifo_size[i] > 768
+		    || params->dev_tx_fifo_size[i] < 4)
+			return 0;
+	}
+
+	if (params->dev_rx_fifo_size > core_if->pwron_rxfsiz)
+		return 0;
+	start_addr = params->dev_rx_fifo_size;
+
+	if (params->dev_nperio_tx_fifo_size > core_if->pwron_gnptxfsiz)
+		return 0;
+	start_addr += params->dev_nperio_tx_fifo_size;
+
+	for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
+
+		if (params->dev_tx_fifo_size[i] > core_if->pwron_txfsiz[i])
+			return 0;
+		start_addr += params->dev_tx_fifo_size[i];
+	}
+
+	return 1;
+}
+
+/**
+ * This function resizes Device mode FIFOs
+ * 
+ * @param core_if Programming view of DWC_otg controller
+ *
+ * @return 1 if successful, 0 otherwise
+ *
+ */
+static uint8_t resize_fifos(dwc_otg_core_if_t * core_if)
+{
+	int i = 0;
+	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+	dwc_otg_core_params_t *params = core_if->core_params;
+	uint32_t rx_fifo_size;
+	fifosize_data_t nptxfifosize;
+	fifosize_data_t txfifosize[15];
+
+	uint32_t rx_fsz_bak;
+	uint32_t nptxfsz_bak;
+	uint32_t txfsz_bak[15];
+
+	uint16_t start_address;
+	uint8_t retval = 1;
+
+	if (!check_fifo_sizes(core_if)) {
+		return 0;
+	}
+
+	/* Configure data FIFO sizes */
+	if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
+		rx_fsz_bak = DWC_READ_REG32(&global_regs->grxfsiz);
+		rx_fifo_size = params->dev_rx_fifo_size;
+		DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fifo_size);
+
+		/*
+		 * Tx FIFOs These FIFOs are numbered from 1 to 15.
+		 * Indexes of the FIFO size module parameters in the
+		 * dev_tx_fifo_size array and the FIFO size registers in
+		 * the dtxfsiz array run from 0 to 14.
+		 */
+
+		/* Non-periodic Tx FIFO */
+		nptxfsz_bak = DWC_READ_REG32(&global_regs->gnptxfsiz);
+		nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
+		start_address = 0x400;
+		nptxfifosize.b.startaddr = start_address;
+
+		DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfifosize.d32);
+
+		start_address += nptxfifosize.b.depth;
+
+		for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
+			txfsz_bak[i] = DWC_READ_REG32(&global_regs->dtxfsiz[i]);
+
+			txfifosize[i].b.depth = params->dev_tx_fifo_size[i];
+			txfifosize[i].b.startaddr = start_address;
+			DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
+					txfifosize[i].d32);
+
+			start_address += txfifosize[i].b.depth;
+		}
+
+		/** Check if register values are set correctly */
+		if (rx_fifo_size != DWC_READ_REG32(&global_regs->grxfsiz)) {
+			retval = 0;
+		}
+
+		if (nptxfifosize.d32 != DWC_READ_REG32(&global_regs->gnptxfsiz)) {
+			retval = 0;
+		}
+
+		for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
+			if (txfifosize[i].d32 !=
+			    DWC_READ_REG32(&global_regs->dtxfsiz[i])) {
+				retval = 0;
+			}
+		}
+
+		/** If register values are not set correctly, reset old values */
+		if (retval == 0) {
+			DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fsz_bak);
+
+			/* Non-periodic Tx FIFO */
+			DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfsz_bak);
+
+			for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
+				DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
+						txfsz_bak[i]);
+			}
+		}
+	} else {
+		return 0;
+	}
+
+	/* Flush the FIFOs */
+	dwc_otg_flush_tx_fifo(core_if, 0x10);	/* all Tx FIFOs */
+	dwc_otg_flush_rx_fifo(core_if);
+
+	return retval;
+}
+
+/**
+ * This function sets a new value for the buffer Alignment setup.
+ */
+static int cfi_ep_set_tx_fifo_val(uint8_t * buf, dwc_otg_pcd_t * pcd)
+{
+	int retval;
+	uint32_t fsiz;
+	uint16_t size;
+	uint16_t ep_addr;
+	dwc_otg_pcd_ep_t *ep;
+	dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
+	tx_fifo_size_setup_t *ptxfifoval;
+
+	ptxfifoval = (tx_fifo_size_setup_t *) buf;
+	ep_addr = ptxfifoval->bEndpointAddress;
+	size = ptxfifoval->wDepth;
+
+	ep = get_ep_by_addr(pcd, ep_addr);
+
+	CFI_INFO
+	    ("%s: Set Tx FIFO size: endpoint addr=0x%02x, depth=%d, FIFO Num=%d\n",
+	     __func__, ep_addr, size, ep->dwc_ep.tx_fifo_num);
+
+	if (NULL == ep) {
+		CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
+			 __func__, ep_addr);
+		return -DWC_E_INVALID;
+	}
+
+	fsiz = params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1];
+	params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] = size;
+
+	if (resize_fifos(GET_CORE_IF(pcd))) {
+		retval = 0;
+	} else {
+		CFI_INFO
+		    ("%s: Error setting the feature Tx FIFO Size for EP%d\n",
+		     __func__, ep_addr);
+		params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] = fsiz;
+		retval = -DWC_E_INVALID;
+	}
+
+	return retval;
+}
+
+/**
+ * This function sets a new value for the buffer Alignment setup.
+ */
+static int cfi_set_rx_fifo_val(uint8_t * buf, dwc_otg_pcd_t * pcd)
+{
+	int retval;
+	uint32_t fsiz;
+	uint16_t size;
+	dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
+	rx_fifo_size_setup_t *prxfifoval;
+
+	prxfifoval = (rx_fifo_size_setup_t *) buf;
+	size = prxfifoval->wDepth;
+
+	fsiz = params->dev_rx_fifo_size;
+	params->dev_rx_fifo_size = size;
+
+	if (resize_fifos(GET_CORE_IF(pcd))) {
+		retval = 0;
+	} else {
+		CFI_INFO("%s: Error setting the feature Rx FIFO Size\n",
+			 __func__);
+		params->dev_rx_fifo_size = fsiz;
+		retval = -DWC_E_INVALID;
+	}
+
+	return retval;
+}
+
+/**
+ * This function reads the SG of an EP's buffer setup into the buffer buf
+ */
+static int cfi_ep_get_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
+			     struct cfi_usb_ctrlrequest *req)
+{
+	int retval = -DWC_E_INVALID;
+	uint8_t addr;
+	cfi_ep_t *ep;
+
+	/* The Low Byte of the wValue contains a non-zero address of the endpoint */
+	addr = req->wValue & 0xFF;
+	if (addr == 0)		/* The address should be non-zero */
+		return retval;
+
+	ep = get_cfi_ep_by_addr(pcd->cfi, addr);
+	if (NULL == ep) {
+		CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
+			 __func__, addr);
+		return retval;
+	}
+
+	dwc_memcpy(buf, ep->bm_sg, BS_SG_VAL_DESC_LEN);
+	retval = BS_SG_VAL_DESC_LEN;
+	return retval;
+}
+
+/**
+ * This function reads the Concatenation value of an EP's buffer mode into 
+ * the buffer buf
+ */
+static int cfi_ep_get_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
+				 struct cfi_usb_ctrlrequest *req)
+{
+	int retval = -DWC_E_INVALID;
+	uint8_t addr;
+	cfi_ep_t *ep;
+	uint8_t desc_count;
+
+	/* The Low Byte of the wValue contains a non-zero address of the endpoint */
+	addr = req->wValue & 0xFF;
+	if (addr == 0)		/* The address should be non-zero */
+		return retval;
+
+	ep = get_cfi_ep_by_addr(pcd->cfi, addr);
+	if (NULL == ep) {
+		CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
+			 __func__, addr);
+		return retval;
+	}
+
+	/* Copy the header to the buffer */
+	dwc_memcpy(buf, ep->bm_concat, BS_CONCAT_VAL_HDR_LEN);
+	/* Advance the buffer pointer by the header size */
+	buf += BS_CONCAT_VAL_HDR_LEN;
+
+	desc_count = ep->bm_concat->hdr.bDescCount;
+	/* Copy alll the wTxBytes to the buffer */
+	dwc_memcpy(buf, ep->bm_concat->wTxBytes, sizeof(uid16_t) * desc_count);
+
+	retval = BS_CONCAT_VAL_HDR_LEN + sizeof(uid16_t) * desc_count;
+	return retval;
+}
+
+/**
+ * This function reads the buffer Alignment value of an EP's buffer mode into 
+ * the buffer buf
+ *
+ * @return The total number of bytes copied to the buffer or negative error code.
+ */
+static int cfi_ep_get_align_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
+				struct cfi_usb_ctrlrequest *req)
+{
+	int retval = -DWC_E_INVALID;
+	uint8_t addr;
+	cfi_ep_t *ep;
+
+	/* The Low Byte of the wValue contains a non-zero address of the endpoint */
+	addr = req->wValue & 0xFF;
+	if (addr == 0)		/* The address should be non-zero */
+		return retval;
+
+	ep = get_cfi_ep_by_addr(pcd->cfi, addr);
+	if (NULL == ep) {
+		CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
+			 __func__, addr);
+		return retval;
+	}
+
+	dwc_memcpy(buf, ep->bm_align, BS_ALIGN_VAL_HDR_LEN);
+	retval = BS_ALIGN_VAL_HDR_LEN;
+
+	return retval;
+}
+
+/**
+ * This function sets a new value for the specified feature
+ * 
+ * @param	pcd	A pointer to the PCD object
+ * 
+ * @return 0 if successful, negative error code otherwise to stall the DCE.
+ */
+static int cfi_set_feature_value(struct dwc_otg_pcd *pcd)
+{
+	int retval = -DWC_E_NOT_SUPPORTED;
+	uint16_t wIndex, wValue;
+	uint8_t bRequest;
+	struct dwc_otg_core_if *coreif;
+	cfiobject_t *cfi = pcd->cfi;
+	struct cfi_usb_ctrlrequest *ctrl_req;
+	uint8_t *buf;
+	ctrl_req = &cfi->ctrl_req;
+
+	buf = pcd->cfi->ctrl_req.data;
+
+	coreif = GET_CORE_IF(pcd);
+	bRequest = ctrl_req->bRequest;
+	wIndex = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wIndex);
+	wValue = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wValue);
+
+	/* See which feature is to be modified */
+	switch (wIndex) {
+	case FT_ID_DMA_BUFFER_SETUP:
+		/* Modify the feature */
+		if ((retval = cfi_ep_set_sg_val(buf, pcd)) < 0)
+			return retval;
+
+		/* And send this request to the gadget */
+		cfi->need_gadget_att = 1;
+		break;
+
+	case FT_ID_DMA_BUFF_ALIGN:
+		if ((retval = cfi_ep_set_alignment_val(buf, pcd)) < 0)
+			return retval;
+		cfi->need_gadget_att = 1;
+		break;
+
+	case FT_ID_DMA_CONCAT_SETUP:
+		/* Modify the feature */
+		if ((retval = cfi_ep_set_concat_val(buf, pcd)) < 0)
+			return retval;
+		cfi->need_gadget_att = 1;
+		break;
+
+	case FT_ID_DMA_CIRCULAR:
+		CFI_INFO("FT_ID_DMA_CIRCULAR\n");
+		break;
+
+	case FT_ID_THRESHOLD_SETUP:
+		CFI_INFO("FT_ID_THRESHOLD_SETUP\n");
+		break;
+
+	case FT_ID_DFIFO_DEPTH:
+		CFI_INFO("FT_ID_DFIFO_DEPTH\n");
+		break;
+
+	case FT_ID_TX_FIFO_DEPTH:
+		CFI_INFO("FT_ID_TX_FIFO_DEPTH\n");
+		if ((retval = cfi_ep_set_tx_fifo_val(buf, pcd)) < 0)
+			return retval;
+		cfi->need_gadget_att = 0;
+		break;
+
+	case FT_ID_RX_FIFO_DEPTH:
+		CFI_INFO("FT_ID_RX_FIFO_DEPTH\n");
+		if ((retval = cfi_set_rx_fifo_val(buf, pcd)) < 0)
+			return retval;
+		cfi->need_gadget_att = 0;
+		break;
+	}
+
+	return retval;
+}
+
+#endif //DWC_UTE_CFI
diff --git a/drivers/usb/dwc_otg/dwc_otg_cfi.h b/drivers/usb/dwc_otg/dwc_otg_cfi.h
new file mode 100644
index 0000000..cbccdab
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_cfi.h
@@ -0,0 +1,320 @@
+/* ==========================================================================
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+#if !defined(__DWC_OTG_CFI_H__)
+#define __DWC_OTG_CFI_H__
+
+#include "dwc_otg_pcd.h"
+#include "dwc_cfi_common.h"
+
+/**
+ * @file
+ * This file contains the CFI related OTG PCD specific common constants, 
+ * interfaces(functions and macros) and data structures.The CFI Protocol is an 
+ * optional interface for internal testing purposes that a DUT may implement to 
+ * support testing of configurable features.
+ *
+ */
+
+struct dwc_otg_pcd;
+struct dwc_otg_pcd_ep;
+
+/** OTG CFI Features (properties) ID constants */
+/** This is a request for all Core Features */
+#define FT_ID_DMA_MODE					0x0001
+#define FT_ID_DMA_BUFFER_SETUP			0x0002
+#define FT_ID_DMA_BUFF_ALIGN			0x0003
+#define FT_ID_DMA_CONCAT_SETUP			0x0004
+#define FT_ID_DMA_CIRCULAR				0x0005
+#define FT_ID_THRESHOLD_SETUP			0x0006
+#define FT_ID_DFIFO_DEPTH				0x0007
+#define FT_ID_TX_FIFO_DEPTH				0x0008
+#define FT_ID_RX_FIFO_DEPTH				0x0009
+
+/**********************************************************/
+#define CFI_INFO_DEF
+
+#ifdef CFI_INFO_DEF
+#define CFI_INFO(fmt...)	DWC_PRINTF("CFI: " fmt);
+#else
+#define CFI_INFO(fmt...)
+#endif
+
+#define min(x,y) ({ \
+	x < y ? x : y; })
+
+#define max(x,y) ({ \
+	x > y ? x : y; })
+
+/**
+ * Descriptor DMA SG Buffer setup structure (SG buffer). This structure is
+ * also used for setting up a buffer for Circular DDMA.
+ */
+struct _ddma_sg_buffer_setup {
+#define BS_SG_VAL_DESC_LEN	6
+	/* The OUT EP address */
+	uint8_t bOutEndpointAddress;
+	/* The IN EP address */
+	uint8_t bInEndpointAddress;
+	/* Number of bytes to put between transfer segments (must be DWORD boundaries) */
+	uint8_t bOffset;
+	/* The number of transfer segments (a DMA descriptors per each segment) */
+	uint8_t bCount;
+	/* Size (in byte) of each transfer segment */
+	uint16_t wSize;
+} __attribute__ ((packed));
+typedef struct _ddma_sg_buffer_setup ddma_sg_buffer_setup_t;
+
+/** Descriptor DMA Concatenation Buffer setup structure */
+struct _ddma_concat_buffer_setup_hdr {
+#define BS_CONCAT_VAL_HDR_LEN	4
+	/* The endpoint for which the buffer is to be set up */
+	uint8_t bEndpointAddress;
+	/* The count of descriptors to be used */
+	uint8_t bDescCount;
+	/* The total size of the transfer */
+	uint16_t wSize;
+} __attribute__ ((packed));
+typedef struct _ddma_concat_buffer_setup_hdr ddma_concat_buffer_setup_hdr_t;
+
+/** Descriptor DMA Concatenation Buffer setup structure */
+struct _ddma_concat_buffer_setup {
+	/* The SG header */
+	ddma_concat_buffer_setup_hdr_t hdr;
+
+	/* The XFER sizes pointer (allocated dynamically) */
+	uint16_t *wTxBytes;
+} __attribute__ ((packed));
+typedef struct _ddma_concat_buffer_setup ddma_concat_buffer_setup_t;
+
+/** Descriptor DMA Alignment Buffer setup structure */
+struct _ddma_align_buffer_setup {
+#define BS_ALIGN_VAL_HDR_LEN	2
+	uint8_t bEndpointAddress;
+	uint8_t bAlign;
+} __attribute__ ((packed));
+typedef struct _ddma_align_buffer_setup ddma_align_buffer_setup_t;
+
+/** Transmit FIFO Size setup structure */
+struct _tx_fifo_size_setup {
+	uint8_t bEndpointAddress;
+	uint16_t wDepth;
+} __attribute__ ((packed));
+typedef struct _tx_fifo_size_setup tx_fifo_size_setup_t;
+
+/** Transmit FIFO Size setup structure */
+struct _rx_fifo_size_setup {
+	uint16_t wDepth;
+} __attribute__ ((packed));
+typedef struct _rx_fifo_size_setup rx_fifo_size_setup_t;
+
+/**
+ * struct cfi_usb_ctrlrequest - the CFI implementation of the struct usb_ctrlrequest
+ * This structure encapsulates the standard usb_ctrlrequest and adds a pointer
+ * to the data returned in the data stage of a 3-stage Control Write requests.
+ */
+struct cfi_usb_ctrlrequest {
+	uint8_t bRequestType;
+	uint8_t bRequest;
+	uint16_t wValue;
+	uint16_t wIndex;
+	uint16_t wLength;
+	uint8_t *data;
+} UPACKED;
+
+/*---------------------------------------------------------------------------*/
+
+/**
+ * The CFI wrapper of the enabled and activated dwc_otg_pcd_ep structures.
+ * This structure is used to store the buffer setup data for any
+ * enabled endpoint in the PCD.
+ */
+struct cfi_ep {
+	/* Entry for the list container */
+	dwc_list_link_t lh;
+	/* Pointer to the active PCD endpoint structure */
+	struct dwc_otg_pcd_ep *ep;
+	/* The last descriptor in the chain of DMA descriptors of the endpoint */
+	struct dwc_otg_dma_desc *dma_desc_last;
+	/* The SG feature value */
+	ddma_sg_buffer_setup_t *bm_sg;
+	/* The Circular feature value */
+	ddma_sg_buffer_setup_t *bm_circ;
+	/* The Concatenation feature value */
+	ddma_concat_buffer_setup_t *bm_concat;
+	/* The Alignment feature value */
+	ddma_align_buffer_setup_t *bm_align;
+	/* XFER length */
+	uint32_t xfer_len;
+	/*
+	 * Count of DMA descriptors currently used.
+	 * The total should not exceed the MAX_DMA_DESCS_PER_EP value
+	 * defined in the dwc_otg_cil.h
+	 */
+	uint32_t desc_count;
+};
+typedef struct cfi_ep cfi_ep_t;
+
+typedef struct cfi_dma_buff {
+#define CFI_IN_BUF_LEN	1024
+#define CFI_OUT_BUF_LEN	1024
+	dma_addr_t addr;
+	uint8_t *buf;
+} cfi_dma_buff_t;
+
+struct cfiobject;
+
+/**
+ * This is the interface for the CFI operations.
+ *
+ * @param	ep_enable			Called when any endpoint is enabled and activated.
+ * @param	release				Called when the CFI object is released and it needs to correctly
+ *								deallocate the dynamic memory
+ * @param	ctrl_write_complete	Called when the data stage of the request is complete
+ */
+typedef struct cfi_ops {
+	int (*ep_enable) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd,
+			  struct dwc_otg_pcd_ep * ep);
+	void *(*ep_alloc_buf) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd,
+			       struct dwc_otg_pcd_ep * ep, dma_addr_t * dma,
+			       unsigned size, gfp_t flags);
+	void (*release) (struct cfiobject * cfi);
+	int (*ctrl_write_complete) (struct cfiobject * cfi,
+				    struct dwc_otg_pcd * pcd);
+	void (*build_descriptors) (struct cfiobject * cfi,
+				   struct dwc_otg_pcd * pcd,
+				   struct dwc_otg_pcd_ep * ep,
+				   dwc_otg_pcd_request_t * req);
+} cfi_ops_t;
+
+struct cfiobject {
+	cfi_ops_t ops;
+	struct dwc_otg_pcd *pcd;
+	struct usb_gadget *gadget;
+
+	/* Buffers used to send/receive CFI-related request data */
+	cfi_dma_buff_t buf_in;
+	cfi_dma_buff_t buf_out;
+
+	/* CFI specific Control request wrapper */
+	struct cfi_usb_ctrlrequest ctrl_req;
+
+	/* The list of active EP's in the PCD of type cfi_ep_t */
+	dwc_list_link_t active_eps;
+
+	/* This flag shall control the propagation of a specific request
+	 * to the gadget's processing routines.
+	 * 0 - no gadget handling
+	 * 1 - the gadget needs to know about this request (w/o completing a status
+	 * phase - just return a 0 to the _setup callback)
+	 */
+	uint8_t need_gadget_att;
+
+	/* Flag indicating whether the status IN phase needs to be
+	 * completed by the PCD
+	 */
+	uint8_t need_status_in_complete;
+};
+typedef struct cfiobject cfiobject_t;
+
+#define DUMP_MSG
+
+#if defined(DUMP_MSG)
+static inline void dump_msg(const u8 * buf, unsigned int length)
+{
+	unsigned int start, num, i;
+	char line[52], *p;
+
+	if (length >= 512)
+		return;
+
+	start = 0;
+	while (length > 0) {
+		num = min(length, 16u);
+		p = line;
+		for (i = 0; i < num; ++i) {
+			if (i == 8)
+				*p++ = ' ';
+			DWC_SPRINTF(p, " %02x", buf[i]);
+			p += 3;
+		}
+		*p = 0;
+		DWC_DEBUG("%6x: %s\n", start, line);
+		buf += num;
+		start += num;
+		length -= num;
+	}
+}
+#else
+static inline void dump_msg(const u8 * buf, unsigned int length)
+{
+}
+#endif
+
+/**
+ * This function returns a pointer to cfi_ep_t object with the addr address.
+ */
+static inline struct cfi_ep *get_cfi_ep_by_addr(struct cfiobject *cfi,
+						uint8_t addr)
+{
+	struct cfi_ep *pcfiep;
+	dwc_list_link_t *tmp;
+
+	DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
+		pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
+
+		if (pcfiep->ep->desc->bEndpointAddress == addr) {
+			return pcfiep;
+		}
+	}
+
+	return NULL;
+}
+
+/**
+ * This function returns a pointer to cfi_ep_t object that matches
+ * the dwc_otg_pcd_ep object.
+ */
+static inline struct cfi_ep *get_cfi_ep_by_pcd_ep(struct cfiobject *cfi,
+						  struct dwc_otg_pcd_ep *ep)
+{
+	struct cfi_ep *pcfiep = NULL;
+	dwc_list_link_t *tmp;
+
+	DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
+		pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
+		if (pcfiep->ep == ep) {
+			return pcfiep;
+		}
+	}
+	return NULL;
+}
+
+int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl);
+
+#endif /* (__DWC_OTG_CFI_H__) */
diff --git a/drivers/usb/dwc_otg/dwc_otg_cil.c b/drivers/usb/dwc_otg/dwc_otg_cil.c
new file mode 100644
index 0000000..84f1179
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_cil.c
@@ -0,0 +1,7049 @@
+/* ==========================================================================
+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil.c $
+ * $Revision: #189 $
+ * $Date: 2011/10/24 $
+ * $Change: 1871160 $
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+/** @file
+ *
+ * The Core Interface Layer provides basic services for accessing and
+ * managing the DWC_otg hardware. These services are used by both the
+ * Host Controller Driver and the Peripheral Controller Driver.
+ *
+ * The CIL manages the memory map for the core so that the HCD and PCD
+ * don't have to do this separately. It also handles basic tasks like
+ * reading/writing the registers and data FIFOs in the controller.
+ * Some of the data access functions provide encapsulation of several
+ * operations required to perform a task, such as writing multiple
+ * registers to start a transfer. Finally, the CIL performs basic
+ * services that are not specific to either the host or device modes
+ * of operation. These services include management of the OTG Host
+ * Negotiation Protocol (HNP) and Session Request Protocol (SRP). A
+ * Diagnostic API is also provided to allow testing of the controller
+ * hardware.
+ *
+ * The Core Interface Layer has the following requirements:
+ * - Provides basic controller operations.
+ * - Minimal use of OS services.
+ * - The OS services used will be abstracted by using inline functions
+ *	 or macros.
+ *
+ */
+
+#include "dwc_os.h"
+#include "dwc_otg_regs.h"
+#include "dwc_otg_cil.h"
+
+static int dwc_otg_setup_params(dwc_otg_core_if_t * core_if);
+
+/**
+ * This function is called to initialize the DWC_otg CSR data
+ * structures. The register addresses in the device and host
+ * structures are initialized from the base address supplied by the
+ * caller. The calling function must make the OS calls to get the
+ * base address of the DWC_otg controller registers. The core_params
+ * argument holds the parameters that specify how the core should be
+ * configured.
+ *
+ * @param reg_base_addr Base address of DWC_otg core registers
+ *
+ */
+dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t * reg_base_addr)
+{
+	dwc_otg_core_if_t *core_if = 0;
+	dwc_otg_dev_if_t *dev_if = 0;
+	dwc_otg_host_if_t *host_if = 0;
+	uint8_t *reg_base = (uint8_t *) reg_base_addr;
+	int i = 0;
+
+	DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, reg_base_addr);
+
+	core_if = DWC_ALLOC(sizeof(dwc_otg_core_if_t));
+
+	if (core_if == NULL) {
+		DWC_DEBUGPL(DBG_CIL,
+			    "Allocation of dwc_otg_core_if_t failed\n");
+		return 0;
+	}
+	core_if->core_global_regs = (dwc_otg_core_global_regs_t *) reg_base;
+
+	/*
+	 * Allocate the Device Mode structures.
+	 */
+	dev_if = DWC_ALLOC(sizeof(dwc_otg_dev_if_t));
+
+	if (dev_if == NULL) {
+		DWC_DEBUGPL(DBG_CIL, "Allocation of dwc_otg_dev_if_t failed\n");
+		DWC_FREE(core_if);
+		return 0;
+	}
+
+	dev_if->dev_global_regs =
+	    (dwc_otg_device_global_regs_t *) (reg_base +
+					      DWC_DEV_GLOBAL_REG_OFFSET);
+
+	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
+		dev_if->in_ep_regs[i] = (dwc_otg_dev_in_ep_regs_t *)
+		    (reg_base + DWC_DEV_IN_EP_REG_OFFSET +
+		     (i * DWC_EP_REG_OFFSET));
+
+		dev_if->out_ep_regs[i] = (dwc_otg_dev_out_ep_regs_t *)
+		    (reg_base + DWC_DEV_OUT_EP_REG_OFFSET +
+		     (i * DWC_EP_REG_OFFSET));
+		DWC_DEBUGPL(DBG_CILV, "in_ep_regs[%d]->diepctl=%p\n",
+			    i, &dev_if->in_ep_regs[i]->diepctl);
+		DWC_DEBUGPL(DBG_CILV, "out_ep_regs[%d]->doepctl=%p\n",
+			    i, &dev_if->out_ep_regs[i]->doepctl);
+	}
+
+	dev_if->speed = 0;	// unknown
+
+	core_if->dev_if = dev_if;
+
+	/*
+	 * Allocate the Host Mode structures.
+	 */
+	host_if = DWC_ALLOC(sizeof(dwc_otg_host_if_t));
+
+	if (host_if == NULL) {
+		DWC_DEBUGPL(DBG_CIL,
+			    "Allocation of dwc_otg_host_if_t failed\n");
+		DWC_FREE(dev_if);
+		DWC_FREE(core_if);
+		return 0;
+	}
+
+	host_if->host_global_regs = (dwc_otg_host_global_regs_t *)
+	    (reg_base + DWC_OTG_HOST_GLOBAL_REG_OFFSET);
+
+	host_if->hprt0 =
+	    (uint32_t *) (reg_base + DWC_OTG_HOST_PORT_REGS_OFFSET);
+
+	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
+		host_if->hc_regs[i] = (dwc_otg_hc_regs_t *)
+		    (reg_base + DWC_OTG_HOST_CHAN_REGS_OFFSET +
+		     (i * DWC_OTG_CHAN_REGS_OFFSET));
+		DWC_DEBUGPL(DBG_CILV, "hc_reg[%d]->hcchar=%p\n",
+			    i, &host_if->hc_regs[i]->hcchar);
+	}
+
+	host_if->num_host_channels = MAX_EPS_CHANNELS;
+	core_if->host_if = host_if;
+
+	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
+		core_if->data_fifo[i] =
+		    (uint32_t *) (reg_base + DWC_OTG_DATA_FIFO_OFFSET +
+				  (i * DWC_OTG_DATA_FIFO_SIZE));
+		DWC_DEBUGPL(DBG_CILV, "data_fifo[%d]=0x%08lx\n",
+			    i, (unsigned long)core_if->data_fifo[i]);
+	}
+
+	core_if->pcgcctl = (uint32_t *) (reg_base + DWC_OTG_PCGCCTL_OFFSET);
+
+	/* Initiate lx_state to L3 disconnected state */
+	core_if->lx_state = DWC_OTG_L3;
+	/*
+	 * Store the contents of the hardware configuration registers here for
+	 * easy access later.
+	 */
+	core_if->hwcfg1.d32 =
+	    DWC_READ_REG32(&core_if->core_global_regs->ghwcfg1);
+	core_if->hwcfg2.d32 =
+	    DWC_READ_REG32(&core_if->core_global_regs->ghwcfg2);
+	core_if->hwcfg3.d32 =
+	    DWC_READ_REG32(&core_if->core_global_regs->ghwcfg3);
+	core_if->hwcfg4.d32 =
+	    DWC_READ_REG32(&core_if->core_global_regs->ghwcfg4);
+
+	/* Force host mode to get HPTXFSIZ exact power on value */
+	{
+		gusbcfg_data_t gusbcfg = {.d32 = 0 };
+		gusbcfg.d32 =  DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
+		gusbcfg.b.force_host_mode = 1;
+		DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
+		dwc_mdelay(100);
+		core_if->hptxfsiz.d32 =
+		DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
+		gusbcfg.d32 =  DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
+		gusbcfg.b.force_host_mode = 0;
+		DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
+		dwc_mdelay(100);
+	}
+
+	DWC_DEBUGPL(DBG_CILV, "hwcfg1=%08x\n", core_if->hwcfg1.d32);
+	DWC_DEBUGPL(DBG_CILV, "hwcfg2=%08x\n", core_if->hwcfg2.d32);
+	DWC_DEBUGPL(DBG_CILV, "hwcfg3=%08x\n", core_if->hwcfg3.d32);
+	DWC_DEBUGPL(DBG_CILV, "hwcfg4=%08x\n", core_if->hwcfg4.d32);
+
+	core_if->hcfg.d32 =
+	    DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
+	core_if->dcfg.d32 =
+	    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
+
+	DWC_DEBUGPL(DBG_CILV, "hcfg=%08x\n", core_if->hcfg.d32);
+	DWC_DEBUGPL(DBG_CILV, "dcfg=%08x\n", core_if->dcfg.d32);
+
+	DWC_DEBUGPL(DBG_CILV, "op_mode=%0x\n", core_if->hwcfg2.b.op_mode);
+	DWC_DEBUGPL(DBG_CILV, "arch=%0x\n", core_if->hwcfg2.b.architecture);
+	DWC_DEBUGPL(DBG_CILV, "num_dev_ep=%d\n", core_if->hwcfg2.b.num_dev_ep);
+	DWC_DEBUGPL(DBG_CILV, "num_host_chan=%d\n",
+		    core_if->hwcfg2.b.num_host_chan);
+	DWC_DEBUGPL(DBG_CILV, "nonperio_tx_q_depth=0x%0x\n",
+		    core_if->hwcfg2.b.nonperio_tx_q_depth);
+	DWC_DEBUGPL(DBG_CILV, "host_perio_tx_q_depth=0x%0x\n",
+		    core_if->hwcfg2.b.host_perio_tx_q_depth);
+	DWC_DEBUGPL(DBG_CILV, "dev_token_q_depth=0x%0x\n",
+		    core_if->hwcfg2.b.dev_token_q_depth);
+
+	DWC_DEBUGPL(DBG_CILV, "Total FIFO SZ=%d\n",
+		    core_if->hwcfg3.b.dfifo_depth);
+	DWC_DEBUGPL(DBG_CILV, "xfer_size_cntr_width=%0x\n",
+		    core_if->hwcfg3.b.xfer_size_cntr_width);
+
+	/*
+	 * Set the SRP sucess bit for FS-I2c
+	 */
+	core_if->srp_success = 0;
+	core_if->srp_timer_started = 0;
+
+	/*
+	 * Create new workqueue and init works
+	 */
+	core_if->wq_otg = DWC_WORKQ_ALLOC("dwc_otg");
+	if (core_if->wq_otg == 0) {
+		DWC_WARN("DWC_WORKQ_ALLOC failed\n");
+		DWC_FREE(host_if);
+		DWC_FREE(dev_if);
+		DWC_FREE(core_if);
+		return 0;
+	}
+
+	core_if->snpsid = DWC_READ_REG32(&core_if->core_global_regs->gsnpsid);
+
+	DWC_PRINTF("Core Release: %x.%x%x%x\n",
+		   (core_if->snpsid >> 12 & 0xF),
+		   (core_if->snpsid >> 8 & 0xF),
+		   (core_if->snpsid >> 4 & 0xF), (core_if->snpsid & 0xF));
+
+	core_if->wkp_timer = DWC_TIMER_ALLOC("Wake Up Timer",
+					     w_wakeup_detected, core_if);
+	if (core_if->wkp_timer == 0) {
+		DWC_WARN("DWC_TIMER_ALLOC failed\n");
+		DWC_FREE(host_if);
+		DWC_FREE(dev_if);
+		DWC_WORKQ_FREE(core_if->wq_otg);
+		DWC_FREE(core_if);
+		return 0;
+	}
+
+	if (dwc_otg_setup_params(core_if)) {
+		DWC_WARN("Error while setting core params\n");
+	}
+
+	core_if->hibernation_suspend = 0;
+
+	/** ADP initialization */
+	dwc_otg_adp_init(core_if);
+
+	return core_if;
+}
+
+/**
+ * This function frees the structures allocated by dwc_otg_cil_init().
+ *
+ * @param core_if The core interface pointer returned from
+ * 		  dwc_otg_cil_init().
+ *
+ */
+void dwc_otg_cil_remove(dwc_otg_core_if_t * core_if)
+{
+	/* Disable all interrupts */
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, 1, 0);
+	DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0);
+
+	if (core_if->wq_otg) {
+		DWC_WORKQ_WAIT_WORK_DONE(core_if->wq_otg, 500);
+		DWC_WORKQ_FREE(core_if->wq_otg);
+	}
+	if (core_if->dev_if) {
+		DWC_FREE(core_if->dev_if);
+	}
+	if (core_if->host_if) {
+		DWC_FREE(core_if->host_if);
+	}
+
+	/** Remove ADP Stuff  */
+	dwc_otg_adp_remove(core_if);
+	if (core_if->core_params) {
+		DWC_FREE(core_if->core_params);
+	}
+	if (core_if->wkp_timer) {
+		DWC_TIMER_FREE(core_if->wkp_timer);
+	}
+	if (core_if->srp_timer) {
+		DWC_TIMER_FREE(core_if->srp_timer);
+	}
+	DWC_FREE(core_if);
+}
+
+/**
+ * This function enables the controller's Global Interrupt in the AHB Config
+ * register.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ */
+void dwc_otg_enable_global_interrupts(dwc_otg_core_if_t * core_if)
+{
+	gahbcfg_data_t ahbcfg = {.d32 = 0 };
+	ahbcfg.b.glblintrmsk = 1;	/* Enable interrupts */
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, 0, ahbcfg.d32);
+}
+
+/**
+ * This function disables the controller's Global Interrupt in the AHB Config
+ * register.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ */
+void dwc_otg_disable_global_interrupts(dwc_otg_core_if_t * core_if)
+{
+	gahbcfg_data_t ahbcfg = {.d32 = 0 };
+	ahbcfg.b.glblintrmsk = 1;	/* Disable interrupts */
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);
+}
+
+/**
+ * This function initializes the commmon interrupts, used in both
+ * device and host modes.
+ *
+ * @param core_if Programming view of the DWC_otg controller
+ *
+ */
+static void dwc_otg_enable_common_interrupts(dwc_otg_core_if_t * core_if)
+{
+	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+	gintmsk_data_t intr_mask = {.d32 = 0 };
+
+	/* Clear any pending OTG Interrupts */
+	DWC_WRITE_REG32(&global_regs->gotgint, 0xFFFFFFFF);
+
+	/* Clear any pending interrupts */
+	DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
+
+	/*
+	 * Enable the interrupts in the GINTMSK.
+	 */
+	intr_mask.b.modemismatch = 1;
+	intr_mask.b.otgintr = 1;
+
+	if (!core_if->dma_enable) {
+		intr_mask.b.rxstsqlvl = 1;
+	}
+
+	intr_mask.b.conidstschng = 1;
+	intr_mask.b.wkupintr = 1;
+	intr_mask.b.disconnect = 0;
+	intr_mask.b.usbsuspend = 1;
+	intr_mask.b.sessreqintr = 1;
+#ifdef CONFIG_USB_DWC_OTG_LPM
+	if (core_if->core_params->lpm_enable) {
+		intr_mask.b.lpmtranrcvd = 1;
+	}
+#endif
+	DWC_WRITE_REG32(&global_regs->gintmsk, intr_mask.d32);
+}
+
+/*
+ * The restore operation is modified to support Synopsys Emulated Powerdown and
+ * Hibernation. This function is for exiting from Device mode hibernation by
+ * Host Initiated Resume/Reset and Device Initiated Remote-Wakeup.
+ * @param core_if Programming view of DWC_otg controller.
+ * @param rem_wakeup - indicates whether resume is initiated by Device or Host.
+ * @param reset - indicates whether resume is initiated by Reset.
+ */
+int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
+				       int rem_wakeup, int reset)
+{
+	gpwrdn_data_t gpwrdn = {.d32 = 0 };
+	pcgcctl_data_t pcgcctl = {.d32 = 0 };
+	dctl_data_t dctl = {.d32 = 0 };
+
+	int timeout = 2000;
+
+	if (!core_if->hibernation_suspend) {
+		DWC_PRINTF("Already exited from Hibernation\n");
+		return 1;
+	}
+
+	DWC_DEBUGPL(DBG_PCD, "%s called\n", __FUNCTION__);
+	/* Switch-on voltage to the core */
+	gpwrdn.b.pwrdnswtch = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+	dwc_udelay(10);
+
+	/* Reset core */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.pwrdnrstn = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+	dwc_udelay(10);
+
+	/* Assert Restore signal */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.restore = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
+	dwc_udelay(10);
+
+	/* Disable power clamps */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.pwrdnclmp = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+
+	if (rem_wakeup) {
+		dwc_udelay(70);
+	}
+
+	/* Deassert Reset core */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.pwrdnrstn = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
+	dwc_udelay(10);
+
+	/* Disable PMU interrupt */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.pmuintsel = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+
+	/* Mask interrupts from gpwrdn */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.connect_det_msk = 1;
+	gpwrdn.b.srp_det_msk = 1;
+	gpwrdn.b.disconn_det_msk = 1;
+	gpwrdn.b.rst_det_msk = 1;
+	gpwrdn.b.lnstchng_msk = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+
+	/* Indicates that we are going out from hibernation */
+	core_if->hibernation_suspend = 0;
+
+	/*
+	 * Set Restore Essential Regs bit in PCGCCTL register, restore_mode = 1
+	 * indicates restore from remote_wakeup
+	 */
+	restore_essential_regs(core_if, rem_wakeup, 0);
+
+	/*
+	 * Wait a little for seeing new value of variable hibernation_suspend if
+	 * Restore done interrupt received before polling
+	 */
+	dwc_udelay(10);
+
+	if (core_if->hibernation_suspend == 0) {
+		/*
+		 * Wait For Restore_done Interrupt. This mechanism of polling the
+		 * interrupt is introduced to avoid any possible race conditions
+		 */
+		do {
+			gintsts_data_t gintsts;
+			gintsts.d32 =
+			    DWC_READ_REG32(&core_if->core_global_regs->gintsts);
+			if (gintsts.b.restoredone) {
+				gintsts.d32 = 0;
+				gintsts.b.restoredone = 1;
+				DWC_WRITE_REG32(&core_if->core_global_regs->
+						gintsts, gintsts.d32);
+				DWC_PRINTF("Restore Done Interrupt seen\n");
+				break;
+			}
+			dwc_udelay(10);
+		} while (--timeout);
+		if (!timeout) {
+			DWC_PRINTF("Restore Done interrupt wasn't generated here\n");
+		}
+	}
+	/* Clear all pending interupts */
+	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
+
+	/* De-assert Restore */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.restore = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+	dwc_udelay(10);
+
+	if (!rem_wakeup) {
+		pcgcctl.d32 = 0;
+		pcgcctl.b.rstpdwnmodule = 1;
+		DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
+	}
+
+	/* Restore GUSBCFG and DCFG */
+	DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
+			core_if->gr_backup->gusbcfg_local);
+	DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
+			core_if->dr_backup->dcfg);
+
+	/* De-assert Wakeup Logic */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.pmuactv = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+	dwc_udelay(10);
+
+	if (!rem_wakeup) {
+		/* Set Device programming done bit */
+		dctl.b.pwronprgdone = 1;
+		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
+	} else {
+		/* Start Remote Wakeup Signaling */
+		dctl.d32 = core_if->dr_backup->dctl;
+		dctl.b.rmtwkupsig = 1;
+		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
+	}
+
+	dwc_mdelay(2);
+	/* Clear all pending interupts */
+	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
+
+	/* Restore global registers */
+	dwc_otg_restore_global_regs(core_if);
+	/* Restore device global registers */
+	dwc_otg_restore_dev_regs(core_if, rem_wakeup);
+
+	if (rem_wakeup) {
+		dwc_mdelay(7);
+		dctl.d32 = 0;
+		dctl.b.rmtwkupsig = 1;
+		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
+	}
+
+	core_if->hibernation_suspend = 0;
+	/* The core will be in ON STATE */
+	core_if->lx_state = DWC_OTG_L0;
+	DWC_PRINTF("Hibernation recovery completes here\n");
+
+	return 1;
+}
+
+/*
+ * The restore operation is modified to support Synopsys Emulated Powerdown and
+ * Hibernation. This function is for exiting from Host mode hibernation by
+ * Host Initiated Resume/Reset and Device Initiated Remote-Wakeup.
+ * @param core_if Programming view of DWC_otg controller.
+ * @param rem_wakeup - indicates whether resume is initiated by Device or Host.
+ * @param reset - indicates whether resume is initiated by Reset.
+ */
+int dwc_otg_host_hibernation_restore(dwc_otg_core_if_t * core_if,
+				     int rem_wakeup, int reset)
+{
+	gpwrdn_data_t gpwrdn = {.d32 = 0 };
+	hprt0_data_t hprt0 = {.d32 = 0 };
+
+	int timeout = 2000;
+
+	DWC_DEBUGPL(DBG_HCD, "%s called\n", __FUNCTION__);
+	/* Switch-on voltage to the core */
+	gpwrdn.b.pwrdnswtch = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+	dwc_udelay(10);
+
+	/* Reset core */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.pwrdnrstn = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+	dwc_udelay(10);
+
+	/* Assert Restore signal */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.restore = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
+	dwc_udelay(10);
+
+	/* Disable power clamps */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.pwrdnclmp = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+
+	if (!rem_wakeup) {
+		dwc_udelay(50);
+	}
+
+	/* Deassert Reset core */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.pwrdnrstn = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
+	dwc_udelay(10);
+
+	/* Disable PMU interrupt */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.pmuintsel = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+
+	gpwrdn.d32 = 0;
+	gpwrdn.b.connect_det_msk = 1;
+	gpwrdn.b.srp_det_msk = 1;
+	gpwrdn.b.disconn_det_msk = 1;
+	gpwrdn.b.rst_det_msk = 1;
+	gpwrdn.b.lnstchng_msk = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+
+	/* Indicates that we are going out from hibernation */
+	core_if->hibernation_suspend = 0;
+
+	/* Set Restore Essential Regs bit in PCGCCTL register */
+	restore_essential_regs(core_if, rem_wakeup, 1);
+
+	/* Wait a little for seeing new value of variable hibernation_suspend if
+	 * Restore done interrupt received before polling */
+	dwc_udelay(10);
+
+	if (core_if->hibernation_suspend == 0) {
+		/* Wait For Restore_done Interrupt. This mechanism of polling the
+		 * interrupt is introduced to avoid any possible race conditions
+		 */
+		do {
+			gintsts_data_t gintsts;
+			gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
+			if (gintsts.b.restoredone) {
+				gintsts.d32 = 0;
+				gintsts.b.restoredone = 1;
+         		DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
+				DWC_DEBUGPL(DBG_HCD,"Restore Done Interrupt seen\n");
+				break;
+			}
+			dwc_udelay(10);
+		} while (--timeout);
+		if (!timeout) {
+			DWC_WARN("Restore Done interrupt wasn't generated\n");
+		}
+	}
+
+	/* Set the flag's value to 0 again after receiving restore done interrupt */
+	core_if->hibernation_suspend = 0;
+
+	/* This step is not described in functional spec but if not wait for this
+	 * delay, mismatch interrupts occurred because just after restore core is
+	 * in Device mode(gintsts.curmode == 0) */
+	dwc_mdelay(100);
+
+	/* Clear all pending interrupts */
+	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
+
+	/* De-assert Restore */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.restore = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+	dwc_udelay(10);
+
+	/* Restore GUSBCFG and HCFG */
+	DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
+			core_if->gr_backup->gusbcfg_local);
+	DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg,
+			core_if->hr_backup->hcfg_local);
+
+	/* De-assert Wakeup Logic */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.pmuactv = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+	dwc_udelay(10);
+
+	/* Start the Resume operation by programming HPRT0 */
+	hprt0.d32 = core_if->hr_backup->hprt0_local;
+	hprt0.b.prtpwr = 1;
+	hprt0.b.prtena = 0;
+	hprt0.b.prtsusp = 0;
+	DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+
+	DWC_PRINTF("Resume Starts Now\n");
+	if (!reset) {		// Indicates it is Resume Operation
+		hprt0.d32 = core_if->hr_backup->hprt0_local;
+		hprt0.b.prtres = 1;
+		hprt0.b.prtpwr = 1;
+		hprt0.b.prtena = 0;
+		hprt0.b.prtsusp = 0;
+		DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+
+		if (!rem_wakeup)
+			hprt0.b.prtres = 0;
+		/* Wait for Resume time and then program HPRT again */
+		dwc_mdelay(100);
+		DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+
+	} else {		// Indicates it is Reset Operation
+		hprt0.d32 = core_if->hr_backup->hprt0_local;
+		hprt0.b.prtrst = 1;
+		hprt0.b.prtpwr = 1;
+		hprt0.b.prtena = 0;
+		hprt0.b.prtsusp = 0;
+		DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+		/* Wait for Reset time and then program HPRT again */
+		dwc_mdelay(60);
+		hprt0.b.prtrst = 0;
+		DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+	}
+	/* Clear all interrupt status */
+	hprt0.d32 = dwc_otg_read_hprt0(core_if);
+	hprt0.b.prtconndet = 1;
+	hprt0.b.prtenchng = 1;
+	DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+
+	/* Clear all pending interupts */
+	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
+
+	/* Restore global registers */
+	dwc_otg_restore_global_regs(core_if);
+	/* Restore host global registers */
+	dwc_otg_restore_host_regs(core_if, reset);
+
+	/* The core will be in ON STATE */
+	core_if->lx_state = DWC_OTG_L0;
+	DWC_PRINTF("Hibernation recovery is complete here\n");
+	return 0;
+}
+
+/** Saves some register values into system memory. */
+int dwc_otg_save_global_regs(dwc_otg_core_if_t * core_if)
+{
+	struct dwc_otg_global_regs_backup *gr;
+	int i;
+
+	gr = core_if->gr_backup;
+	if (!gr) {
+		gr = DWC_ALLOC(sizeof(*gr));
+		if (!gr) {
+			return -DWC_E_NO_MEMORY;
+		}
+		core_if->gr_backup = gr;
+	}
+
+	gr->gotgctl_local = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
+	gr->gintmsk_local = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
+	gr->gahbcfg_local = DWC_READ_REG32(&core_if->core_global_regs->gahbcfg);
+	gr->gusbcfg_local = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
+	gr->grxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
+	gr->gnptxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz);
+	gr->hptxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
+#ifdef CONFIG_USB_DWC_OTG_LPM
+	gr->glpmcfg_local = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
+#endif
+	gr->gi2cctl_local = DWC_READ_REG32(&core_if->core_global_regs->gi2cctl);
+	gr->pcgcctl_local = DWC_READ_REG32(core_if->pcgcctl);
+	gr->gdfifocfg_local =
+	    DWC_READ_REG32(&core_if->core_global_regs->gdfifocfg);
+	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
+		gr->dtxfsiz_local[i] =
+		    DWC_READ_REG32(&(core_if->core_global_regs->dtxfsiz[i]));
+	}
+
+	DWC_DEBUGPL(DBG_ANY, "===========Backing Global registers==========\n");
+	DWC_DEBUGPL(DBG_ANY, "Backed up gotgctl   = %08x\n", gr->gotgctl_local);
+	DWC_DEBUGPL(DBG_ANY, "Backed up gintmsk   = %08x\n", gr->gintmsk_local);
+	DWC_DEBUGPL(DBG_ANY, "Backed up gahbcfg   = %08x\n", gr->gahbcfg_local);
+	DWC_DEBUGPL(DBG_ANY, "Backed up gusbcfg   = %08x\n", gr->gusbcfg_local);
+	DWC_DEBUGPL(DBG_ANY, "Backed up grxfsiz   = %08x\n", gr->grxfsiz_local);
+	DWC_DEBUGPL(DBG_ANY, "Backed up gnptxfsiz = %08x\n",
+		    gr->gnptxfsiz_local);
+	DWC_DEBUGPL(DBG_ANY, "Backed up hptxfsiz  = %08x\n",
+		    gr->hptxfsiz_local);
+#ifdef CONFIG_USB_DWC_OTG_LPM
+	DWC_DEBUGPL(DBG_ANY, "Backed up glpmcfg   = %08x\n", gr->glpmcfg_local);
+#endif
+	DWC_DEBUGPL(DBG_ANY, "Backed up gi2cctl   = %08x\n", gr->gi2cctl_local);
+	DWC_DEBUGPL(DBG_ANY, "Backed up pcgcctl   = %08x\n", gr->pcgcctl_local);
+	DWC_DEBUGPL(DBG_ANY,"Backed up gdfifocfg   = %08x\n",gr->gdfifocfg_local);
+
+	return 0;
+}
+
+/** Saves GINTMSK register before setting the msk bits. */
+int dwc_otg_save_gintmsk_reg(dwc_otg_core_if_t * core_if)
+{
+	struct dwc_otg_global_regs_backup *gr;
+
+	gr = core_if->gr_backup;
+	if (!gr) {
+		gr = DWC_ALLOC(sizeof(*gr));
+		if (!gr) {
+			return -DWC_E_NO_MEMORY;
+		}
+		core_if->gr_backup = gr;
+	}
+
+	gr->gintmsk_local = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
+
+	DWC_DEBUGPL(DBG_ANY,"=============Backing GINTMSK registers============\n");
+	DWC_DEBUGPL(DBG_ANY, "Backed up gintmsk   = %08x\n", gr->gintmsk_local);
+
+	return 0;
+}
+
+int dwc_otg_save_dev_regs(dwc_otg_core_if_t * core_if)
+{
+	struct dwc_otg_dev_regs_backup *dr;
+	int i;
+
+	dr = core_if->dr_backup;
+	if (!dr) {
+		dr = DWC_ALLOC(sizeof(*dr));
+		if (!dr) {
+			return -DWC_E_NO_MEMORY;
+		}
+		core_if->dr_backup = dr;
+	}
+
+	dr->dcfg = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
+	dr->dctl = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
+	dr->daintmsk =
+	    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daintmsk);
+	dr->diepmsk =
+	    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->diepmsk);
+	dr->doepmsk =
+	    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->doepmsk);
+
+	for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
+		dr->diepctl[i] =
+		    DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl);
+		dr->dieptsiz[i] =
+		    DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->dieptsiz);
+		dr->diepdma[i] =
+		    DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepdma);
+	}
+
+	DWC_DEBUGPL(DBG_ANY,
+		    "=============Backing Host registers==============\n");
+	DWC_DEBUGPL(DBG_ANY, "Backed up dcfg            = %08x\n", dr->dcfg);
+	DWC_DEBUGPL(DBG_ANY, "Backed up dctl        = %08x\n", dr->dctl);
+	DWC_DEBUGPL(DBG_ANY, "Backed up daintmsk            = %08x\n",
+		    dr->daintmsk);
+	DWC_DEBUGPL(DBG_ANY, "Backed up diepmsk        = %08x\n", dr->diepmsk);
+	DWC_DEBUGPL(DBG_ANY, "Backed up doepmsk        = %08x\n", dr->doepmsk);
+	for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
+		DWC_DEBUGPL(DBG_ANY, "Backed up diepctl[%d]        = %08x\n", i,
+			    dr->diepctl[i]);
+		DWC_DEBUGPL(DBG_ANY, "Backed up dieptsiz[%d]        = %08x\n",
+			    i, dr->dieptsiz[i]);
+		DWC_DEBUGPL(DBG_ANY, "Backed up diepdma[%d]        = %08x\n", i,
+			    dr->diepdma[i]);
+	}
+
+	return 0;
+}
+
+int dwc_otg_save_host_regs(dwc_otg_core_if_t * core_if)
+{
+	struct dwc_otg_host_regs_backup *hr;
+	int i;
+
+	hr = core_if->hr_backup;
+	if (!hr) {
+		hr = DWC_ALLOC(sizeof(*hr));
+		if (!hr) {
+			return -DWC_E_NO_MEMORY;
+		}
+		core_if->hr_backup = hr;
+	}
+
+	hr->hcfg_local =
+	    DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
+	hr->haintmsk_local =
+	    DWC_READ_REG32(&core_if->host_if->host_global_regs->haintmsk);
+	for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
+		hr->hcintmsk_local[i] =
+		    DWC_READ_REG32(&core_if->host_if->hc_regs[i]->hcintmsk);
+	}
+	hr->hprt0_local = DWC_READ_REG32(core_if->host_if->hprt0);
+	hr->hfir_local =
+	    DWC_READ_REG32(&core_if->host_if->host_global_regs->hfir);
+
+	DWC_DEBUGPL(DBG_ANY,
+		    "=============Backing Host registers===============\n");
+	DWC_DEBUGPL(DBG_ANY, "Backed up hcfg		= %08x\n",
+		    hr->hcfg_local);
+	DWC_DEBUGPL(DBG_ANY, "Backed up haintmsk = %08x\n", hr->haintmsk_local);
+	for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
+		DWC_DEBUGPL(DBG_ANY, "Backed up hcintmsk[%02d]=%08x\n", i,
+			    hr->hcintmsk_local[i]);
+	}
+	DWC_DEBUGPL(DBG_ANY, "Backed up hprt0           = %08x\n",
+		    hr->hprt0_local);
+	DWC_DEBUGPL(DBG_ANY, "Backed up hfir           = %08x\n",
+		    hr->hfir_local);
+
+	return 0;
+}
+
+int dwc_otg_restore_global_regs(dwc_otg_core_if_t *core_if)
+{
+	struct dwc_otg_global_regs_backup *gr;
+	int i;
+
+	gr = core_if->gr_backup;
+	if (!gr) {
+		return -DWC_E_INVALID;
+	}
+
+	DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl, gr->gotgctl_local);
+	DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gr->gintmsk_local);
+	DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gr->gusbcfg_local);
+	DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gr->gahbcfg_local);
+	DWC_WRITE_REG32(&core_if->core_global_regs->grxfsiz, gr->grxfsiz_local);
+	DWC_WRITE_REG32(&core_if->core_global_regs->gnptxfsiz,
+			gr->gnptxfsiz_local);
+	DWC_WRITE_REG32(&core_if->core_global_regs->hptxfsiz,
+			gr->hptxfsiz_local);
+	DWC_WRITE_REG32(&core_if->core_global_regs->gdfifocfg,
+			gr->gdfifocfg_local);
+	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
+		DWC_WRITE_REG32(&core_if->core_global_regs->dtxfsiz[i],
+				gr->dtxfsiz_local[i]);
+	}
+
+	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
+	DWC_WRITE_REG32(core_if->host_if->hprt0, 0x0000100A);
+	DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg,
+			(gr->gahbcfg_local));
+	return 0;
+}
+
+int dwc_otg_restore_dev_regs(dwc_otg_core_if_t * core_if, int rem_wakeup)
+{
+	struct dwc_otg_dev_regs_backup *dr;
+	int i;
+
+	dr = core_if->dr_backup;
+
+	if (!dr) {
+		return -DWC_E_INVALID;
+	}
+
+	if (!rem_wakeup)
+	{
+		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dr->dctl);
+	}
+
+	DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daintmsk, dr->daintmsk);
+	DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->diepmsk, dr->diepmsk);
+	DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->doepmsk, dr->doepmsk);
+
+	for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
+		DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl, dr->diepctl[i]);
+		DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->dieptsiz, dr->dieptsiz[i]);
+		DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->diepdma, dr->diepdma[i]);
+	}
+
+	return 0;
+}
+
+int dwc_otg_restore_host_regs(dwc_otg_core_if_t * core_if, int reset)
+{
+	struct dwc_otg_host_regs_backup *hr;
+	int i;
+	hr = core_if->hr_backup;
+
+	if (!hr) {
+		return -DWC_E_INVALID;
+	}
+
+	DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hr->hcfg_local);
+	//if (!reset)
+	//{
+	//      DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hfir, hr->hfir_local);
+	//}
+
+	DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haintmsk,
+			hr->haintmsk_local);
+	for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
+		DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcintmsk,
+				hr->hcintmsk_local[i]);
+	}
+
+	return 0;
+}
+
+int restore_lpm_i2c_regs(dwc_otg_core_if_t * core_if)
+{
+	struct dwc_otg_global_regs_backup *gr;
+
+	gr = core_if->gr_backup;
+
+	/* Restore values for LPM and I2C */
+#ifdef CONFIG_USB_DWC_OTG_LPM
+	DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, gr->glpmcfg_local);
+#endif
+	DWC_WRITE_REG32(&core_if->core_global_regs->gi2cctl, gr->gi2cctl_local);
+
+	return 0;
+}
+
+int restore_essential_regs(dwc_otg_core_if_t * core_if, int rmode, int is_host)
+{
+	struct dwc_otg_global_regs_backup *gr;
+	pcgcctl_data_t pcgcctl = {.d32 = 0 };
+	gahbcfg_data_t gahbcfg = {.d32 = 0 };
+	gusbcfg_data_t gusbcfg = {.d32 = 0 };
+	gintmsk_data_t gintmsk = {.d32 = 0 };
+
+	/* Restore LPM and I2C registers */
+	restore_lpm_i2c_regs(core_if);
+
+	/* Set PCGCCTL to 0 */
+	DWC_WRITE_REG32(core_if->pcgcctl, 0x00000000);
+
+	gr = core_if->gr_backup;
+	/* Load restore values for [31:14] bits */
+	DWC_WRITE_REG32(core_if->pcgcctl,
+			((gr->pcgcctl_local & 0xffffc000) | 0x00020000));
+
+	/* Umnask global Interrupt in GAHBCFG and restore it */
+	gahbcfg.d32 = gr->gahbcfg_local;
+	gahbcfg.b.glblintrmsk = 1;
+	DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gahbcfg.d32);
+
+	/* Clear all pending interupts */
+	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
+
+	/* Unmask restore done interrupt */
+	gintmsk.b.restoredone = 1;
+	DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32);
+
+	/* Restore GUSBCFG and HCFG/DCFG */
+	gusbcfg.d32 = core_if->gr_backup->gusbcfg_local;
+	DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
+
+	if (is_host) {
+		hcfg_data_t hcfg = {.d32 = 0 };
+		hcfg.d32 = core_if->hr_backup->hcfg_local;
+		DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg,
+				hcfg.d32);
+
+		/* Load restore values for [31:14] bits */
+		pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
+		pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
+
+		if (rmode)
+			pcgcctl.b.restoremode = 1;
+		DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
+		dwc_udelay(10);
+
+		/* Load restore values for [31:14] bits and set EssRegRestored bit */
+		pcgcctl.d32 = gr->pcgcctl_local | 0xffffc000;
+		pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
+		pcgcctl.b.ess_reg_restored = 1;
+		if (rmode)
+			pcgcctl.b.restoremode = 1;
+		DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
+	} else {
+		dcfg_data_t dcfg = {.d32 = 0 };
+		dcfg.d32 = core_if->dr_backup->dcfg;
+		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
+
+		/* Load restore values for [31:14] bits */
+		pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
+		pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
+		if (!rmode) {
+			pcgcctl.d32 |= 0x208;
+		}
+		DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
+		dwc_udelay(10);
+
+		/* Load restore values for [31:14] bits */
+		pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
+		pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
+		pcgcctl.b.ess_reg_restored = 1;
+		if (!rmode)
+			pcgcctl.d32 |= 0x208;
+		DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
+	}
+
+	return 0;
+}
+
+/**
+ * Initializes the FSLSPClkSel field of the HCFG register depending on the PHY
+ * type.
+ */
+static void init_fslspclksel(dwc_otg_core_if_t * core_if)
+{
+	uint32_t val;
+	hcfg_data_t hcfg;
+
+	if (((core_if->hwcfg2.b.hs_phy_type == 2) &&
+	     (core_if->hwcfg2.b.fs_phy_type == 1) &&
+	     (core_if->core_params->ulpi_fs_ls)) ||
+	    (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
+		/* Full speed PHY */
+		val = DWC_HCFG_48_MHZ;
+	} else {
+		/* High speed PHY running at full speed or high speed */
+		val = DWC_HCFG_30_60_MHZ;
+	}
+
+	DWC_DEBUGPL(DBG_CIL, "Initializing HCFG.FSLSPClkSel to 0x%1x\n", val);
+	hcfg.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
+	hcfg.b.fslspclksel = val;
+	DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hcfg.d32);
+}
+
+/**
+ * Initializes the DevSpd field of the DCFG register depending on the PHY type
+ * and the enumeration speed of the device.
+ */
+static void init_devspd(dwc_otg_core_if_t * core_if)
+{
+	uint32_t val;
+	dcfg_data_t dcfg;
+
+	if (((core_if->hwcfg2.b.hs_phy_type == 2) &&
+	     (core_if->hwcfg2.b.fs_phy_type == 1) &&
+	     (core_if->core_params->ulpi_fs_ls)) ||
+	    (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
+		/* Full speed PHY */
+		val = 0x3;
+	} else if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) {
+		/* High speed PHY running at full speed */
+		val = 0x1;
+	} else {
+		/* High speed PHY running at high speed */
+		val = 0x0;
+	}
+
+	DWC_DEBUGPL(DBG_CIL, "Initializing DCFG.DevSpd to 0x%1x\n", val);
+
+	dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
+	dcfg.b.devspd = val;
+	DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
+}
+
+/**
+ * This function calculates the number of IN EPS
+ * using GHWCFG1 and GHWCFG2 registers values
+ *
+ * @param core_if Programming view of the DWC_otg controller
+ */
+static uint32_t calc_num_in_eps(dwc_otg_core_if_t * core_if)
+{
+	uint32_t num_in_eps = 0;
+	uint32_t num_eps = core_if->hwcfg2.b.num_dev_ep;
+	uint32_t hwcfg1 = core_if->hwcfg1.d32 >> 3;
+	uint32_t num_tx_fifos = core_if->hwcfg4.b.num_in_eps;
+	int i;
+
+	for (i = 0; i < num_eps; ++i) {
+		if (!(hwcfg1 & 0x1))
+			num_in_eps++;
+
+		hwcfg1 >>= 2;
+	}
+
+	if (core_if->hwcfg4.b.ded_fifo_en) {
+		num_in_eps =
+		    (num_in_eps > num_tx_fifos) ? num_tx_fifos : num_in_eps;
+	}
+
+	return num_in_eps;
+}
+
+/**
+ * This function calculates the number of OUT EPS
+ * using GHWCFG1 and GHWCFG2 registers values
+ *
+ * @param core_if Programming view of the DWC_otg controller
+ */
+static uint32_t calc_num_out_eps(dwc_otg_core_if_t * core_if)
+{
+	uint32_t num_out_eps = 0;
+	uint32_t num_eps = core_if->hwcfg2.b.num_dev_ep;
+	uint32_t hwcfg1 = core_if->hwcfg1.d32 >> 2;
+	int i;
+
+	for (i = 0; i < num_eps; ++i) {
+		if (!(hwcfg1 & 0x1))
+			num_out_eps++;
+
+		hwcfg1 >>= 2;
+	}
+	return num_out_eps;
+}
+
+/**
+ * This function initializes the DWC_otg controller registers and
+ * prepares the core for device mode or host mode operation.
+ *
+ * @param core_if Programming view of the DWC_otg controller
+ *
+ */
+void dwc_otg_core_init(dwc_otg_core_if_t * core_if)
+{
+	int i = 0;
+	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+	gahbcfg_data_t ahbcfg = {.d32 = 0 };
+	gusbcfg_data_t usbcfg = {.d32 = 0 };
+	gi2cctl_data_t i2cctl = {.d32 = 0 };
+
+	DWC_DEBUGPL(DBG_CILV, "dwc_otg_core_init(%p)\n", core_if);
+
+	/* Common Initialization */
+	usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
+
+	/* Program the ULPI External VBUS bit if needed */
+	usbcfg.b.ulpi_ext_vbus_drv =
+	    (core_if->core_params->phy_ulpi_ext_vbus ==
+	     DWC_PHY_ULPI_EXTERNAL_VBUS) ? 1 : 0;
+
+	/* Set external TS Dline pulsing */
+	usbcfg.b.term_sel_dl_pulse =
+	    (core_if->core_params->ts_dline == 1) ? 1 : 0;
+	DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
+
+	/* Reset the Controller */
+	dwc_otg_core_reset(core_if);
+
+	core_if->adp_enable = core_if->core_params->adp_supp_enable;
+	core_if->power_down = core_if->core_params->power_down;
+	core_if->otg_sts = 0;
+
+	/* Initialize parameters from Hardware configuration registers. */
+	dev_if->num_in_eps = calc_num_in_eps(core_if);
+	dev_if->num_out_eps = calc_num_out_eps(core_if);
+
+	DWC_DEBUGPL(DBG_CIL, "num_dev_perio_in_ep=%d\n",
+		    core_if->hwcfg4.b.num_dev_perio_in_ep);
+
+	for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) {
+		dev_if->perio_tx_fifo_size[i] =
+		    DWC_READ_REG32(&global_regs->dtxfsiz[i]) >> 16;
+		DWC_DEBUGPL(DBG_CIL, "Periodic Tx FIFO SZ #%d=0x%0x\n",
+			    i, dev_if->perio_tx_fifo_size[i]);
+	}
+
+	for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
+		dev_if->tx_fifo_size[i] =
+		    DWC_READ_REG32(&global_regs->dtxfsiz[i]) >> 16;
+		DWC_DEBUGPL(DBG_CIL, "Tx FIFO SZ #%d=0x%0x\n",
+			    i, dev_if->tx_fifo_size[i]);
+	}
+
+	core_if->total_fifo_size = core_if->hwcfg3.b.dfifo_depth;
+	core_if->rx_fifo_size = DWC_READ_REG32(&global_regs->grxfsiz);
+	core_if->nperio_tx_fifo_size =
+	    DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16;
+
+	DWC_DEBUGPL(DBG_CIL, "Total FIFO SZ=%d\n", core_if->total_fifo_size);
+	DWC_DEBUGPL(DBG_CIL, "Rx FIFO SZ=%d\n", core_if->rx_fifo_size);
+	DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO SZ=%d\n",
+		    core_if->nperio_tx_fifo_size);
+
+	/* This programming sequence needs to happen in FS mode before any other
+	 * programming occurs */
+	if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) &&
+	    (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
+		/* If FS mode with FS PHY */
+
+		/* core_init() is now called on every switch so only call the
+		 * following for the first time through. */
+		if (!core_if->phy_init_done) {
+			core_if->phy_init_done = 1;
+			DWC_DEBUGPL(DBG_CIL, "FS_PHY detected\n");
+			usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
+			usbcfg.b.physel = 1;
+			DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
+
+			/* Reset after a PHY select */
+			dwc_otg_core_reset(core_if);
+		}
+
+		/* Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS.      Also
+		 * do this on HNP Dev/Host mode switches (done in dev_init and
+		 * host_init). */
+		if (dwc_otg_is_host_mode(core_if)) {
+			init_fslspclksel(core_if);
+		} else {
+			init_devspd(core_if);
+		}
+
+		if (core_if->core_params->i2c_enable) {
+			DWC_DEBUGPL(DBG_CIL, "FS_PHY Enabling I2c\n");
+			/* Program GUSBCFG.OtgUtmifsSel to I2C */
+			usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
+			usbcfg.b.otgutmifssel = 1;
+			DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
+
+			/* Program GI2CCTL.I2CEn */
+			i2cctl.d32 = DWC_READ_REG32(&global_regs->gi2cctl);
+			i2cctl.b.i2cdevaddr = 1;
+			i2cctl.b.i2cen = 0;
+			DWC_WRITE_REG32(&global_regs->gi2cctl, i2cctl.d32);
+			i2cctl.b.i2cen = 1;
+			DWC_WRITE_REG32(&global_regs->gi2cctl, i2cctl.d32);
+		}
+
+	} /* endif speed == DWC_SPEED_PARAM_FULL */
+	else {
+		/* High speed PHY. */
+		if (!core_if->phy_init_done) {
+			core_if->phy_init_done = 1;
+			/* HS PHY parameters.  These parameters are preserved
+			 * during soft reset so only program the first time.  Do
+			 * a soft reset immediately after setting phyif.  */
+
+			if (core_if->core_params->phy_type == 2) {
+				/* ULPI interface */
+				usbcfg.b.ulpi_utmi_sel = 1;
+				usbcfg.b.phyif = 0;
+				usbcfg.b.ddrsel =
+				    core_if->core_params->phy_ulpi_ddr;
+			} else if (core_if->core_params->phy_type == 1) {
+				/* UTMI+ interface */
+				usbcfg.b.ulpi_utmi_sel = 0;
+				if (core_if->core_params->phy_utmi_width == 16) {
+					usbcfg.b.phyif = 1;
+
+				} else {
+					usbcfg.b.phyif = 0;
+				}
+			} else {
+				DWC_ERROR("FS PHY TYPE\n");
+			}
+			DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
+			/* Reset after setting the PHY parameters */
+			dwc_otg_core_reset(core_if);
+		}
+	}
+
+	if ((core_if->hwcfg2.b.hs_phy_type == 2) &&
+	    (core_if->hwcfg2.b.fs_phy_type == 1) &&
+	    (core_if->core_params->ulpi_fs_ls)) {
+		DWC_DEBUGPL(DBG_CIL, "Setting ULPI FSLS\n");
+		usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
+		usbcfg.b.ulpi_fsls = 1;
+		usbcfg.b.ulpi_clk_sus_m = 1;
+		DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
+	} else {
+		usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
+		usbcfg.b.ulpi_fsls = 0;
+		usbcfg.b.ulpi_clk_sus_m = 0;
+		DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
+	}
+
+	/* Program the GAHBCFG Register. */
+	switch (core_if->hwcfg2.b.architecture) {
+
+	case DWC_SLAVE_ONLY_ARCH:
+		DWC_DEBUGPL(DBG_CIL, "Slave Only Mode\n");
+		ahbcfg.b.nptxfemplvl_txfemplvl =
+		    DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
+		ahbcfg.b.ptxfemplvl = DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
+		core_if->dma_enable = 0;
+		core_if->dma_desc_enable = 0;
+		break;
+
+	case DWC_EXT_DMA_ARCH:
+		DWC_DEBUGPL(DBG_CIL, "External DMA Mode\n");
+		{
+			uint8_t brst_sz = core_if->core_params->dma_burst_size;
+			ahbcfg.b.hburstlen = 0;
+			while (brst_sz > 1) {
+				ahbcfg.b.hburstlen++;
+				brst_sz >>= 1;
+			}
+		}
+		core_if->dma_enable = (core_if->core_params->dma_enable != 0);
+		core_if->dma_desc_enable =
+		    (core_if->core_params->dma_desc_enable != 0);
+		break;
+
+	case DWC_INT_DMA_ARCH:
+		DWC_DEBUGPL(DBG_CIL, "Internal DMA Mode\n");
+		/* Old value was DWC_GAHBCFG_INT_DMA_BURST_INCR - done for
+		  Host mode ISOC in issue fix - vahrama */
+		ahbcfg.b.hburstlen = DWC_GAHBCFG_INT_DMA_BURST_INCR16;
+		core_if->dma_enable = (core_if->core_params->dma_enable != 0);
+		core_if->dma_desc_enable =
+		    (core_if->core_params->dma_desc_enable != 0);
+		break;
+
+	}
+	if (core_if->dma_enable) {
+		if (core_if->dma_desc_enable) {
+			DWC_PRINTF("Using Descriptor DMA mode\n");
+		} else {
+			DWC_PRINTF("Using Buffer DMA mode\n");
+
+		}
+	} else {
+		DWC_PRINTF("Using Slave mode\n");
+		core_if->dma_desc_enable = 0;
+	}
+
+	if (core_if->core_params->ahb_single) {
+		ahbcfg.b.ahbsingle = 1;
+	}
+
+	ahbcfg.b.dmaenable = core_if->dma_enable;
+	DWC_WRITE_REG32(&global_regs->gahbcfg, ahbcfg.d32);
+
+	core_if->en_multiple_tx_fifo = core_if->hwcfg4.b.ded_fifo_en;
+
+	core_if->pti_enh_enable = core_if->core_params->pti_enable != 0;
+	core_if->multiproc_int_enable = core_if->core_params->mpi_enable;
+	DWC_PRINTF("Periodic Transfer Interrupt Enhancement - %s\n",
+		   ((core_if->pti_enh_enable) ? "enabled" : "disabled"));
+	DWC_PRINTF("Multiprocessor Interrupt Enhancement - %s\n",
+		   ((core_if->multiproc_int_enable) ? "enabled" : "disabled"));
+
+	/*
+	 * Program the GUSBCFG register.
+	 */
+	usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
+
+	switch (core_if->hwcfg2.b.op_mode) {
+	case DWC_MODE_HNP_SRP_CAPABLE:
+		usbcfg.b.hnpcap = (core_if->core_params->otg_cap ==
+				   DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE);
+		usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
+				   DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
+		break;
+
+	case DWC_MODE_SRP_ONLY_CAPABLE:
+		usbcfg.b.hnpcap = 0;
+		usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
+				   DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
+		break;
+
+	case DWC_MODE_NO_HNP_SRP_CAPABLE:
+		usbcfg.b.hnpcap = 0;
+		usbcfg.b.srpcap = 0;
+		break;
+
+	case DWC_MODE_SRP_CAPABLE_DEVICE:
+		usbcfg.b.hnpcap = 0;
+		usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
+				   DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
+		break;
+
+	case DWC_MODE_NO_SRP_CAPABLE_DEVICE:
+		usbcfg.b.hnpcap = 0;
+		usbcfg.b.srpcap = 0;
+		break;
+
+	case DWC_MODE_SRP_CAPABLE_HOST:
+		usbcfg.b.hnpcap = 0;
+		usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
+				   DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
+		break;
+
+	case DWC_MODE_NO_SRP_CAPABLE_HOST:
+		usbcfg.b.hnpcap = 0;
+		usbcfg.b.srpcap = 0;
+		break;
+	}
+
+	DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
+
+#ifdef CONFIG_USB_DWC_OTG_LPM
+	if (core_if->core_params->lpm_enable) {
+		glpmcfg_data_t lpmcfg = {.d32 = 0 };
+
+		/* To enable LPM support set lpm_cap_en bit */
+		lpmcfg.b.lpm_cap_en = 1;
+
+		/* Make AppL1Res ACK */
+		lpmcfg.b.appl_resp = 1;
+
+		/* Retry 3 times */
+		lpmcfg.b.retry_count = 3;
+
+		DWC_MODIFY_REG32(&core_if->core_global_regs->glpmcfg,
+				 0, lpmcfg.d32);
+
+	}
+#endif
+	if (core_if->core_params->ic_usb_cap) {
+		gusbcfg_data_t gusbcfg = {.d32 = 0 };
+		gusbcfg.b.ic_usb_cap = 1;
+		DWC_MODIFY_REG32(&core_if->core_global_regs->gusbcfg,
+				 0, gusbcfg.d32);
+	}
+	{
+		gotgctl_data_t gotgctl = {.d32 = 0 };
+		gotgctl.b.otgver = core_if->core_params->otg_ver;
+		DWC_MODIFY_REG32(&core_if->core_global_regs->gotgctl, 0,
+				 gotgctl.d32);
+		/* Set OTG version supported */
+		core_if->otg_ver = core_if->core_params->otg_ver;
+		DWC_PRINTF("OTG VER PARAM: %d, OTG VER FLAG: %d\n",
+			   core_if->core_params->otg_ver, core_if->otg_ver);
+	}
+
+
+	/* Enable common interrupts */
+	dwc_otg_enable_common_interrupts(core_if);
+
+	/* Do device or host intialization based on mode during PCD
+	 * and HCD initialization  */
+	if (dwc_otg_is_host_mode(core_if)) {
+		DWC_DEBUGPL(DBG_ANY, "Host Mode\n");
+		core_if->op_state = A_HOST;
+	} else {
+		DWC_DEBUGPL(DBG_ANY, "Device Mode\n");
+		core_if->op_state = B_PERIPHERAL;
+#ifdef DWC_DEVICE_ONLY
+		dwc_otg_core_dev_init(core_if);
+#endif
+	}
+}
+
+/**
+ * This function enables the Device mode interrupts.
+ *
+ * @param core_if Programming view of DWC_otg controller
+ */
+void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t * core_if)
+{
+	gintmsk_data_t intr_mask = {.d32 = 0 };
+	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+
+	DWC_DEBUGPL(DBG_CIL, "%s()\n", __func__);
+
+	/* Disable all interrupts. */
+	DWC_WRITE_REG32(&global_regs->gintmsk, 0);
+
+	/* Clear any pending interrupts */
+	DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
+
+	/* Enable the common interrupts */
+	dwc_otg_enable_common_interrupts(core_if);
+
+	/* Enable interrupts */
+	intr_mask.b.usbreset = 1;
+	intr_mask.b.enumdone = 1;
+	/* Disable Disconnect interrupt in Device mode */
+	intr_mask.b.disconnect = 0;
+
+	if (!core_if->multiproc_int_enable) {
+		intr_mask.b.inepintr = 1;
+		intr_mask.b.outepintr = 1;
+	}
+
+	intr_mask.b.erlysuspend = 1;
+
+	if (core_if->en_multiple_tx_fifo == 0) {
+		intr_mask.b.epmismatch = 1;
+	}
+
+	//intr_mask.b.incomplisoout = 1;
+	intr_mask.b.incomplisoin = 1;
+
+/* Enable the ignore frame number for ISOC xfers - MAS */
+/* Disable to support high bandwith ISOC transfers - manukz */
+#if 0
+#ifdef DWC_UTE_PER_IO
+	if (core_if->dma_enable) {
+		if (core_if->dma_desc_enable) {
+			dctl_data_t dctl1 = {.d32 = 0 };
+			dctl1.b.ifrmnum = 1;
+			DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
+					 dctl, 0, dctl1.d32);
+			DWC_DEBUG("----Enabled Ignore frame number (0x%08x)",
+				  DWC_READ_REG32(&core_if->dev_if->
+						 dev_global_regs->dctl));
+		}
+	}
+#endif
+#endif
+#ifdef DWC_EN_ISOC
+	if (core_if->dma_enable) {
+		if (core_if->dma_desc_enable == 0) {
+			if (core_if->pti_enh_enable) {
+				dctl_data_t dctl = {.d32 = 0 };
+				dctl.b.ifrmnum = 1;
+				DWC_MODIFY_REG32(&core_if->
+						 dev_if->dev_global_regs->dctl,
+						 0, dctl.d32);
+			} else {
+				intr_mask.b.incomplisoin = 1;
+				intr_mask.b.incomplisoout = 1;
+			}
+		}
+	} else {
+		intr_mask.b.incomplisoin = 1;
+		intr_mask.b.incomplisoout = 1;
+	}
+#endif /* DWC_EN_ISOC */
+
+	/** @todo NGS: Should this be a module parameter? */
+#ifdef USE_PERIODIC_EP
+	intr_mask.b.isooutdrop = 1;
+	intr_mask.b.eopframe = 1;
+	intr_mask.b.incomplisoin = 1;
+	intr_mask.b.incomplisoout = 1;
+#endif
+
+	DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
+
+	DWC_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__,
+		    DWC_READ_REG32(&global_regs->gintmsk));
+}
+
+/**
+ * This function initializes the DWC_otg controller registers for
+ * device mode.
+ *
+ * @param core_if Programming view of DWC_otg controller
+ *
+ */
+void dwc_otg_core_dev_init(dwc_otg_core_if_t * core_if)
+{
+	int i;
+	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+	dwc_otg_core_params_t *params = core_if->core_params;
+	dcfg_data_t dcfg = {.d32 = 0 };
+	depctl_data_t diepctl = {.d32 = 0 };
+	grstctl_t resetctl = {.d32 = 0 };
+	uint32_t rx_fifo_size;
+	fifosize_data_t nptxfifosize;
+	fifosize_data_t txfifosize;
+	dthrctl_data_t dthrctl;
+	fifosize_data_t ptxfifosize;
+	uint16_t rxfsiz, nptxfsiz;
+	gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
+	hwcfg3_data_t hwcfg3 = {.d32 = 0 };
+
+	/* Restart the Phy Clock */
+	DWC_WRITE_REG32(core_if->pcgcctl, 0);
+
+	/* Device configuration register */
+	init_devspd(core_if);
+	dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
+	dcfg.b.descdma = (core_if->dma_desc_enable) ? 1 : 0;
+	dcfg.b.perfrint = DWC_DCFG_FRAME_INTERVAL_80;
+	/* Enable Device OUT NAK in case of DDMA mode*/
+	if (core_if->core_params->dev_out_nak) {
+		dcfg.b.endevoutnak = 1;
+	}
+
+	if (core_if->core_params->cont_on_bna) {
+		dctl_data_t dctl = {.d32 = 0 };
+		dctl.b.encontonbna = 1;
+		DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, 0, dctl.d32);
+	}
+
+
+	DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
+
+	/* Configure data FIFO sizes */
+	if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
+		DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n",
+			    core_if->total_fifo_size);
+		DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n",
+			    params->dev_rx_fifo_size);
+		DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n",
+			    params->dev_nperio_tx_fifo_size);
+
+		/* Rx FIFO */
+		DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n",
+			    DWC_READ_REG32(&global_regs->grxfsiz));
+
+#ifdef DWC_UTE_CFI
+		core_if->pwron_rxfsiz = DWC_READ_REG32(&global_regs->grxfsiz);
+		core_if->init_rxfsiz = params->dev_rx_fifo_size;
+#endif
+		rx_fifo_size = params->dev_rx_fifo_size;
+		DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fifo_size);
+
+		DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n",
+			    DWC_READ_REG32(&global_regs->grxfsiz));
+
+		/** Set Periodic Tx FIFO Mask all bits 0 */
+		core_if->p_tx_msk = 0;
+
+		/** Set Tx FIFO Mask all bits 0 */
+		core_if->tx_msk = 0;
+
+		if (core_if->en_multiple_tx_fifo == 0) {
+			/* Non-periodic Tx FIFO */
+			DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
+				    DWC_READ_REG32(&global_regs->gnptxfsiz));
+
+			nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
+			nptxfifosize.b.startaddr = 0x400;
+
+			DWC_WRITE_REG32(&global_regs->gnptxfsiz,
+					nptxfifosize.d32);
+
+			DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
+				    DWC_READ_REG32(&global_regs->gnptxfsiz));
+
+			/**@todo NGS: Fix Periodic FIFO Sizing! */
+			/*
+			 * Periodic Tx FIFOs These FIFOs are numbered from 1 to 15.
+			 * Indexes of the FIFO size module parameters in the
+			 * dev_perio_tx_fifo_size array and the FIFO size registers in
+			 * the dptxfsiz array run from 0 to 14.
+			 */
+			/** @todo Finish debug of this */
+			ptxfifosize.b.startaddr =
+			    nptxfifosize.b.startaddr + nptxfifosize.b.depth;
+			for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) {
+				ptxfifosize.b.depth =
+				    params->dev_perio_tx_fifo_size[i];
+				DWC_DEBUGPL(DBG_CIL,
+					    "initial dtxfsiz[%d]=%08x\n", i,
+					    DWC_READ_REG32(&global_regs->dtxfsiz
+							   [i]));
+				DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
+						ptxfifosize.d32);
+				DWC_DEBUGPL(DBG_CIL, "new dtxfsiz[%d]=%08x\n",
+					    i,
+					    DWC_READ_REG32(&global_regs->dtxfsiz
+							   [i]));
+				ptxfifosize.b.startaddr += ptxfifosize.b.depth;
+			}
+		} else {
+			/*
+			 * Tx FIFOs These FIFOs are numbered from 1 to 15.
+			 * Indexes of the FIFO size module parameters in the
+			 * dev_tx_fifo_size array and the FIFO size registers in
+			 * the dtxfsiz array run from 0 to 14.
+			 */
+
+			/* Non-periodic Tx FIFO */
+			DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
+				    DWC_READ_REG32(&global_regs->gnptxfsiz));
+
+#ifdef DWC_UTE_CFI
+			core_if->pwron_gnptxfsiz =
+			    (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
+			core_if->init_gnptxfsiz =
+			    params->dev_nperio_tx_fifo_size;
+#endif
+			nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
+			nptxfifosize.b.startaddr = 0x400;
+
+			DWC_WRITE_REG32(&global_regs->gnptxfsiz,
+					nptxfifosize.d32);
+
+			DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
+				    DWC_READ_REG32(&global_regs->gnptxfsiz));
+
+			txfifosize.b.startaddr =
+			    nptxfifosize.b.startaddr + nptxfifosize.b.depth;
+
+			for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
+
+				txfifosize.b.depth =
+				    params->dev_tx_fifo_size[i];
+
+				DWC_DEBUGPL(DBG_CIL,
+					    "initial dtxfsiz[%d]=%08x\n",
+					    i,
+					    DWC_READ_REG32(&global_regs->dtxfsiz
+							   [i]));
+
+#ifdef DWC_UTE_CFI
+				core_if->pwron_txfsiz[i] =
+				    (DWC_READ_REG32
+				     (&global_regs->dtxfsiz[i]) >> 16);
+				core_if->init_txfsiz[i] =
+				    params->dev_tx_fifo_size[i];
+#endif
+				DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
+						txfifosize.d32);
+
+				DWC_DEBUGPL(DBG_CIL,
+					    "new dtxfsiz[%d]=%08x\n",
+					    i,
+					    DWC_READ_REG32(&global_regs->dtxfsiz
+							   [i]));
+
+				txfifosize.b.startaddr += txfifosize.b.depth;
+			}
+		        /* Calculating DFIFOCFG for Device mode to include RxFIFO and NPTXFIFO */
+			gdfifocfg.d32 = DWC_READ_REG32(&global_regs->gdfifocfg);
+			hwcfg3.d32 = DWC_READ_REG32(&global_regs->ghwcfg3);
+			gdfifocfg.b.gdfifocfg = (DWC_READ_REG32(&global_regs->ghwcfg3) >> 16);
+			DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
+			rxfsiz = (DWC_READ_REG32(&global_regs->grxfsiz) & 0x0000ffff);
+			nptxfsiz = (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
+			gdfifocfg.b.epinfobase = rxfsiz + nptxfsiz;
+			DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
+		}
+	}
+
+	/* Flush the FIFOs */
+	dwc_otg_flush_tx_fifo(core_if, 0x10);	/* all Tx FIFOs */
+	dwc_otg_flush_rx_fifo(core_if);
+
+	/* Flush the Learning Queue. */
+	resetctl.b.intknqflsh = 1;
+	DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32);
+
+	if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable) {
+		core_if->start_predict = 0;
+		for (i = 0; i<= core_if->dev_if->num_in_eps; ++i) {
+			core_if->nextep_seq[i] = 0xff;	// 0xff - EP not active
+		}
+		core_if->nextep_seq[0] = 0;
+		core_if->first_in_nextep_seq = 0;
+		diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
+		diepctl.b.nextep = 0;
+		DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
+
+		/* Update IN Endpoint Mismatch Count by active IN NP EP count + 1 */
+		dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
+		dcfg.b.epmscnt = 2;
+		DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
+
+		DWC_DEBUGPL(DBG_CILV,"%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
+			__func__, core_if->first_in_nextep_seq);
+		for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
+			DWC_DEBUGPL(DBG_CILV, "%2d ", core_if->nextep_seq[i]);
+		}
+		DWC_DEBUGPL(DBG_CILV,"\n");
+	}
+
+	/* Clear all pending Device Interrupts */
+	/** @todo - if the condition needed to be checked
+	 *  or in any case all pending interrutps should be cleared?
+     */
+	if (core_if->multiproc_int_enable) {
+		for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
+			DWC_WRITE_REG32(&dev_if->
+					dev_global_regs->diepeachintmsk[i], 0);
+		}
+
+		for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
+			DWC_WRITE_REG32(&dev_if->
+					dev_global_regs->doepeachintmsk[i], 0);
+		}
+
+		DWC_WRITE_REG32(&dev_if->dev_global_regs->deachint, 0xFFFFFFFF);
+		DWC_WRITE_REG32(&dev_if->dev_global_regs->deachintmsk, 0);
+	} else {
+		DWC_WRITE_REG32(&dev_if->dev_global_regs->diepmsk, 0);
+		DWC_WRITE_REG32(&dev_if->dev_global_regs->doepmsk, 0);
+		DWC_WRITE_REG32(&dev_if->dev_global_regs->daint, 0xFFFFFFFF);
+		DWC_WRITE_REG32(&dev_if->dev_global_regs->daintmsk, 0);
+	}
+
+	for (i = 0; i <= dev_if->num_in_eps; i++) {
+		depctl_data_t depctl;
+		depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
+		if (depctl.b.epena) {
+			depctl.d32 = 0;
+			depctl.b.epdis = 1;
+			depctl.b.snak = 1;
+		} else {
+			depctl.d32 = 0;
+		}
+
+		DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
+
+		DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->dieptsiz, 0);
+		DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepdma, 0);
+		DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepint, 0xFF);
+	}
+
+	for (i = 0; i <= dev_if->num_out_eps; i++) {
+		depctl_data_t depctl;
+		depctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl);
+		if (depctl.b.epena) {
+			depctl.d32 = 0;
+			depctl.b.epdis = 1;
+			depctl.b.snak = 1;
+		} else {
+			depctl.d32 = 0;
+		}
+
+		DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, depctl.d32);
+
+		DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doeptsiz, 0);
+		DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepdma, 0);
+		DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepint, 0xFF);
+	}
+
+	if (core_if->en_multiple_tx_fifo && core_if->dma_enable) {
+		dev_if->non_iso_tx_thr_en = params->thr_ctl & 0x1;
+		dev_if->iso_tx_thr_en = (params->thr_ctl >> 1) & 0x1;
+		dev_if->rx_thr_en = (params->thr_ctl >> 2) & 0x1;
+
+		dev_if->rx_thr_length = params->rx_thr_length;
+		dev_if->tx_thr_length = params->tx_thr_length;
+
+		dev_if->setup_desc_index = 0;
+
+		dthrctl.d32 = 0;
+		dthrctl.b.non_iso_thr_en = dev_if->non_iso_tx_thr_en;
+		dthrctl.b.iso_thr_en = dev_if->iso_tx_thr_en;
+		dthrctl.b.tx_thr_len = dev_if->tx_thr_length;
+		dthrctl.b.rx_thr_en = dev_if->rx_thr_en;
+		dthrctl.b.rx_thr_len = dev_if->rx_thr_length;
+		dthrctl.b.ahb_thr_ratio = params->ahb_thr_ratio;
+
+		DWC_WRITE_REG32(&dev_if->dev_global_regs->dtknqr3_dthrctl,
+				dthrctl.d32);
+
+		DWC_DEBUGPL(DBG_CIL,
+			    "Non ISO Tx Thr - %d\nISO Tx Thr - %d\nRx Thr - %d\nTx Thr Len - %d\nRx Thr Len - %d\n",
+			    dthrctl.b.non_iso_thr_en, dthrctl.b.iso_thr_en,
+			    dthrctl.b.rx_thr_en, dthrctl.b.tx_thr_len,
+			    dthrctl.b.rx_thr_len);
+
+	}
+
+	dwc_otg_enable_device_interrupts(core_if);
+
+	{
+		diepmsk_data_t msk = {.d32 = 0 };
+		msk.b.txfifoundrn = 1;
+		if (core_if->multiproc_int_enable) {
+			DWC_MODIFY_REG32(&dev_if->
+					 dev_global_regs->diepeachintmsk[0],
+					 msk.d32, msk.d32);
+		} else {
+			DWC_MODIFY_REG32(&dev_if->dev_global_regs->diepmsk,
+					 msk.d32, msk.d32);
+		}
+	}
+
+	if (core_if->multiproc_int_enable) {
+		/* Set NAK on Babble */
+		dctl_data_t dctl = {.d32 = 0 };
+		dctl.b.nakonbble = 1;
+		DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, 0, dctl.d32);
+	}
+
+	if (core_if->snpsid >= OTG_CORE_REV_2_94a) {
+		dctl_data_t dctl = {.d32 = 0 };
+		dctl.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dctl);
+		dctl.b.sftdiscon = 0;
+		DWC_WRITE_REG32(&dev_if->dev_global_regs->dctl, dctl.d32);
+	}
+}
+
+/**
+ * This function enables the Host mode interrupts.
+ *
+ * @param core_if Programming view of DWC_otg controller
+ */
+void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t * core_if)
+{
+	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+	gintmsk_data_t intr_mask = {.d32 = 0 };
+
+	DWC_DEBUGPL(DBG_CIL, "%s()\n", __func__);
+
+	/* Disable all interrupts. */
+	DWC_WRITE_REG32(&global_regs->gintmsk, 0);
+
+	/* Clear any pending interrupts. */
+	DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
+
+	/* Enable the common interrupts */
+	dwc_otg_enable_common_interrupts(core_if);
+
+	/*
+	 * Enable host mode interrupts without disturbing common
+	 * interrupts.
+	 */
+
+	intr_mask.b.disconnect = 1;
+	intr_mask.b.portintr = 1;
+	intr_mask.b.hcintr = 1;
+
+	DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
+}
+
+/**
+ * This function disables the Host Mode interrupts.
+ *
+ * @param core_if Programming view of DWC_otg controller
+ */
+void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t * core_if)
+{
+	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+	gintmsk_data_t intr_mask = {.d32 = 0 };
+
+	DWC_DEBUGPL(DBG_CILV, "%s()\n", __func__);
+
+	/*
+	 * Disable host mode interrupts without disturbing common
+	 * interrupts.
+	 */
+	intr_mask.b.sofintr = 1;
+	intr_mask.b.portintr = 1;
+	intr_mask.b.hcintr = 1;
+	intr_mask.b.ptxfempty = 1;
+	intr_mask.b.nptxfempty = 1;
+
+	DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, 0);
+}
+
+/**
+ * This function initializes the DWC_otg controller registers for
+ * host mode.
+ *
+ * This function flushes the Tx and Rx FIFOs and it flushes any entries in the
+ * request queues. Host channels are reset to ensure that they are ready for
+ * performing transfers.
+ *
+ * @param core_if Programming view of DWC_otg controller
+ *
+ */
+void dwc_otg_core_host_init(dwc_otg_core_if_t * core_if)
+{
+	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+	dwc_otg_host_if_t *host_if = core_if->host_if;
+	dwc_otg_core_params_t *params = core_if->core_params;
+	hprt0_data_t hprt0 = {.d32 = 0 };
+	fifosize_data_t nptxfifosize;
+	fifosize_data_t ptxfifosize;
+	uint16_t rxfsiz, nptxfsiz, hptxfsiz;
+	gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
+	int i;
+	hcchar_data_t hcchar;
+	hcfg_data_t hcfg;
+	hfir_data_t hfir;
+	dwc_otg_hc_regs_t *hc_regs;
+	int num_channels;
+	gotgctl_data_t gotgctl = {.d32 = 0 };
+
+	DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, core_if);
+
+	/* Restart the Phy Clock */
+	DWC_WRITE_REG32(core_if->pcgcctl, 0);
+
+	/* Initialize Host Configuration Register */
+	init_fslspclksel(core_if);
+	if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) {
+		hcfg.d32 = DWC_READ_REG32(&host_if->host_global_regs->hcfg);
+		hcfg.b.fslssupp = 1;
+		DWC_WRITE_REG32(&host_if->host_global_regs->hcfg, hcfg.d32);
+
+	}
+
+	/* This bit allows dynamic reloading of the HFIR register
+	 * during runtime. This bit needs to be programmed during
+	 * initial configuration and its value must not be changed
+	 * during runtime.*/
+	if (core_if->core_params->reload_ctl == 1) {
+		hfir.d32 = DWC_READ_REG32(&host_if->host_global_regs->hfir);
+		hfir.b.hfirrldctrl = 1;
+		DWC_WRITE_REG32(&host_if->host_global_regs->hfir, hfir.d32);
+	}
+
+	if (core_if->core_params->dma_desc_enable) {
+		uint8_t op_mode = core_if->hwcfg2.b.op_mode;
+		if (!
+		    (core_if->hwcfg4.b.desc_dma
+		     && (core_if->snpsid >= OTG_CORE_REV_2_90a)
+		     && ((op_mode == DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
+			 || (op_mode == DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
+			 || (op_mode ==
+			     DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG)
+			 || (op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)
+			 || (op_mode ==
+			     DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST)))) {
+
+			DWC_ERROR("Host can't operate in Descriptor DMA mode.\n"
+				  "Either core version is below 2.90a or "
+				  "GHWCFG2, GHWCFG4 registers' values do not allow Descriptor DMA in host mode.\n"
+				  "To run the driver in Buffer DMA host mode set dma_desc_enable "
+				  "module parameter to 0.\n");
+			return;
+		}
+		hcfg.d32 = DWC_READ_REG32(&host_if->host_global_regs->hcfg);
+		hcfg.b.descdma = 1;
+		DWC_WRITE_REG32(&host_if->host_global_regs->hcfg, hcfg.d32);
+	}
+
+	/* Configure data FIFO sizes */
+	if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
+		DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n",
+			    core_if->total_fifo_size);
+		DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n",
+			    params->host_rx_fifo_size);
+		DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n",
+			    params->host_nperio_tx_fifo_size);
+		DWC_DEBUGPL(DBG_CIL, "P Tx FIFO Size=%d\n",
+			    params->host_perio_tx_fifo_size);
+
+		/* Rx FIFO */
+		DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n",
+			    DWC_READ_REG32(&global_regs->grxfsiz));
+		DWC_WRITE_REG32(&global_regs->grxfsiz,
+				params->host_rx_fifo_size);
+		DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n",
+			    DWC_READ_REG32(&global_regs->grxfsiz));
+
+		/* Non-periodic Tx FIFO */
+		DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
+			    DWC_READ_REG32(&global_regs->gnptxfsiz));
+		nptxfifosize.b.depth = params->host_nperio_tx_fifo_size;
+		nptxfifosize.b.startaddr = 0x400;
+
+		DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfifosize.d32);
+		DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
+			    DWC_READ_REG32(&global_regs->gnptxfsiz));
+
+		/* Periodic Tx FIFO */
+		DWC_DEBUGPL(DBG_CIL, "initial hptxfsiz=%08x\n",
+			    DWC_READ_REG32(&global_regs->hptxfsiz));
+		ptxfifosize.b.depth = params->host_perio_tx_fifo_size;
+		ptxfifosize.b.startaddr = 0xC00;
+		DWC_WRITE_REG32(&global_regs->hptxfsiz, ptxfifosize.d32);
+		DWC_DEBUGPL(DBG_CIL, "new hptxfsiz=%08x\n",
+			    DWC_READ_REG32(&global_regs->hptxfsiz));
+
+		if (core_if->en_multiple_tx_fifo) {
+			/* Global DFIFOCFG calculation for Host mode - include RxFIFO, NPTXFIFO and HPTXFIFO */
+			gdfifocfg.d32 = DWC_READ_REG32(&global_regs->gdfifocfg);
+			rxfsiz = (DWC_READ_REG32(&global_regs->grxfsiz) & 0x0000ffff);
+			nptxfsiz = (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
+			hptxfsiz = (DWC_READ_REG32(&global_regs->hptxfsiz) >> 16);
+			gdfifocfg.b.epinfobase = rxfsiz + nptxfsiz + hptxfsiz;
+			DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
+		}
+	}
+
+	/* TODO - check this */
+	/* Clear Host Set HNP Enable in the OTG Control Register */
+	gotgctl.b.hstsethnpen = 1;
+	DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
+	/* Make sure the FIFOs are flushed. */
+	dwc_otg_flush_tx_fifo(core_if, 0x10 /* all TX FIFOs */ );
+	dwc_otg_flush_rx_fifo(core_if);
+
+	/* Clear Host Set HNP Enable in the OTG Control Register */
+	gotgctl.b.hstsethnpen = 1;
+	DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
+
+	if (!core_if->core_params->dma_desc_enable) {
+		/* Flush out any leftover queued requests. */
+		num_channels = core_if->core_params->host_channels;
+
+		for (i = 0; i < num_channels; i++) {
+			hc_regs = core_if->host_if->hc_regs[i];
+			hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+			hcchar.b.chen = 0;
+			hcchar.b.chdis = 1;
+			hcchar.b.epdir = 0;
+			DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
+		}
+
+		/* Halt all channels to put them into a known state. */
+		for (i = 0; i < num_channels; i++) {
+			int count = 0;
+			hc_regs = core_if->host_if->hc_regs[i];
+			hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+			hcchar.b.chen = 1;
+			hcchar.b.chdis = 1;
+			hcchar.b.epdir = 0;
+			DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
+			DWC_DEBUGPL(DBG_HCDV, "%s: Halt channel %d\n", __func__, i);
+			do {
+				hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+				if (++count > 1000) {
+					DWC_ERROR
+					    ("%s: Unable to clear halt on channel %d\n",
+					     __func__, i);
+					break;
+				}
+				dwc_udelay(1);
+			} while (hcchar.b.chen);
+		}
+	}
+
+	/* Turn on the vbus power. */
+	DWC_PRINTF("Init: Port Power? op_state=%d\n", core_if->op_state);
+	if (core_if->op_state == A_HOST) {
+		hprt0.d32 = dwc_otg_read_hprt0(core_if);
+		DWC_PRINTF("Init: Power Port (%d)\n", hprt0.b.prtpwr);
+		if (hprt0.b.prtpwr == 0) {
+			hprt0.b.prtpwr = 1;
+			DWC_WRITE_REG32(host_if->hprt0, hprt0.d32);
+		}
+	}
+
+	dwc_otg_enable_host_interrupts(core_if);
+}
+
+/**
+ * Prepares a host channel for transferring packets to/from a specific
+ * endpoint. The HCCHARn register is set up with the characteristics specified
+ * in _hc. Host channel interrupts that may need to be serviced while this
+ * transfer is in progress are enabled.
+ *
+ * @param core_if Programming view of DWC_otg controller
+ * @param hc Information needed to initialize the host channel
+ */
+void dwc_otg_hc_init(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
+{
+	uint32_t intr_enable;
+	hcintmsk_data_t hc_intr_mask;
+	gintmsk_data_t gintmsk = {.d32 = 0 };
+	hcchar_data_t hcchar;
+	hcsplt_data_t hcsplt;
+
+	uint8_t hc_num = hc->hc_num;
+	dwc_otg_host_if_t *host_if = core_if->host_if;
+	dwc_otg_hc_regs_t *hc_regs = host_if->hc_regs[hc_num];
+
+	/* Clear old interrupt conditions for this host channel. */
+	hc_intr_mask.d32 = 0xFFFFFFFF;
+	hc_intr_mask.b.reserved14_31 = 0;
+	DWC_WRITE_REG32(&hc_regs->hcint, hc_intr_mask.d32);
+
+	/* Enable channel interrupts required for this transfer. */
+	hc_intr_mask.d32 = 0;
+	hc_intr_mask.b.chhltd = 1;
+	if (core_if->dma_enable) {
+		/* For Descriptor DMA mode core halts the channel on AHB error. Interrupt is not required */
+		if (!core_if->dma_desc_enable)
+			hc_intr_mask.b.ahberr = 1;
+		else {
+			if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
+				hc_intr_mask.b.xfercompl = 1;
+		}
+
+		if (hc->error_state && !hc->do_split &&
+		    hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
+			hc_intr_mask.b.ack = 1;
+			if (hc->ep_is_in) {
+				hc_intr_mask.b.datatglerr = 1;
+				if (hc->ep_type != DWC_OTG_EP_TYPE_INTR) {
+					hc_intr_mask.b.nak = 1;
+				}
+			}
+		}
+	} else {
+		switch (hc->ep_type) {
+		case DWC_OTG_EP_TYPE_CONTROL:
+		case DWC_OTG_EP_TYPE_BULK:
+			hc_intr_mask.b.xfercompl = 1;
+			hc_intr_mask.b.stall = 1;
+			hc_intr_mask.b.xacterr = 1;
+			hc_intr_mask.b.datatglerr = 1;
+			if (hc->ep_is_in) {
+				hc_intr_mask.b.bblerr = 1;
+			} else {
+				hc_intr_mask.b.nak = 1;
+				hc_intr_mask.b.nyet = 1;
+				if (hc->do_ping) {
+					hc_intr_mask.b.ack = 1;
+				}
+			}
+
+			if (hc->do_split) {
+				hc_intr_mask.b.nak = 1;
+				if (hc->complete_split) {
+					hc_intr_mask.b.nyet = 1;
+				} else {
+					hc_intr_mask.b.ack = 1;
+				}
+			}
+
+			if (hc->error_state) {
+				hc_intr_mask.b.ack = 1;
+			}
+			break;
+		case DWC_OTG_EP_TYPE_INTR:
+			hc_intr_mask.b.xfercompl = 1;
+			hc_intr_mask.b.nak = 1;
+			hc_intr_mask.b.stall = 1;
+			hc_intr_mask.b.xacterr = 1;
+			hc_intr_mask.b.datatglerr = 1;
+			hc_intr_mask.b.frmovrun = 1;
+
+			if (hc->ep_is_in) {
+				hc_intr_mask.b.bblerr = 1;
+			}
+			if (hc->error_state) {
+				hc_intr_mask.b.ack = 1;
+			}
+			if (hc->do_split) {
+				if (hc->complete_split) {
+					hc_intr_mask.b.nyet = 1;
+				} else {
+					hc_intr_mask.b.ack = 1;
+				}
+			}
+			break;
+		case DWC_OTG_EP_TYPE_ISOC:
+			hc_intr_mask.b.xfercompl = 1;
+			hc_intr_mask.b.frmovrun = 1;
+			hc_intr_mask.b.ack = 1;
+
+			if (hc->ep_is_in) {
+				hc_intr_mask.b.xacterr = 1;
+				hc_intr_mask.b.bblerr = 1;
+			}
+			break;
+		}
+	}
+	DWC_WRITE_REG32(&hc_regs->hcintmsk, hc_intr_mask.d32);
+
+	/* Enable the top level host channel interrupt. */
+	intr_enable = (1 << hc_num);
+	DWC_MODIFY_REG32(&host_if->host_global_regs->haintmsk, 0, intr_enable);
+
+	/* Make sure host channel interrupts are enabled. */
+	gintmsk.b.hcintr = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, gintmsk.d32);
+
+	/*
+	 * Program the HCCHARn register with the endpoint characteristics for
+	 * the current transfer.
+	 */
+	hcchar.d32 = 0;
+	hcchar.b.devaddr = hc->dev_addr;
+	hcchar.b.epnum = hc->ep_num;
+	hcchar.b.epdir = hc->ep_is_in;
+	hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
+	hcchar.b.eptype = hc->ep_type;
+	hcchar.b.mps = hc->max_packet;
+
+	DWC_WRITE_REG32(&host_if->hc_regs[hc_num]->hcchar, hcchar.d32);
+
+	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
+	DWC_DEBUGPL(DBG_HCDV, "	 Dev Addr: %d\n", hcchar.b.devaddr);
+	DWC_DEBUGPL(DBG_HCDV, "	 Ep Num: %d\n", hcchar.b.epnum);
+	DWC_DEBUGPL(DBG_HCDV, "	 Is In: %d\n", hcchar.b.epdir);
+	DWC_DEBUGPL(DBG_HCDV, "	 Is Low Speed: %d\n", hcchar.b.lspddev);
+	DWC_DEBUGPL(DBG_HCDV, "	 Ep Type: %d\n", hcchar.b.eptype);
+	DWC_DEBUGPL(DBG_HCDV, "	 Max Pkt: %d\n", hcchar.b.mps);
+	DWC_DEBUGPL(DBG_HCDV, "	 Multi Cnt: %d\n", hcchar.b.multicnt);
+
+	/*
+	 * Program the HCSPLIT register for SPLITs
+	 */
+	hcsplt.d32 = 0;
+	if (hc->do_split) {
+		DWC_DEBUGPL(DBG_HCDV, "Programming HC %d with split --> %s\n",
+			    hc->hc_num,
+			    hc->complete_split ? "CSPLIT" : "SSPLIT");
+		hcsplt.b.compsplt = hc->complete_split;
+		hcsplt.b.xactpos = hc->xact_pos;
+		hcsplt.b.hubaddr = hc->hub_addr;
+		hcsplt.b.prtaddr = hc->port_addr;
+		DWC_DEBUGPL(DBG_HCDV, "	  comp split %d\n", hc->complete_split);
+		DWC_DEBUGPL(DBG_HCDV, "	  xact pos %d\n", hc->xact_pos);
+		DWC_DEBUGPL(DBG_HCDV, "	  hub addr %d\n", hc->hub_addr);
+		DWC_DEBUGPL(DBG_HCDV, "	  port addr %d\n", hc->port_addr);
+		DWC_DEBUGPL(DBG_HCDV, "	  is_in %d\n", hc->ep_is_in);
+		DWC_DEBUGPL(DBG_HCDV, "	  Max Pkt: %d\n", hcchar.b.mps);
+		DWC_DEBUGPL(DBG_HCDV, "	  xferlen: %d\n", hc->xfer_len);
+	}
+	DWC_WRITE_REG32(&host_if->hc_regs[hc_num]->hcsplt, hcsplt.d32);
+
+}
+
+/**
+ * Attempts to halt a host channel. This function should only be called in
+ * Slave mode or to abort a transfer in either Slave mode or DMA mode. Under
+ * normal circumstances in DMA mode, the controller halts the channel when the
+ * transfer is complete or a condition occurs that requires application
+ * intervention.
+ *
+ * In slave mode, checks for a free request queue entry, then sets the Channel
+ * Enable and Channel Disable bits of the Host Channel Characteristics
+ * register of the specified channel to intiate the halt. If there is no free
+ * request queue entry, sets only the Channel Disable bit of the HCCHARn
+ * register to flush requests for this channel. In the latter case, sets a
+ * flag to indicate that the host channel needs to be halted when a request
+ * queue slot is open.
+ *
+ * In DMA mode, always sets the Channel Enable and Channel Disable bits of the
+ * HCCHARn register. The controller ensures there is space in the request
+ * queue before submitting the halt request.
+ *
+ * Some time may elapse before the core flushes any posted requests for this
+ * host channel and halts. The Channel Halted interrupt handler completes the
+ * deactivation of the host channel.
+ *
+ * @param core_if Controller register interface.
+ * @param hc Host channel to halt.
+ * @param halt_status Reason for halting the channel.
+ */
+void dwc_otg_hc_halt(dwc_otg_core_if_t * core_if,
+		     dwc_hc_t * hc, dwc_otg_halt_status_e halt_status)
+{
+	gnptxsts_data_t nptxsts;
+	hptxsts_data_t hptxsts;
+	hcchar_data_t hcchar;
+	dwc_otg_hc_regs_t *hc_regs;
+	dwc_otg_core_global_regs_t *global_regs;
+	dwc_otg_host_global_regs_t *host_global_regs;
+
+	hc_regs = core_if->host_if->hc_regs[hc->hc_num];
+	global_regs = core_if->core_global_regs;
+	host_global_regs = core_if->host_if->host_global_regs;
+
+	DWC_ASSERT(!(halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS),
+		   "halt_status = %d\n", halt_status);
+
+	if (halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
+	    halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
+		/*
+		 * Disable all channel interrupts except Ch Halted. The QTD
+		 * and QH state associated with this transfer has been cleared
+		 * (in the case of URB_DEQUEUE), so the channel needs to be
+		 * shut down carefully to prevent crashes.
+		 */
+		hcintmsk_data_t hcintmsk;
+		hcintmsk.d32 = 0;
+		hcintmsk.b.chhltd = 1;
+		DWC_WRITE_REG32(&hc_regs->hcintmsk, hcintmsk.d32);
+
+		/*
+		 * Make sure no other interrupts besides halt are currently
+		 * pending. Handling another interrupt could cause a crash due
+		 * to the QTD and QH state.
+		 */
+		DWC_WRITE_REG32(&hc_regs->hcint, ~hcintmsk.d32);
+
+		/*
+		 * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR
+		 * even if the channel was already halted for some other
+		 * reason.
+		 */
+		hc->halt_status = halt_status;
+
+		hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+		if (hcchar.b.chen == 0) {
+			/*
+			 * The channel is either already halted or it hasn't
+			 * started yet. In DMA mode, the transfer may halt if
+			 * it finishes normally or a condition occurs that
+			 * requires driver intervention. Don't want to halt
+			 * the channel again. In either Slave or DMA mode,
+			 * it's possible that the transfer has been assigned
+			 * to a channel, but not started yet when an URB is
+			 * dequeued. Don't want to halt a channel that hasn't
+			 * started yet.
+			 */
+			return;
+		}
+	}
+	if (hc->halt_pending) {
+		/*
+		 * A halt has already been issued for this channel. This might
+		 * happen when a transfer is aborted by a higher level in
+		 * the stack.
+		 */
+#ifdef DEBUG
+		DWC_PRINTF
+		    ("*** %s: Channel %d, _hc->halt_pending already set ***\n",
+		     __func__, hc->hc_num);
+
+#endif
+		return;
+	}
+
+	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+
+	/* No need to set the bit in DDMA for disabling the channel */
+	//TODO check it everywhere channel is disabled
+	if (!core_if->core_params->dma_desc_enable)
+		hcchar.b.chen = 1;
+	hcchar.b.chdis = 1;
+
+	if (!core_if->dma_enable) {
+		/* Check for space in the request queue to issue the halt. */
+		if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
+		    hc->ep_type == DWC_OTG_EP_TYPE_BULK) {
+			nptxsts.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
+			if (nptxsts.b.nptxqspcavail == 0) {
+				hcchar.b.chen = 0;
+			}
+		} else {
+			hptxsts.d32 =
+			    DWC_READ_REG32(&host_global_regs->hptxsts);
+			if ((hptxsts.b.ptxqspcavail == 0)
+			    || (core_if->queuing_high_bandwidth)) {
+				hcchar.b.chen = 0;
+			}
+		}
+	}
+	DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
+
+	hc->halt_status = halt_status;
+
+	if (hcchar.b.chen) {
+		hc->halt_pending = 1;
+		hc->halt_on_queue = 0;
+	} else {
+		hc->halt_on_queue = 1;
+	}
+
+	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
+	DWC_DEBUGPL(DBG_HCDV, "	 hcchar: 0x%08x\n", hcchar.d32);
+	DWC_DEBUGPL(DBG_HCDV, "	 halt_pending: %d\n", hc->halt_pending);
+	DWC_DEBUGPL(DBG_HCDV, "	 halt_on_queue: %d\n", hc->halt_on_queue);
+	DWC_DEBUGPL(DBG_HCDV, "	 halt_status: %d\n", hc->halt_status);
+
+	return;
+}
+
+/**
+ * Clears the transfer state for a host channel. This function is normally
+ * called after a transfer is done and the host channel is being released.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param hc Identifies the host channel to clean up.
+ */
+void dwc_otg_hc_cleanup(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
+{
+	dwc_otg_hc_regs_t *hc_regs;
+
+	hc->xfer_started = 0;
+
+	/*
+	 * Clear channel interrupt enables and any unhandled channel interrupt
+	 * conditions.
+	 */
+	hc_regs = core_if->host_if->hc_regs[hc->hc_num];
+	DWC_WRITE_REG32(&hc_regs->hcintmsk, 0);
+	DWC_WRITE_REG32(&hc_regs->hcint, 0xFFFFFFFF);
+#ifdef DEBUG
+	DWC_TIMER_CANCEL(core_if->hc_xfer_timer[hc->hc_num]);
+#endif
+}
+
+/**
+ * Sets the channel property that indicates in which frame a periodic transfer
+ * should occur. This is always set to the _next_ frame. This function has no
+ * effect on non-periodic transfers.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param hc Identifies the host channel to set up and its properties.
+ * @param hcchar Current value of the HCCHAR register for the specified host
+ * channel.
+ */
+static inline void hc_set_even_odd_frame(dwc_otg_core_if_t * core_if,
+					 dwc_hc_t * hc, hcchar_data_t * hcchar)
+{
+	if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
+	    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
+		hfnum_data_t hfnum;
+		hfnum.d32 =
+		    DWC_READ_REG32(&core_if->host_if->host_global_regs->hfnum);
+
+		/* 1 if _next_ frame is odd, 0 if it's even */
+		hcchar->b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1;
+#ifdef DEBUG
+		if (hc->ep_type == DWC_OTG_EP_TYPE_INTR && hc->do_split
+		    && !hc->complete_split) {
+			switch (hfnum.b.frnum & 0x7) {
+			case 7:
+				core_if->hfnum_7_samples++;
+				core_if->hfnum_7_frrem_accum += hfnum.b.frrem;
+				break;
+			case 0:
+				core_if->hfnum_0_samples++;
+				core_if->hfnum_0_frrem_accum += hfnum.b.frrem;
+				break;
+			default:
+				core_if->hfnum_other_samples++;
+				core_if->hfnum_other_frrem_accum +=
+				    hfnum.b.frrem;
+				break;
+			}
+		}
+#endif
+	}
+}
+
+#ifdef DEBUG
+void hc_xfer_timeout(void *ptr)
+{
+	hc_xfer_info_t *xfer_info = NULL;
+	int hc_num = 0;
+
+	if (ptr)
+		xfer_info = (hc_xfer_info_t *) ptr;
+
+	if (!xfer_info->hc) {
+		DWC_ERROR("xfer_info->hc = %p\n", xfer_info->hc);
+		return;
+	}
+
+	hc_num = xfer_info->hc->hc_num;
+	DWC_WARN("%s: timeout on channel %d\n", __func__, hc_num);
+	DWC_WARN("	start_hcchar_val 0x%08x\n",
+		 xfer_info->core_if->start_hcchar_val[hc_num]);
+}
+#endif
+
+void ep_xfer_timeout(void *ptr)
+{
+	ep_xfer_info_t *xfer_info = NULL;
+	int ep_num = 0;
+	dctl_data_t dctl = {.d32 = 0 };
+	gintsts_data_t gintsts = {.d32 = 0 };
+	gintmsk_data_t gintmsk = {.d32 = 0 };
+
+	if (ptr)
+		xfer_info = (ep_xfer_info_t *) ptr;
+
+	if (!xfer_info->ep) {
+		DWC_ERROR("xfer_info->ep = %p\n", xfer_info->ep);
+		return;
+	}
+
+	ep_num = xfer_info->ep->num;
+	DWC_WARN("%s: timeout on endpoit %d\n", __func__, ep_num);
+	/* Put the sate to 2 as it was time outed */
+	xfer_info->state = 2;
+
+	dctl.d32 = DWC_READ_REG32(&xfer_info->core_if->
+		dev_if->dev_global_regs->dctl);
+	gintsts.d32 = DWC_READ_REG32(&xfer_info->core_if->
+		core_global_regs->gintsts);
+	gintmsk.d32 = DWC_READ_REG32(&xfer_info->core_if->
+		core_global_regs->gintmsk);
+
+	if (!gintmsk.b.goutnakeff) {
+		/* Unmask it */
+		gintmsk.b.goutnakeff = 1;
+		DWC_WRITE_REG32(&xfer_info->core_if->
+			core_global_regs->gintmsk, gintmsk.d32);
+
+	}
+
+	if (!gintsts.b.goutnakeff) {
+		dctl.b.sgoutnak = 1;
+	}
+	DWC_WRITE_REG32(&xfer_info->core_if->dev_if->
+		dev_global_regs->dctl, dctl.d32);
+
+}
+
+void set_pid_isoc(dwc_hc_t * hc)
+{
+	/* Set up the initial PID for the transfer. */
+	if (hc->speed == DWC_OTG_EP_SPEED_HIGH) {
+		if (hc->ep_is_in) {
+			if (hc->multi_count == 1) {
+				hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
+			} else if (hc->multi_count == 2) {
+				hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
+			} else {
+				hc->data_pid_start = DWC_OTG_HC_PID_DATA2;
+			}
+		} else {
+			if (hc->multi_count == 1) {
+				hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
+			} else {
+				hc->data_pid_start = DWC_OTG_HC_PID_MDATA;
+			}
+		}
+	} else {
+		hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
+	}
+}
+
+/**
+ * This function does the setup for a data transfer for a host channel and
+ * starts the transfer. May be called in either Slave mode or DMA mode. In
+ * Slave mode, the caller must ensure that there is sufficient space in the
+ * request queue and Tx Data FIFO.
+ *
+ * For an OUT transfer in Slave mode, it loads a data packet into the
+ * appropriate FIFO. If necessary, additional data packets will be loaded in
+ * the Host ISR.
+ *
+ * For an IN transfer in Slave mode, a data packet is requested. The data
+ * packets are unloaded from the Rx FIFO in the Host ISR. If necessary,
+ * additional data packets are requested in the Host ISR.
+ *
+ * For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ
+ * register along with a packet count of 1 and the channel is enabled. This
+ * causes a single PING transaction to occur. Other fields in HCTSIZ are
+ * simply set to 0 since no data transfer occurs in this case.
+ *
+ * For a PING transfer in DMA mode, the HCTSIZ register is initialized with
+ * all the information required to perform the subsequent data transfer. In
+ * addition, the Do Ping bit is set in the HCTSIZ register. In this case, the
+ * controller performs the entire PING protocol, then starts the data
+ * transfer.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param hc Information needed to initialize the host channel. The xfer_len
+ * value may be reduced to accommodate the max widths of the XferSize and
+ * PktCnt fields in the HCTSIZn register. The multi_count value may be changed
+ * to reflect the final xfer_len value.
+ */
+void dwc_otg_hc_start_transfer(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
+{
+	hcchar_data_t hcchar;
+	hctsiz_data_t hctsiz;
+	uint16_t num_packets;
+	uint32_t max_hc_xfer_size = core_if->core_params->max_transfer_size;
+	uint16_t max_hc_pkt_count = core_if->core_params->max_packet_count;
+	dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
+
+	hctsiz.d32 = 0;
+
+	if (hc->do_ping) {
+		if (!core_if->dma_enable) {
+			dwc_otg_hc_do_ping(core_if, hc);
+			hc->xfer_started = 1;
+			return;
+		} else {
+			hctsiz.b.dopng = 1;
+		}
+	}
+
+	if (hc->do_split) {
+		num_packets = 1;
+
+		if (hc->complete_split && !hc->ep_is_in) {
+			/* For CSPLIT OUT Transfer, set the size to 0 so the
+			 * core doesn't expect any data written to the FIFO */
+			hc->xfer_len = 0;
+		} else if (hc->ep_is_in || (hc->xfer_len > hc->max_packet)) {
+			hc->xfer_len = hc->max_packet;
+		} else if (!hc->ep_is_in && (hc->xfer_len > 188)) {
+			hc->xfer_len = 188;
+		}
+
+		hctsiz.b.xfersize = hc->xfer_len;
+	} else {
+		/*
+		 * Ensure that the transfer length and packet count will fit
+		 * in the widths allocated for them in the HCTSIZn register.
+		 */
+		if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
+		    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
+			/*
+			 * Make sure the transfer size is no larger than one
+			 * (micro)frame's worth of data. (A check was done
+			 * when the periodic transfer was accepted to ensure
+			 * that a (micro)frame's worth of data can be
+			 * programmed into a channel.)
+			 */
+			uint32_t max_periodic_len =
+			    hc->multi_count * hc->max_packet;
+			if (hc->xfer_len > max_periodic_len) {
+				hc->xfer_len = max_periodic_len;
+			} else {
+			}
+		} else if (hc->xfer_len > max_hc_xfer_size) {
+			/* Make sure that xfer_len is a multiple of max packet size. */
+			hc->xfer_len = max_hc_xfer_size - hc->max_packet + 1;
+		}
+
+		if (hc->xfer_len > 0) {
+			num_packets =
+			    (hc->xfer_len + hc->max_packet -
+			     1) / hc->max_packet;
+			if (num_packets > max_hc_pkt_count) {
+				num_packets = max_hc_pkt_count;
+				hc->xfer_len = num_packets * hc->max_packet;
+			}
+		} else {
+			/* Need 1 packet for transfer length of 0. */
+			num_packets = 1;
+		}
+
+		if (hc->ep_is_in) {
+			/* Always program an integral # of max packets for IN transfers. */
+			hc->xfer_len = num_packets * hc->max_packet;
+		}
+
+		if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
+		    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
+			/*
+			 * Make sure that the multi_count field matches the
+			 * actual transfer length.
+			 */
+			hc->multi_count = num_packets;
+		}
+
+		if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
+			set_pid_isoc(hc);
+
+		hctsiz.b.xfersize = hc->xfer_len;
+	}
+
+	hc->start_pkt_count = num_packets;
+	hctsiz.b.pktcnt = num_packets;
+	hctsiz.b.pid = hc->data_pid_start;
+	DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
+
+	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
+	DWC_DEBUGPL(DBG_HCDV, "	 Xfer Size: %d\n", hctsiz.b.xfersize);
+	DWC_DEBUGPL(DBG_HCDV, "	 Num Pkts: %d\n", hctsiz.b.pktcnt);
+	DWC_DEBUGPL(DBG_HCDV, "	 Start PID: %d\n", hctsiz.b.pid);
+
+	if (core_if->dma_enable) {
+		dwc_dma_t dma_addr;
+		if (hc->align_buff) {
+			dma_addr = hc->align_buff;
+		} else {
+			dma_addr = ((unsigned long)hc->xfer_buff & 0xffffffff);
+		}
+		DWC_WRITE_REG32(&hc_regs->hcdma, dma_addr);
+	}
+
+	/* Start the split */
+	if (hc->do_split) {
+		hcsplt_data_t hcsplt;
+		hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
+		hcsplt.b.spltena = 1;
+		DWC_WRITE_REG32(&hc_regs->hcsplt, hcsplt.d32);
+	}
+
+	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+	hcchar.b.multicnt = hc->multi_count;
+	hc_set_even_odd_frame(core_if, hc, &hcchar);
+#ifdef DEBUG
+	core_if->start_hcchar_val[hc->hc_num] = hcchar.d32;
+	if (hcchar.b.chdis) {
+		DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
+			 __func__, hc->hc_num, hcchar.d32);
+	}
+#endif
+
+	/* Set host channel enable after all other setup is complete. */
+	hcchar.b.chen = 1;
+	hcchar.b.chdis = 0;
+	DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
+
+	hc->xfer_started = 1;
+	hc->requests++;
+
+	if (!core_if->dma_enable && !hc->ep_is_in && hc->xfer_len > 0) {
+		/* Load OUT packet into the appropriate Tx FIFO. */
+		dwc_otg_hc_write_packet(core_if, hc);
+	}
+#ifdef DEBUG
+	if (hc->ep_type != DWC_OTG_EP_TYPE_INTR) {
+		core_if->hc_xfer_info[hc->hc_num].core_if = core_if;
+		core_if->hc_xfer_info[hc->hc_num].hc = hc;
+
+		/* Start a timer for this transfer. */
+		DWC_TIMER_SCHEDULE(core_if->hc_xfer_timer[hc->hc_num], 10000);
+	}
+#endif
+}
+
+/**
+ * This function does the setup for a data transfer for a host channel
+ * and starts the transfer in Descriptor DMA mode.
+ *
+ * Initializes HCTSIZ register. For a PING transfer the Do Ping bit is set.
+ * Sets PID and NTD values. For periodic transfers
+ * initializes SCHED_INFO field with micro-frame bitmap.
+ *
+ * Initializes HCDMA register with descriptor list address and CTD value
+ * then starts the transfer via enabling the channel.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param hc Information needed to initialize the host channel.
+ */
+void dwc_otg_hc_start_transfer_ddma(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
+{
+	dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
+	hcchar_data_t hcchar;
+	hctsiz_data_t hctsiz;
+	hcdma_data_t hcdma;
+
+	hctsiz.d32 = 0;
+
+	if (hc->do_ping)
+		hctsiz.b_ddma.dopng = 1;
+
+	if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
+		set_pid_isoc(hc);
+
+	/* Packet Count and Xfer Size are not used in Descriptor DMA mode */
+	hctsiz.b_ddma.pid = hc->data_pid_start;
+	hctsiz.b_ddma.ntd = hc->ntd - 1;	/* 0 - 1 descriptor, 1 - 2 descriptors, etc. */
+	hctsiz.b_ddma.schinfo = hc->schinfo;	/* Non-zero only for high-speed interrupt endpoints */
+
+	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
+	DWC_DEBUGPL(DBG_HCDV, "	 Start PID: %d\n", hctsiz.b.pid);
+	DWC_DEBUGPL(DBG_HCDV, "	 NTD: %d\n", hctsiz.b_ddma.ntd);
+
+	DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
+
+	hcdma.d32 = 0;
+	hcdma.b.dma_addr = ((uint32_t) hc->desc_list_addr) >> 11;
+
+	/* Always start from first descriptor. */
+	hcdma.b.ctd = 0;
+	DWC_WRITE_REG32(&hc_regs->hcdma, hcdma.d32);
+
+	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+	hcchar.b.multicnt = hc->multi_count;
+
+#ifdef DEBUG
+	core_if->start_hcchar_val[hc->hc_num] = hcchar.d32;
+	if (hcchar.b.chdis) {
+		DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
+			 __func__, hc->hc_num, hcchar.d32);
+	}
+#endif
+
+	/* Set host channel enable after all other setup is complete. */
+	hcchar.b.chen = 1;
+	hcchar.b.chdis = 0;
+
+	DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
+
+	hc->xfer_started = 1;
+	hc->requests++;
+
+#ifdef DEBUG
+	if ((hc->ep_type != DWC_OTG_EP_TYPE_INTR)
+	    && (hc->ep_type != DWC_OTG_EP_TYPE_ISOC)) {
+		core_if->hc_xfer_info[hc->hc_num].core_if = core_if;
+		core_if->hc_xfer_info[hc->hc_num].hc = hc;
+		/* Start a timer for this transfer. */
+		DWC_TIMER_SCHEDULE(core_if->hc_xfer_timer[hc->hc_num], 10000);
+	}
+#endif
+
+}
+
+/**
+ * This function continues a data transfer that was started by previous call
+ * to <code>dwc_otg_hc_start_transfer</code>. The caller must ensure there is
+ * sufficient space in the request queue and Tx Data FIFO. This function
+ * should only be called in Slave mode. In DMA mode, the controller acts
+ * autonomously to complete transfers programmed to a host channel.
+ *
+ * For an OUT transfer, a new data packet is loaded into the appropriate FIFO
+ * if there is any data remaining to be queued. For an IN transfer, another
+ * data packet is always requested. For the SETUP phase of a control transfer,
+ * this function does nothing.
+ *
+ * @return 1 if a new request is queued, 0 if no more requests are required
+ * for this transfer.
+ */
+int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
+{
+	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
+
+	if (hc->do_split) {
+		/* SPLITs always queue just once per channel */
+		return 0;
+	} else if (hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
+		/* SETUPs are queued only once since they can't be NAKed. */
+		return 0;
+	} else if (hc->ep_is_in) {
+		/*
+		 * Always queue another request for other IN transfers. If
+		 * back-to-back INs are issued and NAKs are received for both,
+		 * the driver may still be processing the first NAK when the
+		 * second NAK is received. When the interrupt handler clears
+		 * the NAK interrupt for the first NAK, the second NAK will
+		 * not be seen. So we can't depend on the NAK interrupt
+		 * handler to requeue a NAKed request. Instead, IN requests
+		 * are issued each time this function is called. When the
+		 * transfer completes, the extra requests for the channel will
+		 * be flushed.
+		 */
+		hcchar_data_t hcchar;
+		dwc_otg_hc_regs_t *hc_regs =
+		    core_if->host_if->hc_regs[hc->hc_num];
+
+		hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+		hc_set_even_odd_frame(core_if, hc, &hcchar);
+		hcchar.b.chen = 1;
+		hcchar.b.chdis = 0;
+		DWC_DEBUGPL(DBG_HCDV, "	 IN xfer: hcchar = 0x%08x\n",
+			    hcchar.d32);
+		DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
+		hc->requests++;
+		return 1;
+	} else {
+		/* OUT transfers. */
+		if (hc->xfer_count < hc->xfer_len) {
+			if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
+			    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
+				hcchar_data_t hcchar;
+				dwc_otg_hc_regs_t *hc_regs;
+				hc_regs = core_if->host_if->hc_regs[hc->hc_num];
+				hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+				hc_set_even_odd_frame(core_if, hc, &hcchar);
+			}
+
+			/* Load OUT packet into the appropriate Tx FIFO. */
+			dwc_otg_hc_write_packet(core_if, hc);
+			hc->requests++;
+			return 1;
+		} else {
+			return 0;
+		}
+	}
+}
+
+/**
+ * Starts a PING transfer. This function should only be called in Slave mode.
+ * The Do Ping bit is set in the HCTSIZ register, then the channel is enabled.
+ */
+void dwc_otg_hc_do_ping(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
+{
+	hcchar_data_t hcchar;
+	hctsiz_data_t hctsiz;
+	dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
+
+	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
+
+	hctsiz.d32 = 0;
+	hctsiz.b.dopng = 1;
+	hctsiz.b.pktcnt = 1;
+	DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
+
+	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+	hcchar.b.chen = 1;
+	hcchar.b.chdis = 0;
+	DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
+}
+
+/*
+ * This function writes a packet into the Tx FIFO associated with the Host
+ * Channel. For a channel associated with a non-periodic EP, the non-periodic
+ * Tx FIFO is written. For a channel associated with a periodic EP, the
+ * periodic Tx FIFO is written. This function should only be called in Slave
+ * mode.
+ *
+ * Upon return the xfer_buff and xfer_count fields in _hc are incremented by
+ * then number of bytes written to the Tx FIFO.
+ */
+void dwc_otg_hc_write_packet(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
+{
+	uint32_t i;
+	uint32_t remaining_count;
+	uint32_t byte_count;
+	uint32_t dword_count;
+
+	uint32_t *data_buff = (uint32_t *) (hc->xfer_buff);
+	uint32_t *data_fifo = core_if->data_fifo[hc->hc_num];
+
+	remaining_count = hc->xfer_len - hc->xfer_count;
+	if (remaining_count > hc->max_packet) {
+		byte_count = hc->max_packet;
+	} else {
+		byte_count = remaining_count;
+	}
+
+	dword_count = (byte_count + 3) / 4;
+
+	if ((((unsigned long)data_buff) & 0x3) == 0) {
+		/* xfer_buff is DWORD aligned. */
+		for (i = 0; i < dword_count; i++, data_buff++) {
+			DWC_WRITE_REG32(data_fifo, *data_buff);
+		}
+	} else {
+		/* xfer_buff is not DWORD aligned. */
+		for (i = 0; i < dword_count; i++, data_buff++) {
+			uint32_t data;
+			data =
+			    (data_buff[0] | data_buff[1] << 8 | data_buff[2] <<
+			     16 | data_buff[3] << 24);
+			DWC_WRITE_REG32(data_fifo, data);
+		}
+	}
+
+	hc->xfer_count += byte_count;
+	hc->xfer_buff += byte_count;
+}
+
+/**
+ * Gets the current USB frame number. This is the frame number from the last
+ * SOF packet.
+ */
+uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t * core_if)
+{
+	dsts_data_t dsts;
+	dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
+
+	/* read current frame/microframe number from DSTS register */
+	return dsts.b.soffn;
+}
+
+/**
+ * Calculates and gets the frame Interval value of HFIR register according PHY
+ * type and speed.The application can modify a value of HFIR register only after
+ * the Port Enable bit of the Host Port Control and Status register
+ * (HPRT.PrtEnaPort) has been set.
+*/
+
+uint32_t calc_frame_interval(dwc_otg_core_if_t * core_if)
+{
+	gusbcfg_data_t usbcfg;
+	hwcfg2_data_t hwcfg2;
+	hprt0_data_t hprt0;
+	int clock = 60;		// default value
+	usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
+	hwcfg2.d32 = DWC_READ_REG32(&core_if->core_global_regs->ghwcfg2);
+	hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
+	if (!usbcfg.b.physel && usbcfg.b.ulpi_utmi_sel && !usbcfg.b.phyif)
+		clock = 60;
+	if (usbcfg.b.physel && hwcfg2.b.fs_phy_type == 3)
+		clock = 48;
+	if (!usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
+	    !usbcfg.b.ulpi_utmi_sel && usbcfg.b.phyif)
+		clock = 30;
+	if (!usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
+	    !usbcfg.b.ulpi_utmi_sel && !usbcfg.b.phyif)
+		clock = 60;
+	if (usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
+	    !usbcfg.b.ulpi_utmi_sel && usbcfg.b.phyif)
+		clock = 48;
+	if (usbcfg.b.physel && !usbcfg.b.phyif && hwcfg2.b.fs_phy_type == 2)
+		clock = 48;
+	if (usbcfg.b.physel && hwcfg2.b.fs_phy_type == 1)
+		clock = 48;
+	if (hprt0.b.prtspd == 0)
+		/* High speed case */
+		return 125 * clock;
+	else
+		/* FS/LS case */
+		return 1000 * clock;
+}
+
+/**
+ * This function reads a setup packet from the Rx FIFO into the destination
+ * buffer. This function is called from the Rx Status Queue Level (RxStsQLvl)
+ * Interrupt routine when a SETUP packet has been received in Slave mode.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param dest Destination buffer for packet data.
+ */
+void dwc_otg_read_setup_packet(dwc_otg_core_if_t * core_if, uint32_t * dest)
+{
+	/* Get the 8 bytes of a setup transaction data */
+
+	/* Pop 2 DWORDS off the receive data FIFO into memory */
+	dest[0] = DWC_READ_REG32(core_if->data_fifo[0]);
+	dest[1] = DWC_READ_REG32(core_if->data_fifo[0]);
+}
+
+/**
+ * This function enables EP0 OUT to receive SETUP packets and configures EP0
+ * IN for transmitting packets. It is normally called when the
+ * "Enumeration Done" interrupt occurs.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param ep The EP0 data.
+ */
+void dwc_otg_ep0_activate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+{
+	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+	dsts_data_t dsts;
+	depctl_data_t diepctl;
+	depctl_data_t doepctl;
+	dctl_data_t dctl = {.d32 = 0 };
+
+	/* Read the Device Status and Endpoint 0 Control registers */
+	dsts.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dsts);
+	diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
+	doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl);
+
+	/* Set the MPS of the IN EP based on the enumeration speed */
+	switch (dsts.b.enumspd) {
+	case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
+	case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
+	case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:
+		diepctl.b.mps = DWC_DEP0CTL_MPS_64;
+		break;
+	case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:
+		diepctl.b.mps = DWC_DEP0CTL_MPS_8;
+		break;
+	}
+
+	DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
+
+	/* Enable OUT EP for receive */
+	doepctl.b.epena = 1;
+	DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32);
+
+#ifdef VERBOSE
+	DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n",
+		    DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl));
+	DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n",
+		    DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl));
+#endif
+	dctl.b.cgnpinnak = 1;
+
+	DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
+	DWC_DEBUGPL(DBG_PCDV, "dctl=%0x\n",
+		    DWC_READ_REG32(&dev_if->dev_global_regs->dctl));
+
+}
+
+/**
+ * This function activates an EP.  The Device EP control register for
+ * the EP is configured as defined in the ep structure. Note: This
+ * function is not used for EP0.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param ep The EP to activate.
+ */
+void dwc_otg_ep_activate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+{
+	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+	depctl_data_t depctl;
+	volatile uint32_t *addr;
+	daint_data_t daintmsk = {.d32 = 0 };
+	dcfg_data_t dcfg;
+	uint8_t i;
+
+	DWC_DEBUGPL(DBG_PCDV, "%s() EP%d-%s\n", __func__, ep->num,
+		    (ep->is_in ? "IN" : "OUT"));
+
+#ifdef DWC_UTE_PER_IO
+	ep->xiso_frame_num = 0xFFFFFFFF;
+	ep->xiso_active_xfers = 0;
+	ep->xiso_queued_xfers = 0;
+#endif
+	/* Read DEPCTLn register */
+	if (ep->is_in == 1) {
+		addr = &dev_if->in_ep_regs[ep->num]->diepctl;
+		daintmsk.ep.in = 1 << ep->num;
+	} else {
+		addr = &dev_if->out_ep_regs[ep->num]->doepctl;
+		daintmsk.ep.out = 1 << ep->num;
+	}
+
+	/* If the EP is already active don't change the EP Control
+	 * register. */
+	depctl.d32 = DWC_READ_REG32(addr);
+	if (!depctl.b.usbactep) {
+		depctl.b.mps = ep->maxpacket;
+		depctl.b.eptype = ep->type;
+		depctl.b.txfnum = ep->tx_fifo_num;
+
+		if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
+			depctl.b.setd0pid = 1;	// ???
+		} else {
+			depctl.b.setd0pid = 1;
+		}
+		depctl.b.usbactep = 1;
+
+		/* Update nextep_seq array and EPMSCNT in DCFG*/
+		if (!(depctl.b.eptype & 1) && (ep->is_in == 1)) {	// NP IN EP
+			for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
+				if (core_if->nextep_seq[i] == core_if->first_in_nextep_seq)
+				break;
+			}
+			core_if->nextep_seq[i] = ep->num;
+			core_if->nextep_seq[ep->num] = core_if->first_in_nextep_seq;
+			depctl.b.nextep = core_if->nextep_seq[ep->num];
+			dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
+			dcfg.b.epmscnt++;
+			DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
+
+			DWC_DEBUGPL(DBG_PCDV,"%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
+				__func__, core_if->first_in_nextep_seq);
+			for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
+				DWC_DEBUGPL(DBG_PCDV, "%2d\n", core_if->nextep_seq[i]);
+			}
+
+		}
+
+
+		DWC_WRITE_REG32(addr, depctl.d32);
+		DWC_DEBUGPL(DBG_PCDV, "DEPCTL=%08x\n", DWC_READ_REG32(addr));
+	}
+
+	/* Enable the Interrupt for this EP */
+	if (core_if->multiproc_int_enable) {
+		if (ep->is_in == 1) {
+			diepmsk_data_t diepmsk = {.d32 = 0 };
+			diepmsk.b.xfercompl = 1;
+			diepmsk.b.timeout = 1;
+			diepmsk.b.epdisabled = 1;
+			diepmsk.b.ahberr = 1;
+			diepmsk.b.intknepmis = 1;
+			if (!core_if->en_multiple_tx_fifo && core_if->dma_enable)
+				diepmsk.b.intknepmis = 0;
+			diepmsk.b.txfifoundrn = 1;	//?????
+			if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
+				diepmsk.b.nak = 1;
+			}
+
+
+
+/*
+			if (core_if->dma_desc_enable) {
+				diepmsk.b.bna = 1;
+			}
+*/
+/*
+			if (core_if->dma_enable) {
+				doepmsk.b.nak = 1;
+			}
+*/
+			DWC_WRITE_REG32(&dev_if->dev_global_regs->
+					diepeachintmsk[ep->num], diepmsk.d32);
+
+		} else {
+			doepmsk_data_t doepmsk = {.d32 = 0 };
+			doepmsk.b.xfercompl = 1;
+			doepmsk.b.ahberr = 1;
+			doepmsk.b.epdisabled = 1;
+			if (ep->type == DWC_OTG_EP_TYPE_ISOC)
+				doepmsk.b.outtknepdis = 1;
+
+/*
+
+			if (core_if->dma_desc_enable) {
+				doepmsk.b.bna = 1;
+			}
+*/
+/*
+			doepmsk.b.babble = 1;
+			doepmsk.b.nyet = 1;
+			doepmsk.b.nak = 1;
+*/
+			DWC_WRITE_REG32(&dev_if->dev_global_regs->
+					doepeachintmsk[ep->num], doepmsk.d32);
+		}
+		DWC_MODIFY_REG32(&dev_if->dev_global_regs->deachintmsk,
+				 0, daintmsk.d32);
+	} else {
+		if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
+			if (ep->is_in)
+			{
+				diepmsk_data_t diepmsk = {.d32 = 0 };
+				diepmsk.b.nak = 1;
+				DWC_MODIFY_REG32(&dev_if->dev_global_regs->diepmsk, 0, diepmsk.d32);
+			} else {
+				doepmsk_data_t doepmsk = {.d32 = 0 };
+				doepmsk.b.outtknepdis = 1;
+				DWC_MODIFY_REG32(&dev_if->dev_global_regs->doepmsk, 0, doepmsk.d32);
+			}
+		}
+		DWC_MODIFY_REG32(&dev_if->dev_global_regs->daintmsk,
+				 0, daintmsk.d32);
+	}
+
+	DWC_DEBUGPL(DBG_PCDV, "DAINTMSK=%0x\n",
+		    DWC_READ_REG32(&dev_if->dev_global_regs->daintmsk));
+
+	ep->stall_clear_flag = 0;
+
+	return;
+}
+
+/**
+ * This function deactivates an EP. This is done by clearing the USB Active
+ * EP bit in the Device EP control register. Note: This function is not used
+ * for EP0. EP0 cannot be deactivated.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param ep The EP to deactivate.
+ */
+void dwc_otg_ep_deactivate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+{
+	depctl_data_t depctl = {.d32 = 0 };
+	volatile uint32_t *addr;
+	daint_data_t daintmsk = {.d32 = 0 };
+	dcfg_data_t dcfg;
+	uint8_t i = 0;
+
+#ifdef DWC_UTE_PER_IO
+	ep->xiso_frame_num = 0xFFFFFFFF;
+	ep->xiso_active_xfers = 0;
+	ep->xiso_queued_xfers = 0;
+#endif
+
+	/* Read DEPCTLn register */
+	if (ep->is_in == 1) {
+		addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
+		daintmsk.ep.in = 1 << ep->num;
+	} else {
+		addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
+		daintmsk.ep.out = 1 << ep->num;
+	}
+
+	depctl.d32 = DWC_READ_REG32(addr);
+
+	depctl.b.usbactep = 0;
+
+	/* Update nextep_seq array and EPMSCNT in DCFG*/
+	if (!(depctl.b.eptype & 1) && ep->is_in == 1) {	// NP EP IN
+		for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
+			if (core_if->nextep_seq[i] == ep->num)
+			break;
+		}
+		core_if->nextep_seq[i] = core_if->nextep_seq[ep->num];
+		if (core_if->first_in_nextep_seq == ep->num)
+			core_if->first_in_nextep_seq = i;
+		core_if->nextep_seq[ep->num] = 0xff;
+		depctl.b.nextep = 0;
+		dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
+		dcfg.b.epmscnt--;
+		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
+
+			DWC_DEBUGPL(DBG_PCDV,"%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
+				__func__, core_if->first_in_nextep_seq);
+			for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
+				DWC_DEBUGPL(DBG_PCDV, "%2d\n", core_if->nextep_seq[i]);
+			}
+	}
+
+	if (ep->is_in == 1)
+		depctl.b.txfnum = 0;
+
+	if (core_if->dma_desc_enable)
+		depctl.b.epdis = 1;
+
+	DWC_WRITE_REG32(addr, depctl.d32);
+	depctl.d32 = DWC_READ_REG32(addr);
+	if (core_if->dma_enable && ep->type == DWC_OTG_EP_TYPE_ISOC && depctl.b.epena)
+	{
+		depctl_data_t depctl = {.d32 = 0};
+		if (ep->is_in)
+		{
+			diepint_data_t diepint = {.d32 = 0};
+
+			depctl.b.snak = 1;
+			DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->diepctl, depctl.d32);
+			do
+			{
+				dwc_udelay(10);
+				diepint.d32 = DWC_READ_REG32(&core_if->dev_if->
+											in_ep_regs[ep->num]->diepint);
+			} while (!diepint.b.inepnakeff);
+			diepint.b.inepnakeff = 1;
+			DWC_WRITE_REG32(&core_if->dev_if->
+							in_ep_regs[ep->num]->diepint, diepint.d32);
+			depctl.d32 = 0;
+			depctl.b.epdis = 1;
+			DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->diepctl, depctl.d32);
+			do
+			{
+				dwc_udelay(10);
+				diepint.d32 = DWC_READ_REG32(&core_if->dev_if->
+											in_ep_regs[ep->num]->diepint);
+			} while (!diepint.b.epdisabled);
+			diepint.b.epdisabled = 1;
+			DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->diepint, diepint.d32);
+		} else {
+			dctl_data_t dctl = {.d32 = 0};
+			gintmsk_data_t gintsts = {.d32 = 0};
+			doepint_data_t doepint = {.d32 = 0};
+			dctl.b.sgoutnak = 1;
+			DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
+			do
+			{
+				dwc_udelay(10);
+				gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
+			} while (!gintsts.b.goutnakeff);
+			gintsts.d32 = 0;
+			gintsts.b.goutnakeff = 1;
+			DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
+
+			depctl.d32 = 0;
+			depctl.b.epdis = 1;
+			depctl.b.snak = 1;
+			DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->doepctl, depctl.d32);
+			do
+			{
+				dwc_udelay(10);
+				doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
+											out_ep_regs[ep->num]->doepint);
+			} while (!doepint.b.epdisabled);
+
+			doepint.b.epdisabled = 1;
+			DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->doepint, doepint.d32);
+
+			dctl.d32 = 0;
+			dctl.b.cgoutnak = 1;
+			DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
+		}
+	}
+
+	/* Disable the Interrupt for this EP */
+	if (core_if->multiproc_int_enable) {
+		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->deachintmsk,
+				 daintmsk.d32, 0);
+
+		if (ep->is_in == 1) {
+			DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
+					diepeachintmsk[ep->num], 0);
+		} else {
+			DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
+					doepeachintmsk[ep->num], 0);
+		}
+	} else {
+		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->daintmsk,
+				 daintmsk.d32, 0);
+	}
+
+}
+
+/**
+ * This function initializes dma descriptor chain.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param ep The EP to start the transfer on.
+ */
+static void init_dma_desc_chain(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+{
+	dwc_otg_dev_dma_desc_t *dma_desc;
+	uint32_t offset;
+	uint32_t xfer_est;
+	int i;
+	unsigned maxxfer_local, total_len;
+
+	if (!ep->is_in && ep->type == DWC_OTG_EP_TYPE_INTR &&
+					(ep->maxpacket%4)) {
+		maxxfer_local = ep->maxpacket;
+		total_len = ep->xfer_len;
+	} else {
+		maxxfer_local = ep->maxxfer;
+		total_len = ep->total_len;
+	}
+
+	ep->desc_cnt = (total_len / maxxfer_local) +
+            ((total_len % maxxfer_local) ? 1 : 0);
+
+	if (!ep->desc_cnt)
+		ep->desc_cnt = 1;
+
+	if (ep->desc_cnt > MAX_DMA_DESC_CNT)
+		ep->desc_cnt = MAX_DMA_DESC_CNT;
+
+	dma_desc = ep->desc_addr;
+	if (maxxfer_local == ep->maxpacket) {
+		if ((total_len % maxxfer_local) &&
+				(total_len/maxxfer_local < MAX_DMA_DESC_CNT)) {
+			xfer_est = (ep->desc_cnt - 1) * maxxfer_local +
+					(total_len % maxxfer_local);
+		} else
+			xfer_est = ep->desc_cnt * maxxfer_local;
+	}
+	else
+		xfer_est = total_len;
+	offset = 0;
+	for (i = 0; i < ep->desc_cnt; ++i) {
+		/** DMA Descriptor Setup */
+		if (xfer_est > maxxfer_local) {
+			dma_desc->status.b.bs = BS_HOST_BUSY;
+			dma_desc->status.b.l = 0;
+			dma_desc->status.b.ioc = 0;
+			dma_desc->status.b.sp = 0;
+			dma_desc->status.b.bytes = maxxfer_local;
+			dma_desc->buf = ep->dma_addr + offset;
+			dma_desc->status.b.sts = 0;
+			dma_desc->status.b.bs = BS_HOST_READY;
+
+			xfer_est -= maxxfer_local;
+			offset += maxxfer_local;
+		} else {
+			dma_desc->status.b.bs = BS_HOST_BUSY;
+			dma_desc->status.b.l = 1;
+			dma_desc->status.b.ioc = 1;
+			if (ep->is_in) {
+				dma_desc->status.b.sp =
+				    (xfer_est %
+				     ep->maxpacket) ? 1 : ((ep->
+							    sent_zlp) ? 1 : 0);
+				dma_desc->status.b.bytes = xfer_est;
+			} else {
+				if (maxxfer_local == ep->maxpacket)
+					dma_desc->status.b.bytes = xfer_est;
+				else
+					dma_desc->status.b.bytes =
+				    		xfer_est + ((4 - (xfer_est & 0x3)) & 0x3);
+			}
+
+			dma_desc->buf = ep->dma_addr + offset;
+			dma_desc->status.b.sts = 0;
+			dma_desc->status.b.bs = BS_HOST_READY;
+		}
+		dma_desc++;
+	}
+}
+/**
+ * This function is called when to write ISOC data into appropriate dedicated
+ * periodic FIFO.
+ */
+static int32_t write_isoc_tx_fifo(dwc_otg_core_if_t * core_if, dwc_ep_t * dwc_ep)
+{
+	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+	dwc_otg_dev_in_ep_regs_t *ep_regs;
+	dtxfsts_data_t txstatus = {.d32 = 0 };
+	uint32_t len = 0;
+	int epnum = dwc_ep->num;
+	int dwords;
+
+	DWC_DEBUGPL(DBG_PCD, "Dedicated TxFifo Empty: %d \n", epnum);
+
+	ep_regs = core_if->dev_if->in_ep_regs[epnum];
+
+	len = dwc_ep->xfer_len - dwc_ep->xfer_count;
+
+	if (len > dwc_ep->maxpacket) {
+		len = dwc_ep->maxpacket;
+	}
+
+	dwords = (len + 3) / 4;
+
+	/* While there is space in the queue and space in the FIFO and
+	 * More data to tranfer, Write packets to the Tx FIFO */
+	txstatus.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
+	DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum, txstatus.d32);
+
+	while (txstatus.b.txfspcavail > dwords &&
+	       dwc_ep->xfer_count < dwc_ep->xfer_len &&
+	       dwc_ep->xfer_len != 0) {
+		/* Write the FIFO */
+		dwc_otg_ep_write_packet(core_if, dwc_ep, 0);
+
+		len = dwc_ep->xfer_len - dwc_ep->xfer_count;
+		if (len > dwc_ep->maxpacket) {
+			len = dwc_ep->maxpacket;
+		}
+
+		dwords = (len + 3) / 4;
+		txstatus.d32 =
+		    DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
+		DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", epnum,
+			    txstatus.d32);
+	}
+
+	DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum,
+		    DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts));
+
+	return 1;
+}
+/**
+ * This function does the setup for a data transfer for an EP and
+ * starts the transfer. For an IN transfer, the packets will be
+ * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers,
+ * the packets are unloaded from the Rx FIFO in the ISR.  the ISR.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param ep The EP to start the transfer on.
+ */
+
+void dwc_otg_ep_start_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+{
+	depctl_data_t depctl;
+	deptsiz_data_t deptsiz;
+	gintmsk_data_t intr_mask = {.d32 = 0 };
+
+	DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__);
+	DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
+		    "xfer_buff=%p start_xfer_buff=%p, total_len = %d\n",
+		    ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len,
+		    ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff,
+		    ep->total_len);
+	/* IN endpoint */
+	if (ep->is_in == 1) {
+		dwc_otg_dev_in_ep_regs_t *in_regs =
+		    core_if->dev_if->in_ep_regs[ep->num];
+
+		gnptxsts_data_t gtxstatus;
+
+		gtxstatus.d32 =
+		    DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
+
+		if (core_if->en_multiple_tx_fifo == 0
+		    && gtxstatus.b.nptxqspcavail == 0
+		    && !core_if->dma_enable) {
+#ifdef DEBUG
+			DWC_PRINTF("TX Queue Full (0x%0x)\n", gtxstatus.d32);
+#endif
+			return;
+		}
+
+		depctl.d32 = DWC_READ_REG32(&(in_regs->diepctl));
+		deptsiz.d32 = DWC_READ_REG32(&(in_regs->dieptsiz));
+
+		if (ep->maxpacket > ep->maxxfer / MAX_PKT_CNT)
+			ep->xfer_len += (ep->maxxfer < (ep->total_len - ep->xfer_len)) ?
+		    		ep->maxxfer : (ep->total_len - ep->xfer_len);
+		else
+			ep->xfer_len += (MAX_PKT_CNT * ep->maxpacket < (ep->total_len - ep->xfer_len)) ?
+				 MAX_PKT_CNT * ep->maxpacket : (ep->total_len - ep->xfer_len);
+
+
+		/* Zero Length Packet? */
+		if ((ep->xfer_len - ep->xfer_count) == 0) {
+			deptsiz.b.xfersize = 0;
+			deptsiz.b.pktcnt = 1;
+		} else {
+			/* Program the transfer size and packet count
+			 *      as follows: xfersize = N * maxpacket +
+			 *      short_packet pktcnt = N + (short_packet
+			 *      exist ? 1 : 0)
+			 */
+			deptsiz.b.xfersize = ep->xfer_len - ep->xfer_count;
+			deptsiz.b.pktcnt =
+			    (ep->xfer_len - ep->xfer_count - 1 +
+			     ep->maxpacket) / ep->maxpacket;
+			if (deptsiz.b.pktcnt > MAX_PKT_CNT) {
+				deptsiz.b.pktcnt = MAX_PKT_CNT;
+				deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
+			}
+			if (ep->type == DWC_OTG_EP_TYPE_ISOC)
+				deptsiz.b.mc = deptsiz.b.pktcnt;
+		}
+
+		/* Write the DMA register */
+		if (core_if->dma_enable) {
+			if (core_if->dma_desc_enable == 0) {
+				if (ep->type != DWC_OTG_EP_TYPE_ISOC)
+					deptsiz.b.mc = 1;
+				DWC_WRITE_REG32(&in_regs->dieptsiz,
+						deptsiz.d32);
+				DWC_WRITE_REG32(&(in_regs->diepdma),
+						(uint32_t) ep->dma_addr);
+			} else {
+#ifdef DWC_UTE_CFI
+				/* The descriptor chain should be already initialized by now */
+				if (ep->buff_mode != BM_STANDARD) {
+					DWC_WRITE_REG32(&in_regs->diepdma,
+							ep->descs_dma_addr);
+				} else {
+#endif
+					init_dma_desc_chain(core_if, ep);
+				/** DIEPDMAn Register write */
+					DWC_WRITE_REG32(&in_regs->diepdma,
+							ep->dma_desc_addr);
+#ifdef DWC_UTE_CFI
+				}
+#endif
+			}
+		} else {
+			DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
+			if (ep->type != DWC_OTG_EP_TYPE_ISOC) {
+				/**
+				 * Enable the Non-Periodic Tx FIFO empty interrupt,
+				 * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode,
+				 * the data will be written into the fifo by the ISR.
+				 */
+				if (core_if->en_multiple_tx_fifo == 0) {
+					intr_mask.b.nptxfempty = 1;
+					DWC_MODIFY_REG32
+					    (&core_if->core_global_regs->gintmsk,
+					     intr_mask.d32, intr_mask.d32);
+				} else {
+					/* Enable the Tx FIFO Empty Interrupt for this EP */
+					if (ep->xfer_len > 0) {
+						uint32_t fifoemptymsk = 0;
+						fifoemptymsk = 1 << ep->num;
+						DWC_MODIFY_REG32
+						    (&core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
+						     0, fifoemptymsk);
+
+					}
+				}
+			}  else {
+					 write_isoc_tx_fifo(core_if, ep);
+			}
+		}
+		if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
+			depctl.b.nextep = core_if->nextep_seq[ep->num];
+
+		if (ep->type == DWC_OTG_EP_TYPE_ISOC)
+		{
+			dsts_data_t dsts = {.d32 = 0};
+			if (ep->bInterval == 1) {
+				dsts.d32 =
+					DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
+				ep->frame_num = dsts.b.soffn + ep->bInterval;
+				if (ep->frame_num > 0x3FFF)
+				{
+					ep->frm_overrun = 1;
+					ep->frame_num &= 0x3FFF;
+				} else
+					ep->frm_overrun = 0;
+				if (ep->frame_num & 0x1) {
+					depctl.b.setd1pid = 1;
+				} else {
+					depctl.b.setd0pid = 1;
+				}
+			}
+		}
+		/* EP enable, IN data in FIFO */
+		depctl.b.cnak = 1;
+		depctl.b.epena = 1;
+		DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
+
+	} else {
+		/* OUT endpoint */
+		dwc_otg_dev_out_ep_regs_t *out_regs =
+		    core_if->dev_if->out_ep_regs[ep->num];
+
+		depctl.d32 = DWC_READ_REG32(&(out_regs->doepctl));
+		deptsiz.d32 = DWC_READ_REG32(&(out_regs->doeptsiz));
+
+		if (!core_if->dma_desc_enable) {
+			if (ep->maxpacket > ep->maxxfer / MAX_PKT_CNT)
+				ep->xfer_len += (ep->maxxfer < (ep->total_len - ep->xfer_len)) ?
+                        	ep->maxxfer : (ep->total_len - ep->xfer_len);
+                else
+					ep->xfer_len += (MAX_PKT_CNT * ep->maxpacket < (ep->total_len
+					- ep->xfer_len)) ? MAX_PKT_CNT * ep->maxpacket : (ep->total_len - ep->xfer_len);
+		}
+
+		/* Program the transfer size and packet count as follows:
+		 *
+		 *      pktcnt = N
+		 *      xfersize = N * maxpacket
+		 */
+		if ((ep->xfer_len - ep->xfer_count) == 0) {
+			/* Zero Length Packet */
+			deptsiz.b.xfersize = ep->maxpacket;
+			deptsiz.b.pktcnt = 1;
+		} else {
+			deptsiz.b.pktcnt =
+			    (ep->xfer_len - ep->xfer_count +
+			     (ep->maxpacket - 1)) / ep->maxpacket;
+			if (deptsiz.b.pktcnt > MAX_PKT_CNT) {
+				deptsiz.b.pktcnt = MAX_PKT_CNT;
+			}
+			if (!core_if->dma_desc_enable) {
+				ep->xfer_len =
+			    		deptsiz.b.pktcnt * ep->maxpacket + ep->xfer_count;
+			}
+			deptsiz.b.xfersize = ep->xfer_len - ep->xfer_count;
+		}
+
+		DWC_DEBUGPL(DBG_PCDV, "ep%d xfersize=%d pktcnt=%d\n",
+			    ep->num, deptsiz.b.xfersize, deptsiz.b.pktcnt);
+
+		if (core_if->dma_enable) {
+			if (!core_if->dma_desc_enable) {
+				DWC_WRITE_REG32(&out_regs->doeptsiz,
+						deptsiz.d32);
+
+				DWC_WRITE_REG32(&(out_regs->doepdma),
+						(uint32_t) ep->dma_addr);
+			} else {
+#ifdef DWC_UTE_CFI
+				/* The descriptor chain should be already initialized by now */
+				if (ep->buff_mode != BM_STANDARD) {
+					DWC_WRITE_REG32(&out_regs->doepdma,
+							ep->descs_dma_addr);
+				} else {
+#endif
+					/** This is used for interrupt out transfers*/
+					if (!ep->xfer_len)
+						ep->xfer_len = ep->total_len;
+					init_dma_desc_chain(core_if, ep);
+
+					if (core_if->core_params->dev_out_nak) {
+						if (ep->type == DWC_OTG_EP_TYPE_BULK) {
+							deptsiz.b.pktcnt = (ep->total_len +
+								(ep->maxpacket - 1)) / ep->maxpacket;
+							deptsiz.b.xfersize = ep->total_len;
+							/* Remember initial value of doeptsiz */
+							core_if->start_doeptsiz_val[ep->num] = deptsiz.d32;
+							DWC_WRITE_REG32(&out_regs->doeptsiz,
+								deptsiz.d32);
+						}
+					}
+				/** DOEPDMAn Register write */
+					DWC_WRITE_REG32(&out_regs->doepdma,
+							ep->dma_desc_addr);
+#ifdef DWC_UTE_CFI
+				}
+#endif
+			}
+		} else {
+			DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
+		}
+
+		if (ep->type == DWC_OTG_EP_TYPE_ISOC)
+		{
+			dsts_data_t dsts = {.d32 = 0};
+			if (ep->bInterval == 1) {
+				dsts.d32 =
+					DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
+				ep->frame_num = dsts.b.soffn + ep->bInterval;
+				if (ep->frame_num > 0x3FFF)
+				{
+					ep->frm_overrun = 1;
+					ep->frame_num &= 0x3FFF;
+				} else
+					ep->frm_overrun = 0;
+
+				if (ep->frame_num & 0x1) {
+					depctl.b.setd1pid = 1;
+				} else {
+					depctl.b.setd0pid = 1;
+				}
+			}
+		}
+
+		/* EP enable */
+		depctl.b.cnak = 1;
+		depctl.b.epena = 1;
+
+		DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
+
+		DWC_DEBUGPL(DBG_PCD, "DOEPCTL=%08x DOEPTSIZ=%08x\n",
+			    DWC_READ_REG32(&out_regs->doepctl),
+			    DWC_READ_REG32(&out_regs->doeptsiz));
+		DWC_DEBUGPL(DBG_PCD, "DAINTMSK=%08x GINTMSK=%08x\n",
+			    DWC_READ_REG32(&core_if->dev_if->
+					   dev_global_regs->daintmsk),
+			    DWC_READ_REG32(&core_if->
+					   core_global_regs->gintmsk));
+
+
+		/* Timer is scheduling only for out bulk transfers for
+		 * "Device DDMA OUT NAK Enhancement" feature to inform user
+		 * about received data payload in case of timeout
+		 */
+		if (core_if->core_params->dev_out_nak) {
+			if (ep->type == DWC_OTG_EP_TYPE_BULK) {
+				core_if->ep_xfer_info[ep->num].core_if = core_if;
+				core_if->ep_xfer_info[ep->num].ep = ep;
+				core_if->ep_xfer_info[ep->num].state = 1;
+
+				/* Start a timer for this transfer. */
+				DWC_TIMER_SCHEDULE(core_if->ep_xfer_timer[ep->num], 10000);
+			}
+		}
+	}
+}
+
+/**
+ * This function setup a zero length transfer in Buffer DMA and
+ * Slave modes for usb requests with zero field set
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param ep The EP to start the transfer on.
+ *
+ */
+void dwc_otg_ep_start_zl_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+{
+
+	depctl_data_t depctl;
+	deptsiz_data_t deptsiz;
+	gintmsk_data_t intr_mask = {.d32 = 0 };
+
+	DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__);
+	DWC_PRINTF("zero length transfer is called\n");
+
+	/* IN endpoint */
+	if (ep->is_in == 1) {
+		dwc_otg_dev_in_ep_regs_t *in_regs =
+		    core_if->dev_if->in_ep_regs[ep->num];
+
+		depctl.d32 = DWC_READ_REG32(&(in_regs->diepctl));
+		deptsiz.d32 = DWC_READ_REG32(&(in_regs->dieptsiz));
+
+		deptsiz.b.xfersize = 0;
+		deptsiz.b.pktcnt = 1;
+
+		/* Write the DMA register */
+		if (core_if->dma_enable) {
+			if (core_if->dma_desc_enable == 0) {
+				deptsiz.b.mc = 1;
+				DWC_WRITE_REG32(&in_regs->dieptsiz,
+						deptsiz.d32);
+				DWC_WRITE_REG32(&(in_regs->diepdma),
+						(uint32_t) ep->dma_addr);
+			}
+		} else {
+			DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
+			/**
+			 * Enable the Non-Periodic Tx FIFO empty interrupt,
+			 * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode,
+			 * the data will be written into the fifo by the ISR.
+			 */
+			if (core_if->en_multiple_tx_fifo == 0) {
+				intr_mask.b.nptxfempty = 1;
+				DWC_MODIFY_REG32(&core_if->
+						 core_global_regs->gintmsk,
+						 intr_mask.d32, intr_mask.d32);
+			} else {
+				/* Enable the Tx FIFO Empty Interrupt for this EP */
+				if (ep->xfer_len > 0) {
+					uint32_t fifoemptymsk = 0;
+					fifoemptymsk = 1 << ep->num;
+					DWC_MODIFY_REG32(&core_if->
+							 dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
+							 0, fifoemptymsk);
+				}
+			}
+		}
+
+		if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
+			depctl.b.nextep = core_if->nextep_seq[ep->num];
+		/* EP enable, IN data in FIFO */
+		depctl.b.cnak = 1;
+		depctl.b.epena = 1;
+		DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
+
+	} else {
+		/* OUT endpoint */
+		dwc_otg_dev_out_ep_regs_t *out_regs =
+		    core_if->dev_if->out_ep_regs[ep->num];
+
+		depctl.d32 = DWC_READ_REG32(&(out_regs->doepctl));
+		deptsiz.d32 = DWC_READ_REG32(&(out_regs->doeptsiz));
+
+		/* Zero Length Packet */
+		deptsiz.b.xfersize = ep->maxpacket;
+		deptsiz.b.pktcnt = 1;
+
+		if (core_if->dma_enable) {
+			if (!core_if->dma_desc_enable) {
+				DWC_WRITE_REG32(&out_regs->doeptsiz,
+						deptsiz.d32);
+
+				DWC_WRITE_REG32(&(out_regs->doepdma),
+						(uint32_t) ep->dma_addr);
+			}
+		} else {
+			DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
+		}
+
+		/* EP enable */
+		depctl.b.cnak = 1;
+		depctl.b.epena = 1;
+
+		DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
+
+	}
+}
+
+/**
+ * This function does the setup for a data transfer for EP0 and starts
+ * the transfer.  For an IN transfer, the packets will be loaded into
+ * the appropriate Tx FIFO in the ISR. For OUT transfers, the packets are
+ * unloaded from the Rx FIFO in the ISR.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param ep The EP0 data.
+ */
+void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+{
+	depctl_data_t depctl;
+	deptsiz0_data_t deptsiz;
+	gintmsk_data_t intr_mask = {.d32 = 0 };
+	dwc_otg_dev_dma_desc_t *dma_desc;
+
+	DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
+		    "xfer_buff=%p start_xfer_buff=%p \n",
+		    ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len,
+		    ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff);
+
+	ep->total_len = ep->xfer_len;
+
+	/* IN endpoint */
+	if (ep->is_in == 1) {
+		dwc_otg_dev_in_ep_regs_t *in_regs =
+		    core_if->dev_if->in_ep_regs[0];
+
+		gnptxsts_data_t gtxstatus;
+
+		gtxstatus.d32 =
+		    DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
+
+		if (core_if->en_multiple_tx_fifo == 0
+		    && gtxstatus.b.nptxqspcavail == 0
+		    && !core_if->dma_enable) {
+#ifdef DEBUG
+			deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
+			DWC_DEBUGPL(DBG_PCD, "DIEPCTL0=%0x\n",
+				    DWC_READ_REG32(&in_regs->diepctl));
+			DWC_DEBUGPL(DBG_PCD, "DIEPTSIZ0=%0x (sz=%d, pcnt=%d)\n",
+				    deptsiz.d32,
+				    deptsiz.b.xfersize, deptsiz.b.pktcnt);
+			DWC_PRINTF("TX Queue or FIFO Full (0x%0x)\n",
+				   gtxstatus.d32);
+#endif
+			return;
+		}
+
+		depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
+		deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
+
+		/* Zero Length Packet? */
+		if (ep->xfer_len == 0) {
+			deptsiz.b.xfersize = 0;
+			deptsiz.b.pktcnt = 1;
+		} else {
+			/* Program the transfer size and packet count
+			 *      as follows: xfersize = N * maxpacket +
+			 *      short_packet pktcnt = N + (short_packet
+			 *      exist ? 1 : 0)
+			 */
+			if (ep->xfer_len > ep->maxpacket) {
+				ep->xfer_len = ep->maxpacket;
+				deptsiz.b.xfersize = ep->maxpacket;
+			} else {
+				deptsiz.b.xfersize = ep->xfer_len;
+			}
+			deptsiz.b.pktcnt = 1;
+
+		}
+		DWC_DEBUGPL(DBG_PCDV,
+			    "IN len=%d  xfersize=%d pktcnt=%d [%08x]\n",
+			    ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
+			    deptsiz.d32);
+
+		/* Write the DMA register */
+		if (core_if->dma_enable) {
+			if (core_if->dma_desc_enable == 0) {
+				DWC_WRITE_REG32(&in_regs->dieptsiz,
+						deptsiz.d32);
+
+				DWC_WRITE_REG32(&(in_regs->diepdma),
+						(uint32_t) ep->dma_addr);
+			} else {
+				dma_desc = core_if->dev_if->in_desc_addr;
+
+				/** DMA Descriptor Setup */
+				dma_desc->status.b.bs = BS_HOST_BUSY;
+				dma_desc->status.b.l = 1;
+				dma_desc->status.b.ioc = 1;
+				dma_desc->status.b.sp =
+				    (ep->xfer_len == ep->maxpacket) ? 0 : 1;
+				dma_desc->status.b.bytes = ep->xfer_len;
+				dma_desc->buf = ep->dma_addr;
+				dma_desc->status.b.sts = 0;
+				dma_desc->status.b.bs = BS_HOST_READY;
+
+				/** DIEPDMA0 Register write */
+				DWC_WRITE_REG32(&in_regs->diepdma,
+						core_if->
+						dev_if->dma_in_desc_addr);
+			}
+		} else {
+			DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
+		}
+
+		if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
+			depctl.b.nextep = core_if->nextep_seq[ep->num];
+		/* EP enable, IN data in FIFO */
+		depctl.b.cnak = 1;
+		depctl.b.epena = 1;
+		DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
+
+		/**
+		 * Enable the Non-Periodic Tx FIFO empty interrupt, the
+		 * data will be written into the fifo by the ISR.
+		 */
+		if (!core_if->dma_enable) {
+			if (core_if->en_multiple_tx_fifo == 0) {
+				intr_mask.b.nptxfempty = 1;
+				DWC_MODIFY_REG32(&core_if->
+						 core_global_regs->gintmsk,
+						 intr_mask.d32, intr_mask.d32);
+			} else {
+				/* Enable the Tx FIFO Empty Interrupt for this EP */
+				if (ep->xfer_len > 0) {
+					uint32_t fifoemptymsk = 0;
+					fifoemptymsk |= 1 << ep->num;
+					DWC_MODIFY_REG32(&core_if->
+							 dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
+							 0, fifoemptymsk);
+				}
+			}
+		}
+	} else {
+		/* OUT endpoint */
+		dwc_otg_dev_out_ep_regs_t *out_regs =
+		    core_if->dev_if->out_ep_regs[0];
+
+		depctl.d32 = DWC_READ_REG32(&out_regs->doepctl);
+		deptsiz.d32 = DWC_READ_REG32(&out_regs->doeptsiz);
+
+		/* Program the transfer size and packet count as follows:
+		 *      xfersize = N * (maxpacket + 4 - (maxpacket % 4))
+		 *      pktcnt = N                                                                                      */
+		/* Zero Length Packet */
+		deptsiz.b.xfersize = ep->maxpacket;
+		deptsiz.b.pktcnt = 1;
+
+		DWC_DEBUGPL(DBG_PCDV, "len=%d  xfersize=%d pktcnt=%d\n",
+			    ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt);
+
+		if (core_if->dma_enable) {
+			if (!core_if->dma_desc_enable) {
+				DWC_WRITE_REG32(&out_regs->doeptsiz,
+						deptsiz.d32);
+
+				DWC_WRITE_REG32(&(out_regs->doepdma),
+						(uint32_t) ep->dma_addr);
+			} else {
+				dma_desc = core_if->dev_if->out_desc_addr;
+
+				/** DMA Descriptor Setup */
+				dma_desc->status.b.bs = BS_HOST_BUSY;
+				dma_desc->status.b.l = 1;
+				dma_desc->status.b.ioc = 1;
+				dma_desc->status.b.bytes = ep->maxpacket;
+				dma_desc->buf = ep->dma_addr;
+				dma_desc->status.b.sts = 0;
+				dma_desc->status.b.bs = BS_HOST_READY;
+
+				/** DOEPDMA0 Register write */
+				DWC_WRITE_REG32(&out_regs->doepdma,
+						core_if->
+						dev_if->dma_out_desc_addr);
+			}
+		} else {
+			DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
+		}
+
+		/* EP enable */
+		depctl.b.cnak = 1;
+		depctl.b.epena = 1;
+		DWC_WRITE_REG32(&(out_regs->doepctl), depctl.d32);
+	}
+}
+
+/**
+ * This function continues control IN transfers started by
+ * dwc_otg_ep0_start_transfer, when the transfer does not fit in a
+ * single packet.  NOTE: The DIEPCTL0/DOEPCTL0 registers only have one
+ * bit for the packet count.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param ep The EP0 data.
+ */
+void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+{
+	depctl_data_t depctl;
+	deptsiz0_data_t deptsiz;
+	gintmsk_data_t intr_mask = {.d32 = 0 };
+	dwc_otg_dev_dma_desc_t *dma_desc;
+
+	if (ep->is_in == 1) {
+		dwc_otg_dev_in_ep_regs_t *in_regs =
+		    core_if->dev_if->in_ep_regs[0];
+		gnptxsts_data_t tx_status = {.d32 = 0 };
+
+		tx_status.d32 =
+		    DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
+		/** @todo Should there be check for room in the Tx
+		 * Status Queue.  If not remove the code above this comment. */
+
+		depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
+		deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
+
+		/* Program the transfer size and packet count
+		 *      as follows: xfersize = N * maxpacket +
+		 *      short_packet pktcnt = N + (short_packet
+		 *      exist ? 1 : 0)
+		 */
+
+		if (core_if->dma_desc_enable == 0) {
+			deptsiz.b.xfersize =
+			    (ep->total_len - ep->xfer_count) >
+			    ep->maxpacket ? ep->maxpacket : (ep->total_len -
+							     ep->xfer_count);
+			deptsiz.b.pktcnt = 1;
+			if (core_if->dma_enable == 0) {
+				ep->xfer_len += deptsiz.b.xfersize;
+			} else {
+				ep->xfer_len = deptsiz.b.xfersize;
+			}
+			DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
+		} else {
+			ep->xfer_len =
+			    (ep->total_len - ep->xfer_count) >
+			    ep->maxpacket ? ep->maxpacket : (ep->total_len -
+							     ep->xfer_count);
+
+			dma_desc = core_if->dev_if->in_desc_addr;
+
+			/** DMA Descriptor Setup */
+			dma_desc->status.b.bs = BS_HOST_BUSY;
+			dma_desc->status.b.l = 1;
+			dma_desc->status.b.ioc = 1;
+			dma_desc->status.b.sp =
+			    (ep->xfer_len == ep->maxpacket) ? 0 : 1;
+			dma_desc->status.b.bytes = ep->xfer_len;
+			dma_desc->buf = ep->dma_addr;
+			dma_desc->status.b.sts = 0;
+			dma_desc->status.b.bs = BS_HOST_READY;
+
+			/** DIEPDMA0 Register write */
+			DWC_WRITE_REG32(&in_regs->diepdma,
+					core_if->dev_if->dma_in_desc_addr);
+		}
+
+		DWC_DEBUGPL(DBG_PCDV,
+			    "IN len=%d  xfersize=%d pktcnt=%d [%08x]\n",
+			    ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
+			    deptsiz.d32);
+
+		/* Write the DMA register */
+		if (core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) {
+			if (core_if->dma_desc_enable == 0)
+				DWC_WRITE_REG32(&(in_regs->diepdma),
+						(uint32_t) ep->dma_addr);
+		}
+		if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
+			depctl.b.nextep = core_if->nextep_seq[ep->num];
+		/* EP enable, IN data in FIFO */
+		depctl.b.cnak = 1;
+		depctl.b.epena = 1;
+		DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
+
+		/**
+		 * Enable the Non-Periodic Tx FIFO empty interrupt, the
+		 * data will be written into the fifo by the ISR.
+		 */
+		if (!core_if->dma_enable) {
+			if (core_if->en_multiple_tx_fifo == 0) {
+				/* First clear it from GINTSTS */
+				intr_mask.b.nptxfempty = 1;
+				DWC_MODIFY_REG32(&core_if->
+						 core_global_regs->gintmsk,
+						 intr_mask.d32, intr_mask.d32);
+
+			} else {
+				/* Enable the Tx FIFO Empty Interrupt for this EP */
+				if (ep->xfer_len > 0) {
+					uint32_t fifoemptymsk = 0;
+					fifoemptymsk |= 1 << ep->num;
+					DWC_MODIFY_REG32(&core_if->
+							 dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
+							 0, fifoemptymsk);
+				}
+			}
+		}
+	} else {
+		dwc_otg_dev_out_ep_regs_t *out_regs =
+		    core_if->dev_if->out_ep_regs[0];
+
+		depctl.d32 = DWC_READ_REG32(&out_regs->doepctl);
+		deptsiz.d32 = DWC_READ_REG32(&out_regs->doeptsiz);
+
+		/* Program the transfer size and packet count
+		 *      as follows: xfersize = N * maxpacket +
+		 *      short_packet pktcnt = N + (short_packet
+		 *      exist ? 1 : 0)
+		 */
+		deptsiz.b.xfersize = ep->maxpacket;
+		deptsiz.b.pktcnt = 1;
+
+		if (core_if->dma_desc_enable == 0) {
+			DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
+		} else {
+			dma_desc = core_if->dev_if->out_desc_addr;
+
+			/** DMA Descriptor Setup */
+			dma_desc->status.b.bs = BS_HOST_BUSY;
+			dma_desc->status.b.l = 1;
+			dma_desc->status.b.ioc = 1;
+			dma_desc->status.b.bytes = ep->maxpacket;
+			dma_desc->buf = ep->dma_addr;
+			dma_desc->status.b.sts = 0;
+			dma_desc->status.b.bs = BS_HOST_READY;
+
+			/** DOEPDMA0 Register write */
+			DWC_WRITE_REG32(&out_regs->doepdma,
+					core_if->dev_if->dma_out_desc_addr);
+		}
+
+		DWC_DEBUGPL(DBG_PCDV,
+			    "IN len=%d  xfersize=%d pktcnt=%d [%08x]\n",
+			    ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
+			    deptsiz.d32);
+
+		/* Write the DMA register */
+		if (core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) {
+			if (core_if->dma_desc_enable == 0)
+				DWC_WRITE_REG32(&(out_regs->doepdma),
+						(uint32_t) ep->dma_addr);
+
+		}
+
+		/* EP enable, IN data in FIFO */
+		depctl.b.cnak = 1;
+		depctl.b.epena = 1;
+		DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
+
+	}
+}
+
+#ifdef DEBUG
+void dump_msg(const u8 * buf, unsigned int length)
+{
+	unsigned int start, num, i;
+	char line[52], *p;
+
+	if (length >= 512)
+		return;
+	start = 0;
+	while (length > 0) {
+		num = length < 16u ? length : 16u;
+		p = line;
+		for (i = 0; i < num; ++i) {
+			if (i == 8)
+				*p++ = ' ';
+			DWC_SPRINTF(p, " %02x", buf[i]);
+			p += 3;
+		}
+		*p = 0;
+		DWC_PRINTF("%6x: %s\n", start, line);
+		buf += num;
+		start += num;
+		length -= num;
+	}
+}
+#else
+static inline void dump_msg(const u8 * buf, unsigned int length)
+{
+}
+#endif
+
+/**
+ * This function writes a packet into the Tx FIFO associated with the
+ * EP. For non-periodic EPs the non-periodic Tx FIFO is written.  For
+ * periodic EPs the periodic Tx FIFO associated with the EP is written
+ * with all packets for the next micro-frame.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param ep The EP to write packet for.
+ * @param dma Indicates if DMA is being used.
+ */
+void dwc_otg_ep_write_packet(dwc_otg_core_if_t * core_if, dwc_ep_t * ep,
+			     int dma)
+{
+	/**
+	 * The buffer is padded to DWORD on a per packet basis in
+	 * slave/dma mode if the MPS is not DWORD aligned. The last
+	 * packet, if short, is also padded to a multiple of DWORD.
+	 *
+	 * ep->xfer_buff always starts DWORD aligned in memory and is a
+	 * multiple of DWORD in length
+	 *
+	 * ep->xfer_len can be any number of bytes
+	 *
+	 * ep->xfer_count is a multiple of ep->maxpacket until the last
+	 *	packet
+	 *
+	 * FIFO access is DWORD */
+
+	uint32_t i;
+	uint32_t byte_count;
+	uint32_t dword_count;
+	uint32_t *fifo;
+	uint32_t *data_buff = (uint32_t *) ep->xfer_buff;
+
+	DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p)\n", __func__, core_if,
+		    ep);
+	if (ep->xfer_count >= ep->xfer_len) {
+		DWC_WARN("%s() No data for EP%d!!!\n", __func__, ep->num);
+		return;
+	}
+
+	/* Find the byte length of the packet either short packet or MPS */
+	if ((ep->xfer_len - ep->xfer_count) < ep->maxpacket) {
+		byte_count = ep->xfer_len - ep->xfer_count;
+	} else {
+		byte_count = ep->maxpacket;
+	}
+
+	/* Find the DWORD length, padded by extra bytes as neccessary if MPS
+	 * is not a multiple of DWORD */
+	dword_count = (byte_count + 3) / 4;
+
+#ifdef VERBOSE
+	dump_msg(ep->xfer_buff, byte_count);
+#endif
+
+	/**@todo NGS Where are the Periodic Tx FIFO addresses
+	 * intialized?	What should this be? */
+
+	fifo = core_if->data_fifo[ep->num];
+
+	DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "fifo=%p buff=%p *p=%08x bc=%d\n",
+		    fifo, data_buff, *data_buff, byte_count);
+
+	if (!dma) {
+		for (i = 0; i < dword_count; i++, data_buff++) {
+			DWC_WRITE_REG32(fifo, *data_buff);
+		}
+	}
+
+	ep->xfer_count += byte_count;
+	ep->xfer_buff += byte_count;
+	ep->dma_addr += byte_count;
+}
+
+/**
+ * Set the EP STALL.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param ep The EP to set the stall on.
+ */
+void dwc_otg_ep_set_stall(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+{
+	depctl_data_t depctl;
+	volatile uint32_t *depctl_addr;
+
+	DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num,
+		    (ep->is_in ? "IN" : "OUT"));
+
+	if (ep->is_in == 1) {
+		depctl_addr = &(core_if->dev_if->in_ep_regs[ep->num]->diepctl);
+		depctl.d32 = DWC_READ_REG32(depctl_addr);
+
+		/* set the disable and stall bits */
+		if (depctl.b.epena) {
+			depctl.b.epdis = 1;
+		}
+		depctl.b.stall = 1;
+		DWC_WRITE_REG32(depctl_addr, depctl.d32);
+	} else {
+		depctl_addr = &(core_if->dev_if->out_ep_regs[ep->num]->doepctl);
+		depctl.d32 = DWC_READ_REG32(depctl_addr);
+
+		/* set the stall bit */
+		depctl.b.stall = 1;
+		DWC_WRITE_REG32(depctl_addr, depctl.d32);
+	}
+
+	DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", DWC_READ_REG32(depctl_addr));
+
+	return;
+}
+
+/**
+ * Clear the EP STALL.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param ep The EP to clear stall from.
+ */
+void dwc_otg_ep_clear_stall(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+{
+	depctl_data_t depctl;
+	volatile uint32_t *depctl_addr;
+
+	DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num,
+		    (ep->is_in ? "IN" : "OUT"));
+
+	if (ep->is_in == 1) {
+		depctl_addr = &(core_if->dev_if->in_ep_regs[ep->num]->diepctl);
+	} else {
+		depctl_addr = &(core_if->dev_if->out_ep_regs[ep->num]->doepctl);
+	}
+
+	depctl.d32 = DWC_READ_REG32(depctl_addr);
+
+	/* clear the stall bits */
+	depctl.b.stall = 0;
+
+	/*
+	 * USB Spec 9.4.5: For endpoints using data toggle, regardless
+	 * of whether an endpoint has the Halt feature set, a
+	 * ClearFeature(ENDPOINT_HALT) request always results in the
+	 * data toggle being reinitialized to DATA0.
+	 */
+	if (ep->type == DWC_OTG_EP_TYPE_INTR ||
+	    ep->type == DWC_OTG_EP_TYPE_BULK) {
+		depctl.b.setd0pid = 1;	/* DATA0 */
+	}
+
+	DWC_WRITE_REG32(depctl_addr, depctl.d32);
+	DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", DWC_READ_REG32(depctl_addr));
+	return;
+}
+
+/**
+ * This function reads a packet from the Rx FIFO into the destination
+ * buffer. To read SETUP data use dwc_otg_read_setup_packet.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param dest	  Destination buffer for the packet.
+ * @param bytes  Number of bytes to copy to the destination.
+ */
+void dwc_otg_read_packet(dwc_otg_core_if_t * core_if,
+			 uint8_t * dest, uint16_t bytes)
+{
+	int i;
+	int word_count = (bytes + 3) / 4;
+
+	volatile uint32_t *fifo = core_if->data_fifo[0];
+	uint32_t *data_buff = (uint32_t *) dest;
+
+	/**
+	 * @todo Account for the case where _dest is not dword aligned. This
+	 * requires reading data from the FIFO into a uint32_t temp buffer,
+	 * then moving it into the data buffer.
+	 */
+
+	DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p,%d)\n", __func__,
+		    core_if, dest, bytes);
+
+	for (i = 0; i < word_count; i++, data_buff++) {
+		*data_buff = DWC_READ_REG32(fifo);
+	}
+
+	return;
+}
+
+/**
+ * This functions reads the device registers and prints them
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ */
+void dwc_otg_dump_dev_registers(dwc_otg_core_if_t * core_if)
+{
+	int i;
+	volatile uint32_t *addr;
+
+	DWC_PRINTF("Device Global Registers\n");
+	addr = &core_if->dev_if->dev_global_regs->dcfg;
+	DWC_PRINTF("DCFG		 @0x%08lX : 0x%08X\n", (unsigned long) addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->dev_if->dev_global_regs->dctl;
+	DWC_PRINTF("DCTL		 @0x%08lX : 0x%08X\n", (unsigned long) addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->dev_if->dev_global_regs->dsts;
+	DWC_PRINTF("DSTS		 @0x%08lX : 0x%08X\n", (unsigned long) addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->dev_if->dev_global_regs->diepmsk;
+	DWC_PRINTF("DIEPMSK	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->dev_if->dev_global_regs->doepmsk;
+	DWC_PRINTF("DOEPMSK	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->dev_if->dev_global_regs->daint;
+	DWC_PRINTF("DAINT	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->dev_if->dev_global_regs->daintmsk;
+	DWC_PRINTF("DAINTMSK	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->dev_if->dev_global_regs->dtknqr1;
+	DWC_PRINTF("DTKNQR1	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	if (core_if->hwcfg2.b.dev_token_q_depth > 6) {
+		addr = &core_if->dev_if->dev_global_regs->dtknqr2;
+		DWC_PRINTF("DTKNQR2	 @0x%08lX : 0x%08X\n",
+			   (unsigned long)addr, DWC_READ_REG32(addr));
+	}
+
+	addr = &core_if->dev_if->dev_global_regs->dvbusdis;
+	DWC_PRINTF("DVBUSID	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+
+	addr = &core_if->dev_if->dev_global_regs->dvbuspulse;
+	DWC_PRINTF("DVBUSPULSE	@0x%08lX : 0x%08X\n",
+		   (unsigned long)addr, DWC_READ_REG32(addr));
+
+	addr = &core_if->dev_if->dev_global_regs->dtknqr3_dthrctl;
+	DWC_PRINTF("DTKNQR3_DTHRCTL	 @0x%08lX : 0x%08X\n",
+		   (unsigned long)addr, DWC_READ_REG32(addr));
+
+	if (core_if->hwcfg2.b.dev_token_q_depth > 22) {
+		addr = &core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk;
+		DWC_PRINTF("DTKNQR4	 @0x%08lX : 0x%08X\n",
+			   (unsigned long)addr, DWC_READ_REG32(addr));
+	}
+
+	addr = &core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk;
+	DWC_PRINTF("FIFOEMPMSK	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+
+	if (core_if->hwcfg2.b.multi_proc_int) {
+
+		addr = &core_if->dev_if->dev_global_regs->deachint;
+		DWC_PRINTF("DEACHINT	 @0x%08lX : 0x%08X\n",
+			   (unsigned long)addr, DWC_READ_REG32(addr));
+		addr = &core_if->dev_if->dev_global_regs->deachintmsk;
+		DWC_PRINTF("DEACHINTMSK	 @0x%08lX : 0x%08X\n",
+			   (unsigned long)addr, DWC_READ_REG32(addr));
+
+		for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
+			addr =
+			    &core_if->dev_if->dev_global_regs->
+			    diepeachintmsk[i];
+			DWC_PRINTF("DIEPEACHINTMSK[%d]	 @0x%08lX : 0x%08X\n",
+				   i, (unsigned long)addr,
+				   DWC_READ_REG32(addr));
+		}
+
+		for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
+			addr =
+			    &core_if->dev_if->dev_global_regs->
+			    doepeachintmsk[i];
+			DWC_PRINTF("DOEPEACHINTMSK[%d]	 @0x%08lX : 0x%08X\n",
+				   i, (unsigned long)addr,
+				   DWC_READ_REG32(addr));
+		}
+	}
+
+	for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
+		DWC_PRINTF("Device IN EP %d Registers\n", i);
+		addr = &core_if->dev_if->in_ep_regs[i]->diepctl;
+		DWC_PRINTF("DIEPCTL	 @0x%08lX : 0x%08X\n",
+			   (unsigned long)addr, DWC_READ_REG32(addr));
+		addr = &core_if->dev_if->in_ep_regs[i]->diepint;
+		DWC_PRINTF("DIEPINT	 @0x%08lX : 0x%08X\n",
+			   (unsigned long)addr, DWC_READ_REG32(addr));
+		addr = &core_if->dev_if->in_ep_regs[i]->dieptsiz;
+		DWC_PRINTF("DIETSIZ	 @0x%08lX : 0x%08X\n",
+			   (unsigned long)addr, DWC_READ_REG32(addr));
+		addr = &core_if->dev_if->in_ep_regs[i]->diepdma;
+		DWC_PRINTF("DIEPDMA	 @0x%08lX : 0x%08X\n",
+			   (unsigned long)addr, DWC_READ_REG32(addr));
+		addr = &core_if->dev_if->in_ep_regs[i]->dtxfsts;
+		DWC_PRINTF("DTXFSTS	 @0x%08lX : 0x%08X\n",
+			   (unsigned long)addr, DWC_READ_REG32(addr));
+		addr = &core_if->dev_if->in_ep_regs[i]->diepdmab;
+		DWC_PRINTF("DIEPDMAB	 @0x%08lX : 0x%08X\n",
+			   (unsigned long)addr, 0 /*DWC_READ_REG32(addr) */ );
+	}
+
+	for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
+		DWC_PRINTF("Device OUT EP %d Registers\n", i);
+		addr = &core_if->dev_if->out_ep_regs[i]->doepctl;
+		DWC_PRINTF("DOEPCTL	 @0x%08lX : 0x%08X\n",
+			   (unsigned long)addr, DWC_READ_REG32(addr));
+		addr = &core_if->dev_if->out_ep_regs[i]->doepint;
+		DWC_PRINTF("DOEPINT	 @0x%08lX : 0x%08X\n",
+			   (unsigned long)addr, DWC_READ_REG32(addr));
+		addr = &core_if->dev_if->out_ep_regs[i]->doeptsiz;
+		DWC_PRINTF("DOETSIZ	 @0x%08lX : 0x%08X\n",
+			   (unsigned long)addr, DWC_READ_REG32(addr));
+		addr = &core_if->dev_if->out_ep_regs[i]->doepdma;
+		DWC_PRINTF("DOEPDMA	 @0x%08lX : 0x%08X\n",
+			   (unsigned long)addr, DWC_READ_REG32(addr));
+		if (core_if->dma_enable) {	/* Don't access this register in SLAVE mode */
+			addr = &core_if->dev_if->out_ep_regs[i]->doepdmab;
+			DWC_PRINTF("DOEPDMAB	 @0x%08lX : 0x%08X\n",
+				   (unsigned long)addr, DWC_READ_REG32(addr));
+		}
+
+	}
+}
+
+/**
+ * This functions reads the SPRAM and prints its content
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ */
+void dwc_otg_dump_spram(dwc_otg_core_if_t * core_if)
+{
+	volatile uint8_t *addr, *start_addr, *end_addr;
+
+	DWC_PRINTF("SPRAM Data:\n");
+	start_addr = (void *)core_if->core_global_regs;
+	DWC_PRINTF("Base Address: 0x%8lX\n", (unsigned long)start_addr);
+	start_addr += 0x00028000;
+	end_addr = (void *)core_if->core_global_regs;
+	end_addr += 0x000280e0;
+
+	for (addr = start_addr; addr < end_addr; addr += 16) {
+		DWC_PRINTF
+		    ("0x%8lX:\t%2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X\n",
+		     (unsigned long)addr, addr[0], addr[1], addr[2], addr[3],
+		     addr[4], addr[5], addr[6], addr[7], addr[8], addr[9],
+		     addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]
+		    );
+	}
+
+	return;
+}
+
+/**
+ * This function reads the host registers and prints them
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ */
+void dwc_otg_dump_host_registers(dwc_otg_core_if_t * core_if)
+{
+	int i;
+	volatile uint32_t *addr;
+
+	DWC_PRINTF("Host Global Registers\n");
+	addr = &core_if->host_if->host_global_regs->hcfg;
+	DWC_PRINTF("HCFG		 @0x%08lX : 0x%08X\n",
+		   (unsigned long)addr, DWC_READ_REG32(addr));
+	addr = &core_if->host_if->host_global_regs->hfir;
+	DWC_PRINTF("HFIR		 @0x%08lX : 0x%08X\n",
+		   (unsigned long)addr, DWC_READ_REG32(addr));
+	addr = &core_if->host_if->host_global_regs->hfnum;
+	DWC_PRINTF("HFNUM	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->host_if->host_global_regs->hptxsts;
+	DWC_PRINTF("HPTXSTS	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->host_if->host_global_regs->haint;
+	DWC_PRINTF("HAINT	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->host_if->host_global_regs->haintmsk;
+	DWC_PRINTF("HAINTMSK	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	if (core_if->dma_desc_enable) {
+		addr = &core_if->host_if->host_global_regs->hflbaddr;
+		DWC_PRINTF("HFLBADDR	 @0x%08lX : 0x%08X\n",
+			   (unsigned long)addr, DWC_READ_REG32(addr));
+	}
+
+	addr = core_if->host_if->hprt0;
+	DWC_PRINTF("HPRT0	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+
+	for (i = 0; i < core_if->core_params->host_channels; i++) {
+		DWC_PRINTF("Host Channel %d Specific Registers\n", i);
+		addr = &core_if->host_if->hc_regs[i]->hcchar;
+		DWC_PRINTF("HCCHAR	 @0x%08lX : 0x%08X\n",
+			   (unsigned long)addr, DWC_READ_REG32(addr));
+		addr = &core_if->host_if->hc_regs[i]->hcsplt;
+		DWC_PRINTF("HCSPLT	 @0x%08lX : 0x%08X\n",
+			   (unsigned long)addr, DWC_READ_REG32(addr));
+		addr = &core_if->host_if->hc_regs[i]->hcint;
+		DWC_PRINTF("HCINT	 @0x%08lX : 0x%08X\n",
+			   (unsigned long)addr, DWC_READ_REG32(addr));
+		addr = &core_if->host_if->hc_regs[i]->hcintmsk;
+		DWC_PRINTF("HCINTMSK	 @0x%08lX : 0x%08X\n",
+			   (unsigned long)addr, DWC_READ_REG32(addr));
+		addr = &core_if->host_if->hc_regs[i]->hctsiz;
+		DWC_PRINTF("HCTSIZ	 @0x%08lX : 0x%08X\n",
+			   (unsigned long)addr, DWC_READ_REG32(addr));
+		addr = &core_if->host_if->hc_regs[i]->hcdma;
+		DWC_PRINTF("HCDMA	 @0x%08lX : 0x%08X\n",
+			   (unsigned long)addr, DWC_READ_REG32(addr));
+		if (core_if->dma_desc_enable) {
+			addr = &core_if->host_if->hc_regs[i]->hcdmab;
+			DWC_PRINTF("HCDMAB	 @0x%08lX : 0x%08X\n",
+				   (unsigned long)addr, DWC_READ_REG32(addr));
+		}
+
+	}
+	return;
+}
+
+/**
+ * This function reads the core global registers and prints them
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ */
+void dwc_otg_dump_global_registers(dwc_otg_core_if_t * core_if)
+{
+	int i, ep_num;
+	volatile uint32_t *addr;
+	char *txfsiz;
+
+	DWC_PRINTF("Core Global Registers\n");
+	addr = &core_if->core_global_regs->gotgctl;
+	DWC_PRINTF("GOTGCTL	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->core_global_regs->gotgint;
+	DWC_PRINTF("GOTGINT	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->core_global_regs->gahbcfg;
+	DWC_PRINTF("GAHBCFG	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->core_global_regs->gusbcfg;
+	DWC_PRINTF("GUSBCFG	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->core_global_regs->grstctl;
+	DWC_PRINTF("GRSTCTL	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->core_global_regs->gintsts;
+	DWC_PRINTF("GINTSTS	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->core_global_regs->gintmsk;
+	DWC_PRINTF("GINTMSK	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->core_global_regs->grxstsr;
+	DWC_PRINTF("GRXSTSR	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->core_global_regs->grxfsiz;
+	DWC_PRINTF("GRXFSIZ	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->core_global_regs->gnptxfsiz;
+	DWC_PRINTF("GNPTXFSIZ @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->core_global_regs->gnptxsts;
+	DWC_PRINTF("GNPTXSTS	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->core_global_regs->gi2cctl;
+	DWC_PRINTF("GI2CCTL	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->core_global_regs->gpvndctl;
+	DWC_PRINTF("GPVNDCTL	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->core_global_regs->ggpio;
+	DWC_PRINTF("GGPIO	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->core_global_regs->guid;
+	DWC_PRINTF("GUID		 @0x%08lX : 0x%08X\n",
+		   (unsigned long)addr, DWC_READ_REG32(addr));
+	addr = &core_if->core_global_regs->gsnpsid;
+	DWC_PRINTF("GSNPSID	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->core_global_regs->ghwcfg1;
+	DWC_PRINTF("GHWCFG1	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->core_global_regs->ghwcfg2;
+	DWC_PRINTF("GHWCFG2	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->core_global_regs->ghwcfg3;
+	DWC_PRINTF("GHWCFG3	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->core_global_regs->ghwcfg4;
+	DWC_PRINTF("GHWCFG4	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->core_global_regs->glpmcfg;
+	DWC_PRINTF("GLPMCFG	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->core_global_regs->gpwrdn;
+	DWC_PRINTF("GPWRDN	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->core_global_regs->gdfifocfg;
+	DWC_PRINTF("GDFIFOCFG	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+	addr = &core_if->core_global_regs->adpctl;
+	DWC_PRINTF("ADPCTL	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   dwc_otg_adp_read_reg(core_if));
+	addr = &core_if->core_global_regs->hptxfsiz;
+	DWC_PRINTF("HPTXFSIZ	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+
+	if (core_if->en_multiple_tx_fifo == 0) {
+		ep_num = core_if->hwcfg4.b.num_dev_perio_in_ep;
+		txfsiz = "DPTXFSIZ";
+	} else {
+		ep_num = core_if->hwcfg4.b.num_in_eps;
+		txfsiz = "DIENPTXF";
+	}
+	for (i = 0; i < ep_num; i++) {
+		addr = &core_if->core_global_regs->dtxfsiz[i];
+		DWC_PRINTF("%s[%d] @0x%08lX : 0x%08X\n", txfsiz, i + 1,
+			   (unsigned long)addr, DWC_READ_REG32(addr));
+	}
+	addr = core_if->pcgcctl;
+	DWC_PRINTF("PCGCCTL	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
+		   DWC_READ_REG32(addr));
+}
+
+/**
+ * Flush a Tx FIFO.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param num Tx FIFO to flush.
+ */
+void dwc_otg_flush_tx_fifo(dwc_otg_core_if_t * core_if, const int num)
+{
+	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+	volatile grstctl_t greset = {.d32 = 0 };
+	int count = 0;
+
+	DWC_DEBUGPL((DBG_CIL | DBG_PCDV), "Flush Tx FIFO %d\n", num);
+
+	greset.b.txfflsh = 1;
+	greset.b.txfnum = num;
+	DWC_WRITE_REG32(&global_regs->grstctl, greset.d32);
+
+	do {
+		greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
+		if (++count > 10000) {
+			DWC_WARN("%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n",
+				 __func__, greset.d32,
+				 DWC_READ_REG32(&global_regs->gnptxsts));
+			break;
+		}
+		dwc_udelay(1);
+	} while (greset.b.txfflsh == 1);
+
+	/* Wait for 3 PHY Clocks */
+	dwc_udelay(1);
+}
+
+/**
+ * Flush Rx FIFO.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ */
+void dwc_otg_flush_rx_fifo(dwc_otg_core_if_t * core_if)
+{
+	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+	volatile grstctl_t greset = {.d32 = 0 };
+	int count = 0;
+
+	DWC_DEBUGPL((DBG_CIL | DBG_PCDV), "%s\n", __func__);
+	/*
+	 *
+	 */
+	greset.b.rxfflsh = 1;
+	DWC_WRITE_REG32(&global_regs->grstctl, greset.d32);
+
+	do {
+		greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
+		if (++count > 10000) {
+			DWC_WARN("%s() HANG! GRSTCTL=%0x\n", __func__,
+				 greset.d32);
+			break;
+		}
+		dwc_udelay(1);
+	} while (greset.b.rxfflsh == 1);
+
+	/* Wait for 3 PHY Clocks */
+	dwc_udelay(1);
+}
+
+/**
+ * Do core a soft reset of the core.  Be careful with this because it
+ * resets all the internal state machines of the core.
+ */
+void dwc_otg_core_reset(dwc_otg_core_if_t * core_if)
+{
+	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+	volatile grstctl_t greset = {.d32 = 0 };
+	int count = 0;
+
+	DWC_DEBUGPL(DBG_CILV, "%s\n", __func__);
+	/* Wait for AHB master IDLE state. */
+	do {
+		dwc_udelay(10);
+		greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
+		if (++count > 100000) {
+			DWC_WARN("%s() HANG! AHB Idle GRSTCTL=%0x\n", __func__,
+				 greset.d32);
+			return;
+		}
+	}
+	while (greset.b.ahbidle == 0);
+
+	/* Core Soft Reset */
+	count = 0;
+	greset.b.csftrst = 1;
+	DWC_WRITE_REG32(&global_regs->grstctl, greset.d32);
+	do {
+		greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
+		if (++count > 10000) {
+			DWC_WARN("%s() HANG! Soft Reset GRSTCTL=%0x\n",
+				 __func__, greset.d32);
+			break;
+		}
+		dwc_udelay(1);
+	}
+	while (greset.b.csftrst == 1);
+
+	/* Wait for 3 PHY Clocks */
+	dwc_mdelay(100);
+}
+
+uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t * _core_if)
+{
+	return (dwc_otg_mode(_core_if) != DWC_HOST_MODE);
+}
+
+uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t * _core_if)
+{
+	return (dwc_otg_mode(_core_if) == DWC_HOST_MODE);
+}
+
+/**
+ * Register HCD callbacks. The callbacks are used to start and stop
+ * the HCD for interrupt processing.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param cb the HCD callback structure.
+ * @param p pointer to be passed to callback function (usb_hcd*).
+ */
+void dwc_otg_cil_register_hcd_callbacks(dwc_otg_core_if_t * core_if,
+					dwc_otg_cil_callbacks_t * cb, void *p)
+{
+	core_if->hcd_cb = cb;
+	cb->p = p;
+}
+
+/**
+ * Register PCD callbacks. The callbacks are used to start and stop
+ * the PCD for interrupt processing.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param cb the PCD callback structure.
+ * @param p pointer to be passed to callback function (pcd*).
+ */
+void dwc_otg_cil_register_pcd_callbacks(dwc_otg_core_if_t * core_if,
+					dwc_otg_cil_callbacks_t * cb, void *p)
+{
+	core_if->pcd_cb = cb;
+	cb->p = p;
+}
+
+#ifdef DWC_EN_ISOC
+
+/**
+ * This function writes isoc data per 1 (micro)frame into tx fifo
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param ep The EP to start the transfer on.
+ *
+ */
+void write_isoc_frame_data(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+{
+	dwc_otg_dev_in_ep_regs_t *ep_regs;
+	dtxfsts_data_t txstatus = {.d32 = 0 };
+	uint32_t len = 0;
+	uint32_t dwords;
+
+	ep->xfer_len = ep->data_per_frame;
+	ep->xfer_count = 0;
+
+	ep_regs = core_if->dev_if->in_ep_regs[ep->num];
+
+	len = ep->xfer_len - ep->xfer_count;
+
+	if (len > ep->maxpacket) {
+		len = ep->maxpacket;
+	}
+
+	dwords = (len + 3) / 4;
+
+	/* While there is space in the queue and space in the FIFO and
+	 * More data to tranfer, Write packets to the Tx FIFO */
+	txstatus.d32 =
+	    DWC_READ_REG32(&core_if->dev_if->in_ep_regs[ep->num]->dtxfsts);
+	DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", ep->num, txstatus.d32);
+
+	while (txstatus.b.txfspcavail > dwords &&
+	       ep->xfer_count < ep->xfer_len && ep->xfer_len != 0) {
+		/* Write the FIFO */
+		dwc_otg_ep_write_packet(core_if, ep, 0);
+
+		len = ep->xfer_len - ep->xfer_count;
+		if (len > ep->maxpacket) {
+			len = ep->maxpacket;
+		}
+
+		dwords = (len + 3) / 4;
+		txstatus.d32 =
+		    DWC_READ_REG32(&core_if->dev_if->
+				   in_ep_regs[ep->num]->dtxfsts);
+		DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", ep->num,
+			    txstatus.d32);
+	}
+}
+
+/**
+ * This function initializes a descriptor chain for Isochronous transfer
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param ep The EP to start the transfer on.
+ *
+ */
+void dwc_otg_iso_ep_start_frm_transfer(dwc_otg_core_if_t * core_if,
+				       dwc_ep_t * ep)
+{
+	deptsiz_data_t deptsiz = {.d32 = 0 };
+	depctl_data_t depctl = {.d32 = 0 };
+	dsts_data_t dsts = {.d32 = 0 };
+	volatile uint32_t *addr;
+
+	if (ep->is_in) {
+		addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
+	} else {
+		addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
+	}
+
+	ep->xfer_len = ep->data_per_frame;
+	ep->xfer_count = 0;
+	ep->xfer_buff = ep->cur_pkt_addr;
+	ep->dma_addr = ep->cur_pkt_dma_addr;
+
+	if (ep->is_in) {
+		/* Program the transfer size and packet count
+		 *      as follows: xfersize = N * maxpacket +
+		 *      short_packet pktcnt = N + (short_packet
+		 *      exist ? 1 : 0)
+		 */
+		deptsiz.b.xfersize = ep->xfer_len;
+		deptsiz.b.pktcnt =
+		    (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
+		deptsiz.b.mc = deptsiz.b.pktcnt;
+		DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->dieptsiz,
+				deptsiz.d32);
+
+		/* Write the DMA register */
+		if (core_if->dma_enable) {
+			DWC_WRITE_REG32(&
+					(core_if->dev_if->in_ep_regs[ep->num]->
+					 diepdma), (uint32_t) ep->dma_addr);
+		}
+	} else {
+		deptsiz.b.pktcnt =
+		    (ep->xfer_len + (ep->maxpacket - 1)) / ep->maxpacket;
+		deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
+
+		DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->
+				doeptsiz, deptsiz.d32);
+
+		if (core_if->dma_enable) {
+			DWC_WRITE_REG32(&
+					(core_if->dev_if->out_ep_regs[ep->num]->
+					 doepdma), (uint32_t) ep->dma_addr);
+		}
+	}
+
+	/** Enable endpoint, clear nak  */
+
+	depctl.d32 = 0;
+	if (ep->bInterval == 1) {
+		dsts.d32 =
+		    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
+		ep->next_frame = dsts.b.soffn + ep->bInterval;
+
+		if (ep->next_frame & 0x1) {
+			depctl.b.setd1pid = 1;
+		} else {
+			depctl.b.setd0pid = 1;
+		}
+	} else {
+		ep->next_frame += ep->bInterval;
+
+		if (ep->next_frame & 0x1) {
+			depctl.b.setd1pid = 1;
+		} else {
+			depctl.b.setd0pid = 1;
+		}
+	}
+	depctl.b.epena = 1;
+	depctl.b.cnak = 1;
+
+	DWC_MODIFY_REG32(addr, 0, depctl.d32);
+	depctl.d32 = DWC_READ_REG32(addr);
+
+	if (ep->is_in && core_if->dma_enable == 0) {
+		write_isoc_frame_data(core_if, ep);
+	}
+
+}
+#endif /* DWC_EN_ISOC */
+
+static void dwc_otg_set_uninitialized(int32_t * p, int size)
+{
+	int i;
+	for (i = 0; i < size; i++) {
+		p[i] = -1;
+	}
+}
+
+static int dwc_otg_param_initialized(int32_t val)
+{
+	return val != -1;
+}
+
+static int dwc_otg_setup_params(dwc_otg_core_if_t * core_if)
+{
+	int i;
+	core_if->core_params = DWC_ALLOC(sizeof(*core_if->core_params));
+	if (!core_if->core_params) {
+		return -DWC_E_NO_MEMORY;
+	}
+	dwc_otg_set_uninitialized((int32_t *) core_if->core_params,
+				  sizeof(*core_if->core_params) /
+				  sizeof(int32_t));
+	DWC_PRINTF("Setting default values for core params\n");
+	dwc_otg_set_param_otg_cap(core_if, dwc_param_otg_cap_default);
+	dwc_otg_set_param_dma_enable(core_if, dwc_param_dma_enable_default);
+	dwc_otg_set_param_dma_desc_enable(core_if,
+					  dwc_param_dma_desc_enable_default);
+	dwc_otg_set_param_opt(core_if, dwc_param_opt_default);
+	dwc_otg_set_param_dma_burst_size(core_if,
+					 dwc_param_dma_burst_size_default);
+	dwc_otg_set_param_host_support_fs_ls_low_power(core_if,
+						       dwc_param_host_support_fs_ls_low_power_default);
+	dwc_otg_set_param_enable_dynamic_fifo(core_if,
+					      dwc_param_enable_dynamic_fifo_default);
+	dwc_otg_set_param_data_fifo_size(core_if,
+					 dwc_param_data_fifo_size_default);
+	dwc_otg_set_param_dev_rx_fifo_size(core_if,
+					   dwc_param_dev_rx_fifo_size_default);
+	dwc_otg_set_param_dev_nperio_tx_fifo_size(core_if,
+						  dwc_param_dev_nperio_tx_fifo_size_default);
+	dwc_otg_set_param_host_rx_fifo_size(core_if,
+					    dwc_param_host_rx_fifo_size_default);
+	dwc_otg_set_param_host_nperio_tx_fifo_size(core_if,
+						   dwc_param_host_nperio_tx_fifo_size_default);
+	dwc_otg_set_param_host_perio_tx_fifo_size(core_if,
+						  dwc_param_host_perio_tx_fifo_size_default);
+	dwc_otg_set_param_max_transfer_size(core_if,
+					    dwc_param_max_transfer_size_default);
+	dwc_otg_set_param_max_packet_count(core_if,
+					   dwc_param_max_packet_count_default);
+	dwc_otg_set_param_host_channels(core_if,
+					dwc_param_host_channels_default);
+	dwc_otg_set_param_dev_endpoints(core_if,
+					dwc_param_dev_endpoints_default);
+	dwc_otg_set_param_phy_type(core_if, dwc_param_phy_type_default);
+	dwc_otg_set_param_speed(core_if, dwc_param_speed_default);
+	dwc_otg_set_param_host_ls_low_power_phy_clk(core_if,
+						    dwc_param_host_ls_low_power_phy_clk_default);
+	dwc_otg_set_param_phy_ulpi_ddr(core_if, dwc_param_phy_ulpi_ddr_default);
+	dwc_otg_set_param_phy_ulpi_ext_vbus(core_if,
+					    dwc_param_phy_ulpi_ext_vbus_default);
+	dwc_otg_set_param_phy_utmi_width(core_if,
+					 dwc_param_phy_utmi_width_default);
+	dwc_otg_set_param_ts_dline(core_if, dwc_param_ts_dline_default);
+	dwc_otg_set_param_i2c_enable(core_if, dwc_param_i2c_enable_default);
+	dwc_otg_set_param_ulpi_fs_ls(core_if, dwc_param_ulpi_fs_ls_default);
+	dwc_otg_set_param_en_multiple_tx_fifo(core_if,
+					      dwc_param_en_multiple_tx_fifo_default);
+	for (i = 0; i < 15; i++) {
+		dwc_otg_set_param_dev_perio_tx_fifo_size(core_if,
+							 dwc_param_dev_perio_tx_fifo_size_default,
+							 i);
+	}
+
+	for (i = 0; i < 15; i++) {
+		dwc_otg_set_param_dev_tx_fifo_size(core_if,
+						   dwc_param_dev_tx_fifo_size_default,
+						   i);
+	}
+	dwc_otg_set_param_thr_ctl(core_if, dwc_param_thr_ctl_default);
+	dwc_otg_set_param_mpi_enable(core_if, dwc_param_mpi_enable_default);
+	dwc_otg_set_param_pti_enable(core_if, dwc_param_pti_enable_default);
+	dwc_otg_set_param_lpm_enable(core_if, dwc_param_lpm_enable_default);
+	dwc_otg_set_param_ic_usb_cap(core_if, dwc_param_ic_usb_cap_default);
+	dwc_otg_set_param_tx_thr_length(core_if,
+					dwc_param_tx_thr_length_default);
+	dwc_otg_set_param_rx_thr_length(core_if,
+					dwc_param_rx_thr_length_default);
+	dwc_otg_set_param_ahb_thr_ratio(core_if,
+					dwc_param_ahb_thr_ratio_default);
+	dwc_otg_set_param_power_down(core_if, dwc_param_power_down_default);
+	dwc_otg_set_param_reload_ctl(core_if, dwc_param_reload_ctl_default);
+	dwc_otg_set_param_dev_out_nak(core_if, dwc_param_dev_out_nak_default);
+	dwc_otg_set_param_cont_on_bna(core_if, dwc_param_cont_on_bna_default);
+	dwc_otg_set_param_ahb_single(core_if, dwc_param_ahb_single_default);
+	dwc_otg_set_param_otg_ver(core_if, dwc_param_otg_ver_default);
+	dwc_otg_set_param_adp_enable(core_if, dwc_param_adp_enable_default);
+	return 0;
+}
+
+uint8_t dwc_otg_is_dma_enable(dwc_otg_core_if_t * core_if)
+{
+	return core_if->dma_enable;
+}
+
+/* Checks if the parameter is outside of its valid range of values */
+#define DWC_OTG_PARAM_TEST(_param_, _low_, _high_) \
+		(((_param_) < (_low_)) || \
+		((_param_) > (_high_)))
+
+/* Parameter access functions */
+int dwc_otg_set_param_otg_cap(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	int valid;
+	int retval = 0;
+	if (DWC_OTG_PARAM_TEST(val, 0, 2)) {
+		DWC_WARN("Wrong value for otg_cap parameter\n");
+		DWC_WARN("otg_cap parameter must be 0,1 or 2\n");
+		retval = -DWC_E_INVALID;
+		goto out;
+	}
+
+	valid = 1;
+	switch (val) {
+	case DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE:
+		if (core_if->hwcfg2.b.op_mode !=
+		    DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
+			valid = 0;
+		break;
+	case DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE:
+		if ((core_if->hwcfg2.b.op_mode !=
+		     DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
+		    && (core_if->hwcfg2.b.op_mode !=
+			DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
+		    && (core_if->hwcfg2.b.op_mode !=
+			DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE)
+		    && (core_if->hwcfg2.b.op_mode !=
+			DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) {
+			valid = 0;
+		}
+		break;
+	case DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE:
+		/* always valid */
+		break;
+	}
+	if (!valid) {
+		if (dwc_otg_param_initialized(core_if->core_params->otg_cap)) {
+			DWC_ERROR
+			    ("%d invalid for otg_cap paremter. Check HW configuration.\n",
+			     val);
+		}
+		val =
+		    (((core_if->hwcfg2.b.op_mode ==
+		       DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
+		      || (core_if->hwcfg2.b.op_mode ==
+			  DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
+		      || (core_if->hwcfg2.b.op_mode ==
+			  DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE)
+		      || (core_if->hwcfg2.b.op_mode ==
+			  DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) ?
+		     DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE :
+		     DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
+		retval = -DWC_E_INVALID;
+	}
+
+	core_if->core_params->otg_cap = val;
+out:
+	return retval;
+}
+
+int32_t dwc_otg_get_param_otg_cap(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->otg_cap;
+}
+
+int dwc_otg_set_param_opt(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+		DWC_WARN("Wrong value for opt parameter\n");
+		return -DWC_E_INVALID;
+	}
+	core_if->core_params->opt = val;
+	return 0;
+}
+
+int32_t dwc_otg_get_param_opt(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->opt;
+}
+
+int dwc_otg_set_param_dma_enable(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	int retval = 0;
+	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+		DWC_WARN("Wrong value for dma enable\n");
+		return -DWC_E_INVALID;
+	}
+
+	if ((val == 1) && (core_if->hwcfg2.b.architecture == 0)) {
+		if (dwc_otg_param_initialized(core_if->core_params->dma_enable)) {
+			DWC_ERROR
+			    ("%d invalid for dma_enable paremter. Check HW configuration.\n",
+			     val);
+		}
+		val = 0;
+		retval = -DWC_E_INVALID;
+	}
+
+	core_if->core_params->dma_enable = val;
+	if (val == 0) {
+		dwc_otg_set_param_dma_desc_enable(core_if, 0);
+	}
+	return retval;
+}
+
+int32_t dwc_otg_get_param_dma_enable(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->dma_enable;
+}
+
+int dwc_otg_set_param_dma_desc_enable(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	int retval = 0;
+	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+		DWC_WARN("Wrong value for dma_enable\n");
+		DWC_WARN("dma_desc_enable must be 0 or 1\n");
+		return -DWC_E_INVALID;
+	}
+
+	if ((val == 1)
+	    && ((dwc_otg_get_param_dma_enable(core_if) == 0)
+		|| (core_if->hwcfg4.b.desc_dma == 0))) {
+		if (dwc_otg_param_initialized
+		    (core_if->core_params->dma_desc_enable)) {
+			DWC_ERROR
+			    ("%d invalid for dma_desc_enable paremter. Check HW configuration.\n",
+			     val);
+		}
+		val = 0;
+		retval = -DWC_E_INVALID;
+	}
+	core_if->core_params->dma_desc_enable = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_dma_desc_enable(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->dma_desc_enable;
+}
+
+int dwc_otg_set_param_host_support_fs_ls_low_power(dwc_otg_core_if_t * core_if,
+						   int32_t val)
+{
+	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+		DWC_WARN("Wrong value for host_support_fs_low_power\n");
+		DWC_WARN("host_support_fs_low_power must be 0 or 1\n");
+		return -DWC_E_INVALID;
+	}
+	core_if->core_params->host_support_fs_ls_low_power = val;
+	return 0;
+}
+
+int32_t dwc_otg_get_param_host_support_fs_ls_low_power(dwc_otg_core_if_t *
+						       core_if)
+{
+	return core_if->core_params->host_support_fs_ls_low_power;
+}
+
+int dwc_otg_set_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if,
+					  int32_t val)
+{
+	int retval = 0;
+	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+		DWC_WARN("Wrong value for enable_dynamic_fifo\n");
+		DWC_WARN("enable_dynamic_fifo must be 0 or 1\n");
+		return -DWC_E_INVALID;
+	}
+
+	if ((val == 1) && (core_if->hwcfg2.b.dynamic_fifo == 0)) {
+		if (dwc_otg_param_initialized
+		    (core_if->core_params->enable_dynamic_fifo)) {
+			DWC_ERROR
+			    ("%d invalid for enable_dynamic_fifo paremter. Check HW configuration.\n",
+			     val);
+		}
+		val = 0;
+		retval = -DWC_E_INVALID;
+	}
+	core_if->core_params->enable_dynamic_fifo = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->enable_dynamic_fifo;
+}
+
+int dwc_otg_set_param_data_fifo_size(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	int retval = 0;
+	if (DWC_OTG_PARAM_TEST(val, 32, 32768)) {
+		DWC_WARN("Wrong value for data_fifo_size\n");
+		DWC_WARN("data_fifo_size must be 32-32768\n");
+		return -DWC_E_INVALID;
+	}
+
+	if (val > core_if->hwcfg3.b.dfifo_depth) {
+		if (dwc_otg_param_initialized
+		    (core_if->core_params->data_fifo_size)) {
+			DWC_ERROR
+			    ("%d invalid for data_fifo_size parameter. Check HW configuration.\n",
+			     val);
+		}
+		val = core_if->hwcfg3.b.dfifo_depth;
+		retval = -DWC_E_INVALID;
+	}
+
+	core_if->core_params->data_fifo_size = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_data_fifo_size(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->data_fifo_size;
+}
+
+int dwc_otg_set_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	int retval = 0;
+	if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
+		DWC_WARN("Wrong value for dev_rx_fifo_size\n");
+		DWC_WARN("dev_rx_fifo_size must be 16-32768\n");
+		return -DWC_E_INVALID;
+	}
+
+	if (val > DWC_READ_REG32(&core_if->core_global_regs->grxfsiz)) {
+		if (dwc_otg_param_initialized(core_if->core_params->dev_rx_fifo_size)) {
+		DWC_WARN("%d invalid for dev_rx_fifo_size parameter\n", val);
+		}
+		val = DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
+		retval = -DWC_E_INVALID;
+	}
+
+	core_if->core_params->dev_rx_fifo_size = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->dev_rx_fifo_size;
+}
+
+int dwc_otg_set_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if,
+					      int32_t val)
+{
+	int retval = 0;
+
+	if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
+		DWC_WARN("Wrong value for dev_nperio_tx_fifo\n");
+		DWC_WARN("dev_nperio_tx_fifo must be 16-32768\n");
+		return -DWC_E_INVALID;
+	}
+
+	if (val > (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >> 16)) {
+		if (dwc_otg_param_initialized
+		    (core_if->core_params->dev_nperio_tx_fifo_size)) {
+			DWC_ERROR
+			    ("%d invalid for dev_nperio_tx_fifo_size. Check HW configuration.\n",
+			     val);
+		}
+		val =
+		    (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >>
+		     16);
+		retval = -DWC_E_INVALID;
+	}
+
+	core_if->core_params->dev_nperio_tx_fifo_size = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->dev_nperio_tx_fifo_size;
+}
+
+int dwc_otg_set_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if,
+					int32_t val)
+{
+	int retval = 0;
+
+	if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
+		DWC_WARN("Wrong value for host_rx_fifo_size\n");
+		DWC_WARN("host_rx_fifo_size must be 16-32768\n");
+		return -DWC_E_INVALID;
+	}
+
+	if (val > DWC_READ_REG32(&core_if->core_global_regs->grxfsiz)) {
+		if (dwc_otg_param_initialized
+		    (core_if->core_params->host_rx_fifo_size)) {
+			DWC_ERROR
+			    ("%d invalid for host_rx_fifo_size. Check HW configuration.\n",
+			     val);
+		}
+		val = DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
+		retval = -DWC_E_INVALID;
+	}
+
+	core_if->core_params->host_rx_fifo_size = val;
+	return retval;
+
+}
+
+int32_t dwc_otg_get_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->host_rx_fifo_size;
+}
+
+int dwc_otg_set_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if,
+					       int32_t val)
+{
+	int retval = 0;
+
+	if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
+		DWC_WARN("Wrong value for host_nperio_tx_fifo_size\n");
+		DWC_WARN("host_nperio_tx_fifo_size must be 16-32768\n");
+		return -DWC_E_INVALID;
+	}
+
+	if (val > (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >> 16)) {
+		if (dwc_otg_param_initialized
+		    (core_if->core_params->host_nperio_tx_fifo_size)) {
+			DWC_ERROR
+			    ("%d invalid for host_nperio_tx_fifo_size. Check HW configuration.\n",
+			     val);
+		}
+		val =
+		    (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >>
+		     16);
+		retval = -DWC_E_INVALID;
+	}
+
+	core_if->core_params->host_nperio_tx_fifo_size = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->host_nperio_tx_fifo_size;
+}
+
+int dwc_otg_set_param_host_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
+					      int32_t val)
+{
+	int retval = 0;
+	if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
+		DWC_WARN("Wrong value for host_perio_tx_fifo_size\n");
+		DWC_WARN("host_perio_tx_fifo_size must be 16-32768\n");
+		return -DWC_E_INVALID;
+	}
+
+	if (val >
+		((core_if->hptxfsiz.d32)>> 16)) {
+		if (dwc_otg_param_initialized
+		    (core_if->core_params->host_perio_tx_fifo_size)) {
+			DWC_ERROR
+			    ("%d invalid for host_perio_tx_fifo_size. Check HW configuration.\n",
+			     val);
+		}
+		val = (core_if->hptxfsiz.d32) >> 16;
+		retval = -DWC_E_INVALID;
+	}
+
+	core_if->core_params->host_perio_tx_fifo_size = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_host_perio_tx_fifo_size(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->host_perio_tx_fifo_size;
+}
+
+int dwc_otg_set_param_max_transfer_size(dwc_otg_core_if_t * core_if,
+					int32_t val)
+{
+	int retval = 0;
+
+	if (DWC_OTG_PARAM_TEST(val, 2047, 524288)) {
+		DWC_WARN("Wrong value for max_transfer_size\n");
+		DWC_WARN("max_transfer_size must be 2047-524288\n");
+		return -DWC_E_INVALID;
+	}
+
+	if (val >= (1 << (core_if->hwcfg3.b.xfer_size_cntr_width + 11))) {
+		if (dwc_otg_param_initialized
+		    (core_if->core_params->max_transfer_size)) {
+			DWC_ERROR
+			    ("%d invalid for max_transfer_size. Check HW configuration.\n",
+			     val);
+		}
+		val =
+		    ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 11)) -
+		     1);
+		retval = -DWC_E_INVALID;
+	}
+
+	core_if->core_params->max_transfer_size = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_max_transfer_size(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->max_transfer_size;
+}
+
+int dwc_otg_set_param_max_packet_count(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	int retval = 0;
+
+	if (DWC_OTG_PARAM_TEST(val, 15, 511)) {
+		DWC_WARN("Wrong value for max_packet_count\n");
+		DWC_WARN("max_packet_count must be 15-511\n");
+		return -DWC_E_INVALID;
+	}
+
+	if (val > (1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4))) {
+		if (dwc_otg_param_initialized
+		    (core_if->core_params->max_packet_count)) {
+			DWC_ERROR
+			    ("%d invalid for max_packet_count. Check HW configuration.\n",
+			     val);
+		}
+		val =
+		    ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1);
+		retval = -DWC_E_INVALID;
+	}
+
+	core_if->core_params->max_packet_count = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_max_packet_count(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->max_packet_count;
+}
+
+int dwc_otg_set_param_host_channels(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	int retval = 0;
+
+	if (DWC_OTG_PARAM_TEST(val, 1, 16)) {
+		DWC_WARN("Wrong value for host_channels\n");
+		DWC_WARN("host_channels must be 1-16\n");
+		return -DWC_E_INVALID;
+	}
+
+	if (val > (core_if->hwcfg2.b.num_host_chan + 1)) {
+		if (dwc_otg_param_initialized
+		    (core_if->core_params->host_channels)) {
+			DWC_ERROR
+			    ("%d invalid for host_channels. Check HW configurations.\n",
+			     val);
+		}
+		val = (core_if->hwcfg2.b.num_host_chan + 1);
+		retval = -DWC_E_INVALID;
+	}
+
+	core_if->core_params->host_channels = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_host_channels(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->host_channels;
+}
+
+int dwc_otg_set_param_dev_endpoints(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	int retval = 0;
+
+	if (DWC_OTG_PARAM_TEST(val, 1, 15)) {
+		DWC_WARN("Wrong value for dev_endpoints\n");
+		DWC_WARN("dev_endpoints must be 1-15\n");
+		return -DWC_E_INVALID;
+	}
+
+	if (val > (core_if->hwcfg2.b.num_dev_ep)) {
+		if (dwc_otg_param_initialized
+		    (core_if->core_params->dev_endpoints)) {
+			DWC_ERROR
+			    ("%d invalid for dev_endpoints. Check HW configurations.\n",
+			     val);
+		}
+		val = core_if->hwcfg2.b.num_dev_ep;
+		retval = -DWC_E_INVALID;
+	}
+
+	core_if->core_params->dev_endpoints = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_dev_endpoints(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->dev_endpoints;
+}
+
+int dwc_otg_set_param_phy_type(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	int retval = 0;
+	int valid = 0;
+
+	if (DWC_OTG_PARAM_TEST(val, 0, 2)) {
+		DWC_WARN("Wrong value for phy_type\n");
+		DWC_WARN("phy_type must be 0,1 or 2\n");
+		return -DWC_E_INVALID;
+	}
+#ifndef NO_FS_PHY_HW_CHECKS
+	if ((val == DWC_PHY_TYPE_PARAM_UTMI) &&
+	    ((core_if->hwcfg2.b.hs_phy_type == 1) ||
+	     (core_if->hwcfg2.b.hs_phy_type == 3))) {
+		valid = 1;
+	} else if ((val == DWC_PHY_TYPE_PARAM_ULPI) &&
+		   ((core_if->hwcfg2.b.hs_phy_type == 2) ||
+		    (core_if->hwcfg2.b.hs_phy_type == 3))) {
+		valid = 1;
+	} else if ((val == DWC_PHY_TYPE_PARAM_FS) &&
+		   (core_if->hwcfg2.b.fs_phy_type == 1)) {
+		valid = 1;
+	}
+	if (!valid) {
+		if (dwc_otg_param_initialized(core_if->core_params->phy_type)) {
+			DWC_ERROR
+			    ("%d invalid for phy_type. Check HW configurations.\n",
+			     val);
+		}
+		if (core_if->hwcfg2.b.hs_phy_type) {
+			if ((core_if->hwcfg2.b.hs_phy_type == 3) ||
+			    (core_if->hwcfg2.b.hs_phy_type == 1)) {
+				val = DWC_PHY_TYPE_PARAM_UTMI;
+			} else {
+				val = DWC_PHY_TYPE_PARAM_ULPI;
+			}
+		}
+		retval = -DWC_E_INVALID;
+	}
+#endif
+	core_if->core_params->phy_type = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_phy_type(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->phy_type;
+}
+
+int dwc_otg_set_param_speed(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	int retval = 0;
+	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+		DWC_WARN("Wrong value for speed parameter\n");
+		DWC_WARN("max_speed parameter must be 0 or 1\n");
+		return -DWC_E_INVALID;
+	}
+	if ((val == 0)
+	    && dwc_otg_get_param_phy_type(core_if) == DWC_PHY_TYPE_PARAM_FS) {
+		if (dwc_otg_param_initialized(core_if->core_params->speed)) {
+			DWC_ERROR
+			    ("%d invalid for speed paremter. Check HW configuration.\n",
+			     val);
+		}
+		val =
+		    (dwc_otg_get_param_phy_type(core_if) ==
+		     DWC_PHY_TYPE_PARAM_FS ? 1 : 0);
+		retval = -DWC_E_INVALID;
+	}
+	core_if->core_params->speed = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_speed(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->speed;
+}
+
+int dwc_otg_set_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t * core_if,
+						int32_t val)
+{
+	int retval = 0;
+
+	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+		DWC_WARN
+		    ("Wrong value for host_ls_low_power_phy_clk parameter\n");
+		DWC_WARN("host_ls_low_power_phy_clk must be 0 or 1\n");
+		return -DWC_E_INVALID;
+	}
+
+	if ((val == DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ)
+	    && (dwc_otg_get_param_phy_type(core_if) == DWC_PHY_TYPE_PARAM_FS)) {
+		if (dwc_otg_param_initialized
+		    (core_if->core_params->host_ls_low_power_phy_clk)) {
+			DWC_ERROR
+			    ("%d invalid for host_ls_low_power_phy_clk. Check HW configuration.\n",
+			     val);
+		}
+		val =
+		    (dwc_otg_get_param_phy_type(core_if) ==
+		     DWC_PHY_TYPE_PARAM_FS) ?
+		    DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ :
+		    DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ;
+		retval = -DWC_E_INVALID;
+	}
+
+	core_if->core_params->host_ls_low_power_phy_clk = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->host_ls_low_power_phy_clk;
+}
+
+int dwc_otg_set_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+		DWC_WARN("Wrong value for phy_ulpi_ddr\n");
+		DWC_WARN("phy_upli_ddr must be 0 or 1\n");
+		return -DWC_E_INVALID;
+	}
+
+	core_if->core_params->phy_ulpi_ddr = val;
+	return 0;
+}
+
+int32_t dwc_otg_get_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->phy_ulpi_ddr;
+}
+
+int dwc_otg_set_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if,
+					int32_t val)
+{
+	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+		DWC_WARN("Wrong valaue for phy_ulpi_ext_vbus\n");
+		DWC_WARN("phy_ulpi_ext_vbus must be 0 or 1\n");
+		return -DWC_E_INVALID;
+	}
+
+	core_if->core_params->phy_ulpi_ext_vbus = val;
+	return 0;
+}
+
+int32_t dwc_otg_get_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->phy_ulpi_ext_vbus;
+}
+
+int dwc_otg_set_param_phy_utmi_width(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	if (DWC_OTG_PARAM_TEST(val, 8, 8) && DWC_OTG_PARAM_TEST(val, 16, 16)) {
+		DWC_WARN("Wrong valaue for phy_utmi_width\n");
+		DWC_WARN("phy_utmi_width must be 8 or 16\n");
+		return -DWC_E_INVALID;
+	}
+
+	core_if->core_params->phy_utmi_width = val;
+	return 0;
+}
+
+int32_t dwc_otg_get_param_phy_utmi_width(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->phy_utmi_width;
+}
+
+int dwc_otg_set_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+		DWC_WARN("Wrong valaue for ulpi_fs_ls\n");
+		DWC_WARN("ulpi_fs_ls must be 0 or 1\n");
+		return -DWC_E_INVALID;
+	}
+
+	core_if->core_params->ulpi_fs_ls = val;
+	return 0;
+}
+
+int32_t dwc_otg_get_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->ulpi_fs_ls;
+}
+
+int dwc_otg_set_param_ts_dline(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+		DWC_WARN("Wrong valaue for ts_dline\n");
+		DWC_WARN("ts_dline must be 0 or 1\n");
+		return -DWC_E_INVALID;
+	}
+
+	core_if->core_params->ts_dline = val;
+	return 0;
+}
+
+int32_t dwc_otg_get_param_ts_dline(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->ts_dline;
+}
+
+int dwc_otg_set_param_i2c_enable(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	int retval = 0;
+	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+		DWC_WARN("Wrong valaue for i2c_enable\n");
+		DWC_WARN("i2c_enable must be 0 or 1\n");
+		return -DWC_E_INVALID;
+	}
+#ifndef NO_FS_PHY_HW_CHECK
+	if (val == 1 && core_if->hwcfg3.b.i2c == 0) {
+		if (dwc_otg_param_initialized(core_if->core_params->i2c_enable)) {
+			DWC_ERROR
+			    ("%d invalid for i2c_enable. Check HW configuration.\n",
+			     val);
+		}
+		val = 0;
+		retval = -DWC_E_INVALID;
+	}
+#endif
+
+	core_if->core_params->i2c_enable = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_i2c_enable(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->i2c_enable;
+}
+
+int dwc_otg_set_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
+					     int32_t val, int fifo_num)
+{
+	int retval = 0;
+
+	if (DWC_OTG_PARAM_TEST(val, 4, 768)) {
+		DWC_WARN("Wrong value for dev_perio_tx_fifo_size\n");
+		DWC_WARN("dev_perio_tx_fifo_size must be 4-768\n");
+		return -DWC_E_INVALID;
+	}
+
+	if (val >
+	    (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]))) {
+		if (dwc_otg_param_initialized
+		    (core_if->core_params->dev_perio_tx_fifo_size[fifo_num])) {
+			DWC_ERROR
+			    ("`%d' invalid for parameter `dev_perio_fifo_size_%d'. Check HW configuration.\n",
+			     val, fifo_num);
+		}
+		val = (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]));
+		retval = -DWC_E_INVALID;
+	}
+
+	core_if->core_params->dev_perio_tx_fifo_size[fifo_num] = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
+						 int fifo_num)
+{
+	return core_if->core_params->dev_perio_tx_fifo_size[fifo_num];
+}
+
+int dwc_otg_set_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if,
+					  int32_t val)
+{
+	int retval = 0;
+	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+		DWC_WARN("Wrong valaue for en_multiple_tx_fifo,\n");
+		DWC_WARN("en_multiple_tx_fifo must be 0 or 1\n");
+		return -DWC_E_INVALID;
+	}
+
+	if (val == 1 && core_if->hwcfg4.b.ded_fifo_en == 0) {
+		if (dwc_otg_param_initialized
+		    (core_if->core_params->en_multiple_tx_fifo)) {
+			DWC_ERROR
+			    ("%d invalid for parameter en_multiple_tx_fifo. Check HW configuration.\n",
+			     val);
+		}
+		val = 0;
+		retval = -DWC_E_INVALID;
+	}
+
+	core_if->core_params->en_multiple_tx_fifo = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->en_multiple_tx_fifo;
+}
+
+int dwc_otg_set_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if, int32_t val,
+				       int fifo_num)
+{
+	int retval = 0;
+
+	if (DWC_OTG_PARAM_TEST(val, 4, 768)) {
+		DWC_WARN("Wrong value for dev_tx_fifo_size\n");
+		DWC_WARN("dev_tx_fifo_size must be 4-768\n");
+		return -DWC_E_INVALID;
+	}
+
+	if (val >
+	    (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]))) {
+		if (dwc_otg_param_initialized
+		    (core_if->core_params->dev_tx_fifo_size[fifo_num])) {
+			DWC_ERROR
+			    ("`%d' invalid for parameter `dev_tx_fifo_size_%d'. Check HW configuration.\n",
+			     val, fifo_num);
+		}
+		val = (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]));
+		retval = -DWC_E_INVALID;
+	}
+
+	core_if->core_params->dev_tx_fifo_size[fifo_num] = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
+					   int fifo_num)
+{
+	return core_if->core_params->dev_tx_fifo_size[fifo_num];
+}
+
+int dwc_otg_set_param_thr_ctl(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	int retval = 0;
+
+	if (DWC_OTG_PARAM_TEST(val, 0, 7)) {
+		DWC_WARN("Wrong value for thr_ctl\n");
+		DWC_WARN("thr_ctl must be 0-7\n");
+		return -DWC_E_INVALID;
+	}
+
+	if ((val != 0) &&
+	    (!dwc_otg_get_param_dma_enable(core_if) ||
+	     !core_if->hwcfg4.b.ded_fifo_en)) {
+		if (dwc_otg_param_initialized(core_if->core_params->thr_ctl)) {
+			DWC_ERROR
+			    ("%d invalid for parameter thr_ctl. Check HW configuration.\n",
+			     val);
+		}
+		val = 0;
+		retval = -DWC_E_INVALID;
+	}
+
+	core_if->core_params->thr_ctl = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_thr_ctl(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->thr_ctl;
+}
+
+int dwc_otg_set_param_lpm_enable(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	int retval = 0;
+
+	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+		DWC_WARN("Wrong value for lpm_enable\n");
+		DWC_WARN("lpm_enable must be 0 or 1\n");
+		return -DWC_E_INVALID;
+	}
+
+	if (val && !core_if->hwcfg3.b.otg_lpm_en) {
+		if (dwc_otg_param_initialized(core_if->core_params->lpm_enable)) {
+			DWC_ERROR
+			    ("%d invalid for parameter lpm_enable. Check HW configuration.\n",
+			     val);
+		}
+		val = 0;
+		retval = -DWC_E_INVALID;
+	}
+
+	core_if->core_params->lpm_enable = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_lpm_enable(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->lpm_enable;
+}
+
+int dwc_otg_set_param_tx_thr_length(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	if (DWC_OTG_PARAM_TEST(val, 8, 128)) {
+		DWC_WARN("Wrong valaue for tx_thr_length\n");
+		DWC_WARN("tx_thr_length must be 8 - 128\n");
+		return -DWC_E_INVALID;
+	}
+
+	core_if->core_params->tx_thr_length = val;
+	return 0;
+}
+
+int32_t dwc_otg_get_param_tx_thr_length(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->tx_thr_length;
+}
+
+int dwc_otg_set_param_rx_thr_length(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	if (DWC_OTG_PARAM_TEST(val, 8, 128)) {
+		DWC_WARN("Wrong valaue for rx_thr_length\n");
+		DWC_WARN("rx_thr_length must be 8 - 128\n");
+		return -DWC_E_INVALID;
+	}
+
+	core_if->core_params->rx_thr_length = val;
+	return 0;
+}
+
+int32_t dwc_otg_get_param_rx_thr_length(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->rx_thr_length;
+}
+
+int dwc_otg_set_param_dma_burst_size(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	if (DWC_OTG_PARAM_TEST(val, 1, 1) &&
+	    DWC_OTG_PARAM_TEST(val, 4, 4) &&
+	    DWC_OTG_PARAM_TEST(val, 8, 8) &&
+	    DWC_OTG_PARAM_TEST(val, 16, 16) &&
+	    DWC_OTG_PARAM_TEST(val, 32, 32) &&
+	    DWC_OTG_PARAM_TEST(val, 64, 64) &&
+	    DWC_OTG_PARAM_TEST(val, 128, 128) &&
+	    DWC_OTG_PARAM_TEST(val, 256, 256)) {
+		DWC_WARN("`%d' invalid for parameter `dma_burst_size'\n", val);
+		return -DWC_E_INVALID;
+	}
+	core_if->core_params->dma_burst_size = val;
+	return 0;
+}
+
+int32_t dwc_otg_get_param_dma_burst_size(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->dma_burst_size;
+}
+
+int dwc_otg_set_param_pti_enable(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	int retval = 0;
+	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+		DWC_WARN("`%d' invalid for parameter `pti_enable'\n", val);
+		return -DWC_E_INVALID;
+	}
+	if (val && (core_if->snpsid < OTG_CORE_REV_2_72a)) {
+		if (dwc_otg_param_initialized(core_if->core_params->pti_enable)) {
+			DWC_ERROR
+			    ("%d invalid for parameter pti_enable. Check HW configuration.\n",
+			     val);
+		}
+		retval = -DWC_E_INVALID;
+		val = 0;
+	}
+	core_if->core_params->pti_enable = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_pti_enable(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->pti_enable;
+}
+
+int dwc_otg_set_param_mpi_enable(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	int retval = 0;
+	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+		DWC_WARN("`%d' invalid for parameter `mpi_enable'\n", val);
+		return -DWC_E_INVALID;
+	}
+	if (val && (core_if->hwcfg2.b.multi_proc_int == 0)) {
+		if (dwc_otg_param_initialized(core_if->core_params->mpi_enable)) {
+			DWC_ERROR
+			    ("%d invalid for parameter mpi_enable. Check HW configuration.\n",
+			     val);
+		}
+		retval = -DWC_E_INVALID;
+		val = 0;
+	}
+	core_if->core_params->mpi_enable = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_mpi_enable(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->mpi_enable;
+}
+
+int dwc_otg_set_param_adp_enable(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	int retval = 0;
+	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+		DWC_WARN("`%d' invalid for parameter `adp_enable'\n", val);
+		return -DWC_E_INVALID;
+	}
+	if (val && (core_if->hwcfg3.b.adp_supp == 0)) {
+		if (dwc_otg_param_initialized
+		    (core_if->core_params->adp_supp_enable)) {
+			DWC_ERROR
+			    ("%d invalid for parameter adp_enable. Check HW configuration.\n",
+			     val);
+		}
+		retval = -DWC_E_INVALID;
+		val = 0;
+	}
+	core_if->core_params->adp_supp_enable = val;
+	/*Set OTG version 2.0 in case of enabling ADP*/
+	if (val)
+		dwc_otg_set_param_otg_ver(core_if, 1);
+
+	return retval;
+}
+
+int32_t dwc_otg_get_param_adp_enable(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->adp_supp_enable;
+}
+
+int dwc_otg_set_param_ic_usb_cap(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	int retval = 0;
+	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+		DWC_WARN("`%d' invalid for parameter `ic_usb_cap'\n", val);
+		DWC_WARN("ic_usb_cap must be 0 or 1\n");
+		return -DWC_E_INVALID;
+	}
+
+	if (val && (core_if->hwcfg2.b.otg_enable_ic_usb == 0)) {
+		if (dwc_otg_param_initialized(core_if->core_params->ic_usb_cap)) {
+			DWC_ERROR
+			    ("%d invalid for parameter ic_usb_cap. Check HW configuration.\n",
+			     val);
+		}
+		retval = -DWC_E_INVALID;
+		val = 0;
+	}
+	core_if->core_params->ic_usb_cap = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_ic_usb_cap(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->ic_usb_cap;
+}
+
+int dwc_otg_set_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	int retval = 0;
+	int valid = 1;
+
+	if (DWC_OTG_PARAM_TEST(val, 0, 3)) {
+		DWC_WARN("`%d' invalid for parameter `ahb_thr_ratio'\n", val);
+		DWC_WARN("ahb_thr_ratio must be 0 - 3\n");
+		return -DWC_E_INVALID;
+	}
+
+	if (val
+	    && (core_if->snpsid < OTG_CORE_REV_2_81a
+		|| !dwc_otg_get_param_thr_ctl(core_if))) {
+		valid = 0;
+	} else if (val
+		   && ((dwc_otg_get_param_tx_thr_length(core_if) / (1 << val)) <
+		       4)) {
+		valid = 0;
+	}
+	if (valid == 0) {
+		if (dwc_otg_param_initialized
+		    (core_if->core_params->ahb_thr_ratio)) {
+			DWC_ERROR
+			    ("%d invalid for parameter ahb_thr_ratio. Check HW configuration.\n",
+			     val);
+		}
+		retval = -DWC_E_INVALID;
+		val = 0;
+	}
+
+	core_if->core_params->ahb_thr_ratio = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->ahb_thr_ratio;
+}
+
+int dwc_otg_set_param_power_down(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	int retval = 0;
+	int valid = 1;
+
+	if (DWC_OTG_PARAM_TEST(val, 0, 2)) {
+		DWC_WARN("`%d' invalid for parameter `power_down'\n", val);
+		DWC_WARN("power_down must be 0 - 2\n");
+		return -DWC_E_INVALID;
+	}
+
+	if ((val == 2) && (core_if->snpsid < OTG_CORE_REV_2_91a)) {
+		valid = 0;
+	}
+	if (valid == 0) {
+		if (dwc_otg_param_initialized(core_if->core_params->power_down)) {
+			DWC_ERROR
+			    ("%d invalid for parameter power_down. Check HW configuration.\n",
+			     val);
+		}
+		retval = -DWC_E_INVALID;
+		val = 0;
+	}
+	core_if->core_params->power_down = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_power_down(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->power_down;
+}
+
+int dwc_otg_set_param_reload_ctl(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	int retval = 0;
+	int valid = 1;
+
+	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+		DWC_WARN("`%d' invalid for parameter `reload_ctl'\n", val);
+		DWC_WARN("reload_ctl must be 0 or 1\n");
+		return -DWC_E_INVALID;
+	}
+
+	if ((val == 1) && (core_if->snpsid < OTG_CORE_REV_2_92a)) {
+		valid = 0;
+	}
+	if (valid == 0) {
+		if (dwc_otg_param_initialized(core_if->core_params->reload_ctl)) {
+			DWC_ERROR("%d invalid for parameter reload_ctl."
+				  "Check HW configuration.\n", val);
+		}
+		retval = -DWC_E_INVALID;
+		val = 0;
+	}
+	core_if->core_params->reload_ctl = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_reload_ctl(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->reload_ctl;
+}
+
+int dwc_otg_set_param_dev_out_nak(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	int retval = 0;
+	int valid = 1;
+
+	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+		DWC_WARN("`%d' invalid for parameter `dev_out_nak'\n", val);
+		DWC_WARN("dev_out_nak must be 0 or 1\n");
+		return -DWC_E_INVALID;
+	}
+
+	if ((val == 1) && ((core_if->snpsid < OTG_CORE_REV_2_93a) ||
+		!(core_if->core_params->dma_desc_enable))) {
+		valid = 0;
+	}
+	if (valid == 0) {
+		if (dwc_otg_param_initialized(core_if->core_params->dev_out_nak)) {
+			DWC_ERROR("%d invalid for parameter dev_out_nak."
+				"Check HW configuration.\n", val);
+		}
+		retval = -DWC_E_INVALID;
+		val = 0;
+	}
+	core_if->core_params->dev_out_nak = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_dev_out_nak(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->dev_out_nak;
+}
+
+int dwc_otg_set_param_cont_on_bna(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	int retval = 0;
+	int valid = 1;
+
+	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+		DWC_WARN("`%d' invalid for parameter `cont_on_bna'\n", val);
+		DWC_WARN("cont_on_bna must be 0 or 1\n");
+		return -DWC_E_INVALID;
+	}
+
+	if ((val == 1) && ((core_if->snpsid < OTG_CORE_REV_2_94a) ||
+		!(core_if->core_params->dma_desc_enable))) {
+			valid = 0;
+	}
+	if (valid == 0) {
+		if (dwc_otg_param_initialized(core_if->core_params->cont_on_bna)) {
+			DWC_ERROR("%d invalid for parameter cont_on_bna."
+				"Check HW configuration.\n", val);
+		}
+		retval = -DWC_E_INVALID;
+		val = 0;
+	}
+	core_if->core_params->cont_on_bna = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_cont_on_bna(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->cont_on_bna;
+}
+
+int dwc_otg_set_param_ahb_single(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	int retval = 0;
+	int valid = 1;
+
+	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+		DWC_WARN("`%d' invalid for parameter `ahb_single'\n", val);
+		DWC_WARN("ahb_single must be 0 or 1\n");
+		return -DWC_E_INVALID;
+	}
+
+	if ((val == 1) && (core_if->snpsid < OTG_CORE_REV_2_94a)) {
+			valid = 0;
+	}
+	if (valid == 0) {
+		if (dwc_otg_param_initialized(core_if->core_params->ahb_single)) {
+			DWC_ERROR("%d invalid for parameter ahb_single."
+				"Check HW configuration.\n", val);
+		}
+		retval = -DWC_E_INVALID;
+		val = 0;
+	}
+	core_if->core_params->ahb_single = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_ahb_single(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->ahb_single;
+}
+
+int dwc_otg_set_param_otg_ver(dwc_otg_core_if_t * core_if, int32_t val)
+{
+	int retval = 0;
+
+	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+		DWC_WARN("`%d' invalid for parameter `otg_ver'\n", val);
+		DWC_WARN
+		    ("otg_ver must be 0(for OTG 1.3 support) or 1(for OTG 2.0 support)\n");
+		return -DWC_E_INVALID;
+	}
+
+	core_if->core_params->otg_ver = val;
+	return retval;
+}
+
+int32_t dwc_otg_get_param_otg_ver(dwc_otg_core_if_t * core_if)
+{
+	return core_if->core_params->otg_ver;
+}
+
+uint32_t dwc_otg_get_hnpstatus(dwc_otg_core_if_t * core_if)
+{
+	gotgctl_data_t otgctl;
+	otgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
+	return otgctl.b.hstnegscs;
+}
+
+uint32_t dwc_otg_get_srpstatus(dwc_otg_core_if_t * core_if)
+{
+	gotgctl_data_t otgctl;
+	otgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
+	return otgctl.b.sesreqscs;
+}
+
+void dwc_otg_set_hnpreq(dwc_otg_core_if_t * core_if, uint32_t val)
+{
+	if(core_if->otg_ver == 0) {
+		gotgctl_data_t otgctl;
+		otgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
+		otgctl.b.hnpreq = val;
+		DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl, otgctl.d32);
+	} else {
+		core_if->otg_sts = val;
+	}
+}
+
+uint32_t dwc_otg_get_gsnpsid(dwc_otg_core_if_t * core_if)
+{
+	return core_if->snpsid;
+}
+
+uint32_t dwc_otg_get_mode(dwc_otg_core_if_t * core_if)
+{
+	gintsts_data_t gintsts;
+	gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
+	return gintsts.b.curmode;
+}
+
+uint32_t dwc_otg_get_hnpcapable(dwc_otg_core_if_t * core_if)
+{
+	gusbcfg_data_t usbcfg;
+	usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
+	return usbcfg.b.hnpcap;
+}
+
+void dwc_otg_set_hnpcapable(dwc_otg_core_if_t * core_if, uint32_t val)
+{
+	gusbcfg_data_t usbcfg;
+	usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
+	usbcfg.b.hnpcap = val;
+	DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, usbcfg.d32);
+}
+
+uint32_t dwc_otg_get_srpcapable(dwc_otg_core_if_t * core_if)
+{
+	gusbcfg_data_t usbcfg;
+	usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
+	return usbcfg.b.srpcap;
+}
+
+void dwc_otg_set_srpcapable(dwc_otg_core_if_t * core_if, uint32_t val)
+{
+	gusbcfg_data_t usbcfg;
+	usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
+	usbcfg.b.srpcap = val;
+	DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, usbcfg.d32);
+}
+
+uint32_t dwc_otg_get_devspeed(dwc_otg_core_if_t * core_if)
+{
+	dcfg_data_t dcfg;
+	dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
+	return dcfg.b.devspd;
+}
+
+void dwc_otg_set_devspeed(dwc_otg_core_if_t * core_if, uint32_t val)
+{
+	dcfg_data_t dcfg;
+	dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
+	dcfg.b.devspd = val;
+	DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
+}
+
+uint32_t dwc_otg_get_busconnected(dwc_otg_core_if_t * core_if)
+{
+	hprt0_data_t hprt0;
+	hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
+	return hprt0.b.prtconnsts;
+}
+
+uint32_t dwc_otg_get_enumspeed(dwc_otg_core_if_t * core_if)
+{
+	dsts_data_t dsts;
+	dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
+	return dsts.b.enumspd;
+}
+
+uint32_t dwc_otg_get_prtpower(dwc_otg_core_if_t * core_if)
+{
+	hprt0_data_t hprt0;
+	hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
+	return hprt0.b.prtpwr;
+
+}
+
+uint32_t dwc_otg_get_core_state(dwc_otg_core_if_t * core_if)
+{
+	return core_if->hibernation_suspend;
+}
+
+void dwc_otg_set_prtpower(dwc_otg_core_if_t * core_if, uint32_t val)
+{
+	hprt0_data_t hprt0;
+	hprt0.d32 = dwc_otg_read_hprt0(core_if);
+	hprt0.b.prtpwr = val;
+	DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+}
+
+uint32_t dwc_otg_get_prtsuspend(dwc_otg_core_if_t * core_if)
+{
+	hprt0_data_t hprt0;
+	hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
+	return hprt0.b.prtsusp;
+
+}
+
+void dwc_otg_set_prtsuspend(dwc_otg_core_if_t * core_if, uint32_t val)
+{
+	hprt0_data_t hprt0;
+	hprt0.d32 = dwc_otg_read_hprt0(core_if);
+	hprt0.b.prtsusp = val;
+	DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+}
+
+uint32_t dwc_otg_get_fr_interval(dwc_otg_core_if_t * core_if)
+{
+	hfir_data_t hfir;
+	hfir.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hfir);
+	return hfir.b.frint;
+
+}
+
+void dwc_otg_set_fr_interval(dwc_otg_core_if_t * core_if, uint32_t val)
+{
+	hfir_data_t hfir;
+	uint32_t fram_int;
+	fram_int = calc_frame_interval(core_if);
+	hfir.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hfir);
+	if (!core_if->core_params->reload_ctl) {
+		DWC_WARN("\nCannot reload HFIR register.HFIR.HFIRRldCtrl bit is"
+			 "not set to 1.\nShould load driver with reload_ctl=1"
+			 " module parameter\n");
+		return;
+	}
+	switch (fram_int) {
+	case 3750:
+		if ((val < 3350) || (val > 4150)) {
+			DWC_WARN("HFIR interval for HS core and 30 MHz"
+				 "clock freq should be from 3350 to 4150\n");
+			return;
+		}
+		break;
+	case 30000:
+		if ((val < 26820) || (val > 33180)) {
+			DWC_WARN("HFIR interval for FS/LS core and 30 MHz"
+				 "clock freq should be from 26820 to 33180\n");
+			return;
+		}
+		break;
+	case 6000:
+		if ((val < 5360) || (val > 6640)) {
+			DWC_WARN("HFIR interval for HS core and 48 MHz"
+				 "clock freq should be from 5360 to 6640\n");
+			return;
+		}
+		break;
+	case 48000:
+		if ((val < 42912) || (val > 53088)) {
+			DWC_WARN("HFIR interval for FS/LS core and 48 MHz"
+				 "clock freq should be from 42912 to 53088\n");
+			return;
+		}
+		break;
+	case 7500:
+		if ((val < 6700) || (val > 8300)) {
+			DWC_WARN("HFIR interval for HS core and 60 MHz"
+				 "clock freq should be from 6700 to 8300\n");
+			return;
+		}
+		break;
+	case 60000:
+		if ((val < 53640) || (val > 65536)) {
+			DWC_WARN("HFIR interval for FS/LS core and 60 MHz"
+				 "clock freq should be from 53640 to 65536\n");
+			return;
+		}
+		break;
+	default:
+		DWC_WARN("Unknown frame interval\n");
+		return;
+		break;
+
+	}
+	hfir.b.frint = val;
+	DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hfir, hfir.d32);
+}
+
+uint32_t dwc_otg_get_mode_ch_tim(dwc_otg_core_if_t * core_if)
+{
+	hcfg_data_t hcfg;
+	hcfg.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
+	return hcfg.b.modechtimen;
+
+}
+
+void dwc_otg_set_mode_ch_tim(dwc_otg_core_if_t * core_if, uint32_t val)
+{
+	hcfg_data_t hcfg;
+	hcfg.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
+	hcfg.b.modechtimen = val;
+	DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hcfg.d32);
+}
+
+void dwc_otg_set_prtresume(dwc_otg_core_if_t * core_if, uint32_t val)
+{
+	hprt0_data_t hprt0;
+	hprt0.d32 = dwc_otg_read_hprt0(core_if);
+	hprt0.b.prtres = val;
+	DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+}
+
+uint32_t dwc_otg_get_remotewakesig(dwc_otg_core_if_t * core_if)
+{
+	dctl_data_t dctl;
+	dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
+	return dctl.b.rmtwkupsig;
+}
+
+uint32_t dwc_otg_get_lpm_portsleepstatus(dwc_otg_core_if_t * core_if)
+{
+	glpmcfg_data_t lpmcfg;
+	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
+
+	DWC_ASSERT(!
+		   ((core_if->lx_state == DWC_OTG_L1) ^ lpmcfg.b.prt_sleep_sts),
+		   "lx_state = %d, lmpcfg.prt_sleep_sts = %d\n",
+		   core_if->lx_state, lpmcfg.b.prt_sleep_sts);
+
+	return lpmcfg.b.prt_sleep_sts;
+}
+
+uint32_t dwc_otg_get_lpm_remotewakeenabled(dwc_otg_core_if_t * core_if)
+{
+	glpmcfg_data_t lpmcfg;
+	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
+	return lpmcfg.b.rem_wkup_en;
+}
+
+uint32_t dwc_otg_get_lpmresponse(dwc_otg_core_if_t * core_if)
+{
+	glpmcfg_data_t lpmcfg;
+	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
+	return lpmcfg.b.appl_resp;
+}
+
+void dwc_otg_set_lpmresponse(dwc_otg_core_if_t * core_if, uint32_t val)
+{
+	glpmcfg_data_t lpmcfg;
+	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
+	lpmcfg.b.appl_resp = val;
+	DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
+}
+
+uint32_t dwc_otg_get_hsic_connect(dwc_otg_core_if_t * core_if)
+{
+	glpmcfg_data_t lpmcfg;
+	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
+	return lpmcfg.b.hsic_connect;
+}
+
+void dwc_otg_set_hsic_connect(dwc_otg_core_if_t * core_if, uint32_t val)
+{
+	glpmcfg_data_t lpmcfg;
+	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
+	lpmcfg.b.hsic_connect = val;
+	DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
+}
+
+uint32_t dwc_otg_get_inv_sel_hsic(dwc_otg_core_if_t * core_if)
+{
+	glpmcfg_data_t lpmcfg;
+	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
+	return lpmcfg.b.inv_sel_hsic;
+
+}
+
+void dwc_otg_set_inv_sel_hsic(dwc_otg_core_if_t * core_if, uint32_t val)
+{
+	glpmcfg_data_t lpmcfg;
+	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
+	lpmcfg.b.inv_sel_hsic = val;
+	DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
+}
+
+uint32_t dwc_otg_get_gotgctl(dwc_otg_core_if_t * core_if)
+{
+	return DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
+}
+
+void dwc_otg_set_gotgctl(dwc_otg_core_if_t * core_if, uint32_t val)
+{
+	DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl, val);
+}
+
+uint32_t dwc_otg_get_gusbcfg(dwc_otg_core_if_t * core_if)
+{
+	return DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
+}
+
+void dwc_otg_set_gusbcfg(dwc_otg_core_if_t * core_if, uint32_t val)
+{
+	DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, val);
+}
+
+uint32_t dwc_otg_get_grxfsiz(dwc_otg_core_if_t * core_if)
+{
+	return DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
+}
+
+void dwc_otg_set_grxfsiz(dwc_otg_core_if_t * core_if, uint32_t val)
+{
+	DWC_WRITE_REG32(&core_if->core_global_regs->grxfsiz, val);
+}
+
+uint32_t dwc_otg_get_gnptxfsiz(dwc_otg_core_if_t * core_if)
+{
+	return DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz);
+}
+
+void dwc_otg_set_gnptxfsiz(dwc_otg_core_if_t * core_if, uint32_t val)
+{
+	DWC_WRITE_REG32(&core_if->core_global_regs->gnptxfsiz, val);
+}
+
+uint32_t dwc_otg_get_gpvndctl(dwc_otg_core_if_t * core_if)
+{
+	return DWC_READ_REG32(&core_if->core_global_regs->gpvndctl);
+}
+
+void dwc_otg_set_gpvndctl(dwc_otg_core_if_t * core_if, uint32_t val)
+{
+	DWC_WRITE_REG32(&core_if->core_global_regs->gpvndctl, val);
+}
+
+uint32_t dwc_otg_get_ggpio(dwc_otg_core_if_t * core_if)
+{
+	return DWC_READ_REG32(&core_if->core_global_regs->ggpio);
+}
+
+void dwc_otg_set_ggpio(dwc_otg_core_if_t * core_if, uint32_t val)
+{
+	DWC_WRITE_REG32(&core_if->core_global_regs->ggpio, val);
+}
+
+uint32_t dwc_otg_get_hprt0(dwc_otg_core_if_t * core_if)
+{
+	return DWC_READ_REG32(core_if->host_if->hprt0);
+
+}
+
+void dwc_otg_set_hprt0(dwc_otg_core_if_t * core_if, uint32_t val)
+{
+	DWC_WRITE_REG32(core_if->host_if->hprt0, val);
+}
+
+uint32_t dwc_otg_get_guid(dwc_otg_core_if_t * core_if)
+{
+	return DWC_READ_REG32(&core_if->core_global_regs->guid);
+}
+
+void dwc_otg_set_guid(dwc_otg_core_if_t * core_if, uint32_t val)
+{
+	DWC_WRITE_REG32(&core_if->core_global_regs->guid, val);
+}
+
+uint32_t dwc_otg_get_hptxfsiz(dwc_otg_core_if_t * core_if)
+{
+	return DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
+}
+
+uint16_t dwc_otg_get_otg_version(dwc_otg_core_if_t * core_if)
+{
+	return ((core_if->otg_ver == 1) ? (uint16_t)0x0200 : (uint16_t)0x0103);
+}
+
+/**
+ * Start the SRP timer to detect when the SRP does not complete within
+ * 6 seconds.
+ *
+ * @param core_if the pointer to core_if strucure.
+ */
+void dwc_otg_pcd_start_srp_timer(dwc_otg_core_if_t * core_if)
+{
+	core_if->srp_timer_started = 1;
+	DWC_TIMER_SCHEDULE(core_if->srp_timer, 6000 /* 6 secs */ );
+}
+
+void dwc_otg_initiate_srp(dwc_otg_core_if_t * core_if)
+{
+	uint32_t *addr = (uint32_t *) & (core_if->core_global_regs->gotgctl);
+	gotgctl_data_t mem;
+	gotgctl_data_t val;
+
+	val.d32 = DWC_READ_REG32(addr);
+	if (val.b.sesreq) {
+		DWC_ERROR("Session Request Already active!\n");
+		return;
+	}
+
+	DWC_INFO("Session Request Initated\n");	//NOTICE
+	mem.d32 = DWC_READ_REG32(addr);
+	mem.b.sesreq = 1;
+	DWC_WRITE_REG32(addr, mem.d32);
+
+	/* Start the SRP timer */
+	dwc_otg_pcd_start_srp_timer(core_if);
+	return;
+}
diff --git a/drivers/usb/dwc_otg/dwc_otg_cil.h b/drivers/usb/dwc_otg/dwc_otg_cil.h
new file mode 100644
index 0000000..9957861
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_cil.h
@@ -0,0 +1,1453 @@
+/* ==========================================================================
+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil.h $
+ * $Revision: #122 $
+ * $Date: 2011/10/24 $
+ * $Change: 1871160 $
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+#if !defined(__DWC_CIL_H__)
+#define __DWC_CIL_H__
+
+#include "dwc_list.h"
+#include "dwc_otg_dbg.h"
+#include "dwc_otg_regs.h"
+
+#include "dwc_otg_core_if.h"
+#include "dwc_otg_adp.h"
+
+/**
+ * @file
+ * This file contains the interface to the Core Interface Layer.
+ */
+
+#ifdef DWC_UTE_CFI
+
+#define MAX_DMA_DESCS_PER_EP	256
+
+/**
+ * Enumeration for the data buffer mode
+ */
+typedef enum _data_buffer_mode {
+	BM_STANDARD = 0,	/* data buffer is in normal mode */
+	BM_SG = 1,		/* data buffer uses the scatter/gather mode */
+	BM_CONCAT = 2,		/* data buffer uses the concatenation mode */
+	BM_CIRCULAR = 3,	/* data buffer uses the circular DMA mode */
+	BM_ALIGN = 4		/* data buffer is in buffer alignment mode */
+} data_buffer_mode_e;
+#endif //DWC_UTE_CFI
+
+/** Macros defined for DWC OTG HW Release version */
+
+#define OTG_CORE_REV_2_60a	0x4F54260A
+#define OTG_CORE_REV_2_71a	0x4F54271A
+#define OTG_CORE_REV_2_72a	0x4F54272A
+#define OTG_CORE_REV_2_80a	0x4F54280A
+#define OTG_CORE_REV_2_81a	0x4F54281A
+#define OTG_CORE_REV_2_90a	0x4F54290A
+#define OTG_CORE_REV_2_91a	0x4F54291A
+#define OTG_CORE_REV_2_92a	0x4F54292A
+#define OTG_CORE_REV_2_93a	0x4F54293A
+#define OTG_CORE_REV_2_94a	0x4F54294A
+
+/**
+ * Information for each ISOC packet.
+ */
+typedef struct iso_pkt_info {
+	uint32_t offset;
+	uint32_t length;
+	int32_t status;
+} iso_pkt_info_t;
+
+/**
+ * The <code>dwc_ep</code> structure represents the state of a single
+ * endpoint when acting in device mode. It contains the data items
+ * needed for an endpoint to be activated and transfer packets.
+ */
+typedef struct dwc_ep {
+	/** EP number used for register address lookup */
+	uint8_t num;
+	/** EP direction 0 = OUT */
+	unsigned is_in:1;
+	/** EP active. */
+	unsigned active:1;
+
+	/**
+	 * Periodic Tx FIFO # for IN EPs For INTR EP set to 0 to use non-periodic
+	 * Tx FIFO. If dedicated Tx FIFOs are enabled Tx FIFO # FOR IN EPs*/
+	unsigned tx_fifo_num:4;
+	/** EP type: 0 - Control, 1 - ISOC,	 2 - BULK,	3 - INTR */
+	unsigned type:2;
+#define DWC_OTG_EP_TYPE_CONTROL	   0
+#define DWC_OTG_EP_TYPE_ISOC	   1
+#define DWC_OTG_EP_TYPE_BULK	   2
+#define DWC_OTG_EP_TYPE_INTR	   3
+
+	/** DATA start PID for INTR and BULK EP */
+	unsigned data_pid_start:1;
+	/** Frame (even/odd) for ISOC EP */
+	unsigned even_odd_frame:1;
+	/** Max Packet bytes */
+	unsigned maxpacket:11;
+
+	/** Max Transfer size */
+	uint32_t maxxfer;
+
+	/** @name Transfer state */
+	/** @{ */
+
+	/**
+	 * Pointer to the beginning of the transfer buffer -- do not modify
+	 * during transfer.
+	 */
+
+	dwc_dma_t dma_addr;
+
+	dwc_dma_t dma_desc_addr;
+	dwc_otg_dev_dma_desc_t *desc_addr;
+
+	uint8_t *start_xfer_buff;
+	/** pointer to the transfer buffer */
+	uint8_t *xfer_buff;
+	/** Number of bytes to transfer */
+	unsigned xfer_len:19;
+	/** Number of bytes transferred. */
+	unsigned xfer_count:19;
+	/** Sent ZLP */
+	unsigned sent_zlp:1;
+	/** Total len for control transfer */
+	unsigned total_len:19;
+
+	/** stall clear flag */
+	unsigned stall_clear_flag:1;
+
+#ifdef DWC_UTE_CFI
+	/* The buffer mode */
+	data_buffer_mode_e buff_mode;
+
+	/* The chain of DMA descriptors.
+	 * MAX_DMA_DESCS_PER_EP will be allocated for each active EP.
+	 */
+	dwc_otg_dma_desc_t *descs;
+
+	/* The DMA address of the descriptors chain start */
+	dma_addr_t descs_dma_addr;
+	/** This variable stores the length of the last enqueued request */
+	uint32_t cfi_req_len;
+#endif				//DWC_UTE_CFI
+
+/** Max DMA Descriptor count for any EP */
+#define MAX_DMA_DESC_CNT 256
+	/** Allocated DMA Desc count */
+	uint32_t desc_cnt;
+
+	/** bInterval */
+	uint32_t bInterval;
+	/** Next frame num to setup next ISOC transfer */
+	uint32_t frame_num;
+	/** Indicates SOF number overrun in DSTS */
+	uint8_t frm_overrun;
+
+#ifdef DWC_UTE_PER_IO
+	/** Next frame num for which will be setup DMA Desc */
+	uint32_t xiso_frame_num;
+	/** bInterval */
+	uint32_t xiso_bInterval;
+	/** Count of currently active transfers - shall be either 0 or 1 */
+	int xiso_active_xfers;
+	int xiso_queued_xfers;
+#endif
+#ifdef DWC_EN_ISOC
+	/**
+	 * Variables specific for ISOC EPs
+	 *
+	 */
+	/** DMA addresses of ISOC buffers */
+	dwc_dma_t dma_addr0;
+	dwc_dma_t dma_addr1;
+
+	dwc_dma_t iso_dma_desc_addr;
+	dwc_otg_dev_dma_desc_t *iso_desc_addr;
+
+	/** pointer to the transfer buffers */
+	uint8_t *xfer_buff0;
+	uint8_t *xfer_buff1;
+
+	/** number of ISOC Buffer is processing */
+	uint32_t proc_buf_num;
+	/** Interval of ISOC Buffer processing */
+	uint32_t buf_proc_intrvl;
+	/** Data size for regular frame */
+	uint32_t data_per_frame;
+
+	/* todo - pattern data support is to be implemented in the future */
+	/** Data size for pattern frame */
+	uint32_t data_pattern_frame;
+	/** Frame number of pattern data */
+	uint32_t sync_frame;
+
+	/** ISO Packet number per frame */
+	uint32_t pkt_per_frm;
+	/** Next frame num for which will be setup DMA Desc */
+	uint32_t next_frame;
+	/** Number of packets per buffer processing */
+	uint32_t pkt_cnt;
+	/** Info for all isoc packets */
+	iso_pkt_info_t *pkt_info;
+	/** current pkt number */
+	uint32_t cur_pkt;
+	/** current pkt number */
+	uint8_t *cur_pkt_addr;
+	/** current pkt number */
+	uint32_t cur_pkt_dma_addr;
+#endif				/* DWC_EN_ISOC */
+
+/** @} */
+} dwc_ep_t;
+
+/*
+ * Reasons for halting a host channel.
+ */
+typedef enum dwc_otg_halt_status {
+	DWC_OTG_HC_XFER_NO_HALT_STATUS,
+	DWC_OTG_HC_XFER_COMPLETE,
+	DWC_OTG_HC_XFER_URB_COMPLETE,
+	DWC_OTG_HC_XFER_ACK,
+	DWC_OTG_HC_XFER_NAK,
+	DWC_OTG_HC_XFER_NYET,
+	DWC_OTG_HC_XFER_STALL,
+	DWC_OTG_HC_XFER_XACT_ERR,
+	DWC_OTG_HC_XFER_FRAME_OVERRUN,
+	DWC_OTG_HC_XFER_BABBLE_ERR,
+	DWC_OTG_HC_XFER_DATA_TOGGLE_ERR,
+	DWC_OTG_HC_XFER_AHB_ERR,
+	DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE,
+	DWC_OTG_HC_XFER_URB_DEQUEUE
+} dwc_otg_halt_status_e;
+
+/**
+ * Host channel descriptor. This structure represents the state of a single
+ * host channel when acting in host mode. It contains the data items needed to
+ * transfer packets to an endpoint via a host channel.
+ */
+typedef struct dwc_hc {
+	/** Host channel number used for register address lookup */
+	uint8_t hc_num;
+
+	/** Device to access */
+	unsigned dev_addr:7;
+
+	/** EP to access */
+	unsigned ep_num:4;
+
+	/** EP direction. 0: OUT, 1: IN */
+	unsigned ep_is_in:1;
+
+	/**
+	 * EP speed.
+	 * One of the following values:
+	 *	- DWC_OTG_EP_SPEED_LOW
+	 *	- DWC_OTG_EP_SPEED_FULL
+	 *	- DWC_OTG_EP_SPEED_HIGH
+	 */
+	unsigned speed:2;
+#define DWC_OTG_EP_SPEED_LOW	0
+#define DWC_OTG_EP_SPEED_FULL	1
+#define DWC_OTG_EP_SPEED_HIGH	2
+
+	/**
+	 * Endpoint type.
+	 * One of the following values:
+	 *	- DWC_OTG_EP_TYPE_CONTROL: 0
+	 *	- DWC_OTG_EP_TYPE_ISOC: 1
+	 *	- DWC_OTG_EP_TYPE_BULK: 2
+	 *	- DWC_OTG_EP_TYPE_INTR: 3
+	 */
+	unsigned ep_type:2;
+
+	/** Max packet size in bytes */
+	unsigned max_packet:11;
+
+	/**
+	 * PID for initial transaction.
+	 * 0: DATA0,<br>
+	 * 1: DATA2,<br>
+	 * 2: DATA1,<br>
+	 * 3: MDATA (non-Control EP),
+	 *	  SETUP (Control EP)
+	 */
+	unsigned data_pid_start:2;
+#define DWC_OTG_HC_PID_DATA0 0
+#define DWC_OTG_HC_PID_DATA2 1
+#define DWC_OTG_HC_PID_DATA1 2
+#define DWC_OTG_HC_PID_MDATA 3
+#define DWC_OTG_HC_PID_SETUP 3
+
+	/** Number of periodic transactions per (micro)frame */
+	unsigned multi_count:2;
+
+	/** @name Transfer State */
+	/** @{ */
+
+	/** Pointer to the current transfer buffer position. */
+	uint8_t *xfer_buff;
+	/**
+	 * In Buffer DMA mode this buffer will be used
+	 * if xfer_buff is not DWORD aligned.
+	 */
+	dwc_dma_t align_buff;
+	/** Total number of bytes to transfer. */
+	uint32_t xfer_len;
+	/** Number of bytes transferred so far. */
+	uint32_t xfer_count;
+	/** Packet count at start of transfer.*/
+	uint16_t start_pkt_count;
+
+	/**
+	 * Flag to indicate whether the transfer has been started. Set to 1 if
+	 * it has been started, 0 otherwise.
+	 */
+	uint8_t xfer_started;
+
+	/**
+	 * Set to 1 to indicate that a PING request should be issued on this
+	 * channel. If 0, process normally.
+	 */
+	uint8_t do_ping;
+
+	/**
+	 * Set to 1 to indicate that the error count for this transaction is
+	 * non-zero. Set to 0 if the error count is 0.
+	 */
+	uint8_t error_state;
+
+	/**
+	 * Set to 1 to indicate that this channel should be halted the next
+	 * time a request is queued for the channel. This is necessary in
+	 * slave mode if no request queue space is available when an attempt
+	 * is made to halt the channel.
+	 */
+	uint8_t halt_on_queue;
+
+	/**
+	 * Set to 1 if the host channel has been halted, but the core is not
+	 * finished flushing queued requests. Otherwise 0.
+	 */
+	uint8_t halt_pending;
+
+	/**
+	 * Reason for halting the host channel.
+	 */
+	dwc_otg_halt_status_e halt_status;
+
+	/*
+	 * Split settings for the host channel
+	 */
+	uint8_t do_split;		   /**< Enable split for the channel */
+	uint8_t complete_split;	   /**< Enable complete split */
+	uint8_t hub_addr;		   /**< Address of high speed hub */
+
+	uint8_t port_addr;		   /**< Port of the low/full speed device */
+	/** Split transaction position
+	 * One of the following values:
+	 *	  - DWC_HCSPLIT_XACTPOS_MID
+	 *	  - DWC_HCSPLIT_XACTPOS_BEGIN
+	 *	  - DWC_HCSPLIT_XACTPOS_END
+	 *	  - DWC_HCSPLIT_XACTPOS_ALL */
+	uint8_t xact_pos;
+
+	/** Set when the host channel does a short read. */
+	uint8_t short_read;
+
+	/**
+	 * Number of requests issued for this channel since it was assigned to
+	 * the current transfer (not counting PINGs).
+	 */
+	uint8_t requests;
+
+	/**
+	 * Queue Head for the transfer being processed by this channel.
+	 */
+	struct dwc_otg_qh *qh;
+
+	/** @} */
+
+	/** Entry in list of host channels. */
+	 DWC_CIRCLEQ_ENTRY(dwc_hc) hc_list_entry;
+
+	/** @name Descriptor DMA support */
+	/** @{ */
+
+	/** Number of Transfer Descriptors */
+	uint16_t ntd;
+
+	/** Descriptor List DMA address */
+	dwc_dma_t desc_list_addr;
+
+	/** Scheduling micro-frame bitmap. */
+	uint8_t schinfo;
+
+	/** @} */
+} dwc_hc_t;
+
+/**
+ * The following parameters may be specified when starting the module. These
+ * parameters define how the DWC_otg controller should be configured.
+ */
+typedef struct dwc_otg_core_params {
+	int32_t opt;
+
+	/**
+	 * Specifies the OTG capabilities. The driver will automatically
+	 * detect the value for this parameter if none is specified.
+	 * 0 - HNP and SRP capable (default)
+	 * 1 - SRP Only capable
+	 * 2 - No HNP/SRP capable
+	 */
+	int32_t otg_cap;
+
+	/**
+	 * Specifies whether to use slave or DMA mode for accessing the data
+	 * FIFOs. The driver will automatically detect the value for this
+	 * parameter if none is specified.
+	 * 0 - Slave
+	 * 1 - DMA (default, if available)
+	 */
+	int32_t dma_enable;
+
+	/**
+	 * When DMA mode is enabled specifies whether to use address DMA or DMA
+	 * Descriptor mode for accessing the data FIFOs in device mode. The driver
+	 * will automatically detect the value for this if none is specified.
+	 * 0 - address DMA
+	 * 1 - DMA Descriptor(default, if available)
+	 */
+	int32_t dma_desc_enable;
+	/** The DMA Burst size (applicable only for External DMA
+	 * Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32)
+	 */
+	int32_t dma_burst_size;	/* Translate this to GAHBCFG values */
+
+	/**
+	 * Specifies the maximum speed of operation in host and device mode.
+	 * The actual speed depends on the speed of the attached device and
+	 * the value of phy_type. The actual speed depends on the speed of the
+	 * attached device.
+	 * 0 - High Speed (default)
+	 * 1 - Full Speed
+	 */
+	int32_t speed;
+	/** Specifies whether low power mode is supported when attached
+	 *	to a Full Speed or Low Speed device in host mode.
+	 * 0 - Don't support low power mode (default)
+	 * 1 - Support low power mode
+	 */
+	int32_t host_support_fs_ls_low_power;
+
+	/** Specifies the PHY clock rate in low power mode when connected to a
+	 * Low Speed device in host mode. This parameter is applicable only if
+	 * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS
+	 * then defaults to 6 MHZ otherwise 48 MHZ.
+	 *
+	 * 0 - 48 MHz
+	 * 1 - 6 MHz
+	 */
+	int32_t host_ls_low_power_phy_clk;
+
+	/**
+	 * 0 - Use cC FIFO size parameters
+	 * 1 - Allow dynamic FIFO sizing (default)
+	 */
+	int32_t enable_dynamic_fifo;
+
+	/** Total number of 4-byte words in the data FIFO memory. This
+	 * memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic
+	 * Tx FIFOs.
+	 * 32 to 32768 (default 8192)
+	 * Note: The total FIFO memory depth in the FPGA configuration is 8192.
+	 */
+	int32_t data_fifo_size;
+
+	/** Number of 4-byte words in the Rx FIFO in device mode when dynamic
+	 * FIFO sizing is enabled.
+	 * 16 to 32768 (default 1064)
+	 */
+	int32_t dev_rx_fifo_size;
+
+	/** Number of 4-byte words in the non-periodic Tx FIFO in device mode
+	 * when dynamic FIFO sizing is enabled.
+	 * 16 to 32768 (default 1024)
+	 */
+	int32_t dev_nperio_tx_fifo_size;
+
+	/** Number of 4-byte words in each of the periodic Tx FIFOs in device
+	 * mode when dynamic FIFO sizing is enabled.
+	 * 4 to 768 (default 256)
+	 */
+	uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS];
+
+	/** Number of 4-byte words in the Rx FIFO in host mode when dynamic
+	 * FIFO sizing is enabled.
+	 * 16 to 32768 (default 1024)
+	 */
+	int32_t host_rx_fifo_size;
+
+	/** Number of 4-byte words in the non-periodic Tx FIFO in host mode
+	 * when Dynamic FIFO sizing is enabled in the core.
+	 * 16 to 32768 (default 1024)
+	 */
+	int32_t host_nperio_tx_fifo_size;
+
+	/** Number of 4-byte words in the host periodic Tx FIFO when dynamic
+	 * FIFO sizing is enabled.
+	 * 16 to 32768 (default 1024)
+	 */
+	int32_t host_perio_tx_fifo_size;
+
+	/** The maximum transfer size supported in bytes.
+	 * 2047 to 65,535  (default 65,535)
+	 */
+	int32_t max_transfer_size;
+
+	/** The maximum number of packets in a transfer.
+	 * 15 to 511  (default 511)
+	 */
+	int32_t max_packet_count;
+
+	/** The number of host channel registers to use.
+	 * 1 to 16 (default 12)
+	 * Note: The FPGA configuration supports a maximum of 12 host channels.
+	 */
+	int32_t host_channels;
+
+	/** The number of endpoints in addition to EP0 available for device
+	 * mode operations.
+	 * 1 to 15 (default 6 IN and OUT)
+	 * Note: The FPGA configuration supports a maximum of 6 IN and OUT
+	 * endpoints in addition to EP0.
+	 */
+	int32_t dev_endpoints;
+
+		/**
+		 * Specifies the type of PHY interface to use. By default, the driver
+		 * will automatically detect the phy_type.
+		 *
+		 * 0 - Full Speed PHY
+		 * 1 - UTMI+ (default)
+		 * 2 - ULPI
+		 */
+	int32_t phy_type;
+
+	/**
+	 * Specifies the UTMI+ Data Width. This parameter is
+	 * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI
+	 * PHY_TYPE, this parameter indicates the data width between
+	 * the MAC and the ULPI Wrapper.) Also, this parameter is
+	 * applicable only if the OTG_HSPHY_WIDTH cC parameter was set
+	 * to "8 and 16 bits", meaning that the core has been
+	 * configured to work at either data path width.
+	 *
+	 * 8 or 16 bits (default 16)
+	 */
+	int32_t phy_utmi_width;
+
+	/**
+	 * Specifies whether the ULPI operates at double or single
+	 * data rate. This parameter is only applicable if PHY_TYPE is
+	 * ULPI.
+	 *
+	 * 0 - single data rate ULPI interface with 8 bit wide data
+	 * bus (default)
+	 * 1 - double data rate ULPI interface with 4 bit wide data
+	 * bus
+	 */
+	int32_t phy_ulpi_ddr;
+
+	/**
+	 * Specifies whether to use the internal or external supply to
+	 * drive the vbus with a ULPI phy.
+	 */
+	int32_t phy_ulpi_ext_vbus;
+
+	/**
+	 * Specifies whether to use the I2Cinterface for full speed PHY. This
+	 * parameter is only applicable if PHY_TYPE is FS.
+	 * 0 - No (default)
+	 * 1 - Yes
+	 */
+	int32_t i2c_enable;
+
+	int32_t ulpi_fs_ls;
+
+	int32_t ts_dline;
+
+	/**
+	 * Specifies whether dedicated transmit FIFOs are
+	 * enabled for non periodic IN endpoints in device mode
+	 * 0 - No
+	 * 1 - Yes
+	 */
+	int32_t en_multiple_tx_fifo;
+
+	/** Number of 4-byte words in each of the Tx FIFOs in device
+	 * mode when dynamic FIFO sizing is enabled.
+	 * 4 to 768 (default 256)
+	 */
+	uint32_t dev_tx_fifo_size[MAX_TX_FIFOS];
+
+	/** Thresholding enable flag-
+	 * bit 0 - enable non-ISO Tx thresholding
+	 * bit 1 - enable ISO Tx thresholding
+	 * bit 2 - enable Rx thresholding
+	 */
+	uint32_t thr_ctl;
+
+	/** Thresholding length for Tx
+	 *	FIFOs in 32 bit DWORDs
+	 */
+	uint32_t tx_thr_length;
+
+	/** Thresholding length for Rx
+	 *	FIFOs in 32 bit DWORDs
+	 */
+	uint32_t rx_thr_length;
+
+	/**
+	 * Specifies whether LPM (Link Power Management) support is enabled
+	 */
+	int32_t lpm_enable;
+
+	/** Per Transfer Interrupt
+	 *	mode enable flag
+	 * 1 - Enabled
+	 * 0 - Disabled
+	 */
+	int32_t pti_enable;
+
+	/** Multi Processor Interrupt
+	 *	mode enable flag
+	 * 1 - Enabled
+	 * 0 - Disabled
+	 */
+	int32_t mpi_enable;
+
+	/** IS_USB Capability
+	 * 1 - Enabled
+	 * 0 - Disabled
+	 */
+	int32_t ic_usb_cap;
+
+	/** AHB Threshold Ratio
+	 * 2'b00 AHB Threshold = 	MAC Threshold
+	 * 2'b01 AHB Threshold = 1/2 	MAC Threshold
+	 * 2'b10 AHB Threshold = 1/4	MAC Threshold
+	 * 2'b11 AHB Threshold = 1/8	MAC Threshold
+	 */
+	int32_t ahb_thr_ratio;
+
+	/** ADP Support
+	 * 1 - Enabled
+	 * 0 - Disabled
+	 */
+	int32_t adp_supp_enable;
+
+	/** HFIR Reload Control
+	 * 0 - The HFIR cannot be reloaded dynamically.
+	 * 1 - Allow dynamic reloading of the HFIR register during runtime.
+	 */
+	int32_t reload_ctl;
+
+	/** DCFG: Enable device Out NAK
+	 * 0 - The core does not set NAK after Bulk Out transfer complete.
+	 * 1 - The core sets NAK after Bulk OUT transfer complete.
+	 */
+	int32_t dev_out_nak;
+
+	/** DCFG: Enable Continue on BNA
+	 * After receiving BNA interrupt the core disables the endpoint,when the
+	 * endpoint is re-enabled by the application the core starts processing
+	 * 0 - from the DOEPDMA descriptor
+	 * 1 - from the descriptor which received the BNA.
+	 */
+	int32_t cont_on_bna;
+
+	/** GAHBCFG: AHB Single Support
+	 * This bit when programmed supports SINGLE transfers for remainder
+	 * data in a transfer for DMA mode of operation.
+	 * 0 - in this case the remainder data will be sent using INCR burst size.
+	 * 1 - in this case the remainder data will be sent using SINGLE burst size.
+	 */
+	int32_t ahb_single;
+
+	/** Core Power down mode
+	 * 0 - No Power Down is enabled
+	 * 1 - Reserved
+	 * 2 - Complete Power Down (Hibernation)
+	 */
+	int32_t power_down;
+
+	/** OTG revision supported
+	 * 0 - OTG 1.3 revision
+	 * 1 - OTG 2.0 revision
+	 */
+	int32_t otg_ver;
+
+} dwc_otg_core_params_t;
+
+#ifdef DEBUG
+struct dwc_otg_core_if;
+typedef struct hc_xfer_info {
+	struct dwc_otg_core_if *core_if;
+	dwc_hc_t *hc;
+} hc_xfer_info_t;
+#endif
+
+typedef struct ep_xfer_info {
+	struct dwc_otg_core_if *core_if;
+	dwc_ep_t *ep;
+	uint8_t state;
+} ep_xfer_info_t;
+/*
+ * Device States
+ */
+typedef enum dwc_otg_lx_state {
+	/** On state */
+	DWC_OTG_L0,
+	/** LPM sleep state*/
+	DWC_OTG_L1,
+	/** USB suspend state*/
+	DWC_OTG_L2,
+	/** Off state*/
+	DWC_OTG_L3
+} dwc_otg_lx_state_e;
+
+struct dwc_otg_global_regs_backup {
+	uint32_t gotgctl_local;
+	uint32_t gintmsk_local;
+	uint32_t gahbcfg_local;
+	uint32_t gusbcfg_local;
+	uint32_t grxfsiz_local;
+	uint32_t gnptxfsiz_local;
+#ifdef CONFIG_USB_DWC_OTG_LPM
+	uint32_t glpmcfg_local;
+#endif
+	uint32_t gi2cctl_local;
+	uint32_t hptxfsiz_local;
+	uint32_t pcgcctl_local;
+	uint32_t gdfifocfg_local;
+	uint32_t dtxfsiz_local[MAX_EPS_CHANNELS];
+	uint32_t gpwrdn_local;
+};
+
+struct dwc_otg_host_regs_backup {
+	uint32_t hcfg_local;
+	uint32_t haintmsk_local;
+	uint32_t hcintmsk_local[MAX_EPS_CHANNELS];
+	uint32_t hprt0_local;
+	uint32_t hfir_local;
+};
+
+struct dwc_otg_dev_regs_backup {
+	uint32_t dcfg;
+	uint32_t dctl;
+	uint32_t daintmsk;
+	uint32_t diepmsk;
+	uint32_t doepmsk;
+	uint32_t diepctl[MAX_EPS_CHANNELS];
+	uint32_t dieptsiz[MAX_EPS_CHANNELS];
+	uint32_t diepdma[MAX_EPS_CHANNELS];
+};
+/**
+ * The <code>dwc_otg_core_if</code> structure contains information needed to manage
+ * the DWC_otg controller acting in either host or device mode. It
+ * represents the programming view of the controller as a whole.
+ */
+struct dwc_otg_core_if {
+	/** Parameters that define how the core should be configured.*/
+	dwc_otg_core_params_t *core_params;
+
+	/** Core Global registers starting at offset 000h. */
+	dwc_otg_core_global_regs_t *core_global_regs;
+
+	/** Device-specific information */
+	dwc_otg_dev_if_t *dev_if;
+	/** Host-specific information */
+	dwc_otg_host_if_t *host_if;
+
+	/** Value from SNPSID register */
+	uint32_t snpsid;
+
+	/*
+	 * Set to 1 if the core PHY interface bits in USBCFG have been
+	 * initialized.
+	 */
+	uint8_t phy_init_done;
+
+	/*
+	 * SRP Success flag, set by srp success interrupt in FS I2C mode
+	 */
+	uint8_t srp_success;
+	uint8_t srp_timer_started;
+	/** Timer for SRP. If it expires before SRP is successful
+	 * clear the SRP. */
+	dwc_timer_t *srp_timer;
+
+#ifdef DWC_DEV_SRPCAP
+	/* This timer is needed to power on the hibernated host core if SRP is not
+	 * initiated on connected SRP capable device for limited period of time
+	 */
+	uint8_t pwron_timer_started;
+	dwc_timer_t *pwron_timer;
+#endif
+	/* Common configuration information */
+	/** Power and Clock Gating Control Register */
+	volatile uint32_t *pcgcctl;
+#define DWC_OTG_PCGCCTL_OFFSET 0xE00
+
+	/** Push/pop addresses for endpoints or host channels.*/
+	uint32_t *data_fifo[MAX_EPS_CHANNELS];
+#define DWC_OTG_DATA_FIFO_OFFSET 0x1000
+#define DWC_OTG_DATA_FIFO_SIZE 0x1000
+
+	/** Total RAM for FIFOs (Bytes) */
+	uint16_t total_fifo_size;
+	/** Size of Rx FIFO (Bytes) */
+	uint16_t rx_fifo_size;
+	/** Size of Non-periodic Tx FIFO (Bytes) */
+	uint16_t nperio_tx_fifo_size;
+
+	/** 1 if DMA is enabled, 0 otherwise. */
+	uint8_t dma_enable;
+
+	/** 1 if DMA descriptor is enabled, 0 otherwise. */
+	uint8_t dma_desc_enable;
+
+	/** 1 if PTI Enhancement mode is enabled, 0 otherwise. */
+	uint8_t pti_enh_enable;
+
+	/** 1 if MPI Enhancement mode is enabled, 0 otherwise. */
+	uint8_t multiproc_int_enable;
+
+	/** 1 if dedicated Tx FIFOs are enabled, 0 otherwise. */
+	uint8_t en_multiple_tx_fifo;
+
+	/** Set to 1 if multiple packets of a high-bandwidth transfer is in
+	 * process of being queued */
+	uint8_t queuing_high_bandwidth;
+
+	/** Hardware Configuration -- stored here for convenience.*/
+	hwcfg1_data_t hwcfg1;
+	hwcfg2_data_t hwcfg2;
+	hwcfg3_data_t hwcfg3;
+	hwcfg4_data_t hwcfg4;
+	fifosize_data_t hptxfsiz;
+
+	/** Host and Device Configuration -- stored here for convenience.*/
+	hcfg_data_t hcfg;
+	dcfg_data_t dcfg;
+
+	/** The operational State, during transations
+	 * (a_host>>a_peripherial and b_device=>b_host) this may not
+	 * match the core but allows the software to determine
+	 * transitions.
+	 */
+	uint8_t op_state;
+
+	/**
+	 * Set to 1 if the HCD needs to be restarted on a session request
+	 * interrupt. This is required if no connector ID status change has
+	 * occurred since the HCD was last disconnected.
+	 */
+	uint8_t restart_hcd_on_session_req;
+
+	/** HCD callbacks */
+	/** A-Device is a_host */
+#define A_HOST		(1)
+	/** A-Device is a_suspend */
+#define A_SUSPEND	(2)
+	/** A-Device is a_peripherial */
+#define A_PERIPHERAL	(3)
+	/** B-Device is operating as a Peripheral. */
+#define B_PERIPHERAL	(4)
+	/** B-Device is operating as a Host. */
+#define B_HOST		(5)
+
+	/** HCD callbacks */
+	struct dwc_otg_cil_callbacks *hcd_cb;
+	/** PCD callbacks */
+	struct dwc_otg_cil_callbacks *pcd_cb;
+
+	/** Device mode Periodic Tx FIFO Mask */
+	uint32_t p_tx_msk;
+	/** Device mode Periodic Tx FIFO Mask */
+	uint32_t tx_msk;
+
+	/** Workqueue object used for handling several interrupts */
+	dwc_workq_t *wq_otg;
+
+	/** Timer object used for handling "Wakeup Detected" Interrupt */
+	dwc_timer_t *wkp_timer;
+	/** This arrays used for debug purposes for DEV OUT NAK enhancement */
+	uint32_t start_doeptsiz_val[MAX_EPS_CHANNELS];
+	ep_xfer_info_t ep_xfer_info[MAX_EPS_CHANNELS];
+	dwc_timer_t *ep_xfer_timer[MAX_EPS_CHANNELS];
+#ifdef DEBUG
+	uint32_t start_hcchar_val[MAX_EPS_CHANNELS];
+
+	hc_xfer_info_t hc_xfer_info[MAX_EPS_CHANNELS];
+	dwc_timer_t *hc_xfer_timer[MAX_EPS_CHANNELS];
+
+	uint32_t hfnum_7_samples;
+	uint64_t hfnum_7_frrem_accum;
+	uint32_t hfnum_0_samples;
+	uint64_t hfnum_0_frrem_accum;
+	uint32_t hfnum_other_samples;
+	uint64_t hfnum_other_frrem_accum;
+#endif
+
+#ifdef DWC_UTE_CFI
+	uint16_t pwron_rxfsiz;
+	uint16_t pwron_gnptxfsiz;
+	uint16_t pwron_txfsiz[15];
+
+	uint16_t init_rxfsiz;
+	uint16_t init_gnptxfsiz;
+	uint16_t init_txfsiz[15];
+#endif
+
+	/** Lx state of device */
+	dwc_otg_lx_state_e lx_state;
+
+	/** Saved Core Global registers */
+	struct dwc_otg_global_regs_backup *gr_backup;
+	/** Saved Host registers */
+	struct dwc_otg_host_regs_backup *hr_backup;
+	/** Saved Device registers */
+	struct dwc_otg_dev_regs_backup *dr_backup;
+
+	/** Power Down Enable */
+	uint32_t power_down;
+
+	/** ADP support Enable */
+	uint32_t adp_enable;
+
+	/** ADP structure object */
+	dwc_otg_adp_t adp;
+
+	/** hibernation/suspend flag */
+	int hibernation_suspend;
+
+	/** OTG revision supported */
+	uint32_t otg_ver;
+
+	/** OTG status flag used for HNP polling */
+	uint8_t otg_sts;
+
+	/** Pointer to either hcd->lock or pcd->lock */
+	dwc_spinlock_t *lock;
+
+	/** Start predict NextEP based on Learning Queue if equal 1,
+	 * also used as counter of disabled NP IN EP's */
+	uint8_t start_predict;
+
+	/** NextEp sequence, including EP0: nextep_seq[] = EP if non-periodic and
+	 * active, 0xff otherwise */
+	uint8_t nextep_seq[MAX_EPS_CHANNELS];
+
+	/** Index of fisrt EP in nextep_seq array which should be re-enabled **/
+	uint8_t first_in_nextep_seq;
+
+	/** Frame number while entering to ISR - needed for ISOCs **/
+	uint32_t frame_num;
+
+};
+
+#ifdef DEBUG
+/*
+ * This function is called when transfer is timed out.
+ */
+extern void hc_xfer_timeout(void *ptr);
+#endif
+
+/*
+ * This function is called when transfer is timed out on endpoint.
+ */
+extern void ep_xfer_timeout(void *ptr);
+
+/*
+ * The following functions are functions for works
+ * using during handling some interrupts
+ */
+extern void w_conn_id_status_change(void *p);
+
+extern void w_wakeup_detected(void *p);
+
+/** Saves global register values into system memory. */
+extern int dwc_otg_save_global_regs(dwc_otg_core_if_t * core_if);
+/** Saves device register values into system memory. */
+extern int dwc_otg_save_dev_regs(dwc_otg_core_if_t * core_if);
+/** Saves host register values into system memory. */
+extern int dwc_otg_save_host_regs(dwc_otg_core_if_t * core_if);
+/** Restore global register values. */
+extern int dwc_otg_restore_global_regs(dwc_otg_core_if_t * core_if);
+/** Restore host register values. */
+extern int dwc_otg_restore_host_regs(dwc_otg_core_if_t * core_if, int reset);
+/** Restore device register values. */
+extern int dwc_otg_restore_dev_regs(dwc_otg_core_if_t * core_if,
+				    int rem_wakeup);
+extern int restore_lpm_i2c_regs(dwc_otg_core_if_t * core_if);
+extern int restore_essential_regs(dwc_otg_core_if_t * core_if, int rmode,
+				  int is_host);
+
+extern int dwc_otg_host_hibernation_restore(dwc_otg_core_if_t * core_if,
+					    int restore_mode, int reset);
+extern int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
+					      int rem_wakeup, int reset);
+
+/*
+ * The following functions support initialization of the CIL driver component
+ * and the DWC_otg controller.
+ */
+extern void dwc_otg_core_host_init(dwc_otg_core_if_t * _core_if);
+extern void dwc_otg_core_dev_init(dwc_otg_core_if_t * _core_if);
+
+/** @name Device CIL Functions
+ * The following functions support managing the DWC_otg controller in device
+ * mode.
+ */
+/**@{*/
+extern void dwc_otg_wakeup(dwc_otg_core_if_t * _core_if);
+extern void dwc_otg_read_setup_packet(dwc_otg_core_if_t * _core_if,
+				      uint32_t * _dest);
+extern uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t * _core_if);
+extern void dwc_otg_ep0_activate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
+extern void dwc_otg_ep_activate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
+extern void dwc_otg_ep_deactivate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
+extern void dwc_otg_ep_start_transfer(dwc_otg_core_if_t * _core_if,
+				      dwc_ep_t * _ep);
+extern void dwc_otg_ep_start_zl_transfer(dwc_otg_core_if_t * _core_if,
+					 dwc_ep_t * _ep);
+extern void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t * _core_if,
+				       dwc_ep_t * _ep);
+extern void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t * _core_if,
+					  dwc_ep_t * _ep);
+extern void dwc_otg_ep_write_packet(dwc_otg_core_if_t * _core_if,
+				    dwc_ep_t * _ep, int _dma);
+extern void dwc_otg_ep_set_stall(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
+extern void dwc_otg_ep_clear_stall(dwc_otg_core_if_t * _core_if,
+				   dwc_ep_t * _ep);
+extern void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t * _core_if);
+
+#ifdef DWC_EN_ISOC
+extern void dwc_otg_iso_ep_start_frm_transfer(dwc_otg_core_if_t * core_if,
+					      dwc_ep_t * ep);
+extern void dwc_otg_iso_ep_start_buf_transfer(dwc_otg_core_if_t * core_if,
+					      dwc_ep_t * ep);
+#endif /* DWC_EN_ISOC */
+/**@}*/
+
+/** @name Host CIL Functions
+ * The following functions support managing the DWC_otg controller in host
+ * mode.
+ */
+/**@{*/
+extern void dwc_otg_hc_init(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
+extern void dwc_otg_hc_halt(dwc_otg_core_if_t * _core_if,
+			    dwc_hc_t * _hc, dwc_otg_halt_status_e _halt_status);
+extern void dwc_otg_hc_cleanup(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
+extern void dwc_otg_hc_start_transfer(dwc_otg_core_if_t * _core_if,
+				      dwc_hc_t * _hc);
+extern int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t * _core_if,
+					dwc_hc_t * _hc);
+extern void dwc_otg_hc_do_ping(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
+extern void dwc_otg_hc_write_packet(dwc_otg_core_if_t * _core_if,
+				    dwc_hc_t * _hc);
+extern void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t * _core_if);
+extern void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t * _core_if);
+
+extern void dwc_otg_hc_start_transfer_ddma(dwc_otg_core_if_t * core_if,
+					   dwc_hc_t * hc);
+
+extern uint32_t calc_frame_interval(dwc_otg_core_if_t * core_if);
+
+/* Macro used to clear one channel interrupt */
+#define clear_hc_int(_hc_regs_, _intr_) \
+do { \
+	hcint_data_t hcint_clear = {.d32 = 0}; \
+	hcint_clear.b._intr_ = 1; \
+	DWC_WRITE_REG32(&(_hc_regs_)->hcint, hcint_clear.d32); \
+} while (0)
+
+/*
+ * Macro used to disable one channel interrupt. Channel interrupts are
+ * disabled when the channel is halted or released by the interrupt handler.
+ * There is no need to handle further interrupts of that type until the
+ * channel is re-assigned. In fact, subsequent handling may cause crashes
+ * because the channel structures are cleaned up when the channel is released.
+ */
+#define disable_hc_int(_hc_regs_, _intr_) \
+do { \
+	hcintmsk_data_t hcintmsk = {.d32 = 0}; \
+	hcintmsk.b._intr_ = 1; \
+	DWC_MODIFY_REG32(&(_hc_regs_)->hcintmsk, hcintmsk.d32, 0); \
+} while (0)
+
+/**
+ * This function Reads HPRT0 in preparation to modify. It keeps the
+ * WC bits 0 so that if they are read as 1, they won't clear when you
+ * write it back
+ */
+static inline uint32_t dwc_otg_read_hprt0(dwc_otg_core_if_t * _core_if)
+{
+	hprt0_data_t hprt0;
+	hprt0.d32 = DWC_READ_REG32(_core_if->host_if->hprt0);
+	hprt0.b.prtena = 0;
+	hprt0.b.prtconndet = 0;
+	hprt0.b.prtenchng = 0;
+	hprt0.b.prtovrcurrchng = 0;
+	return hprt0.d32;
+}
+
+/**@}*/
+
+/** @name Common CIL Functions
+ * The following functions support managing the DWC_otg controller in either
+ * device or host mode.
+ */
+/**@{*/
+
+extern void dwc_otg_read_packet(dwc_otg_core_if_t * core_if,
+				uint8_t * dest, uint16_t bytes);
+
+extern void dwc_otg_flush_tx_fifo(dwc_otg_core_if_t * _core_if, const int _num);
+extern void dwc_otg_flush_rx_fifo(dwc_otg_core_if_t * _core_if);
+extern void dwc_otg_core_reset(dwc_otg_core_if_t * _core_if);
+
+/**
+ * This function returns the Core Interrupt register.
+ */
+static inline uint32_t dwc_otg_read_core_intr(dwc_otg_core_if_t * core_if)
+{
+	return (DWC_READ_REG32(&core_if->core_global_regs->gintsts) &
+		DWC_READ_REG32(&core_if->core_global_regs->gintmsk));
+}
+
+/**
+ * This function returns the OTG Interrupt register.
+ */
+static inline uint32_t dwc_otg_read_otg_intr(dwc_otg_core_if_t * core_if)
+{
+	return (DWC_READ_REG32(&core_if->core_global_regs->gotgint));
+}
+
+/**
+ * This function reads the Device All Endpoints Interrupt register and
+ * returns the IN endpoint interrupt bits.
+ */
+static inline uint32_t dwc_otg_read_dev_all_in_ep_intr(dwc_otg_core_if_t *
+						       core_if)
+{
+
+	uint32_t v;
+
+	if (core_if->multiproc_int_enable) {
+		v = DWC_READ_REG32(&core_if->dev_if->
+				   dev_global_regs->deachint) &
+		    DWC_READ_REG32(&core_if->
+				   dev_if->dev_global_regs->deachintmsk);
+	} else {
+		v = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daint) &
+		    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daintmsk);
+	}
+	return (v & 0xffff);
+}
+
+/**
+ * This function reads the Device All Endpoints Interrupt register and
+ * returns the OUT endpoint interrupt bits.
+ */
+static inline uint32_t dwc_otg_read_dev_all_out_ep_intr(dwc_otg_core_if_t *
+							core_if)
+{
+	uint32_t v;
+
+	if (core_if->multiproc_int_enable) {
+		v = DWC_READ_REG32(&core_if->dev_if->
+				   dev_global_regs->deachint) &
+		    DWC_READ_REG32(&core_if->
+				   dev_if->dev_global_regs->deachintmsk);
+	} else {
+		v = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daint) &
+		    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daintmsk);
+	}
+
+	return ((v & 0xffff0000) >> 16);
+}
+
+/**
+ * This function returns the Device IN EP Interrupt register
+ */
+static inline uint32_t dwc_otg_read_dev_in_ep_intr(dwc_otg_core_if_t * core_if,
+						   dwc_ep_t * ep)
+{
+	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+	uint32_t v, msk, emp;
+
+	if (core_if->multiproc_int_enable) {
+		msk =
+		    DWC_READ_REG32(&dev_if->
+				   dev_global_regs->diepeachintmsk[ep->num]);
+		emp =
+		    DWC_READ_REG32(&dev_if->
+				   dev_global_regs->dtknqr4_fifoemptymsk);
+		msk |= ((emp >> ep->num) & 0x1) << 7;
+		v = DWC_READ_REG32(&dev_if->in_ep_regs[ep->num]->diepint) & msk;
+	} else {
+		msk = DWC_READ_REG32(&dev_if->dev_global_regs->diepmsk);
+		emp =
+		    DWC_READ_REG32(&dev_if->
+				   dev_global_regs->dtknqr4_fifoemptymsk);
+		msk |= ((emp >> ep->num) & 0x1) << 7;
+		v = DWC_READ_REG32(&dev_if->in_ep_regs[ep->num]->diepint) & msk;
+	}
+
+	return v;
+}
+
+/**
+ * This function returns the Device OUT EP Interrupt register
+ */
+static inline uint32_t dwc_otg_read_dev_out_ep_intr(dwc_otg_core_if_t *
+						    _core_if, dwc_ep_t * _ep)
+{
+	dwc_otg_dev_if_t *dev_if = _core_if->dev_if;
+	uint32_t v;
+	doepmsk_data_t msk = {.d32 = 0 };
+
+	if (_core_if->multiproc_int_enable) {
+		msk.d32 =
+		    DWC_READ_REG32(&dev_if->
+				   dev_global_regs->doepeachintmsk[_ep->num]);
+		if (_core_if->pti_enh_enable) {
+			msk.b.pktdrpsts = 1;
+		}
+		v = DWC_READ_REG32(&dev_if->
+				   out_ep_regs[_ep->num]->doepint) & msk.d32;
+	} else {
+		msk.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->doepmsk);
+		if (_core_if->pti_enh_enable) {
+			msk.b.pktdrpsts = 1;
+		}
+		v = DWC_READ_REG32(&dev_if->
+				   out_ep_regs[_ep->num]->doepint) & msk.d32;
+	}
+	return v;
+}
+
+/**
+ * This function returns the Host All Channel Interrupt register
+ */
+static inline uint32_t dwc_otg_read_host_all_channels_intr(dwc_otg_core_if_t *
+							   _core_if)
+{
+	return (DWC_READ_REG32(&_core_if->host_if->host_global_regs->haint));
+}
+
+static inline uint32_t dwc_otg_read_host_channel_intr(dwc_otg_core_if_t *
+						      _core_if, dwc_hc_t * _hc)
+{
+	return (DWC_READ_REG32
+		(&_core_if->host_if->hc_regs[_hc->hc_num]->hcint));
+}
+
+/**
+ * This function returns the mode of the operation, host or device.
+ *
+ * @return 0 - Device Mode, 1 - Host Mode
+ */
+static inline uint32_t dwc_otg_mode(dwc_otg_core_if_t * _core_if)
+{
+	return (DWC_READ_REG32(&_core_if->core_global_regs->gintsts) & 0x1);
+}
+
+/**@}*/
+
+/**
+ * DWC_otg CIL callback structure. This structure allows the HCD and
+ * PCD to register functions used for starting and stopping the PCD
+ * and HCD for role change on for a DRD.
+ */
+typedef struct dwc_otg_cil_callbacks {
+	/** Start function for role change */
+	int (*start) (void *_p);
+	/** Stop Function for role change */
+	int (*stop) (void *_p);
+	/** Disconnect Function for role change */
+	int (*disconnect) (void *_p);
+	/** Resume/Remote wakeup Function */
+	int (*resume_wakeup) (void *_p);
+	/** Suspend function */
+	int (*suspend) (void *_p);
+	/** Session Start (SRP) */
+	int (*session_start) (void *_p);
+#ifdef CONFIG_USB_DWC_OTG_LPM
+	/** Sleep (switch to L0 state) */
+	int (*sleep) (void *_p);
+#endif
+	/** Pointer passed to start() and stop() */
+	void *p;
+} dwc_otg_cil_callbacks_t;
+
+extern void dwc_otg_cil_register_pcd_callbacks(dwc_otg_core_if_t * _core_if,
+					       dwc_otg_cil_callbacks_t * _cb,
+					       void *_p);
+extern void dwc_otg_cil_register_hcd_callbacks(dwc_otg_core_if_t * _core_if,
+					       dwc_otg_cil_callbacks_t * _cb,
+					       void *_p);
+
+void dwc_otg_initiate_srp(dwc_otg_core_if_t * core_if);
+
+//////////////////////////////////////////////////////////////////////
+/** Start the HCD.  Helper function for using the HCD callbacks.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ */
+static inline void cil_hcd_start(dwc_otg_core_if_t * core_if)
+{
+	if (core_if->hcd_cb && core_if->hcd_cb->start) {
+		core_if->hcd_cb->start(core_if->hcd_cb->p);
+	}
+}
+
+/** Stop the HCD.  Helper function for using the HCD callbacks.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ */
+static inline void cil_hcd_stop(dwc_otg_core_if_t * core_if)
+{
+	if (core_if->hcd_cb && core_if->hcd_cb->stop) {
+		core_if->hcd_cb->stop(core_if->hcd_cb->p);
+	}
+}
+
+/** Disconnect the HCD.  Helper function for using the HCD callbacks.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ */
+static inline void cil_hcd_disconnect(dwc_otg_core_if_t * core_if)
+{
+	if (core_if->hcd_cb && core_if->hcd_cb->disconnect) {
+		core_if->hcd_cb->disconnect(core_if->hcd_cb->p);
+	}
+}
+
+/** Inform the HCD the a New Session has begun.  Helper function for
+ * using the HCD callbacks.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ */
+static inline void cil_hcd_session_start(dwc_otg_core_if_t * core_if)
+{
+	if (core_if->hcd_cb && core_if->hcd_cb->session_start) {
+		core_if->hcd_cb->session_start(core_if->hcd_cb->p);
+	}
+}
+
+#ifdef CONFIG_USB_DWC_OTG_LPM
+/**
+ * Inform the HCD about LPM sleep.
+ * Helper function for using the HCD callbacks.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ */
+static inline void cil_hcd_sleep(dwc_otg_core_if_t * core_if)
+{
+	if (core_if->hcd_cb && core_if->hcd_cb->sleep) {
+		core_if->hcd_cb->sleep(core_if->hcd_cb->p);
+	}
+}
+#endif
+
+/** Resume the HCD.  Helper function for using the HCD callbacks.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ */
+static inline void cil_hcd_resume(dwc_otg_core_if_t * core_if)
+{
+	if (core_if->hcd_cb && core_if->hcd_cb->resume_wakeup) {
+		core_if->hcd_cb->resume_wakeup(core_if->hcd_cb->p);
+	}
+}
+
+/** Start the PCD.  Helper function for using the PCD callbacks.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ */
+static inline void cil_pcd_start(dwc_otg_core_if_t * core_if)
+{
+	if (core_if->pcd_cb && core_if->pcd_cb->start) {
+		core_if->pcd_cb->start(core_if->pcd_cb->p);
+	}
+}
+
+/** Stop the PCD.  Helper function for using the PCD callbacks.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ */
+static inline void cil_pcd_stop(dwc_otg_core_if_t * core_if)
+{
+	if (core_if->pcd_cb && core_if->pcd_cb->stop) {
+		core_if->pcd_cb->stop(core_if->pcd_cb->p);
+	}
+}
+
+/** Suspend the PCD.  Helper function for using the PCD callbacks.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ */
+static inline void cil_pcd_suspend(dwc_otg_core_if_t * core_if)
+{
+	if (core_if->pcd_cb && core_if->pcd_cb->suspend) {
+		core_if->pcd_cb->suspend(core_if->pcd_cb->p);
+	}
+}
+
+/** Resume the PCD.  Helper function for using the PCD callbacks.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ */
+static inline void cil_pcd_resume(dwc_otg_core_if_t * core_if)
+{
+	if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
+		core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
+	}
+}
+
+//////////////////////////////////////////////////////////////////////
+
+#endif
diff --git a/drivers/usb/dwc_otg/dwc_otg_cil_intr.c b/drivers/usb/dwc_otg/dwc_otg_cil_intr.c
new file mode 100644
index 0000000..0581b49
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_cil_intr.c
@@ -0,0 +1,1393 @@
+/* ==========================================================================
+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil_intr.c $
+ * $Revision: #31 $
+ * $Date: 2011/10/24 $
+ * $Change: 1871286 $
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+/** @file
+ *
+ * The Core Interface Layer provides basic services for accessing and
+ * managing the DWC_otg hardware. These services are used by both the
+ * Host Controller Driver and the Peripheral Controller Driver.
+ *
+ * This file contains the Common Interrupt handlers.
+ */
+#include "dwc_os.h"
+#include "dwc_otg_regs.h"
+#include "dwc_otg_cil.h"
+#include "dwc_otg_driver.h"
+#include "dwc_otg_pcd.h"
+#include "dwc_otg_hcd.h"
+
+#ifdef DEBUG
+inline const char *op_state_str(dwc_otg_core_if_t * core_if)
+{
+	return (core_if->op_state == A_HOST ? "a_host" :
+		(core_if->op_state == A_SUSPEND ? "a_suspend" :
+		 (core_if->op_state == A_PERIPHERAL ? "a_peripheral" :
+		  (core_if->op_state == B_PERIPHERAL ? "b_peripheral" :
+		   (core_if->op_state == B_HOST ? "b_host" : "unknown")))));
+}
+#endif
+
+/** This function will log a debug message
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ */
+int32_t dwc_otg_handle_mode_mismatch_intr(dwc_otg_core_if_t * core_if)
+{
+	gintsts_data_t gintsts;
+	DWC_WARN("Mode Mismatch Interrupt: currently in %s mode\n",
+		 dwc_otg_mode(core_if) ? "Host" : "Device");
+
+	/* Clear interrupt */
+	gintsts.d32 = 0;
+	gintsts.b.modemismatch = 1;
+	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
+	return 1;
+}
+
+/**
+ * This function handles the OTG Interrupts. It reads the OTG
+ * Interrupt Register (GOTGINT) to determine what interrupt has
+ * occurred.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ */
+int32_t dwc_otg_handle_otg_intr(dwc_otg_core_if_t * core_if)
+{
+	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+	gotgint_data_t gotgint;
+	gotgctl_data_t gotgctl;
+	gintmsk_data_t gintmsk;
+	gpwrdn_data_t gpwrdn;
+
+	gotgint.d32 = DWC_READ_REG32(&global_regs->gotgint);
+	gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
+	DWC_DEBUGPL(DBG_CIL, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint.d32,
+		    op_state_str(core_if));
+
+	if (gotgint.b.sesenddet) {
+		DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
+			    "Session End Detected++ (%s)\n",
+			    op_state_str(core_if));
+		gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
+
+		if (core_if->op_state == B_HOST) {
+			cil_pcd_start(core_if);
+			core_if->op_state = B_PERIPHERAL;
+		} else {
+			/* If not B_HOST and Device HNP still set. HNP
+			 * Did not succeed!*/
+			if (gotgctl.b.devhnpen) {
+				DWC_DEBUGPL(DBG_ANY, "Session End Detected\n");
+				__DWC_ERROR("Device Not Connected/Responding!\n");
+			}
+
+			/* If Session End Detected the B-Cable has
+			 * been disconnected. */
+			/* Reset PCD and Gadget driver to a
+			 * clean state. */
+			core_if->lx_state = DWC_OTG_L0;
+			DWC_SPINUNLOCK(core_if->lock);
+			cil_pcd_stop(core_if);
+			DWC_SPINLOCK(core_if->lock);
+
+			if (core_if->adp_enable) {
+				if (core_if->power_down == 2) {
+					gpwrdn.d32 = 0;
+					gpwrdn.b.pwrdnswtch = 1;
+					DWC_MODIFY_REG32(&core_if->
+							 core_global_regs->
+							 gpwrdn, gpwrdn.d32, 0);
+				}
+
+				gpwrdn.d32 = 0;
+				gpwrdn.b.pmuintsel = 1;
+				gpwrdn.b.pmuactv = 1;
+				DWC_MODIFY_REG32(&core_if->core_global_regs->
+						 gpwrdn, 0, gpwrdn.d32);
+
+				dwc_otg_adp_sense_start(core_if);
+			}
+		}
+
+		gotgctl.d32 = 0;
+		gotgctl.b.devhnpen = 1;
+		DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
+	}
+	if (gotgint.b.sesreqsucstschng) {
+		DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
+			    "Session Reqeust Success Status Change++\n");
+		gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
+		if (gotgctl.b.sesreqscs) {
+
+			if ((core_if->core_params->phy_type ==
+			     DWC_PHY_TYPE_PARAM_FS) && (core_if->core_params->i2c_enable)) {
+				core_if->srp_success = 1;
+			} else {
+				DWC_SPINUNLOCK(core_if->lock);
+				cil_pcd_resume(core_if);
+				DWC_SPINLOCK(core_if->lock);
+				/* Clear Session Request */
+				gotgctl.d32 = 0;
+				gotgctl.b.sesreq = 1;
+				DWC_MODIFY_REG32(&global_regs->gotgctl,
+						 gotgctl.d32, 0);
+			}
+		}
+	}
+	if (gotgint.b.hstnegsucstschng) {
+		/* Print statements during the HNP interrupt handling
+		 * can cause it to fail.*/
+		gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
+		if (gotgctl.b.hstnegscs) {
+			if (dwc_otg_is_host_mode(core_if)) {
+				core_if->op_state = B_HOST;
+				/*
+				 * Need to disable SOF interrupt immediately.
+				 * When switching from device to host, the PCD
+				 * interrupt handler won't handle the
+				 * interrupt if host mode is already set. The
+				 * HCD interrupt handler won't get called if
+				 * the HCD state is HALT. This means that the
+				 * interrupt does not get handled and Linux
+				 * complains loudly.
+				 */
+				gintmsk.d32 = 0;
+				gintmsk.b.sofintr = 1;
+				DWC_MODIFY_REG32(&global_regs->gintmsk,
+						 gintmsk.d32, 0);
+				/* Call callback function with spin lock released */
+				DWC_SPINUNLOCK(core_if->lock);
+				cil_pcd_stop(core_if);
+				/*
+				 * Initialize the Core for Host mode.
+				 */
+				cil_hcd_start(core_if);
+				DWC_SPINLOCK(core_if->lock);
+				core_if->op_state = B_HOST;
+			}
+		} else {
+			gotgctl.d32 = 0;
+			gotgctl.b.hnpreq = 1;
+			gotgctl.b.devhnpen = 1;
+			DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
+			DWC_DEBUGPL(DBG_ANY, "HNP Failed\n");
+			__DWC_ERROR("Device Not Connected/Responding\n");
+		}
+	}
+	if (gotgint.b.hstnegdet) {
+		/* The disconnect interrupt is set at the same time as
+		 * Host Negotiation Detected.  During the mode
+		 * switch all interrupts are cleared so the disconnect
+		 * interrupt handler will not get executed.
+		 */
+		DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
+			    "Host Negotiation Detected++ (%s)\n",
+			    (dwc_otg_is_host_mode(core_if) ? "Host" :
+			     "Device"));
+		if (dwc_otg_is_device_mode(core_if)) {
+			DWC_DEBUGPL(DBG_ANY, "a_suspend->a_peripheral (%d)\n",
+				    core_if->op_state);
+			DWC_SPINUNLOCK(core_if->lock);
+			cil_hcd_disconnect(core_if);
+			cil_pcd_start(core_if);
+			DWC_SPINLOCK(core_if->lock);
+			core_if->op_state = A_PERIPHERAL;
+		} else {
+			/*
+			 * Need to disable SOF interrupt immediately. When
+			 * switching from device to host, the PCD interrupt
+			 * handler won't handle the interrupt if host mode is
+			 * already set. The HCD interrupt handler won't get
+			 * called if the HCD state is HALT. This means that
+			 * the interrupt does not get handled and Linux
+			 * complains loudly.
+			 */
+			gintmsk.d32 = 0;
+			gintmsk.b.sofintr = 1;
+			DWC_MODIFY_REG32(&global_regs->gintmsk, gintmsk.d32, 0);
+			DWC_SPINUNLOCK(core_if->lock);
+			cil_pcd_stop(core_if);
+			cil_hcd_start(core_if);
+			DWC_SPINLOCK(core_if->lock);
+			core_if->op_state = A_HOST;
+		}
+	}
+	if (gotgint.b.adevtoutchng) {
+		DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
+			    "A-Device Timeout Change++\n");
+	}
+	if (gotgint.b.debdone) {
+		DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " "Debounce Done++\n");
+	}
+
+	/* Clear GOTGINT */
+	DWC_WRITE_REG32(&core_if->core_global_regs->gotgint, gotgint.d32);
+
+	return 1;
+}
+
+void w_conn_id_status_change(void *p)
+{
+	dwc_otg_core_if_t *core_if = p;
+	uint32_t count = 0;
+	gotgctl_data_t gotgctl = {.d32 = 0 };
+
+	gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
+	DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32);
+	DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts);
+
+	/* B-Device connector (Device Mode) */
+	if (gotgctl.b.conidsts) {
+		/* Wait for switch to device mode. */
+		while (!dwc_otg_is_device_mode(core_if)) {
+			DWC_PRINTF("Waiting for Peripheral Mode, Mode=%s\n",
+				   (dwc_otg_is_host_mode(core_if) ? "Host" :
+				    "Peripheral"));
+			dwc_mdelay(100);
+			if (++count > 10000)
+				break;
+		}
+		DWC_ASSERT(++count < 10000,
+			   "Connection id status change timed out");
+		core_if->op_state = B_PERIPHERAL;
+		dwc_otg_core_init(core_if);
+		dwc_otg_enable_global_interrupts(core_if);
+		cil_pcd_start(core_if);
+	} else {
+		/* A-Device connector (Host Mode) */
+		while (!dwc_otg_is_host_mode(core_if)) {
+			DWC_PRINTF("Waiting for Host Mode, Mode=%s\n",
+				   (dwc_otg_is_host_mode(core_if) ? "Host" :
+				    "Peripheral"));
+			dwc_mdelay(100);
+			if (++count > 10000)
+				break;
+		}
+		DWC_ASSERT(++count < 10000,
+			   "Connection id status change timed out");
+		core_if->op_state = A_HOST;
+		/*
+		 * Initialize the Core for Host mode.
+		 */
+		dwc_otg_core_init(core_if);
+		dwc_otg_enable_global_interrupts(core_if);
+		cil_hcd_start(core_if);
+	}
+}
+
+/**
+ * This function handles the Connector ID Status Change Interrupt.  It
+ * reads the OTG Interrupt Register (GOTCTL) to determine whether this
+ * is a Device to Host Mode transition or a Host Mode to Device
+ * Transition. 
+ *
+ * This only occurs when the cable is connected/removed from the PHY
+ * connector.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ */
+int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t * core_if)
+{
+
+	/*
+	 * Need to disable SOF interrupt immediately. If switching from device
+	 * to host, the PCD interrupt handler won't handle the interrupt if
+	 * host mode is already set. The HCD interrupt handler won't get
+	 * called if the HCD state is HALT. This means that the interrupt does
+	 * not get handled and Linux complains loudly.
+	 */
+	gintmsk_data_t gintmsk = {.d32 = 0 };
+	gintsts_data_t gintsts = {.d32 = 0 };
+
+	gintmsk.b.sofintr = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
+
+	DWC_DEBUGPL(DBG_CIL,
+		    " ++Connector ID Status Change Interrupt++  (%s)\n",
+		    (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"));
+	
+	if (core_if->lock)
+		DWC_SPINUNLOCK(core_if->lock);
+
+	/*
+	 * Need to schedule a work, as there are possible DELAY function calls
+	 * Release lock before scheduling workq as it holds spinlock during scheduling
+	 */
+
+	DWC_WORKQ_SCHEDULE(core_if->wq_otg, w_conn_id_status_change,
+			   core_if, "connection id status change");
+	if (core_if->lock)
+		DWC_SPINLOCK(core_if->lock);
+
+	/* Set flag and clear interrupt */
+	gintsts.b.conidstschng = 1;
+	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
+
+	return 1;
+}
+
+/**
+ * This interrupt indicates that a device is initiating the Session
+ * Request Protocol to request the host to turn on bus power so a new
+ * session can begin. The handler responds by turning on bus power. If
+ * the DWC_otg controller is in low power mode, the handler brings the
+ * controller out of low power mode before turning on bus power.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ */
+int32_t dwc_otg_handle_session_req_intr(dwc_otg_core_if_t * core_if)
+{
+	gintsts_data_t gintsts;
+
+#ifndef DWC_HOST_ONLY
+	DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n");
+
+	if (dwc_otg_is_device_mode(core_if)) {
+		DWC_PRINTF("SRP: Device mode\n");
+	} else {
+		hprt0_data_t hprt0;
+		DWC_PRINTF("SRP: Host mode\n");
+
+		/* Turn on the port power bit. */
+		hprt0.d32 = dwc_otg_read_hprt0(core_if);
+		hprt0.b.prtpwr = 1;
+		DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+
+		/* Start the Connection timer. So a message can be displayed
+		 * if connect does not occur within 10 seconds. */
+		cil_hcd_session_start(core_if);
+	}
+#endif
+
+	/* Clear interrupt */
+	gintsts.d32 = 0;
+	gintsts.b.sessreqintr = 1;
+	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
+
+	return 1;
+}
+
+void w_wakeup_detected(void *p)
+{
+	dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) p;
+	/*
+	 * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
+	 * so that OPT tests pass with all PHYs).
+	 */
+	hprt0_data_t hprt0 = {.d32 = 0 };
+#if 0
+	pcgcctl_data_t pcgcctl = {.d32 = 0 };
+	/* Restart the Phy Clock */
+	pcgcctl.b.stoppclk = 1;
+	DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
+	dwc_udelay(10);
+#endif //0
+	hprt0.d32 = dwc_otg_read_hprt0(core_if);
+	DWC_DEBUGPL(DBG_ANY, "Resume: HPRT0=%0x\n", hprt0.d32);
+//      dwc_mdelay(70);
+	hprt0.b.prtres = 0;	/* Resume */
+	DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+	DWC_DEBUGPL(DBG_ANY, "Clear Resume: HPRT0=%0x\n",
+		    DWC_READ_REG32(core_if->host_if->hprt0));
+
+	cil_hcd_resume(core_if);
+
+	/** Change to L0 state*/
+	core_if->lx_state = DWC_OTG_L0;
+}
+
+/**
+ * This interrupt indicates that the DWC_otg controller has detected a
+ * resume or remote wakeup sequence. If the DWC_otg controller is in
+ * low power mode, the handler must brings the controller out of low
+ * power mode. The controller automatically begins resume
+ * signaling. The handler schedules a time to stop resume signaling.
+ */
+int32_t dwc_otg_handle_wakeup_detected_intr(dwc_otg_core_if_t * core_if)
+{
+	gintsts_data_t gintsts;
+
+	DWC_DEBUGPL(DBG_ANY,
+		    "++Resume and Remote Wakeup Detected Interrupt++\n");
+
+	DWC_PRINTF("%s lxstate = %d\n", __func__, core_if->lx_state);
+
+	if (dwc_otg_is_device_mode(core_if)) {
+		dctl_data_t dctl = {.d32 = 0 };
+		DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n",
+			    DWC_READ_REG32(&core_if->dev_if->
+					   dev_global_regs->dsts));
+		if (core_if->lx_state == DWC_OTG_L2) {
+#ifdef PARTIAL_POWER_DOWN
+			if (core_if->hwcfg4.b.power_optimiz) {
+				pcgcctl_data_t power = {.d32 = 0 };
+
+				power.d32 = DWC_READ_REG32(core_if->pcgcctl);
+				DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n",
+					    power.d32);
+
+				power.b.stoppclk = 0;
+				DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
+
+				power.b.pwrclmp = 0;
+				DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
+
+				power.b.rstpdwnmodule = 0;
+				DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
+			}
+#endif
+			/* Clear the Remote Wakeup Signaling */
+			dctl.b.rmtwkupsig = 1;
+			DWC_MODIFY_REG32(&core_if->dev_if->
+					 dev_global_regs->dctl, dctl.d32, 0);
+
+			DWC_SPINUNLOCK(core_if->lock);
+			if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
+				core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
+			}
+			DWC_SPINLOCK(core_if->lock);
+		} else {
+			glpmcfg_data_t lpmcfg;
+			lpmcfg.d32 =
+			    DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
+			lpmcfg.b.hird_thres &= (~(1 << 4));
+			DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg,
+					lpmcfg.d32);
+		}
+		/** Change to L0 state*/
+		core_if->lx_state = DWC_OTG_L0;
+	} else {
+		if (core_if->lx_state != DWC_OTG_L1) {
+			pcgcctl_data_t pcgcctl = {.d32 = 0 };
+
+			/* Restart the Phy Clock */
+			pcgcctl.b.stoppclk = 1;
+			DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
+			DWC_TIMER_SCHEDULE(core_if->wkp_timer, 71);
+		} else {
+			/** Change to L0 state*/
+			core_if->lx_state = DWC_OTG_L0;
+		}
+	}
+
+	/* Clear interrupt */
+	gintsts.d32 = 0;
+	gintsts.b.wkupintr = 1;
+	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
+
+	return 1;
+}
+
+/**
+ * This interrupt indicates that the Wakeup Logic has detected a
+ * Device disconnect.
+ */
+static int32_t dwc_otg_handle_pwrdn_disconnect_intr(dwc_otg_core_if_t *core_if)
+{
+	gpwrdn_data_t gpwrdn = { .d32 = 0 };
+	gpwrdn_data_t gpwrdn_temp = { .d32 = 0 };
+	gpwrdn_temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
+
+	DWC_PRINTF("%s called\n", __FUNCTION__);
+
+	if (!core_if->hibernation_suspend) {
+		DWC_PRINTF("Already exited from Hibernation\n");
+		return 1;
+	}
+
+	/* Switch on the voltage to the core */
+	gpwrdn.b.pwrdnswtch = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+	dwc_udelay(10);
+
+	/* Reset the core */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.pwrdnrstn = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+	dwc_udelay(10);
+
+	/* Disable power clamps*/
+	gpwrdn.d32 = 0;
+	gpwrdn.b.pwrdnclmp = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+
+	/* Remove reset the core signal */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.pwrdnrstn = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
+	dwc_udelay(10);
+
+	/* Disable PMU interrupt */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.pmuintsel = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+
+	core_if->hibernation_suspend = 0;
+
+	/* Disable PMU */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.pmuactv = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+	dwc_udelay(10);
+
+	if (gpwrdn_temp.b.idsts) {
+		core_if->op_state = B_PERIPHERAL;
+		dwc_otg_core_init(core_if);
+		dwc_otg_enable_global_interrupts(core_if);
+		cil_pcd_start(core_if);
+	} else {
+		core_if->op_state = A_HOST;
+		dwc_otg_core_init(core_if);
+		dwc_otg_enable_global_interrupts(core_if);
+		cil_hcd_start(core_if);
+	}
+
+	return 1;
+}
+
+/**
+ * This interrupt indicates that the Wakeup Logic has detected a
+ * remote wakeup sequence.
+ */
+static int32_t dwc_otg_handle_pwrdn_wakeup_detected_intr(dwc_otg_core_if_t * core_if)
+{
+	gpwrdn_data_t gpwrdn = {.d32 = 0 };
+	DWC_DEBUGPL(DBG_ANY,
+		    "++Powerdown Remote Wakeup Detected Interrupt++\n");
+
+	if (!core_if->hibernation_suspend) {
+		DWC_PRINTF("Already exited from Hibernation\n");
+		return 1;
+	}
+
+	gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
+	if (gpwrdn.b.idsts) {	// Device Mode
+		if ((core_if->power_down == 2)
+		    && (core_if->hibernation_suspend == 1)) {
+			dwc_otg_device_hibernation_restore(core_if, 0, 0);
+		}
+	} else {
+		if ((core_if->power_down == 2)
+		    && (core_if->hibernation_suspend == 1)) {
+			dwc_otg_host_hibernation_restore(core_if, 1, 0);
+		}
+	}
+	return 1;
+}
+
+static int32_t dwc_otg_handle_pwrdn_idsts_change(dwc_otg_device_t *otg_dev)
+{
+	gpwrdn_data_t gpwrdn = {.d32 = 0 };
+	gpwrdn_data_t gpwrdn_temp = {.d32 = 0 };
+	dwc_otg_core_if_t *core_if = otg_dev->core_if;
+
+	DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
+	gpwrdn_temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
+	if (core_if->power_down == 2)
+	{		
+		if (!core_if->hibernation_suspend) {
+			DWC_PRINTF("Already exited from Hibernation\n");
+			return 1;
+		}
+		DWC_DEBUGPL(DBG_ANY, "Exit from hibernation on ID sts change\n");
+		/* Switch on the voltage to the core */
+		gpwrdn.b.pwrdnswtch = 1;
+		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+		dwc_udelay(10);
+
+		/* Reset the core */
+		gpwrdn.d32 = 0;
+		gpwrdn.b.pwrdnrstn = 1;
+		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+		dwc_udelay(10);
+
+		/* Disable power clamps */
+		gpwrdn.d32 = 0;
+		gpwrdn.b.pwrdnclmp = 1;
+		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+
+		/* Remove reset the core signal */
+		gpwrdn.d32 = 0;
+		gpwrdn.b.pwrdnrstn = 1;
+		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
+		dwc_udelay(10);
+
+		/* Disable PMU interrupt */
+		gpwrdn.d32 = 0;
+		gpwrdn.b.pmuintsel = 1;
+		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+
+		/*Indicates that we are exiting from hibernation */
+		core_if->hibernation_suspend = 0;
+
+		/* Disable PMU */
+		gpwrdn.d32 = 0;
+		gpwrdn.b.pmuactv = 1;
+		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+		dwc_udelay(10);
+
+		gpwrdn.d32 = core_if->gr_backup->gpwrdn_local;
+		if (gpwrdn.b.dis_vbus == 1) {
+			gpwrdn.d32 = 0;
+			gpwrdn.b.dis_vbus = 1;
+			DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+		}
+
+		if (gpwrdn_temp.b.idsts) {
+			core_if->op_state = B_PERIPHERAL;
+			dwc_otg_core_init(core_if);
+			dwc_otg_enable_global_interrupts(core_if);
+			cil_pcd_start(core_if);
+		} else {
+			core_if->op_state = A_HOST;
+			dwc_otg_core_init(core_if);
+			dwc_otg_enable_global_interrupts(core_if);
+			cil_hcd_start(core_if);
+		}
+	}
+
+	if (core_if->adp_enable)
+	{
+		uint8_t is_host = 0;
+		DWC_SPINUNLOCK(core_if->lock);
+		/* Change the core_if's lock to hcd/pcd lock depend on mode? */
+#ifndef DWC_HOST_ONLY		
+		if (gpwrdn_temp.b.idsts)
+			core_if->lock = otg_dev->pcd->lock;
+#endif
+#ifndef DWC_DEVICE_ONLY
+		if (!gpwrdn_temp.b.idsts) {
+				core_if->lock = otg_dev->hcd->lock;	
+				is_host = 1;
+		}
+#endif
+		DWC_PRINTF("RESTART ADP\n");
+		if (core_if->adp.probe_enabled)		
+			dwc_otg_adp_probe_stop(core_if);
+		if (core_if->adp.sense_enabled)		
+			dwc_otg_adp_sense_stop(core_if);
+		if (core_if->adp.sense_timer_started)		
+			DWC_TIMER_CANCEL(core_if->adp.sense_timer);
+		if (core_if->adp.vbuson_timer_started)		
+			DWC_TIMER_CANCEL(core_if->adp.vbuson_timer);
+		core_if->adp.probe_timer_values[0] = -1;
+		core_if->adp.probe_timer_values[1] = -1;
+		core_if->adp.sense_timer_started = 0;
+		core_if->adp.vbuson_timer_started = 0;
+		core_if->adp.probe_counter = 0;
+		core_if->adp.gpwrdn = 0;
+		
+		/* Disable PMU and restart ADP */
+		gpwrdn_temp.d32 = 0;
+		gpwrdn_temp.b.pmuactv = 1;
+		gpwrdn_temp.b.pmuintsel = 1;
+		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+		DWC_PRINTF("Check point 1\n");
+		dwc_mdelay(110);
+		dwc_otg_adp_start(core_if, is_host);
+		DWC_SPINLOCK(core_if->lock);
+	}
+	
+
+	return 1;
+}
+
+static int32_t dwc_otg_handle_pwrdn_session_change(dwc_otg_core_if_t * core_if)
+{
+	gpwrdn_data_t gpwrdn = {.d32 = 0 };
+	int32_t otg_cap_param = core_if->core_params->otg_cap;
+	DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
+
+	gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
+	if (core_if->power_down == 2) {
+		if (!core_if->hibernation_suspend) {
+			DWC_PRINTF("Already exited from Hibernation\n");
+			return 1;
+		}
+
+		if ((otg_cap_param != DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE ||
+			 otg_cap_param != DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE) &&
+			gpwrdn.b.bsessvld == 0) {
+			/* Save gpwrdn register for further usage if stschng interrupt */
+			core_if->gr_backup->gpwrdn_local =
+				DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
+			/*Exit from ISR and wait for stschng interrupt with bsessvld = 1 */
+			return 1;
+		}
+
+		/* Switch on the voltage to the core */
+		gpwrdn.d32 = 0;
+		gpwrdn.b.pwrdnswtch = 1;
+		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+		dwc_udelay(10);
+
+		/* Reset the core */
+		gpwrdn.d32 = 0;
+		gpwrdn.b.pwrdnrstn = 1;
+		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+		dwc_udelay(10);
+
+		/* Disable power clamps */
+		gpwrdn.d32 = 0;
+		gpwrdn.b.pwrdnclmp = 1;
+		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+
+		/* Remove reset the core signal */
+		gpwrdn.d32 = 0;
+		gpwrdn.b.pwrdnrstn = 1;
+		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
+		dwc_udelay(10);
+
+		/* Disable PMU interrupt */
+		gpwrdn.d32 = 0;
+		gpwrdn.b.pmuintsel = 1;
+		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+		dwc_udelay(10);
+
+		/*Indicates that we are exiting from hibernation */
+		core_if->hibernation_suspend = 0;
+
+		/* Disable PMU */
+		gpwrdn.d32 = 0;
+		gpwrdn.b.pmuactv = 1;
+		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+		dwc_udelay(10);
+
+		core_if->op_state = B_PERIPHERAL;
+		dwc_otg_core_init(core_if);
+		dwc_otg_enable_global_interrupts(core_if);
+		cil_pcd_start(core_if);
+
+		if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE ||
+			otg_cap_param == DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE) {
+			/*
+			 * Initiate SRP after initial ADP probe.
+			 */
+			dwc_otg_initiate_srp(core_if);	
+		}
+	}
+
+	return 1;
+}
+/**
+ * This interrupt indicates that the Wakeup Logic has detected a
+ * status change either on IDDIG or BSessVld.
+ */
+static uint32_t dwc_otg_handle_pwrdn_stschng_intr(dwc_otg_device_t *otg_dev)
+{
+	int retval;
+	gpwrdn_data_t gpwrdn = {.d32 = 0 };
+	gpwrdn_data_t gpwrdn_temp = {.d32 = 0 };
+	dwc_otg_core_if_t *core_if = otg_dev->core_if;
+
+	DWC_PRINTF("%s called\n", __FUNCTION__);
+	
+	if (core_if->power_down == 2) {
+		if (core_if->hibernation_suspend <= 0) {
+			DWC_PRINTF("Already exited from Hibernation\n");
+			return 1;
+		} else
+			gpwrdn_temp.d32 = core_if->gr_backup->gpwrdn_local;
+
+	} else {
+		gpwrdn_temp.d32 = core_if->adp.gpwrdn;
+	}
+
+	gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
+	
+	if (gpwrdn.b.idsts ^ gpwrdn_temp.b.idsts) {
+		retval = dwc_otg_handle_pwrdn_idsts_change(otg_dev);
+	} else if (gpwrdn.b.bsessvld ^ gpwrdn_temp.b.bsessvld) {
+		retval = dwc_otg_handle_pwrdn_session_change(core_if);
+	}
+
+	return retval;
+}
+
+/**
+ * This interrupt indicates that the Wakeup Logic has detected a
+ * SRP.
+ */
+static int32_t dwc_otg_handle_pwrdn_srp_intr(dwc_otg_core_if_t * core_if)
+{
+	gpwrdn_data_t gpwrdn = {.d32 = 0 };
+
+	DWC_PRINTF("%s called\n", __FUNCTION__);
+
+	if (!core_if->hibernation_suspend) {
+		DWC_PRINTF("Already exited from Hibernation\n");
+		return 1;
+	}
+#ifdef DWC_DEV_SRPCAP
+	if (core_if->pwron_timer_started) {
+		core_if->pwron_timer_started = 0;
+		DWC_TIMER_CANCEL(core_if->pwron_timer);
+	}
+#endif
+
+	/* Switch on the voltage to the core */
+	gpwrdn.b.pwrdnswtch = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+	dwc_udelay(10);
+
+	/* Reset the core */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.pwrdnrstn = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+	dwc_udelay(10);
+
+	/* Disable power clamps */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.pwrdnclmp = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+
+	/* Remove reset the core signal */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.pwrdnrstn = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
+	dwc_udelay(10);
+
+	/* Disable PMU interrupt */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.pmuintsel = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+
+	/* Indicates that we are exiting from hibernation */
+	core_if->hibernation_suspend = 0;
+
+	/* Disable PMU */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.pmuactv = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+	dwc_udelay(10);
+
+	/* Programm Disable VBUS to 0 */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.dis_vbus = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+
+	/*Initialize the core as Host */
+	core_if->op_state = A_HOST;
+	dwc_otg_core_init(core_if);
+	dwc_otg_enable_global_interrupts(core_if);
+	cil_hcd_start(core_if);
+
+	return 1;
+}
+
+/** This interrupt indicates that restore command after Hibernation
+ * was completed by the core. */
+int32_t dwc_otg_handle_restore_done_intr(dwc_otg_core_if_t * core_if)
+{
+	pcgcctl_data_t pcgcctl;
+	DWC_DEBUGPL(DBG_ANY, "++Restore Done Interrupt++\n");
+
+	//TODO De-assert restore signal. 8.a
+	pcgcctl.d32 = DWC_READ_REG32(core_if->pcgcctl);
+	if (pcgcctl.b.restoremode == 1) {
+		gintmsk_data_t gintmsk = {.d32 = 0 };
+		/*
+		 * If restore mode is Remote Wakeup,
+		 * unmask Remote Wakeup interrupt.
+		 */
+		gintmsk.b.wkupintr = 1;
+		DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
+				 0, gintmsk.d32);
+	}
+
+	return 1;
+}
+
+/**
+ * This interrupt indicates that a device has been disconnected from
+ * the root port.
+ */
+int32_t dwc_otg_handle_disconnect_intr(dwc_otg_core_if_t * core_if)
+{
+	gintsts_data_t gintsts;
+
+	DWC_DEBUGPL(DBG_ANY, "++Disconnect Detected Interrupt++ (%s) %s\n",
+		    (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"),
+		    op_state_str(core_if));
+
+/** @todo Consolidate this if statement. */
+#ifndef DWC_HOST_ONLY
+	if (core_if->op_state == B_HOST) {
+		/* If in device mode Disconnect and stop the HCD, then
+		 * start the PCD. */
+		DWC_SPINUNLOCK(core_if->lock);
+		cil_hcd_disconnect(core_if);
+		cil_pcd_start(core_if);
+		DWC_SPINLOCK(core_if->lock);
+		core_if->op_state = B_PERIPHERAL;
+	} else if (dwc_otg_is_device_mode(core_if)) {
+		gotgctl_data_t gotgctl = {.d32 = 0 };
+		gotgctl.d32 =
+		    DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
+		if (gotgctl.b.hstsethnpen == 1) {
+			/* Do nothing, if HNP in process the OTG
+			 * interrupt "Host Negotiation Detected"
+			 * interrupt will do the mode switch.
+			 */
+		} else if (gotgctl.b.devhnpen == 0) {
+			/* If in device mode Disconnect and stop the HCD, then
+			 * start the PCD. */
+			DWC_SPINUNLOCK(core_if->lock);
+			cil_hcd_disconnect(core_if);
+			cil_pcd_start(core_if);
+			DWC_SPINLOCK(core_if->lock);
+			core_if->op_state = B_PERIPHERAL;
+		} else {
+			DWC_DEBUGPL(DBG_ANY, "!a_peripheral && !devhnpen\n");
+		}
+	} else {
+		if (core_if->op_state == A_HOST) {
+			/* A-Cable still connected but device disconnected. */
+			cil_hcd_disconnect(core_if);
+			if (core_if->adp_enable) {
+				gpwrdn_data_t gpwrdn = { .d32 = 0 };
+				cil_hcd_stop(core_if);
+				/* Enable Power Down Logic */
+				gpwrdn.b.pmuintsel = 1;
+				gpwrdn.b.pmuactv = 1;
+				DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
+				dwc_otg_adp_probe_start(core_if);
+
+				/* Power off the core */
+				if (core_if->power_down == 2) {
+					gpwrdn.d32 = 0;
+					gpwrdn.b.pwrdnswtch = 1;
+					DWC_MODIFY_REG32(&core_if->
+							 core_global_regs->
+							 gpwrdn, gpwrdn.d32, 0);
+				}
+			}
+		}
+	}
+#endif
+	/* Change to L3(OFF) state */
+	core_if->lx_state = DWC_OTG_L3;
+
+	gintsts.d32 = 0;
+	gintsts.b.disconnect = 1;
+	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
+	return 1;
+}
+
+/**
+ * This interrupt indicates that SUSPEND state has been detected on
+ * the USB.
+ *
+ * For HNP the USB Suspend interrupt signals the change from
+ * "a_peripheral" to "a_host".
+ *
+ * When power management is enabled the core will be put in low power
+ * mode.
+ */
+int32_t dwc_otg_handle_usb_suspend_intr(dwc_otg_core_if_t * core_if)
+{
+	dsts_data_t dsts;
+	gintsts_data_t gintsts;
+	dcfg_data_t dcfg;
+
+	DWC_DEBUGPL(DBG_ANY, "USB SUSPEND\n");
+
+	if (dwc_otg_is_device_mode(core_if)) {
+		/* Check the Device status register to determine if the Suspend
+		 * state is active. */
+		dsts.d32 =
+		    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
+		DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", dsts.d32);
+		DWC_DEBUGPL(DBG_PCD, "DSTS.Suspend Status=%d "
+			    "HWCFG4.power Optimize=%d\n",
+			    dsts.b.suspsts, core_if->hwcfg4.b.power_optimiz);
+
+#ifdef PARTIAL_POWER_DOWN
+/** @todo Add a module parameter for power management. */
+
+		if (dsts.b.suspsts && core_if->hwcfg4.b.power_optimiz) {
+			pcgcctl_data_t power = {.d32 = 0 };
+			DWC_DEBUGPL(DBG_CIL, "suspend\n");
+
+			power.b.pwrclmp = 1;
+			DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
+
+			power.b.rstpdwnmodule = 1;
+			DWC_MODIFY_REG32(core_if->pcgcctl, 0, power.d32);
+
+			power.b.stoppclk = 1;
+			DWC_MODIFY_REG32(core_if->pcgcctl, 0, power.d32);
+
+		} else {
+			DWC_DEBUGPL(DBG_ANY, "disconnect?\n");
+		}
+#endif
+		/* PCD callback for suspend. Release the lock inside of callback function */
+		cil_pcd_suspend(core_if);
+		if (core_if->power_down == 2)
+		{
+			dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
+			DWC_DEBUGPL(DBG_ANY,"lx_state = %08x\n",core_if->lx_state);
+			DWC_DEBUGPL(DBG_ANY," device address = %08d\n",dcfg.b.devaddr);
+
+			if (core_if->lx_state != DWC_OTG_L3 && dcfg.b.devaddr) {
+				pcgcctl_data_t pcgcctl = {.d32 = 0 };
+				gpwrdn_data_t gpwrdn = {.d32 = 0 };
+				gusbcfg_data_t gusbcfg = {.d32 = 0 };
+
+				/* Change to L2(suspend) state */
+				core_if->lx_state = DWC_OTG_L2;
+
+				/* Clear interrupt in gintsts */
+				gintsts.d32 = 0;
+				gintsts.b.usbsuspend = 1;
+				DWC_WRITE_REG32(&core_if->core_global_regs->
+						gintsts, gintsts.d32);
+				DWC_PRINTF("Start of hibernation completed\n");
+				dwc_otg_save_global_regs(core_if);
+				dwc_otg_save_dev_regs(core_if);
+
+				gusbcfg.d32 =
+				    DWC_READ_REG32(&core_if->core_global_regs->
+						   gusbcfg);
+				if (gusbcfg.b.ulpi_utmi_sel == 1) {
+					/* ULPI interface */
+					/* Suspend the Phy Clock */
+					pcgcctl.d32 = 0;
+					pcgcctl.b.stoppclk = 1;
+					DWC_MODIFY_REG32(core_if->pcgcctl, 0,
+							 pcgcctl.d32);
+					dwc_udelay(10);
+					gpwrdn.b.pmuactv = 1;
+					DWC_MODIFY_REG32(&core_if->
+							 core_global_regs->
+							 gpwrdn, 0, gpwrdn.d32);
+				} else {
+					/* UTMI+ Interface */
+					gpwrdn.b.pmuactv = 1;
+					DWC_MODIFY_REG32(&core_if->
+							 core_global_regs->
+							 gpwrdn, 0, gpwrdn.d32);
+					dwc_udelay(10);
+					pcgcctl.b.stoppclk = 1;
+					DWC_MODIFY_REG32(core_if->pcgcctl, 0,
+							 pcgcctl.d32);
+					dwc_udelay(10);
+				}
+
+				/* Set flag to indicate that we are in hibernation */
+				core_if->hibernation_suspend = 1;
+				/* Enable interrupts from wake up logic */
+				gpwrdn.d32 = 0;
+				gpwrdn.b.pmuintsel = 1;
+				DWC_MODIFY_REG32(&core_if->core_global_regs->
+						 gpwrdn, 0, gpwrdn.d32);
+				dwc_udelay(10);
+
+				/* Unmask device mode interrupts in GPWRDN */
+				gpwrdn.d32 = 0;
+				gpwrdn.b.rst_det_msk = 1;
+				gpwrdn.b.lnstchng_msk = 1;
+				gpwrdn.b.sts_chngint_msk = 1;
+				DWC_MODIFY_REG32(&core_if->core_global_regs->
+						 gpwrdn, 0, gpwrdn.d32);
+				dwc_udelay(10);
+
+				/* Enable Power Down Clamp */
+				gpwrdn.d32 = 0;
+				gpwrdn.b.pwrdnclmp = 1;
+				DWC_MODIFY_REG32(&core_if->core_global_regs->
+						 gpwrdn, 0, gpwrdn.d32);
+				dwc_udelay(10);
+
+				/* Switch off VDD */
+				gpwrdn.d32 = 0;
+				gpwrdn.b.pwrdnswtch = 1;
+				DWC_MODIFY_REG32(&core_if->core_global_regs->
+						 gpwrdn, 0, gpwrdn.d32);
+
+				/* Save gpwrdn register for further usage if stschng interrupt */
+				core_if->gr_backup->gpwrdn_local =
+							DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
+				DWC_PRINTF("Hibernation completed\n");
+
+				return 1;
+			}
+		}
+	} else {
+		if (core_if->op_state == A_PERIPHERAL) {
+			DWC_DEBUGPL(DBG_ANY, "a_peripheral->a_host\n");
+			/* Clear the a_peripheral flag, back to a_host. */
+			DWC_SPINUNLOCK(core_if->lock);
+			cil_pcd_stop(core_if);
+			cil_hcd_start(core_if);
+			DWC_SPINLOCK(core_if->lock);
+			core_if->op_state = A_HOST;
+		}
+	}
+
+	/* Change to L2(suspend) state */
+	core_if->lx_state = DWC_OTG_L2;
+
+	/* Clear interrupt */
+	gintsts.d32 = 0;
+	gintsts.b.usbsuspend = 1;
+	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
+
+	return 1;
+}
+
+#ifdef CONFIG_USB_DWC_OTG_LPM
+/**
+ * This function hadles LPM transaction received interrupt.
+ */
+static int32_t dwc_otg_handle_lpm_intr(dwc_otg_core_if_t * core_if)
+{
+	glpmcfg_data_t lpmcfg;
+	gintsts_data_t gintsts;
+
+	if (!core_if->core_params->lpm_enable) {
+		DWC_PRINTF("Unexpected LPM interrupt\n");
+	}
+
+	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
+	DWC_PRINTF("LPM config register = 0x%08x\n", lpmcfg.d32);
+
+	if (dwc_otg_is_host_mode(core_if)) {
+		cil_hcd_sleep(core_if);
+	} else {
+		lpmcfg.b.hird_thres |= (1 << 4);
+		DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg,
+				lpmcfg.d32);
+	}
+
+	/* Examine prt_sleep_sts after TL1TokenTetry period max (10 us) */
+	dwc_udelay(10);
+	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
+	if (lpmcfg.b.prt_sleep_sts) {
+		/* Save the current state */
+		core_if->lx_state = DWC_OTG_L1;
+	}
+
+	/* Clear interrupt  */
+	gintsts.d32 = 0;
+	gintsts.b.lpmtranrcvd = 1;
+	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
+	return 1;
+}
+#endif /* CONFIG_USB_DWC_OTG_LPM */
+
+/**
+ * This function returns the Core Interrupt register.
+ */
+static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if)
+{
+	gahbcfg_data_t gahbcfg = {.d32 = 0 };
+	gintsts_data_t gintsts;
+	gintmsk_data_t gintmsk;
+	gintmsk_data_t gintmsk_common = {.d32 = 0 };
+	gintmsk_common.b.wkupintr = 1;
+	gintmsk_common.b.sessreqintr = 1;
+	gintmsk_common.b.conidstschng = 1;
+	gintmsk_common.b.otgintr = 1;
+	gintmsk_common.b.modemismatch = 1;
+	gintmsk_common.b.disconnect = 1;
+	gintmsk_common.b.usbsuspend = 1;
+#ifdef CONFIG_USB_DWC_OTG_LPM
+	gintmsk_common.b.lpmtranrcvd = 1;
+#endif
+	gintmsk_common.b.restoredone = 1;
+	/** @todo: The port interrupt occurs while in device
+         * mode. Added code to CIL to clear the interrupt for now!
+         */
+	gintmsk_common.b.portintr = 1;
+
+	gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
+	gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
+	gahbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gahbcfg);
+
+#ifdef DEBUG
+	/* if any common interrupts set */
+	if (gintsts.d32 & gintmsk_common.d32) {
+		DWC_DEBUGPL(DBG_ANY, "gintsts=%08x  gintmsk=%08x\n",
+			    gintsts.d32, gintmsk.d32);
+	}
+#endif
+	if (gahbcfg.b.glblintrmsk)	
+		return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32);
+	else
+		return 0;
+
+}
+
+/* MACRO for clearing interupt bits in GPWRDN register */
+#define CLEAR_GPWRDN_INTR(__core_if,__intr) \
+do { \
+		gpwrdn_data_t gpwrdn = {.d32=0}; \
+		gpwrdn.b.__intr = 1; \
+		DWC_MODIFY_REG32(&__core_if->core_global_regs->gpwrdn, \
+		0, gpwrdn.d32); \
+} while (0)
+
+/**
+ * Common interrupt handler.
+ *
+ * The common interrupts are those that occur in both Host and Device mode.
+ * This handler handles the following interrupts:
+ * - Mode Mismatch Interrupt
+ * - Disconnect Interrupt
+ * - OTG Interrupt
+ * - Connector ID Status Change Interrupt
+ * - Session Request Interrupt.
+ * - Resume / Remote Wakeup Detected Interrupt.
+ * - LPM Transaction Received Interrupt
+ * - ADP Transaction Received Interrupt
+ *
+ */
+int32_t dwc_otg_handle_common_intr(void *dev)
+{
+	int retval = 0;
+	gintsts_data_t gintsts;
+	gpwrdn_data_t gpwrdn = {.d32 = 0 };
+	dwc_otg_device_t *otg_dev = dev;
+	dwc_otg_core_if_t *core_if = otg_dev->core_if;
+	gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
+	if (dwc_otg_is_device_mode(core_if))
+		core_if->frame_num = dwc_otg_get_frame_number(core_if);
+		
+	if (core_if->lock)
+		DWC_SPINLOCK(core_if->lock);
+
+	if (core_if->hibernation_suspend <= 0) {
+		gintsts.d32 = dwc_otg_read_common_intr(core_if);
+
+		if (gintsts.b.modemismatch) {
+			retval |= dwc_otg_handle_mode_mismatch_intr(core_if);
+		}
+		if (gintsts.b.otgintr) {
+			retval |= dwc_otg_handle_otg_intr(core_if);
+		}
+		if (gintsts.b.conidstschng) {
+			retval |= dwc_otg_handle_conn_id_status_change_intr(core_if);
+		}
+		if (gintsts.b.disconnect) {
+			retval |= dwc_otg_handle_disconnect_intr(core_if);
+		}
+		if (gintsts.b.sessreqintr) {
+			retval |= dwc_otg_handle_session_req_intr(core_if);
+		}
+		if (gintsts.b.wkupintr) {
+			retval |= dwc_otg_handle_wakeup_detected_intr(core_if);
+		}
+		if (gintsts.b.usbsuspend) {
+			retval |= dwc_otg_handle_usb_suspend_intr(core_if);
+		}
+#ifdef CONFIG_USB_DWC_OTG_LPM
+		if (gintsts.b.lpmtranrcvd) {
+			retval |= dwc_otg_handle_lpm_intr(core_if);
+		}
+#endif
+		if (gintsts.b.restoredone) {
+			gintsts.d32 = 0;
+	                if (core_if->power_down == 2)
+				core_if->hibernation_suspend = -1;
+			gintsts.b.restoredone = 1;
+			DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,gintsts.d32);
+			DWC_PRINTF(" --Restore done interrupt received-- \n");
+			retval |= 1;
+		}
+		if (gintsts.b.portintr && dwc_otg_is_device_mode(core_if)) {
+			/* The port interrupt occurs while in device mode with HPRT0
+			 * Port Enable/Disable.
+			 */
+			gintsts.d32 = 0;
+			gintsts.b.portintr = 1;
+			DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,gintsts.d32);
+			retval |= 1;
+
+		}
+	} else {
+		DWC_DEBUGPL(DBG_ANY, "gpwrdn=%08x\n", gpwrdn.d32);
+
+		if (gpwrdn.b.disconn_det && gpwrdn.b.disconn_det_msk) {
+			CLEAR_GPWRDN_INTR(core_if, disconn_det);
+			if (gpwrdn.b.linestate == 0) {
+				dwc_otg_handle_pwrdn_disconnect_intr(core_if);
+			} else {
+				DWC_PRINTF("Disconnect detected while linestate is not 0\n");
+			}
+
+			retval |= 1;
+		}
+	 	if (gpwrdn.b.lnstschng && gpwrdn.b.lnstchng_msk) {
+			CLEAR_GPWRDN_INTR(core_if, lnstschng);
+			/* remote wakeup from hibernation */
+			if (gpwrdn.b.linestate == 2 || gpwrdn.b.linestate == 1) {
+				dwc_otg_handle_pwrdn_wakeup_detected_intr(core_if);
+			} else {
+				DWC_PRINTF("gpwrdn.linestate = %d\n", gpwrdn.b.linestate);
+			}
+			retval |= 1;
+	 	}
+		if (gpwrdn.b.rst_det && gpwrdn.b.rst_det_msk) {
+			CLEAR_GPWRDN_INTR(core_if, rst_det);
+			if (gpwrdn.b.linestate == 0) {
+				DWC_PRINTF("Reset detected\n");
+				retval |= dwc_otg_device_hibernation_restore(core_if, 0, 1);
+			}
+		}
+		if (gpwrdn.b.srp_det && gpwrdn.b.srp_det_msk) {
+			CLEAR_GPWRDN_INTR(core_if, srp_det);
+			dwc_otg_handle_pwrdn_srp_intr(core_if);
+			retval |= 1;
+		}
+	}
+	/* Handle ADP interrupt here */
+	if (gpwrdn.b.adp_int) {
+		DWC_PRINTF("ADP interrupt\n");
+		CLEAR_GPWRDN_INTR(core_if, adp_int);
+		dwc_otg_adp_handle_intr(core_if);
+		retval |= 1;
+	}
+	if (gpwrdn.b.sts_chngint && gpwrdn.b.sts_chngint_msk) {
+		DWC_PRINTF("STS CHNG interrupt asserted\n");
+		CLEAR_GPWRDN_INTR(core_if, sts_chngint);
+		dwc_otg_handle_pwrdn_stschng_intr(otg_dev);
+
+		retval |= 1;
+	}
+	if (core_if->lock)
+		DWC_SPINUNLOCK(core_if->lock);
+
+	return retval;
+}
diff --git a/drivers/usb/dwc_otg/dwc_otg_core_if.h b/drivers/usb/dwc_otg/dwc_otg_core_if.h
new file mode 100644
index 0000000..30f52fe
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_core_if.h
@@ -0,0 +1,699 @@
+/* ==========================================================================
+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_core_if.h $
+ * $Revision: #12 $
+ * $Date: 2011/10/24 $
+ * $Change: 1871159 $
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+#if !defined(__DWC_CORE_IF_H__)
+#define __DWC_CORE_IF_H__
+
+#include "dwc_os.h"
+
+/** @file
+ * This file defines DWC_OTG Core API
+ */
+
+struct dwc_otg_core_if;
+typedef struct dwc_otg_core_if dwc_otg_core_if_t;
+
+/** Maximum number of Periodic FIFOs */
+#define MAX_PERIO_FIFOS 15
+/** Maximum number of Periodic FIFOs */
+#define MAX_TX_FIFOS 15
+
+/** Maximum number of Endpoints/HostChannels */
+#define MAX_EPS_CHANNELS 16
+
+extern dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t * _reg_base_addr);
+extern void dwc_otg_core_init(dwc_otg_core_if_t * _core_if);
+extern void dwc_otg_cil_remove(dwc_otg_core_if_t * _core_if);
+
+extern void dwc_otg_enable_global_interrupts(dwc_otg_core_if_t * _core_if);
+extern void dwc_otg_disable_global_interrupts(dwc_otg_core_if_t * _core_if);
+
+extern uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t * _core_if);
+extern uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t * _core_if);
+
+extern uint8_t dwc_otg_is_dma_enable(dwc_otg_core_if_t * core_if);
+
+/** This function should be called on every hardware interrupt. */
+extern int32_t dwc_otg_handle_common_intr(void *otg_dev);
+
+/** @name OTG Core Parameters */
+/** @{ */
+
+/**
+ * Specifies the OTG capabilities. The driver will automatically
+ * detect the value for this parameter if none is specified.
+ * 0 - HNP and SRP capable (default)
+ * 1 - SRP Only capable
+ * 2 - No HNP/SRP capable
+ */
+extern int dwc_otg_set_param_otg_cap(dwc_otg_core_if_t * core_if, int32_t val);
+extern int32_t dwc_otg_get_param_otg_cap(dwc_otg_core_if_t * core_if);
+#define DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE 0
+#define DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE 1
+#define DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE 2
+#define dwc_param_otg_cap_default DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE
+
+extern int dwc_otg_set_param_opt(dwc_otg_core_if_t * core_if, int32_t val);
+extern int32_t dwc_otg_get_param_opt(dwc_otg_core_if_t * core_if);
+#define dwc_param_opt_default 1
+
+/**
+ * Specifies whether to use slave or DMA mode for accessing the data
+ * FIFOs. The driver will automatically detect the value for this
+ * parameter if none is specified.
+ * 0 - Slave
+ * 1 - DMA (default, if available)
+ */
+extern int dwc_otg_set_param_dma_enable(dwc_otg_core_if_t * core_if,
+					int32_t val);
+extern int32_t dwc_otg_get_param_dma_enable(dwc_otg_core_if_t * core_if);
+#define dwc_param_dma_enable_default 1
+
+/**
+ * When DMA mode is enabled specifies whether to use
+ * address DMA or DMA Descritor mode for accessing the data
+ * FIFOs in device mode. The driver will automatically detect
+ * the value for this parameter if none is specified.
+ * 0 - address DMA
+ * 1 - DMA Descriptor(default, if available)
+ */
+extern int dwc_otg_set_param_dma_desc_enable(dwc_otg_core_if_t * core_if,
+					     int32_t val);
+extern int32_t dwc_otg_get_param_dma_desc_enable(dwc_otg_core_if_t * core_if);
+#define dwc_param_dma_desc_enable_default 0
+
+/** The DMA Burst size (applicable only for External DMA
+ * Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32)
+ */
+extern int dwc_otg_set_param_dma_burst_size(dwc_otg_core_if_t * core_if,
+					    int32_t val);
+extern int32_t dwc_otg_get_param_dma_burst_size(dwc_otg_core_if_t * core_if);
+#define dwc_param_dma_burst_size_default 32
+
+/**
+ * Specifies the maximum speed of operation in host and device mode.
+ * The actual speed depends on the speed of the attached device and
+ * the value of phy_type. The actual speed depends on the speed of the
+ * attached device.
+ * 0 - High Speed (default)
+ * 1 - Full Speed
+ */
+extern int dwc_otg_set_param_speed(dwc_otg_core_if_t * core_if, int32_t val);
+extern int32_t dwc_otg_get_param_speed(dwc_otg_core_if_t * core_if);
+#define dwc_param_speed_default 0
+#define DWC_SPEED_PARAM_HIGH 0
+#define DWC_SPEED_PARAM_FULL 1
+
+/** Specifies whether low power mode is supported when attached
+ *	to a Full Speed or Low Speed device in host mode.
+ * 0 - Don't support low power mode (default)
+ * 1 - Support low power mode
+ */
+extern int dwc_otg_set_param_host_support_fs_ls_low_power(dwc_otg_core_if_t *
+							  core_if, int32_t val);
+extern int32_t dwc_otg_get_param_host_support_fs_ls_low_power(dwc_otg_core_if_t
+							      * core_if);
+#define dwc_param_host_support_fs_ls_low_power_default 0
+
+/** Specifies the PHY clock rate in low power mode when connected to a
+ * Low Speed device in host mode. This parameter is applicable only if
+ * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS
+ * then defaults to 6 MHZ otherwise 48 MHZ.
+ *
+ * 0 - 48 MHz
+ * 1 - 6 MHz
+ */
+extern int dwc_otg_set_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t *
+						       core_if, int32_t val);
+extern int32_t dwc_otg_get_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t *
+							   core_if);
+#define dwc_param_host_ls_low_power_phy_clk_default 0
+#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0
+#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1
+
+/**
+ * 0 - Use cC FIFO size parameters
+ * 1 - Allow dynamic FIFO sizing (default)
+ */
+extern int dwc_otg_set_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if,
+						 int32_t val);
+extern int32_t dwc_otg_get_param_enable_dynamic_fifo(dwc_otg_core_if_t *
+						     core_if);
+#define dwc_param_enable_dynamic_fifo_default 1
+
+/** Total number of 4-byte words in the data FIFO memory. This
+ * memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic
+ * Tx FIFOs.
+ * 32 to 32768 (default 8192)
+ * Note: The total FIFO memory depth in the FPGA configuration is 8192.
+ */
+extern int dwc_otg_set_param_data_fifo_size(dwc_otg_core_if_t * core_if,
+					    int32_t val);
+extern int32_t dwc_otg_get_param_data_fifo_size(dwc_otg_core_if_t * core_if);
+#define dwc_param_data_fifo_size_default 8192
+
+/** Number of 4-byte words in the Rx FIFO in device mode when dynamic
+ * FIFO sizing is enabled.
+ * 16 to 32768 (default 1064)
+ */
+extern int dwc_otg_set_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if,
+					      int32_t val);
+extern int32_t dwc_otg_get_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if);
+#define dwc_param_dev_rx_fifo_size_default 1064
+
+/** Number of 4-byte words in the non-periodic Tx FIFO in device mode
+ * when dynamic FIFO sizing is enabled.
+ * 16 to 32768 (default 1024)
+ */
+extern int dwc_otg_set_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t *
+						     core_if, int32_t val);
+extern int32_t dwc_otg_get_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t *
+							 core_if);
+#define dwc_param_dev_nperio_tx_fifo_size_default 1024
+
+/** Number of 4-byte words in each of the periodic Tx FIFOs in device
+ * mode when dynamic FIFO sizing is enabled.
+ * 4 to 768 (default 256)
+ */
+extern int dwc_otg_set_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
+						    int32_t val, int fifo_num);
+extern int32_t dwc_otg_get_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t *
+							core_if, int fifo_num);
+#define dwc_param_dev_perio_tx_fifo_size_default 256
+
+/** Number of 4-byte words in the Rx FIFO in host mode when dynamic
+ * FIFO sizing is enabled.
+ * 16 to 32768 (default 1024)
+ */
+extern int dwc_otg_set_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if,
+					       int32_t val);
+extern int32_t dwc_otg_get_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if);
+#define dwc_param_host_rx_fifo_size_default 776
+
+
+/** Number of 4-byte words in the non-periodic Tx FIFO in host mode
+ * when Dynamic FIFO sizing is enabled in the core.
+ * 16 to 32768 (default 1024)
+ */
+extern int dwc_otg_set_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t *
+						      core_if, int32_t val);
+extern int32_t dwc_otg_get_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t *
+							  core_if);
+#define dwc_param_host_nperio_tx_fifo_size_default 512
+
+/** Number of 4-byte words in the host periodic Tx FIFO when dynamic
+ * FIFO sizing is enabled.
+ * 16 to 32768 (default 1024)
+ */
+extern int dwc_otg_set_param_host_perio_tx_fifo_size(dwc_otg_core_if_t *
+						     core_if, int32_t val);
+extern int32_t dwc_otg_get_param_host_perio_tx_fifo_size(dwc_otg_core_if_t *
+							 core_if);
+#define dwc_param_host_perio_tx_fifo_size_default 768
+
+/** The maximum transfer size supported in bytes.
+ * 2047 to 65,535  (default 65,535)
+ */
+extern int dwc_otg_set_param_max_transfer_size(dwc_otg_core_if_t * core_if,
+					       int32_t val);
+extern int32_t dwc_otg_get_param_max_transfer_size(dwc_otg_core_if_t * core_if);
+#define dwc_param_max_transfer_size_default 65535
+
+/** The maximum number of packets in a transfer.
+ * 15 to 511  (default 511)
+ */
+extern int dwc_otg_set_param_max_packet_count(dwc_otg_core_if_t * core_if,
+					      int32_t val);
+extern int32_t dwc_otg_get_param_max_packet_count(dwc_otg_core_if_t * core_if);
+#define dwc_param_max_packet_count_default 511
+
+/** The number of host channel registers to use.
+ * 1 to 16 (default 12)
+ * Note: The FPGA configuration supports a maximum of 12 host channels.
+ */
+extern int dwc_otg_set_param_host_channels(dwc_otg_core_if_t * core_if,
+					   int32_t val);
+extern int32_t dwc_otg_get_param_host_channels(dwc_otg_core_if_t * core_if);
+#define dwc_param_host_channels_default 14
+
+/** The number of endpoints in addition to EP0 available for device
+ * mode operations.
+ * 1 to 15 (default 6 IN and OUT)
+ * Note: The FPGA configuration supports a maximum of 6 IN and OUT
+ * endpoints in addition to EP0.
+ */
+extern int dwc_otg_set_param_dev_endpoints(dwc_otg_core_if_t * core_if,
+					   int32_t val);
+extern int32_t dwc_otg_get_param_dev_endpoints(dwc_otg_core_if_t * core_if);
+#define dwc_param_dev_endpoints_default 7
+
+/**
+ * Specifies the type of PHY interface to use. By default, the driver
+ * will automatically detect the phy_type.
+ *
+ * 0 - Full Speed PHY
+ * 1 - UTMI+ (default)
+ * 2 - ULPI
+ */
+extern int dwc_otg_set_param_phy_type(dwc_otg_core_if_t * core_if, int32_t val);
+extern int32_t dwc_otg_get_param_phy_type(dwc_otg_core_if_t * core_if);
+#define DWC_PHY_TYPE_PARAM_FS 0
+#define DWC_PHY_TYPE_PARAM_UTMI 1
+#define DWC_PHY_TYPE_PARAM_ULPI 2
+#define dwc_param_phy_type_default DWC_PHY_TYPE_PARAM_UTMI
+
+/**
+ * Specifies the UTMI+ Data Width. This parameter is
+ * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI
+ * PHY_TYPE, this parameter indicates the data width between
+ * the MAC and the ULPI Wrapper.) Also, this parameter is
+ * applicable only if the OTG_HSPHY_WIDTH cC parameter was set
+ * to "8 and 16 bits", meaning that the core has been
+ * configured to work at either data path width.
+ *
+ * 8 or 16 bits (default 16)
+ */
+extern int dwc_otg_set_param_phy_utmi_width(dwc_otg_core_if_t * core_if,
+					    int32_t val);
+extern int32_t dwc_otg_get_param_phy_utmi_width(dwc_otg_core_if_t * core_if);
+#define dwc_param_phy_utmi_width_default 16
+
+/**
+ * Specifies whether the ULPI operates at double or single
+ * data rate. This parameter is only applicable if PHY_TYPE is
+ * ULPI.
+ *
+ * 0 - single data rate ULPI interface with 8 bit wide data
+ * bus (default)
+ * 1 - double data rate ULPI interface with 4 bit wide data
+ * bus
+ */
+extern int dwc_otg_set_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if,
+					  int32_t val);
+extern int32_t dwc_otg_get_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if);
+#define dwc_param_phy_ulpi_ddr_default 0
+
+/**
+ * Specifies whether to use the internal or external supply to
+ * drive the vbus with a ULPI phy.
+ */
+extern int dwc_otg_set_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if,
+					       int32_t val);
+extern int32_t dwc_otg_get_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if);
+#define DWC_PHY_ULPI_INTERNAL_VBUS 0
+#define DWC_PHY_ULPI_EXTERNAL_VBUS 1
+#define dwc_param_phy_ulpi_ext_vbus_default DWC_PHY_ULPI_INTERNAL_VBUS
+
+/**
+ * Specifies whether to use the I2Cinterface for full speed PHY. This
+ * parameter is only applicable if PHY_TYPE is FS.
+ * 0 - No (default)
+ * 1 - Yes
+ */
+extern int dwc_otg_set_param_i2c_enable(dwc_otg_core_if_t * core_if,
+					int32_t val);
+extern int32_t dwc_otg_get_param_i2c_enable(dwc_otg_core_if_t * core_if);
+#define dwc_param_i2c_enable_default 0
+
+extern int dwc_otg_set_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if,
+					int32_t val);
+extern int32_t dwc_otg_get_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if);
+#define dwc_param_ulpi_fs_ls_default 0
+
+extern int dwc_otg_set_param_ts_dline(dwc_otg_core_if_t * core_if, int32_t val);
+extern int32_t dwc_otg_get_param_ts_dline(dwc_otg_core_if_t * core_if);
+#define dwc_param_ts_dline_default 0
+
+/**
+ * Specifies whether dedicated transmit FIFOs are
+ * enabled for non periodic IN endpoints in device mode
+ * 0 - No
+ * 1 - Yes
+ */
+extern int dwc_otg_set_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if,
+						 int32_t val);
+extern int32_t dwc_otg_get_param_en_multiple_tx_fifo(dwc_otg_core_if_t *
+						     core_if);
+#define dwc_param_en_multiple_tx_fifo_default 1
+
+/** Number of 4-byte words in each of the Tx FIFOs in device
+ * mode when dynamic FIFO sizing is enabled.
+ * 4 to 768 (default 256)
+ */
+extern int dwc_otg_set_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
+					      int fifo_num, int32_t val);
+extern int32_t dwc_otg_get_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
+						  int fifo_num);
+#define dwc_param_dev_tx_fifo_size_default 768
+
+/** Thresholding enable flag-
+ * bit 0 - enable non-ISO Tx thresholding
+ * bit 1 - enable ISO Tx thresholding
+ * bit 2 - enable Rx thresholding
+ */
+extern int dwc_otg_set_param_thr_ctl(dwc_otg_core_if_t * core_if, int32_t val);
+extern int32_t dwc_otg_get_thr_ctl(dwc_otg_core_if_t * core_if, int fifo_num);
+#define dwc_param_thr_ctl_default 0
+
+/** Thresholding length for Tx
+ * FIFOs in 32 bit DWORDs
+ */
+extern int dwc_otg_set_param_tx_thr_length(dwc_otg_core_if_t * core_if,
+					   int32_t val);
+extern int32_t dwc_otg_get_tx_thr_length(dwc_otg_core_if_t * core_if);
+#define dwc_param_tx_thr_length_default 64
+
+/** Thresholding length for Rx
+ *	FIFOs in 32 bit DWORDs
+ */
+extern int dwc_otg_set_param_rx_thr_length(dwc_otg_core_if_t * core_if,
+					   int32_t val);
+extern int32_t dwc_otg_get_rx_thr_length(dwc_otg_core_if_t * core_if);
+#define dwc_param_rx_thr_length_default 64
+
+/**
+ * Specifies whether LPM (Link Power Management) support is enabled
+ */
+extern int dwc_otg_set_param_lpm_enable(dwc_otg_core_if_t * core_if,
+					int32_t val);
+extern int32_t dwc_otg_get_param_lpm_enable(dwc_otg_core_if_t * core_if);
+#define dwc_param_lpm_enable_default 1
+
+/**
+ * Specifies whether PTI enhancement is enabled
+ */
+extern int dwc_otg_set_param_pti_enable(dwc_otg_core_if_t * core_if,
+					int32_t val);
+extern int32_t dwc_otg_get_param_pti_enable(dwc_otg_core_if_t * core_if);
+#define dwc_param_pti_enable_default 0
+
+/**
+ * Specifies whether MPI enhancement is enabled
+ */
+extern int dwc_otg_set_param_mpi_enable(dwc_otg_core_if_t * core_if,
+					int32_t val);
+extern int32_t dwc_otg_get_param_mpi_enable(dwc_otg_core_if_t * core_if);
+#define dwc_param_mpi_enable_default 0
+
+/**
+ * Specifies whether ADP capability is enabled
+ */
+extern int dwc_otg_set_param_adp_enable(dwc_otg_core_if_t * core_if,
+					int32_t val);
+extern int32_t dwc_otg_get_param_adp_enable(dwc_otg_core_if_t * core_if);
+#define dwc_param_adp_enable_default 0
+
+/**
+ * Specifies whether IC_USB capability is enabled
+ */
+
+extern int dwc_otg_set_param_ic_usb_cap(dwc_otg_core_if_t * core_if,
+					int32_t val);
+extern int32_t dwc_otg_get_param_ic_usb_cap(dwc_otg_core_if_t * core_if);
+#define dwc_param_ic_usb_cap_default 0
+
+extern int dwc_otg_set_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if,
+					   int32_t val);
+extern int32_t dwc_otg_get_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if);
+#define dwc_param_ahb_thr_ratio_default 0
+
+extern int dwc_otg_set_param_power_down(dwc_otg_core_if_t * core_if,
+					int32_t val);
+extern int32_t dwc_otg_get_param_power_down(dwc_otg_core_if_t * core_if);
+#define dwc_param_power_down_default 0
+
+extern int dwc_otg_set_param_reload_ctl(dwc_otg_core_if_t * core_if,
+					int32_t val);
+extern int32_t dwc_otg_get_param_reload_ctl(dwc_otg_core_if_t * core_if);
+#define dwc_param_reload_ctl_default 0
+
+extern int dwc_otg_set_param_dev_out_nak(dwc_otg_core_if_t * core_if,
+										int32_t val);
+extern int32_t dwc_otg_get_param_dev_out_nak(dwc_otg_core_if_t * core_if);
+#define dwc_param_dev_out_nak_default 0
+
+extern int dwc_otg_set_param_cont_on_bna(dwc_otg_core_if_t * core_if,
+										 int32_t val);
+extern int32_t dwc_otg_get_param_cont_on_bna(dwc_otg_core_if_t * core_if);
+#define dwc_param_cont_on_bna_default 0
+
+extern int dwc_otg_set_param_ahb_single(dwc_otg_core_if_t * core_if,
+										 int32_t val);
+extern int32_t dwc_otg_get_param_ahb_single(dwc_otg_core_if_t * core_if);
+#define dwc_param_ahb_single_default 0
+
+extern int dwc_otg_set_param_otg_ver(dwc_otg_core_if_t * core_if, int32_t val);
+extern int32_t dwc_otg_get_param_otg_ver(dwc_otg_core_if_t * core_if);
+#define dwc_param_otg_ver_default 0
+
+/** @} */
+
+/** @name Access to registers and bit-fields */
+
+/**
+ * Dump core registers and SPRAM
+ */
+extern void dwc_otg_dump_dev_registers(dwc_otg_core_if_t * _core_if);
+extern void dwc_otg_dump_spram(dwc_otg_core_if_t * _core_if);
+extern void dwc_otg_dump_host_registers(dwc_otg_core_if_t * _core_if);
+extern void dwc_otg_dump_global_registers(dwc_otg_core_if_t * _core_if);
+
+/**
+ * Get host negotiation status.
+ */
+extern uint32_t dwc_otg_get_hnpstatus(dwc_otg_core_if_t * core_if);
+
+/**
+ * Get srp status
+ */
+extern uint32_t dwc_otg_get_srpstatus(dwc_otg_core_if_t * core_if);
+
+/**
+ * Set hnpreq bit in the GOTGCTL register.
+ */
+extern void dwc_otg_set_hnpreq(dwc_otg_core_if_t * core_if, uint32_t val);
+
+/**
+ * Get Content of SNPSID register.
+ */
+extern uint32_t dwc_otg_get_gsnpsid(dwc_otg_core_if_t * core_if);
+
+/**
+ * Get current mode.
+ * Returns 0 if in device mode, and 1 if in host mode.
+ */
+extern uint32_t dwc_otg_get_mode(dwc_otg_core_if_t * core_if);
+
+/**
+ * Get value of hnpcapable field in the GUSBCFG register
+ */
+extern uint32_t dwc_otg_get_hnpcapable(dwc_otg_core_if_t * core_if);
+/**
+ * Set value of hnpcapable field in the GUSBCFG register
+ */
+extern void dwc_otg_set_hnpcapable(dwc_otg_core_if_t * core_if, uint32_t val);
+
+/**
+ * Get value of srpcapable field in the GUSBCFG register
+ */
+extern uint32_t dwc_otg_get_srpcapable(dwc_otg_core_if_t * core_if);
+/**
+ * Set value of srpcapable field in the GUSBCFG register
+ */
+extern void dwc_otg_set_srpcapable(dwc_otg_core_if_t * core_if, uint32_t val);
+
+/**
+ * Get value of devspeed field in the DCFG register
+ */
+extern uint32_t dwc_otg_get_devspeed(dwc_otg_core_if_t * core_if);
+/**
+ * Set value of devspeed field in the DCFG register
+ */
+extern void dwc_otg_set_devspeed(dwc_otg_core_if_t * core_if, uint32_t val);
+
+/**
+ * Get the value of busconnected field from the HPRT0 register
+ */
+extern uint32_t dwc_otg_get_busconnected(dwc_otg_core_if_t * core_if);
+
+/**
+ * Gets the device enumeration Speed.
+ */
+extern uint32_t dwc_otg_get_enumspeed(dwc_otg_core_if_t * core_if);
+
+/**
+ * Get value of prtpwr field from the HPRT0 register
+ */
+extern uint32_t dwc_otg_get_prtpower(dwc_otg_core_if_t * core_if);
+
+/**
+ * Get value of flag indicating core state - hibernated or not
+ */
+extern uint32_t dwc_otg_get_core_state(dwc_otg_core_if_t * core_if);
+
+/**
+ * Set value of prtpwr field from the HPRT0 register
+ */
+extern void dwc_otg_set_prtpower(dwc_otg_core_if_t * core_if, uint32_t val);
+
+/**
+ * Get value of prtsusp field from the HPRT0 regsiter
+ */
+extern uint32_t dwc_otg_get_prtsuspend(dwc_otg_core_if_t * core_if);
+/**
+ * Set value of prtpwr field from the HPRT0 register
+ */
+extern void dwc_otg_set_prtsuspend(dwc_otg_core_if_t * core_if, uint32_t val);
+
+/**
+ * Get value of ModeChTimEn field from the HCFG regsiter
+ */
+extern uint32_t dwc_otg_get_mode_ch_tim(dwc_otg_core_if_t * core_if);
+/**
+ * Set value of ModeChTimEn field from the HCFG regsiter
+ */
+extern void dwc_otg_set_mode_ch_tim(dwc_otg_core_if_t * core_if, uint32_t val);
+
+/**
+ * Get value of Fram Interval field from the HFIR regsiter
+ */
+extern uint32_t dwc_otg_get_fr_interval(dwc_otg_core_if_t * core_if);
+/**
+ * Set value of Frame Interval field from the HFIR regsiter
+ */
+extern void dwc_otg_set_fr_interval(dwc_otg_core_if_t * core_if, uint32_t val);
+
+/**
+ * Set value of prtres field from the HPRT0 register
+ *FIXME Remove?
+ */
+extern void dwc_otg_set_prtresume(dwc_otg_core_if_t * core_if, uint32_t val);
+
+/**
+ * Get value of rmtwkupsig bit in DCTL register
+ */
+extern uint32_t dwc_otg_get_remotewakesig(dwc_otg_core_if_t * core_if);
+
+/**
+ * Get value of prt_sleep_sts field from the GLPMCFG register
+ */
+extern uint32_t dwc_otg_get_lpm_portsleepstatus(dwc_otg_core_if_t * core_if);
+
+/**
+ * Get value of rem_wkup_en field from the GLPMCFG register
+ */
+extern uint32_t dwc_otg_get_lpm_remotewakeenabled(dwc_otg_core_if_t * core_if);
+
+/**
+ * Get value of appl_resp field from the GLPMCFG register
+ */
+extern uint32_t dwc_otg_get_lpmresponse(dwc_otg_core_if_t * core_if);
+/**
+ * Set value of appl_resp field from the GLPMCFG register
+ */
+extern void dwc_otg_set_lpmresponse(dwc_otg_core_if_t * core_if, uint32_t val);
+
+/**
+ * Get value of hsic_connect field from the GLPMCFG register
+ */
+extern uint32_t dwc_otg_get_hsic_connect(dwc_otg_core_if_t * core_if);
+/**
+ * Set value of hsic_connect field from the GLPMCFG register
+ */
+extern void dwc_otg_set_hsic_connect(dwc_otg_core_if_t * core_if, uint32_t val);
+
+/**
+ * Get value of inv_sel_hsic field from the GLPMCFG register.
+ */
+extern uint32_t dwc_otg_get_inv_sel_hsic(dwc_otg_core_if_t * core_if);
+/**
+ * Set value of inv_sel_hsic field from the GLPMFG register.
+ */
+extern void dwc_otg_set_inv_sel_hsic(dwc_otg_core_if_t * core_if, uint32_t val);
+
+/*
+ * Some functions for accessing registers
+ */
+
+/**
+ *  GOTGCTL register
+ */
+extern uint32_t dwc_otg_get_gotgctl(dwc_otg_core_if_t * core_if);
+extern void dwc_otg_set_gotgctl(dwc_otg_core_if_t * core_if, uint32_t val);
+
+/**
+ * GUSBCFG register
+ */
+extern uint32_t dwc_otg_get_gusbcfg(dwc_otg_core_if_t * core_if);
+extern void dwc_otg_set_gusbcfg(dwc_otg_core_if_t * core_if, uint32_t val);
+
+/**
+ * GRXFSIZ register
+ */
+extern uint32_t dwc_otg_get_grxfsiz(dwc_otg_core_if_t * core_if);
+extern void dwc_otg_set_grxfsiz(dwc_otg_core_if_t * core_if, uint32_t val);
+
+/**
+ * GNPTXFSIZ register
+ */
+extern uint32_t dwc_otg_get_gnptxfsiz(dwc_otg_core_if_t * core_if);
+extern void dwc_otg_set_gnptxfsiz(dwc_otg_core_if_t * core_if, uint32_t val);
+
+extern uint32_t dwc_otg_get_gpvndctl(dwc_otg_core_if_t * core_if);
+extern void dwc_otg_set_gpvndctl(dwc_otg_core_if_t * core_if, uint32_t val);
+
+/**
+ * GGPIO register
+ */
+extern uint32_t dwc_otg_get_ggpio(dwc_otg_core_if_t * core_if);
+extern void dwc_otg_set_ggpio(dwc_otg_core_if_t * core_if, uint32_t val);
+
+/**
+ * GUID register
+ */
+extern uint32_t dwc_otg_get_guid(dwc_otg_core_if_t * core_if);
+extern void dwc_otg_set_guid(dwc_otg_core_if_t * core_if, uint32_t val);
+
+/**
+ * HPRT0 register
+ */
+extern uint32_t dwc_otg_get_hprt0(dwc_otg_core_if_t * core_if);
+extern void dwc_otg_set_hprt0(dwc_otg_core_if_t * core_if, uint32_t val);
+
+/**
+ * GHPTXFSIZE
+ */
+extern uint32_t dwc_otg_get_hptxfsiz(dwc_otg_core_if_t * core_if);
+
+/** @} */
+
+#endif				/* __DWC_CORE_IF_H__ */
diff --git a/drivers/usb/dwc_otg/dwc_otg_dbg.h b/drivers/usb/dwc_otg/dwc_otg_dbg.h
new file mode 100644
index 0000000..e81d093
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_dbg.h
@@ -0,0 +1,113 @@
+/* ==========================================================================
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ * 
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ * 
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+#ifndef __DWC_OTG_DBG_H__
+#define __DWC_OTG_DBG_H__
+
+/** @file
+ * This file defines debug levels.
+ * Debugging support vanishes in non-debug builds.  
+ */
+
+/**
+ * The Debug Level bit-mask variable.
+ */
+extern uint32_t g_dbg_lvl;
+/**
+ * Set the Debug Level variable.
+ */
+static inline uint32_t SET_DEBUG_LEVEL(const uint32_t new)
+{
+	uint32_t old = g_dbg_lvl;
+	g_dbg_lvl = new;
+	return old;
+}
+
+/** When debug level has the DBG_CIL bit set, display CIL Debug messages. */
+#define DBG_CIL		(0x2)
+/** When debug level has the DBG_CILV bit set, display CIL Verbose debug
+ * messages */
+#define DBG_CILV	(0x20)
+/**  When debug level has the DBG_PCD bit set, display PCD (Device) debug
+ *  messages */
+#define DBG_PCD		(0x4)
+/** When debug level has the DBG_PCDV set, display PCD (Device) Verbose debug
+ * messages */
+#define DBG_PCDV	(0x40)
+/** When debug level has the DBG_HCD bit set, display Host debug messages */
+#define DBG_HCD		(0x8)
+/** When debug level has the DBG_HCDV bit set, display Verbose Host debug
+ * messages */
+#define DBG_HCDV	(0x80)
+/** When debug level has the DBG_HCD_URB bit set, display enqueued URBs in host
+ *  mode. */
+#define DBG_HCD_URB	(0x800)
+
+/** When debug level has any bit set, display debug messages */
+#define DBG_ANY		(0xFF)
+
+/** All debug messages off */
+#define DBG_OFF		0
+
+/** Prefix string for DWC_DEBUG print macros. */
+#define USB_DWC "DWC_otg: "
+
+/** 
+ * Print a debug message when the Global debug level variable contains
+ * the bit defined in <code>lvl</code>.
+ *
+ * @param[in] lvl - Debug level, use one of the DBG_ constants above.
+ * @param[in] x - like printf
+ *
+ *    Example:<p>
+ * <code>
+ *      DWC_DEBUGPL( DBG_ANY, "%s(%p)\n", __func__, _reg_base_addr);
+ * </code>
+ * <br>
+ * results in:<br> 
+ * <code>
+ * usb-DWC_otg: dwc_otg_cil_init(ca867000)
+ * </code>
+ */
+#ifdef DEBUG
+
+# define DWC_DEBUGPL(lvl, x...) do{ if ((lvl)&g_dbg_lvl)__DWC_DEBUG(USB_DWC x ); }while(0)
+# define DWC_DEBUGP(x...)	DWC_DEBUGPL(DBG_ANY, x )
+
+# define CHK_DEBUG_LEVEL(level) ((level) & g_dbg_lvl)
+
+#else
+
+# define DWC_DEBUGPL(lvl, x...) do{}while(0)
+# define DWC_DEBUGP(x...)
+
+# define CHK_DEBUG_LEVEL(level) (0)
+
+#endif /*DEBUG*/
+#endif
diff --git a/drivers/usb/dwc_otg/dwc_otg_driver.c b/drivers/usb/dwc_otg/dwc_otg_driver.c
new file mode 100644
index 0000000..2afd1bc
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_driver.c
@@ -0,0 +1,1893 @@
+/* ==========================================================================
+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_driver.c $
+ * $Revision: #91 $
+ * $Date: 2011/10/24 $
+ * $Change: 1871159 $
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+/** @file
+ * The dwc_otg_driver module provides the initialization and cleanup entry
+ * points for the DWC_otg driver. This module will be dynamically installed
+ * after Linux is booted using the insmod command. When the module is
+ * installed, the dwc_otg_driver_init function is called. When the module is
+ * removed (using rmmod), the dwc_otg_driver_cleanup function is called.
+ *
+ * This module also defines a data structure for the dwc_otg_driver, which is
+ * used in conjunction with the standard ARM lm_device structure. These
+ * structures allow the OTG driver to comply with the standard Linux driver
+ * model in which devices and drivers are registered with a bus driver. This
+ * has the benefit that Linux can expose attributes of the driver and device
+ * in its special sysfs file system. Users can then read or write files in
+ * this file system to perform diagnostics on the driver components or the
+ * device.
+ */
+
+#include "dwc_otg_os_dep.h"
+#include "dwc_os.h"
+#include "dwc_otg_dbg.h"
+#include "dwc_otg_driver.h"
+#include "dwc_otg_attr.h"
+#include "dwc_otg_core_if.h"
+#include "dwc_otg_pcd_if.h"
+#include "dwc_otg_hcd_if.h"
+#include <mach/reset.h>
+#include <mach/hardware.h>
+
+#include <linux/clk.h>
+#include <mach/comcerto-2000/pm.h>
+
+/* USB 3.0 clock */
+static struct clk *usb2_clk;
+
+extern void dwc_otg_host_port_suspend(struct usb_hcd *hcd);
+extern void dwc_otg_host_port_resume(struct usb_hcd *hcd);
+
+
+#define DWC_DRIVER_VERSION	"2.94a 27-OCT-2011"
+#define DWC_DRIVER_DESC		"HS OTG USB Controller driver"
+
+static const char dwc_driver_name[] = "dwc_otg";
+
+extern int pcd_init(
+#ifdef LM_INTERFACE
+			   struct lm_device *_dev
+#elif  defined(PCI_INTERFACE)
+			   struct pci_dev *_dev
+#else
+				struct platform_device *_dev
+#endif
+    );
+extern int hcd_init(
+#ifdef LM_INTERFACE
+			   struct lm_device *_dev
+#elif  defined(PCI_INTERFACE)
+			   struct pci_dev *_dev
+#else
+				struct platform_device *_dev
+#endif
+    );
+
+extern int pcd_remove(
+#ifdef LM_INTERFACE
+			     struct lm_device *_dev
+#elif  defined(PCI_INTERFACE)
+			     struct pci_dev *_dev
+#else
+				 struct platform_device *_dev
+#endif
+    );
+
+extern void hcd_remove(
+#ifdef LM_INTERFACE
+			      struct lm_device *_dev
+#elif  defined(PCI_INTERFACE)
+			      struct pci_dev *_dev
+#else
+					struct platform_device *_dev
+#endif
+    );
+
+extern void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host);
+
+/*-------------------------------------------------------------------------*/
+/* Encapsulate the module parameter settings */
+
+struct dwc_otg_driver_module_params {
+	int32_t opt;
+	int32_t otg_cap;
+	int32_t dma_enable;
+	int32_t dma_desc_enable;
+	int32_t dma_burst_size;
+	int32_t speed;
+	int32_t host_support_fs_ls_low_power;
+	int32_t host_ls_low_power_phy_clk;
+	int32_t enable_dynamic_fifo;
+	int32_t data_fifo_size;
+	int32_t dev_rx_fifo_size;
+	int32_t dev_nperio_tx_fifo_size;
+	uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS];
+	int32_t host_rx_fifo_size;
+	int32_t host_nperio_tx_fifo_size;
+	int32_t host_perio_tx_fifo_size;
+	int32_t max_transfer_size;
+	int32_t max_packet_count;
+	int32_t host_channels;
+	int32_t dev_endpoints;
+	int32_t phy_type;
+	int32_t phy_utmi_width;
+	int32_t phy_ulpi_ddr;
+	int32_t phy_ulpi_ext_vbus;
+	int32_t i2c_enable;
+	int32_t ulpi_fs_ls;
+	int32_t ts_dline;
+	int32_t en_multiple_tx_fifo;
+	uint32_t dev_tx_fifo_size[MAX_TX_FIFOS];
+	uint32_t thr_ctl;
+	uint32_t tx_thr_length;
+	uint32_t rx_thr_length;
+	int32_t pti_enable;
+	int32_t mpi_enable;
+	int32_t lpm_enable;
+	int32_t ic_usb_cap;
+	int32_t ahb_thr_ratio;
+	int32_t power_down;
+	int32_t reload_ctl;
+	int32_t dev_out_nak;
+	int32_t cont_on_bna;
+	int32_t ahb_single;
+	int32_t otg_ver;
+	int32_t adp_enable;
+};
+
+static struct dwc_otg_driver_module_params dwc_otg_module_params = {
+	.opt = -1,
+	.otg_cap = -1,
+	.dma_enable = -1,
+	.dma_desc_enable = -1,
+	.dma_burst_size = -1,
+	.speed = -1,
+	.host_support_fs_ls_low_power = -1,
+	.host_ls_low_power_phy_clk = -1,
+	.enable_dynamic_fifo = -1,
+	.data_fifo_size = -1,
+	.dev_rx_fifo_size = -1,
+	.dev_nperio_tx_fifo_size = -1,
+	.dev_perio_tx_fifo_size = {
+				   /* dev_perio_tx_fifo_size_1 */
+				   -1,
+				   -1,
+				   -1,
+				   -1,
+				   -1,
+				   -1,
+				   -1,
+				   -1,
+				   -1,
+				   -1,
+				   -1,
+				   -1,
+				   -1,
+				   -1,
+				   -1
+				   /* 15 */
+				   },
+	.host_rx_fifo_size = -1,
+	.host_nperio_tx_fifo_size = -1,
+	.host_perio_tx_fifo_size = -1,
+	.max_transfer_size = -1,
+	.max_packet_count = -1,
+	.host_channels = -1,
+	.dev_endpoints = -1,
+	.phy_type = -1,
+	.phy_utmi_width = -1,
+	.phy_ulpi_ddr = -1,
+	.phy_ulpi_ext_vbus = -1,
+	.i2c_enable = -1,
+	.ulpi_fs_ls = -1,
+	.ts_dline = -1,
+	.en_multiple_tx_fifo = -1,
+	.dev_tx_fifo_size = {
+			     /* dev_tx_fifo_size */
+			     -1,
+			     -1,
+			     -1,
+			     -1,
+			     -1,
+			     -1,
+			     -1,
+			     -1,
+			     -1,
+			     -1,
+			     -1,
+			     -1,
+			     -1,
+			     -1,
+			     -1
+			     /* 15 */
+			     },
+	.thr_ctl = -1,
+	.tx_thr_length = -1,
+	.rx_thr_length = -1,
+	.pti_enable = -1,
+	.mpi_enable = -1,
+	.lpm_enable = -1,
+	.ic_usb_cap = -1,
+	.ahb_thr_ratio = -1,
+	.power_down = -1,
+	.reload_ctl = -1,
+	.dev_out_nak = -1,
+	.cont_on_bna = -1,
+	.ahb_single = -1,
+	.otg_ver = -1,
+	.adp_enable = -1,
+};
+
+/**
+ * This function shows the Driver Version.
+ */
+static ssize_t version_show(struct device_driver *dev, char *buf)
+{
+	return snprintf(buf, sizeof(DWC_DRIVER_VERSION) + 2, "%s\n",
+			DWC_DRIVER_VERSION);
+}
+
+static DRIVER_ATTR(version, S_IRUGO, version_show, NULL);
+
+/**
+ * Global Debug Level Mask.
+ */
+uint32_t g_dbg_lvl = 0;		/* OFF */
+
+/**
+ * This function shows the driver Debug Level.
+ */
+static ssize_t dbg_level_show(struct device_driver *drv, char *buf)
+{
+	return sprintf(buf, "0x%0x\n", g_dbg_lvl);
+}
+
+/**
+ * This function stores the driver Debug Level.
+ */
+static ssize_t dbg_level_store(struct device_driver *drv, const char *buf,
+			       size_t count)
+{
+	g_dbg_lvl = simple_strtoul(buf, NULL, 16);
+	return count;
+}
+
+static DRIVER_ATTR(debuglevel, S_IRUGO | S_IWUSR, dbg_level_show,
+		   dbg_level_store);
+
+/**
+ * This function is called during module intialization
+ * to pass module parameters to the DWC_OTG CORE.
+ */
+static int set_parameters(dwc_otg_core_if_t * core_if)
+{
+	int retval = 0;
+	int i;
+
+	if (dwc_otg_module_params.otg_cap != -1) {
+		retval +=
+		    dwc_otg_set_param_otg_cap(core_if,
+					      dwc_otg_module_params.otg_cap);
+	}
+	if (dwc_otg_module_params.dma_enable != -1) {
+		retval +=
+		    dwc_otg_set_param_dma_enable(core_if,
+						 dwc_otg_module_params.
+						 dma_enable);
+	}
+	if (dwc_otg_module_params.dma_desc_enable != -1) {
+		retval +=
+		    dwc_otg_set_param_dma_desc_enable(core_if,
+						      dwc_otg_module_params.
+						      dma_desc_enable);
+	}
+	if (dwc_otg_module_params.opt != -1) {
+		retval +=
+		    dwc_otg_set_param_opt(core_if, dwc_otg_module_params.opt);
+	}
+	if (dwc_otg_module_params.dma_burst_size != -1) {
+		retval +=
+		    dwc_otg_set_param_dma_burst_size(core_if,
+						     dwc_otg_module_params.
+						     dma_burst_size);
+	}
+	if (dwc_otg_module_params.host_support_fs_ls_low_power != -1) {
+		retval +=
+		    dwc_otg_set_param_host_support_fs_ls_low_power(core_if,
+								   dwc_otg_module_params.
+								   host_support_fs_ls_low_power);
+	}
+	if (dwc_otg_module_params.enable_dynamic_fifo != -1) {
+		retval +=
+		    dwc_otg_set_param_enable_dynamic_fifo(core_if,
+							  dwc_otg_module_params.
+							  enable_dynamic_fifo);
+	}
+	if (dwc_otg_module_params.data_fifo_size != -1) {
+		retval +=
+		    dwc_otg_set_param_data_fifo_size(core_if,
+						     dwc_otg_module_params.
+						     data_fifo_size);
+	}
+	if (dwc_otg_module_params.dev_rx_fifo_size != -1) {
+		retval +=
+		    dwc_otg_set_param_dev_rx_fifo_size(core_if,
+						       dwc_otg_module_params.
+						       dev_rx_fifo_size);
+	}
+	if (dwc_otg_module_params.dev_nperio_tx_fifo_size != -1) {
+		retval +=
+		    dwc_otg_set_param_dev_nperio_tx_fifo_size(core_if,
+							      dwc_otg_module_params.
+							      dev_nperio_tx_fifo_size);
+	}
+	if (dwc_otg_module_params.host_rx_fifo_size != -1) {
+		retval +=
+		    dwc_otg_set_param_host_rx_fifo_size(core_if,
+							dwc_otg_module_params.host_rx_fifo_size);
+	}
+	if (dwc_otg_module_params.host_nperio_tx_fifo_size != -1) {
+		retval +=
+		    dwc_otg_set_param_host_nperio_tx_fifo_size(core_if,
+							       dwc_otg_module_params.
+							       host_nperio_tx_fifo_size);
+	}
+	if (dwc_otg_module_params.host_perio_tx_fifo_size != -1) {
+		retval +=
+		    dwc_otg_set_param_host_perio_tx_fifo_size(core_if,
+							      dwc_otg_module_params.
+							      host_perio_tx_fifo_size);
+	}
+	if (dwc_otg_module_params.max_transfer_size != -1) {
+		retval +=
+		    dwc_otg_set_param_max_transfer_size(core_if,
+							dwc_otg_module_params.
+							max_transfer_size);
+	}
+	if (dwc_otg_module_params.max_packet_count != -1) {
+		retval +=
+		    dwc_otg_set_param_max_packet_count(core_if,
+						       dwc_otg_module_params.
+						       max_packet_count);
+	}
+	if (dwc_otg_module_params.host_channels != -1) {
+		retval +=
+		    dwc_otg_set_param_host_channels(core_if,
+						    dwc_otg_module_params.
+						    host_channels);
+	}
+	if (dwc_otg_module_params.dev_endpoints != -1) {
+		retval +=
+		    dwc_otg_set_param_dev_endpoints(core_if,
+						    dwc_otg_module_params.
+						    dev_endpoints);
+	}
+	if (dwc_otg_module_params.phy_type != -1) {
+		retval +=
+		    dwc_otg_set_param_phy_type(core_if,
+					       dwc_otg_module_params.phy_type);
+	}
+	if (dwc_otg_module_params.speed != -1) {
+		retval +=
+		    dwc_otg_set_param_speed(core_if,
+					    dwc_otg_module_params.speed);
+	}
+	if (dwc_otg_module_params.host_ls_low_power_phy_clk != -1) {
+		retval +=
+		    dwc_otg_set_param_host_ls_low_power_phy_clk(core_if,
+								dwc_otg_module_params.
+								host_ls_low_power_phy_clk);
+	}
+	if (dwc_otg_module_params.phy_ulpi_ddr != -1) {
+		retval +=
+		    dwc_otg_set_param_phy_ulpi_ddr(core_if,
+						   dwc_otg_module_params.
+						   phy_ulpi_ddr);
+	}
+	if (dwc_otg_module_params.phy_ulpi_ext_vbus != -1) {
+		retval +=
+		    dwc_otg_set_param_phy_ulpi_ext_vbus(core_if,
+							dwc_otg_module_params.
+							phy_ulpi_ext_vbus);
+	}
+	if (dwc_otg_module_params.phy_utmi_width != -1) {
+		retval +=
+		    dwc_otg_set_param_phy_utmi_width(core_if,
+						     dwc_otg_module_params.
+						     phy_utmi_width);
+	}
+	if (dwc_otg_module_params.ulpi_fs_ls != -1) {
+		retval +=
+		    dwc_otg_set_param_ulpi_fs_ls(core_if,
+						 dwc_otg_module_params.ulpi_fs_ls);
+	}
+	if (dwc_otg_module_params.ts_dline != -1) {
+		retval +=
+		    dwc_otg_set_param_ts_dline(core_if,
+					       dwc_otg_module_params.ts_dline);
+	}
+	if (dwc_otg_module_params.i2c_enable != -1) {
+		retval +=
+		    dwc_otg_set_param_i2c_enable(core_if,
+						 dwc_otg_module_params.
+						 i2c_enable);
+	}
+	if (dwc_otg_module_params.en_multiple_tx_fifo != -1) {
+		retval +=
+		    dwc_otg_set_param_en_multiple_tx_fifo(core_if,
+							  dwc_otg_module_params.
+							  en_multiple_tx_fifo);
+	}
+
+	for (i = 0; i < 7; i++) {
+		if (dwc_otg_module_params.dev_perio_tx_fifo_size[i] != -1) {
+			retval +=
+			    dwc_otg_set_param_dev_perio_tx_fifo_size(core_if,
+								     dwc_otg_module_params.
+								     dev_perio_tx_fifo_size
+								     [i], i);
+		}
+	}
+
+	for (i = 0; i < 7; i++) {
+		if (dwc_otg_module_params.dev_tx_fifo_size[i] != -1) {
+			retval += dwc_otg_set_param_dev_tx_fifo_size(core_if,
+								     dwc_otg_module_params.
+								     dev_tx_fifo_size
+								     [i], i);
+		}
+	}
+	if (dwc_otg_module_params.thr_ctl != -1) {
+		retval +=
+		    dwc_otg_set_param_thr_ctl(core_if,
+					      dwc_otg_module_params.thr_ctl);
+	}
+	if (dwc_otg_module_params.mpi_enable != -1) {
+		retval +=
+		    dwc_otg_set_param_mpi_enable(core_if,
+						 dwc_otg_module_params.
+						 mpi_enable);
+	}
+	if (dwc_otg_module_params.pti_enable != -1) {
+		retval +=
+		    dwc_otg_set_param_pti_enable(core_if,
+						 dwc_otg_module_params.
+						 pti_enable);
+	}
+	if (dwc_otg_module_params.lpm_enable != -1) {
+		retval +=
+		    dwc_otg_set_param_lpm_enable(core_if,
+						 dwc_otg_module_params.
+						 lpm_enable);
+	}
+	if (dwc_otg_module_params.ic_usb_cap != -1) {
+		retval +=
+		    dwc_otg_set_param_ic_usb_cap(core_if,
+						 dwc_otg_module_params.
+						 ic_usb_cap);
+	}
+	if (dwc_otg_module_params.tx_thr_length != -1) {
+		retval +=
+		    dwc_otg_set_param_tx_thr_length(core_if,
+						    dwc_otg_module_params.tx_thr_length);
+	}
+	if (dwc_otg_module_params.rx_thr_length != -1) {
+		retval +=
+		    dwc_otg_set_param_rx_thr_length(core_if,
+						    dwc_otg_module_params.
+						    rx_thr_length);
+	}
+	if (dwc_otg_module_params.ahb_thr_ratio != -1) {
+		retval +=
+		    dwc_otg_set_param_ahb_thr_ratio(core_if,
+						    dwc_otg_module_params.ahb_thr_ratio);
+	}
+	if (dwc_otg_module_params.power_down != -1) {
+		retval +=
+		    dwc_otg_set_param_power_down(core_if,
+						 dwc_otg_module_params.power_down);
+	}
+	if (dwc_otg_module_params.reload_ctl != -1) {
+		retval +=
+		    dwc_otg_set_param_reload_ctl(core_if,
+						 dwc_otg_module_params.reload_ctl);
+	}
+
+	if (dwc_otg_module_params.dev_out_nak != -1) {
+		retval +=
+			dwc_otg_set_param_dev_out_nak(core_if,
+			dwc_otg_module_params.dev_out_nak);
+	}
+
+	if (dwc_otg_module_params.cont_on_bna != -1) {
+		retval +=
+			dwc_otg_set_param_cont_on_bna(core_if,
+			dwc_otg_module_params.cont_on_bna);
+	}
+
+	if (dwc_otg_module_params.ahb_single != -1) {
+		retval +=
+			dwc_otg_set_param_ahb_single(core_if,
+			dwc_otg_module_params.ahb_single);
+	}
+
+	if (dwc_otg_module_params.otg_ver != -1) {
+		retval +=
+		    dwc_otg_set_param_otg_ver(core_if,
+					      dwc_otg_module_params.otg_ver);
+	}
+	if (dwc_otg_module_params.adp_enable != -1) {
+		retval +=
+		    dwc_otg_set_param_adp_enable(core_if,
+						 dwc_otg_module_params.
+						 adp_enable);
+	}
+	return retval;
+}
+
+
+/**
+ * Platform specific initialization for USB 2 PHY
+ */
+static void comcerto_usb2_phy_init(void)
+{
+		uint32_t rd_data;
+
+#define COMCERTO_USB0_PHY_CTRL_REG0 	(COMCERTO_DWC1_CFG_BASE + 0x000)
+#define COMCERTO_USB0_DWC_CFG_REGF 		(USB2_PHY_BASE + 0x03C)
+
+
+		/* take device out of reset , enable clock. */
+		/* Programming the USB0 PHY CONTROL REGISTER */
+		/*	Bit[2]:usb0_vbusvldextsel - The internal Session Valid comparator is used.
+		 * Bit[3]:usb0_vbusvldext - The VBUS signal is not valid, and the pull-up resistor on D+ is disabled.
+		 * Bit[4]:usb0_otgdisable  - TThe OTG block is powered up.
+		 * Bit[17:16]:usb0_refclkdiv - Reference Clock Frequency Select, 48 MHz
+		 * Bit[21:20]:usb0_refclksel - The XO block uses an external, 2.5 V clock supplied on the XO pin.
+		 */
+		if(HAL_get_ref_clk() == REF_CLK_24MHZ)
+			writel(0x00210000, COMCERTO_USB0_PHY_CTRL_REG0);  //24MHz ref clk
+		else
+			writel(0x00220000, COMCERTO_USB0_PHY_CTRL_REG0);  //48MHz ref clk
+
+		/* Programming the IDSEL values to USB 2.0 Controller @ DWC_CFG_REGF register */
+		/* Configuring the usb2 controller to select the ID value from register */
+		rd_data = readl(COMCERTO_USB0_DWC_CFG_REGF);
+
+		/*	Bit[8]:usb0_id_sel - Selects from the register bit
+		 *	Bit[9]:usb1_id_sel - Selects from the register bit
+		 */
+		rd_data = ((rd_data & 0xFFFF11FF)| 0x00001100);  //For Host mode.
+		writel (rd_data, COMCERTO_USB0_DWC_CFG_REGF);
+
+
+		/* Programming USB2.0 controller with scale down value. */
+		/* Configuring the usb2 controller in scaledown disable mode */
+		rd_data = readl(COMCERTO_USB0_DWC_CFG_REGF);
+		rd_data = ((rd_data & 0xFFFFFFF0)| 0x0);
+		writel (rd_data, COMCERTO_USB0_DWC_CFG_REGF);
+}
+
+
+
+/**
+ * Platform specific initialization for Dwc OTG Controller
+ */
+static void comcerto_start_dwc_otg(void)
+{
+	/* Get the FAST-UART clk structure from DUS ,To be used for UART0/UART1 initilization */
+	usb2_clk = clk_get(NULL,"usb0");
+
+	/* Enable the Clock */
+	if (clk_enable(usb2_clk)){
+		pr_err("comcerto_start_dwc_otg:Unable to enable the usb2 clock \n");
+	}
+
+	/* USB 2.0 PHY Initialization */
+	comcerto_usb2_phy_init();
+
+	/* Continuing resets on usb2 controller+phy blocks */
+
+	/* APPLYING THE RESET TO USB2 UTMI */
+	c2000_block_reset(COMPONENT_UTMI_USB0, 1);
+
+	/* APPLYING THE RESET TO USB2 PHY */
+	c2000_block_reset(COMPONENT_USB0_PHY, 1);
+
+	/* APLLYING RESET TO USB2 AXI RESET */
+	c2000_block_reset(COMPONENT_AXI_USB0, 1);
+
+	/* Releasing the (POR) Power on Reset to usb2 nano phy block */
+	c2000_block_reset(COMPONENT_USB0_PHY, 0);
+
+	/* Releasing the UTMI Reset to usb2 controller block */
+	c2000_block_reset(COMPONENT_UTMI_USB0, 0);
+
+	/* Releasing the AHB Reset to usb2 controller block -- Bit[4]-USB3,Bit[3]-USB2 */
+	c2000_block_reset(COMPONENT_AXI_USB0, 0);
+}
+
+
+/**
+ * Platform specific Shutdown for Dwc OTG Controller
+ */
+static void comcerto_stop_dwc_otg(void)
+{
+	/* APPLYING THE RESET TO USB2 UTMI */
+	c2000_block_reset(COMPONENT_UTMI_USB0, 1);
+
+	/* APPLYING THE RESET TO USB2 PHY */
+	c2000_block_reset(COMPONENT_USB0_PHY, 1);
+
+	/* APLLYING RESET TO USB2 AXI RESET */
+	c2000_block_reset(COMPONENT_AXI_USB0, 1);
+
+	/* Disable the Clock */
+	clk_disable(usb2_clk);
+
+	/* Release the clock */
+	clk_put(usb2_clk);
+}
+
+
+/**
+ * This function is the top level interrupt handler for the Common
+ * (Device and host modes) interrupts.
+ */
+static irqreturn_t dwc_otg_common_irq(int irq, void *dev)
+{
+	int32_t retval = IRQ_NONE;
+
+	retval = dwc_otg_handle_common_intr(dev);
+	if (retval != 0) {
+		S3C2410X_CLEAR_EINTPEND();
+	}
+	return IRQ_RETVAL(retval);
+}
+
+/**
+ * This function is called when a lm_device is unregistered with the
+ * dwc_otg_driver. This happens, for example, when the rmmod command is
+ * executed. The device may or may not be electrically present. If it is
+ * present, the driver stops device processing. Any resources used on behalf
+ * of this device are freed.
+ *
+ * @param _dev
+ */
+static void dwc_otg_driver_remove(
+#ifdef LM_INTERFACE
+					 struct lm_device *_dev
+#elif defined(PCI_INTERFACE)
+					 struct pci_dev *_dev
+#else
+					 struct platform_device *_dev
+#endif
+    )
+{
+#ifdef LM_INTERFACE
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev);
+#endif
+
+	DWC_DEBUGPL(DBG_ANY, "%s(%p)\n", __func__, _dev);
+
+	if (!otg_dev) {
+		/* Memory allocation for the dwc_otg_device failed. */
+		DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__);
+		return;
+	}
+#ifndef DWC_DEVICE_ONLY
+	if (otg_dev->hcd) {
+		hcd_remove(_dev);
+	} else {
+		DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__);
+		return;
+	}
+#endif
+
+#ifndef DWC_HOST_ONLY
+	if (otg_dev->pcd) {
+		pcd_remove(_dev);
+	} else {
+		DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->pcd NULL!\n", __func__);
+		return;
+	}
+#endif
+	/*
+	 * Free the IRQ
+	 */
+	if (otg_dev->common_irq_installed) {
+		free_irq(otg_dev->irq, otg_dev);
+	} else {
+		DWC_DEBUGPL(DBG_ANY, "%s: There is no installed irq!\n", __func__);
+		return;
+	}
+
+	if (otg_dev->core_if) {
+		dwc_otg_cil_remove(otg_dev->core_if);
+	} else {
+		DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->core_if NULL!\n", __func__);
+		return;
+	}
+
+	/*
+	 * Remove the device attributes
+	 */
+	dwc_otg_attr_remove(_dev);
+
+	/*
+	 * Return the memory.
+	 */
+	if (otg_dev->os_dep.base) {
+		iounmap(otg_dev->os_dep.base);
+	}
+
+	/* Do the Platform specific shutdown */
+	comcerto_stop_dwc_otg();
+
+	DWC_FREE(otg_dev);
+
+	/*
+	 * Clear the drvdata pointer.
+	 */
+#ifdef LM_INTERFACE
+	lm_set_drvdata(_dev, 0);
+#elif defined(PCI_INTERFACE)
+    release_mem_region(otg_dev->os_dep.rsrc_start, otg_dev->os_dep.rsrc_len);
+	pci_set_drvdata(_dev, 0);
+#else
+	platform_set_drvdata(_dev, 0);
+#endif
+}
+
+/**
+ * This function is called when an lm_device is bound to a
+ * dwc_otg_driver. It creates the driver components required to
+ * control the device (CIL, HCD, and PCD) and it initializes the
+ * device. The driver components are stored in a dwc_otg_device
+ * structure. A reference to the dwc_otg_device is saved in the
+ * lm_device. This allows the driver to access the dwc_otg_device
+ * structure on subsequent calls to driver methods for this device.
+ *
+ * @param _dev Bus device
+ */
+static int dwc_otg_driver_probe(
+#ifdef LM_INTERFACE
+				       struct lm_device *_dev
+#elif defined(PCI_INTERFACE)
+				       struct pci_dev *_dev,
+				       const struct pci_device_id *id
+#else
+						struct platform_device *_dev
+#endif
+    )
+{
+	int retval = 0;
+	dwc_otg_device_t *dwc_otg_device;
+
+	dev_dbg(&_dev->dev, "dwc_otg_driver_probe(%p)\n", _dev);
+#ifdef LM_INTERFACE
+	dev_dbg(&_dev->dev, "start=0x%08x\n", (unsigned)_dev->resource.start);
+#elif defined(PCI_INTERFACE)
+	if (!id) {
+		DWC_ERROR("Invalid pci_device_id %p", id);
+		return -EINVAL;
+	}
+
+	if (!_dev || (pci_enable_device(_dev) < 0)) {
+		DWC_ERROR("Invalid pci_device %p", _dev);
+		return -ENODEV;
+	}
+	dev_dbg(&_dev->dev, "start=0x%08x\n", (unsigned)pci_resource_start(_dev,0));
+	/* other stuff needed as well? */
+#else
+	dev_dbg(&_dev->dev, "start=0x%08x\n", (unsigned)_dev->resource->start);
+#endif
+
+	dwc_otg_device = DWC_ALLOC(sizeof(dwc_otg_device_t));
+
+	if (!dwc_otg_device) {
+		dev_err(&_dev->dev, "kmalloc of dwc_otg_device failed\n");
+		return -ENOMEM;
+	}
+
+	memset(dwc_otg_device, 0, sizeof(*dwc_otg_device));
+	dwc_otg_device->os_dep.reg_offset = 0xFFFFFFFF;
+
+	/* Platform Specific initialization */
+	comcerto_start_dwc_otg();
+
+	dwc_otg_device->os_dep.parent= &_dev->dev;
+
+	/*
+	 * Map the DWC_otg Core memory into virtual address space.
+	 */
+#ifdef LM_INTERFACE
+	dwc_otg_device->os_dep.base = ioremap(_dev->resource.start, SZ_256K);
+
+	if (!dwc_otg_device->os_dep.base) {
+		dev_err(&_dev->dev, "ioremap() failed\n");
+		DWC_FREE(dwc_otg_device);
+		return -ENOMEM;
+	}
+	dev_dbg(&_dev->dev, "base=0x%08x\n",
+		(unsigned)dwc_otg_device->os_dep.base);
+#elif defined(PCI_INTERFACE)
+	_dev->current_state = PCI_D0;
+	_dev->dev.power.power_state = PMSG_ON;
+
+	if (!_dev->irq) {
+		DWC_ERROR("Found HC with no IRQ. Check BIOS/PCI %s setup!",
+			  pci_name(_dev));
+		iounmap(dwc_otg_device->os_dep.base);
+		DWC_FREE(dwc_otg_device);
+		return -ENODEV;
+	}
+
+	dwc_otg_device->os_dep.rsrc_start = pci_resource_start(_dev, 0);
+	dwc_otg_device->os_dep.rsrc_len = pci_resource_len(_dev, 0);
+	DWC_DEBUGPL(DBG_ANY, "PCI resource: start=%08x, len=%08x\n",
+		    (unsigned)dwc_otg_device->os_dep.rsrc_start,
+		    (unsigned)dwc_otg_device->os_dep.rsrc_len);
+	if (!request_mem_region
+	    (dwc_otg_device->os_dep.rsrc_start, dwc_otg_device->os_dep.rsrc_len,
+	     "dwc_otg")) {
+		dev_dbg(&_dev->dev, "error requesting memory\n");
+		iounmap(dwc_otg_device->os_dep.base);
+		DWC_FREE(dwc_otg_device);
+		return -EFAULT;
+	}
+
+	dwc_otg_device->os_dep.base =
+	    ioremap_nocache(dwc_otg_device->os_dep.rsrc_start,
+			    dwc_otg_device->os_dep.rsrc_len);
+	if (dwc_otg_device->os_dep.base == NULL) {
+		dev_dbg(&_dev->dev, "error mapping memory\n");
+		release_mem_region(dwc_otg_device->os_dep.rsrc_start,
+				   dwc_otg_device->os_dep.rsrc_len);
+		iounmap(dwc_otg_device->os_dep.base);
+		DWC_FREE(dwc_otg_device);
+		return -EFAULT;
+	}
+	dev_dbg(&_dev->dev, "base=0x%p (before adjust) \n",
+		dwc_otg_device->os_dep.base);
+	dwc_otg_device->os_dep.base = (char *)dwc_otg_device->os_dep.base;
+	dev_dbg(&_dev->dev, "base=0x%p (after adjust) \n",
+		dwc_otg_device->os_dep.base);
+	dev_dbg(&_dev->dev, "%s: mapped PA 0x%x to VA 0x%p\n", __func__,
+		(unsigned)dwc_otg_device->os_dep.rsrc_start,
+		dwc_otg_device->os_dep.base);
+
+	pci_set_master(_dev);
+	pci_set_drvdata(_dev, dwc_otg_device);
+#else
+	dwc_otg_device->os_dep.base = ioremap(_dev->resource->start, SZ_256K);
+
+	if (!dwc_otg_device->os_dep.base) {
+		dev_err(&_dev->dev, "ioremap() failed\n");
+		DWC_FREE(dwc_otg_device);
+		return -ENOMEM;
+	}
+	dev_dbg(&_dev->dev, "base=0x%08x\n",
+		(unsigned)dwc_otg_device->os_dep.base);
+#endif
+
+	/*
+	 * Retrieve the memory and IRQ resources.
+	 */
+	 dwc_otg_device->irq = platform_get_irq(_dev, 0);
+	if (dwc_otg_device->irq <= 0) {
+		dev_err(&_dev->dev, "no device irq\n");
+		retval = -EINVAL;
+		goto fail;
+	}
+
+	/*
+	 * Initialize driver data to point to the global DWC_otg
+	 * Device structure.
+	 */
+#ifdef LM_INTERFACE
+	lm_set_drvdata(_dev, dwc_otg_device);
+#else
+	platform_set_drvdata(_dev, dwc_otg_device);
+	_dev->dev.platform_data = (void *) dwc_otg_device;
+#endif
+	dev_dbg(&_dev->dev, "dwc_otg_device=0x%p\n", dwc_otg_device);
+
+	dwc_otg_device->core_if = dwc_otg_cil_init(dwc_otg_device->os_dep.base);
+	if (!dwc_otg_device->core_if) {
+		dev_err(&_dev->dev, "CIL initialization failed!\n");
+		retval = -ENOMEM;
+		goto fail;
+	}
+
+	/*
+	 * Attempt to ensure this device is really a DWC_otg Controller.
+	 * Read and verify the SNPSID register contents. The value should be
+	 * 0x45F42XXX, which corresponds to "OT2", as in "OTG version 2.XX".
+	 */
+
+	if ((dwc_otg_get_gsnpsid(dwc_otg_device->core_if) & 0xFFFFF000) !=
+	    0x4F542000) {
+		dev_err(&_dev->dev, "Bad value for SNPSID: 0x%08x\n",
+			dwc_otg_get_gsnpsid(dwc_otg_device->core_if));
+		retval = -EINVAL;
+		goto fail;
+	}
+
+	/*
+	 * Validate parameter values.
+	 */
+	if (set_parameters(dwc_otg_device->core_if)) {
+		retval = -EINVAL;
+		goto fail;
+	}
+
+	/*
+	 * Create Device Attributes in sysfs
+	 */
+	dwc_otg_attr_create(_dev);
+
+	/*
+	 * Disable the global interrupt until all the interrupt
+	 * handlers are installed.
+	 */
+	dwc_otg_disable_global_interrupts(dwc_otg_device->core_if);
+
+	/*
+	 * Install the interrupt handler for the common interrupts before
+	 * enabling common interrupts in core_init below.
+	 */
+	DWC_DEBUGPL(DBG_CIL, "registering (common) handler for irq%d\n",
+		    dwc_otg_device->irq);
+	retval = request_irq(dwc_otg_device->irq, dwc_otg_common_irq,
+			     IRQF_SHARED | IRQF_DISABLED | IRQ_LEVEL, "dwc_otg",
+			     dwc_otg_device);
+	if (retval) {
+		DWC_ERROR("request of irq%d failed\n", dwc_otg_device->irq);
+		retval = -EBUSY;
+		goto fail;
+	} else {
+		dwc_otg_device->common_irq_installed = 1;
+	}
+
+#ifdef LM_INTERFACE
+	set_irq_type(_dev->irq, IRQT_LOW);
+#endif
+	/*
+	 * Initialize the DWC_otg core.
+	 */
+	dwc_otg_core_init(dwc_otg_device->core_if);
+
+#ifndef DWC_HOST_ONLY
+	/*
+	 * Initialize the PCD
+	 */
+	retval = pcd_init(_dev);
+	if (retval != 0) {
+		DWC_ERROR("pcd_init failed\n");
+		dwc_otg_device->pcd = NULL;
+		goto fail;
+	}
+#endif
+#ifndef DWC_DEVICE_ONLY
+	/*
+	 * Initialize the HCD
+	 */
+	retval = hcd_init(_dev);
+	if (retval != 0) {
+		DWC_ERROR("hcd_init failed\n");
+		dwc_otg_device->hcd = NULL;
+		goto fail;
+	}
+#endif
+#ifdef PCI_INTERFACE
+	pci_set_drvdata(_dev, dwc_otg_device);
+	dwc_otg_device->os_dep.pcidev = _dev;
+#endif
+
+	/*
+	 * Enable the global interrupt after all the interrupt
+	 * handlers are installed if there is no ADP support else
+	 * perform initial actions required for Internal ADP logic.
+	 */
+	if (!dwc_otg_get_param_adp_enable(dwc_otg_device->core_if))
+		dwc_otg_enable_global_interrupts(dwc_otg_device->core_if);
+	else
+		dwc_otg_adp_start(dwc_otg_device->core_if,
+							dwc_otg_is_host_mode(dwc_otg_device->core_if));
+
+	return 0;
+
+fail:
+	dwc_otg_driver_remove(_dev);
+	return retval;
+}
+
+#if 0
+/**
+ * This structure defines the methods to be called by a bus driver
+ * during the lifecycle of a device on that bus. Both drivers and
+ * devices are registered with a bus driver. The bus driver matches
+ * devices to drivers based on information in the device and driver
+ * structures.
+ *
+ * The probe function is called when the bus driver matches a device
+ * to this driver. The remove function is called when a device is
+ * unregistered with the bus driver.
+ */
+#ifdef LM_INTERFACE
+static struct lm_driver dwc_otg_driver = {
+	.drv = {.name = (char *)dwc_driver_name,},
+	.probe = dwc_otg_driver_probe,
+	.remove = dwc_otg_driver_remove,
+};
+#elif defined(PCI_INTERFACE)
+static const struct pci_device_id pci_ids[] = { {
+						 PCI_DEVICE(0x16c3, 0xabcd),
+						 .driver_data =
+						 (unsigned long)0xdeadbeef,
+						 }, { /* end: all zeroes */ }
+};
+
+MODULE_DEVICE_TABLE(pci, pci_ids);
+
+/* pci driver glue; this is a "new style" PCI driver module */
+static struct pci_driver dwc_otg_driver = {
+	.name = "dwc_otg",
+	.id_table = pci_ids,
+
+	.probe = dwc_otg_driver_probe,
+	.remove = dwc_otg_driver_remove,
+
+	.driver = {
+		   .name = (char *)dwc_driver_name,
+		   },
+};
+#endif
+
+/**
+ * This function is called when the dwc_otg_driver is installed with the
+ * insmod command. It registers the dwc_otg_driver structure with the
+ * appropriate bus driver. This will cause the dwc_otg_driver_probe function
+ * to be called. In addition, the bus driver will automatically expose
+ * attributes defined for the device and driver in the special sysfs file
+ * system.
+ *
+ * @return
+ */
+static int __init dwc_otg_driver_init(void)
+{
+	int retval = 0;
+	int error;
+	printk(KERN_INFO "%s: version %s\n", dwc_driver_name,
+	       DWC_DRIVER_VERSION);
+#ifdef LM_INTERFACE
+	retval = lm_driver_register(&dwc_otg_driver);
+#elif defined(PCI_INTERFACE)
+	retval = pci_register_driver(&dwc_otg_driver);
+#endif
+	if (retval < 0) {
+		printk(KERN_ERR "%s retval=%d\n", __func__, retval);
+		return retval;
+	}
+#ifdef LM_INTERFACE
+	error = driver_create_file(&dwc_otg_driver.drv, &driver_attr_version);
+	error = driver_create_file(&dwc_otg_driver.drv, &driver_attr_debuglevel);
+#elif defined(PCI_INTERFACE)
+	error = driver_create_file(&dwc_otg_driver.driver, &driver_attr_version);
+	error = driver_create_file(&dwc_otg_driver.driver, &driver_attr_debuglevel);
+#endif
+	return retval;
+}
+
+module_init(dwc_otg_driver_init);
+
+/**
+ * This function is called when the driver is removed from the kernel
+ * with the rmmod command. The driver unregisters itself with its bus
+ * driver.
+ *
+ */
+static void __exit dwc_otg_driver_cleanup(void)
+{
+	printk(KERN_DEBUG "dwc_otg_driver_cleanup()\n");
+
+#ifdef LM_INTERFACE
+	driver_remove_file(&dwc_otg_driver.drv, &driver_attr_debuglevel);
+	driver_remove_file(&dwc_otg_driver.drv, &driver_attr_version);
+	lm_driver_unregister(&dwc_otg_driver);
+#elif defined(PCI_INTERFACE)
+	driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel);
+	driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version);
+	pci_unregister_driver(&dwc_otg_driver);
+#endif
+
+	printk(KERN_INFO "%s module removed\n", dwc_driver_name);
+}
+
+module_exit(dwc_otg_driver_cleanup);
+#else
+
+/*
+ * Platform Specific Controller Suspend Routiene.
+ * It does a Port suspend, and gate the clock (Power Off L1).
+ * Controller and PHY reset (Power Off L2) functionality
+ * is not supported
+ */
+int comcerto_usb2_bus_suspend(struct platform_device * pd, pm_message_t state)
+{
+	int error_status = 0, val = 0;
+	struct usb_hcd *hcd = NULL;
+
+	/* Check for the Bit Mask bit for USB2, if not enabled
+         * then we are not going suspend the USB2 device , as by
+         * this device , we will wake from resume.
+         */
+        if ( !(host_utilpe_shared_pmu_bitmask & USB2p0_IRQ )){
+
+                /* We will return here.
+                 * Not prepared yet for suspend , so that device suspend
+                 * will not occur.
+                */
+		return error_status;
+	}
+
+	hcd = (struct usb_hcd *) platform_get_drvdata(pd);
+
+	/* Do the port suspend for USB 2.0 Controller */
+	dwc_otg_host_port_suspend(hcd);
+
+	for (val = 0 ; val < 50 ; val++)
+		udelay(1000);
+
+	/* Disable the Clock */
+	clk_disable(usb2_clk);
+
+	/* PM Performance Enhancement : USB0 PD */
+	/* Common Block Power-Down Control and powering down all analog blocks */
+	writel(0x01220040, COMCERTO_USB0_PHY_CTRL_REG0);
+
+	return error_status;
+}
+
+/*
+ * Platform Specific Controller Resume Routiene.
+ * It does a Port resume, and enable the clock (Power Off L1).
+ * Resume from (Power Off L2) is not supported
+ */
+int comcerto_usb2_bus_resume(struct platform_device *pd)
+{
+	int error_status = 0;
+	struct usb_hcd *hcd = NULL;
+
+
+	/* Check for the Bit Mask bit for USB2, if not enabled
+         * then we are not going suspend the USB2 device , as by
+         * this device , we will wake from resume.
+         */
+        if ( host_utilpe_shared_pmu_bitmask & USB2p0_IRQ ){
+
+                /* We will return here.
+                 * Not prepared yet for suspend , so that device suspend
+                 * will not occur.
+                */
+		return error_status;
+	}
+
+	/* PM Performance Enhancement : USB0 PD */
+	/* Common Block Power-Down Control and powering down all analog blocks */
+	writel(0x00220000, COMCERTO_USB0_PHY_CTRL_REG0);
+
+	/* Enable the Clock */
+	if (clk_enable(usb2_clk)){
+		pr_err("comcerto_usb2_bus_resume_dummy:Unable to enable the usb2 clock \n");
+	}
+
+	hcd = (struct usb_hcd *) platform_get_drvdata(pd);
+
+	dwc_otg_host_port_resume(hcd);
+
+	return error_status;
+}
+
+/**
+ * This structure defines the methods to be called by a bus driver
+ * during the lifecycle of a device on that bus. Both drivers and
+ * devices are registered with a bus driver. The bus driver matches
+ * devices to drivers based on information in the device and driver
+ * structures.
+ *
+ * The probe function is called when the bus driver matches a device
+ * to this driver. The remove function is called when a device is
+ * unregistered with the bus driver.
+ */
+static struct platform_driver dwc_otg_driver = {
+	.driver = {
+		.name	= (char *)dwc_driver_name,
+	},
+	.probe		= dwc_otg_driver_probe,
+	.remove		= dwc_otg_driver_remove,
+
+	.suspend = comcerto_usb2_bus_suspend,
+	.resume = comcerto_usb2_bus_resume,
+};
+
+/**
+ * This function is called when the dwc_otg_driver is installed with the
+ * insmod command. It registers the dwc_otg_driver structure with the
+ * appropriate bus driver. This will cause the dwc_otg_driver_probe function
+ * to be called. In addition, the bus driver will automatically expose
+ * attributes defined for the device and driver in the special sysfs file
+ * system.
+ *
+ * @return
+ */
+static int __init dwc_otg_driver_init(void)
+{
+	int retval = 0;
+	int error;
+
+	printk(KERN_INFO "%s: version %s\n", dwc_driver_name, DWC_DRIVER_VERSION);
+
+	retval = platform_driver_register(&dwc_otg_driver);
+	if (retval) {
+		printk(KERN_ERR "%s retval=%d\n", __func__, retval);
+		return retval;
+	}
+
+	error = driver_create_file(&dwc_otg_driver.driver, &driver_attr_version);
+	error = driver_create_file(&dwc_otg_driver.driver, &driver_attr_debuglevel);
+
+	return retval;
+}
+module_init(dwc_otg_driver_init);
+
+/**
+ * This function is called when the driver is removed from the kernel
+ * with the rmmod command. The driver unregisters itself with its bus
+ * driver.
+ *
+ */
+static void __exit dwc_otg_driver_cleanup(void)
+{
+	printk(KERN_DEBUG "dwc_otg_driver_cleanup()\n");
+
+	driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel);
+	driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version);
+
+	platform_driver_unregister(&dwc_otg_driver);
+
+	printk(KERN_INFO "%s module removed\n", dwc_driver_name);
+}
+module_exit(dwc_otg_driver_cleanup);
+
+#endif
+
+MODULE_DESCRIPTION(DWC_DRIVER_DESC);
+MODULE_AUTHOR("Synopsys Inc.");
+MODULE_LICENSE("GPL");
+
+module_param_named(otg_cap, dwc_otg_module_params.otg_cap, int, 0444);
+MODULE_PARM_DESC(otg_cap, "OTG Capabilities 0=HNP&SRP 1=SRP Only 2=None");
+module_param_named(opt, dwc_otg_module_params.opt, int, 0444);
+MODULE_PARM_DESC(opt, "OPT Mode");
+module_param_named(dma_enable, dwc_otg_module_params.dma_enable, int, 0444);
+MODULE_PARM_DESC(dma_enable, "DMA Mode 0=Slave 1=DMA enabled");
+
+module_param_named(dma_desc_enable, dwc_otg_module_params.dma_desc_enable, int,
+		   0444);
+MODULE_PARM_DESC(dma_desc_enable,
+		 "DMA Desc Mode 0=Address DMA 1=DMA Descriptor enabled");
+
+module_param_named(dma_burst_size, dwc_otg_module_params.dma_burst_size, int,
+		   0444);
+MODULE_PARM_DESC(dma_burst_size,
+		 "DMA Burst Size 1, 4, 8, 16, 32, 64, 128, 256");
+module_param_named(speed, dwc_otg_module_params.speed, int, 0444);
+MODULE_PARM_DESC(speed, "Speed 0=High Speed 1=Full Speed");
+module_param_named(host_support_fs_ls_low_power,
+		   dwc_otg_module_params.host_support_fs_ls_low_power, int,
+		   0444);
+MODULE_PARM_DESC(host_support_fs_ls_low_power,
+		 "Support Low Power w/FS or LS 0=Support 1=Don't Support");
+module_param_named(host_ls_low_power_phy_clk,
+		   dwc_otg_module_params.host_ls_low_power_phy_clk, int, 0444);
+MODULE_PARM_DESC(host_ls_low_power_phy_clk,
+		 "Low Speed Low Power Clock 0=48Mhz 1=6Mhz");
+module_param_named(enable_dynamic_fifo,
+		   dwc_otg_module_params.enable_dynamic_fifo, int, 0444);
+MODULE_PARM_DESC(enable_dynamic_fifo, "0=cC Setting 1=Allow Dynamic Sizing");
+module_param_named(data_fifo_size, dwc_otg_module_params.data_fifo_size, int,
+		   0444);
+MODULE_PARM_DESC(data_fifo_size,
+		 "Total number of words in the data FIFO memory 32-32768");
+module_param_named(dev_rx_fifo_size, dwc_otg_module_params.dev_rx_fifo_size,
+		   int, 0444);
+MODULE_PARM_DESC(dev_rx_fifo_size, "Number of words in the Rx FIFO 16-32768");
+module_param_named(dev_nperio_tx_fifo_size,
+		   dwc_otg_module_params.dev_nperio_tx_fifo_size, int, 0444);
+MODULE_PARM_DESC(dev_nperio_tx_fifo_size,
+		 "Number of words in the non-periodic Tx FIFO 16-32768");
+module_param_named(dev_perio_tx_fifo_size_1,
+		   dwc_otg_module_params.dev_perio_tx_fifo_size[0], int, 0444);
+MODULE_PARM_DESC(dev_perio_tx_fifo_size_1,
+		 "Number of words in the periodic Tx FIFO 4-768");
+module_param_named(dev_perio_tx_fifo_size_2,
+		   dwc_otg_module_params.dev_perio_tx_fifo_size[1], int, 0444);
+MODULE_PARM_DESC(dev_perio_tx_fifo_size_2,
+		 "Number of words in the periodic Tx FIFO 4-768");
+module_param_named(dev_perio_tx_fifo_size_3,
+		   dwc_otg_module_params.dev_perio_tx_fifo_size[2], int, 0444);
+MODULE_PARM_DESC(dev_perio_tx_fifo_size_3,
+		 "Number of words in the periodic Tx FIFO 4-768");
+module_param_named(dev_perio_tx_fifo_size_4,
+		   dwc_otg_module_params.dev_perio_tx_fifo_size[3], int, 0444);
+MODULE_PARM_DESC(dev_perio_tx_fifo_size_4,
+		 "Number of words in the periodic Tx FIFO 4-768");
+module_param_named(dev_perio_tx_fifo_size_5,
+		   dwc_otg_module_params.dev_perio_tx_fifo_size[4], int, 0444);
+MODULE_PARM_DESC(dev_perio_tx_fifo_size_5,
+		 "Number of words in the periodic Tx FIFO 4-768");
+module_param_named(dev_perio_tx_fifo_size_6,
+		   dwc_otg_module_params.dev_perio_tx_fifo_size[5], int, 0444);
+MODULE_PARM_DESC(dev_perio_tx_fifo_size_6,
+		 "Number of words in the periodic Tx FIFO 4-768");
+module_param_named(dev_perio_tx_fifo_size_7,
+		   dwc_otg_module_params.dev_perio_tx_fifo_size[6], int, 0444);
+MODULE_PARM_DESC(dev_perio_tx_fifo_size_7,
+		 "Number of words in the periodic Tx FIFO 4-768");
+module_param_named(dev_perio_tx_fifo_size_8,
+		   dwc_otg_module_params.dev_perio_tx_fifo_size[7], int, 0444);
+MODULE_PARM_DESC(dev_perio_tx_fifo_size_8,
+		 "Number of words in the periodic Tx FIFO 4-768");
+module_param_named(dev_perio_tx_fifo_size_9,
+		   dwc_otg_module_params.dev_perio_tx_fifo_size[8], int, 0444);
+MODULE_PARM_DESC(dev_perio_tx_fifo_size_9,
+		 "Number of words in the periodic Tx FIFO 4-768");
+module_param_named(dev_perio_tx_fifo_size_10,
+		   dwc_otg_module_params.dev_perio_tx_fifo_size[9], int, 0444);
+MODULE_PARM_DESC(dev_perio_tx_fifo_size_10,
+		 "Number of words in the periodic Tx FIFO 4-768");
+module_param_named(dev_perio_tx_fifo_size_11,
+		   dwc_otg_module_params.dev_perio_tx_fifo_size[10], int, 0444);
+MODULE_PARM_DESC(dev_perio_tx_fifo_size_11,
+		 "Number of words in the periodic Tx FIFO 4-768");
+module_param_named(dev_perio_tx_fifo_size_12,
+		   dwc_otg_module_params.dev_perio_tx_fifo_size[11], int, 0444);
+MODULE_PARM_DESC(dev_perio_tx_fifo_size_12,
+		 "Number of words in the periodic Tx FIFO 4-768");
+module_param_named(dev_perio_tx_fifo_size_13,
+		   dwc_otg_module_params.dev_perio_tx_fifo_size[12], int, 0444);
+MODULE_PARM_DESC(dev_perio_tx_fifo_size_13,
+		 "Number of words in the periodic Tx FIFO 4-768");
+module_param_named(dev_perio_tx_fifo_size_14,
+		   dwc_otg_module_params.dev_perio_tx_fifo_size[13], int, 0444);
+MODULE_PARM_DESC(dev_perio_tx_fifo_size_14,
+		 "Number of words in the periodic Tx FIFO 4-768");
+module_param_named(dev_perio_tx_fifo_size_15,
+		   dwc_otg_module_params.dev_perio_tx_fifo_size[14], int, 0444);
+MODULE_PARM_DESC(dev_perio_tx_fifo_size_15,
+		 "Number of words in the periodic Tx FIFO 4-768");
+module_param_named(host_rx_fifo_size, dwc_otg_module_params.host_rx_fifo_size,
+		   int, 0444);
+MODULE_PARM_DESC(host_rx_fifo_size, "Number of words in the Rx FIFO 16-32768");
+module_param_named(host_nperio_tx_fifo_size,
+		   dwc_otg_module_params.host_nperio_tx_fifo_size, int, 0444);
+MODULE_PARM_DESC(host_nperio_tx_fifo_size,
+		 "Number of words in the non-periodic Tx FIFO 16-32768");
+module_param_named(host_perio_tx_fifo_size,
+		   dwc_otg_module_params.host_perio_tx_fifo_size, int, 0444);
+MODULE_PARM_DESC(host_perio_tx_fifo_size,
+		 "Number of words in the host periodic Tx FIFO 16-32768");
+module_param_named(max_transfer_size, dwc_otg_module_params.max_transfer_size,
+		   int, 0444);
+/** @todo Set the max to 512K, modify checks */
+MODULE_PARM_DESC(max_transfer_size,
+		 "The maximum transfer size supported in bytes 2047-65535");
+module_param_named(max_packet_count, dwc_otg_module_params.max_packet_count,
+		   int, 0444);
+MODULE_PARM_DESC(max_packet_count,
+		 "The maximum number of packets in a transfer 15-511");
+module_param_named(host_channels, dwc_otg_module_params.host_channels, int,
+		   0444);
+MODULE_PARM_DESC(host_channels,
+		 "The number of host channel registers to use 1-16");
+module_param_named(dev_endpoints, dwc_otg_module_params.dev_endpoints, int,
+		   0444);
+MODULE_PARM_DESC(dev_endpoints,
+		 "The number of endpoints in addition to EP0 available for device mode 1-15");
+module_param_named(phy_type, dwc_otg_module_params.phy_type, int, 0444);
+MODULE_PARM_DESC(phy_type, "0=Reserved 1=UTMI+ 2=ULPI");
+module_param_named(phy_utmi_width, dwc_otg_module_params.phy_utmi_width, int,
+		   0444);
+MODULE_PARM_DESC(phy_utmi_width, "Specifies the UTMI+ Data Width 8 or 16 bits");
+module_param_named(phy_ulpi_ddr, dwc_otg_module_params.phy_ulpi_ddr, int, 0444);
+MODULE_PARM_DESC(phy_ulpi_ddr,
+		 "ULPI at double or single data rate 0=Single 1=Double");
+module_param_named(phy_ulpi_ext_vbus, dwc_otg_module_params.phy_ulpi_ext_vbus,
+		   int, 0444);
+MODULE_PARM_DESC(phy_ulpi_ext_vbus,
+		 "ULPI PHY using internal or external vbus 0=Internal");
+module_param_named(i2c_enable, dwc_otg_module_params.i2c_enable, int, 0444);
+MODULE_PARM_DESC(i2c_enable, "FS PHY Interface");
+module_param_named(ulpi_fs_ls, dwc_otg_module_params.ulpi_fs_ls, int, 0444);
+MODULE_PARM_DESC(ulpi_fs_ls, "ULPI PHY FS/LS mode only");
+module_param_named(ts_dline, dwc_otg_module_params.ts_dline, int, 0444);
+MODULE_PARM_DESC(ts_dline, "Term select Dline pulsing for all PHYs");
+module_param_named(debug, g_dbg_lvl, int, 0444);
+MODULE_PARM_DESC(debug, "");
+
+module_param_named(en_multiple_tx_fifo,
+		   dwc_otg_module_params.en_multiple_tx_fifo, int, 0444);
+MODULE_PARM_DESC(en_multiple_tx_fifo,
+		 "Dedicated Non Periodic Tx FIFOs 0=disabled 1=enabled");
+module_param_named(dev_tx_fifo_size_1,
+		   dwc_otg_module_params.dev_tx_fifo_size[0], int, 0444);
+MODULE_PARM_DESC(dev_tx_fifo_size_1, "Number of words in the Tx FIFO 4-768");
+module_param_named(dev_tx_fifo_size_2,
+		   dwc_otg_module_params.dev_tx_fifo_size[1], int, 0444);
+MODULE_PARM_DESC(dev_tx_fifo_size_2, "Number of words in the Tx FIFO 4-768");
+module_param_named(dev_tx_fifo_size_3,
+		   dwc_otg_module_params.dev_tx_fifo_size[2], int, 0444);
+MODULE_PARM_DESC(dev_tx_fifo_size_3, "Number of words in the Tx FIFO 4-768");
+module_param_named(dev_tx_fifo_size_4,
+		   dwc_otg_module_params.dev_tx_fifo_size[3], int, 0444);
+MODULE_PARM_DESC(dev_tx_fifo_size_4, "Number of words in the Tx FIFO 4-768");
+module_param_named(dev_tx_fifo_size_5,
+		   dwc_otg_module_params.dev_tx_fifo_size[4], int, 0444);
+MODULE_PARM_DESC(dev_tx_fifo_size_5, "Number of words in the Tx FIFO 4-768");
+module_param_named(dev_tx_fifo_size_6,
+		   dwc_otg_module_params.dev_tx_fifo_size[5], int, 0444);
+MODULE_PARM_DESC(dev_tx_fifo_size_6, "Number of words in the Tx FIFO 4-768");
+module_param_named(dev_tx_fifo_size_7,
+		   dwc_otg_module_params.dev_tx_fifo_size[6], int, 0444);
+MODULE_PARM_DESC(dev_tx_fifo_size_7, "Number of words in the Tx FIFO 4-768");
+module_param_named(dev_tx_fifo_size_8,
+		   dwc_otg_module_params.dev_tx_fifo_size[7], int, 0444);
+MODULE_PARM_DESC(dev_tx_fifo_size_8, "Number of words in the Tx FIFO 4-768");
+module_param_named(dev_tx_fifo_size_9,
+		   dwc_otg_module_params.dev_tx_fifo_size[8], int, 0444);
+MODULE_PARM_DESC(dev_tx_fifo_size_9, "Number of words in the Tx FIFO 4-768");
+module_param_named(dev_tx_fifo_size_10,
+		   dwc_otg_module_params.dev_tx_fifo_size[9], int, 0444);
+MODULE_PARM_DESC(dev_tx_fifo_size_10, "Number of words in the Tx FIFO 4-768");
+module_param_named(dev_tx_fifo_size_11,
+		   dwc_otg_module_params.dev_tx_fifo_size[10], int, 0444);
+MODULE_PARM_DESC(dev_tx_fifo_size_11, "Number of words in the Tx FIFO 4-768");
+module_param_named(dev_tx_fifo_size_12,
+		   dwc_otg_module_params.dev_tx_fifo_size[11], int, 0444);
+MODULE_PARM_DESC(dev_tx_fifo_size_12, "Number of words in the Tx FIFO 4-768");
+module_param_named(dev_tx_fifo_size_13,
+		   dwc_otg_module_params.dev_tx_fifo_size[12], int, 0444);
+MODULE_PARM_DESC(dev_tx_fifo_size_13, "Number of words in the Tx FIFO 4-768");
+module_param_named(dev_tx_fifo_size_14,
+		   dwc_otg_module_params.dev_tx_fifo_size[13], int, 0444);
+MODULE_PARM_DESC(dev_tx_fifo_size_14, "Number of words in the Tx FIFO 4-768");
+module_param_named(dev_tx_fifo_size_15,
+		   dwc_otg_module_params.dev_tx_fifo_size[14], int, 0444);
+MODULE_PARM_DESC(dev_tx_fifo_size_15, "Number of words in the Tx FIFO 4-768");
+
+module_param_named(thr_ctl, dwc_otg_module_params.thr_ctl, int, 0444);
+MODULE_PARM_DESC(thr_ctl,
+		 "Thresholding enable flag bit 0 - non ISO Tx thr., 1 - ISO Tx thr., 2 - Rx thr.- bit 0=disabled 1=enabled");
+module_param_named(tx_thr_length, dwc_otg_module_params.tx_thr_length, int,
+		   0444);
+MODULE_PARM_DESC(tx_thr_length, "Tx Threshold length in 32 bit DWORDs");
+module_param_named(rx_thr_length, dwc_otg_module_params.rx_thr_length, int,
+		   0444);
+MODULE_PARM_DESC(rx_thr_length, "Rx Threshold length in 32 bit DWORDs");
+
+module_param_named(pti_enable, dwc_otg_module_params.pti_enable, int, 0444);
+module_param_named(mpi_enable, dwc_otg_module_params.mpi_enable, int, 0444);
+module_param_named(lpm_enable, dwc_otg_module_params.lpm_enable, int, 0444);
+MODULE_PARM_DESC(lpm_enable, "LPM Enable 0=LPM Disabled 1=LPM Enabled");
+module_param_named(ic_usb_cap, dwc_otg_module_params.ic_usb_cap, int, 0444);
+MODULE_PARM_DESC(ic_usb_cap,
+		 "IC_USB Capability 0=IC_USB Disabled 1=IC_USB Enabled");
+module_param_named(ahb_thr_ratio, dwc_otg_module_params.ahb_thr_ratio, int,
+		   0444);
+MODULE_PARM_DESC(ahb_thr_ratio, "AHB Threshold Ratio");
+module_param_named(power_down, dwc_otg_module_params.power_down, int, 0444);
+MODULE_PARM_DESC(power_down, "Power Down Mode");
+module_param_named(reload_ctl, dwc_otg_module_params.reload_ctl, int, 0444);
+MODULE_PARM_DESC(reload_ctl, "HFIR Reload Control");
+module_param_named(dev_out_nak, dwc_otg_module_params.dev_out_nak, int, 0444);
+MODULE_PARM_DESC(dev_out_nak, "Enable Device OUT NAK");
+module_param_named(cont_on_bna, dwc_otg_module_params.cont_on_bna, int, 0444);
+MODULE_PARM_DESC(cont_on_bna, "Enable Enable Continue on BNA");
+module_param_named(ahb_single, dwc_otg_module_params.ahb_single, int, 0444);
+MODULE_PARM_DESC(ahb_single, "Enable AHB Single Support");
+module_param_named(adp_enable, dwc_otg_module_params.adp_enable, int, 0444);
+MODULE_PARM_DESC(adp_enable, "ADP Enable 0=ADP Disabled 1=ADP Enabled");
+module_param_named(otg_ver, dwc_otg_module_params.otg_ver, int, 0444);
+MODULE_PARM_DESC(otg_ver, "OTG revision supported 0=OTG 1.3 1=OTG 2.0");
+
+/** @page "Module Parameters"
+ *
+ * The following parameters may be specified when starting the module.
+ * These parameters define how the DWC_otg controller should be
+ * configured. Parameter values are passed to the CIL initialization
+ * function dwc_otg_cil_init
+ *
+ * Example: <code>modprobe dwc_otg speed=1 otg_cap=1</code>
+ *
+
+ <table>
+ <tr><td>Parameter Name</td><td>Meaning</td></tr>
+
+ <tr>
+ <td>otg_cap</td>
+ <td>Specifies the OTG capabilities. The driver will automatically detect the
+ value for this parameter if none is specified.
+ - 0: HNP and SRP capable (default, if available)
+ - 1: SRP Only capable
+ - 2: No HNP/SRP capable
+ </td></tr>
+
+ <tr>
+ <td>dma_enable</td>
+ <td>Specifies whether to use slave or DMA mode for accessing the data FIFOs.
+ The driver will automatically detect the value for this parameter if none is
+ specified.
+ - 0: Slave
+ - 1: DMA (default, if available)
+ </td></tr>
+
+ <tr>
+ <td>dma_burst_size</td>
+ <td>The DMA Burst size (applicable only for External DMA Mode).
+ - Values: 1, 4, 8 16, 32, 64, 128, 256 (default 32)
+ </td></tr>
+
+ <tr>
+ <td>speed</td>
+ <td>Specifies the maximum speed of operation in host and device mode. The
+ actual speed depends on the speed of the attached device and the value of
+ phy_type.
+ - 0: High Speed (default)
+ - 1: Full Speed
+ </td></tr>
+
+ <tr>
+ <td>host_support_fs_ls_low_power</td>
+ <td>Specifies whether low power mode is supported when attached to a Full
+ Speed or Low Speed device in host mode.
+ - 0: Don't support low power mode (default)
+ - 1: Support low power mode
+ </td></tr>
+
+ <tr>
+ <td>host_ls_low_power_phy_clk</td>
+ <td>Specifies the PHY clock rate in low power mode when connected to a Low
+ Speed device in host mode. This parameter is applicable only if
+ HOST_SUPPORT_FS_LS_LOW_POWER is enabled.
+ - 0: 48 MHz (default)
+ - 1: 6 MHz
+ </td></tr>
+
+ <tr>
+ <td>enable_dynamic_fifo</td>
+ <td> Specifies whether FIFOs may be resized by the driver software.
+ - 0: Use cC FIFO size parameters
+ - 1: Allow dynamic FIFO sizing (default)
+ </td></tr>
+
+ <tr>
+ <td>data_fifo_size</td>
+ <td>Total number of 4-byte words in the data FIFO memory. This memory
+ includes the Rx FIFO, non-periodic Tx FIFO, and periodic Tx FIFOs.
+ - Values: 32 to 32768 (default 8192)
+
+ Note: The total FIFO memory depth in the FPGA configuration is 8192.
+ </td></tr>
+
+ <tr>
+ <td>dev_rx_fifo_size</td>
+ <td>Number of 4-byte words in the Rx FIFO in device mode when dynamic
+ FIFO sizing is enabled.
+ - Values: 16 to 32768 (default 1064)
+ </td></tr>
+
+ <tr>
+ <td>dev_nperio_tx_fifo_size</td>
+ <td>Number of 4-byte words in the non-periodic Tx FIFO in device mode when
+ dynamic FIFO sizing is enabled.
+ - Values: 16 to 32768 (default 1024)
+ </td></tr>
+
+ <tr>
+ <td>dev_perio_tx_fifo_size_n (n = 1 to 15)</td>
+ <td>Number of 4-byte words in each of the periodic Tx FIFOs in device mode
+ when dynamic FIFO sizing is enabled.
+ - Values: 4 to 768 (default 256)
+ </td></tr>
+
+ <tr>
+ <td>host_rx_fifo_size</td>
+ <td>Number of 4-byte words in the Rx FIFO in host mode when dynamic FIFO
+ sizing is enabled.
+ - Values: 16 to 32768 (default 1024)
+ </td></tr>
+
+ <tr>
+ <td>host_nperio_tx_fifo_size</td>
+ <td>Number of 4-byte words in the non-periodic Tx FIFO in host mode when
+ dynamic FIFO sizing is enabled in the core.
+ - Values: 16 to 32768 (default 1024)
+ </td></tr>
+
+ <tr>
+ <td>host_perio_tx_fifo_size</td>
+ <td>Number of 4-byte words in the host periodic Tx FIFO when dynamic FIFO
+ sizing is enabled.
+ - Values: 16 to 32768 (default 1024)
+ </td></tr>
+
+ <tr>
+ <td>max_transfer_size</td>
+ <td>The maximum transfer size supported in bytes.
+ - Values: 2047 to 65,535 (default 65,535)
+ </td></tr>
+
+ <tr>
+ <td>max_packet_count</td>
+ <td>The maximum number of packets in a transfer.
+ - Values: 15 to 511 (default 511)
+ </td></tr>
+
+ <tr>
+ <td>host_channels</td>
+ <td>The number of host channel registers to use.
+ - Values: 1 to 16 (default 12)
+
+ Note: The FPGA configuration supports a maximum of 12 host channels.
+ </td></tr>
+
+ <tr>
+ <td>dev_endpoints</td>
+ <td>The number of endpoints in addition to EP0 available for device mode
+ operations.
+ - Values: 1 to 15 (default 6 IN and OUT)
+
+ Note: The FPGA configuration supports a maximum of 6 IN and OUT endpoints in
+ addition to EP0.
+ </td></tr>
+
+ <tr>
+ <td>phy_type</td>
+ <td>Specifies the type of PHY interface to use. By default, the driver will
+ automatically detect the phy_type.
+ - 0: Full Speed
+ - 1: UTMI+ (default, if available)
+ - 2: ULPI
+ </td></tr>
+
+ <tr>
+ <td>phy_utmi_width</td>
+ <td>Specifies the UTMI+ Data Width. This parameter is applicable for a
+ phy_type of UTMI+. Also, this parameter is applicable only if the
+ OTG_HSPHY_WIDTH cC parameter was set to "8 and 16 bits", meaning that the
+ core has been configured to work at either data path width.
+ - Values: 8 or 16 bits (default 16)
+ </td></tr>
+
+ <tr>
+ <td>phy_ulpi_ddr</td>
+ <td>Specifies whether the ULPI operates at double or single data rate. This
+ parameter is only applicable if phy_type is ULPI.
+ - 0: single data rate ULPI interface with 8 bit wide data bus (default)
+ - 1: double data rate ULPI interface with 4 bit wide data bus
+ </td></tr>
+
+ <tr>
+ <td>i2c_enable</td>
+ <td>Specifies whether to use the I2C interface for full speed PHY. This
+ parameter is only applicable if PHY_TYPE is FS.
+ - 0: Disabled (default)
+ - 1: Enabled
+ </td></tr>
+
+ <tr>
+ <td>ulpi_fs_ls</td>
+ <td>Specifies whether to use ULPI FS/LS mode only.
+ - 0: Disabled (default)
+ - 1: Enabled
+ </td></tr>
+
+ <tr>
+ <td>ts_dline</td>
+ <td>Specifies whether term select D-Line pulsing for all PHYs is enabled.
+ - 0: Disabled (default)
+ - 1: Enabled
+ </td></tr>
+
+ <tr>
+ <td>en_multiple_tx_fifo</td>
+ <td>Specifies whether dedicatedto tx fifos are enabled for non periodic IN EPs.
+ The driver will automatically detect the value for this parameter if none is
+ specified.
+ - 0: Disabled
+ - 1: Enabled (default, if available)
+ </td></tr>
+
+ <tr>
+ <td>dev_tx_fifo_size_n (n = 1 to 15)</td>
+ <td>Number of 4-byte words in each of the Tx FIFOs in device mode
+ when dynamic FIFO sizing is enabled.
+ - Values: 4 to 768 (default 256)
+ </td></tr>
+
+ <tr>
+ <td>tx_thr_length</td>
+ <td>Transmit Threshold length in 32 bit double words
+ - Values: 8 to 128 (default 64)
+ </td></tr>
+
+ <tr>
+ <td>rx_thr_length</td>
+ <td>Receive Threshold length in 32 bit double words
+ - Values: 8 to 128 (default 64)
+ </td></tr>
+
+<tr>
+ <td>thr_ctl</td>
+ <td>Specifies whether to enable Thresholding for Device mode. Bits 0, 1, 2 of
+ this parmater specifies if thresholding is enabled for non-Iso Tx, Iso Tx and
+ Rx transfers accordingly.
+ The driver will automatically detect the value for this parameter if none is
+ specified.
+ - Values: 0 to 7 (default 0)
+ Bit values indicate:
+ - 0: Thresholding disabled
+ - 1: Thresholding enabled
+ </td></tr>
+
+<tr>
+ <td>dma_desc_enable</td>
+ <td>Specifies whether to enable Descriptor DMA mode.
+ The driver will automatically detect the value for this parameter if none is
+ specified.
+ - 0: Descriptor DMA disabled
+ - 1: Descriptor DMA (default, if available)
+ </td></tr>
+
+<tr>
+ <td>mpi_enable</td>
+ <td>Specifies whether to enable MPI enhancement mode.
+ The driver will automatically detect the value for this parameter if none is
+ specified.
+ - 0: MPI disabled (default)
+ - 1: MPI enable
+ </td></tr>
+
+<tr>
+ <td>pti_enable</td>
+ <td>Specifies whether to enable PTI enhancement support.
+ The driver will automatically detect the value for this parameter if none is
+ specified.
+ - 0: PTI disabled (default)
+ - 1: PTI enable
+ </td></tr>
+
+<tr>
+ <td>lpm_enable</td>
+ <td>Specifies whether to enable LPM support.
+ The driver will automatically detect the value for this parameter if none is
+ specified.
+ - 0: LPM disabled
+ - 1: LPM enable (default, if available)
+ </td></tr>
+
+<tr>
+ <td>ic_usb_cap</td>
+ <td>Specifies whether to enable IC_USB capability.
+ The driver will automatically detect the value for this parameter if none is
+ specified.
+ - 0: IC_USB disabled (default, if available)
+ - 1: IC_USB enable
+ </td></tr>
+
+<tr>
+ <td>ahb_thr_ratio</td>
+ <td>Specifies AHB Threshold ratio.
+ - Values: 0 to 3 (default 0)
+ </td></tr>
+
+<tr>
+ <td>power_down</td>
+ <td>Specifies Power Down(Hibernation) Mode.
+ The driver will automatically detect the value for this parameter if none is
+ specified.
+ - 0: Power Down disabled (default)
+ - 2: Power Down enabled
+ </td></tr>
+
+ <tr>
+ <td>reload_ctl</td>
+ <td>Specifies whether dynamic reloading of the HFIR register is allowed during
+ run time. The driver will automatically detect the value for this parameter if
+ none is specified. In case the HFIR value is reloaded when HFIR.RldCtrl == 1'b0
+ the core might misbehave.
+ - 0: Reload Control disabled (default)
+ - 1: Reload Control enabled
+ </td></tr>
+
+ <tr>
+ <td>dev_out_nak</td>
+ <td>Specifies whether  Device OUT NAK enhancement enabled or no.
+ The driver will automatically detect the value for this parameter if
+ none is specified. This parameter is valid only when OTG_EN_DESC_DMA == 1Â’b1.
+ - 0: The core does not set NAK after Bulk OUT transfer complete (default)
+ - 1: The core sets NAK after Bulk OUT transfer complete
+ </td></tr>
+
+ <tr>
+ <td>cont_on_bna</td>
+ <td>Specifies whether Enable Continue on BNA enabled or no.
+ After receiving BNA interrupt the core disables the endpoint,when the
+ endpoint is re-enabled by the application the
+ - 0: Core starts processing from the DOEPDMA descriptor (default)
+ - 1: Core starts processing from the descriptor which received the BNA.
+ This parameter is valid only when OTG_EN_DESC_DMA == 1Â’b1.
+ </td></tr>
+
+ <tr>
+ <td>ahb_single</td>
+ <td>This bit when programmed supports SINGLE transfers for remainder data
+ in a transfer for DMA mode of operation.
+ - 0: The remainder data will be sent using INCR burst size (default)
+ - 1: The remainder data will be sent using SINGLE burst size.
+ </td></tr>
+
+<tr>
+ <td>adp_enable</td>
+ <td>Specifies whether ADP feature is enabled.
+ The driver will automatically detect the value for this parameter if none is
+ specified.
+ - 0: ADP feature disabled (default)
+ - 1: ADP feature enabled
+ </td></tr>
+
+  <tr>
+ <td>otg_ver</td>
+ <td>Specifies whether OTG is performing as USB OTG Revision 2.0 or Revision 1.3
+ USB OTG device.
+ - 0: OTG 2.0 support disabled (default)
+ - 1: OTG 2.0 support enabled
+ </td></tr>
+
+*/
diff --git a/drivers/usb/dwc_otg/dwc_otg_driver.h b/drivers/usb/dwc_otg/dwc_otg_driver.h
new file mode 100644
index 0000000..7e3cf23
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_driver.h
@@ -0,0 +1,88 @@
+/* ==========================================================================
+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_driver.h $
+ * $Revision: #19 $
+ * $Date: 2010/11/15 $
+ * $Change: 1627671 $
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ * 
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ * 
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+#ifndef __DWC_OTG_DRIVER_H__
+#define __DWC_OTG_DRIVER_H__
+
+/** @file
+ * This file contains the interface to the Linux driver.
+ */
+#include "dwc_otg_os_dep.h"
+#include "dwc_otg_core_if.h"
+
+/* Type declarations */
+struct dwc_otg_pcd;
+struct dwc_otg_hcd;
+
+/**
+ * This structure is a wrapper that encapsulates the driver components used to
+ * manage a single DWC_otg controller.
+ */
+typedef struct dwc_otg_device {
+	/** Structure containing OS-dependent stuff. KEEP THIS STRUCT AT THE
+	 * VERY BEGINNING OF THE DEVICE STRUCT. OSes such as FreeBSD and NetBSD
+	 * require this. */
+	struct os_dependent os_dep;
+
+	/** Pointer to the core interface structure. */
+	dwc_otg_core_if_t *core_if;
+
+	/** Pointer to the PCD structure. */
+	struct dwc_otg_pcd *pcd;
+
+	/** Pointer to the HCD structure. */
+	struct dwc_otg_hcd *hcd;
+
+	/** Flag to indicate whether the common IRQ handler is installed. */
+	uint8_t common_irq_installed;
+
+	/* Interrupt request number. */
+	unsigned int irq;
+} dwc_otg_device_t;
+
+/*We must clear S3C24XX_EINTPEND external interrupt register 
+ * because after clearing in this register trigerred IRQ from 
+ * H/W core in kernel interrupt can be occured again before OTG
+ * handlers clear all IRQ sources of Core registers because of
+ * timing latencies and Low Level IRQ Type.
+ */
+#ifdef CONFIG_MACH_IPMATE
+#define  S3C2410X_CLEAR_EINTPEND()   \
+do { \
+	__raw_writel(1UL << 11,S3C24XX_EINTPEND); \
+} while (0)
+#else
+#define  S3C2410X_CLEAR_EINTPEND()   do { } while (0)
+#endif
+
+#endif
diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd.c b/drivers/usb/dwc_otg/dwc_otg_hcd.c
new file mode 100644
index 0000000..d49f475
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_hcd.c
@@ -0,0 +1,3348 @@
+/* ==========================================================================
+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.c $
+ * $Revision: #104 $
+ * $Date: 2011/10/24 $
+ * $Change: 1871159 $
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+#ifndef DWC_DEVICE_ONLY
+
+/** @file
+ * This file implements HCD Core. All code in this file is portable and doesn't
+ * use any OS specific functions.
+ * Interface provided by HCD Core is defined in <code><hcd_if.h></code>
+ * header file.
+ */
+
+#include "dwc_otg_hcd.h"
+#include "dwc_otg_regs.h"
+
+dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void)
+{
+	return DWC_ALLOC(sizeof(dwc_otg_hcd_t));
+}
+
+/**
+ * Connection timeout function.  An OTG host is required to display a
+ * message if the device does not connect within 10 seconds.
+ */
+void dwc_otg_hcd_connect_timeout(void *ptr)
+{
+	DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, ptr);
+	DWC_PRINTF("Connect Timeout\n");
+	__DWC_ERROR("Device Not Connected/Responding\n");
+}
+
+#ifdef DEBUG
+static void dump_channel_info(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+{
+	if (qh->channel != NULL) {
+		dwc_hc_t *hc = qh->channel;
+		dwc_list_link_t *item;
+		dwc_otg_qh_t *qh_item;
+		int num_channels = hcd->core_if->core_params->host_channels;
+		int i;
+
+		dwc_otg_hc_regs_t *hc_regs;
+		hcchar_data_t hcchar;
+		hcsplt_data_t hcsplt;
+		hctsiz_data_t hctsiz;
+		uint32_t hcdma;
+
+		hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num];
+		hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+		hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
+		hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
+		hcdma = DWC_READ_REG32(&hc_regs->hcdma);
+
+		DWC_PRINTF("  Assigned to channel %p:\n", hc);
+		DWC_PRINTF("    hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32,
+			   hcsplt.d32);
+		DWC_PRINTF("    hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32,
+			   hcdma);
+		DWC_PRINTF("    dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
+			   hc->dev_addr, hc->ep_num, hc->ep_is_in);
+		DWC_PRINTF("    ep_type: %d\n", hc->ep_type);
+		DWC_PRINTF("    max_packet: %d\n", hc->max_packet);
+		DWC_PRINTF("    data_pid_start: %d\n", hc->data_pid_start);
+		DWC_PRINTF("    xfer_started: %d\n", hc->xfer_started);
+		DWC_PRINTF("    halt_status: %d\n", hc->halt_status);
+		DWC_PRINTF("    xfer_buff: %p\n", hc->xfer_buff);
+		DWC_PRINTF("    xfer_len: %d\n", hc->xfer_len);
+		DWC_PRINTF("    qh: %p\n", hc->qh);
+		DWC_PRINTF("  NP inactive sched:\n");
+		DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_inactive) {
+			qh_item =
+			    DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
+			DWC_PRINTF("    %p\n", qh_item);
+		}
+		DWC_PRINTF("  NP active sched:\n");
+		DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_active) {
+			qh_item =
+			    DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
+			DWC_PRINTF("    %p\n", qh_item);
+		}
+		DWC_PRINTF("  Channels: \n");
+		for (i = 0; i < num_channels; i++) {
+			dwc_hc_t *hc = hcd->hc_ptr_array[i];
+			DWC_PRINTF("    %2d: %p\n", i, hc);
+		}
+	}
+}
+#endif /* DEBUG */
+
+/**
+ * Work queue function for starting the HCD when A-Cable is connected.
+ * The hcd_start() must be called in a process context.
+ */
+static void hcd_start_func(void *_vp)
+{
+	dwc_otg_hcd_t *hcd = (dwc_otg_hcd_t *) _vp;
+
+	DWC_DEBUGPL(DBG_HCDV, "%s() %p\n", __func__, hcd);
+	if (hcd) {
+		hcd->fops->start(hcd);
+	}
+}
+
+static void del_xfer_timers(dwc_otg_hcd_t * hcd)
+{
+#ifdef DEBUG
+	int i;
+	int num_channels = hcd->core_if->core_params->host_channels;
+	for (i = 0; i < num_channels; i++) {
+		DWC_TIMER_CANCEL(hcd->core_if->hc_xfer_timer[i]);
+	}
+#endif
+}
+
+static void del_timers(dwc_otg_hcd_t * hcd)
+{
+	del_xfer_timers(hcd);
+	DWC_TIMER_CANCEL(hcd->conn_timer);
+}
+
+/**
+ * Processes all the URBs in a single list of QHs. Completes them with
+ * -ETIMEDOUT and frees the QTD.
+ */
+static void kill_urbs_in_qh_list(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
+{
+	dwc_list_link_t *qh_item;
+	dwc_otg_qh_t *qh;
+	dwc_otg_qtd_t *qtd, *qtd_tmp;
+
+	DWC_LIST_FOREACH(qh_item, qh_list) {
+		qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry);
+		DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp,
+					 &qh->qtd_list, qtd_list_entry) {
+			qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
+			if (qtd->urb != NULL) {
+				hcd->fops->complete(hcd, qtd->urb->priv,
+						    qtd->urb, -DWC_E_TIMEOUT);
+				dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
+			}
+
+		}
+	}
+}
+
+/**
+ * Responds with an error status of ETIMEDOUT to all URBs in the non-periodic
+ * and periodic schedules. The QTD associated with each URB is removed from
+ * the schedule and freed. This function may be called when a disconnect is
+ * detected or when the HCD is being stopped.
+ */
+static void kill_all_urbs(dwc_otg_hcd_t * hcd)
+{
+	kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_inactive);
+	kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_active);
+	kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_inactive);
+	kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_ready);
+	kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_assigned);
+	kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_queued);
+}
+
+/**
+ * Start the connection timer.  An OTG host is required to display a
+ * message if the device does not connect within 10 seconds.  The
+ * timer is deleted if a port connect interrupt occurs before the
+ * timer expires.
+ */
+static void dwc_otg_hcd_start_connect_timer(dwc_otg_hcd_t * hcd)
+{
+	DWC_TIMER_SCHEDULE(hcd->conn_timer, 10000 /* 10 secs */ );
+}
+
+/**
+ * HCD Callback function for disconnect of the HCD.
+ *
+ * @param p void pointer to the <code>struct usb_hcd</code>
+ */
+static int32_t dwc_otg_hcd_session_start_cb(void *p)
+{
+	dwc_otg_hcd_t *dwc_otg_hcd;
+	DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
+	dwc_otg_hcd = p;
+	dwc_otg_hcd_start_connect_timer(dwc_otg_hcd);
+	return 1;
+}
+
+/**
+ * HCD Callback function for starting the HCD when A-Cable is
+ * connected.
+ *
+ * @param p void pointer to the <code>struct usb_hcd</code>
+ */
+static int32_t dwc_otg_hcd_start_cb(void *p)
+{
+	dwc_otg_hcd_t *dwc_otg_hcd = p;
+	dwc_otg_core_if_t *core_if;
+	hprt0_data_t hprt0;
+
+	core_if = dwc_otg_hcd->core_if;
+
+	if (core_if->op_state == B_HOST) {
+		/*
+		 * Reset the port.  During a HNP mode switch the reset
+		 * needs to occur within 1ms and have a duration of at
+		 * least 50ms.
+		 */
+		hprt0.d32 = dwc_otg_read_hprt0(core_if);
+		hprt0.b.prtrst = 1;
+		DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+	}
+	DWC_WORKQ_SCHEDULE_DELAYED(core_if->wq_otg,
+				   hcd_start_func, dwc_otg_hcd, 50,
+				   "start hcd");
+
+	return 1;
+}
+
+/**
+ * HCD Callback function for disconnect of the HCD.
+ *
+ * @param p void pointer to the <code>struct usb_hcd</code>
+ */
+static int32_t dwc_otg_hcd_disconnect_cb(void *p)
+{
+	gintsts_data_t intr;
+	dwc_otg_hcd_t *dwc_otg_hcd = p;
+
+	/*
+	 * Set status flags for the hub driver.
+	 */
+	dwc_otg_hcd->flags.b.port_connect_status_change = 1;
+	dwc_otg_hcd->flags.b.port_connect_status = 0;
+
+	/*
+	 * Shutdown any transfers in process by clearing the Tx FIFO Empty
+	 * interrupt mask and status bits and disabling subsequent host
+	 * channel interrupts.
+	 */
+	intr.d32 = 0;
+	intr.b.nptxfempty = 1;
+	intr.b.ptxfempty = 1;
+	intr.b.hcintr = 1;
+	DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintmsk,
+			 intr.d32, 0);
+	DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintsts,
+			 intr.d32, 0);
+
+	del_timers(dwc_otg_hcd);
+
+	/*
+	 * Turn off the vbus power only if the core has transitioned to device
+	 * mode. If still in host mode, need to keep power on to detect a
+	 * reconnection.
+	 */
+	if (dwc_otg_is_device_mode(dwc_otg_hcd->core_if)) {
+		if (dwc_otg_hcd->core_if->op_state != A_SUSPEND) {
+			hprt0_data_t hprt0 = {.d32 = 0 };
+			DWC_PRINTF("Disconnect: PortPower off\n");
+			hprt0.b.prtpwr = 0;
+			DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0,
+					hprt0.d32);
+		}
+
+		dwc_otg_disable_host_interrupts(dwc_otg_hcd->core_if);
+	}
+
+	/* Respond with an error status to all URBs in the schedule. */
+	kill_all_urbs(dwc_otg_hcd);
+
+	if (dwc_otg_is_host_mode(dwc_otg_hcd->core_if)) {
+		/* Clean up any host channels that were in use. */
+		int num_channels;
+		int i;
+		dwc_hc_t *channel;
+		dwc_otg_hc_regs_t *hc_regs;
+		hcchar_data_t hcchar;
+
+		num_channels = dwc_otg_hcd->core_if->core_params->host_channels;
+
+		if (!dwc_otg_hcd->core_if->dma_enable) {
+			/* Flush out any channel requests in slave mode. */
+			for (i = 0; i < num_channels; i++) {
+				channel = dwc_otg_hcd->hc_ptr_array[i];
+				if (DWC_CIRCLEQ_EMPTY_ENTRY
+				    (channel, hc_list_entry)) {
+					hc_regs =
+					    dwc_otg_hcd->core_if->
+					    host_if->hc_regs[i];
+					hcchar.d32 =
+					    DWC_READ_REG32(&hc_regs->hcchar);
+					if (hcchar.b.chen) {
+						hcchar.b.chen = 0;
+						hcchar.b.chdis = 1;
+						hcchar.b.epdir = 0;
+						DWC_WRITE_REG32
+						    (&hc_regs->hcchar,
+						     hcchar.d32);
+					}
+				}
+			}
+		}
+
+		for (i = 0; i < num_channels; i++) {
+			channel = dwc_otg_hcd->hc_ptr_array[i];
+			if (DWC_CIRCLEQ_EMPTY_ENTRY(channel, hc_list_entry)) {
+				hc_regs =
+				    dwc_otg_hcd->core_if->host_if->hc_regs[i];
+				hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+				if (hcchar.b.chen) {
+					/* Halt the channel. */
+					hcchar.b.chdis = 1;
+					DWC_WRITE_REG32(&hc_regs->hcchar,
+							hcchar.d32);
+				}
+
+				dwc_otg_hc_cleanup(dwc_otg_hcd->core_if,
+						   channel);
+				DWC_CIRCLEQ_INSERT_TAIL
+				    (&dwc_otg_hcd->free_hc_list, channel,
+				     hc_list_entry);
+				/*
+				 * Added for Descriptor DMA to prevent channel double cleanup
+				 * in release_channel_ddma(). Which called from ep_disable
+				 * when device disconnect.
+				 */
+				channel->qh = NULL;
+			}
+		}
+	}
+
+	if (dwc_otg_hcd->fops->disconnect) {
+		dwc_otg_hcd->fops->disconnect(dwc_otg_hcd);
+	}
+
+	return 1;
+}
+
+/**
+ * HCD Callback function for stopping the HCD.
+ *
+ * @param p void pointer to the <code>struct usb_hcd</code>
+ */
+static int32_t dwc_otg_hcd_stop_cb(void *p)
+{
+	dwc_otg_hcd_t *dwc_otg_hcd = p;
+
+	DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
+	dwc_otg_hcd_stop(dwc_otg_hcd);
+	return 1;
+}
+
+#ifdef CONFIG_USB_DWC_OTG_LPM
+/**
+ * HCD Callback function for sleep of HCD.
+ *
+ * @param p void pointer to the <code>struct usb_hcd</code>
+ */
+static int dwc_otg_hcd_sleep_cb(void *p)
+{
+	dwc_otg_hcd_t *hcd = p;
+
+	dwc_otg_hcd_free_hc_from_lpm(hcd);
+
+	return 0;
+}
+#endif
+
+/**
+ * HCD Callback function for Remote Wakeup.
+ *
+ * @param p void pointer to the <code>struct usb_hcd</code>
+ */
+static int dwc_otg_hcd_rem_wakeup_cb(void *p)
+{
+	dwc_otg_hcd_t *hcd = p;
+
+	if (hcd->core_if->lx_state == DWC_OTG_L2) {
+		hcd->flags.b.port_suspend_change = 1;
+	}
+#ifdef CONFIG_USB_DWC_OTG_LPM
+	else {
+		hcd->flags.b.port_l1_change = 1;
+	}
+#endif
+	return 0;
+}
+
+/**
+ * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
+ * stopped.
+ */
+void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd)
+{
+	hprt0_data_t hprt0 = {.d32 = 0 };
+
+	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD STOP\n");
+
+	/*
+	 * The root hub should be disconnected before this function is called.
+	 * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue)
+	 * and the QH lists (via ..._hcd_endpoint_disable).
+	 */
+
+	/* Turn off all host-specific interrupts. */
+	dwc_otg_disable_host_interrupts(hcd->core_if);
+
+	/* Turn off the vbus power */
+	DWC_PRINTF("PortPower off\n");
+	hprt0.b.prtpwr = 0;
+	DWC_WRITE_REG32(hcd->core_if->host_if->hprt0, hprt0.d32);
+	dwc_mdelay(1);
+}
+
+int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
+			    dwc_otg_hcd_urb_t * dwc_otg_urb, void **ep_handle,
+			    int atomic_alloc)
+{
+	dwc_irqflags_t flags;
+	int retval = 0;
+	dwc_otg_qtd_t *qtd;
+	gintmsk_data_t intr_mask = {.d32 = 0 };
+
+	if (!hcd->flags.b.port_connect_status) {
+		/* No longer connected. */
+		DWC_ERROR("Not connected\n");
+		return -DWC_E_NO_DEVICE;
+	}
+
+	qtd = dwc_otg_hcd_qtd_create(dwc_otg_urb, atomic_alloc);
+	if (qtd == NULL) {
+		DWC_ERROR("DWC OTG HCD URB Enqueue failed creating QTD\n");
+		return -DWC_E_NO_MEMORY;
+	}
+
+	retval =
+	    dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc);
+	if (retval < 0) {
+		DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. "
+			  "Error status %d\n", retval);
+		dwc_otg_hcd_qtd_free(qtd);
+	} else {
+		qtd->qh = *ep_handle;
+	}
+	intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk);
+	if (!intr_mask.b.sofintr && retval == 0) {
+		dwc_otg_transaction_type_e tr_type;
+		if ((qtd->qh->ep_type == UE_BULK)
+		    && !(qtd->urb->flags & URB_GIVEBACK_ASAP)) {
+			/* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */
+			return 0;
+		}
+		DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
+		tr_type = dwc_otg_hcd_select_transactions(hcd);
+		if (tr_type != DWC_OTG_TRANSACTION_NONE) {
+			dwc_otg_hcd_queue_transactions(hcd, tr_type);
+		}
+		DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
+	}
+
+	return retval;
+}
+
+int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd,
+			    dwc_otg_hcd_urb_t * dwc_otg_urb)
+{
+	dwc_otg_qh_t *qh;
+	dwc_otg_qtd_t *urb_qtd;
+
+	urb_qtd = dwc_otg_urb->qtd;
+	qh = urb_qtd->qh;
+#ifdef DEBUG
+	if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
+		if (urb_qtd->in_process) {
+			dump_channel_info(hcd, qh);
+		}
+	}
+#endif
+	if (urb_qtd->in_process && qh->channel) {
+		/* The QTD is in process (it has been assigned to a channel). */
+		if (hcd->flags.b.port_connect_status) {
+			/*
+			 * If still connected (i.e. in host mode), halt the
+			 * channel so it can be used for other transfers. If
+			 * no longer connected, the host registers can't be
+			 * written to halt the channel since the core is in
+			 * device mode.
+			 */
+			dwc_otg_hc_halt(hcd->core_if, qh->channel,
+					DWC_OTG_HC_XFER_URB_DEQUEUE);
+		}
+	}
+
+	/*
+	 * Free the QTD and clean up the associated QH. Leave the QH in the
+	 * schedule if it has any remaining QTDs.
+	 */
+
+	if (!hcd->core_if->dma_desc_enable) {
+		uint8_t b = urb_qtd->in_process;
+		dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
+		if (b) {
+			dwc_otg_hcd_qh_deactivate(hcd, qh, 0);
+			qh->channel = NULL;
+		} else if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
+			dwc_otg_hcd_qh_remove(hcd, qh);
+		}
+	} else {
+		dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
+	}
+	return 0;
+}
+
+int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle,
+				 int retry)
+{
+	dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
+	int retval = 0;
+	dwc_irqflags_t flags;
+
+	if (retry < 0) {
+		retval = -DWC_E_INVALID;
+		goto done;
+	}
+
+	if (!qh) {
+		retval = -DWC_E_INVALID;
+		goto done;
+	}
+
+	DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
+
+	while (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list) && retry) {
+		DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
+		retry--;
+		dwc_msleep(5);
+		DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
+	}
+
+	dwc_otg_hcd_qh_remove(hcd, qh);
+
+	DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
+	/*
+	 * Split dwc_otg_hcd_qh_remove_and_free() into qh_remove
+	 * and qh_free to prevent stack dump on DWC_DMA_FREE() with
+	 * irq_disabled (spinlock_irqsave) in dwc_otg_hcd_desc_list_free()
+	 * and dwc_otg_hcd_frame_list_alloc().
+	 */
+	dwc_otg_hcd_qh_free(hcd, qh);
+
+done:
+	return retval;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
+int dwc_otg_hcd_endpoint_reset(dwc_otg_hcd_t * hcd, void *ep_handle)
+{
+	int retval = 0;
+	dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
+	if (!qh)
+		return -DWC_E_INVALID;
+
+	qh->data_toggle = DWC_OTG_HC_PID_DATA0;
+	return retval;
+}
+#endif
+
+/**
+ * HCD Callback structure for handling mode switching.
+ */
+static dwc_otg_cil_callbacks_t hcd_cil_callbacks = {
+	.start = dwc_otg_hcd_start_cb,
+	.stop = dwc_otg_hcd_stop_cb,
+	.disconnect = dwc_otg_hcd_disconnect_cb,
+	.session_start = dwc_otg_hcd_session_start_cb,
+	.resume_wakeup = dwc_otg_hcd_rem_wakeup_cb,
+#ifdef CONFIG_USB_DWC_OTG_LPM
+	.sleep = dwc_otg_hcd_sleep_cb,
+#endif
+	.p = 0,
+};
+
+/**
+ * Reset tasklet function
+ */
+static void reset_tasklet_func(void *data)
+{
+	dwc_otg_hcd_t *dwc_otg_hcd = (dwc_otg_hcd_t *) data;
+	dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
+	hprt0_data_t hprt0;
+
+	DWC_DEBUGPL(DBG_HCDV, "USB RESET tasklet called\n");
+
+	hprt0.d32 = dwc_otg_read_hprt0(core_if);
+	hprt0.b.prtrst = 1;
+	DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+	dwc_mdelay(60);
+
+	hprt0.b.prtrst = 0;
+	DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+	dwc_otg_hcd->flags.b.port_reset_change = 1;
+}
+
+static void qh_list_free(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
+{
+	dwc_list_link_t *item;
+	dwc_otg_qh_t *qh;
+	dwc_irqflags_t flags;
+
+	if (!qh_list->next) {
+		/* The list hasn't been initialized yet. */
+		return;
+	}
+	/*
+	 * Hold spinlock here. Not needed in that case if bellow 
+	 * function is being called from ISR 
+	 */
+	DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
+	/* Ensure there are no QTDs or URBs left. */
+	kill_urbs_in_qh_list(hcd, qh_list);
+	DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
+
+	DWC_LIST_FOREACH(item, qh_list) {
+		qh = DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
+		dwc_otg_hcd_qh_remove_and_free(hcd, qh);
+	}
+}
+
+/**
+ * Exit from Hibernation if Host did not detect SRP from connected SRP capable
+ * Device during SRP time by host power up.
+ */
+void dwc_otg_hcd_power_up(void *ptr)
+{
+	gpwrdn_data_t gpwrdn = {.d32 = 0 };
+	dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
+
+	DWC_PRINTF("%s called\n", __FUNCTION__);
+
+	if (!core_if->hibernation_suspend) {
+		DWC_PRINTF("Already exited from Hibernation\n");
+		return;
+	}
+
+	/* Switch on the voltage to the core */
+	gpwrdn.b.pwrdnswtch = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+	dwc_udelay(10);
+
+	/* Reset the core */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.pwrdnrstn = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+	dwc_udelay(10);
+
+	/* Disable power clamps */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.pwrdnclmp = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+
+	/* Remove reset the core signal */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.pwrdnrstn = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
+	dwc_udelay(10);
+
+	/* Disable PMU interrupt */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.pmuintsel = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+
+	core_if->hibernation_suspend = 0;
+
+	/* Disable PMU */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.pmuactv = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+	dwc_udelay(10);
+
+	/* Enable VBUS */
+	gpwrdn.d32 = 0;
+	gpwrdn.b.dis_vbus = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
+
+	core_if->op_state = A_HOST;
+	dwc_otg_core_init(core_if);
+	dwc_otg_enable_global_interrupts(core_if);
+	cil_hcd_start(core_if);
+}
+
+/**
+ * Frees secondary storage associated with the dwc_otg_hcd structure contained
+ * in the struct usb_hcd field.
+ */
+static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd)
+{
+	int i;
+
+	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD FREE\n");
+
+	del_timers(dwc_otg_hcd);
+
+	/* Free memory for QH/QTD lists */
+	qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_inactive);
+	qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_active);
+	qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_inactive);
+	qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_ready);
+	qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_assigned);
+	qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_queued);
+
+	/* Free memory for the host channels. */
+	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
+		dwc_hc_t *hc = dwc_otg_hcd->hc_ptr_array[i];
+
+#ifdef DEBUG
+		if (dwc_otg_hcd->core_if->hc_xfer_timer[i]) {
+			DWC_TIMER_FREE(dwc_otg_hcd->core_if->hc_xfer_timer[i]);
+		}
+#endif
+		if (hc != NULL) {
+			DWC_DEBUGPL(DBG_HCDV, "HCD Free channel #%i, hc=%p\n",
+				    i, hc);
+			DWC_FREE(hc);
+		}
+	}
+
+	if (dwc_otg_hcd->core_if->dma_enable) {
+		if (dwc_otg_hcd->status_buf_dma) {
+			DWC_DMA_FREE(DWC_OTG_HCD_STATUS_BUF_SIZE,
+				     dwc_otg_hcd->status_buf,
+				     dwc_otg_hcd->status_buf_dma);
+		}
+	} else if (dwc_otg_hcd->status_buf != NULL) {
+		DWC_FREE(dwc_otg_hcd->status_buf);
+	}
+	DWC_SPINLOCK_FREE(dwc_otg_hcd->lock);
+	/* Set core_if's lock pointer to NULL */
+	dwc_otg_hcd->core_if->lock = NULL;
+
+	DWC_TIMER_FREE(dwc_otg_hcd->conn_timer);
+	DWC_TASK_FREE(dwc_otg_hcd->reset_tasklet);
+
+#ifdef DWC_DEV_SRPCAP
+	if (dwc_otg_hcd->core_if->power_down == 2 &&
+	    dwc_otg_hcd->core_if->pwron_timer) {
+		DWC_TIMER_FREE(dwc_otg_hcd->core_if->pwron_timer);
+	}
+#endif
+	DWC_FREE(dwc_otg_hcd);
+}
+
+int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if)
+{
+	int retval = 0;
+	int num_channels;
+	int i;
+	dwc_hc_t *channel;
+
+	hcd->lock = DWC_SPINLOCK_ALLOC();
+	if (!hcd->lock) {
+		DWC_ERROR("Could not allocate lock for pcd");
+		DWC_FREE(hcd);
+		retval = -DWC_E_NO_MEMORY;
+		goto out;
+	}
+	hcd->core_if = core_if;
+
+	/* Register the HCD CIL Callbacks */
+	dwc_otg_cil_register_hcd_callbacks(hcd->core_if,
+					   &hcd_cil_callbacks, hcd);
+
+	/* Initialize the non-periodic schedule. */
+	DWC_LIST_INIT(&hcd->non_periodic_sched_inactive);
+	DWC_LIST_INIT(&hcd->non_periodic_sched_active);
+
+	/* Initialize the periodic schedule. */
+	DWC_LIST_INIT(&hcd->periodic_sched_inactive);
+	DWC_LIST_INIT(&hcd->periodic_sched_ready);
+	DWC_LIST_INIT(&hcd->periodic_sched_assigned);
+	DWC_LIST_INIT(&hcd->periodic_sched_queued);
+
+	/*
+	 * Create a host channel descriptor for each host channel implemented
+	 * in the controller. Initialize the channel descriptor array.
+	 */
+	DWC_CIRCLEQ_INIT(&hcd->free_hc_list);
+	num_channels = hcd->core_if->core_params->host_channels;
+	DWC_MEMSET(hcd->hc_ptr_array, 0, sizeof(hcd->hc_ptr_array));
+	for (i = 0; i < num_channels; i++) {
+		channel = DWC_ALLOC(sizeof(dwc_hc_t));
+		if (channel == NULL) {
+			retval = -DWC_E_NO_MEMORY;
+			DWC_ERROR("%s: host channel allocation failed\n",
+				  __func__);
+			dwc_otg_hcd_free(hcd);
+			goto out;
+		}
+		channel->hc_num = i;
+		hcd->hc_ptr_array[i] = channel;
+#ifdef DEBUG
+		hcd->core_if->hc_xfer_timer[i] =
+		    DWC_TIMER_ALLOC("hc timer", hc_xfer_timeout,
+				    &hcd->core_if->hc_xfer_info[i]);
+#endif
+		DWC_DEBUGPL(DBG_HCDV, "HCD Added channel #%d, hc=%p\n", i,
+			    channel);
+	}
+
+	/* Initialize the Connection timeout timer. */
+	hcd->conn_timer = DWC_TIMER_ALLOC("Connection timer",
+					  dwc_otg_hcd_connect_timeout, 0);
+
+	/* Initialize reset tasklet. */
+	hcd->reset_tasklet = DWC_TASK_ALLOC("reset_tasklet", reset_tasklet_func, hcd);
+#ifdef DWC_DEV_SRPCAP
+	if (hcd->core_if->power_down == 2) {
+		/* Initialize Power on timer for Host power up in case hibernation */
+		hcd->core_if->pwron_timer = DWC_TIMER_ALLOC("PWRON TIMER",
+									dwc_otg_hcd_power_up, core_if);
+	}
+#endif	
+
+	/*
+	 * Allocate space for storing data on status transactions. Normally no
+	 * data is sent, but this space acts as a bit bucket. This must be
+	 * done after usb_add_hcd since that function allocates the DMA buffer
+	 * pool.
+	 */
+	if (hcd->core_if->dma_enable) {
+		hcd->status_buf =
+		    DWC_DMA_ALLOC(DWC_OTG_HCD_STATUS_BUF_SIZE,
+				  &hcd->status_buf_dma);
+	} else {
+		hcd->status_buf = DWC_ALLOC(DWC_OTG_HCD_STATUS_BUF_SIZE);
+	}
+	if (!hcd->status_buf) {
+		retval = -DWC_E_NO_MEMORY;
+		DWC_ERROR("%s: status_buf allocation failed\n", __func__);
+		dwc_otg_hcd_free(hcd);
+		goto out;
+	}
+
+	hcd->otg_port = 1;
+	hcd->frame_list = NULL;
+	hcd->frame_list_dma = 0;
+	hcd->periodic_qh_count = 0;
+out:
+	return retval;
+}
+
+void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd)
+{
+	/* Turn off all host-specific interrupts. */
+	dwc_otg_disable_host_interrupts(hcd->core_if);
+
+	dwc_otg_hcd_free(hcd);
+}
+
+/**
+ * Initializes dynamic portions of the DWC_otg HCD state.
+ */
+static void dwc_otg_hcd_reinit(dwc_otg_hcd_t * hcd)
+{
+	int num_channels;
+	int i;
+	dwc_hc_t *channel;
+	dwc_hc_t *channel_tmp;
+
+	hcd->flags.d32 = 0;
+
+	hcd->non_periodic_qh_ptr = &hcd->non_periodic_sched_active;
+	hcd->non_periodic_channels = 0;
+	hcd->periodic_channels = 0;
+
+	/*
+	 * Put all channels in the free channel list and clean up channel
+	 * states.
+	 */
+	DWC_CIRCLEQ_FOREACH_SAFE(channel, channel_tmp,
+				 &hcd->free_hc_list, hc_list_entry) {
+		DWC_CIRCLEQ_REMOVE(&hcd->free_hc_list, channel, hc_list_entry);
+	}
+
+	num_channels = hcd->core_if->core_params->host_channels;
+	for (i = 0; i < num_channels; i++) {
+		channel = hcd->hc_ptr_array[i];
+		DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, channel,
+					hc_list_entry);
+		dwc_otg_hc_cleanup(hcd->core_if, channel);
+	}
+
+	/* Initialize the DWC core for host mode operation. */
+	dwc_otg_core_host_init(hcd->core_if);
+
+	/* Set core_if's lock pointer to the hcd->lock */
+	hcd->core_if->lock = hcd->lock;
+}
+
+/**
+ * Assigns transactions from a QTD to a free host channel and initializes the
+ * host channel to perform the transactions. The host channel is removed from
+ * the free list.
+ *
+ * @param hcd The HCD state structure.
+ * @param qh Transactions from the first QTD for this QH are selected and
+ * assigned to a free host channel.
+ */
+static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+{
+	dwc_hc_t *hc;
+	dwc_otg_qtd_t *qtd;
+	dwc_otg_hcd_urb_t *urb;
+	void* ptr = NULL;
+
+	DWC_DEBUGPL(DBG_HCDV, "%s(%p,%p)\n", __func__, hcd, qh);
+
+	hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
+
+	/* Remove the host channel from the free list. */
+	DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
+
+	qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
+
+	urb = qtd->urb;
+	qh->channel = hc;
+
+	qtd->in_process = 1;
+
+	/*
+	 * Use usb_pipedevice to determine device address. This address is
+	 * 0 before the SET_ADDRESS command and the correct address afterward.
+	 */
+	hc->dev_addr = dwc_otg_hcd_get_dev_addr(&urb->pipe_info);
+	hc->ep_num = dwc_otg_hcd_get_ep_num(&urb->pipe_info);
+	hc->speed = qh->dev_speed;
+	hc->max_packet = dwc_max_packet(qh->maxp);
+
+	hc->xfer_started = 0;
+	hc->halt_status = DWC_OTG_HC_XFER_NO_HALT_STATUS;
+	hc->error_state = (qtd->error_count > 0);
+	hc->halt_on_queue = 0;
+	hc->halt_pending = 0;
+	hc->requests = 0;
+
+	/*
+	 * The following values may be modified in the transfer type section
+	 * below. The xfer_len value may be reduced when the transfer is
+	 * started to accommodate the max widths of the XferSize and PktCnt
+	 * fields in the HCTSIZn register.
+	 */
+
+	hc->ep_is_in = (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) != 0);
+	if (hc->ep_is_in) {
+		hc->do_ping = 0;
+	} else {
+		hc->do_ping = qh->ping_state;
+	}
+
+	hc->data_pid_start = qh->data_toggle;
+	hc->multi_count = 1;
+
+	if (hcd->core_if->dma_enable) {
+		hc->xfer_buff = (uint8_t *) urb->dma + urb->actual_length;
+
+		/* For non-dword aligned case */
+		if (((unsigned long)hc->xfer_buff & 0x3)
+		    && !hcd->core_if->dma_desc_enable) {
+			ptr = (uint8_t *) urb->buf + urb->actual_length;
+		}
+	} else {
+		hc->xfer_buff = (uint8_t *) urb->buf + urb->actual_length;
+	}
+	hc->xfer_len = urb->length - urb->actual_length;
+	hc->xfer_count = 0;
+
+	/*
+	 * Set the split attributes
+	 */
+	hc->do_split = 0;
+	if (qh->do_split) {
+		uint32_t hub_addr, port_addr;
+		hc->do_split = 1;
+		hc->xact_pos = qtd->isoc_split_pos;
+		hc->complete_split = qtd->complete_split;
+		hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &port_addr);
+		hc->hub_addr = (uint8_t) hub_addr;
+		hc->port_addr = (uint8_t) port_addr;
+	}
+
+	switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) {
+	case UE_CONTROL:
+		hc->ep_type = DWC_OTG_EP_TYPE_CONTROL;
+		switch (qtd->control_phase) {
+		case DWC_OTG_CONTROL_SETUP:
+			DWC_DEBUGPL(DBG_HCDV, "  Control setup transaction\n");
+			hc->do_ping = 0;
+			hc->ep_is_in = 0;
+			hc->data_pid_start = DWC_OTG_HC_PID_SETUP;
+			if (hcd->core_if->dma_enable) {
+				hc->xfer_buff = (uint8_t *) urb->setup_dma;
+			} else {
+				hc->xfer_buff = (uint8_t *) urb->setup_packet;
+			}
+			hc->xfer_len = 8;
+			ptr = NULL;
+			break;
+		case DWC_OTG_CONTROL_DATA:
+			DWC_DEBUGPL(DBG_HCDV, "  Control data transaction\n");
+			hc->data_pid_start = qtd->data_toggle;
+			break;
+		case DWC_OTG_CONTROL_STATUS:
+			/*
+			 * Direction is opposite of data direction or IN if no
+			 * data.
+			 */
+			DWC_DEBUGPL(DBG_HCDV, "  Control status transaction\n");
+			if (urb->length == 0) {
+				hc->ep_is_in = 1;
+			} else {
+				hc->ep_is_in =
+				    dwc_otg_hcd_is_pipe_out(&urb->pipe_info);
+			}
+			if (hc->ep_is_in) {
+				hc->do_ping = 0;
+			}
+
+			hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
+
+			hc->xfer_len = 0;
+			if (hcd->core_if->dma_enable) {
+				hc->xfer_buff = (uint8_t *) hcd->status_buf_dma;
+			} else {
+				hc->xfer_buff = (uint8_t *) hcd->status_buf;
+			}
+			ptr = NULL;
+			break;
+		}
+		break;
+	case UE_BULK:
+		hc->ep_type = DWC_OTG_EP_TYPE_BULK;
+		break;
+	case UE_INTERRUPT:
+		hc->ep_type = DWC_OTG_EP_TYPE_INTR;
+		break;
+	case UE_ISOCHRONOUS:
+		{
+			struct dwc_otg_hcd_iso_packet_desc *frame_desc;
+
+			hc->ep_type = DWC_OTG_EP_TYPE_ISOC;
+
+			if (hcd->core_if->dma_desc_enable)
+				break;
+
+			frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
+
+			frame_desc->status = 0;
+
+			if (hcd->core_if->dma_enable) {
+				hc->xfer_buff = (uint8_t *) urb->dma;
+			} else {
+				hc->xfer_buff = (uint8_t *) urb->buf;
+			}
+			hc->xfer_buff +=
+			    frame_desc->offset + qtd->isoc_split_offset;
+			hc->xfer_len =
+			    frame_desc->length - qtd->isoc_split_offset;
+
+			/* For non-dword aligned buffers */
+			if (((unsigned long)hc->xfer_buff & 0x3)
+			    && hcd->core_if->dma_enable) {
+				ptr =
+				    (uint8_t *) urb->buf + frame_desc->offset +
+				    qtd->isoc_split_offset;
+			} else
+				ptr = NULL;
+
+			if (hc->xact_pos == DWC_HCSPLIT_XACTPOS_ALL) {
+				if (hc->xfer_len <= 188) {
+					hc->xact_pos = DWC_HCSPLIT_XACTPOS_ALL;
+				} else {
+					hc->xact_pos =
+					    DWC_HCSPLIT_XACTPOS_BEGIN;
+				}
+			}
+		}
+		break;
+	}
+	/* non DWORD-aligned buffer case */	
+	if (ptr) {
+		uint32_t buf_size;
+		if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
+			buf_size = hcd->core_if->core_params->max_transfer_size;
+		} else {				
+			buf_size = 4096;
+		}
+		if (!qh->dw_align_buf) {
+			qh->dw_align_buf = DWC_DMA_ALLOC_ATOMIC(buf_size,
+							 &qh->dw_align_buf_dma);
+			if (!qh->dw_align_buf) {
+				DWC_ERROR
+				    ("%s: Failed to allocate memory to handle "
+				     "non-dword aligned buffer case\n",
+				     __func__);
+				return;
+			}
+		}
+		if (!hc->ep_is_in) {
+			dwc_memcpy(qh->dw_align_buf, ptr, hc->xfer_len);
+		}
+		hc->align_buff = qh->dw_align_buf_dma;
+	} else {
+		hc->align_buff = 0;
+	}
+
+	if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
+	    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
+		/*
+		 * This value may be modified when the transfer is started to
+		 * reflect the actual transfer length.
+		 */
+		hc->multi_count = dwc_hb_mult(qh->maxp);
+	}
+
+	if (hcd->core_if->dma_desc_enable)
+		hc->desc_list_addr = qh->desc_list_dma;
+
+	dwc_otg_hc_init(hcd->core_if, hc);
+	hc->qh = qh;
+}
+
+/**
+ * This function selects transactions from the HCD transfer schedule and
+ * assigns them to available host channels. It is called from HCD interrupt
+ * handler functions.
+ *
+ * @param hcd The HCD state structure.
+ *
+ * @return The types of new transactions that were assigned to host channels.
+ */
+dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd)
+{
+	dwc_list_link_t *qh_ptr;
+	dwc_otg_qh_t *qh;
+	int num_channels;
+	dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE;
+
+#ifdef DEBUG_SOF
+	DWC_DEBUGPL(DBG_HCD, "  Select Transactions\n");
+#endif
+
+	/* Process entries in the periodic ready list. */
+	qh_ptr = DWC_LIST_FIRST(&hcd->periodic_sched_ready);
+
+	while (qh_ptr != &hcd->periodic_sched_ready &&
+	       !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
+
+		qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
+		assign_and_init_hc(hcd, qh);
+
+		/*
+		 * Move the QH from the periodic ready schedule to the
+		 * periodic assigned schedule.
+		 */
+		qh_ptr = DWC_LIST_NEXT(qh_ptr);
+		DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
+				   &qh->qh_list_entry);
+
+		ret_val = DWC_OTG_TRANSACTION_PERIODIC;
+	}
+
+	/*
+	 * Process entries in the inactive portion of the non-periodic
+	 * schedule. Some free host channels may not be used if they are
+	 * reserved for periodic transfers.
+	 */
+	qh_ptr = hcd->non_periodic_sched_inactive.next;
+	num_channels = hcd->core_if->core_params->host_channels;
+	while (qh_ptr != &hcd->non_periodic_sched_inactive &&
+	       (hcd->non_periodic_channels <
+		num_channels - hcd->periodic_channels) &&
+	       !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
+
+		qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
+
+		assign_and_init_hc(hcd, qh);
+
+		/*
+		 * Move the QH from the non-periodic inactive schedule to the
+		 * non-periodic active schedule.
+		 */
+		qh_ptr = DWC_LIST_NEXT(qh_ptr);
+		DWC_LIST_MOVE_HEAD(&hcd->non_periodic_sched_active,
+				   &qh->qh_list_entry);
+
+		if (ret_val == DWC_OTG_TRANSACTION_NONE) {
+			ret_val = DWC_OTG_TRANSACTION_NON_PERIODIC;
+		} else {
+			ret_val = DWC_OTG_TRANSACTION_ALL;
+		}
+
+		hcd->non_periodic_channels++;
+	}
+
+	return ret_val;
+}
+
+/**
+ * Attempts to queue a single transaction request for a host channel
+ * associated with either a periodic or non-periodic transfer. This function
+ * assumes that there is space available in the appropriate request queue. For
+ * an OUT transfer or SETUP transaction in Slave mode, it checks whether space
+ * is available in the appropriate Tx FIFO.
+ *
+ * @param hcd The HCD state structure.
+ * @param hc Host channel descriptor associated with either a periodic or
+ * non-periodic transfer.
+ * @param fifo_dwords_avail Number of DWORDs available in the periodic Tx
+ * FIFO for periodic transfers or the non-periodic Tx FIFO for non-periodic
+ * transfers.
+ *
+ * @return 1 if a request is queued and more requests may be needed to
+ * complete the transfer, 0 if no more requests are required for this
+ * transfer, -1 if there is insufficient space in the Tx FIFO.
+ */
+static int queue_transaction(dwc_otg_hcd_t * hcd,
+			     dwc_hc_t * hc, uint16_t fifo_dwords_avail)
+{
+	int retval;
+
+	if (hcd->core_if->dma_enable) {
+		if (hcd->core_if->dma_desc_enable) {
+			if (!hc->xfer_started
+			    || (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)) {
+				dwc_otg_hcd_start_xfer_ddma(hcd, hc->qh);
+				hc->qh->ping_state = 0;
+			}
+		} else if (!hc->xfer_started) {
+			dwc_otg_hc_start_transfer(hcd->core_if, hc);
+			hc->qh->ping_state = 0;
+		}
+		retval = 0;
+	} else if (hc->halt_pending) {
+		/* Don't queue a request if the channel has been halted. */
+		retval = 0;
+	} else if (hc->halt_on_queue) {
+		dwc_otg_hc_halt(hcd->core_if, hc, hc->halt_status);
+		retval = 0;
+	} else if (hc->do_ping) {
+		if (!hc->xfer_started) {
+			dwc_otg_hc_start_transfer(hcd->core_if, hc);
+		}
+		retval = 0;
+	} else if (!hc->ep_is_in || hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
+		if ((fifo_dwords_avail * 4) >= hc->max_packet) {
+			if (!hc->xfer_started) {
+				dwc_otg_hc_start_transfer(hcd->core_if, hc);
+				retval = 1;
+			} else {
+				retval =
+				    dwc_otg_hc_continue_transfer(hcd->core_if,
+								 hc);
+			}
+		} else {
+			retval = -1;
+		}
+	} else {
+		if (!hc->xfer_started) {
+			dwc_otg_hc_start_transfer(hcd->core_if, hc);
+			retval = 1;
+		} else {
+			retval = dwc_otg_hc_continue_transfer(hcd->core_if, hc);
+		}
+	}
+
+	return retval;
+}
+
+/**
+ * Processes periodic channels for the next frame and queues transactions for
+ * these channels to the DWC_otg controller. After queueing transactions, the
+ * Periodic Tx FIFO Empty interrupt is enabled if there are more transactions
+ * to queue as Periodic Tx FIFO or request queue space becomes available.
+ * Otherwise, the Periodic Tx FIFO Empty interrupt is disabled.
+ */
+static void process_periodic_channels(dwc_otg_hcd_t * hcd)
+{
+	hptxsts_data_t tx_status;
+	dwc_list_link_t *qh_ptr;
+	dwc_otg_qh_t *qh;
+	int status;
+	int no_queue_space = 0;
+	int no_fifo_space = 0;
+
+	dwc_otg_host_global_regs_t *host_regs;
+	host_regs = hcd->core_if->host_if->host_global_regs;
+
+	DWC_DEBUGPL(DBG_HCDV, "Queue periodic transactions\n");
+#ifdef DEBUG
+	tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
+	DWC_DEBUGPL(DBG_HCDV,
+		    "  P Tx Req Queue Space Avail (before queue): %d\n",
+		    tx_status.b.ptxqspcavail);
+	DWC_DEBUGPL(DBG_HCDV, "  P Tx FIFO Space Avail (before queue): %d\n",
+		    tx_status.b.ptxfspcavail);
+#endif
+
+	qh_ptr = hcd->periodic_sched_assigned.next;
+	while (qh_ptr != &hcd->periodic_sched_assigned) {
+		tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
+		if (tx_status.b.ptxqspcavail == 0) {
+			no_queue_space = 1;
+			break;
+		}
+
+		qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
+
+		/*
+		 * Set a flag if we're queuing high-bandwidth in slave mode.
+		 * The flag prevents any halts to get into the request queue in
+		 * the middle of multiple high-bandwidth packets getting queued.
+		 */
+		if (!hcd->core_if->dma_enable && qh->channel->multi_count > 1) {
+			hcd->core_if->queuing_high_bandwidth = 1;
+		}
+		status =
+		    queue_transaction(hcd, qh->channel,
+				      tx_status.b.ptxfspcavail);
+		if (status < 0) {
+			no_fifo_space = 1;
+			break;
+		}
+
+		/*
+		 * In Slave mode, stay on the current transfer until there is
+		 * nothing more to do or the high-bandwidth request count is
+		 * reached. In DMA mode, only need to queue one request. The
+		 * controller automatically handles multiple packets for
+		 * high-bandwidth transfers.
+		 */
+		if (hcd->core_if->dma_enable || status == 0 ||
+		    qh->channel->requests == qh->channel->multi_count) {
+			qh_ptr = qh_ptr->next;
+			/*
+			 * Move the QH from the periodic assigned schedule to
+			 * the periodic queued schedule.
+			 */
+			DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_queued,
+					   &qh->qh_list_entry);
+
+			/* done queuing high bandwidth */
+			hcd->core_if->queuing_high_bandwidth = 0;
+		}
+	}
+
+	if (!hcd->core_if->dma_enable) {
+		dwc_otg_core_global_regs_t *global_regs;
+		gintmsk_data_t intr_mask = {.d32 = 0 };
+
+		global_regs = hcd->core_if->core_global_regs;
+		intr_mask.b.ptxfempty = 1;
+#ifdef DEBUG
+		tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
+		DWC_DEBUGPL(DBG_HCDV,
+			    "  P Tx Req Queue Space Avail (after queue): %d\n",
+			    tx_status.b.ptxqspcavail);
+		DWC_DEBUGPL(DBG_HCDV,
+			    "  P Tx FIFO Space Avail (after queue): %d\n",
+			    tx_status.b.ptxfspcavail);
+#endif
+		if (!DWC_LIST_EMPTY(&hcd->periodic_sched_assigned) ||
+		    no_queue_space || no_fifo_space) {
+			/*
+			 * May need to queue more transactions as the request
+			 * queue or Tx FIFO empties. Enable the periodic Tx
+			 * FIFO empty interrupt. (Always use the half-empty
+			 * level to ensure that new requests are loaded as
+			 * soon as possible.)
+			 */
+			DWC_MODIFY_REG32(&global_regs->gintmsk, 0,
+					 intr_mask.d32);
+		} else {
+			/*
+			 * Disable the Tx FIFO empty interrupt since there are
+			 * no more transactions that need to be queued right
+			 * now. This function is called from interrupt
+			 * handlers to queue more transactions as transfer
+			 * states change.
+			 */
+			DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32,
+					 0);
+		}
+	}
+}
+
+/**
+ * Processes active non-periodic channels and queues transactions for these
+ * channels to the DWC_otg controller. After queueing transactions, the NP Tx
+ * FIFO Empty interrupt is enabled if there are more transactions to queue as
+ * NP Tx FIFO or request queue space becomes available. Otherwise, the NP Tx
+ * FIFO Empty interrupt is disabled.
+ */
+static void process_non_periodic_channels(dwc_otg_hcd_t * hcd)
+{
+	gnptxsts_data_t tx_status;
+	dwc_list_link_t *orig_qh_ptr;
+	dwc_otg_qh_t *qh;
+	int status;
+	int no_queue_space = 0;
+	int no_fifo_space = 0;
+	int more_to_do = 0;
+
+	dwc_otg_core_global_regs_t *global_regs =
+	    hcd->core_if->core_global_regs;
+
+	DWC_DEBUGPL(DBG_HCDV, "Queue non-periodic transactions\n");
+#ifdef DEBUG
+	tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
+	DWC_DEBUGPL(DBG_HCDV,
+		    "  NP Tx Req Queue Space Avail (before queue): %d\n",
+		    tx_status.b.nptxqspcavail);
+	DWC_DEBUGPL(DBG_HCDV, "  NP Tx FIFO Space Avail (before queue): %d\n",
+		    tx_status.b.nptxfspcavail);
+#endif
+	/*
+	 * Keep track of the starting point. Skip over the start-of-list
+	 * entry.
+	 */
+	if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
+		hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
+	}
+	orig_qh_ptr = hcd->non_periodic_qh_ptr;
+
+	/*
+	 * Process once through the active list or until no more space is
+	 * available in the request queue or the Tx FIFO.
+	 */
+	do {
+		tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
+		if (!hcd->core_if->dma_enable && tx_status.b.nptxqspcavail == 0) {
+			no_queue_space = 1;
+			break;
+		}
+
+		qh = DWC_LIST_ENTRY(hcd->non_periodic_qh_ptr, dwc_otg_qh_t,
+				    qh_list_entry);
+		status =
+		    queue_transaction(hcd, qh->channel,
+				      tx_status.b.nptxfspcavail);
+
+		if (status > 0) {
+			more_to_do = 1;
+		} else if (status < 0) {
+			no_fifo_space = 1;
+			break;
+		}
+
+		/* Advance to next QH, skipping start-of-list entry. */
+		hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
+		if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
+			hcd->non_periodic_qh_ptr =
+			    hcd->non_periodic_qh_ptr->next;
+		}
+
+	} while (hcd->non_periodic_qh_ptr != orig_qh_ptr);
+
+	if (!hcd->core_if->dma_enable) {
+		gintmsk_data_t intr_mask = {.d32 = 0 };
+		intr_mask.b.nptxfempty = 1;
+
+#ifdef DEBUG
+		tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
+		DWC_DEBUGPL(DBG_HCDV,
+			    "  NP Tx Req Queue Space Avail (after queue): %d\n",
+			    tx_status.b.nptxqspcavail);
+		DWC_DEBUGPL(DBG_HCDV,
+			    "  NP Tx FIFO Space Avail (after queue): %d\n",
+			    tx_status.b.nptxfspcavail);
+#endif
+		if (more_to_do || no_queue_space || no_fifo_space) {
+			/*
+			 * May need to queue more transactions as the request
+			 * queue or Tx FIFO empties. Enable the non-periodic
+			 * Tx FIFO empty interrupt. (Always use the half-empty
+			 * level to ensure that new requests are loaded as
+			 * soon as possible.)
+			 */
+			DWC_MODIFY_REG32(&global_regs->gintmsk, 0,
+					 intr_mask.d32);
+		} else {
+			/*
+			 * Disable the Tx FIFO empty interrupt since there are
+			 * no more transactions that need to be queued right
+			 * now. This function is called from interrupt
+			 * handlers to queue more transactions as transfer
+			 * states change.
+			 */
+			DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32,
+					 0);
+		}
+	}
+}
+
+/**
+ * This function processes the currently active host channels and queues
+ * transactions for these channels to the DWC_otg controller. It is called
+ * from HCD interrupt handler functions.
+ *
+ * @param hcd The HCD state structure.
+ * @param tr_type The type(s) of transactions to queue (non-periodic,
+ * periodic, or both).
+ */
+void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd,
+				    dwc_otg_transaction_type_e tr_type)
+{
+#ifdef DEBUG_SOF
+	DWC_DEBUGPL(DBG_HCD, "Queue Transactions\n");
+#endif
+	/* Process host channels associated with periodic transfers. */
+	if ((tr_type == DWC_OTG_TRANSACTION_PERIODIC ||
+	     tr_type == DWC_OTG_TRANSACTION_ALL) &&
+	    !DWC_LIST_EMPTY(&hcd->periodic_sched_assigned)) {
+
+		process_periodic_channels(hcd);
+	}
+
+	/* Process host channels associated with non-periodic transfers. */
+	if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC ||
+	    tr_type == DWC_OTG_TRANSACTION_ALL) {
+		if (!DWC_LIST_EMPTY(&hcd->non_periodic_sched_active)) {
+			process_non_periodic_channels(hcd);
+		} else {
+			/*
+			 * Ensure NP Tx FIFO empty interrupt is disabled when
+			 * there are no non-periodic transfers to process.
+			 */
+			gintmsk_data_t gintmsk = {.d32 = 0 };
+			gintmsk.b.nptxfempty = 1;
+			DWC_MODIFY_REG32(&hcd->core_if->
+					 core_global_regs->gintmsk, gintmsk.d32,
+					 0);
+		}
+	}
+}
+
+#ifdef DWC_HS_ELECT_TST
+/*
+ * Quick and dirty hack to implement the HS Electrical Test
+ * SINGLE_STEP_GET_DEVICE_DESCRIPTOR feature.
+ *
+ * This code was copied from our userspace app "hset". It sends a
+ * Get Device Descriptor control sequence in two parts, first the
+ * Setup packet by itself, followed some time later by the In and
+ * Ack packets. Rather than trying to figure out how to add this
+ * functionality to the normal driver code, we just hijack the
+ * hardware, using these two function to drive the hardware
+ * directly.
+ */
+
+static dwc_otg_core_global_regs_t *global_regs;
+static dwc_otg_host_global_regs_t *hc_global_regs;
+static dwc_otg_hc_regs_t *hc_regs;
+static uint32_t *data_fifo;
+
+static void do_setup(void)
+{
+	gintsts_data_t gintsts;
+	hctsiz_data_t hctsiz;
+	hcchar_data_t hcchar;
+	haint_data_t haint;
+	hcint_data_t hcint;
+
+	/* Enable HAINTs */
+	DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0001);
+
+	/* Enable HCINTs */
+	DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x04a3);
+
+	/* Read GINTSTS */
+	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
+
+	/* Read HAINT */
+	haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
+
+	/* Read HCINT */
+	hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
+
+	/* Read HCCHAR */
+	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+
+	/* Clear HCINT */
+	DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
+
+	/* Clear HAINT */
+	DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
+
+	/* Clear GINTSTS */
+	DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
+
+	/* Read GINTSTS */
+	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
+
+	/*
+	 * Send Setup packet (Get Device Descriptor)
+	 */
+
+	/* Make sure channel is disabled */
+	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+	if (hcchar.b.chen) {
+		hcchar.b.chdis = 1;
+//              hcchar.b.chen = 1;
+		DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
+		//sleep(1);
+		dwc_mdelay(1000);
+
+		/* Read GINTSTS */
+		gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
+
+		/* Read HAINT */
+		haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
+
+		/* Read HCINT */
+		hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
+
+		/* Read HCCHAR */
+		hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+
+		/* Clear HCINT */
+		DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
+
+		/* Clear HAINT */
+		DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
+
+		/* Clear GINTSTS */
+		DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
+
+		hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+	}
+
+	/* Set HCTSIZ */
+	hctsiz.d32 = 0;
+	hctsiz.b.xfersize = 8;
+	hctsiz.b.pktcnt = 1;
+	hctsiz.b.pid = DWC_OTG_HC_PID_SETUP;
+	DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
+
+	/* Set HCCHAR */
+	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+	hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
+	hcchar.b.epdir = 0;
+	hcchar.b.epnum = 0;
+	hcchar.b.mps = 8;
+	hcchar.b.chen = 1;
+	DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
+
+	/* Fill FIFO with Setup data for Get Device Descriptor */
+	data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
+	DWC_WRITE_REG32(data_fifo++, 0x01000680);
+	DWC_WRITE_REG32(data_fifo++, 0x00080000);
+
+	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
+
+	/* Wait for host channel interrupt */
+	do {
+		gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
+	} while (gintsts.b.hcintr == 0);
+
+	/* Disable HCINTs */
+	DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x0000);
+
+	/* Disable HAINTs */
+	DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0000);
+
+	/* Read HAINT */
+	haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
+
+	/* Read HCINT */
+	hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
+
+	/* Read HCCHAR */
+	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+
+	/* Clear HCINT */
+	DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
+
+	/* Clear HAINT */
+	DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
+
+	/* Clear GINTSTS */
+	DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
+
+	/* Read GINTSTS */
+	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
+}
+
+static void do_in_ack(void)
+{
+	gintsts_data_t gintsts;
+	hctsiz_data_t hctsiz;
+	hcchar_data_t hcchar;
+	haint_data_t haint;
+	hcint_data_t hcint;
+	host_grxsts_data_t grxsts;
+
+	/* Enable HAINTs */
+	DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0001);
+
+	/* Enable HCINTs */
+	DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x04a3);
+
+	/* Read GINTSTS */
+	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
+
+	/* Read HAINT */
+	haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
+
+	/* Read HCINT */
+	hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
+
+	/* Read HCCHAR */
+	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+
+	/* Clear HCINT */
+	DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
+
+	/* Clear HAINT */
+	DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
+
+	/* Clear GINTSTS */
+	DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
+
+	/* Read GINTSTS */
+	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
+
+	/*
+	 * Receive Control In packet
+	 */
+
+	/* Make sure channel is disabled */
+	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+	if (hcchar.b.chen) {
+		hcchar.b.chdis = 1;
+		hcchar.b.chen = 1;
+		DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
+		//sleep(1);
+		dwc_mdelay(1000);
+
+		/* Read GINTSTS */
+		gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
+
+		/* Read HAINT */
+		haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
+
+		/* Read HCINT */
+		hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
+
+		/* Read HCCHAR */
+		hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+
+		/* Clear HCINT */
+		DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
+
+		/* Clear HAINT */
+		DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
+
+		/* Clear GINTSTS */
+		DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
+
+		hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+	}
+
+	/* Set HCTSIZ */
+	hctsiz.d32 = 0;
+	hctsiz.b.xfersize = 8;
+	hctsiz.b.pktcnt = 1;
+	hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
+	DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
+
+	/* Set HCCHAR */
+	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+	hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
+	hcchar.b.epdir = 1;
+	hcchar.b.epnum = 0;
+	hcchar.b.mps = 8;
+	hcchar.b.chen = 1;
+	DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
+
+	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
+
+	/* Wait for receive status queue interrupt */
+	do {
+		gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
+	} while (gintsts.b.rxstsqlvl == 0);
+
+	/* Read RXSTS */
+	grxsts.d32 = DWC_READ_REG32(&global_regs->grxstsp);
+
+	/* Clear RXSTSQLVL in GINTSTS */
+	gintsts.d32 = 0;
+	gintsts.b.rxstsqlvl = 1;
+	DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
+
+	switch (grxsts.b.pktsts) {
+	case DWC_GRXSTS_PKTSTS_IN:
+		/* Read the data into the host buffer */
+		if (grxsts.b.bcnt > 0) {
+			int i;
+			int word_count = (grxsts.b.bcnt + 3) / 4;
+
+			data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
+
+			for (i = 0; i < word_count; i++) {
+				(void)DWC_READ_REG32(data_fifo++);
+			}
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
+
+	/* Wait for receive status queue interrupt */
+	do {
+		gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
+	} while (gintsts.b.rxstsqlvl == 0);
+
+	/* Read RXSTS */
+	grxsts.d32 = DWC_READ_REG32(&global_regs->grxstsp);
+
+	/* Clear RXSTSQLVL in GINTSTS */
+	gintsts.d32 = 0;
+	gintsts.b.rxstsqlvl = 1;
+	DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
+
+	switch (grxsts.b.pktsts) {
+	case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
+		break;
+
+	default:
+		break;
+	}
+
+	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
+
+	/* Wait for host channel interrupt */
+	do {
+		gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
+	} while (gintsts.b.hcintr == 0);
+
+	/* Read HAINT */
+	haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
+
+	/* Read HCINT */
+	hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
+
+	/* Read HCCHAR */
+	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+
+	/* Clear HCINT */
+	DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
+
+	/* Clear HAINT */
+	DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
+
+	/* Clear GINTSTS */
+	DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
+
+	/* Read GINTSTS */
+	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
+
+//      usleep(100000);
+//      mdelay(100);
+	dwc_mdelay(1);
+
+	/*
+	 * Send handshake packet
+	 */
+
+	/* Read HAINT */
+	haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
+
+	/* Read HCINT */
+	hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
+
+	/* Read HCCHAR */
+	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+
+	/* Clear HCINT */
+	DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
+
+	/* Clear HAINT */
+	DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
+
+	/* Clear GINTSTS */
+	DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
+
+	/* Read GINTSTS */
+	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
+
+	/* Make sure channel is disabled */
+	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+	if (hcchar.b.chen) {
+		hcchar.b.chdis = 1;
+		hcchar.b.chen = 1;
+		DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
+		//sleep(1);
+		dwc_mdelay(1000);
+
+		/* Read GINTSTS */
+		gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
+
+		/* Read HAINT */
+		haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
+
+		/* Read HCINT */
+		hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
+
+		/* Read HCCHAR */
+		hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+
+		/* Clear HCINT */
+		DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
+
+		/* Clear HAINT */
+		DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
+
+		/* Clear GINTSTS */
+		DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
+
+		hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+	}
+
+	/* Set HCTSIZ */
+	hctsiz.d32 = 0;
+	hctsiz.b.xfersize = 0;
+	hctsiz.b.pktcnt = 1;
+	hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
+	DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
+
+	/* Set HCCHAR */
+	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+	hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
+	hcchar.b.epdir = 0;
+	hcchar.b.epnum = 0;
+	hcchar.b.mps = 8;
+	hcchar.b.chen = 1;
+	DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
+
+	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
+
+	/* Wait for host channel interrupt */
+	do {
+		gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
+	} while (gintsts.b.hcintr == 0);
+
+	/* Disable HCINTs */
+	DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x0000);
+
+	/* Disable HAINTs */
+	DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0000);
+
+	/* Read HAINT */
+	haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
+
+	/* Read HCINT */
+	hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
+
+	/* Read HCCHAR */
+	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+
+	/* Clear HCINT */
+	DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
+
+	/* Clear HAINT */
+	DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
+
+	/* Clear GINTSTS */
+	DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
+
+	/* Read GINTSTS */
+	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
+}
+#endif
+
+/** Handles hub class-specific requests. */
+int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd,
+			    uint16_t typeReq,
+			    uint16_t wValue,
+			    uint16_t wIndex, uint8_t * buf, uint16_t wLength)
+{
+	int retval = 0;
+
+	dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
+	usb_hub_descriptor_t *hub_desc;
+	hprt0_data_t hprt0 = {.d32 = 0 };
+
+	uint32_t port_status;
+
+	switch (typeReq) {
+	case UCR_CLEAR_HUB_FEATURE:
+		DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+			    "ClearHubFeature 0x%x\n", wValue);
+		switch (wValue) {
+		case UHF_C_HUB_LOCAL_POWER:
+		case UHF_C_HUB_OVER_CURRENT:
+			/* Nothing required here */
+			break;
+		default:
+			retval = -DWC_E_INVALID;
+			DWC_ERROR("DWC OTG HCD - "
+				  "ClearHubFeature request %xh unknown\n",
+				  wValue);
+		}
+		break;
+	case UCR_CLEAR_PORT_FEATURE:
+#ifdef CONFIG_USB_DWC_OTG_LPM
+		if (wValue != UHF_PORT_L1)
+#endif
+			if (!wIndex || wIndex > 1)
+				goto error;
+
+		switch (wValue) {
+		case UHF_PORT_ENABLE:
+			DWC_DEBUGPL(DBG_ANY, "DWC OTG HCD HUB CONTROL - "
+				    "ClearPortFeature USB_PORT_FEAT_ENABLE\n");
+			hprt0.d32 = dwc_otg_read_hprt0(core_if);
+			hprt0.b.prtena = 1;
+			DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+			break;
+		case UHF_PORT_SUSPEND:
+			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+				    "ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
+
+			if (core_if->power_down == 2) {
+				dwc_otg_host_hibernation_restore(core_if, 0, 0);
+			} else {
+				DWC_WRITE_REG32(core_if->pcgcctl, 0);
+				dwc_mdelay(5);
+
+				hprt0.d32 = dwc_otg_read_hprt0(core_if);
+				hprt0.b.prtres = 1;
+				DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+				hprt0.b.prtsusp = 0;
+				/* Clear Resume bit */
+				dwc_mdelay(100);
+				hprt0.b.prtres = 0;
+				DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+			}
+			break;
+#ifdef CONFIG_USB_DWC_OTG_LPM
+		case UHF_PORT_L1:
+			{
+				pcgcctl_data_t pcgcctl = {.d32 = 0 };
+				glpmcfg_data_t lpmcfg = {.d32 = 0 };
+
+				lpmcfg.d32 =
+				    DWC_READ_REG32(&core_if->
+						   core_global_regs->glpmcfg);
+				lpmcfg.b.en_utmi_sleep = 0;
+				lpmcfg.b.hird_thres &= (~(1 << 4));
+				lpmcfg.b.prt_sleep_sts = 1;
+				DWC_WRITE_REG32(&core_if->
+						core_global_regs->glpmcfg,
+						lpmcfg.d32);
+
+				/* Clear Enbl_L1Gating bit. */
+				pcgcctl.b.enbl_sleep_gating = 1;
+				DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32,
+						 0);
+
+				dwc_mdelay(5);
+
+				hprt0.d32 = dwc_otg_read_hprt0(core_if);
+				hprt0.b.prtres = 1;
+				DWC_WRITE_REG32(core_if->host_if->hprt0,
+						hprt0.d32);
+				/* This bit will be cleared in wakeup interrupt handle */
+				break;
+			}
+#endif
+		case UHF_PORT_POWER:
+			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+				    "ClearPortFeature USB_PORT_FEAT_POWER\n");
+			hprt0.d32 = dwc_otg_read_hprt0(core_if);
+			hprt0.b.prtpwr = 0;
+			DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+			break;
+		case UHF_PORT_INDICATOR:
+			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+				    "ClearPortFeature USB_PORT_FEAT_INDICATOR\n");
+			/* Port inidicator not supported */
+			break;
+		case UHF_C_PORT_CONNECTION:
+			/* Clears drivers internal connect status change
+			 * flag */
+			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+				    "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n");
+			dwc_otg_hcd->flags.b.port_connect_status_change = 0;
+			break;
+		case UHF_C_PORT_RESET:
+			/* Clears the driver's internal Port Reset Change
+			 * flag */
+			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+				    "ClearPortFeature USB_PORT_FEAT_C_RESET\n");
+			dwc_otg_hcd->flags.b.port_reset_change = 0;
+			break;
+		case UHF_C_PORT_ENABLE:
+			/* Clears the driver's internal Port
+			 * Enable/Disable Change flag */
+			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+				    "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n");
+			dwc_otg_hcd->flags.b.port_enable_change = 0;
+			break;
+		case UHF_C_PORT_SUSPEND:
+			/* Clears the driver's internal Port Suspend
+			 * Change flag, which is set when resume signaling on
+			 * the host port is complete */
+			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+				    "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n");
+			dwc_otg_hcd->flags.b.port_suspend_change = 0;
+			break;
+#ifdef CONFIG_USB_DWC_OTG_LPM
+		case UHF_C_PORT_L1:
+			dwc_otg_hcd->flags.b.port_l1_change = 0;
+			break;
+#endif
+		case UHF_C_PORT_OVER_CURRENT:
+			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+				    "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n");
+			dwc_otg_hcd->flags.b.port_over_current_change = 0;
+			break;
+		default:
+			retval = -DWC_E_INVALID;
+			DWC_ERROR("DWC OTG HCD - "
+				  "ClearPortFeature request %xh "
+				  "unknown or unsupported\n", wValue);
+		}
+		break;
+	case UCR_GET_HUB_DESCRIPTOR:
+		DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+			    "GetHubDescriptor\n");
+		hub_desc = (usb_hub_descriptor_t *) buf;
+		hub_desc->bDescLength = 9;
+		hub_desc->bDescriptorType = 0x29;
+		hub_desc->bNbrPorts = 1;
+		USETW(hub_desc->wHubCharacteristics, 0x08);
+		hub_desc->bPwrOn2PwrGood = 1;
+		hub_desc->bHubContrCurrent = 0;
+		hub_desc->DeviceRemovable[0] = 0;
+		hub_desc->DeviceRemovable[1] = 0xff;
+		break;
+	case UCR_GET_HUB_STATUS:
+		DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+			    "GetHubStatus\n");
+		DWC_MEMSET(buf, 0, 4);
+		break;
+	case UCR_GET_PORT_STATUS:
+		DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+			    "GetPortStatus wIndex = 0x%04x FLAGS=0x%08x\n",
+			    wIndex, dwc_otg_hcd->flags.d32);
+		if (!wIndex || wIndex > 1)
+			goto error;
+
+		port_status = 0;
+
+		if (dwc_otg_hcd->flags.b.port_connect_status_change)
+			port_status |= (1 << UHF_C_PORT_CONNECTION);
+
+		if (dwc_otg_hcd->flags.b.port_enable_change)
+			port_status |= (1 << UHF_C_PORT_ENABLE);
+
+		if (dwc_otg_hcd->flags.b.port_suspend_change)
+			port_status |= (1 << UHF_C_PORT_SUSPEND);
+
+		if (dwc_otg_hcd->flags.b.port_l1_change)
+			port_status |= (1 << UHF_C_PORT_L1);
+
+		if (dwc_otg_hcd->flags.b.port_reset_change) {
+			port_status |= (1 << UHF_C_PORT_RESET);
+		}
+
+		if (dwc_otg_hcd->flags.b.port_over_current_change) {
+			DWC_WARN("Overcurrent change detected\n");
+			port_status |= (1 << UHF_C_PORT_OVER_CURRENT);
+		}
+
+		if (!dwc_otg_hcd->flags.b.port_connect_status) {
+			/*
+			 * The port is disconnected, which means the core is
+			 * either in device mode or it soon will be. Just
+			 * return 0's for the remainder of the port status
+			 * since the port register can't be read if the core
+			 * is in device mode.
+			 */
+			*((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
+			break;
+		}
+
+		hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
+		DWC_DEBUGPL(DBG_HCDV, "  HPRT0: 0x%08x\n", hprt0.d32);
+
+		if (hprt0.b.prtconnsts)
+			port_status |= (1 << UHF_PORT_CONNECTION);
+
+		if (hprt0.b.prtena)
+			port_status |= (1 << UHF_PORT_ENABLE);
+
+		if (hprt0.b.prtsusp)
+			port_status |= (1 << UHF_PORT_SUSPEND);
+
+		if (hprt0.b.prtovrcurract)
+			port_status |= (1 << UHF_PORT_OVER_CURRENT);
+
+		if (hprt0.b.prtrst)
+			port_status |= (1 << UHF_PORT_RESET);
+
+		if (hprt0.b.prtpwr)
+			port_status |= (1 << UHF_PORT_POWER);
+
+		if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED)
+			port_status |= (1 << UHF_PORT_HIGH_SPEED);
+		else if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED)
+			port_status |= (1 << UHF_PORT_LOW_SPEED);
+
+		if (hprt0.b.prttstctl)
+			port_status |= (1 << UHF_PORT_TEST);
+		if (dwc_otg_get_lpm_portsleepstatus(dwc_otg_hcd->core_if)) {
+			port_status |= (1 << UHF_PORT_L1);
+		}
+		/*
+		   For Synopsys HW emulation of Power down wkup_control asserts the 
+		   hreset_n and prst_n on suspned. This causes the HPRT0 to be zero. 
+		   We intentionally tell the software that port is in L2Suspend state. 
+		   Only for STE.
+		*/
+		if ((core_if->power_down == 2)
+		    && (core_if->hibernation_suspend == 1)) {
+			port_status |= (1 << UHF_PORT_SUSPEND);
+		}
+		/* USB_PORT_FEAT_INDICATOR unsupported always 0 */
+
+		*((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
+
+		break;
+	case UCR_SET_HUB_FEATURE:
+		DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+			    "SetHubFeature\n");
+		/* No HUB features supported */
+		break;
+	case UCR_SET_PORT_FEATURE:
+		if (wValue != UHF_PORT_TEST && (!wIndex || wIndex > 1))
+			goto error;
+
+		if (!dwc_otg_hcd->flags.b.port_connect_status) {
+			/*
+			 * The port is disconnected, which means the core is
+			 * either in device mode or it soon will be. Just
+			 * return without doing anything since the port
+			 * register can't be written if the core is in device
+			 * mode.
+			 */
+			break;
+		}
+
+		switch (wValue) {
+		case UHF_PORT_SUSPEND:
+			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+				    "SetPortFeature - USB_PORT_FEAT_SUSPEND\n");
+			if (dwc_otg_hcd_otg_port(dwc_otg_hcd) != wIndex) {
+				goto error;
+			}
+			if (core_if->power_down == 2) {
+				int timeout = 300;
+				dwc_irqflags_t flags;
+				pcgcctl_data_t pcgcctl = {.d32 = 0 };
+				gpwrdn_data_t gpwrdn = {.d32 = 0 };
+				gusbcfg_data_t gusbcfg = {.d32 = 0 };
+#ifdef DWC_DEV_SRPCAP
+				int32_t otg_cap_param = core_if->core_params->otg_cap;
+#endif
+				DWC_PRINTF("Preparing for complete power-off\n");
+
+				/* Save registers before hibernation */
+				dwc_otg_save_global_regs(core_if);
+				dwc_otg_save_host_regs(core_if);
+
+				hprt0.d32 = dwc_otg_read_hprt0(core_if);
+				hprt0.b.prtsusp = 1;
+				hprt0.b.prtena = 0;
+				DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+				/* Spin hprt0.b.prtsusp to became 1 */
+				do {
+					hprt0.d32 = dwc_otg_read_hprt0(core_if);
+					if (hprt0.b.prtsusp) {
+						break;
+					}
+					dwc_mdelay(1);
+				} while (--timeout);
+				if (!timeout) {
+					DWC_WARN("Suspend wasn't genereted\n");
+				}
+				dwc_udelay(10);
+
+				/*
+				 * We need to disable interrupts to prevent servicing of any IRQ
+				 * during going to hibernation
+				 */
+				DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
+				core_if->lx_state = DWC_OTG_L2;
+#ifdef DWC_DEV_SRPCAP
+				hprt0.d32 = dwc_otg_read_hprt0(core_if);
+				hprt0.b.prtpwr = 0;
+				hprt0.b.prtena = 0;
+				DWC_WRITE_REG32(core_if->host_if->hprt0,
+						hprt0.d32);
+#endif
+				gusbcfg.d32 =
+				    DWC_READ_REG32(&core_if->core_global_regs->
+						   gusbcfg);
+				if (gusbcfg.b.ulpi_utmi_sel == 1) {
+					/* ULPI interface */
+					/* Suspend the Phy Clock */
+					pcgcctl.d32 = 0;
+					pcgcctl.b.stoppclk = 1;
+					DWC_MODIFY_REG32(core_if->pcgcctl, 0,
+							 pcgcctl.d32);
+					dwc_udelay(10);
+					gpwrdn.b.pmuactv = 1;
+					DWC_MODIFY_REG32(&core_if->
+							 core_global_regs->
+							 gpwrdn, 0, gpwrdn.d32);
+				} else {
+					/* UTMI+ Interface */
+					gpwrdn.b.pmuactv = 1;
+					DWC_MODIFY_REG32(&core_if->
+							 core_global_regs->
+							 gpwrdn, 0, gpwrdn.d32);
+					dwc_udelay(10);
+					pcgcctl.b.stoppclk = 1;
+					DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
+					dwc_udelay(10);
+				}
+#ifdef DWC_DEV_SRPCAP				
+				gpwrdn.d32 = 0;
+				gpwrdn.b.dis_vbus = 1;
+				DWC_MODIFY_REG32(&core_if->core_global_regs->
+						 gpwrdn, 0, gpwrdn.d32);
+#endif
+				gpwrdn.d32 = 0;
+				gpwrdn.b.pmuintsel = 1;
+				DWC_MODIFY_REG32(&core_if->core_global_regs->
+						 gpwrdn, 0, gpwrdn.d32);
+				dwc_udelay(10);
+
+				gpwrdn.d32 = 0;
+#ifdef DWC_DEV_SRPCAP
+				gpwrdn.b.srp_det_msk = 1;
+#endif
+				gpwrdn.b.disconn_det_msk = 1;
+				gpwrdn.b.lnstchng_msk = 1;
+				gpwrdn.b.sts_chngint_msk = 1;
+				DWC_MODIFY_REG32(&core_if->core_global_regs->
+						 gpwrdn, 0, gpwrdn.d32);
+				dwc_udelay(10);
+
+				/* Enable Power Down Clamp and all interrupts in GPWRDN */
+				gpwrdn.d32 = 0;
+				gpwrdn.b.pwrdnclmp = 1;
+				DWC_MODIFY_REG32(&core_if->core_global_regs->
+						 gpwrdn, 0, gpwrdn.d32);
+				dwc_udelay(10);
+
+				/* Switch off VDD */
+				gpwrdn.d32 = 0;
+				gpwrdn.b.pwrdnswtch = 1;
+				DWC_MODIFY_REG32(&core_if->core_global_regs->
+						 gpwrdn, 0, gpwrdn.d32);
+
+#ifdef DWC_DEV_SRPCAP
+				if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE)
+				{
+					core_if->pwron_timer_started = 1;
+					DWC_TIMER_SCHEDULE(core_if->pwron_timer, 6000 /* 6 secs */ );
+				}
+#endif
+				/* Save gpwrdn register for further usage if stschng interrupt */
+				core_if->gr_backup->gpwrdn_local =
+						DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
+
+				/* Set flag to indicate that we are in hibernation */
+				core_if->hibernation_suspend = 1;
+				DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock,flags);
+
+				DWC_PRINTF("Host hibernation completed\n");
+				// Exit from case statement
+				break;
+
+			}
+			if (dwc_otg_hcd_otg_port(dwc_otg_hcd) == wIndex &&
+			    dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
+				gotgctl_data_t gotgctl = {.d32 = 0 };
+				gotgctl.b.hstsethnpen = 1;
+				DWC_MODIFY_REG32(&core_if->core_global_regs->
+						 gotgctl, 0, gotgctl.d32);
+				core_if->op_state = A_SUSPEND;
+			}
+			hprt0.d32 = dwc_otg_read_hprt0(core_if);
+			hprt0.b.prtsusp = 1;
+			DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+			{
+				dwc_irqflags_t flags;
+				/* Update lx_state */
+				DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
+				core_if->lx_state = DWC_OTG_L2;
+				DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
+			}
+			/* Suspend the Phy Clock */
+			{
+				pcgcctl_data_t pcgcctl = {.d32 = 0 };
+				pcgcctl.b.stoppclk = 1;
+				DWC_MODIFY_REG32(core_if->pcgcctl, 0,
+						 pcgcctl.d32);
+				dwc_udelay(10);
+			}
+
+			/* For HNP the bus must be suspended for at least 200ms. */
+			if (dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
+				pcgcctl_data_t pcgcctl = {.d32 = 0 };
+				pcgcctl.b.stoppclk = 1;
+                DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
+				dwc_mdelay(200);
+			}
+
+			/** @todo - check how sw can wait for 1 sec to check asesvld??? */
+#if 0 //vahrama !!!!!!!!!!!!!!!!!!
+			if (core_if->adp_enable) {
+				gotgctl_data_t gotgctl = {.d32 = 0 };
+				gpwrdn_data_t gpwrdn;
+
+				while (gotgctl.b.asesvld == 1) {
+					gotgctl.d32 =
+					    DWC_READ_REG32(&core_if->
+							   core_global_regs->
+							   gotgctl);
+					dwc_mdelay(100);
+				}
+
+				/* Enable Power Down Logic */
+				gpwrdn.d32 = 0;
+				gpwrdn.b.pmuactv = 1;
+				DWC_MODIFY_REG32(&core_if->core_global_regs->
+						 gpwrdn, 0, gpwrdn.d32);
+
+				/* Unmask SRP detected interrupt from Power Down Logic */
+				gpwrdn.d32 = 0;
+				gpwrdn.b.srp_det_msk = 1;
+				DWC_MODIFY_REG32(&core_if->core_global_regs->
+						 gpwrdn, 0, gpwrdn.d32);
+
+				dwc_otg_adp_probe_start(core_if);
+			}
+#endif
+			break;
+		case UHF_PORT_POWER:
+			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+				    "SetPortFeature - USB_PORT_FEAT_POWER\n");
+			hprt0.d32 = dwc_otg_read_hprt0(core_if);
+			hprt0.b.prtpwr = 1;
+			DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+			break;
+		case UHF_PORT_RESET:
+			if ((core_if->power_down == 2)
+			    && (core_if->hibernation_suspend == 1)) {
+				/* If we are going to exit from Hibernated
+				 * state via USB RESET.
+				 */
+				dwc_otg_host_hibernation_restore(core_if, 0, 1);
+			} else {
+				hprt0.d32 = dwc_otg_read_hprt0(core_if);
+
+				DWC_DEBUGPL(DBG_HCD,
+					    "DWC OTG HCD HUB CONTROL - "
+					    "SetPortFeature - USB_PORT_FEAT_RESET\n");
+				{
+					pcgcctl_data_t pcgcctl = {.d32 = 0 };
+					pcgcctl.b.enbl_sleep_gating = 1;
+					pcgcctl.b.stoppclk = 1;
+					DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
+					DWC_WRITE_REG32(core_if->pcgcctl, 0);
+				}
+#ifdef CONFIG_USB_DWC_OTG_LPM
+				{
+					glpmcfg_data_t lpmcfg;
+					lpmcfg.d32 =
+						DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
+					if (lpmcfg.b.prt_sleep_sts) {
+						lpmcfg.b.en_utmi_sleep = 0;
+						lpmcfg.b.hird_thres &= (~(1 << 4));
+						DWC_WRITE_REG32
+						    (&core_if->core_global_regs->glpmcfg,
+						     lpmcfg.d32);
+						dwc_mdelay(1);
+					}
+				}
+#endif
+				hprt0.d32 = dwc_otg_read_hprt0(core_if);
+				/* Clear suspend bit if resetting from suspended state. */
+				hprt0.b.prtsusp = 0;
+				/* When B-Host the Port reset bit is set in
+				 * the Start HCD Callback function, so that
+				 * the reset is started within 1ms of the HNP
+				 * success interrupt. */
+				if (!dwc_otg_hcd_is_b_host(dwc_otg_hcd)) {
+					hprt0.b.prtpwr = 1;
+					hprt0.b.prtrst = 1;
+					DWC_PRINTF("Indeed it is in host mode hprt0 = %08x\n",hprt0.d32);
+					DWC_WRITE_REG32(core_if->host_if->hprt0,
+							hprt0.d32);
+				}
+				/* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
+				dwc_mdelay(60);
+				hprt0.b.prtrst = 0;
+				DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+				core_if->lx_state = DWC_OTG_L0;	/* Now back to the on state */
+			}
+			break;
+#ifdef DWC_HS_ELECT_TST
+		case UHF_PORT_TEST:
+			{
+				uint32_t t;
+				gintmsk_data_t gintmsk;
+
+				t = (wIndex >> 8);	/* MSB wIndex USB */
+				DWC_DEBUGPL(DBG_HCD,
+					    "DWC OTG HCD HUB CONTROL - "
+					    "SetPortFeature - USB_PORT_FEAT_TEST %d\n",
+					    t);
+				DWC_WARN("USB_PORT_FEAT_TEST %d\n", t);
+				if (t < 6) {
+					hprt0.d32 = dwc_otg_read_hprt0(core_if);
+					hprt0.b.prttstctl = t;
+					DWC_WRITE_REG32(core_if->host_if->hprt0,
+							hprt0.d32);
+				} else {
+					/* Setup global vars with reg addresses (quick and
+					 * dirty hack, should be cleaned up)
+					 */
+					global_regs = core_if->core_global_regs;
+					hc_global_regs =
+					    core_if->host_if->host_global_regs;
+					hc_regs =
+					    (dwc_otg_hc_regs_t *) ((char *)
+								   global_regs +
+								   0x500);
+					data_fifo =
+					    (uint32_t *) ((char *)global_regs +
+							  0x1000);
+
+					if (t == 6) {	/* HS_HOST_PORT_SUSPEND_RESUME */
+						/* Save current interrupt mask */
+						gintmsk.d32 =
+						    DWC_READ_REG32
+						    (&global_regs->gintmsk);
+
+						/* Disable all interrupts while we muck with
+						 * the hardware directly
+						 */
+						DWC_WRITE_REG32(&global_regs->gintmsk, 0);
+
+						/* 15 second delay per the test spec */
+						dwc_mdelay(15000);
+
+						/* Drive suspend on the root port */
+						hprt0.d32 =
+						    dwc_otg_read_hprt0(core_if);
+						hprt0.b.prtsusp = 1;
+						hprt0.b.prtres = 0;
+						DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+
+						/* 15 second delay per the test spec */
+						dwc_mdelay(15000);
+
+						/* Drive resume on the root port */
+						hprt0.d32 =
+						    dwc_otg_read_hprt0(core_if);
+						hprt0.b.prtsusp = 0;
+						hprt0.b.prtres = 1;
+						DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+						dwc_mdelay(100);
+
+						/* Clear the resume bit */
+						hprt0.b.prtres = 0;
+						DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
+
+						/* Restore interrupts */
+						DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
+					} else if (t == 7) {	/* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
+						/* Save current interrupt mask */
+						gintmsk.d32 =
+						    DWC_READ_REG32
+						    (&global_regs->gintmsk);
+
+						/* Disable all interrupts while we muck with
+						 * the hardware directly
+						 */
+						DWC_WRITE_REG32(&global_regs->gintmsk, 0);
+
+						/* 15 second delay per the test spec */
+						dwc_mdelay(15000);
+
+						/* Send the Setup packet */
+						do_setup();
+
+						/* 15 second delay so nothing else happens for awhile */
+						dwc_mdelay(15000);
+
+						/* Restore interrupts */
+						DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
+					} else if (t == 8) {	/* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
+						/* Save current interrupt mask */
+						gintmsk.d32 =
+						    DWC_READ_REG32
+						    (&global_regs->gintmsk);
+
+						/* Disable all interrupts while we muck with
+						 * the hardware directly
+						 */
+						DWC_WRITE_REG32(&global_regs->gintmsk, 0);
+
+						/* Send the Setup packet */
+						do_setup();
+
+						/* 15 second delay so nothing else happens for awhile */
+						dwc_mdelay(15000);
+
+						/* Send the In and Ack packets */
+						do_in_ack();
+
+						/* 15 second delay so nothing else happens for awhile */
+						dwc_mdelay(15000);
+
+						/* Restore interrupts */
+						DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
+					}
+				}
+				break;
+			}
+#endif /* DWC_HS_ELECT_TST */
+
+		case UHF_PORT_INDICATOR:
+			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+				    "SetPortFeature - USB_PORT_FEAT_INDICATOR\n");
+			/* Not supported */
+			break;
+		default:
+			retval = -DWC_E_INVALID;
+			DWC_ERROR("DWC OTG HCD - "
+				  "SetPortFeature request %xh "
+				  "unknown or unsupported\n", wValue);
+			break;
+		}
+		break;
+#ifdef CONFIG_USB_DWC_OTG_LPM
+	case UCR_SET_AND_TEST_PORT_FEATURE:
+		if (wValue != UHF_PORT_L1) {
+			goto error;
+		}
+		{
+			int portnum, hird, devaddr, remwake;
+			glpmcfg_data_t lpmcfg;
+			uint32_t time_usecs;
+			gintsts_data_t gintsts;
+			gintmsk_data_t gintmsk;
+
+			if (!dwc_otg_get_param_lpm_enable(core_if)) {
+				goto error;
+			}
+			if (wValue != UHF_PORT_L1 || wLength != 1) {
+				goto error;
+			}
+			/* Check if the port currently is in SLEEP state */
+			lpmcfg.d32 =
+			    DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
+			if (lpmcfg.b.prt_sleep_sts) {
+				DWC_INFO("Port is already in sleep mode\n");
+				buf[0] = 0;	/* Return success */
+				break;
+			}
+
+			portnum = wIndex & 0xf;
+			hird = (wIndex >> 4) & 0xf;
+			devaddr = (wIndex >> 8) & 0x7f;
+			remwake = (wIndex >> 15);
+
+			if (portnum != 1) {
+				retval = -DWC_E_INVALID;
+				DWC_WARN
+				    ("Wrong port number(%d) in SetandTestPortFeature request\n",
+				     portnum);
+				break;
+			}
+
+			DWC_PRINTF
+			    ("SetandTestPortFeature request: portnum = %d, hird = %d, devaddr = %d, rewake = %d\n",
+			     portnum, hird, devaddr, remwake);
+			/* Disable LPM interrupt */
+			gintmsk.d32 = 0;
+			gintmsk.b.lpmtranrcvd = 1;
+			DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
+					 gintmsk.d32, 0);
+
+			if (dwc_otg_hcd_send_lpm
+			    (dwc_otg_hcd, devaddr, hird, remwake)) {
+				retval = -DWC_E_INVALID;
+				break;
+			}
+
+			time_usecs = 10 * (lpmcfg.b.retry_count + 1);
+			/* We will consider timeout if time_usecs microseconds pass,
+			 * and we don't receive LPM transaction status.
+			 * After receiving non-error responce(ACK/NYET/STALL) from device,
+			 *  core will set lpmtranrcvd bit.
+			 */
+			do {
+				gintsts.d32 =
+				    DWC_READ_REG32(&core_if->core_global_regs->gintsts);
+				if (gintsts.b.lpmtranrcvd) {
+					break;
+				}
+				dwc_udelay(1);
+			} while (--time_usecs);
+			/* lpm_int bit will be cleared in LPM interrupt handler */
+
+			/* Now fill status
+			 * 0x00 - Success
+			 * 0x10 - NYET
+			 * 0x11 - Timeout
+			 */
+			if (!gintsts.b.lpmtranrcvd) {
+				buf[0] = 0x3;	/* Completion code is Timeout */
+				dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd);
+			} else {
+				lpmcfg.d32 =
+				    DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
+				if (lpmcfg.b.lpm_resp == 0x3) {
+					/* ACK responce from the device */
+					buf[0] = 0x00;	/* Success */
+				} else if (lpmcfg.b.lpm_resp == 0x2) {
+					/* NYET responce from the device */
+					buf[0] = 0x2;
+				} else {
+					/* Otherwise responce with Timeout */
+					buf[0] = 0x3;
+				}
+			}
+			DWC_PRINTF("Device responce to LPM trans is %x\n",
+				   lpmcfg.b.lpm_resp);
+			DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0,
+					 gintmsk.d32);
+
+			break;
+		}
+#endif /* CONFIG_USB_DWC_OTG_LPM */
+	default:
+error:
+		retval = -DWC_E_INVALID;
+		DWC_WARN("DWC OTG HCD - "
+			 "Unknown hub control request type or invalid typeReq: %xh wIndex: %xh wValue: %xh\n",
+			 typeReq, wIndex, wValue);
+		break;
+	}
+
+	return retval;
+}
+
+#ifdef CONFIG_USB_DWC_OTG_LPM
+/** Returns index of host channel to perform LPM transaction. */
+int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd, uint8_t devaddr)
+{
+	dwc_otg_core_if_t *core_if = hcd->core_if;
+	dwc_hc_t *hc;
+	hcchar_data_t hcchar;
+	gintmsk_data_t gintmsk = {.d32 = 0 };
+
+	if (DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
+		DWC_PRINTF("No free channel to select for LPM transaction\n");
+		return -1;
+	}
+
+	hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
+
+	/* Mask host channel interrupts. */
+	gintmsk.b.hcintr = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
+
+	/* Fill fields that core needs for LPM transaction */
+	hcchar.b.devaddr = devaddr;
+	hcchar.b.epnum = 0;
+	hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
+	hcchar.b.mps = 64;
+	hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
+	hcchar.b.epdir = 0;	/* OUT */
+	DWC_WRITE_REG32(&core_if->host_if->hc_regs[hc->hc_num]->hcchar,
+			hcchar.d32);
+
+	/* Remove the host channel from the free list. */
+	DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
+
+	DWC_PRINTF("hcnum = %d devaddr = %d\n", hc->hc_num, devaddr);
+
+	return hc->hc_num;
+}
+
+/** Release hc after performing LPM transaction */
+void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd)
+{
+	dwc_hc_t *hc;
+	glpmcfg_data_t lpmcfg;
+	uint8_t hc_num;
+
+	lpmcfg.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->glpmcfg);
+	hc_num = lpmcfg.b.lpm_chan_index;
+
+	hc = hcd->hc_ptr_array[hc_num];
+
+	DWC_PRINTF("Freeing channel %d after LPM\n", hc_num);
+	/* Return host channel to free list */
+	DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
+}
+
+int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr, uint8_t hird,
+			 uint8_t bRemoteWake)
+{
+	glpmcfg_data_t lpmcfg;
+	pcgcctl_data_t pcgcctl = {.d32 = 0 };
+	int channel;
+
+	channel = dwc_otg_hcd_get_hc_for_lpm_tran(hcd, devaddr);
+	if (channel < 0) {
+		return channel;
+	}
+
+	pcgcctl.b.enbl_sleep_gating = 1;
+	DWC_MODIFY_REG32(hcd->core_if->pcgcctl, 0, pcgcctl.d32);
+
+	/* Read LPM config register */
+	lpmcfg.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->glpmcfg);
+
+	/* Program LPM transaction fields */
+	lpmcfg.b.rem_wkup_en = bRemoteWake;
+	lpmcfg.b.hird = hird;
+	lpmcfg.b.hird_thres = 0x1c;
+	lpmcfg.b.lpm_chan_index = channel;
+	lpmcfg.b.en_utmi_sleep = 1;
+	/* Program LPM config register */
+	DWC_WRITE_REG32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
+
+	/* Send LPM transaction */
+	lpmcfg.b.send_lpm = 1;
+	DWC_WRITE_REG32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
+
+	return 0;
+}
+
+#endif /* CONFIG_USB_DWC_OTG_LPM */
+
+int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port)
+{
+	int retval;
+
+	if (port != 1) {
+		return -DWC_E_INVALID;
+	}
+
+	retval = (hcd->flags.b.port_connect_status_change ||
+		  hcd->flags.b.port_reset_change ||
+		  hcd->flags.b.port_enable_change ||
+		  hcd->flags.b.port_suspend_change ||
+		  hcd->flags.b.port_over_current_change);
+#ifdef DEBUG
+	if (retval) {
+		DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB STATUS DATA:"
+			    " Root port status changed\n");
+		DWC_DEBUGPL(DBG_HCDV, "  port_connect_status_change: %d\n",
+			    hcd->flags.b.port_connect_status_change);
+		DWC_DEBUGPL(DBG_HCDV, "  port_reset_change: %d\n",
+			    hcd->flags.b.port_reset_change);
+		DWC_DEBUGPL(DBG_HCDV, "  port_enable_change: %d\n",
+			    hcd->flags.b.port_enable_change);
+		DWC_DEBUGPL(DBG_HCDV, "  port_suspend_change: %d\n",
+			    hcd->flags.b.port_suspend_change);
+		DWC_DEBUGPL(DBG_HCDV, "  port_over_current_change: %d\n",
+			    hcd->flags.b.port_over_current_change);
+	}
+#endif
+	return retval;
+}
+
+int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * dwc_otg_hcd)
+{
+	hfnum_data_t hfnum;
+	hfnum.d32 =
+	    DWC_READ_REG32(&dwc_otg_hcd->core_if->host_if->host_global_regs->
+			   hfnum);
+
+#ifdef DEBUG_SOF
+	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD GET FRAME NUMBER %d\n",
+		    hfnum.b.frnum);
+#endif
+	return hfnum.b.frnum;
+}
+
+int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd,
+		      struct dwc_otg_hcd_function_ops *fops)
+{
+	int retval = 0;
+
+	hcd->fops = fops;
+	if (!dwc_otg_is_device_mode(hcd->core_if) && 
+		(!hcd->core_if->adp_enable || hcd->core_if->adp.adp_started)) {
+		dwc_otg_hcd_reinit(hcd);
+	} else {
+		retval = -DWC_E_NO_DEVICE;
+	}
+
+	return retval;
+}
+
+void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd)
+{
+	return hcd->priv;
+}
+
+void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data)
+{
+	hcd->priv = priv_data;
+}
+
+uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd)
+{
+	return hcd->otg_port;
+}
+
+uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd)
+{
+	uint32_t is_b_host;
+	if (hcd->core_if->op_state == B_HOST) {
+		is_b_host = 1;
+	} else {
+		is_b_host = 0;
+	}
+
+	return is_b_host;
+}
+
+dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd,
+					 int iso_desc_count, int atomic_alloc)
+{
+	dwc_otg_hcd_urb_t *dwc_otg_urb;
+	uint32_t size;
+
+	size =
+	    sizeof(*dwc_otg_urb) +
+	    iso_desc_count * sizeof(struct dwc_otg_hcd_iso_packet_desc);
+	if (atomic_alloc)
+		dwc_otg_urb = DWC_ALLOC_ATOMIC(size);
+	else
+		dwc_otg_urb = DWC_ALLOC(size);
+
+	dwc_otg_urb->packet_count = iso_desc_count;
+
+	return dwc_otg_urb;
+}
+
+void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * dwc_otg_urb,
+				  uint8_t dev_addr, uint8_t ep_num,
+				  uint8_t ep_type, uint8_t ep_dir, uint16_t mps)
+{
+	dwc_otg_hcd_fill_pipe(&dwc_otg_urb->pipe_info, dev_addr, ep_num,
+			      ep_type, ep_dir, mps);
+#if 0
+	DWC_PRINTF
+	    ("addr = %d, ep_num = %d, ep_dir = 0x%x, ep_type = 0x%x, mps = %d\n",
+	     dev_addr, ep_num, ep_dir, ep_type, mps);
+#endif
+}
+
+void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
+				void *urb_handle, void *buf, dwc_dma_t dma,
+				uint32_t buflen, void *setup_packet,
+				dwc_dma_t setup_dma, uint32_t flags,
+				uint16_t interval)
+{
+	dwc_otg_urb->priv = urb_handle;
+	dwc_otg_urb->buf = buf;
+	dwc_otg_urb->dma = dma;
+	dwc_otg_urb->length = buflen;
+	dwc_otg_urb->setup_packet = setup_packet;
+	dwc_otg_urb->setup_dma = setup_dma;
+	dwc_otg_urb->flags = flags;
+	dwc_otg_urb->interval = interval;
+	dwc_otg_urb->status = -DWC_E_IN_PROGRESS;
+}
+
+uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb)
+{
+	return dwc_otg_urb->status;
+}
+
+uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t * dwc_otg_urb)
+{
+	return dwc_otg_urb->actual_length;
+}
+
+uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t * dwc_otg_urb)
+{
+	return dwc_otg_urb->error_count;
+}
+
+void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
+					 int desc_num, uint32_t offset,
+					 uint32_t length)
+{
+	dwc_otg_urb->iso_descs[desc_num].offset = offset;
+	dwc_otg_urb->iso_descs[desc_num].length = length;
+}
+
+uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t * dwc_otg_urb,
+					     int desc_num)
+{
+	return dwc_otg_urb->iso_descs[desc_num].status;
+}
+
+uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t *
+						    dwc_otg_urb, int desc_num)
+{
+	return dwc_otg_urb->iso_descs[desc_num].actual_length;
+}
+
+int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd, void *ep_handle)
+{
+	int allocated = 0;
+	dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
+
+	if (qh) {
+		if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
+			allocated = 1;
+		}
+	}
+	return allocated;
+}
+
+int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle)
+{
+	dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
+	int freed = 0;
+	DWC_ASSERT(qh, "qh is not allocated\n");
+
+	if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
+		freed = 1;
+	}
+
+	return freed;
+}
+
+uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd, void *ep_handle)
+{
+	dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
+	DWC_ASSERT(qh, "qh is not allocated\n");
+	return qh->usecs;
+}
+
+void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd)
+{
+#ifdef DEBUG
+	int num_channels;
+	int i;
+	gnptxsts_data_t np_tx_status;
+	hptxsts_data_t p_tx_status;
+
+	num_channels = hcd->core_if->core_params->host_channels;
+	DWC_PRINTF("\n");
+	DWC_PRINTF
+	    ("************************************************************\n");
+	DWC_PRINTF("HCD State:\n");
+	DWC_PRINTF("  Num channels: %d\n", num_channels);
+	for (i = 0; i < num_channels; i++) {
+		dwc_hc_t *hc = hcd->hc_ptr_array[i];
+		DWC_PRINTF("  Channel %d:\n", i);
+		DWC_PRINTF("    dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
+			   hc->dev_addr, hc->ep_num, hc->ep_is_in);
+		DWC_PRINTF("    speed: %d\n", hc->speed);
+		DWC_PRINTF("    ep_type: %d\n", hc->ep_type);
+		DWC_PRINTF("    max_packet: %d\n", hc->max_packet);
+		DWC_PRINTF("    data_pid_start: %d\n", hc->data_pid_start);
+		DWC_PRINTF("    multi_count: %d\n", hc->multi_count);
+		DWC_PRINTF("    xfer_started: %d\n", hc->xfer_started);
+		DWC_PRINTF("    xfer_buff: %p\n", hc->xfer_buff);
+		DWC_PRINTF("    xfer_len: %d\n", hc->xfer_len);
+		DWC_PRINTF("    xfer_count: %d\n", hc->xfer_count);
+		DWC_PRINTF("    halt_on_queue: %d\n", hc->halt_on_queue);
+		DWC_PRINTF("    halt_pending: %d\n", hc->halt_pending);
+		DWC_PRINTF("    halt_status: %d\n", hc->halt_status);
+		DWC_PRINTF("    do_split: %d\n", hc->do_split);
+		DWC_PRINTF("    complete_split: %d\n", hc->complete_split);
+		DWC_PRINTF("    hub_addr: %d\n", hc->hub_addr);
+		DWC_PRINTF("    port_addr: %d\n", hc->port_addr);
+		DWC_PRINTF("    xact_pos: %d\n", hc->xact_pos);
+		DWC_PRINTF("    requests: %d\n", hc->requests);
+		DWC_PRINTF("    qh: %p\n", hc->qh);
+		if (hc->xfer_started) {
+			hfnum_data_t hfnum;
+			hcchar_data_t hcchar;
+			hctsiz_data_t hctsiz;
+			hcint_data_t hcint;
+			hcintmsk_data_t hcintmsk;
+			hfnum.d32 =
+			    DWC_READ_REG32(&hcd->core_if->
+					   host_if->host_global_regs->hfnum);
+			hcchar.d32 =
+			    DWC_READ_REG32(&hcd->core_if->host_if->
+					   hc_regs[i]->hcchar);
+			hctsiz.d32 =
+			    DWC_READ_REG32(&hcd->core_if->host_if->
+					   hc_regs[i]->hctsiz);
+			hcint.d32 =
+			    DWC_READ_REG32(&hcd->core_if->host_if->
+					   hc_regs[i]->hcint);
+			hcintmsk.d32 =
+			    DWC_READ_REG32(&hcd->core_if->host_if->
+					   hc_regs[i]->hcintmsk);
+			DWC_PRINTF("    hfnum: 0x%08x\n", hfnum.d32);
+			DWC_PRINTF("    hcchar: 0x%08x\n", hcchar.d32);
+			DWC_PRINTF("    hctsiz: 0x%08x\n", hctsiz.d32);
+			DWC_PRINTF("    hcint: 0x%08x\n", hcint.d32);
+			DWC_PRINTF("    hcintmsk: 0x%08x\n", hcintmsk.d32);
+		}
+		if (hc->xfer_started && hc->qh) {
+			dwc_otg_qtd_t *qtd;
+			dwc_otg_hcd_urb_t *urb;
+			
+			DWC_CIRCLEQ_FOREACH(qtd, &hc->qh->qtd_list, qtd_list_entry) {
+				if (!qtd->in_process)
+					break;
+				
+				urb = qtd->urb;
+			DWC_PRINTF("    URB Info:\n");
+			DWC_PRINTF("      qtd: %p, urb: %p\n", qtd, urb);
+			if (urb) {
+				DWC_PRINTF("      Dev: %d, EP: %d %s\n",
+					   dwc_otg_hcd_get_dev_addr(&urb->
+								    pipe_info),
+					   dwc_otg_hcd_get_ep_num(&urb->
+								  pipe_info),
+					   dwc_otg_hcd_is_pipe_in(&urb->
+								  pipe_info) ?
+					   "IN" : "OUT");
+				DWC_PRINTF("      Max packet size: %d\n",
+					   dwc_otg_hcd_get_mps(&urb->
+							       pipe_info));
+				DWC_PRINTF("      transfer_buffer: %p\n",
+					   urb->buf);
+				DWC_PRINTF("      transfer_dma: %p\n",
+					   (void *)urb->dma);
+				DWC_PRINTF("      transfer_buffer_length: %d\n",
+					   urb->length);
+					DWC_PRINTF("      actual_length: %d\n",
+						   urb->actual_length);
+				}
+			}
+		}
+	}
+	DWC_PRINTF("  non_periodic_channels: %d\n", hcd->non_periodic_channels);
+	DWC_PRINTF("  periodic_channels: %d\n", hcd->periodic_channels);
+	DWC_PRINTF("  periodic_usecs: %d\n", hcd->periodic_usecs);
+	np_tx_status.d32 =
+	    DWC_READ_REG32(&hcd->core_if->core_global_regs->gnptxsts);
+	DWC_PRINTF("  NP Tx Req Queue Space Avail: %d\n",
+		   np_tx_status.b.nptxqspcavail);
+	DWC_PRINTF("  NP Tx FIFO Space Avail: %d\n",
+		   np_tx_status.b.nptxfspcavail);
+	p_tx_status.d32 =
+	    DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hptxsts);
+	DWC_PRINTF("  P Tx Req Queue Space Avail: %d\n",
+		   p_tx_status.b.ptxqspcavail);
+	DWC_PRINTF("  P Tx FIFO Space Avail: %d\n", p_tx_status.b.ptxfspcavail);
+	dwc_otg_hcd_dump_frrem(hcd);
+	dwc_otg_dump_global_registers(hcd->core_if);
+	dwc_otg_dump_host_registers(hcd->core_if);
+	DWC_PRINTF
+	    ("************************************************************\n");
+	DWC_PRINTF("\n");
+#endif
+}
+
+#ifdef DEBUG
+void dwc_print_setup_data(uint8_t * setup)
+{
+	int i;
+	if (CHK_DEBUG_LEVEL(DBG_HCD)) {
+		DWC_PRINTF("Setup Data = MSB ");
+		for (i = 7; i >= 0; i--)
+			DWC_PRINTF("%02x ", setup[i]);
+		DWC_PRINTF("\n");
+		DWC_PRINTF("  bmRequestType Tranfer = %s\n",
+			   (setup[0] & 0x80) ? "Device-to-Host" :
+			   "Host-to-Device");
+		DWC_PRINTF("  bmRequestType Type = ");
+		switch ((setup[0] & 0x60) >> 5) {
+		case 0:
+			DWC_PRINTF("Standard\n");
+			break;
+		case 1:
+			DWC_PRINTF("Class\n");
+			break;
+		case 2:
+			DWC_PRINTF("Vendor\n");
+			break;
+		case 3:
+			DWC_PRINTF("Reserved\n");
+			break;
+		}
+		DWC_PRINTF("  bmRequestType Recipient = ");
+		switch (setup[0] & 0x1f) {
+		case 0:
+			DWC_PRINTF("Device\n");
+			break;
+		case 1:
+			DWC_PRINTF("Interface\n");
+			break;
+		case 2:
+			DWC_PRINTF("Endpoint\n");
+			break;
+		case 3:
+			DWC_PRINTF("Other\n");
+			break;
+		default:
+			DWC_PRINTF("Reserved\n");
+			break;
+		}
+		DWC_PRINTF("  bRequest = 0x%0x\n", setup[1]);
+		DWC_PRINTF("  wValue = 0x%0x\n", *((uint16_t *) & setup[2]));
+		DWC_PRINTF("  wIndex = 0x%0x\n", *((uint16_t *) & setup[4]));
+		DWC_PRINTF("  wLength = 0x%0x\n\n", *((uint16_t *) & setup[6]));
+	}
+}
+#endif
+
+void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd)
+{
+#if 0
+	DWC_PRINTF("Frame remaining at SOF:\n");
+	DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
+		   hcd->frrem_samples, hcd->frrem_accum,
+		   (hcd->frrem_samples > 0) ?
+		   hcd->frrem_accum / hcd->frrem_samples : 0);
+
+	DWC_PRINTF("\n");
+	DWC_PRINTF("Frame remaining at start_transfer (uframe 7):\n");
+	DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
+		   hcd->core_if->hfnum_7_samples,
+		   hcd->core_if->hfnum_7_frrem_accum,
+		   (hcd->core_if->hfnum_7_samples >
+		    0) ? hcd->core_if->hfnum_7_frrem_accum /
+		   hcd->core_if->hfnum_7_samples : 0);
+	DWC_PRINTF("Frame remaining at start_transfer (uframe 0):\n");
+	DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
+		   hcd->core_if->hfnum_0_samples,
+		   hcd->core_if->hfnum_0_frrem_accum,
+		   (hcd->core_if->hfnum_0_samples >
+		    0) ? hcd->core_if->hfnum_0_frrem_accum /
+		   hcd->core_if->hfnum_0_samples : 0);
+	DWC_PRINTF("Frame remaining at start_transfer (uframe 1-6):\n");
+	DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
+		   hcd->core_if->hfnum_other_samples,
+		   hcd->core_if->hfnum_other_frrem_accum,
+		   (hcd->core_if->hfnum_other_samples >
+		    0) ? hcd->core_if->hfnum_other_frrem_accum /
+		   hcd->core_if->hfnum_other_samples : 0);
+
+	DWC_PRINTF("\n");
+	DWC_PRINTF("Frame remaining at sample point A (uframe 7):\n");
+	DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
+		   hcd->hfnum_7_samples_a, hcd->hfnum_7_frrem_accum_a,
+		   (hcd->hfnum_7_samples_a > 0) ?
+		   hcd->hfnum_7_frrem_accum_a / hcd->hfnum_7_samples_a : 0);
+	DWC_PRINTF("Frame remaining at sample point A (uframe 0):\n");
+	DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
+		   hcd->hfnum_0_samples_a, hcd->hfnum_0_frrem_accum_a,
+		   (hcd->hfnum_0_samples_a > 0) ?
+		   hcd->hfnum_0_frrem_accum_a / hcd->hfnum_0_samples_a : 0);
+	DWC_PRINTF("Frame remaining at sample point A (uframe 1-6):\n");
+	DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
+		   hcd->hfnum_other_samples_a, hcd->hfnum_other_frrem_accum_a,
+		   (hcd->hfnum_other_samples_a > 0) ?
+		   hcd->hfnum_other_frrem_accum_a /
+		   hcd->hfnum_other_samples_a : 0);
+
+	DWC_PRINTF("\n");
+	DWC_PRINTF("Frame remaining at sample point B (uframe 7):\n");
+	DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
+		   hcd->hfnum_7_samples_b, hcd->hfnum_7_frrem_accum_b,
+		   (hcd->hfnum_7_samples_b > 0) ?
+		   hcd->hfnum_7_frrem_accum_b / hcd->hfnum_7_samples_b : 0);
+	DWC_PRINTF("Frame remaining at sample point B (uframe 0):\n");
+	DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
+		   hcd->hfnum_0_samples_b, hcd->hfnum_0_frrem_accum_b,
+		   (hcd->hfnum_0_samples_b > 0) ?
+		   hcd->hfnum_0_frrem_accum_b / hcd->hfnum_0_samples_b : 0);
+	DWC_PRINTF("Frame remaining at sample point B (uframe 1-6):\n");
+	DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
+		   hcd->hfnum_other_samples_b, hcd->hfnum_other_frrem_accum_b,
+		   (hcd->hfnum_other_samples_b > 0) ?
+		   hcd->hfnum_other_frrem_accum_b /
+		   hcd->hfnum_other_samples_b : 0);
+#endif
+}
+
+#endif /* DWC_DEVICE_ONLY */
diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd.h b/drivers/usb/dwc_otg/dwc_otg_hcd.h
new file mode 100644
index 0000000..58a1293
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_hcd.h
@@ -0,0 +1,803 @@
+/* ==========================================================================
+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.h $
+ * $Revision: #58 $
+ * $Date: 2011/09/15 $
+ * $Change: 1846647 $
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+#ifndef DWC_DEVICE_ONLY
+#ifndef __DWC_HCD_H__
+#define __DWC_HCD_H__
+
+#include "dwc_otg_os_dep.h"
+#include "usb.h"
+#include "dwc_otg_hcd_if.h"
+#include "dwc_otg_core_if.h"
+#include "dwc_list.h"
+#include "dwc_otg_cil.h"
+
+/**
+ * @file
+ *
+ * This file contains the structures, constants, and interfaces for
+ * the Host Contoller Driver (HCD).
+ *
+ * The Host Controller Driver (HCD) is responsible for translating requests
+ * from the USB Driver into the appropriate actions on the DWC_otg controller.
+ * It isolates the USBD from the specifics of the controller by providing an
+ * API to the USBD.
+ */
+
+struct dwc_otg_hcd_pipe_info {
+	uint8_t dev_addr;
+	uint8_t ep_num;
+	uint8_t pipe_type;
+	uint8_t pipe_dir;
+	uint16_t mps;
+};
+
+struct dwc_otg_hcd_iso_packet_desc {
+	uint32_t offset;
+	uint32_t length;
+	uint32_t actual_length;
+	uint32_t status;
+};
+
+struct dwc_otg_qtd;
+
+struct dwc_otg_hcd_urb {
+	void *priv;
+	struct dwc_otg_qtd *qtd;
+	void *buf;
+	dwc_dma_t dma;
+	void *setup_packet;
+	dwc_dma_t setup_dma;
+	uint32_t length;
+	uint32_t actual_length;
+	uint32_t status;
+	uint32_t error_count;
+	uint32_t packet_count;
+	uint32_t flags;
+	uint16_t interval;
+	struct dwc_otg_hcd_pipe_info pipe_info;
+	struct dwc_otg_hcd_iso_packet_desc iso_descs[0];
+};
+
+static inline uint8_t dwc_otg_hcd_get_ep_num(struct dwc_otg_hcd_pipe_info *pipe)
+{
+	return pipe->ep_num;
+}
+
+static inline uint8_t dwc_otg_hcd_get_pipe_type(struct dwc_otg_hcd_pipe_info
+						*pipe)
+{
+	return pipe->pipe_type;
+}
+
+static inline uint16_t dwc_otg_hcd_get_mps(struct dwc_otg_hcd_pipe_info *pipe)
+{
+	return pipe->mps;
+}
+
+static inline uint8_t dwc_otg_hcd_get_dev_addr(struct dwc_otg_hcd_pipe_info
+					       *pipe)
+{
+	return pipe->dev_addr;
+}
+
+static inline uint8_t dwc_otg_hcd_is_pipe_isoc(struct dwc_otg_hcd_pipe_info
+					       *pipe)
+{
+	return (pipe->pipe_type == UE_ISOCHRONOUS);
+}
+
+static inline uint8_t dwc_otg_hcd_is_pipe_int(struct dwc_otg_hcd_pipe_info
+					      *pipe)
+{
+	return (pipe->pipe_type == UE_INTERRUPT);
+}
+
+static inline uint8_t dwc_otg_hcd_is_pipe_bulk(struct dwc_otg_hcd_pipe_info
+					       *pipe)
+{
+	return (pipe->pipe_type == UE_BULK);
+}
+
+static inline uint8_t dwc_otg_hcd_is_pipe_control(struct dwc_otg_hcd_pipe_info
+						  *pipe)
+{
+	return (pipe->pipe_type == UE_CONTROL);
+}
+
+static inline uint8_t dwc_otg_hcd_is_pipe_in(struct dwc_otg_hcd_pipe_info *pipe)
+{
+	return (pipe->pipe_dir == UE_DIR_IN);
+}
+
+static inline uint8_t dwc_otg_hcd_is_pipe_out(struct dwc_otg_hcd_pipe_info
+					      *pipe)
+{
+	return (!dwc_otg_hcd_is_pipe_in(pipe));
+}
+
+static inline void dwc_otg_hcd_fill_pipe(struct dwc_otg_hcd_pipe_info *pipe,
+					 uint8_t devaddr, uint8_t ep_num,
+					 uint8_t pipe_type, uint8_t pipe_dir,
+					 uint16_t mps)
+{
+	pipe->dev_addr = devaddr;
+	pipe->ep_num = ep_num;
+	pipe->pipe_type = pipe_type;
+	pipe->pipe_dir = pipe_dir;
+	pipe->mps = mps;
+}
+
+/**
+ * Phases for control transfers.
+ */
+typedef enum dwc_otg_control_phase {
+	DWC_OTG_CONTROL_SETUP,
+	DWC_OTG_CONTROL_DATA,
+	DWC_OTG_CONTROL_STATUS
+} dwc_otg_control_phase_e;
+
+/** Transaction types. */
+typedef enum dwc_otg_transaction_type {
+	DWC_OTG_TRANSACTION_NONE,
+	DWC_OTG_TRANSACTION_PERIODIC,
+	DWC_OTG_TRANSACTION_NON_PERIODIC,
+	DWC_OTG_TRANSACTION_ALL
+} dwc_otg_transaction_type_e;
+
+struct dwc_otg_qh;
+
+/**
+ * A Queue Transfer Descriptor (QTD) holds the state of a bulk, control,
+ * interrupt, or isochronous transfer. A single QTD is created for each URB
+ * (of one of these types) submitted to the HCD. The transfer associated with
+ * a QTD may require one or multiple transactions.
+ *
+ * A QTD is linked to a Queue Head, which is entered in either the
+ * non-periodic or periodic schedule for execution. When a QTD is chosen for
+ * execution, some or all of its transactions may be executed. After
+ * execution, the state of the QTD is updated. The QTD may be retired if all
+ * its transactions are complete or if an error occurred. Otherwise, it
+ * remains in the schedule so more transactions can be executed later.
+ */
+typedef struct dwc_otg_qtd {
+	/**
+	 * Determines the PID of the next data packet for the data phase of
+	 * control transfers. Ignored for other transfer types.<br>
+	 * One of the following values:
+	 *	- DWC_OTG_HC_PID_DATA0
+	 *	- DWC_OTG_HC_PID_DATA1
+	 */
+	uint8_t data_toggle;
+
+	/** Current phase for control transfers (Setup, Data, or Status). */
+	dwc_otg_control_phase_e control_phase;
+
+	/** Keep track of the current split type
+	 * for FS/LS endpoints on a HS Hub */
+	uint8_t complete_split;
+
+	/** How many bytes transferred during SSPLIT OUT */
+	uint32_t ssplit_out_xfer_count;
+
+	/**
+	 * Holds the number of bus errors that have occurred for a transaction
+	 * within this transfer.
+	 */
+	uint8_t error_count;
+
+	/**
+	 * Index of the next frame descriptor for an isochronous transfer. A
+	 * frame descriptor describes the buffer position and length of the
+	 * data to be transferred in the next scheduled (micro)frame of an
+	 * isochronous transfer. It also holds status for that transaction.
+	 * The frame index starts at 0.
+	 */
+	uint16_t isoc_frame_index;
+
+	/** Position of the ISOC split on full/low speed */
+	uint8_t isoc_split_pos;
+
+	/** Position of the ISOC split in the buffer for the current frame */
+	uint16_t isoc_split_offset;
+
+	/** URB for this transfer */
+	struct dwc_otg_hcd_urb *urb;
+
+	struct dwc_otg_qh *qh;
+
+	/** This list of QTDs */
+	 DWC_CIRCLEQ_ENTRY(dwc_otg_qtd) qtd_list_entry;
+
+	/** Indicates if this QTD is currently processed by HW. */
+	uint8_t in_process;
+
+	/** Number of DMA descriptors for this QTD */
+	uint8_t n_desc;
+
+	/** 
+	 * Last activated frame(packet) index. 
+	 * Used in Descriptor DMA mode only.
+	 */
+	uint16_t isoc_frame_index_last;
+
+} dwc_otg_qtd_t;
+
+DWC_CIRCLEQ_HEAD(dwc_otg_qtd_list, dwc_otg_qtd);
+
+/**
+ * A Queue Head (QH) holds the static characteristics of an endpoint and
+ * maintains a list of transfers (QTDs) for that endpoint. A QH structure may
+ * be entered in either the non-periodic or periodic schedule.
+ */
+typedef struct dwc_otg_qh {
+	/**
+	 * Endpoint type.
+	 * One of the following values:
+	 *	- UE_CONTROL
+	 *	- UE_BULK
+	 *	- UE_INTERRUPT
+	 *	- UE_ISOCHRONOUS
+	 */
+	uint8_t ep_type;
+	uint8_t ep_is_in;
+
+	/** wMaxPacketSize Field of Endpoint Descriptor. */
+	uint16_t maxp;
+
+	/**
+	 * Device speed.
+	 * One of the following values:
+	 *	- DWC_OTG_EP_SPEED_LOW
+	 *	- DWC_OTG_EP_SPEED_FULL
+	 *	- DWC_OTG_EP_SPEED_HIGH
+	 */
+	uint8_t dev_speed;
+
+	/**
+	 * Determines the PID of the next data packet for non-control
+	 * transfers. Ignored for control transfers.<br>
+	 * One of the following values:
+	 *	- DWC_OTG_HC_PID_DATA0
+	 *	- DWC_OTG_HC_PID_DATA1
+	 */
+	uint8_t data_toggle;
+
+	/** Ping state if 1. */
+	uint8_t ping_state;
+
+	/**
+	 * List of QTDs for this QH.
+	 */
+	struct dwc_otg_qtd_list qtd_list;
+
+	/** Host channel currently processing transfers for this QH. */
+	struct dwc_hc *channel;
+
+	/** Full/low speed endpoint on high-speed hub requires split. */
+	uint8_t do_split;
+
+	/** @name Periodic schedule information */
+	/** @{ */
+
+	/** Bandwidth in microseconds per (micro)frame. */
+	uint16_t usecs;
+
+	/** Interval between transfers in (micro)frames. */
+	uint16_t interval;
+
+	/**
+	 * (micro)frame to initialize a periodic transfer. The transfer
+	 * executes in the following (micro)frame.
+	 */
+	uint16_t sched_frame;
+
+	/** (micro)frame at which last start split was initialized. */
+	uint16_t start_split_frame;
+
+	/** @} */
+
+	/** 
+	 * Used instead of original buffer if 
+	 * it(physical address) is not dword-aligned.
+	 */
+	uint8_t *dw_align_buf;
+	dwc_dma_t dw_align_buf_dma;
+
+	/** Entry for QH in either the periodic or non-periodic schedule. */
+	dwc_list_link_t qh_list_entry;
+
+	/** @name Descriptor DMA support */
+	/** @{ */
+
+	/** Descriptor List. */
+	dwc_otg_host_dma_desc_t *desc_list;
+
+	/** Descriptor List physical address. */
+	dwc_dma_t desc_list_dma;
+
+	/** 
+	 * Xfer Bytes array.
+	 * Each element corresponds to a descriptor and indicates 
+	 * original XferSize size value for the descriptor.
+	 */
+	uint32_t *n_bytes;
+
+	/** Actual number of transfer descriptors in a list. */
+	uint16_t ntd;
+
+	/** First activated isochronous transfer descriptor index. */
+	uint8_t td_first;
+	/** Last activated isochronous transfer descriptor index. */
+	uint8_t td_last;
+
+	/** @} */
+
+} dwc_otg_qh_t;
+
+DWC_CIRCLEQ_HEAD(hc_list, dwc_hc);
+
+/**
+ * This structure holds the state of the HCD, including the non-periodic and
+ * periodic schedules.
+ */
+struct dwc_otg_hcd {
+	/** The DWC otg device pointer */
+	struct dwc_otg_device *otg_dev;
+	/** DWC OTG Core Interface Layer */
+	dwc_otg_core_if_t *core_if;
+
+	/** Function HCD driver callbacks */
+	struct dwc_otg_hcd_function_ops *fops;
+
+	/** Internal DWC HCD Flags */
+	volatile union dwc_otg_hcd_internal_flags {
+		uint32_t d32;
+		struct {
+			unsigned port_connect_status_change:1;
+			unsigned port_connect_status:1;
+			unsigned port_reset_change:1;
+			unsigned port_enable_change:1;
+			unsigned port_suspend_change:1;
+			unsigned port_over_current_change:1;
+			unsigned port_l1_change:1;
+			unsigned reserved:26;
+		} b;
+	} flags;
+
+	/**
+	 * Inactive items in the non-periodic schedule. This is a list of
+	 * Queue Heads. Transfers associated with these Queue Heads are not
+	 * currently assigned to a host channel.
+	 */
+	dwc_list_link_t non_periodic_sched_inactive;
+
+	/**
+	 * Active items in the non-periodic schedule. This is a list of
+	 * Queue Heads. Transfers associated with these Queue Heads are
+	 * currently assigned to a host channel.
+	 */
+	dwc_list_link_t non_periodic_sched_active;
+
+	/**
+	 * Pointer to the next Queue Head to process in the active
+	 * non-periodic schedule.
+	 */
+	dwc_list_link_t *non_periodic_qh_ptr;
+
+	/**
+	 * Inactive items in the periodic schedule. This is a list of QHs for
+	 * periodic transfers that are _not_ scheduled for the next frame.
+	 * Each QH in the list has an interval counter that determines when it
+	 * needs to be scheduled for execution. This scheduling mechanism
+	 * allows only a simple calculation for periodic bandwidth used (i.e.
+	 * must assume that all periodic transfers may need to execute in the
+	 * same frame). However, it greatly simplifies scheduling and should
+	 * be sufficient for the vast majority of OTG hosts, which need to
+	 * connect to a small number of peripherals at one time.
+	 *
+	 * Items move from this list to periodic_sched_ready when the QH
+	 * interval counter is 0 at SOF.
+	 */
+	dwc_list_link_t periodic_sched_inactive;
+
+	/**
+	 * List of periodic QHs that are ready for execution in the next
+	 * frame, but have not yet been assigned to host channels.
+	 *
+	 * Items move from this list to periodic_sched_assigned as host
+	 * channels become available during the current frame.
+	 */
+	dwc_list_link_t periodic_sched_ready;
+
+	/**
+	 * List of periodic QHs to be executed in the next frame that are
+	 * assigned to host channels.
+	 *
+	 * Items move from this list to periodic_sched_queued as the
+	 * transactions for the QH are queued to the DWC_otg controller.
+	 */
+	dwc_list_link_t periodic_sched_assigned;
+
+	/**
+	 * List of periodic QHs that have been queued for execution.
+	 *
+	 * Items move from this list to either periodic_sched_inactive or
+	 * periodic_sched_ready when the channel associated with the transfer
+	 * is released. If the interval for the QH is 1, the item moves to
+	 * periodic_sched_ready because it must be rescheduled for the next
+	 * frame. Otherwise, the item moves to periodic_sched_inactive.
+	 */
+	dwc_list_link_t periodic_sched_queued;
+
+	/**
+	 * Total bandwidth claimed so far for periodic transfers. This value
+	 * is in microseconds per (micro)frame. The assumption is that all
+	 * periodic transfers may occur in the same (micro)frame.
+	 */
+	uint16_t periodic_usecs;
+
+	/**
+	 * Frame number read from the core at SOF. The value ranges from 0 to
+	 * DWC_HFNUM_MAX_FRNUM.
+	 */
+	uint16_t frame_number;
+
+	/**
+	 * Count of periodic QHs, if using several eps. For SOF enable/disable.
+	 */
+	uint16_t periodic_qh_count;
+
+	/**
+	 * Free host channels in the controller. This is a list of
+	 * dwc_hc_t items.
+	 */
+	struct hc_list free_hc_list;
+	/**
+	 * Number of host channels assigned to periodic transfers. Currently
+	 * assuming that there is a dedicated host channel for each periodic
+	 * transaction and at least one host channel available for
+	 * non-periodic transactions.
+	 */
+	int periodic_channels;
+
+	/**
+	 * Number of host channels assigned to non-periodic transfers.
+	 */
+	int non_periodic_channels;
+
+	/**
+	 * Array of pointers to the host channel descriptors. Allows accessing
+	 * a host channel descriptor given the host channel number. This is
+	 * useful in interrupt handlers.
+	 */
+	struct dwc_hc *hc_ptr_array[MAX_EPS_CHANNELS];
+
+	/**
+	 * Buffer to use for any data received during the status phase of a
+	 * control transfer. Normally no data is transferred during the status
+	 * phase. This buffer is used as a bit bucket.
+	 */
+	uint8_t *status_buf;
+
+	/**
+	 * DMA address for status_buf.
+	 */
+	dma_addr_t status_buf_dma;
+#define DWC_OTG_HCD_STATUS_BUF_SIZE 64
+
+	/**
+	 * Connection timer. An OTG host must display a message if the device
+	 * does not connect. Started when the VBus power is turned on via
+	 * sysfs attribute "buspower".
+	 */
+	dwc_timer_t *conn_timer;
+
+	/* Tasket to do a reset */
+	dwc_tasklet_t *reset_tasklet;
+
+	/*  */
+	dwc_spinlock_t *lock;
+
+	/**
+	 * Private data that could be used by OS wrapper.
+	 */
+	void *priv;
+
+	uint8_t otg_port;
+
+	/** Frame List */
+	uint32_t *frame_list;
+
+	/** Frame List DMA address */
+	dma_addr_t frame_list_dma;
+
+#ifdef DEBUG
+	uint32_t frrem_samples;
+	uint64_t frrem_accum;
+
+	uint32_t hfnum_7_samples_a;
+	uint64_t hfnum_7_frrem_accum_a;
+	uint32_t hfnum_0_samples_a;
+	uint64_t hfnum_0_frrem_accum_a;
+	uint32_t hfnum_other_samples_a;
+	uint64_t hfnum_other_frrem_accum_a;
+
+	uint32_t hfnum_7_samples_b;
+	uint64_t hfnum_7_frrem_accum_b;
+	uint32_t hfnum_0_samples_b;
+	uint64_t hfnum_0_frrem_accum_b;
+	uint32_t hfnum_other_samples_b;
+	uint64_t hfnum_other_frrem_accum_b;
+#endif
+};
+
+/** @name Transaction Execution Functions */
+/** @{ */
+extern dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t
+								  * hcd);
+extern void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd,
+					   dwc_otg_transaction_type_e tr_type);
+
+/** @} */
+
+/** @name Interrupt Handler Functions */
+/** @{ */
+extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd);
+extern int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * dwc_otg_hcd);
+extern int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t *
+							 dwc_otg_hcd);
+extern int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t *
+							dwc_otg_hcd);
+extern int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(dwc_otg_hcd_t *
+							   dwc_otg_hcd);
+extern int32_t dwc_otg_hcd_handle_incomplete_periodic_intr(dwc_otg_hcd_t *
+							   dwc_otg_hcd);
+extern int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd);
+extern int32_t dwc_otg_hcd_handle_conn_id_status_change_intr(dwc_otg_hcd_t *
+							     dwc_otg_hcd);
+extern int32_t dwc_otg_hcd_handle_disconnect_intr(dwc_otg_hcd_t * dwc_otg_hcd);
+extern int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd);
+extern int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd,
+					    uint32_t num);
+extern int32_t dwc_otg_hcd_handle_session_req_intr(dwc_otg_hcd_t * dwc_otg_hcd);
+extern int32_t dwc_otg_hcd_handle_wakeup_detected_intr(dwc_otg_hcd_t *
+						       dwc_otg_hcd);
+/** @} */
+
+/** @name Schedule Queue Functions */
+/** @{ */
+
+/* Implemented in dwc_otg_hcd_queue.c */
+extern dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
+					   dwc_otg_hcd_urb_t * urb, int atomic_alloc);
+extern void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
+extern int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
+extern void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
+extern void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
+				      int sched_csplit);
+
+/** Remove and free a QH */
+static inline void dwc_otg_hcd_qh_remove_and_free(dwc_otg_hcd_t * hcd,
+						  dwc_otg_qh_t * qh)
+{
+	dwc_irqflags_t flags;
+	DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
+	dwc_otg_hcd_qh_remove(hcd, qh);
+	DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
+	dwc_otg_hcd_qh_free(hcd, qh);
+}
+
+/** Allocates memory for a QH structure.
+ * @return Returns the memory allocate or NULL on error. */
+static inline dwc_otg_qh_t *dwc_otg_hcd_qh_alloc(int atomic_alloc)
+{
+	if (atomic_alloc)
+		return (dwc_otg_qh_t *) DWC_ALLOC_ATOMIC(sizeof(dwc_otg_qh_t));
+	else
+		return (dwc_otg_qh_t *) DWC_ALLOC(sizeof(dwc_otg_qh_t));
+}
+
+extern dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb,
+					     int atomic_alloc);
+extern void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb);
+extern int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd, dwc_otg_hcd_t * dwc_otg_hcd,
+			       dwc_otg_qh_t ** qh, int atomic_alloc);
+
+/** Allocates memory for a QTD structure.
+ * @return Returns the memory allocate or NULL on error. */
+static inline dwc_otg_qtd_t *dwc_otg_hcd_qtd_alloc(int atomic_alloc)
+{
+	if (atomic_alloc)
+		return (dwc_otg_qtd_t *) DWC_ALLOC_ATOMIC(sizeof(dwc_otg_qtd_t));
+	else
+		return (dwc_otg_qtd_t *) DWC_ALLOC(sizeof(dwc_otg_qtd_t));
+}
+
+/** Frees the memory for a QTD structure.  QTD should already be removed from
+ * list.
+ * @param qtd QTD to free.*/
+static inline void dwc_otg_hcd_qtd_free(dwc_otg_qtd_t * qtd)
+{
+	DWC_FREE(qtd);
+}
+
+/** Removes a QTD from list.
+ * @param hcd HCD instance.
+ * @param qtd QTD to remove from list.
+ * @param qh QTD belongs to.
+ */
+static inline void dwc_otg_hcd_qtd_remove(dwc_otg_hcd_t * hcd,
+					  dwc_otg_qtd_t * qtd,
+					  dwc_otg_qh_t * qh)
+{
+	DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
+}
+
+/** Remove and free a QTD 
+  * Need to disable IRQ and hold hcd lock while calling this function out of 
+  * interrupt servicing chain */
+static inline void dwc_otg_hcd_qtd_remove_and_free(dwc_otg_hcd_t * hcd,
+						   dwc_otg_qtd_t * qtd,
+						   dwc_otg_qh_t * qh)
+{
+	dwc_otg_hcd_qtd_remove(hcd, qtd, qh);
+	dwc_otg_hcd_qtd_free(qtd);
+}
+
+/** @} */
+
+/** @name Descriptor DMA Supporting Functions */
+/** @{ */
+
+extern void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
+extern void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t * hcd,
+					   dwc_hc_t * hc,
+					   dwc_otg_hc_regs_t * hc_regs,
+					   dwc_otg_halt_status_e halt_status);
+
+extern int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
+extern void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
+
+/** @} */
+
+/** @name Internal Functions */
+/** @{ */
+dwc_otg_qh_t *dwc_urb_to_qh(dwc_otg_hcd_urb_t * urb);
+/** @} */
+
+#ifdef CONFIG_USB_DWC_OTG_LPM
+extern int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd,
+					   uint8_t devaddr);
+extern void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd);
+#endif
+
+/** Gets the QH that contains the list_head */
+#define dwc_list_to_qh(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qh_t, qh_list_entry)
+
+/** Gets the QTD that contains the list_head */
+#define dwc_list_to_qtd(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qtd_t, qtd_list_entry)
+
+/** Check if QH is non-periodic  */
+#define dwc_qh_is_non_per(_qh_ptr_) ((_qh_ptr_->ep_type == UE_BULK) || \
+				     (_qh_ptr_->ep_type == UE_CONTROL))
+
+/** High bandwidth multiplier as encoded in highspeed endpoint descriptors */
+#define dwc_hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+
+/** Packet size for any kind of endpoint descriptor */
+#define dwc_max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
+
+/**
+ * Returns true if _frame1 is less than or equal to _frame2. The comparison is
+ * done modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the
+ * frame number when the max frame number is reached.
+ */
+static inline int dwc_frame_num_le(uint16_t frame1, uint16_t frame2)
+{
+	return ((frame2 - frame1) & DWC_HFNUM_MAX_FRNUM) <=
+	    (DWC_HFNUM_MAX_FRNUM >> 1);
+}
+
+/**
+ * Returns true if _frame1 is greater than _frame2. The comparison is done
+ * modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the frame
+ * number when the max frame number is reached.
+ */
+static inline int dwc_frame_num_gt(uint16_t frame1, uint16_t frame2)
+{
+	return (frame1 != frame2) &&
+	    (((frame1 - frame2) & DWC_HFNUM_MAX_FRNUM) <
+	     (DWC_HFNUM_MAX_FRNUM >> 1));
+}
+
+/**
+ * Increments _frame by the amount specified by _inc. The addition is done
+ * modulo DWC_HFNUM_MAX_FRNUM. Returns the incremented value.
+ */
+static inline uint16_t dwc_frame_num_inc(uint16_t frame, uint16_t inc)
+{
+	return (frame + inc) & DWC_HFNUM_MAX_FRNUM;
+}
+
+static inline uint16_t dwc_full_frame_num(uint16_t frame)
+{
+	return (frame & DWC_HFNUM_MAX_FRNUM) >> 3;
+}
+
+static inline uint16_t dwc_micro_frame_num(uint16_t frame)
+{
+	return frame & 0x7;
+}
+
+void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc,
+				  dwc_otg_hc_regs_t * hc_regs,
+				  dwc_otg_qtd_t * qtd);
+
+#ifdef DEBUG
+/**
+ * Macro to sample the remaining PHY clocks left in the current frame. This
+ * may be used during debugging to determine the average time it takes to
+ * execute sections of code. There are two possible sample points, "a" and
+ * "b", so the _letter argument must be one of these values.
+ *
+ * To dump the average sample times, read the "hcd_frrem" sysfs attribute. For
+ * example, "cat /sys/devices/lm0/hcd_frrem".
+ */
+#define dwc_sample_frrem(_hcd, _qh, _letter) \
+{ \
+	hfnum_data_t hfnum; \
+	dwc_otg_qtd_t *qtd; \
+	qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); \
+	if (usb_pipeint(qtd->urb->pipe) && _qh->start_split_frame != 0 && !qtd->complete_split) { \
+		hfnum.d32 = DWC_READ_REG32(&_hcd->core_if->host_if->host_global_regs->hfnum); \
+		switch (hfnum.b.frnum & 0x7) { \
+		case 7: \
+			_hcd->hfnum_7_samples_##_letter++; \
+			_hcd->hfnum_7_frrem_accum_##_letter += hfnum.b.frrem; \
+			break; \
+		case 0: \
+			_hcd->hfnum_0_samples_##_letter++; \
+			_hcd->hfnum_0_frrem_accum_##_letter += hfnum.b.frrem; \
+			break; \
+		default: \
+			_hcd->hfnum_other_samples_##_letter++; \
+			_hcd->hfnum_other_frrem_accum_##_letter += hfnum.b.frrem; \
+			break; \
+		} \
+	} \
+}
+#else
+#define dwc_sample_frrem(_hcd, _qh, _letter)
+#endif
+#endif
+#endif /* DWC_DEVICE_ONLY */
diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd_ddma.c b/drivers/usb/dwc_otg/dwc_otg_hcd_ddma.c
new file mode 100644
index 0000000..6911e04
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_hcd_ddma.c
@@ -0,0 +1,1122 @@
+/*==========================================================================
+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_ddma.c $
+ * $Revision: #10 $
+ * $Date: 2011/10/20 $
+ * $Change: 1869464 $
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+#ifndef DWC_DEVICE_ONLY
+
+/** @file
+ * This file contains Descriptor DMA support implementation for host mode.
+ */
+
+#include "dwc_otg_hcd.h"
+#include "dwc_otg_regs.h"
+
+static inline uint8_t frame_list_idx(uint16_t frame)
+{
+	return (frame & (MAX_FRLIST_EN_NUM - 1));
+}
+
+static inline uint16_t desclist_idx_inc(uint16_t idx, uint16_t inc, uint8_t speed)
+{
+	return (idx + inc) &
+	    (((speed ==
+	       DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC :
+	      MAX_DMA_DESC_NUM_GENERIC) - 1);
+}
+
+static inline uint16_t desclist_idx_dec(uint16_t idx, uint16_t inc, uint8_t speed)
+{
+	return (idx - inc) &
+	    (((speed ==
+	       DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC :
+	      MAX_DMA_DESC_NUM_GENERIC) - 1);
+}
+
+static inline uint16_t max_desc_num(dwc_otg_qh_t * qh)
+{
+	return (((qh->ep_type == UE_ISOCHRONOUS)
+		 && (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH))
+		? MAX_DMA_DESC_NUM_HS_ISOC : MAX_DMA_DESC_NUM_GENERIC);
+}
+static inline uint16_t frame_incr_val(dwc_otg_qh_t * qh)
+{
+	return ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH)
+		? ((qh->interval + 8 - 1) / 8)
+		: qh->interval);
+}
+
+static int desc_list_alloc(dwc_otg_qh_t * qh)
+{
+	int retval = 0;
+
+	qh->desc_list = (dwc_otg_host_dma_desc_t *)
+	    DWC_DMA_ALLOC(sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh),
+			  &qh->desc_list_dma);
+
+	if (!qh->desc_list) {
+		retval = -DWC_E_NO_MEMORY;
+		DWC_ERROR("%s: DMA descriptor list allocation failed\n", __func__);
+		
+	}
+
+	dwc_memset(qh->desc_list, 0x00,
+		   sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
+
+	qh->n_bytes =
+	    (uint32_t *) DWC_ALLOC(sizeof(uint32_t) * max_desc_num(qh));
+
+	if (!qh->n_bytes) {
+		retval = -DWC_E_NO_MEMORY;
+		DWC_ERROR
+		    ("%s: Failed to allocate array for descriptors' size actual values\n",
+		     __func__);
+
+	}
+	return retval;
+
+}
+
+static void desc_list_free(dwc_otg_qh_t * qh)
+{
+	if (qh->desc_list) {
+		DWC_DMA_FREE(max_desc_num(qh), qh->desc_list,
+			     qh->desc_list_dma);
+		qh->desc_list = NULL;
+	}
+
+	if (qh->n_bytes) {
+		DWC_FREE(qh->n_bytes);
+		qh->n_bytes = NULL;
+	}
+}
+
+static int frame_list_alloc(dwc_otg_hcd_t * hcd)
+{
+	int retval = 0;
+	if (hcd->frame_list)
+		return 0;
+
+	hcd->frame_list = DWC_DMA_ALLOC(4 * MAX_FRLIST_EN_NUM,
+					&hcd->frame_list_dma);
+	if (!hcd->frame_list) {
+		retval = -DWC_E_NO_MEMORY;
+		DWC_ERROR("%s: Frame List allocation failed\n", __func__);
+	}
+
+	dwc_memset(hcd->frame_list, 0x00, 4 * MAX_FRLIST_EN_NUM);
+
+	return retval;
+}
+
+static void frame_list_free(dwc_otg_hcd_t * hcd)
+{
+	if (!hcd->frame_list)
+		return;
+	
+	DWC_DMA_FREE(4 * MAX_FRLIST_EN_NUM, hcd->frame_list, hcd->frame_list_dma);
+	hcd->frame_list = NULL;
+}
+
+static void per_sched_enable(dwc_otg_hcd_t * hcd, uint16_t fr_list_en)
+{
+
+	hcfg_data_t hcfg;
+
+	hcfg.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hcfg);
+
+	if (hcfg.b.perschedena) {
+		/* already enabled */
+		return;
+	}
+
+	DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hflbaddr,
+			hcd->frame_list_dma);
+
+	switch (fr_list_en) {
+	case 64:
+		hcfg.b.frlisten = 3;
+		break;
+	case 32:
+		hcfg.b.frlisten = 2;
+		break;
+	case 16:
+		hcfg.b.frlisten = 1;
+		break;
+	case 8:
+		hcfg.b.frlisten = 0;
+		break;
+	default:
+		break;
+	}
+
+	hcfg.b.perschedena = 1;
+
+	DWC_DEBUGPL(DBG_HCD, "Enabling Periodic schedule\n");
+	DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32);
+
+}
+
+static void per_sched_disable(dwc_otg_hcd_t * hcd)
+{
+	hcfg_data_t hcfg;
+
+	hcfg.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hcfg);
+	
+	if (!hcfg.b.perschedena) {
+		/* already disabled */
+		return;
+	}
+	hcfg.b.perschedena = 0;
+
+	DWC_DEBUGPL(DBG_HCD, "Disabling Periodic schedule\n");
+	DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32);
+}
+
+/* 
+ * Activates/Deactivates FrameList entries for the channel 
+ * based on endpoint servicing period.
+ */
+void update_frame_list(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, uint8_t enable)
+{
+	uint16_t i, j, inc;
+	dwc_hc_t *hc = NULL;
+
+	if (!qh->channel) {
+		DWC_ERROR("qh->channel = %p", qh->channel);
+		return;
+	}
+
+	if (!hcd) {
+		DWC_ERROR("------hcd = %p", hcd);
+		return;
+	}
+
+	if (!hcd->frame_list) {
+		DWC_ERROR("-------hcd->frame_list = %p", hcd->frame_list);
+		return;
+	}
+
+	hc = qh->channel;
+	inc = frame_incr_val(qh);
+	if (qh->ep_type == UE_ISOCHRONOUS)
+		i = frame_list_idx(qh->sched_frame);
+	else
+		i = 0;
+
+	j = i;
+	do {
+		if (enable)
+			hcd->frame_list[j] |= (1 << hc->hc_num);
+		else
+			hcd->frame_list[j] &= ~(1 << hc->hc_num);
+		j = (j + inc) & (MAX_FRLIST_EN_NUM - 1);
+	}
+	while (j != i);
+	if (!enable)
+		return;
+	hc->schinfo = 0;
+	if (qh->channel->speed == DWC_OTG_EP_SPEED_HIGH) {
+		j = 1;
+		/* TODO - check this */
+		inc = (8 + qh->interval - 1) / qh->interval;
+		for (i = 0; i < inc; i++) {
+			hc->schinfo |= j;
+			j = j << qh->interval;
+		}
+	} else {
+		hc->schinfo = 0xff;
+	}
+}
+
+#if 1
+void dump_frame_list(dwc_otg_hcd_t * hcd)
+{
+	int i = 0;
+	DWC_PRINTF("--FRAME LIST (hex) --\n");
+	for (i = 0; i < MAX_FRLIST_EN_NUM; i++) {
+		DWC_PRINTF("%x\t", hcd->frame_list[i]);
+		if (!(i % 8) && i)
+			DWC_PRINTF("\n");
+	}
+	DWC_PRINTF("\n----\n");
+
+}
+#endif
+
+static void release_channel_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+{
+	dwc_hc_t *hc = qh->channel;
+	if (dwc_qh_is_non_per(qh))
+		hcd->non_periodic_channels--;
+	else
+		update_frame_list(hcd, qh, 0);
+
+	/* 
+	 * The condition is added to prevent double cleanup try in case of device
+	 * disconnect. See channel cleanup in dwc_otg_hcd_disconnect_cb().
+	 */
+	if (hc->qh) {
+		dwc_otg_hc_cleanup(hcd->core_if, hc);
+		DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
+		hc->qh = NULL;
+	}
+
+	qh->channel = NULL;
+	qh->ntd = 0;
+
+	if (qh->desc_list) {
+		dwc_memset(qh->desc_list, 0x00,
+			   sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
+	}
+}
+
+/** 
+ * Initializes a QH structure's Descriptor DMA related members.
+ * Allocates memory for descriptor list.
+ * On first periodic QH, allocates memory for FrameList 
+ * and enables periodic scheduling.
+ *
+ * @param hcd The HCD state structure for the DWC OTG controller.
+ * @param qh The QH to init.
+ *
+ * @return 0 if successful, negative error code otherwise.
+ */
+int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+{
+	int retval = 0;
+
+	if (qh->do_split) {
+		DWC_ERROR("SPLIT Transfers are not supported in Descriptor DMA.\n");
+    		return -1;
+    	}
+
+	retval = desc_list_alloc(qh);
+
+	if ((retval == 0)
+	    && (qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)) {
+		if (!hcd->frame_list) {
+			retval = frame_list_alloc(hcd);
+			/* Enable periodic schedule on first periodic QH */
+			if (retval == 0)
+				per_sched_enable(hcd, MAX_FRLIST_EN_NUM);
+		}
+	}
+
+	qh->ntd = 0;
+
+	return retval;
+}
+
+/** 
+ * Frees descriptor list memory associated with the QH. 
+ * If QH is periodic and the last, frees FrameList memory 
+ * and disables periodic scheduling. 
+ *
+ * @param hcd The HCD state structure for the DWC OTG controller.
+ * @param qh The QH to init.
+ */
+void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+{
+	desc_list_free(qh);
+
+	/* 
+	 * Channel still assigned due to some reasons. 
+	 * Seen on Isoc URB dequeue. Channel halted but no subsequent
+	 * ChHalted interrupt to release the channel. Afterwards
+	 * when it comes here from endpoint disable routine
+	 * channel remains assigned.
+	 */
+	if (qh->channel)
+		release_channel_ddma(hcd, qh);
+
+	if ((qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)
+	    && !hcd->periodic_channels && hcd->frame_list) {
+
+		per_sched_disable(hcd);
+		frame_list_free(hcd);
+	}
+}
+
+static uint8_t frame_to_desc_idx(dwc_otg_qh_t * qh, uint16_t frame_idx)
+{
+	if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) {
+		/* 
+		 * Descriptor set(8 descriptors) index
+		 * which is 8-aligned.
+		 */
+		return (frame_idx & ((MAX_DMA_DESC_NUM_HS_ISOC / 8) - 1)) * 8;
+	} else {
+		return (frame_idx & (MAX_DMA_DESC_NUM_GENERIC - 1));
+	}
+}
+
+/* 
+ * Determine starting frame for Isochronous transfer. 
+ * Few frames skipped to prevent race condition with HC. 
+ */
+static uint8_t calc_starting_frame(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
+				   uint8_t * skip_frames)
+{
+	uint16_t frame = 0;
+	hcd->frame_number = dwc_otg_hcd_get_frame_number(hcd);
+	
+	/* sched_frame is always frame number(not uFrame) both in FS and HS !! */
+	
+	/* 
+	 * skip_frames is used to limit activated descriptors number
+	 * to avoid the situation when HC services the last activated
+	 * descriptor firstly.
+	 * Example for FS:
+	 * Current frame is 1, scheduled frame is 3. Since HC always fetches the descriptor
+	 * corresponding to curr_frame+1, the descriptor corresponding to frame 2
+	 * will be fetched. If the number of descriptors is max=64 (or greather) the
+	 * list will be fully programmed with Active descriptors and it is possible
+	 * case(rare) that the latest descriptor(considering rollback) corresponding
+	 * to frame 2 will be serviced first. HS case is more probable because, in fact,
+	 * up to 11 uframes(16 in the code) may be skipped.
+	 */
+	if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) {
+		/* 
+		 * Consider uframe counter also, to start xfer asap.
+		 * If half of the frame elapsed skip 2 frames otherwise
+		 * just 1 frame. 
+		 * Starting descriptor index must be 8-aligned, so
+		 * if the current frame is near to complete the next one
+		 * is skipped as well.
+		 */
+
+		if (dwc_micro_frame_num(hcd->frame_number) >= 5) {
+			*skip_frames = 2 * 8;
+		 	frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames);
+		} else {
+			*skip_frames = 1 * 8;
+			frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames);
+		}
+
+		frame = dwc_full_frame_num(frame);
+	} else {
+		/* 
+		 * Two frames are skipped for FS - the current and the next.
+		 * But for descriptor programming, 1 frame(descriptor) is enough,
+		 * see example above.
+		 */
+		*skip_frames = 1;
+		frame = dwc_frame_num_inc(hcd->frame_number, 2);
+	}
+
+	return frame;
+}
+
+/* 
+ * Calculate initial descriptor index for isochronous transfer
+ * based on scheduled frame. 
+ */
+static uint8_t recalc_initial_desc_idx(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+{
+	uint16_t frame = 0, fr_idx, fr_idx_tmp;
+	uint8_t skip_frames = 0;
+	/* 
+	 * With current ISOC processing algorithm the channel is being
+	 * released when no more QTDs in the list(qh->ntd == 0).
+	 * Thus this function is called only when qh->ntd == 0 and qh->channel == 0. 
+	 *
+	 * So qh->channel != NULL branch is not used and just not removed from the
+	 * source file. It is required for another possible approach which is,
+	 * do not disable and release the channel when ISOC session completed, 
+	 * just move QH to inactive schedule until new QTD arrives. 
+	 * On new QTD, the QH moved back to 'ready' schedule,
+	 * starting frame and therefore starting desc_index are recalculated.
+	 * In this case channel is released only on ep_disable.
+	 */
+
+	/* Calculate starting descriptor index. For INTERRUPT endpoint it is always 0. */
+	if (qh->channel) {
+		frame = calc_starting_frame(hcd, qh, &skip_frames);
+		/* 
+		 * Calculate initial descriptor index based on FrameList current bitmap
+		 * and servicing period.
+		 */
+		fr_idx_tmp = frame_list_idx(frame);
+		fr_idx =
+		    (MAX_FRLIST_EN_NUM + frame_list_idx(qh->sched_frame) -
+		     fr_idx_tmp)
+		    % frame_incr_val(qh);
+		fr_idx = (fr_idx + fr_idx_tmp) % MAX_FRLIST_EN_NUM;
+	} else {
+		qh->sched_frame = calc_starting_frame(hcd, qh, &skip_frames);
+		fr_idx = frame_list_idx(qh->sched_frame);
+	}
+
+	qh->td_first = qh->td_last = frame_to_desc_idx(qh, fr_idx);
+
+	return skip_frames;
+}
+
+#define	ISOC_URB_GIVEBACK_ASAP
+
+#define MAX_ISOC_XFER_SIZE_FS 1023
+#define MAX_ISOC_XFER_SIZE_HS 3072
+#define DESCNUM_THRESHOLD 4
+
+static void init_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
+			       uint8_t skip_frames)
+{
+	struct dwc_otg_hcd_iso_packet_desc *frame_desc;
+	dwc_otg_qtd_t *qtd;
+	dwc_otg_host_dma_desc_t *dma_desc;
+	uint16_t idx, inc, n_desc, ntd_max, max_xfer_size;
+
+	idx = qh->td_last;
+	inc = qh->interval;
+	n_desc = 0;
+
+	ntd_max = (max_desc_num(qh) + qh->interval - 1) / qh->interval;
+	if (skip_frames && !qh->channel)
+		ntd_max = ntd_max - skip_frames / qh->interval;
+
+	max_xfer_size =
+	    (qh->dev_speed ==
+	     DWC_OTG_EP_SPEED_HIGH) ? MAX_ISOC_XFER_SIZE_HS :
+	    MAX_ISOC_XFER_SIZE_FS;
+
+	DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) {
+		while ((qh->ntd < ntd_max)
+		       && (qtd->isoc_frame_index_last <
+			   qtd->urb->packet_count)) {
+
+			dma_desc = &qh->desc_list[idx];
+			dwc_memset(dma_desc, 0x00, sizeof(dwc_otg_host_dma_desc_t));
+
+			frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
+
+			if (frame_desc->length > max_xfer_size)
+				qh->n_bytes[idx] = max_xfer_size;
+			else
+				qh->n_bytes[idx] = frame_desc->length;
+			dma_desc->status.b_isoc.n_bytes = qh->n_bytes[idx];
+			dma_desc->status.b_isoc.a = 1;
+			dma_desc->status.b_isoc.sts = 0;
+
+			dma_desc->buf = qtd->urb->dma + frame_desc->offset;
+
+			qh->ntd++;
+
+			qtd->isoc_frame_index_last++;
+
+#ifdef	ISOC_URB_GIVEBACK_ASAP
+			/* 
+			 * Set IOC for each descriptor corresponding to the 
+			 * last frame of the URB.
+			 */
+			if (qtd->isoc_frame_index_last ==
+			    qtd->urb->packet_count)
+				dma_desc->status.b_isoc.ioc = 1;
+
+#endif
+			idx = desclist_idx_inc(idx, inc, qh->dev_speed);
+			n_desc++;
+
+		}
+		qtd->in_process = 1;
+	}
+
+	qh->td_last = idx;
+
+#ifdef	ISOC_URB_GIVEBACK_ASAP
+	/* Set IOC for the last descriptor if descriptor list is full */
+	if (qh->ntd == ntd_max) {
+		idx = desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
+		qh->desc_list[idx].status.b_isoc.ioc = 1;
+	}
+#else
+	/* 
+	 * Set IOC bit only for one descriptor. 
+	 * Always try to be ahead of HW processing,
+	 * i.e. on IOC generation driver activates next descriptors but
+	 * core continues to process descriptors followed the one with IOC set.
+	 */
+
+	if (n_desc > DESCNUM_THRESHOLD) {
+		/* 
+		 * Move IOC "up". Required even if there is only one QTD 
+		 * in the list, cause QTDs migth continue to be queued,
+		 * but during the activation it was only one queued.
+		 * Actually more than one QTD might be in the list if this function called 
+		 * from XferCompletion - QTDs was queued during HW processing of the previous
+		 * descriptor chunk.
+		 */
+		idx = dwc_desclist_idx_dec(idx, inc * ((qh->ntd + 1) / 2), qh->dev_speed);
+	} else {
+		/* 
+		 * Set the IOC for the latest descriptor
+		 * if either number of descriptor is not greather than threshold
+		 * or no more new descriptors activated.
+		 */
+		idx = dwc_desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
+	}
+
+	qh->desc_list[idx].status.b_isoc.ioc = 1;
+#endif
+}
+
+static void init_non_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+{
+
+	dwc_hc_t *hc;
+	dwc_otg_host_dma_desc_t *dma_desc;
+	dwc_otg_qtd_t *qtd;
+	int num_packets, len, n_desc = 0;
+
+	hc = qh->channel;
+
+	/* 
+	 * Start with hc->xfer_buff initialized in 
+	 * assign_and_init_hc(), then if SG transfer consists of multiple URBs,
+	 * this pointer re-assigned to the buffer of the currently processed QTD.
+	 * For non-SG request there is always one QTD active.
+	 */
+
+	DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) {
+
+		if (n_desc) {
+			/* SG request - more than 1 QTDs */
+	 		hc->xfer_buff = (uint8_t *)qtd->urb->dma + qtd->urb->actual_length;
+			hc->xfer_len = qtd->urb->length - qtd->urb->actual_length;
+		}
+
+		qtd->n_desc = 0;
+
+		do {
+			dma_desc = &qh->desc_list[n_desc];
+			len = hc->xfer_len;
+
+			if (len > MAX_DMA_DESC_SIZE)
+				len = MAX_DMA_DESC_SIZE - hc->max_packet + 1;
+
+			if (hc->ep_is_in) {
+				if (len > 0) {
+					num_packets = (len + hc->max_packet - 1) / hc->max_packet;
+				} else {
+					/* Need 1 packet for transfer length of 0. */
+					num_packets = 1;
+				}
+				/* Always program an integral # of max packets for IN transfers. */
+				len = num_packets * hc->max_packet;
+			}
+
+			dma_desc->status.b.n_bytes = len;
+
+			qh->n_bytes[n_desc] = len;
+
+			if ((qh->ep_type == UE_CONTROL)
+			    && (qtd->control_phase == DWC_OTG_CONTROL_SETUP))
+				dma_desc->status.b.sup = 1;	/* Setup Packet */
+
+			dma_desc->status.b.a = 1;	/* Active descriptor */
+			dma_desc->status.b.sts = 0;
+
+			dma_desc->buf =
+			    ((unsigned long)hc->xfer_buff & 0xffffffff);
+
+			/* 
+			 * Last descriptor(or single) of IN transfer 
+			 * with actual size less than MaxPacket.
+			 */
+			if (len > hc->xfer_len) {
+				hc->xfer_len = 0;
+			} else {
+				hc->xfer_buff += len;
+				hc->xfer_len -= len;
+			}
+
+			qtd->n_desc++;
+			n_desc++;
+		}
+		while ((hc->xfer_len > 0) && (n_desc != MAX_DMA_DESC_NUM_GENERIC));
+		
+
+		qtd->in_process = 1;
+
+		if (qh->ep_type == UE_CONTROL)
+			break;
+
+		if (n_desc == MAX_DMA_DESC_NUM_GENERIC)
+			break;
+	}
+
+	if (n_desc) {
+		/* Request Transfer Complete interrupt for the last descriptor */
+		qh->desc_list[n_desc - 1].status.b.ioc = 1;
+		/* End of List indicator */
+		qh->desc_list[n_desc - 1].status.b.eol = 1;
+
+		hc->ntd = n_desc;
+	}
+}
+
+/** 
+ * For Control and Bulk endpoints initializes descriptor list
+ * and starts the transfer.
+ *
+ * For Interrupt and Isochronous endpoints initializes descriptor list
+ * then updates FrameList, marking appropriate entries as active.
+ * In case of Isochronous, the starting descriptor index is calculated based
+ * on the scheduled frame, but only on the first transfer descriptor within a session.
+ * Then starts the transfer via enabling the channel. 
+ * For Isochronous endpoint the channel is not halted on XferComplete 
+ * interrupt so remains assigned to the endpoint(QH) until session is done.
+ *
+ * @param hcd The HCD state structure for the DWC OTG controller.
+ * @param qh The QH to init.
+ *
+ * @return 0 if successful, negative error code otherwise.
+ */
+void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+{
+	/* Channel is already assigned */
+	dwc_hc_t *hc = qh->channel;
+	uint8_t skip_frames = 0;
+
+	switch (hc->ep_type) {
+	case DWC_OTG_EP_TYPE_CONTROL:
+	case DWC_OTG_EP_TYPE_BULK:
+		init_non_isoc_dma_desc(hcd, qh);
+
+		dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
+		break;
+	case DWC_OTG_EP_TYPE_INTR:
+		init_non_isoc_dma_desc(hcd, qh);
+
+		update_frame_list(hcd, qh, 1);
+
+		dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
+		break;
+	case DWC_OTG_EP_TYPE_ISOC:
+
+		if (!qh->ntd)
+			skip_frames = recalc_initial_desc_idx(hcd, qh);
+
+		init_isoc_dma_desc(hcd, qh, skip_frames);
+
+		if (!hc->xfer_started) {
+
+			update_frame_list(hcd, qh, 1);
+
+			/* 
+			 * Always set to max, instead of actual size.
+			 * Otherwise ntd will be changed with 
+			 * channel being enabled. Not recommended.
+			 *
+			 */
+			hc->ntd = max_desc_num(qh);
+			/* Enable channel only once for ISOC */
+			dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
+		}
+
+		break;
+	default:
+
+		break;
+	}
+}
+
+static void complete_isoc_xfer_ddma(dwc_otg_hcd_t * hcd,
+				    dwc_hc_t * hc,
+				    dwc_otg_hc_regs_t * hc_regs,
+				    dwc_otg_halt_status_e halt_status)
+{
+	struct dwc_otg_hcd_iso_packet_desc *frame_desc;
+	dwc_otg_qtd_t *qtd, *qtd_tmp;
+	dwc_otg_qh_t *qh;
+	dwc_otg_host_dma_desc_t *dma_desc;
+	uint16_t idx, remain;
+	uint8_t urb_compl;
+
+	qh = hc->qh;
+	idx = qh->td_first;
+
+	if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
+		DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry)
+		    qtd->in_process = 0;
+		return;
+	} else if ((halt_status == DWC_OTG_HC_XFER_AHB_ERR) ||
+		   (halt_status == DWC_OTG_HC_XFER_BABBLE_ERR)) {
+		/* 
+		 * Channel is halted in these error cases.
+		 * Considered as serious issues.
+		 * Complete all URBs marking all frames as failed, 
+		 * irrespective whether some of the descriptors(frames) succeeded or no.
+		 * Pass error code to completion routine as well, to
+		 * update urb->status, some of class drivers might use it to stop
+		 * queing transfer requests.
+		 */
+		int err = (halt_status == DWC_OTG_HC_XFER_AHB_ERR)
+		    ? (-DWC_E_IO)
+		    : (-DWC_E_OVERFLOW);
+						
+		DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
+			for (idx = 0; idx < qtd->urb->packet_count; idx++) {
+				frame_desc = &qtd->urb->iso_descs[idx];
+				frame_desc->status = err;
+			}
+			hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, err);
+			dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
+		}
+		return;
+	}
+
+	DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
+
+		if (!qtd->in_process)
+			break;
+
+		urb_compl = 0;
+
+		do {
+
+			dma_desc = &qh->desc_list[idx];
+			
+			frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
+			remain = hc->ep_is_in ? dma_desc->status.b_isoc.n_bytes : 0;
+
+			if (dma_desc->status.b_isoc.sts == DMA_DESC_STS_PKTERR) {
+				/* 
+				 * XactError or, unable to complete all the transactions 
+				 * in the scheduled micro-frame/frame, 
+				 * both indicated by DMA_DESC_STS_PKTERR.
+				 */
+				qtd->urb->error_count++;
+				frame_desc->actual_length = qh->n_bytes[idx] - remain;
+				frame_desc->status = -DWC_E_PROTOCOL;
+			} else {
+				/* Success */
+								
+				frame_desc->actual_length = qh->n_bytes[idx] - remain;
+				frame_desc->status = 0;
+			}
+
+			if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
+				/*
+				 * urb->status is not used for isoc transfers here.
+				 * The individual frame_desc status are used instead.
+				 */
+
+				hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
+				dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
+
+				/* 
+				 * This check is necessary because urb_dequeue can be called 
+				 * from urb complete callback(sound driver example).
+				 * All pending URBs are dequeued there, so no need for
+				 * further processing.
+				 */
+				if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {	
+					return;
+				}
+
+				urb_compl = 1;
+
+			}
+
+			qh->ntd--;
+
+			/* Stop if IOC requested descriptor reached */
+			if (dma_desc->status.b_isoc.ioc) {
+				idx = desclist_idx_inc(idx, qh->interval, hc->speed);	
+				goto stop_scan;
+			}
+
+			idx = desclist_idx_inc(idx, qh->interval, hc->speed);
+
+			if (urb_compl)
+				break;
+		}
+		while (idx != qh->td_first);
+	}
+stop_scan:
+	qh->td_first = idx;
+}
+
+uint8_t update_non_isoc_urb_state_ddma(dwc_otg_hcd_t * hcd,
+				       dwc_hc_t * hc,
+				       dwc_otg_qtd_t * qtd,
+				       dwc_otg_host_dma_desc_t * dma_desc,
+				       dwc_otg_halt_status_e halt_status,
+				       uint32_t n_bytes, uint8_t * xfer_done)
+{
+
+	uint16_t remain = hc->ep_is_in ? dma_desc->status.b.n_bytes : 0;
+	dwc_otg_hcd_urb_t *urb = qtd->urb;
+
+	if (halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
+		urb->status = -DWC_E_IO;
+		return 1;
+	}
+	if (dma_desc->status.b.sts == DMA_DESC_STS_PKTERR) {
+		switch (halt_status) {
+		case DWC_OTG_HC_XFER_STALL:
+			urb->status = -DWC_E_PIPE;
+			break;
+		case DWC_OTG_HC_XFER_BABBLE_ERR:
+			urb->status = -DWC_E_OVERFLOW;
+			break;
+		case DWC_OTG_HC_XFER_XACT_ERR:
+			urb->status = -DWC_E_PROTOCOL;
+			break;
+		default:	
+			DWC_ERROR("%s: Unhandled descriptor error status (%d)\n", __func__,
+			  	  halt_status);
+			break;
+		}
+		return 1;
+	}
+
+	if (dma_desc->status.b.a == 1) {
+		DWC_DEBUGPL(DBG_HCDV,
+			    "Active descriptor encountered on channel %d\n",
+			    hc->hc_num);
+		return 0;
+	}
+
+	if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL) {
+		if (qtd->control_phase == DWC_OTG_CONTROL_DATA) {
+			urb->actual_length += n_bytes - remain;
+			if (remain || urb->actual_length == urb->length) {
+				/* 
+				 * For Control Data stage do not set urb->status=0 to prevent
+				 * URB callback. Set it when Status phase done. See below.
+				 */
+				*xfer_done = 1;
+			}
+
+		} else if (qtd->control_phase == DWC_OTG_CONTROL_STATUS) {
+			urb->status = 0;
+			*xfer_done = 1;
+		}
+		/* No handling for SETUP stage */
+	} else {
+		/* BULK and INTR */
+		urb->actual_length += n_bytes - remain;
+		if (remain || urb->actual_length == urb->length) {
+			urb->status = 0;
+			*xfer_done = 1;
+		}
+	}
+
+	return 0;
+}
+
+static void complete_non_isoc_xfer_ddma(dwc_otg_hcd_t * hcd,
+					dwc_hc_t * hc,
+					dwc_otg_hc_regs_t * hc_regs,
+					dwc_otg_halt_status_e halt_status)
+{
+	dwc_otg_hcd_urb_t *urb = NULL;
+	dwc_otg_qtd_t *qtd, *qtd_tmp;
+	dwc_otg_qh_t *qh;
+	dwc_otg_host_dma_desc_t *dma_desc;
+	uint32_t n_bytes, n_desc, i;
+	uint8_t failed = 0, xfer_done;
+
+	n_desc = 0;
+
+	qh = hc->qh;
+
+	if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
+		DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
+			qtd->in_process = 0;
+		}
+		return;
+	}
+
+	DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
+
+		urb = qtd->urb;
+
+		n_bytes = 0;
+		xfer_done = 0;
+
+		for (i = 0; i < qtd->n_desc; i++) {
+			dma_desc = &qh->desc_list[n_desc];
+
+			n_bytes = qh->n_bytes[n_desc];
+
+			failed =
+			    update_non_isoc_urb_state_ddma(hcd, hc, qtd,
+							   dma_desc,
+							   halt_status, n_bytes,
+							   &xfer_done);
+
+			if (failed
+			    || (xfer_done
+				&& (urb->status != -DWC_E_IN_PROGRESS))) {
+
+				hcd->fops->complete(hcd, urb->priv, urb,
+						    urb->status);
+				dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
+
+				if (failed)
+					goto stop_scan;
+			} else if (qh->ep_type == UE_CONTROL) {
+				if (qtd->control_phase == DWC_OTG_CONTROL_SETUP) {
+					if (urb->length > 0) {
+						qtd->control_phase = DWC_OTG_CONTROL_DATA;
+					} else {
+						qtd->control_phase = DWC_OTG_CONTROL_STATUS;
+					}
+					DWC_DEBUGPL(DBG_HCDV, "  Control setup transaction done\n");
+				} else if (qtd->control_phase == DWC_OTG_CONTROL_DATA) {
+					if (xfer_done) {
+						qtd->control_phase = DWC_OTG_CONTROL_STATUS;
+						DWC_DEBUGPL(DBG_HCDV, "  Control data transfer done\n");
+					} else if (i + 1 == qtd->n_desc) {
+						/* 
+						 * Last descriptor for Control data stage which is
+						 * not completed yet.
+						 */
+						dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
+					}
+				}
+			}
+
+			n_desc++;
+		}
+
+	}
+
+stop_scan:
+
+	if (qh->ep_type != UE_CONTROL) {
+		/* 
+		 * Resetting the data toggle for bulk
+		 * and interrupt endpoints in case of stall. See handle_hc_stall_intr() 
+		 */
+		if (halt_status == DWC_OTG_HC_XFER_STALL)
+			qh->data_toggle = DWC_OTG_HC_PID_DATA0;
+		else
+			dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
+	}
+
+	if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
+		hcint_data_t hcint;
+		hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
+		if (hcint.b.nyet) {
+			/*
+			 * Got a NYET on the last transaction of the transfer. It
+			 * means that the endpoint should be in the PING state at the
+			 * beginning of the next transfer.
+			 */
+			qh->ping_state = 1;
+			clear_hc_int(hc_regs, nyet);
+		}
+
+	}
+
+}
+
+/**
+ * This function is called from interrupt handlers.
+ * Scans the descriptor list, updates URB's status and
+ * calls completion routine for the URB if it's done.
+ * Releases the channel to be used by other transfers.
+ * In case of Isochronous endpoint the channel is not halted until 
+ * the end of the session, i.e. QTD list is empty.
+ * If periodic channel released the FrameList is updated accordingly.
+ *
+ * Calls transaction selection routines to activate pending transfers.
+ *
+ * @param hcd The HCD state structure for the DWC OTG controller.
+ * @param hc Host channel, the transfer is completed on.
+ * @param hc_regs Host channel registers.
+ * @param halt_status Reason the channel is being halted, 
+ *		      or just XferComplete for isochronous transfer
+ */
+void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t * hcd,
+				    dwc_hc_t * hc,
+				    dwc_otg_hc_regs_t * hc_regs,
+				    dwc_otg_halt_status_e halt_status)
+{
+	uint8_t continue_isoc_xfer = 0;
+	dwc_otg_transaction_type_e tr_type;
+	dwc_otg_qh_t *qh = hc->qh;
+
+	if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
+
+		complete_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status);
+
+		/* Release the channel if halted or session completed */
+		if (halt_status != DWC_OTG_HC_XFER_COMPLETE ||
+		    DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
+
+			/* Halt the channel if session completed */
+			if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
+				dwc_otg_hc_halt(hcd->core_if, hc, halt_status);
+			}
+
+			release_channel_ddma(hcd, qh);
+			dwc_otg_hcd_qh_remove(hcd, qh);
+		} else {
+			/* Keep in assigned schedule to continue transfer */
+			DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
+					   &qh->qh_list_entry);
+			continue_isoc_xfer = 1;
+
+		}
+		/** @todo Consider the case when period exceeds FrameList size.
+		 *  Frame Rollover interrupt should be used. 
+		 */
+	} else {
+		/* Scan descriptor list to complete the URB(s), then release the channel */
+		complete_non_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status);
+
+		release_channel_ddma(hcd, qh);
+		dwc_otg_hcd_qh_remove(hcd, qh);
+
+		if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
+			/* Add back to inactive non-periodic schedule on normal completion */
+			dwc_otg_hcd_qh_add(hcd, qh);
+		}
+
+	}
+	tr_type = dwc_otg_hcd_select_transactions(hcd);
+	if (tr_type != DWC_OTG_TRANSACTION_NONE || continue_isoc_xfer) {
+		if (continue_isoc_xfer) {
+			if (tr_type == DWC_OTG_TRANSACTION_NONE) {
+				tr_type = DWC_OTG_TRANSACTION_PERIODIC;
+			} else if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC) {
+				tr_type = DWC_OTG_TRANSACTION_ALL;
+			}
+		}
+		dwc_otg_hcd_queue_transactions(hcd, tr_type);
+	}
+}
+
+#endif /* DWC_DEVICE_ONLY */
diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd_if.h b/drivers/usb/dwc_otg/dwc_otg_hcd_if.h
new file mode 100644
index 0000000..b3dc806
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_hcd_if.h
@@ -0,0 +1,412 @@
+/* ==========================================================================
+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_if.h $
+ * $Revision: #12 $
+ * $Date: 2011/10/26 $
+ * $Change: 1873028 $
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+#ifndef DWC_DEVICE_ONLY
+#ifndef __DWC_HCD_IF_H__
+#define __DWC_HCD_IF_H__
+
+#include "dwc_otg_core_if.h"
+
+/** @file
+ * This file defines DWC_OTG HCD Core API.
+ */
+
+struct dwc_otg_hcd;
+typedef struct dwc_otg_hcd dwc_otg_hcd_t;
+
+struct dwc_otg_hcd_urb;
+typedef struct dwc_otg_hcd_urb dwc_otg_hcd_urb_t;
+
+/** @name HCD Function Driver Callbacks */
+/** @{ */
+
+/** This function is called whenever core switches to host mode. */
+typedef int (*dwc_otg_hcd_start_cb_t) (dwc_otg_hcd_t * hcd);
+
+/** This function is called when device has been disconnected */
+typedef int (*dwc_otg_hcd_disconnect_cb_t) (dwc_otg_hcd_t * hcd);
+
+/** Wrapper provides this function to HCD to core, so it can get hub information to which device is connected */
+typedef int (*dwc_otg_hcd_hub_info_from_urb_cb_t) (dwc_otg_hcd_t * hcd,
+						   void *urb_handle,
+						   uint32_t * hub_addr,
+						   uint32_t * port_addr);
+/** Via this function HCD core gets device speed */
+typedef int (*dwc_otg_hcd_speed_from_urb_cb_t) (dwc_otg_hcd_t * hcd,
+						void *urb_handle);
+
+/** This function is called when urb is completed */
+typedef int (*dwc_otg_hcd_complete_urb_cb_t) (dwc_otg_hcd_t * hcd,
+					      void *urb_handle,
+					      dwc_otg_hcd_urb_t * dwc_otg_urb,
+					      int32_t status);
+
+/** Via this function HCD core gets b_hnp_enable parameter */
+typedef int (*dwc_otg_hcd_get_b_hnp_enable) (dwc_otg_hcd_t * hcd);
+
+struct dwc_otg_hcd_function_ops {
+	dwc_otg_hcd_start_cb_t start;
+	dwc_otg_hcd_disconnect_cb_t disconnect;
+	dwc_otg_hcd_hub_info_from_urb_cb_t hub_info;
+	dwc_otg_hcd_speed_from_urb_cb_t speed;
+	dwc_otg_hcd_complete_urb_cb_t complete;
+	dwc_otg_hcd_get_b_hnp_enable get_b_hnp_enable;
+};
+/** @} */
+
+/** @name HCD Core API */
+/** @{ */
+/** This function allocates dwc_otg_hcd structure and returns pointer on it. */
+extern dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void);
+
+/** This function should be called to initiate HCD Core.
+ *
+ * @param hcd The HCD
+ * @param core_if The DWC_OTG Core
+ *
+ * Returns -DWC_E_NO_MEMORY if no enough memory.
+ * Returns 0 on success  
+ */
+extern int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if);
+
+/** Frees HCD
+ *
+ * @param hcd The HCD
+ */
+extern void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd);
+
+/** This function should be called on every hardware interrupt.
+ *
+ * @param dwc_otg_hcd The HCD
+ *
+ * Returns non zero if interrupt is handled
+ * Return 0 if interrupt is not handled
+ */
+extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd);
+
+/**
+ * Returns private data set by
+ * dwc_otg_hcd_set_priv_data function.
+ *
+ * @param hcd The HCD
+ */
+extern void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd);
+
+/**
+ * Set private data.
+ *
+ * @param hcd The HCD
+ * @param priv_data pointer to be stored in private data
+ */
+extern void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data);
+
+/**
+ * This function initializes the HCD Core.
+ *
+ * @param hcd The HCD
+ * @param fops The Function Driver Operations data structure containing pointers to all callbacks.
+ *
+ * Returns -DWC_E_NO_DEVICE if Core is currently is in device mode.
+ * Returns 0 on success
+ */
+extern int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd,
+			     struct dwc_otg_hcd_function_ops *fops);
+
+/**
+ * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
+ * stopped. 
+ *
+ * @param hcd The HCD
+ */
+extern void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd);
+
+/**
+ * Handles hub class-specific requests.
+ *
+ * @param dwc_otg_hcd The HCD
+ * @param typeReq Request Type
+ * @param wValue wValue from control request
+ * @param wIndex wIndex from control request
+ * @param buf data buffer 
+ * @param wLength data buffer length
+ *
+ * Returns -DWC_E_INVALID if invalid argument is passed
+ * Returns 0 on success
+ */
+extern int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd,
+				   uint16_t typeReq, uint16_t wValue,
+				   uint16_t wIndex, uint8_t * buf,
+				   uint16_t wLength);
+
+/**
+ * Returns otg port number.
+ *
+ * @param hcd The HCD
+ */
+extern uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd);
+
+/**
+ * Returns OTG version - either 1.3 or 2.0.
+ *
+ * @param core_if The core_if structure pointer
+ */
+extern uint16_t dwc_otg_get_otg_version(dwc_otg_core_if_t * core_if);
+
+/**
+ * Returns 1 if currently core is acting as B host, and 0 otherwise.
+ *
+ * @param hcd The HCD
+ */
+extern uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd);
+
+/**
+ * Returns current frame number.
+ *
+ * @param hcd The HCD
+ */
+extern int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * hcd);
+
+/**
+ * Dumps hcd state.
+ *
+ * @param hcd The HCD
+ */
+extern void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd);
+
+/**
+ * Dump the average frame remaining at SOF. This can be used to
+ * determine average interrupt latency. Frame remaining is also shown for
+ * start transfer and two additional sample points.
+ * Currently this function is not implemented.
+ *
+ * @param hcd The HCD
+ */
+extern void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd);
+
+/**
+ * Sends LPM transaction to the local device.
+ *
+ * @param hcd The HCD
+ * @param devaddr Device Address
+ * @param hird Host initiated resume duration
+ * @param bRemoteWake Value of bRemoteWake field in LPM transaction
+ *
+ * Returns negative value if sending LPM transaction was not succeeded.
+ * Returns 0 on success.
+ */
+extern int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr,
+				uint8_t hird, uint8_t bRemoteWake);
+
+/* URB interface */
+
+/**
+ * Allocates memory for dwc_otg_hcd_urb structure.
+ * Allocated memory should be freed by call of DWC_FREE.
+ *
+ * @param hcd The HCD
+ * @param iso_desc_count Count of ISOC descriptors
+ * @param atomic_alloc Specefies whether to perform atomic allocation.
+ */
+extern dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd,
+						int iso_desc_count,
+						int atomic_alloc);
+
+/**
+ * Set pipe information in URB.
+ *
+ * @param hcd_urb DWC_OTG URB
+ * @param devaddr Device Address
+ * @param ep_num Endpoint Number
+ * @param ep_type Endpoint Type
+ * @param ep_dir Endpoint Direction
+ * @param mps Max Packet Size
+ */
+extern void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * hcd_urb,
+					 uint8_t devaddr, uint8_t ep_num,
+					 uint8_t ep_type, uint8_t ep_dir,
+					 uint16_t mps);
+
+/* Transfer flags */
+#define URB_GIVEBACK_ASAP 0x1
+#define URB_SEND_ZERO_PACKET 0x2
+
+/**
+ * Sets dwc_otg_hcd_urb parameters.
+ *
+ * @param urb DWC_OTG URB allocated by dwc_otg_hcd_urb_alloc function.
+ * @param urb_handle Unique handle for request, this will be passed back
+ * to function driver in completion callback.
+ * @param buf The buffer for the data
+ * @param dma The DMA buffer for the data
+ * @param buflen Transfer length
+ * @param sp Buffer for setup data
+ * @param sp_dma DMA address of setup data buffer
+ * @param flags Transfer flags
+ * @param interval Polling interval for interrupt or isochronous transfers.
+ */
+extern void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * urb,
+				       void *urb_handle, void *buf,
+				       dwc_dma_t dma, uint32_t buflen, void *sp,
+				       dwc_dma_t sp_dma, uint32_t flags,
+				       uint16_t interval);
+
+/** Gets status from dwc_otg_hcd_urb
+ *
+ * @param dwc_otg_urb DWC_OTG URB
+ */
+extern uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb);
+
+/** Gets actual length from dwc_otg_hcd_urb
+ *
+ * @param dwc_otg_urb DWC_OTG URB
+ */
+extern uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t *
+						  dwc_otg_urb);
+
+/** Gets error count from dwc_otg_hcd_urb. Only for ISOC URBs
+ *
+ * @param dwc_otg_urb DWC_OTG URB
+ */
+extern uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t *
+						dwc_otg_urb);
+
+/** Set ISOC descriptor offset and length
+ *
+ * @param dwc_otg_urb DWC_OTG URB
+ * @param desc_num ISOC descriptor number
+ * @param offset Offset from beginig of buffer.
+ * @param length Transaction length
+ */
+extern void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
+						int desc_num, uint32_t offset,
+						uint32_t length);
+
+/** Get status of ISOC descriptor, specified by desc_num
+ *
+ * @param dwc_otg_urb DWC_OTG URB
+ * @param desc_num ISOC descriptor number 
+ */
+extern uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t *
+						    dwc_otg_urb, int desc_num);
+
+/** Get actual length of ISOC descriptor, specified by desc_num
+ *
+ * @param dwc_otg_urb DWC_OTG URB
+ * @param desc_num ISOC descriptor number
+ */
+extern uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t *
+							   dwc_otg_urb,
+							   int desc_num);
+
+/** Queue URB. After transfer is completes, the complete callback will be called with the URB status
+ *
+ * @param dwc_otg_hcd The HCD
+ * @param dwc_otg_urb DWC_OTG URB
+ * @param ep_handle Out parameter for returning endpoint handle
+ * @param atomic_alloc Flag to do atomic allocation if needed
+ *
+ * Returns -DWC_E_NO_DEVICE if no device is connected.
+ * Returns -DWC_E_NO_MEMORY if there is no enough memory.
+ * Returns 0 on success.
+ */
+extern int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * dwc_otg_hcd,
+				   dwc_otg_hcd_urb_t * dwc_otg_urb,
+				   void **ep_handle, int atomic_alloc);
+
+/** De-queue the specified URB
+ *
+ * @param dwc_otg_hcd The HCD
+ * @param dwc_otg_urb DWC_OTG URB
+ */
+extern int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * dwc_otg_hcd,
+				   dwc_otg_hcd_urb_t * dwc_otg_urb);
+
+/** Frees resources in the DWC_otg controller related to a given endpoint.
+ * Any URBs for the endpoint must already be dequeued.
+ *
+ * @param hcd The HCD
+ * @param ep_handle Endpoint handle, returned by dwc_otg_hcd_urb_enqueue function
+ * @param retry Number of retries if there are queued transfers.
+ *
+ * Returns -DWC_E_INVALID if invalid arguments are passed.
+ * Returns 0 on success
+ */
+extern int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle,
+					int retry);
+
+/* Resets the data toggle in qh structure. This function can be called from
+ * usb_clear_halt routine.
+ *
+ * @param hcd The HCD
+ * @param ep_handle Endpoint handle, returned by dwc_otg_hcd_urb_enqueue function
+ *
+ * Returns -DWC_E_INVALID if invalid arguments are passed.
+ * Returns 0 on success
+ */
+extern int dwc_otg_hcd_endpoint_reset(dwc_otg_hcd_t * hcd, void *ep_handle);
+
+/** Returns 1 if status of specified port is changed and 0 otherwise.
+ *
+ * @param hcd The HCD
+ * @param port Port number
+ */
+extern int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port);
+
+/** Call this function to check if bandwidth was allocated for specified endpoint.
+ * Only for ISOC and INTERRUPT endpoints.
+ *
+ * @param hcd The HCD
+ * @param ep_handle Endpoint handle
+ */
+extern int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd,
+					      void *ep_handle);
+
+/** Call this function to check if bandwidth was freed for specified endpoint.
+ *
+ * @param hcd The HCD
+ * @param ep_handle Endpoint handle
+ */
+extern int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle);
+
+/** Returns bandwidth allocated for specified endpoint in microseconds.
+ * Only for ISOC and INTERRUPT endpoints.
+ *
+ * @param hcd The HCD
+ * @param ep_handle Endpoint handle
+ */
+extern uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd,
+					    void *ep_handle);
+
+/** @} */
+
+#endif /* __DWC_HCD_IF_H__ */
+#endif /* DWC_DEVICE_ONLY */
diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c
new file mode 100644
index 0000000..9fb3602
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c
@@ -0,0 +1,2101 @@
+/* ==========================================================================
+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_intr.c $
+ * $Revision: #89 $
+ * $Date: 2011/10/20 $
+ * $Change: 1869487 $
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+#ifndef DWC_DEVICE_ONLY
+
+#include "dwc_otg_hcd.h"
+#include "dwc_otg_regs.h"
+
+/** @file
+ * This file contains the implementation of the HCD Interrupt handlers.
+ */
+
+/** This function handles interrupts for the HCD. */
+int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd)
+{
+	int retval = 0;
+
+	dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
+	gintsts_data_t gintsts;
+#ifdef DEBUG
+	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+#endif
+
+	/* Exit from ISR if core is hibernated */
+	if (core_if->hibernation_suspend == 1) {
+		return retval;
+	}
+	DWC_SPINLOCK(dwc_otg_hcd->lock);
+	/* Check if HOST Mode */
+	if (dwc_otg_is_host_mode(core_if)) {
+		gintsts.d32 = dwc_otg_read_core_intr(core_if);
+		if (!gintsts.d32) {
+			DWC_SPINUNLOCK(dwc_otg_hcd->lock);
+			return 0;
+		}
+#ifdef DEBUG
+		/* Don't print debug message in the interrupt handler on SOF */
+#ifndef DEBUG_SOF
+		if (gintsts.d32 != DWC_SOF_INTR_MASK)
+#endif
+			DWC_DEBUGPL(DBG_HCD, "\n");
+#endif
+
+#ifdef DEBUG
+#ifndef DEBUG_SOF
+		if (gintsts.d32 != DWC_SOF_INTR_MASK)
+#endif
+			DWC_DEBUGPL(DBG_HCD,
+				    "DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x\n",
+				    gintsts.d32);
+#endif
+
+		if (gintsts.b.sofintr) {
+			retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd);
+		}
+		if (gintsts.b.rxstsqlvl) {
+			retval |=
+			    dwc_otg_hcd_handle_rx_status_q_level_intr
+			    (dwc_otg_hcd);
+		}
+		if (gintsts.b.nptxfempty) {
+			retval |=
+			    dwc_otg_hcd_handle_np_tx_fifo_empty_intr
+			    (dwc_otg_hcd);
+		}
+		if (gintsts.b.i2cintr) {
+			/** @todo Implement i2cintr handler. */
+		}
+		if (gintsts.b.portintr) {
+			retval |= dwc_otg_hcd_handle_port_intr(dwc_otg_hcd);
+		}
+		if (gintsts.b.hcintr) {
+			retval |= dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd);
+		}
+		if (gintsts.b.ptxfempty) {
+			retval |=
+			    dwc_otg_hcd_handle_perio_tx_fifo_empty_intr
+			    (dwc_otg_hcd);
+		}
+#ifdef DEBUG
+#ifndef DEBUG_SOF
+		if (gintsts.d32 != DWC_SOF_INTR_MASK)
+#endif
+		{
+			DWC_DEBUGPL(DBG_HCD,
+				    "DWC OTG HCD Finished Servicing Interrupts\n");
+			DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintsts=0x%08x\n",
+				    DWC_READ_REG32(&global_regs->gintsts));
+			DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintmsk=0x%08x\n",
+				    DWC_READ_REG32(&global_regs->gintmsk));
+		}
+#endif
+
+#ifdef DEBUG
+#ifndef DEBUG_SOF
+		if (gintsts.d32 != DWC_SOF_INTR_MASK)
+#endif
+			DWC_DEBUGPL(DBG_HCD, "\n");
+#endif
+
+	}
+	DWC_SPINUNLOCK(dwc_otg_hcd->lock);
+	return retval;
+}
+
+#ifdef DWC_TRACK_MISSED_SOFS
+#warning Compiling code to track missed SOFs
+#define FRAME_NUM_ARRAY_SIZE 1000
+/**
+ * This function is for debug only.
+ */
+static inline void track_missed_sofs(uint16_t curr_frame_number)
+{
+	static uint16_t frame_num_array[FRAME_NUM_ARRAY_SIZE];
+	static uint16_t last_frame_num_array[FRAME_NUM_ARRAY_SIZE];
+	static int frame_num_idx = 0;
+	static uint16_t last_frame_num = DWC_HFNUM_MAX_FRNUM;
+	static int dumped_frame_num_array = 0;
+
+	if (frame_num_idx < FRAME_NUM_ARRAY_SIZE) {
+		if (((last_frame_num + 1) & DWC_HFNUM_MAX_FRNUM) !=
+		    curr_frame_number) {
+			frame_num_array[frame_num_idx] = curr_frame_number;
+			last_frame_num_array[frame_num_idx++] = last_frame_num;
+		}
+	} else if (!dumped_frame_num_array) {
+		int i;
+		DWC_PRINTF("Frame     Last Frame\n");
+		DWC_PRINTF("-----     ----------\n");
+		for (i = 0; i < FRAME_NUM_ARRAY_SIZE; i++) {
+			DWC_PRINTF("0x%04x    0x%04x\n",
+				   frame_num_array[i], last_frame_num_array[i]);
+		}
+		dumped_frame_num_array = 1;
+	}
+	last_frame_num = curr_frame_number;
+}
+#endif
+
+/**
+ * Handles the start-of-frame interrupt in host mode. Non-periodic
+ * transactions may be queued to the DWC_otg controller for the current
+ * (micro)frame. Periodic transactions may be queued to the controller for the
+ * next (micro)frame.
+ */
+int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd)
+{
+	hfnum_data_t hfnum;
+	dwc_list_link_t *qh_entry;
+	dwc_otg_qh_t *qh;
+	dwc_otg_transaction_type_e tr_type;
+	gintsts_data_t gintsts = {.d32 = 0 };
+
+	hfnum.d32 =
+	    DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hfnum);
+
+#ifdef DEBUG_SOF
+	DWC_DEBUGPL(DBG_HCD, "--Start of Frame Interrupt--\n");
+#endif
+	hcd->frame_number = hfnum.b.frnum;
+
+#ifdef DEBUG
+	hcd->frrem_accum += hfnum.b.frrem;
+	hcd->frrem_samples++;
+#endif
+
+#ifdef DWC_TRACK_MISSED_SOFS
+	track_missed_sofs(hcd->frame_number);
+#endif
+	/* Determine whether any periodic QHs should be executed. */
+	qh_entry = DWC_LIST_FIRST(&hcd->periodic_sched_inactive);
+	while (qh_entry != &hcd->periodic_sched_inactive) {
+		qh = DWC_LIST_ENTRY(qh_entry, dwc_otg_qh_t, qh_list_entry);
+		qh_entry = qh_entry->next;
+		if (dwc_frame_num_le(qh->sched_frame, hcd->frame_number)) {
+			/*
+			 * Move QH to the ready list to be executed next
+			 * (micro)frame.
+			 */
+			DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
+					   &qh->qh_list_entry);
+		}
+	}
+	tr_type = dwc_otg_hcd_select_transactions(hcd);
+	if (tr_type != DWC_OTG_TRANSACTION_NONE) {
+		dwc_otg_hcd_queue_transactions(hcd, tr_type);
+	}
+
+	/* Clear interrupt */
+	gintsts.b.sofintr = 1;
+	DWC_WRITE_REG32(&hcd->core_if->core_global_regs->gintsts, gintsts.d32);
+
+	return 1;
+}
+
+/** Handles the Rx Status Queue Level Interrupt, which indicates that there is at
+ * least one packet in the Rx FIFO.  The packets are moved from the FIFO to
+ * memory if the DWC_otg controller is operating in Slave mode. */
+int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t * dwc_otg_hcd)
+{
+	host_grxsts_data_t grxsts;
+	dwc_hc_t *hc = NULL;
+
+	DWC_DEBUGPL(DBG_HCD, "--RxStsQ Level Interrupt--\n");
+
+	grxsts.d32 =
+	    DWC_READ_REG32(&dwc_otg_hcd->core_if->core_global_regs->grxstsp);
+
+	hc = dwc_otg_hcd->hc_ptr_array[grxsts.b.chnum];
+	if (!hc) {
+		DWC_ERROR("Unable to get corresponding channel\n");
+		return 0;
+	}
+
+	/* Packet Status */
+	DWC_DEBUGPL(DBG_HCDV, "    Ch num = %d\n", grxsts.b.chnum);
+	DWC_DEBUGPL(DBG_HCDV, "    Count = %d\n", grxsts.b.bcnt);
+	DWC_DEBUGPL(DBG_HCDV, "    DPID = %d, hc.dpid = %d\n", grxsts.b.dpid,
+		    hc->data_pid_start);
+	DWC_DEBUGPL(DBG_HCDV, "    PStatus = %d\n", grxsts.b.pktsts);
+
+	switch (grxsts.b.pktsts) {
+	case DWC_GRXSTS_PKTSTS_IN:
+		/* Read the data into the host buffer. */
+		if (grxsts.b.bcnt > 0) {
+			dwc_otg_read_packet(dwc_otg_hcd->core_if,
+					    hc->xfer_buff, grxsts.b.bcnt);
+
+			/* Update the HC fields for the next packet received. */
+			hc->xfer_count += grxsts.b.bcnt;
+			hc->xfer_buff += grxsts.b.bcnt;
+		}
+
+	case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
+	case DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR:
+	case DWC_GRXSTS_PKTSTS_CH_HALTED:
+		/* Handled in interrupt, just ignore data */
+		break;
+	default:
+		DWC_ERROR("RX_STS_Q Interrupt: Unknown status %d\n",
+			  grxsts.b.pktsts);
+		break;
+	}
+
+	return 1;
+}
+
+/** This interrupt occurs when the non-periodic Tx FIFO is half-empty. More
+ * data packets may be written to the FIFO for OUT transfers. More requests
+ * may be written to the non-periodic request queue for IN transfers. This
+ * interrupt is enabled only in Slave mode. */
+int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t * dwc_otg_hcd)
+{
+	DWC_DEBUGPL(DBG_HCD, "--Non-Periodic TxFIFO Empty Interrupt--\n");
+	dwc_otg_hcd_queue_transactions(dwc_otg_hcd,
+				       DWC_OTG_TRANSACTION_NON_PERIODIC);
+	return 1;
+}
+
+/** This interrupt occurs when the periodic Tx FIFO is half-empty. More data
+ * packets may be written to the FIFO for OUT transfers. More requests may be
+ * written to the periodic request queue for IN transfers. This interrupt is
+ * enabled only in Slave mode. */
+int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(dwc_otg_hcd_t * dwc_otg_hcd)
+{
+	DWC_DEBUGPL(DBG_HCD, "--Periodic TxFIFO Empty Interrupt--\n");
+	dwc_otg_hcd_queue_transactions(dwc_otg_hcd,
+				       DWC_OTG_TRANSACTION_PERIODIC);
+	return 1;
+}
+
+/** There are multiple conditions that can cause a port interrupt. This function
+ * determines which interrupt conditions have occurred and handles them
+ * appropriately. */
+int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd)
+{
+	int retval = 0;
+	hprt0_data_t hprt0;
+	hprt0_data_t hprt0_modify;
+
+	hprt0.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
+	hprt0_modify.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
+
+	/* Clear appropriate bits in HPRT0 to clear the interrupt bit in
+	 * GINTSTS */
+
+	hprt0_modify.b.prtena = 0;
+	hprt0_modify.b.prtconndet = 0;
+	hprt0_modify.b.prtenchng = 0;
+	hprt0_modify.b.prtovrcurrchng = 0;
+
+	/* Port Connect Detected
+	 * Set flag and clear if detected */
+	if (dwc_otg_hcd->core_if->hibernation_suspend == 1) {
+		// Dont modify port status if we are in hibernation state
+		hprt0_modify.b.prtconndet = 1;
+		hprt0_modify.b.prtenchng = 1;
+		DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0_modify.d32);
+		hprt0.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
+		return retval;
+	}
+
+	if (hprt0.b.prtconndet) {
+		/** @todo - check if steps performed in 'else' block should be perfromed regardles adp */
+		if (dwc_otg_hcd->core_if->adp_enable &&
+				dwc_otg_hcd->core_if->adp.vbuson_timer_started == 1) {
+			DWC_PRINTF("PORT CONNECT DETECTED ----------------\n");
+			DWC_TIMER_CANCEL(dwc_otg_hcd->core_if->adp.vbuson_timer);
+			dwc_otg_hcd->core_if->adp.vbuson_timer_started = 0;
+			/* TODO - check if this is required, as
+			 * host initialization was already performed
+			 * after initial ADP probing
+			 */
+			/*dwc_otg_hcd->core_if->adp.vbuson_timer_started = 0;
+			dwc_otg_core_init(dwc_otg_hcd->core_if);
+			dwc_otg_enable_global_interrupts(dwc_otg_hcd->core_if);
+			cil_hcd_start(dwc_otg_hcd->core_if);*/
+		} else {
+
+			DWC_DEBUGPL(DBG_HCD, "--Port Interrupt HPRT0=0x%08x "
+				    "Port Connect Detected--\n", hprt0.d32);
+			dwc_otg_hcd->flags.b.port_connect_status_change = 1;
+			dwc_otg_hcd->flags.b.port_connect_status = 1;
+			hprt0_modify.b.prtconndet = 1;
+
+			/* B-Device has connected, Delete the connection timer. */
+			DWC_TIMER_CANCEL(dwc_otg_hcd->conn_timer);
+		}
+		/* The Hub driver asserts a reset when it sees port connect
+		 * status change flag */
+		retval |= 1;
+	}
+
+	/* Port Enable Changed
+	 * Clear if detected - Set internal flag if disabled */
+	if (hprt0.b.prtenchng) {
+		DWC_DEBUGPL(DBG_HCD, "  --Port Interrupt HPRT0=0x%08x "
+			    "Port Enable Changed--\n", hprt0.d32);
+		hprt0_modify.b.prtenchng = 1;
+		if (hprt0.b.prtena == 1) {
+			hfir_data_t hfir;
+			int do_reset = 0;
+			dwc_otg_core_params_t *params =
+			    dwc_otg_hcd->core_if->core_params;
+			dwc_otg_core_global_regs_t *global_regs =
+			    dwc_otg_hcd->core_if->core_global_regs;
+			dwc_otg_host_if_t *host_if =
+			    dwc_otg_hcd->core_if->host_if;
+
+			/* Every time when port enables calculate
+			 * HFIR.FrInterval
+			 */
+			hfir.d32 = DWC_READ_REG32(&host_if->host_global_regs->hfir);
+			hfir.b.frint = calc_frame_interval(dwc_otg_hcd->core_if);
+			DWC_WRITE_REG32(&host_if->host_global_regs->hfir, hfir.d32);
+
+			/* Check if we need to adjust the PHY clock speed for
+			 * low power and adjust it */
+			if (params->host_support_fs_ls_low_power) {
+				gusbcfg_data_t usbcfg;
+
+				usbcfg.d32 =
+				    DWC_READ_REG32(&global_regs->gusbcfg);
+
+				if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED
+				    || hprt0.b.prtspd ==
+				    DWC_HPRT0_PRTSPD_FULL_SPEED) {
+					/*
+					 * Low power
+					 */
+					hcfg_data_t hcfg;
+					if (usbcfg.b.phylpwrclksel == 0) {
+						/* Set PHY low power clock select for FS/LS devices */
+						usbcfg.b.phylpwrclksel = 1;
+						DWC_WRITE_REG32
+						    (&global_regs->gusbcfg,
+						     usbcfg.d32);
+						do_reset = 1;
+					}
+
+					hcfg.d32 =
+					    DWC_READ_REG32
+					    (&host_if->host_global_regs->hcfg);
+
+					if (hprt0.b.prtspd ==
+					    DWC_HPRT0_PRTSPD_LOW_SPEED
+					    && params->host_ls_low_power_phy_clk
+					    ==
+					    DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ)
+					{
+						/* 6 MHZ */
+						DWC_DEBUGPL(DBG_CIL,
+							    "FS_PHY programming HCFG to 6 MHz (Low Power)\n");
+						if (hcfg.b.fslspclksel !=
+						    DWC_HCFG_6_MHZ) {
+							hcfg.b.fslspclksel =
+							    DWC_HCFG_6_MHZ;
+							DWC_WRITE_REG32
+							    (&host_if->host_global_regs->hcfg,
+							     hcfg.d32);
+							do_reset = 1;
+						}
+					} else {
+						/* 48 MHZ */
+						DWC_DEBUGPL(DBG_CIL,
+							    "FS_PHY programming HCFG to 48 MHz ()\n");
+						if (hcfg.b.fslspclksel !=
+						    DWC_HCFG_48_MHZ) {
+							hcfg.b.fslspclksel =
+							    DWC_HCFG_48_MHZ;
+							DWC_WRITE_REG32
+							    (&host_if->host_global_regs->hcfg,
+							     hcfg.d32);
+							do_reset = 1;
+						}
+					}
+				} else {
+					/*
+					 * Not low power
+					 */
+					if (usbcfg.b.phylpwrclksel == 1) {
+						usbcfg.b.phylpwrclksel = 0;
+						DWC_WRITE_REG32
+						    (&global_regs->gusbcfg,
+						     usbcfg.d32);
+						do_reset = 1;
+					}
+				}
+
+				if (do_reset) {
+					DWC_TASK_SCHEDULE(dwc_otg_hcd->reset_tasklet);
+				}
+			}
+
+			if (!do_reset) {
+				/* Port has been enabled set the reset change flag */
+				dwc_otg_hcd->flags.b.port_reset_change = 1;
+			}
+		} else {
+			dwc_otg_hcd->flags.b.port_enable_change = 1;
+		}
+		retval |= 1;
+	}
+
+	/** Overcurrent Change Interrupt */
+	if (hprt0.b.prtovrcurrchng) {
+		DWC_DEBUGPL(DBG_HCD, "  --Port Interrupt HPRT0=0x%08x "
+			    "Port Overcurrent Changed--\n", hprt0.d32);
+		dwc_otg_hcd->flags.b.port_over_current_change = 1;
+		hprt0_modify.b.prtovrcurrchng = 1;
+		retval |= 1;
+	}
+
+	/* Clear Port Interrupts */
+	DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0_modify.d32);
+
+	return retval;
+}
+
+/** This interrupt indicates that one or more host channels has a pending
+ * interrupt. There are multiple conditions that can cause each host channel
+ * interrupt. This function determines which conditions have occurred for each
+ * host channel interrupt and handles them appropriately. */
+int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd)
+{
+	int i;
+	int retval = 0;
+	haint_data_t haint;
+
+	/* Clear appropriate bits in HCINTn to clear the interrupt bit in
+	 * GINTSTS */
+
+	haint.d32 = dwc_otg_read_host_all_channels_intr(dwc_otg_hcd->core_if);
+
+	for (i = 0; i < dwc_otg_hcd->core_if->core_params->host_channels; i++) {
+		if (haint.b2.chint & (1 << i)) {
+			retval |= dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd, i);
+		}
+	}
+
+	return retval;
+}
+
+/**
+ * Gets the actual length of a transfer after the transfer halts. _halt_status
+ * holds the reason for the halt.
+ *
+ * For IN transfers where halt_status is DWC_OTG_HC_XFER_COMPLETE,
+ * *short_read is set to 1 upon return if less than the requested
+ * number of bytes were transferred. Otherwise, *short_read is set to 0 upon
+ * return. short_read may also be NULL on entry, in which case it remains
+ * unchanged.
+ */
+static uint32_t get_actual_xfer_length(dwc_hc_t * hc,
+				       dwc_otg_hc_regs_t * hc_regs,
+				       dwc_otg_qtd_t * qtd,
+				       dwc_otg_halt_status_e halt_status,
+				       int *short_read)
+{
+	hctsiz_data_t hctsiz;
+	uint32_t length;
+
+	if (short_read != NULL) {
+		*short_read = 0;
+	}
+	hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
+
+	if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
+		if (hc->ep_is_in) {
+			length = hc->xfer_len - hctsiz.b.xfersize;
+			if (short_read != NULL) {
+				*short_read = (hctsiz.b.xfersize != 0);
+			}
+		} else if (hc->qh->do_split) {
+			length = qtd->ssplit_out_xfer_count;
+		} else {
+			length = hc->xfer_len;
+		}
+	} else {
+		/*
+		 * Must use the hctsiz.pktcnt field to determine how much data
+		 * has been transferred. This field reflects the number of
+		 * packets that have been transferred via the USB. This is
+		 * always an integral number of packets if the transfer was
+		 * halted before its normal completion. (Can't use the
+		 * hctsiz.xfersize field because that reflects the number of
+		 * bytes transferred via the AHB, not the USB).
+		 */
+		length =
+		    (hc->start_pkt_count - hctsiz.b.pktcnt) * hc->max_packet;
+	}
+
+	return length;
+}
+
+/**
+ * Updates the state of the URB after a Transfer Complete interrupt on the
+ * host channel. Updates the actual_length field of the URB based on the
+ * number of bytes transferred via the host channel. Sets the URB status
+ * if the data transfer is finished.
+ *
+ * @return 1 if the data transfer specified by the URB is completely finished,
+ * 0 otherwise.
+ */
+static int update_urb_state_xfer_comp(dwc_hc_t * hc,
+				      dwc_otg_hc_regs_t * hc_regs,
+				      dwc_otg_hcd_urb_t * urb,
+				      dwc_otg_qtd_t * qtd)
+{
+	int xfer_done = 0;
+	int short_read = 0;
+
+	int xfer_length;
+
+	xfer_length = get_actual_xfer_length(hc, hc_regs, qtd,
+					     DWC_OTG_HC_XFER_COMPLETE,
+					     &short_read);
+
+
+	/* non DWORD-aligned buffer case handling. */
+	if (hc->align_buff && xfer_length && hc->ep_is_in) {
+		dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf,
+			   xfer_length);
+	}
+
+	urb->actual_length += xfer_length;
+
+	if (xfer_length && (hc->ep_type == DWC_OTG_EP_TYPE_BULK) &&
+	    (urb->flags & URB_SEND_ZERO_PACKET)
+	    && (urb->actual_length == urb->length)
+	    && !(urb->length % hc->max_packet)) {
+		xfer_done = 0;
+	} else if (short_read || urb->actual_length == urb->length) {
+		xfer_done = 1;
+		urb->status = 0;
+	}
+
+#ifdef DEBUG
+	{
+		hctsiz_data_t hctsiz;
+		hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
+		DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n",
+			    __func__, (hc->ep_is_in ? "IN" : "OUT"),
+			    hc->hc_num);
+		DWC_DEBUGPL(DBG_HCDV, "  hc->xfer_len %d\n", hc->xfer_len);
+		DWC_DEBUGPL(DBG_HCDV, "  hctsiz.xfersize %d\n",
+			    hctsiz.b.xfersize);
+		DWC_DEBUGPL(DBG_HCDV, "  urb->transfer_buffer_length %d\n",
+			    urb->length);
+		DWC_DEBUGPL(DBG_HCDV, "  urb->actual_length %d\n",
+			    urb->actual_length);
+		DWC_DEBUGPL(DBG_HCDV, "  short_read %d, xfer_done %d\n",
+			    short_read, xfer_done);
+	}
+#endif
+
+	return xfer_done;
+}
+
+/*
+ * Save the starting data toggle for the next transfer. The data toggle is
+ * saved in the QH for non-control transfers and it's saved in the QTD for
+ * control transfers.
+ */
+void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc,
+			     dwc_otg_hc_regs_t * hc_regs, dwc_otg_qtd_t * qtd)
+{
+	hctsiz_data_t hctsiz;
+	hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
+
+	if (hc->ep_type != DWC_OTG_EP_TYPE_CONTROL) {
+		dwc_otg_qh_t *qh = hc->qh;
+		if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) {
+			qh->data_toggle = DWC_OTG_HC_PID_DATA0;
+		} else {
+			qh->data_toggle = DWC_OTG_HC_PID_DATA1;
+		}
+	} else {
+		if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) {
+			qtd->data_toggle = DWC_OTG_HC_PID_DATA0;
+		} else {
+			qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
+		}
+	}
+}
+
+/**
+ * Updates the state of an Isochronous URB when the transfer is stopped for
+ * any reason. The fields of the current entry in the frame descriptor array
+ * are set based on the transfer state and the input _halt_status. Completes
+ * the Isochronous URB if all the URB frames have been completed.
+ *
+ * @return DWC_OTG_HC_XFER_COMPLETE if there are more frames remaining to be
+ * transferred in the URB. Otherwise return DWC_OTG_HC_XFER_URB_COMPLETE.
+ */
+static dwc_otg_halt_status_e
+update_isoc_urb_state(dwc_otg_hcd_t * hcd,
+		      dwc_hc_t * hc,
+		      dwc_otg_hc_regs_t * hc_regs,
+		      dwc_otg_qtd_t * qtd, dwc_otg_halt_status_e halt_status)
+{
+	dwc_otg_hcd_urb_t *urb = qtd->urb;
+	dwc_otg_halt_status_e ret_val = halt_status;
+	struct dwc_otg_hcd_iso_packet_desc *frame_desc;
+
+	frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
+	switch (halt_status) {
+	case DWC_OTG_HC_XFER_COMPLETE:
+		frame_desc->status = 0;
+		frame_desc->actual_length =
+		    get_actual_xfer_length(hc, hc_regs, qtd, halt_status, NULL);
+
+		/* non DWORD-aligned buffer case handling. */
+		if (hc->align_buff && frame_desc->actual_length && hc->ep_is_in) {
+			dwc_memcpy(urb->buf + frame_desc->offset + qtd->isoc_split_offset,
+				   hc->qh->dw_align_buf, frame_desc->actual_length);
+		}
+
+		break;
+	case DWC_OTG_HC_XFER_FRAME_OVERRUN:
+		urb->error_count++;
+		if (hc->ep_is_in) {
+			frame_desc->status = -DWC_E_NO_STREAM_RES;
+		} else {
+			frame_desc->status = -DWC_E_COMMUNICATION;
+		}
+		frame_desc->actual_length = 0;
+		break;
+	case DWC_OTG_HC_XFER_BABBLE_ERR:
+		urb->error_count++;
+		frame_desc->status = -DWC_E_OVERFLOW;
+		/* Don't need to update actual_length in this case. */
+		break;
+	case DWC_OTG_HC_XFER_XACT_ERR:
+		urb->error_count++;
+		frame_desc->status = -DWC_E_PROTOCOL;
+		frame_desc->actual_length =
+		    get_actual_xfer_length(hc, hc_regs, qtd, halt_status, NULL);
+
+		/* non DWORD-aligned buffer case handling. */
+		if (hc->align_buff && frame_desc->actual_length && hc->ep_is_in) {
+			dwc_memcpy(urb->buf + frame_desc->offset + qtd->isoc_split_offset,
+				   hc->qh->dw_align_buf, frame_desc->actual_length);
+		}
+		/* Skip whole frame */
+		if (hc->qh->do_split && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) &&
+		    hc->ep_is_in && hcd->core_if->dma_enable) {
+			qtd->complete_split = 0;
+			qtd->isoc_split_offset = 0;
+		}
+
+		break;
+	default:
+		DWC_ASSERT(1, "Unhandled _halt_status (%d)\n", halt_status);
+		break;
+	}
+	if (++qtd->isoc_frame_index == urb->packet_count) {
+		/*
+		 * urb->status is not used for isoc transfers.
+		 * The individual frame_desc statuses are used instead.
+		 */
+		hcd->fops->complete(hcd, urb->priv, urb, 0);
+		ret_val = DWC_OTG_HC_XFER_URB_COMPLETE;
+	} else {
+		ret_val = DWC_OTG_HC_XFER_COMPLETE;
+	}
+	return ret_val;
+}
+
+/**
+ * Frees the first QTD in the QH's list if free_qtd is 1. For non-periodic
+ * QHs, removes the QH from the active non-periodic schedule. If any QTDs are
+ * still linked to the QH, the QH is added to the end of the inactive
+ * non-periodic schedule. For periodic QHs, removes the QH from the periodic
+ * schedule if no more QTDs are linked to the QH.
+ */
+static void deactivate_qh(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, int free_qtd)
+{
+	int continue_split = 0;
+	dwc_otg_qtd_t *qtd;
+
+	DWC_DEBUGPL(DBG_HCDV, "  %s(%p,%p,%d)\n", __func__, hcd, qh, free_qtd);
+
+	qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
+
+	if (qtd->complete_split) {
+		continue_split = 1;
+	} else if (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_MID ||
+		   qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_END) {
+		continue_split = 1;
+	}
+
+	if (free_qtd) {
+		dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
+		continue_split = 0;
+	}
+
+	qh->channel = NULL;
+	dwc_otg_hcd_qh_deactivate(hcd, qh, continue_split);
+}
+
+/**
+ * Releases a host channel for use by other transfers. Attempts to select and
+ * queue more transactions since at least one host channel is available.
+ *
+ * @param hcd The HCD state structure.
+ * @param hc The host channel to release.
+ * @param qtd The QTD associated with the host channel. This QTD may be freed
+ * if the transfer is complete or an error has occurred.
+ * @param halt_status Reason the channel is being released. This status
+ * determines the actions taken by this function.
+ */
+static void release_channel(dwc_otg_hcd_t * hcd,
+			    dwc_hc_t * hc,
+			    dwc_otg_qtd_t * qtd,
+			    dwc_otg_halt_status_e halt_status)
+{
+	dwc_otg_transaction_type_e tr_type;
+	int free_qtd;
+    gintmsk_data_t intr_mask = {.d32 = 0 };
+
+	DWC_DEBUGPL(DBG_HCDV, "  %s: channel %d, halt_status %d\n",
+		    __func__, hc->hc_num, halt_status);
+
+	switch (halt_status) {
+	case DWC_OTG_HC_XFER_URB_COMPLETE:
+		free_qtd = 1;
+		break;
+	case DWC_OTG_HC_XFER_AHB_ERR:
+	case DWC_OTG_HC_XFER_STALL:
+	case DWC_OTG_HC_XFER_BABBLE_ERR:
+		free_qtd = 1;
+		break;
+	case DWC_OTG_HC_XFER_XACT_ERR:
+		if (qtd->error_count >= 3) {
+			DWC_DEBUGPL(DBG_HCDV,
+				    "  Complete URB with transaction error\n");
+			free_qtd = 1;
+			qtd->urb->status = -DWC_E_PROTOCOL;
+			hcd->fops->complete(hcd, qtd->urb->priv,
+					    qtd->urb, -DWC_E_PROTOCOL);
+		} else {
+			free_qtd = 0;
+		}
+		break;
+	case DWC_OTG_HC_XFER_URB_DEQUEUE:
+		/*
+		 * The QTD has already been removed and the QH has been
+		 * deactivated. Don't want to do anything except release the
+		 * host channel and try to queue more transfers.
+		 */
+		goto cleanup;
+	case DWC_OTG_HC_XFER_NO_HALT_STATUS:
+		free_qtd = 0;
+		break;
+	case DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE:
+		DWC_DEBUGPL(DBG_HCDV,
+			"  Complete URB with I/O error\n");
+		free_qtd = 1;
+		qtd->urb->status = -DWC_E_IO;
+		hcd->fops->complete(hcd, qtd->urb->priv,
+			qtd->urb, -DWC_E_IO);
+		break;
+	default:
+		free_qtd = 0;
+		break;
+	}
+
+	deactivate_qh(hcd, hc->qh, free_qtd);
+
+cleanup:
+	/*
+	 * Release the host channel for use by other transfers. The cleanup
+	 * function clears the channel interrupt enables and conditions, so
+	 * there's no need to clear the Channel Halted interrupt separately.
+	 */
+	dwc_otg_hc_cleanup(hcd->core_if, hc);
+	DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
+
+	switch (hc->ep_type) {
+	case DWC_OTG_EP_TYPE_CONTROL:
+	case DWC_OTG_EP_TYPE_BULK:
+		hcd->non_periodic_channels--;
+		break;
+
+	default:
+		/*
+		 * Don't release reservations for periodic channels here.
+		 * That's done when a periodic transfer is descheduled (i.e.
+		 * when the QH is removed from the periodic schedule).
+		 */
+		break;
+	}
+
+	/* Try to queue more transfers now that there's a free channel. */
+    intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk);
+    if (!intr_mask.b.sofintr) {
+        tr_type = dwc_otg_hcd_select_transactions(hcd);
+        if (tr_type != DWC_OTG_TRANSACTION_NONE) {
+            dwc_otg_hcd_queue_transactions(hcd, tr_type);
+        }
+    }
+}
+
+/**
+ * Halts a host channel. If the channel cannot be halted immediately because
+ * the request queue is full, this function ensures that the FIFO empty
+ * interrupt for the appropriate queue is enabled so that the halt request can
+ * be queued when there is space in the request queue.
+ *
+ * This function may also be called in DMA mode. In that case, the channel is
+ * simply released since the core always halts the channel automatically in
+ * DMA mode.
+ */
+static void halt_channel(dwc_otg_hcd_t * hcd,
+			 dwc_hc_t * hc,
+			 dwc_otg_qtd_t * qtd, dwc_otg_halt_status_e halt_status)
+{
+	if (hcd->core_if->dma_enable) {
+		release_channel(hcd, hc, qtd, halt_status);
+		return;
+	}
+
+	/* Slave mode processing... */
+	dwc_otg_hc_halt(hcd->core_if, hc, halt_status);
+
+	if (hc->halt_on_queue) {
+		gintmsk_data_t gintmsk = {.d32 = 0 };
+		dwc_otg_core_global_regs_t *global_regs;
+		global_regs = hcd->core_if->core_global_regs;
+
+		if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
+		    hc->ep_type == DWC_OTG_EP_TYPE_BULK) {
+			/*
+			 * Make sure the Non-periodic Tx FIFO empty interrupt
+			 * is enabled so that the non-periodic schedule will
+			 * be processed.
+			 */
+			gintmsk.b.nptxfempty = 1;
+			DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmsk.d32);
+		} else {
+			/*
+			 * Move the QH from the periodic queued schedule to
+			 * the periodic assigned schedule. This allows the
+			 * halt to be queued when the periodic schedule is
+			 * processed.
+			 */
+			DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
+					   &hc->qh->qh_list_entry);
+
+			/*
+			 * Make sure the Periodic Tx FIFO Empty interrupt is
+			 * enabled so that the periodic schedule will be
+			 * processed.
+			 */
+			gintmsk.b.ptxfempty = 1;
+			DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmsk.d32);
+		}
+	}
+}
+
+/**
+ * Performs common cleanup for non-periodic transfers after a Transfer
+ * Complete interrupt. This function should be called after any endpoint type
+ * specific handling is finished to release the host channel.
+ */
+static void complete_non_periodic_xfer(dwc_otg_hcd_t * hcd,
+				       dwc_hc_t * hc,
+				       dwc_otg_hc_regs_t * hc_regs,
+				       dwc_otg_qtd_t * qtd,
+				       dwc_otg_halt_status_e halt_status)
+{
+	hcint_data_t hcint;
+
+	qtd->error_count = 0;
+
+	hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
+	if (hcint.b.nyet) {
+		/*
+		 * Got a NYET on the last transaction of the transfer. This
+		 * means that the endpoint should be in the PING state at the
+		 * beginning of the next transfer.
+		 */
+		hc->qh->ping_state = 1;
+		clear_hc_int(hc_regs, nyet);
+	}
+
+	/*
+	 * Always halt and release the host channel to make it available for
+	 * more transfers. There may still be more phases for a control
+	 * transfer or more data packets for a bulk transfer at this point,
+	 * but the host channel is still halted. A channel will be reassigned
+	 * to the transfer when the non-periodic schedule is processed after
+	 * the channel is released. This allows transactions to be queued
+	 * properly via dwc_otg_hcd_queue_transactions, which also enables the
+	 * Tx FIFO Empty interrupt if necessary.
+	 */
+	if (hc->ep_is_in) {
+		/*
+		 * IN transfers in Slave mode require an explicit disable to
+		 * halt the channel. (In DMA mode, this call simply releases
+		 * the channel.)
+		 */
+		halt_channel(hcd, hc, qtd, halt_status);
+	} else {
+		/*
+		 * The channel is automatically disabled by the core for OUT
+		 * transfers in Slave mode.
+		 */
+		release_channel(hcd, hc, qtd, halt_status);
+	}
+}
+
+/**
+ * Performs common cleanup for periodic transfers after a Transfer Complete
+ * interrupt. This function should be called after any endpoint type specific
+ * handling is finished to release the host channel.
+ */
+static void complete_periodic_xfer(dwc_otg_hcd_t * hcd,
+				   dwc_hc_t * hc,
+				   dwc_otg_hc_regs_t * hc_regs,
+				   dwc_otg_qtd_t * qtd,
+				   dwc_otg_halt_status_e halt_status)
+{
+	hctsiz_data_t hctsiz;
+	qtd->error_count = 0;
+
+	hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
+	if (!hc->ep_is_in || hctsiz.b.pktcnt == 0) {
+		/* Core halts channel in these cases. */
+		release_channel(hcd, hc, qtd, halt_status);
+	} else {
+		/* Flush any outstanding requests from the Tx queue. */
+		halt_channel(hcd, hc, qtd, halt_status);
+	}
+}
+
+static int32_t handle_xfercomp_isoc_split_in(dwc_otg_hcd_t * hcd,
+					     dwc_hc_t * hc,
+					     dwc_otg_hc_regs_t * hc_regs,
+					     dwc_otg_qtd_t * qtd)
+{
+	uint32_t len;
+	struct dwc_otg_hcd_iso_packet_desc *frame_desc;
+	frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
+
+	len = get_actual_xfer_length(hc, hc_regs, qtd,
+				     DWC_OTG_HC_XFER_COMPLETE, NULL);
+
+	if (!len) {
+		qtd->complete_split = 0;
+		qtd->isoc_split_offset = 0;
+		return 0;
+	}
+	frame_desc->actual_length += len;
+
+	if (hc->align_buff && len)
+		dwc_memcpy(qtd->urb->buf + frame_desc->offset +
+			   qtd->isoc_split_offset, hc->qh->dw_align_buf, len);
+	qtd->isoc_split_offset += len;
+
+	if (frame_desc->length == frame_desc->actual_length) {
+		frame_desc->status = 0;
+		qtd->isoc_frame_index++;
+		qtd->complete_split = 0;
+		qtd->isoc_split_offset = 0;
+	}
+
+	if (qtd->isoc_frame_index == qtd->urb->packet_count) {
+		hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
+		release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
+	} else {
+		release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
+	}
+
+	return 1;		/* Indicates that channel released */
+}
+
+/**
+ * Handles a host channel Transfer Complete interrupt. This handler may be
+ * called in either DMA mode or Slave mode.
+ */
+static int32_t handle_hc_xfercomp_intr(dwc_otg_hcd_t * hcd,
+				       dwc_hc_t * hc,
+				       dwc_otg_hc_regs_t * hc_regs,
+				       dwc_otg_qtd_t * qtd)
+{
+	int urb_xfer_done;
+	dwc_otg_halt_status_e halt_status = DWC_OTG_HC_XFER_COMPLETE;
+	dwc_otg_hcd_urb_t *urb = qtd->urb;
+	int pipe_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
+
+	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+		    "Transfer Complete--\n", hc->hc_num);
+
+	if (hcd->core_if->dma_desc_enable) {
+		dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, halt_status);
+		if (pipe_type == UE_ISOCHRONOUS) {
+			/* Do not disable the interrupt, just clear it */
+			clear_hc_int(hc_regs, xfercomp);
+			return 1;
+		}
+		goto handle_xfercomp_done;
+	}
+
+	/*
+	 * Handle xfer complete on CSPLIT.
+	 */
+
+	if (hc->qh->do_split) {
+		if ((hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && hc->ep_is_in
+		    && hcd->core_if->dma_enable) {
+			if (qtd->complete_split
+			    && handle_xfercomp_isoc_split_in(hcd, hc, hc_regs,
+							     qtd))
+				goto handle_xfercomp_done;
+		} else {
+			qtd->complete_split = 0;
+		}
+	}
+
+	/* Update the QTD and URB states. */
+	switch (pipe_type) {
+	case UE_CONTROL:
+		switch (qtd->control_phase) {
+		case DWC_OTG_CONTROL_SETUP:
+			if (urb->length > 0) {
+				qtd->control_phase = DWC_OTG_CONTROL_DATA;
+			} else {
+				qtd->control_phase = DWC_OTG_CONTROL_STATUS;
+			}
+			DWC_DEBUGPL(DBG_HCDV,
+				    "  Control setup transaction done\n");
+			halt_status = DWC_OTG_HC_XFER_COMPLETE;
+			break;
+		case DWC_OTG_CONTROL_DATA:{
+				urb_xfer_done =
+				    update_urb_state_xfer_comp(hc, hc_regs, urb,
+							       qtd);
+				if (urb_xfer_done) {
+					qtd->control_phase =
+					    DWC_OTG_CONTROL_STATUS;
+					DWC_DEBUGPL(DBG_HCDV,
+						    "  Control data transfer done\n");
+				} else {
+					dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
+				}
+				halt_status = DWC_OTG_HC_XFER_COMPLETE;
+				break;
+			}
+		case DWC_OTG_CONTROL_STATUS:
+			DWC_DEBUGPL(DBG_HCDV, "  Control transfer complete\n");
+			if (urb->status == -DWC_E_IN_PROGRESS) {
+				urb->status = 0;
+			}
+			hcd->fops->complete(hcd, urb->priv, urb, urb->status);
+			halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
+			break;
+		}
+
+		complete_non_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
+		break;
+	case UE_BULK:
+		DWC_DEBUGPL(DBG_HCDV, "  Bulk transfer complete\n");
+		urb_xfer_done =
+		    update_urb_state_xfer_comp(hc, hc_regs, urb, qtd);
+		if (urb_xfer_done) {
+			hcd->fops->complete(hcd, urb->priv, urb, urb->status);
+			halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
+		} else {
+			halt_status = DWC_OTG_HC_XFER_COMPLETE;
+		}
+
+		dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
+		complete_non_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
+		break;
+	case UE_INTERRUPT:
+		DWC_DEBUGPL(DBG_HCDV, "  Interrupt transfer complete\n");
+		urb_xfer_done =
+			update_urb_state_xfer_comp(hc, hc_regs, urb, qtd);
+
+		/*
+		 * Interrupt URB is done on the first transfer complete
+		 * interrupt.
+		 */
+		if (urb_xfer_done) {
+				hcd->fops->complete(hcd, urb->priv, urb, urb->status);
+				halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
+		} else {
+				halt_status = DWC_OTG_HC_XFER_COMPLETE;
+		}
+
+		dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
+		complete_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
+		break;
+	case UE_ISOCHRONOUS:
+		DWC_DEBUGPL(DBG_HCDV, "  Isochronous transfer complete\n");
+		if (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_ALL) {
+			halt_status =
+			    update_isoc_urb_state(hcd, hc, hc_regs, qtd,
+						  DWC_OTG_HC_XFER_COMPLETE);
+		}
+		complete_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
+		break;
+	}
+
+handle_xfercomp_done:
+	disable_hc_int(hc_regs, xfercompl);
+
+	return 1;
+}
+
+/**
+ * Handles a host channel STALL interrupt. This handler may be called in
+ * either DMA mode or Slave mode.
+ */
+static int32_t handle_hc_stall_intr(dwc_otg_hcd_t * hcd,
+				    dwc_hc_t * hc,
+				    dwc_otg_hc_regs_t * hc_regs,
+				    dwc_otg_qtd_t * qtd)
+{
+	dwc_otg_hcd_urb_t *urb = qtd->urb;
+	int pipe_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
+
+	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+		    "STALL Received--\n", hc->hc_num);
+
+	if (hcd->core_if->dma_desc_enable) {
+		dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, DWC_OTG_HC_XFER_STALL);
+		goto handle_stall_done;
+	}
+
+	if (pipe_type == UE_CONTROL) {
+		hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE);
+	}
+
+	if (pipe_type == UE_BULK || pipe_type == UE_INTERRUPT) {
+		hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE);
+		/*
+		 * USB protocol requires resetting the data toggle for bulk
+		 * and interrupt endpoints when a CLEAR_FEATURE(ENDPOINT_HALT)
+		 * setup command is issued to the endpoint. Anticipate the
+		 * CLEAR_FEATURE command since a STALL has occurred and reset
+		 * the data toggle now.
+		 */
+		hc->qh->data_toggle = 0;
+	}
+
+	halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_STALL);
+
+handle_stall_done:
+	disable_hc_int(hc_regs, stall);
+
+	return 1;
+}
+
+/*
+ * Updates the state of the URB when a transfer has been stopped due to an
+ * abnormal condition before the transfer completes. Modifies the
+ * actual_length field of the URB to reflect the number of bytes that have
+ * actually been transferred via the host channel.
+ */
+static void update_urb_state_xfer_intr(dwc_hc_t * hc,
+				       dwc_otg_hc_regs_t * hc_regs,
+				       dwc_otg_hcd_urb_t * urb,
+				       dwc_otg_qtd_t * qtd,
+				       dwc_otg_halt_status_e halt_status)
+{
+	uint32_t bytes_transferred = get_actual_xfer_length(hc, hc_regs, qtd,
+							    halt_status, NULL);
+	/* non DWORD-aligned buffer case handling. */
+	if (hc->align_buff && bytes_transferred && hc->ep_is_in) {
+		dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf,
+			   bytes_transferred);
+	}
+
+	urb->actual_length += bytes_transferred;
+
+#ifdef DEBUG
+	{
+		hctsiz_data_t hctsiz;
+		hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
+		DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n",
+			    __func__, (hc->ep_is_in ? "IN" : "OUT"),
+			    hc->hc_num);
+		DWC_DEBUGPL(DBG_HCDV, "  hc->start_pkt_count %d\n",
+			    hc->start_pkt_count);
+		DWC_DEBUGPL(DBG_HCDV, "  hctsiz.pktcnt %d\n", hctsiz.b.pktcnt);
+		DWC_DEBUGPL(DBG_HCDV, "  hc->max_packet %d\n", hc->max_packet);
+		DWC_DEBUGPL(DBG_HCDV, "  bytes_transferred %d\n",
+			    bytes_transferred);
+		DWC_DEBUGPL(DBG_HCDV, "  urb->actual_length %d\n",
+			    urb->actual_length);
+		DWC_DEBUGPL(DBG_HCDV, "  urb->transfer_buffer_length %d\n",
+			    urb->length);
+	}
+#endif
+}
+
+/**
+ * Handles a host channel NAK interrupt. This handler may be called in either
+ * DMA mode or Slave mode.
+ */
+static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd,
+				  dwc_hc_t * hc,
+				  dwc_otg_hc_regs_t * hc_regs,
+				  dwc_otg_qtd_t * qtd)
+{
+	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+		    "NAK Received--\n", hc->hc_num);
+
+	/*
+	 * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
+	 * interrupt.  Re-start the SSPLIT transfer.
+	 */
+	if (hc->do_split) {
+		if (hc->complete_split) {
+			qtd->error_count = 0;
+		}
+		qtd->complete_split = 0;
+		halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
+		goto handle_nak_done;
+	}
+
+	switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
+	case UE_CONTROL:
+	case UE_BULK:
+		if (hcd->core_if->dma_enable && hc->ep_is_in) {
+			/*
+			 * NAK interrupts are enabled on bulk/control IN
+			 * transfers in DMA mode for the sole purpose of
+			 * resetting the error count after a transaction error
+			 * occurs. The core will continue transferring data.
+			 */
+			qtd->error_count = 0;
+			goto handle_nak_done;
+		}
+
+		/*
+		 * NAK interrupts normally occur during OUT transfers in DMA
+		 * or Slave mode. For IN transfers, more requests will be
+		 * queued as request queue space is available.
+		 */
+		qtd->error_count = 0;
+
+		if (!hc->qh->ping_state) {
+			update_urb_state_xfer_intr(hc, hc_regs,
+						   qtd->urb, qtd,
+						   DWC_OTG_HC_XFER_NAK);
+			dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
+
+			if (hc->speed == DWC_OTG_EP_SPEED_HIGH)
+				hc->qh->ping_state = 1;
+		}
+
+		/*
+		 * Halt the channel so the transfer can be re-started from
+		 * the appropriate point or the PING protocol will
+		 * start/continue.
+		 */
+		halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
+		break;
+	case UE_INTERRUPT:
+		qtd->error_count = 0;
+		halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
+		break;
+	case UE_ISOCHRONOUS:
+		/* Should never get called for isochronous transfers. */
+		DWC_ASSERT(1, "NACK interrupt for ISOC transfer\n");
+		break;
+	}
+
+handle_nak_done:
+	disable_hc_int(hc_regs, nak);
+
+	return 1;
+}
+
+/**
+ * Handles a host channel ACK interrupt. This interrupt is enabled when
+ * performing the PING protocol in Slave mode, when errors occur during
+ * either Slave mode or DMA mode, and during Start Split transactions.
+ */
+static int32_t handle_hc_ack_intr(dwc_otg_hcd_t * hcd,
+				  dwc_hc_t * hc,
+				  dwc_otg_hc_regs_t * hc_regs,
+				  dwc_otg_qtd_t * qtd)
+{
+	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+		    "ACK Received--\n", hc->hc_num);
+
+	if (hc->do_split) {
+		/*
+		 * Handle ACK on SSPLIT.
+		 * ACK should not occur in CSPLIT.
+		 */
+		if (!hc->ep_is_in && hc->data_pid_start != DWC_OTG_HC_PID_SETUP) {
+			qtd->ssplit_out_xfer_count = hc->xfer_len;
+		}
+		if (!(hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in)) {
+			/* Don't need complete for isochronous out transfers. */
+			qtd->complete_split = 1;
+		}
+
+		/* ISOC OUT */
+		if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in) {
+			switch (hc->xact_pos) {
+			case DWC_HCSPLIT_XACTPOS_ALL:
+				break;
+			case DWC_HCSPLIT_XACTPOS_END:
+				qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
+				qtd->isoc_split_offset = 0;
+				break;
+			case DWC_HCSPLIT_XACTPOS_BEGIN:
+			case DWC_HCSPLIT_XACTPOS_MID:
+				/*
+				 * For BEGIN or MID, calculate the length for
+				 * the next microframe to determine the correct
+				 * SSPLIT token, either MID or END.
+				 */
+				{
+					struct dwc_otg_hcd_iso_packet_desc
+					*frame_desc;
+
+					frame_desc =
+					    &qtd->urb->
+					    iso_descs[qtd->isoc_frame_index];
+					qtd->isoc_split_offset += 188;
+
+					if ((frame_desc->length -
+					     qtd->isoc_split_offset) <= 188) {
+						qtd->isoc_split_pos =
+						    DWC_HCSPLIT_XACTPOS_END;
+					} else {
+						qtd->isoc_split_pos =
+						    DWC_HCSPLIT_XACTPOS_MID;
+					}
+
+				}
+				break;
+			}
+		} else {
+			halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK);
+		}
+	} else {
+		qtd->error_count = 0;
+
+		if (hc->qh->ping_state) {
+			hc->qh->ping_state = 0;
+			/*
+			 * Halt the channel so the transfer can be re-started
+			 * from the appropriate point. This only happens in
+			 * Slave mode. In DMA mode, the ping_state is cleared
+			 * when the transfer is started because the core
+			 * automatically executes the PING, then the transfer.
+			 */
+			halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK);
+		}
+	}
+
+	/*
+	 * If the ACK occurred when _not_ in the PING state, let the channel
+	 * continue transferring data after clearing the error count.
+	 */
+
+	disable_hc_int(hc_regs, ack);
+
+	return 1;
+}
+
+/**
+ * Handles a host channel NYET interrupt. This interrupt should only occur on
+ * Bulk and Control OUT endpoints and for complete split transactions. If a
+ * NYET occurs at the same time as a Transfer Complete interrupt, it is
+ * handled in the xfercomp interrupt handler, not here. This handler may be
+ * called in either DMA mode or Slave mode.
+ */
+static int32_t handle_hc_nyet_intr(dwc_otg_hcd_t * hcd,
+				   dwc_hc_t * hc,
+				   dwc_otg_hc_regs_t * hc_regs,
+				   dwc_otg_qtd_t * qtd)
+{
+	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+		    "NYET Received--\n", hc->hc_num);
+
+	/*
+	 * NYET on CSPLIT
+	 * re-do the CSPLIT immediately on non-periodic
+	 */
+	if (hc->do_split && hc->complete_split) {
+		if (hc->ep_is_in && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
+		    && hcd->core_if->dma_enable) {
+			qtd->complete_split = 0;
+			qtd->isoc_split_offset = 0;
+			if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
+				hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
+				release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
+			}
+			else
+				release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
+			goto handle_nyet_done;
+		}
+
+		if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
+		    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
+			int frnum = dwc_otg_hcd_get_frame_number(hcd);
+
+			if (dwc_full_frame_num(frnum) !=
+			    dwc_full_frame_num(hc->qh->sched_frame)) {
+				/*
+				 * No longer in the same full speed frame.
+				 * Treat this as a transaction error.
+				 */
+#if 0
+				/** @todo Fix system performance so this can
+				 * be treated as an error. Right now complete
+				 * splits cannot be scheduled precisely enough
+				 * due to other system activity, so this error
+				 * occurs regularly in Slave mode.
+				 */
+				qtd->error_count++;
+#endif
+				qtd->complete_split = 0;
+				halt_channel(hcd, hc, qtd,
+					     DWC_OTG_HC_XFER_XACT_ERR);
+				/** @todo add support for isoc release */
+				goto handle_nyet_done;
+			}
+		}
+
+		halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET);
+		goto handle_nyet_done;
+	}
+
+	hc->qh->ping_state = 1;
+	qtd->error_count = 0;
+
+	update_urb_state_xfer_intr(hc, hc_regs, qtd->urb, qtd,
+				   DWC_OTG_HC_XFER_NYET);
+	dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
+
+	/*
+	 * Halt the channel and re-start the transfer so the PING
+	 * protocol will start.
+	 */
+	halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET);
+
+handle_nyet_done:
+	disable_hc_int(hc_regs, nyet);
+	return 1;
+}
+
+/**
+ * Handles a host channel babble interrupt. This handler may be called in
+ * either DMA mode or Slave mode.
+ */
+static int32_t handle_hc_babble_intr(dwc_otg_hcd_t * hcd,
+				     dwc_hc_t * hc,
+				     dwc_otg_hc_regs_t * hc_regs,
+				     dwc_otg_qtd_t * qtd)
+{
+	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+		    "Babble Error--\n", hc->hc_num);
+
+	if (hcd->core_if->dma_desc_enable) {
+		dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
+					       DWC_OTG_HC_XFER_BABBLE_ERR);
+		goto handle_babble_done;
+	}
+
+	if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
+		hcd->fops->complete(hcd, qtd->urb->priv,
+				    qtd->urb, -DWC_E_OVERFLOW);
+		halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_BABBLE_ERR);
+	} else {
+		dwc_otg_halt_status_e halt_status;
+		halt_status = update_isoc_urb_state(hcd, hc, hc_regs, qtd,
+						    DWC_OTG_HC_XFER_BABBLE_ERR);
+		halt_channel(hcd, hc, qtd, halt_status);
+	}
+
+handle_babble_done:
+	disable_hc_int(hc_regs, bblerr);
+	return 1;
+}
+
+/**
+ * Handles a host channel AHB error interrupt. This handler is only called in
+ * DMA mode.
+ */
+static int32_t handle_hc_ahberr_intr(dwc_otg_hcd_t * hcd,
+				     dwc_hc_t * hc,
+				     dwc_otg_hc_regs_t * hc_regs,
+				     dwc_otg_qtd_t * qtd)
+{
+	hcchar_data_t hcchar;
+	hcsplt_data_t hcsplt;
+	hctsiz_data_t hctsiz;
+	uint32_t hcdma;
+	char *pipetype, *speed;
+
+	dwc_otg_hcd_urb_t *urb = qtd->urb;
+
+	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+		    "AHB Error--\n", hc->hc_num);
+
+	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+	hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
+	hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
+	hcdma = DWC_READ_REG32(&hc_regs->hcdma);
+
+	DWC_ERROR("AHB ERROR, Channel %d\n", hc->hc_num);
+	DWC_ERROR("  hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32);
+	DWC_ERROR("  hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma);
+	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Enqueue\n");
+	DWC_ERROR("  Device address: %d\n",
+		  dwc_otg_hcd_get_dev_addr(&urb->pipe_info));
+	DWC_ERROR("  Endpoint: %d, %s\n",
+		  dwc_otg_hcd_get_ep_num(&urb->pipe_info),
+		  (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT"));
+
+	switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) {
+	case UE_CONTROL:
+		pipetype = "CONTROL";
+		break;
+	case UE_BULK:
+		pipetype = "BULK";
+		break;
+	case UE_INTERRUPT:
+		pipetype = "INTERRUPT";
+		break;
+	case UE_ISOCHRONOUS:
+		pipetype = "ISOCHRONOUS";
+		break;
+	default:
+		pipetype = "UNKNOWN";
+		break;
+	}
+
+	DWC_ERROR("  Endpoint type: %s\n", pipetype);
+
+	switch (hc->speed) {
+	case DWC_OTG_EP_SPEED_HIGH:
+		speed = "HIGH";
+		break;
+	case DWC_OTG_EP_SPEED_FULL:
+		speed = "FULL";
+		break;
+	case DWC_OTG_EP_SPEED_LOW:
+		speed = "LOW";
+		break;
+	default:
+		speed = "UNKNOWN";
+		break;
+	};
+
+	DWC_ERROR("  Speed: %s\n", speed);
+
+	DWC_ERROR("  Max packet size: %d\n",
+		  dwc_otg_hcd_get_mps(&urb->pipe_info));
+	DWC_ERROR("  Data buffer length: %d\n", urb->length);
+	DWC_ERROR("  Transfer buffer: %p, Transfer DMA: %p\n",
+		  urb->buf, (void *)urb->dma);
+	DWC_ERROR("  Setup buffer: %p, Setup DMA: %p\n",
+		  urb->setup_packet, (void *)urb->setup_dma);
+	DWC_ERROR("  Interval: %d\n", urb->interval);
+
+	/* Core haltes the channel for Descriptor DMA mode */
+	if (hcd->core_if->dma_desc_enable) {
+		dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
+					       DWC_OTG_HC_XFER_AHB_ERR);
+		goto handle_ahberr_done;
+	}
+
+	hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_IO);
+
+	/*
+	 * Force a channel halt. Don't call halt_channel because that won't
+	 * write to the HCCHARn register in DMA mode to force the halt.
+	 */
+	dwc_otg_hc_halt(hcd->core_if, hc, DWC_OTG_HC_XFER_AHB_ERR);
+handle_ahberr_done:
+	disable_hc_int(hc_regs, ahberr);
+	return 1;
+}
+
+/**
+ * Handles a host channel transaction error interrupt. This handler may be
+ * called in either DMA mode or Slave mode.
+ */
+static int32_t handle_hc_xacterr_intr(dwc_otg_hcd_t * hcd,
+				      dwc_hc_t * hc,
+				      dwc_otg_hc_regs_t * hc_regs,
+				      dwc_otg_qtd_t * qtd)
+{
+	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+		    "Transaction Error--\n", hc->hc_num);
+
+	if (hcd->core_if->dma_desc_enable) {
+		dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
+					       DWC_OTG_HC_XFER_XACT_ERR);
+		goto handle_xacterr_done;
+	}
+
+	if (qtd == NULL)
+		goto handle_xacterr_done;
+
+	if(qtd->urb == NULL)
+		goto handle_xacterr_done;
+
+	if (&qtd->urb->pipe_info == NULL)
+		goto handle_xacterr_done;
+
+	switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
+	case UE_CONTROL:
+	case UE_BULK:
+		qtd->error_count++;
+		if (!hc->qh->ping_state) {
+
+			update_urb_state_xfer_intr(hc, hc_regs,
+						   qtd->urb, qtd,
+						   DWC_OTG_HC_XFER_XACT_ERR);
+			dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
+			if (!hc->ep_is_in && hc->speed == DWC_OTG_EP_SPEED_HIGH) {
+				hc->qh->ping_state = 1;
+			}
+		}
+
+		/*
+		 * Halt the channel so the transfer can be re-started from
+		 * the appropriate point or the PING protocol will start.
+		 */
+		halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
+		break;
+	case UE_INTERRUPT:
+		qtd->error_count++;
+		if (hc->do_split && hc->complete_split) {
+			qtd->complete_split = 0;
+		}
+		halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
+		break;
+	case UE_ISOCHRONOUS:
+		{
+			dwc_otg_halt_status_e halt_status;
+			halt_status =
+			    update_isoc_urb_state(hcd, hc, hc_regs, qtd,
+						  DWC_OTG_HC_XFER_XACT_ERR);
+
+			halt_channel(hcd, hc, qtd, halt_status);
+		}
+		break;
+	}
+handle_xacterr_done:
+	disable_hc_int(hc_regs, xacterr);
+
+	return 1;
+}
+
+/**
+ * Handles a host channel frame overrun interrupt. This handler may be called
+ * in either DMA mode or Slave mode.
+ */
+static int32_t handle_hc_frmovrun_intr(dwc_otg_hcd_t * hcd,
+				       dwc_hc_t * hc,
+				       dwc_otg_hc_regs_t * hc_regs,
+				       dwc_otg_qtd_t * qtd)
+{
+	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+		    "Frame Overrun--\n", hc->hc_num);
+
+	switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
+	case UE_CONTROL:
+	case UE_BULK:
+		break;
+	case UE_INTERRUPT:
+		halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_FRAME_OVERRUN);
+		break;
+	case UE_ISOCHRONOUS:
+		{
+			dwc_otg_halt_status_e halt_status;
+			halt_status =
+			    update_isoc_urb_state(hcd, hc, hc_regs, qtd,
+						  DWC_OTG_HC_XFER_FRAME_OVERRUN);
+
+			halt_channel(hcd, hc, qtd, halt_status);
+		}
+		break;
+	}
+
+	disable_hc_int(hc_regs, frmovrun);
+
+	return 1;
+}
+
+/**
+ * Handles a host channel data toggle error interrupt. This handler may be
+ * called in either DMA mode or Slave mode.
+ */
+static int32_t handle_hc_datatglerr_intr(dwc_otg_hcd_t * hcd,
+					 dwc_hc_t * hc,
+					 dwc_otg_hc_regs_t * hc_regs,
+					 dwc_otg_qtd_t * qtd)
+{
+	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+		    "Data Toggle Error--\n", hc->hc_num);
+
+	if (hc->ep_is_in) {
+		qtd->error_count = 0;
+	} else {
+		DWC_ERROR("Data Toggle Error on OUT transfer,"
+			  "channel %d\n", hc->hc_num);
+	}
+
+	disable_hc_int(hc_regs, datatglerr);
+
+	return 1;
+}
+
+#ifdef DEBUG
+/**
+ * This function is for debug only. It checks that a valid halt status is set
+ * and that HCCHARn.chdis is clear. If there's a problem, corrective action is
+ * taken and a warning is issued.
+ * @return 1 if halt status is ok, 0 otherwise.
+ */
+static inline int halt_status_ok(dwc_otg_hcd_t * hcd,
+				 dwc_hc_t * hc,
+				 dwc_otg_hc_regs_t * hc_regs,
+				 dwc_otg_qtd_t * qtd)
+{
+	hcchar_data_t hcchar;
+	hctsiz_data_t hctsiz;
+	hcint_data_t hcint;
+	hcintmsk_data_t hcintmsk;
+	hcsplt_data_t hcsplt;
+
+	if (hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS) {
+		/*
+		 * This code is here only as a check. This condition should
+		 * never happen. Ignore the halt if it does occur.
+		 */
+		hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+		hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
+		hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
+		hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
+		hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
+		DWC_WARN
+		    ("%s: hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS, "
+		     "channel %d, hcchar 0x%08x, hctsiz 0x%08x, "
+		     "hcint 0x%08x, hcintmsk 0x%08x, "
+		     "hcsplt 0x%08x, qtd->complete_split %d\n", __func__,
+		     hc->hc_num, hcchar.d32, hctsiz.d32, hcint.d32,
+		     hcintmsk.d32, hcsplt.d32, qtd->complete_split);
+
+		DWC_WARN("%s: no halt status, channel %d, ignoring interrupt\n",
+			 __func__, hc->hc_num);
+		DWC_WARN("\n");
+		clear_hc_int(hc_regs, chhltd);
+		return 0;
+	}
+
+	/*
+	 * This code is here only as a check. hcchar.chdis should
+	 * never be set when the halt interrupt occurs. Halt the
+	 * channel again if it does occur.
+	 */
+	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
+	if (hcchar.b.chdis) {
+		DWC_WARN("%s: hcchar.chdis set unexpectedly, "
+			 "hcchar 0x%08x, trying to halt again\n",
+			 __func__, hcchar.d32);
+		clear_hc_int(hc_regs, chhltd);
+		hc->halt_pending = 0;
+		halt_channel(hcd, hc, qtd, hc->halt_status);
+		return 0;
+	}
+
+	return 1;
+}
+#endif
+
+/**
+ * Handles a host Channel Halted interrupt in DMA mode. This handler
+ * determines the reason the channel halted and proceeds accordingly.
+ */
+static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd,
+				      dwc_hc_t * hc,
+				      dwc_otg_hc_regs_t * hc_regs,
+				      dwc_otg_qtd_t * qtd)
+{
+	hcint_data_t hcint;
+	hcintmsk_data_t hcintmsk;
+	int out_nak_enh = 0;
+
+	/* For core with OUT NAK enhancement, the flow for high-
+	 * speed CONTROL/BULK OUT is handled a little differently.
+	 */
+	if (hcd->core_if->snpsid >= OTG_CORE_REV_2_71a) {
+		if (hc->speed == DWC_OTG_EP_SPEED_HIGH && !hc->ep_is_in &&
+		    (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
+		     hc->ep_type == DWC_OTG_EP_TYPE_BULK)) {
+			out_nak_enh = 1;
+		}
+	}
+
+	if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
+	    (hc->halt_status == DWC_OTG_HC_XFER_AHB_ERR
+	     && !hcd->core_if->dma_desc_enable)) {
+		/*
+		 * Just release the channel. A dequeue can happen on a
+		 * transfer timeout. In the case of an AHB Error, the channel
+		 * was forced to halt because there's no way to gracefully
+		 * recover.
+		 */
+		if (hcd->core_if->dma_desc_enable)
+			dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
+						       hc->halt_status);
+		else
+			release_channel(hcd, hc, qtd, hc->halt_status);
+		return;
+	}
+
+	/* Read the HCINTn register to determine the cause for the halt. */
+	hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
+	hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
+
+	if (hcint.b.xfercomp) {
+		/** @todo This is here because of a possible hardware bug.  Spec
+		 * says that on SPLIT-ISOC OUT transfers in DMA mode that a HALT
+		 * interrupt w/ACK bit set should occur, but I only see the
+		 * XFERCOMP bit, even with it masked out.  This is a workaround
+		 * for that behavior.  Should fix this when hardware is fixed.
+		 */
+		if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in) {
+			handle_hc_ack_intr(hcd, hc, hc_regs, qtd);
+		}
+		handle_hc_xfercomp_intr(hcd, hc, hc_regs, qtd);
+	} else if (hcint.b.stall) {
+		handle_hc_stall_intr(hcd, hc, hc_regs, qtd);
+	} else if (hcint.b.xacterr && !hcd->core_if->dma_desc_enable) {
+		if (out_nak_enh) {
+			if (hcint.b.nyet || hcint.b.nak || hcint.b.ack) {
+				DWC_DEBUG("XactErr with NYET/NAK/ACK\n");
+				qtd->error_count = 0;
+			} else {
+				DWC_DEBUG("XactErr without NYET/NAK/ACK\n");
+			}
+		}
+
+		/*
+		 * Must handle xacterr before nak or ack. Could get a xacterr
+		 * at the same time as either of these on a BULK/CONTROL OUT
+		 * that started with a PING. The xacterr takes precedence.
+		 */
+		handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd);
+	} else if (hcint.b.xcs_xact && hcd->core_if->dma_desc_enable) {
+		handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd);
+	} else if (hcint.b.ahberr && hcd->core_if->dma_desc_enable) {
+		handle_hc_ahberr_intr(hcd, hc, hc_regs, qtd);
+	} else if (hcint.b.bblerr) {
+		handle_hc_babble_intr(hcd, hc, hc_regs, qtd);
+	} else if (hcint.b.frmovrun) {
+		handle_hc_frmovrun_intr(hcd, hc, hc_regs, qtd);
+	} else if (!out_nak_enh) {
+		if (hcint.b.nyet) {
+			/*
+			 * Must handle nyet before nak or ack. Could get a nyet at the
+			 * same time as either of those on a BULK/CONTROL OUT that
+			 * started with a PING. The nyet takes precedence.
+			 */
+			handle_hc_nyet_intr(hcd, hc, hc_regs, qtd);
+		} else if (hcint.b.nak && !hcintmsk.b.nak) {
+			/*
+			 * If nak is not masked, it's because a non-split IN transfer
+			 * is in an error state. In that case, the nak is handled by
+			 * the nak interrupt handler, not here. Handle nak here for
+			 * BULK/CONTROL OUT transfers, which halt on a NAK to allow
+			 * rewinding the buffer pointer.
+			 */
+			handle_hc_nak_intr(hcd, hc, hc_regs, qtd);
+		} else if (hcint.b.ack && !hcintmsk.b.ack) {
+			/*
+			 * If ack is not masked, it's because a non-split IN transfer
+			 * is in an error state. In that case, the ack is handled by
+			 * the ack interrupt handler, not here. Handle ack here for
+			 * split transfers. Start splits halt on ACK.
+			 */
+			handle_hc_ack_intr(hcd, hc, hc_regs, qtd);
+		} else {
+			if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
+			    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
+				/*
+				 * A periodic transfer halted with no other channel
+				 * interrupts set. Assume it was halted by the core
+				 * because it could not be completed in its scheduled
+				 * (micro)frame.
+				 */
+#ifdef DEBUG
+				DWC_PRINTF
+				    ("%s: Halt channel %d (assume incomplete periodic transfer)\n",
+				     __func__, hc->hc_num);
+#endif
+				halt_channel(hcd, hc, qtd,
+					     DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE);
+			} else {
+				DWC_ERROR
+				    ("%s: Channel %d, DMA Mode -- ChHltd set, but reason "
+				     "for halting is unknown, hcint 0x%08x, intsts 0x%08x\n",
+				     __func__, hc->hc_num, hcint.d32,
+				     DWC_READ_REG32(&hcd->
+						    core_if->core_global_regs->
+						    gintsts));
+				halt_channel(hcd, hc, qtd,
+					     DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE);
+			}
+
+		}
+	} else {
+		DWC_PRINTF("NYET/NAK/ACK/other in non-error case, 0x%08x\n",
+			   hcint.d32);
+	}
+}
+
+/**
+ * Handles a host channel Channel Halted interrupt.
+ *
+ * In slave mode, this handler is called only when the driver specifically
+ * requests a halt. This occurs during handling other host channel interrupts
+ * (e.g. nak, xacterr, stall, nyet, etc.).
+ *
+ * In DMA mode, this is the interrupt that occurs when the core has finished
+ * processing a transfer on a channel. Other host channel interrupts (except
+ * ahberr) are disabled in DMA mode.
+ */
+static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t * hcd,
+				     dwc_hc_t * hc,
+				     dwc_otg_hc_regs_t * hc_regs,
+				     dwc_otg_qtd_t * qtd)
+{
+	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+		    "Channel Halted--\n", hc->hc_num);
+
+	if (hcd->core_if->dma_enable) {
+		handle_hc_chhltd_intr_dma(hcd, hc, hc_regs, qtd);
+	} else {
+#ifdef DEBUG
+		if (!halt_status_ok(hcd, hc, hc_regs, qtd)) {
+			return 1;
+		}
+#endif
+		release_channel(hcd, hc, qtd, hc->halt_status);
+	}
+
+	return 1;
+}
+
+/** Handles interrupt for a specific Host Channel */
+int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num)
+{
+	int retval = 0;
+	hcint_data_t hcint;
+	hcintmsk_data_t hcintmsk;
+	dwc_hc_t *hc;
+	dwc_otg_hc_regs_t *hc_regs;
+	dwc_otg_qtd_t *qtd;
+
+	DWC_DEBUGPL(DBG_HCDV, "--Host Channel Interrupt--, Channel %d\n", num);
+
+	hc = dwc_otg_hcd->hc_ptr_array[num];
+	hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[num];
+	qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list);
+
+	hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
+	hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
+	DWC_DEBUGPL(DBG_HCDV,
+		    "  hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n",
+		    hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32));
+	hcint.d32 = hcint.d32 & hcintmsk.d32;
+
+	if (!dwc_otg_hcd->core_if->dma_enable) {
+		if (hcint.b.chhltd && hcint.d32 != 0x2) {
+			hcint.b.chhltd = 0;
+		}
+	}
+
+	if (hcint.b.xfercomp) {
+		retval |=
+		    handle_hc_xfercomp_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+		/*
+		 * If NYET occurred at same time as Xfer Complete, the NYET is
+		 * handled by the Xfer Complete interrupt handler. Don't want
+		 * to call the NYET interrupt handler in this case.
+		 */
+		hcint.b.nyet = 0;
+	}
+	if (hcint.b.chhltd) {
+		retval |= handle_hc_chhltd_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+	}
+	if (hcint.b.ahberr) {
+		retval |= handle_hc_ahberr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+	}
+	if (hcint.b.stall) {
+		retval |= handle_hc_stall_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+	}
+	if (hcint.b.nak) {
+		retval |= handle_hc_nak_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+	}
+	if (hcint.b.ack) {
+		retval |= handle_hc_ack_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+	}
+	if (hcint.b.nyet) {
+		retval |= handle_hc_nyet_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+	}
+	if (hcint.b.xacterr) {
+		retval |= handle_hc_xacterr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+	}
+	if (hcint.b.bblerr) {
+		retval |= handle_hc_babble_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+	}
+	if (hcint.b.frmovrun) {
+		retval |=
+		    handle_hc_frmovrun_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+	}
+	if (hcint.b.datatglerr) {
+		retval |=
+		    handle_hc_datatglerr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+	}
+
+	return retval;
+}
+
+#endif /* DWC_DEVICE_ONLY */
diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd_linux.c b/drivers/usb/dwc_otg/dwc_otg_hcd_linux.c
new file mode 100644
index 0000000..5c09aff
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_hcd_linux.c
@@ -0,0 +1,888 @@
+/* ==========================================================================
+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_linux.c $
+ * $Revision: #20 $
+ * $Date: 2011/10/26 $
+ * $Change: 1872981 $
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+#ifndef DWC_DEVICE_ONLY
+
+/**
+ * @file
+ *
+ * This file contains the implementation of the HCD. In Linux, the HCD
+ * implements the hc_driver API.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/dma-mapping.h>
+#include <linux/version.h>
+#include <asm/io.h>
+#include <linux/usb.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
+#include <../drivers/usb/core/hcd.h>
+#else
+#include <linux/usb/hcd.h>
+#endif
+
+#include "dwc_otg_hcd_if.h"
+#include "dwc_otg_dbg.h"
+#include "dwc_otg_driver.h"
+#include "dwc_otg_hcd.h"
+/**
+ * Gets the endpoint number from a _bEndpointAddress argument. The endpoint is
+ * qualified with its direction (possible 32 endpoints per device).
+ */
+#define dwc_ep_addr_to_endpoint(_bEndpointAddress_) ((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \
+						     ((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4)
+
+static const char dwc_otg_hcd_name[] = "dwc_otg";
+
+/** @name Linux HC Driver API Functions */
+/** @{ */
+static int urb_enqueue(struct usb_hcd *hcd,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+		       struct usb_host_endpoint *ep,
+#endif
+		       struct urb *urb, gfp_t mem_flags);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
+#else
+static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
+#endif
+
+static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
+static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
+#endif
+static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd);
+extern int hcd_start(struct usb_hcd *hcd);
+extern void hcd_stop(struct usb_hcd *hcd);
+static int get_frame_number(struct usb_hcd *hcd);
+extern int hub_status_data(struct usb_hcd *hcd, char *buf);
+extern int hub_control(struct usb_hcd *hcd,
+		       u16 typeReq,
+		       u16 wValue, u16 wIndex, char *buf, u16 wLength);
+
+struct wrapper_priv_data {
+	dwc_otg_hcd_t *dwc_otg_hcd;
+};
+
+/** @} */
+
+int comcerto_dwc_dummy_bus_suspend(struct usb_hcd *hcd)
+{
+	printk("\n comcerto_dwc_dummy_bus_suspend...");
+	return 0;
+}
+
+int comcerto_dwc_dummy_bus_resume(struct usb_hcd *hcd)
+{
+	printk("\n comcerto_dwc_dummy_bus_resume...");
+	return 0;
+}
+
+
+static struct hc_driver dwc_otg_hc_driver = {
+
+	.description = dwc_otg_hcd_name,
+	.product_desc = "DWC OTG Controller",
+	.hcd_priv_size = sizeof(struct wrapper_priv_data),
+
+	.irq = dwc_otg_hcd_irq,
+
+	.flags = HCD_MEMORY | HCD_USB2,
+
+	//.reset =
+	.start = hcd_start,
+	//.suspend =
+	//.resume =
+	.stop = hcd_stop,
+
+	.urb_enqueue = urb_enqueue,
+	.urb_dequeue = urb_dequeue,
+	.endpoint_disable = endpoint_disable,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
+	.endpoint_reset = endpoint_reset,
+#endif
+	.get_frame_number = get_frame_number,
+
+	.hub_status_data = hub_status_data,
+	.hub_control = hub_control,
+	.bus_suspend = comcerto_dwc_dummy_bus_suspend,
+	.bus_resume = comcerto_dwc_dummy_bus_resume,
+};
+
+/** Gets the dwc_otg_hcd from a struct usb_hcd */
+static inline dwc_otg_hcd_t *hcd_to_dwc_otg_hcd(struct usb_hcd *hcd)
+{
+	struct wrapper_priv_data *p;
+	p = (struct wrapper_priv_data *)(hcd->hcd_priv);
+	return p->dwc_otg_hcd;
+}
+
+/** Gets the struct usb_hcd that contains a dwc_otg_hcd_t. */
+static inline struct usb_hcd *dwc_otg_hcd_to_hcd(dwc_otg_hcd_t * dwc_otg_hcd)
+{
+	return dwc_otg_hcd_get_priv_data(dwc_otg_hcd);
+}
+
+/** Gets the usb_host_endpoint associated with an URB. */
+inline struct usb_host_endpoint *dwc_urb_to_endpoint(struct urb *urb)
+{
+	struct usb_device *dev = urb->dev;
+	int ep_num = usb_pipeendpoint(urb->pipe);
+
+	if (usb_pipein(urb->pipe))
+		return dev->ep_in[ep_num];
+	else
+		return dev->ep_out[ep_num];
+}
+
+static int _disconnect(dwc_otg_hcd_t * hcd)
+{
+	struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
+
+	usb_hcd->self.is_b_host = 0;
+	return 0;
+}
+
+static int _start(dwc_otg_hcd_t * hcd)
+{
+	struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
+
+	usb_hcd->self.is_b_host = dwc_otg_hcd_is_b_host(hcd);
+	hcd_start(usb_hcd);
+
+	return 0;
+}
+
+static int _hub_info(dwc_otg_hcd_t * hcd, void *urb_handle, uint32_t * hub_addr,
+		     uint32_t * port_addr)
+{
+	struct urb *urb = (struct urb *)urb_handle;
+	if (urb->dev->tt) {
+		*hub_addr = urb->dev->tt->hub->devnum;
+	} else {
+		*hub_addr = 0;
+	}
+	*port_addr = urb->dev->ttport;
+	return 0;
+}
+
+static int _speed(dwc_otg_hcd_t * hcd, void *urb_handle)
+{
+	struct urb *urb = (struct urb *)urb_handle;
+	return urb->dev->speed;
+}
+
+static int _get_b_hnp_enable(dwc_otg_hcd_t * hcd)
+{
+	struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
+	return usb_hcd->self.b_hnp_enable;
+}
+
+static void allocate_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
+				   struct urb *urb)
+{
+	hcd_to_bus(hcd)->bandwidth_allocated += bw / urb->interval;
+	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+		hcd_to_bus(hcd)->bandwidth_isoc_reqs++;
+	} else {
+		hcd_to_bus(hcd)->bandwidth_int_reqs++;
+	}
+}
+
+static void free_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
+			       struct urb *urb)
+{
+	hcd_to_bus(hcd)->bandwidth_allocated -= bw / urb->interval;
+	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+		hcd_to_bus(hcd)->bandwidth_isoc_reqs--;
+	} else {
+		hcd_to_bus(hcd)->bandwidth_int_reqs--;
+	}
+}
+
+/**
+ * Sets the final status of an URB and returns it to the device driver. Any
+ * required cleanup of the URB is performed.
+ */
+static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle,
+		     dwc_otg_hcd_urb_t * dwc_otg_urb, int32_t status)
+{
+	struct urb *urb = (struct urb *)urb_handle;
+#ifdef DEBUG
+	if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
+		DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n",
+			   __func__, urb, usb_pipedevice(urb->pipe),
+			   usb_pipeendpoint(urb->pipe),
+			   usb_pipein(urb->pipe) ? "IN" : "OUT", status);
+		if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+			int i;
+			for (i = 0; i < urb->number_of_packets; i++) {
+				DWC_PRINTF("  ISO Desc %d status: %d\n",
+					   i, urb->iso_frame_desc[i].status);
+			}
+		}
+	}
+#endif
+
+	urb->actual_length = dwc_otg_hcd_urb_get_actual_length(dwc_otg_urb);
+	/* Convert status value. */
+	switch (status) {
+	case -DWC_E_PROTOCOL:
+		status = -EPROTO;
+		break;
+	case -DWC_E_IN_PROGRESS:
+		status = -EINPROGRESS;
+		break;
+	case -DWC_E_PIPE:
+		status = -EPIPE;
+		break;
+	case -DWC_E_IO:
+		status = -EIO;
+		break;
+	case -DWC_E_TIMEOUT:
+		status = -ETIMEDOUT;
+		break;
+	case -DWC_E_OVERFLOW:
+		status = -EOVERFLOW;
+		break;
+	default:
+		if (status) {
+			DWC_PRINTF("Uknown urb status %d\n", status);
+
+		}
+	}
+
+	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+		int i;
+
+		urb->error_count = dwc_otg_hcd_urb_get_error_count(dwc_otg_urb);
+		for (i = 0; i < urb->number_of_packets; ++i) {
+			urb->iso_frame_desc[i].actual_length =
+			    dwc_otg_hcd_urb_get_iso_desc_actual_length
+			    (dwc_otg_urb, i);
+			urb->iso_frame_desc[i].status =
+			    dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_urb, i);
+		}
+	}
+
+	urb->status = status;
+	urb->hcpriv = NULL;
+	if (!status) {
+		if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+		    (urb->actual_length < urb->transfer_buffer_length)) {
+			urb->status = -EREMOTEIO;
+		}
+	}
+
+	if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) ||
+	    (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
+		struct usb_host_endpoint *ep = dwc_urb_to_endpoint(urb);
+		if (ep) {
+			free_bus_bandwidth(dwc_otg_hcd_to_hcd(hcd),
+					   dwc_otg_hcd_get_ep_bandwidth(hcd,
+									ep->hcpriv),
+					   urb);
+		}
+	}
+
+	DWC_FREE(dwc_otg_urb);
+
+	DWC_SPINUNLOCK(hcd->lock);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+	usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb);
+#else
+	usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, status);
+#endif
+	DWC_SPINLOCK(hcd->lock);
+
+	return 0;
+}
+
+static struct dwc_otg_hcd_function_ops hcd_fops = {
+	.start = _start,
+	.disconnect = _disconnect,
+	.hub_info = _hub_info,
+	.speed = _speed,
+	.complete = _complete,
+	.get_b_hnp_enable = _get_b_hnp_enable,
+};
+
+
+/*
+ * Controller Port Suspend Routiene.
+ */
+void dwc_otg_host_port_suspend(struct usb_hcd *hcd)
+{
+	dwc_otg_host_if_t host_if;
+	hprt0_data_t hprt;
+
+	host_if.hprt0 = hcd->regs + DWC_OTG_HOST_PORT_REGS_OFFSET;
+
+	hprt.d32= DWC_READ_REG32(host_if.hprt0);
+	hprt.b.prtsusp = 1;
+	DWC_WRITE_REG32(host_if.hprt0, hprt.d32);
+}
+
+
+/*
+ * Controller Port Resume Routiene.
+ */
+void dwc_otg_host_port_resume(struct usb_hcd *hcd)
+{
+	dwc_otg_host_if_t host_if;
+	hprt0_data_t hprt;
+
+	host_if.hprt0 = hcd->regs + DWC_OTG_HOST_PORT_REGS_OFFSET;
+
+	hprt.d32= DWC_READ_REG32(host_if.hprt0);
+	hprt.b.prtsusp = 0;
+	DWC_WRITE_REG32(host_if.hprt0, hprt.d32);
+}
+
+
+/**
+ * Initializes the HCD. This function allocates memory for and initializes the
+ * static parts of the usb_hcd and dwc_otg_hcd structures. It also registers the
+ * USB bus with the core and calls the hc_driver->start() function. It returns
+ * a negative error on failure.
+ */
+int hcd_init(
+#ifdef LM_INTERFACE
+		    struct lm_device *_dev
+#elif  defined(PCI_INTERFACE)
+		    struct pci_dev *_dev
+#else
+			struct platform_device *_dev
+#endif
+    )
+{
+	struct usb_hcd *hcd = NULL;
+	dwc_otg_hcd_t *dwc_otg_hcd = NULL;
+#ifdef LM_INTERFACE
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
+#elif  defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev);
+#endif
+
+	int retval = 0;
+
+	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT\n");
+
+	/* Set device flags indicating whether the HCD supports DMA. */
+	if (dwc_otg_is_dma_enable(otg_dev->core_if)) {
+#ifdef LM_INTERFACE
+		_dev->dev.dma_mask = (void *)~0;
+		_dev->dev.coherent_dma_mask = ~0;
+#elif  defined(PCI_INTERFACE)
+		pci_set_dma_mask(_dev, DMA_32BIT_MASK);
+		pci_set_consistent_dma_mask(_dev, DMA_32BIT_MASK);
+#endif
+
+	} else {
+#ifdef LM_INTERFACE
+		_dev->dev.dma_mask = (void *)0;
+		_dev->dev.coherent_dma_mask = 0;
+#elif  defined(PCI_INTERFACE)
+		pci_set_dma_mask(_dev, 0);
+		pci_set_consistent_dma_mask(_dev, 0);
+#endif
+	}
+
+	/*
+	 * Allocate memory for the base HCD plus the DWC OTG HCD.
+	 * Initialize the base HCD.
+	 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
+	hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, _dev->dev.bus_id);
+#else
+	hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, dev_name(&_dev->dev));
+	hcd->has_tt = 1;
+//      hcd->uses_new_polling = 1;
+//      hcd->poll_rh = 0;
+#endif
+	if (!hcd) {
+		retval = -ENOMEM;
+		goto error1;
+	}
+
+	hcd->regs = otg_dev->os_dep.base;
+
+	/* Initialize the DWC OTG HCD. */
+	dwc_otg_hcd = dwc_otg_hcd_alloc_hcd();
+	if (!dwc_otg_hcd) {
+		goto error2;
+	}
+	((struct wrapper_priv_data *)(hcd->hcd_priv))->dwc_otg_hcd =
+	    dwc_otg_hcd;
+	otg_dev->hcd = dwc_otg_hcd;
+
+	if (dwc_otg_hcd_init(dwc_otg_hcd, otg_dev->core_if)) {
+		goto error2;
+	}
+
+	otg_dev->hcd->otg_dev = otg_dev;
+	hcd->self.otg_port = dwc_otg_hcd_otg_port(dwc_otg_hcd);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33) //don't support for LM(with 2.6.20.1 kernel)
+	/* Don't support SG list at this point */
+	hcd->self.sg_tablesize = 0;
+#endif
+	/*
+	 * Finish generic HCD initialization and start the HCD. This function
+	 * allocates the DMA buffer pool, registers the USB bus, requests the
+	 * IRQ line, and calls hcd_start method.
+	 */
+	retval = usb_add_hcd(hcd, otg_dev->irq, IRQF_SHARED | IRQF_DISABLED);
+	if (retval < 0) {
+		goto error2;
+	}
+
+	dwc_otg_hcd_set_priv_data(dwc_otg_hcd, hcd);
+	return 0;
+
+error2:
+	usb_put_hcd(hcd);
+error1:
+	return retval;
+}
+
+/**
+ * Removes the HCD.
+ * Frees memory and resources associated with the HCD and deregisters the bus.
+ */
+void hcd_remove(
+#ifdef LM_INTERFACE
+		       struct lm_device *_dev
+#elif  defined(PCI_INTERFACE)
+		       struct pci_dev *_dev
+#else
+				struct platform_device *_dev
+#endif
+    )
+{
+#ifdef LM_INTERFACE
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
+#elif  defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
+#else
+	dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev);
+#endif
+
+	dwc_otg_hcd_t *dwc_otg_hcd;
+	struct usb_hcd *hcd;
+
+	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD REMOVE\n");
+
+	if (!otg_dev) {
+		DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__);
+		return;
+	}
+
+	dwc_otg_hcd = otg_dev->hcd;
+
+	if (!dwc_otg_hcd) {
+		DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__);
+		return;
+	}
+
+	hcd = dwc_otg_hcd_to_hcd(dwc_otg_hcd);
+
+	if (!hcd) {
+		DWC_DEBUGPL(DBG_ANY,
+			    "%s: dwc_otg_hcd_to_hcd(dwc_otg_hcd) NULL!\n",
+			    __func__);
+		return;
+	}
+	usb_remove_hcd(hcd);
+	dwc_otg_hcd_set_priv_data(dwc_otg_hcd, NULL);
+	dwc_otg_hcd_remove(dwc_otg_hcd);
+	usb_put_hcd(hcd);
+}
+
+/* =========================================================================
+ *  Linux HC Driver Functions
+ * ========================================================================= */
+
+/** Initializes the DWC_otg controller and its root hub and prepares it for host
+ * mode operation. Activates the root port. Returns 0 on success and a negative
+ * error code on failure. */
+int hcd_start(struct usb_hcd *hcd)
+{
+	dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+	struct usb_bus *bus;
+
+	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD START\n");
+	bus = hcd_to_bus(hcd);
+
+	hcd->state = HC_STATE_RUNNING;
+	if (dwc_otg_hcd_start(dwc_otg_hcd, &hcd_fops)) {
+		return 0;
+	}
+
+	/* Initialize and connect root hub if one is not already attached */
+	if (bus->root_hub) {
+		DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Has Root Hub\n");
+		/* Inform the HUB driver to resume. */
+		usb_hcd_resume_root_hub(hcd);
+	}
+
+	return 0;
+}
+
+/**
+ * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
+ * stopped.
+ */
+void hcd_stop(struct usb_hcd *hcd)
+{
+	dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+
+	dwc_otg_hcd_stop(dwc_otg_hcd);
+}
+
+/** Returns the current frame number. */
+static int get_frame_number(struct usb_hcd *hcd)
+{
+	dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+
+	return dwc_otg_hcd_get_frame_number(dwc_otg_hcd);
+}
+
+#ifdef DEBUG
+static void dump_urb_info(struct urb *urb, char *fn_name)
+{
+	DWC_PRINTF("%s, urb %p\n", fn_name, urb);
+	DWC_PRINTF("  Device address: %d\n", usb_pipedevice(urb->pipe));
+	DWC_PRINTF("  Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe),
+		   (usb_pipein(urb->pipe) ? "IN" : "OUT"));
+	DWC_PRINTF("  Endpoint type: %s\n", ( {
+					     char *pipetype;
+					     switch (usb_pipetype(urb->pipe)) {
+case PIPE_CONTROL:
+pipetype = "CONTROL"; break; case PIPE_BULK:
+pipetype = "BULK"; break; case PIPE_INTERRUPT:
+pipetype = "INTERRUPT"; break; case PIPE_ISOCHRONOUS:
+pipetype = "ISOCHRONOUS"; break; default:
+					     pipetype = "UNKNOWN"; break;};
+					     pipetype;}
+		   )) ;
+	DWC_PRINTF("  Speed: %s\n", ( {
+				     char *speed; switch (urb->dev->speed) {
+case USB_SPEED_HIGH:
+speed = "HIGH"; break; case USB_SPEED_FULL:
+speed = "FULL"; break; case USB_SPEED_LOW:
+speed = "LOW"; break; default:
+				     speed = "UNKNOWN"; break;};
+				     speed;}
+		   )) ;
+	DWC_PRINTF("  Max packet size: %d\n",
+		   usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)));
+	DWC_PRINTF("  Data buffer length: %d\n", urb->transfer_buffer_length);
+	DWC_PRINTF("  Transfer buffer: %p, Transfer DMA: %p\n",
+		   urb->transfer_buffer, (void *)urb->transfer_dma);
+	DWC_PRINTF("  Setup buffer: %p, Setup DMA: %p\n",
+		   urb->setup_packet, (void *)urb->setup_dma);
+	DWC_PRINTF("  Interval: %d\n", urb->interval);
+	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+		int i;
+		for (i = 0; i < urb->number_of_packets; i++) {
+			DWC_PRINTF("  ISO Desc %d:\n", i);
+			DWC_PRINTF("    offset: %d, length %d\n",
+				   urb->iso_frame_desc[i].offset,
+				   urb->iso_frame_desc[i].length);
+		}
+	}
+}
+
+#endif
+
+/** Starts processing a USB transfer request specified by a USB Request Block
+ * (URB). mem_flags indicates the type of memory allocation to use while
+ * processing this URB. */
+static int urb_enqueue(struct usb_hcd *hcd,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+		       struct usb_host_endpoint *ep,
+#endif
+		       struct urb *urb, gfp_t mem_flags)
+{
+	int retval = 0;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
+	struct usb_host_endpoint *ep = urb->ep;
+#endif
+	dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+	dwc_otg_hcd_urb_t *dwc_otg_urb;
+	int i;
+	int alloc_bandwidth = 0;
+	uint8_t ep_type = 0;
+	uint32_t flags = 0;
+	void *buf;
+
+#ifdef DEBUG
+	if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
+		dump_urb_info(urb, "urb_enqueue");
+	}
+#endif
+
+	if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
+	    || (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
+		if (!dwc_otg_hcd_is_bandwidth_allocated
+		    (dwc_otg_hcd, &ep->hcpriv)) {
+			alloc_bandwidth = 1;
+		}
+	}
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+		ep_type = USB_ENDPOINT_XFER_CONTROL;
+		break;
+	case PIPE_ISOCHRONOUS:
+		ep_type = USB_ENDPOINT_XFER_ISOC;
+		break;
+	case PIPE_BULK:
+		ep_type = USB_ENDPOINT_XFER_BULK;
+		break;
+	case PIPE_INTERRUPT:
+		ep_type = USB_ENDPOINT_XFER_INT;
+		break;
+	default:
+		DWC_WARN("Wrong ep type\n");
+	}
+
+	dwc_otg_urb = dwc_otg_hcd_urb_alloc(dwc_otg_hcd,
+					    urb->number_of_packets,
+					    mem_flags == GFP_ATOMIC ? 1 : 0);
+
+	dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_urb, usb_pipedevice(urb->pipe),
+				     usb_pipeendpoint(urb->pipe), ep_type,
+				     usb_pipein(urb->pipe),
+				     usb_maxpacket(urb->dev, urb->pipe,
+						   !(usb_pipein(urb->pipe))));
+
+	buf = urb->transfer_buffer;
+	if (hcd->self.uses_dma) {
+		/*
+		 * Calculate virtual address from physical address,
+		 * because some class driver may not fill transfer_buffer.
+		 * In Buffer DMA mode virual address is used,
+		 * when handling non DWORD aligned buffers.
+		 */
+		buf = phys_to_virt(urb->transfer_dma);
+	}
+
+	if (!(urb->transfer_flags & URB_NO_INTERRUPT))
+		flags |= URB_GIVEBACK_ASAP;
+	if (urb->transfer_flags & URB_ZERO_PACKET)
+		flags |= URB_SEND_ZERO_PACKET;
+
+	dwc_otg_hcd_urb_set_params(dwc_otg_urb, urb, buf,
+				   urb->transfer_dma,
+				   urb->transfer_buffer_length,
+				   urb->setup_packet,
+				   urb->setup_dma, flags, urb->interval);
+
+	for (i = 0; i < urb->number_of_packets; ++i) {
+		dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_urb, i,
+						    urb->
+						    iso_frame_desc[i].offset,
+						    urb->
+						    iso_frame_desc[i].length);
+	}
+
+	urb->hcpriv = dwc_otg_urb;
+	retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb, &ep->hcpriv,
+					 mem_flags == GFP_ATOMIC ? 1 : 0);
+	if (!retval) {
+		if (alloc_bandwidth) {
+			allocate_bus_bandwidth(hcd,
+					       dwc_otg_hcd_get_ep_bandwidth
+					       (dwc_otg_hcd, ep->hcpriv), urb);
+		}
+	} else {
+		if (retval == -DWC_E_NO_DEVICE) {
+			retval = -ENODEV;
+		}
+	}
+
+	return retval;
+}
+
+/** Aborts/cancels a USB transfer request. Always returns 0 to indicate
+ * success.  */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+#else
+static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+#endif
+{
+	dwc_irqflags_t flags;
+	dwc_otg_hcd_t *dwc_otg_hcd;
+	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue\n");
+
+	dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+
+#ifdef DEBUG
+	if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
+		dump_urb_info(urb, "urb_dequeue");
+	}
+#endif
+
+	DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
+
+	dwc_otg_hcd_urb_dequeue(dwc_otg_hcd, urb->hcpriv);
+
+	DWC_FREE(urb->hcpriv);
+	urb->hcpriv = NULL;
+	DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
+
+	/* Higher layer software sets URB status. */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+	usb_hcd_giveback_urb(hcd, urb);
+#else
+	usb_hcd_giveback_urb(hcd, urb, status);
+#endif
+	if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
+		DWC_PRINTF("Called usb_hcd_giveback_urb()\n");
+		DWC_PRINTF("  urb->status = %d\n", urb->status);
+	}
+
+	return 0;
+}
+
+/* Frees resources in the DWC_otg controller related to a given endpoint. Also
+ * clears state in the HCD related to the endpoint. Any URBs for the endpoint
+ * must already be dequeued. */
+static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
+{
+	dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+
+	DWC_DEBUGPL(DBG_HCD,
+		    "DWC OTG HCD EP DISABLE: _bEndpointAddress=0x%02x, "
+		    "endpoint=%d\n", ep->desc.bEndpointAddress,
+		    dwc_ep_addr_to_endpoint(ep->desc.bEndpointAddress));
+	dwc_otg_hcd_endpoint_disable(dwc_otg_hcd, ep->hcpriv, 250);
+	ep->hcpriv = NULL;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
+/* Resets endpoint specific parameter values, in current version used to reset
+ * the data toggle(as a WA). This function can be called from usb_clear_halt routine */
+static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
+{
+	dwc_irqflags_t flags;
+	struct usb_device *udev = NULL;
+	int epnum = usb_endpoint_num(&ep->desc);
+	int is_out = usb_endpoint_dir_out(&ep->desc);
+	int is_control = usb_endpoint_xfer_control(&ep->desc);
+	dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+#ifdef LM_INTERFACE
+	struct lm_device *_dev = dwc_otg_hcd->otg_dev->os_dep.lmdev;
+#elif defined(PCI_INTERFACE)
+	struct pci_dev *_dev = dwc_otg_hcd->otg_dev->os_dep.pcidev;
+#else
+	struct device *_dev = dwc_otg_hcd->otg_dev->os_dep.parent;
+#endif
+
+	if (_dev)
+		udev = to_usb_device(_dev);
+	else
+		return;
+
+	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD EP RESET: Endpoint Num=0x%02d\n", epnum);
+
+	DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
+	usb_settoggle(udev, epnum, is_out, 0);
+	if (is_control)
+		usb_settoggle(udev, epnum, !is_out, 0);
+
+	if (ep->hcpriv) {
+		dwc_otg_hcd_endpoint_reset(dwc_otg_hcd, ep->hcpriv);
+	}
+	DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
+}
+#endif
+
+/** Handles host mode interrupts for the DWC_otg controller. Returns IRQ_NONE if
+ * there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid
+ * interrupt.
+ *
+ * This function is called by the USB core when an interrupt occurs */
+static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd)
+{
+	dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+	int32_t retval = dwc_otg_hcd_handle_intr(dwc_otg_hcd);
+	if (retval != 0) {
+		S3C2410X_CLEAR_EINTPEND();
+	}
+	return IRQ_RETVAL(retval);
+}
+
+/** Creates Status Change bitmap for the root hub and root port. The bitmap is
+ * returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1
+ * is the status change indicator for the single root port. Returns 1 if either
+ * change indicator is 1, otherwise returns 0. */
+int hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+	dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+
+	buf[0] = 0;
+	buf[0] |= (dwc_otg_hcd_is_status_changed(dwc_otg_hcd, 1)) << 1;
+
+	return (buf[0] != 0);
+}
+
+/** Handles hub class-specific requests. */
+int hub_control(struct usb_hcd *hcd,
+		u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength)
+{
+	int retval;
+
+	retval = dwc_otg_hcd_hub_control(hcd_to_dwc_otg_hcd(hcd),
+					 typeReq, wValue, wIndex, buf, wLength);
+
+	switch (retval) {
+	case -DWC_E_INVALID:
+		retval = -EINVAL;
+		break;
+	}
+
+	return retval;
+}
+
+#endif /* DWC_DEVICE_ONLY */
diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd_queue.c b/drivers/usb/dwc_otg/dwc_otg_hcd_queue.c
new file mode 100644
index 0000000..903a902
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_hcd_queue.c
@@ -0,0 +1,726 @@
+/* ==========================================================================
+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_queue.c $
+ * $Revision: #44 $
+ * $Date: 2011/10/26 $
+ * $Change: 1873028 $
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ * 
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ * 
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+#ifndef DWC_DEVICE_ONLY
+
+/**
+ * @file
+ *
+ * This file contains the functions to manage Queue Heads and Queue
+ * Transfer Descriptors.
+ */
+
+#include "dwc_otg_hcd.h"
+#include "dwc_otg_regs.h"
+
+/** 
+ * Free each QTD in the QH's QTD-list then free the QH.  QH should already be
+ * removed from a list.  QTD list should already be empty if called from URB
+ * Dequeue.
+ *
+ * @param hcd HCD instance.
+ * @param qh The QH to free.
+ */
+void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+{
+	dwc_otg_qtd_t *qtd, *qtd_tmp;
+
+	/* Free each QTD in the QTD list */
+	DWC_SPINLOCK(hcd->lock);
+	DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
+		DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
+		dwc_otg_hcd_qtd_free(qtd);
+	}
+
+	if (hcd->core_if->dma_desc_enable) {
+		dwc_otg_hcd_qh_free_ddma(hcd, qh);
+	} else if (qh->dw_align_buf) {
+		uint32_t buf_size;
+		if (qh->ep_type == UE_ISOCHRONOUS) {
+			buf_size = 4096;
+		} else {
+			buf_size = hcd->core_if->core_params->max_transfer_size;
+		}
+		DWC_DMA_FREE(buf_size, qh->dw_align_buf, qh->dw_align_buf_dma);
+	}
+
+	DWC_FREE(qh);
+	DWC_SPINUNLOCK(hcd->lock);
+	return;
+}
+
+#define BitStuffTime(bytecount)  ((8 * 7* bytecount) / 6)
+#define HS_HOST_DELAY		5	/* nanoseconds */
+#define FS_LS_HOST_DELAY	1000	/* nanoseconds */
+#define HUB_LS_SETUP		333	/* nanoseconds */
+#define NS_TO_US(ns)		((ns + 500) / 1000)
+				/* convert & round nanoseconds to microseconds */
+
+static uint32_t calc_bus_time(int speed, int is_in, int is_isoc, int bytecount)
+{
+	unsigned long retval;
+
+	switch (speed) {
+	case USB_SPEED_HIGH:
+		if (is_isoc) {
+			retval =
+			    ((38 * 8 * 2083) +
+			     (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
+			    HS_HOST_DELAY;
+		} else {
+			retval =
+			    ((55 * 8 * 2083) +
+			     (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
+			    HS_HOST_DELAY;
+		}
+		break;
+	case USB_SPEED_FULL:
+		if (is_isoc) {
+			retval =
+			    (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
+			if (is_in) {
+				retval = 7268 + FS_LS_HOST_DELAY + retval;
+			} else {
+				retval = 6265 + FS_LS_HOST_DELAY + retval;
+			}
+		} else {
+			retval =
+			    (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
+			retval = 9107 + FS_LS_HOST_DELAY + retval;
+		}
+		break;
+	case USB_SPEED_LOW:
+		if (is_in) {
+			retval =
+			    (67667 * (31 + 10 * BitStuffTime(bytecount))) /
+			    1000;
+			retval =
+			    64060 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
+			    retval;
+		} else {
+			retval =
+			    (66700 * (31 + 10 * BitStuffTime(bytecount))) /
+			    1000;
+			retval =
+			    64107 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
+			    retval;
+		}
+		break;
+	default:
+		DWC_WARN("Unknown device speed\n");
+		retval = -1;
+	}
+
+	return NS_TO_US(retval);
+}
+
+/** 
+ * Initializes a QH structure.
+ *
+ * @param hcd The HCD state structure for the DWC OTG controller.
+ * @param qh  The QH to init.
+ * @param urb Holds the information about the device/endpoint that we need
+ * 	      to initialize the QH. 
+ */
+#define SCHEDULE_SLOP 10
+void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb)
+{
+	char *speed, *type;
+	int dev_speed;
+	uint32_t hub_addr, hub_port;
+
+	dwc_memset(qh, 0, sizeof(dwc_otg_qh_t));
+
+	/* Initialize QH */
+	qh->ep_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
+	qh->ep_is_in = dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? 1 : 0;
+
+	qh->data_toggle = DWC_OTG_HC_PID_DATA0;
+	qh->maxp = dwc_otg_hcd_get_mps(&urb->pipe_info);
+	DWC_CIRCLEQ_INIT(&qh->qtd_list);
+	DWC_LIST_INIT(&qh->qh_list_entry);
+	qh->channel = NULL;
+
+	/* FS/LS Enpoint on HS Hub 
+	 * NOT virtual root hub */
+	dev_speed = hcd->fops->speed(hcd, urb->priv);
+
+	hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &hub_port);
+	qh->do_split = 0;
+
+	if (((dev_speed == USB_SPEED_LOW) ||
+	     (dev_speed == USB_SPEED_FULL)) &&
+	    (hub_addr != 0 && hub_addr != 1)) {
+		DWC_DEBUGPL(DBG_HCD,
+			    "QH init: EP %d: TT found at hub addr %d, for port %d\n",
+			    dwc_otg_hcd_get_ep_num(&urb->pipe_info), hub_addr,
+			    hub_port);
+		qh->do_split = 1;
+	}
+
+	if (qh->ep_type == UE_INTERRUPT || qh->ep_type == UE_ISOCHRONOUS) {
+		/* Compute scheduling parameters once and save them. */
+		hprt0_data_t hprt;
+
+		/** @todo Account for split transfers in the bus time. */
+		int bytecount =
+		    dwc_hb_mult(qh->maxp) * dwc_max_packet(qh->maxp);
+
+		qh->usecs =
+		    calc_bus_time((qh->do_split ? USB_SPEED_HIGH : dev_speed),
+				  qh->ep_is_in, (qh->ep_type == UE_ISOCHRONOUS),
+				  bytecount);
+		/* Start in a slightly future (micro)frame. */
+		qh->sched_frame = dwc_frame_num_inc(hcd->frame_number,
+						    SCHEDULE_SLOP);
+		qh->interval = urb->interval;
+
+#if 0
+		/* Increase interrupt polling rate for debugging. */
+		if (qh->ep_type == UE_INTERRUPT) {
+			qh->interval = 8;
+		}
+#endif
+		hprt.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0);
+		if ((hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) &&
+		    ((dev_speed == USB_SPEED_LOW) ||
+		     (dev_speed == USB_SPEED_FULL))) {
+			qh->interval *= 8;
+			qh->sched_frame |= 0x7;
+			qh->start_split_frame = qh->sched_frame;
+		}
+
+	}
+
+	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n");
+	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - qh = %p\n", qh);
+	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Device Address = %d\n",
+		    dwc_otg_hcd_get_dev_addr(&urb->pipe_info));
+	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Endpoint %d, %s\n",
+		    dwc_otg_hcd_get_ep_num(&urb->pipe_info),
+		    dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT");
+	switch (dev_speed) {
+	case USB_SPEED_LOW:
+		qh->dev_speed = DWC_OTG_EP_SPEED_LOW;
+		speed = "low";
+		break;
+	case USB_SPEED_FULL:
+		qh->dev_speed = DWC_OTG_EP_SPEED_FULL;
+		speed = "full";
+		break;
+	case USB_SPEED_HIGH:
+		qh->dev_speed = DWC_OTG_EP_SPEED_HIGH;
+		speed = "high";
+		break;
+	default:
+		speed = "?";
+		break;
+	}
+	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Speed = %s\n", speed);
+
+	switch (qh->ep_type) {
+	case UE_ISOCHRONOUS:
+		type = "isochronous";
+		break;
+	case UE_INTERRUPT:
+		type = "interrupt";
+		break;
+	case UE_CONTROL:
+		type = "control";
+		break;
+	case UE_BULK:
+		type = "bulk";
+		break;
+	default:
+		type = "?";
+		break;
+	}
+
+	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Type = %s\n", type);
+
+#ifdef DEBUG
+	if (qh->ep_type == UE_INTERRUPT) {
+		DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - usecs = %d\n",
+			    qh->usecs);
+		DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - interval = %d\n",
+			    qh->interval);
+	}
+#endif
+
+}
+
+/**
+ * This function allocates and initializes a QH.
+ *
+ * @param hcd The HCD state structure for the DWC OTG controller.
+ * @param urb Holds the information about the device/endpoint that we need
+ * 	      to initialize the QH.
+ * @param atomic_alloc Flag to do atomic allocation if needed
+ *
+ * @return Returns pointer to the newly allocated QH, or NULL on error. */
+dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
+				    dwc_otg_hcd_urb_t * urb, int atomic_alloc)
+{
+	dwc_otg_qh_t *qh;
+
+	/* Allocate memory */
+	/** @todo add memflags argument */
+	qh = dwc_otg_hcd_qh_alloc(atomic_alloc);
+	if (qh == NULL) {
+		DWC_ERROR("qh allocation failed");
+		return NULL;
+	}
+
+	qh_init(hcd, qh, urb);
+
+	if (hcd->core_if->dma_desc_enable
+	    && (dwc_otg_hcd_qh_init_ddma(hcd, qh) < 0)) {
+		dwc_otg_hcd_qh_free(hcd, qh);
+		return NULL;
+	}
+
+	return qh;
+}
+
+/**
+ * Checks that a channel is available for a periodic transfer.
+ *
+ * @return 0 if successful, negative error code otherise.
+ */
+static int periodic_channel_available(dwc_otg_hcd_t * hcd)
+{
+	/*
+	 * Currently assuming that there is a dedicated host channnel for each
+	 * periodic transaction plus at least one host channel for
+	 * non-periodic transactions.
+	 */
+	int status;
+	int num_channels;
+
+	num_channels = hcd->core_if->core_params->host_channels;
+	if ((hcd->periodic_channels + hcd->non_periodic_channels < num_channels)
+	    && (hcd->periodic_channels < num_channels - 1)) {
+		status = 0;
+	} else {
+		DWC_INFO("%s: Total channels: %d, Periodic: %d, Non-periodic: %d\n",
+			__func__, num_channels, hcd->periodic_channels, hcd->non_periodic_channels);	//NOTICE
+		status = -DWC_E_NO_SPACE;
+	}
+
+	return status;
+}
+
+/**
+ * Checks that there is sufficient bandwidth for the specified QH in the
+ * periodic schedule. For simplicity, this calculation assumes that all the
+ * transfers in the periodic schedule may occur in the same (micro)frame.
+ *
+ * @param hcd The HCD state structure for the DWC OTG controller.
+ * @param qh QH containing periodic bandwidth required.
+ *
+ * @return 0 if successful, negative error code otherwise.
+ */
+static int check_periodic_bandwidth(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+{
+	int status;
+	int16_t max_claimed_usecs;
+
+	status = 0;
+
+	if ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) || qh->do_split) {
+		/*
+		 * High speed mode.
+		 * Max periodic usecs is 80% x 125 usec = 100 usec.
+		 */
+
+		max_claimed_usecs = 100 - qh->usecs;
+	} else {
+		/*
+		 * Full speed mode.
+		 * Max periodic usecs is 90% x 1000 usec = 900 usec.
+		 */
+		max_claimed_usecs = 900 - qh->usecs;
+	}
+
+	if (hcd->periodic_usecs > max_claimed_usecs) {
+		DWC_INFO("%s: already claimed usecs %d, required usecs %d\n", __func__, hcd->periodic_usecs, qh->usecs);	//NOTICE
+		status = -DWC_E_NO_SPACE;
+	}
+
+	return status;
+}
+
+/**
+ * Checks that the max transfer size allowed in a host channel is large enough
+ * to handle the maximum data transfer in a single (micro)frame for a periodic
+ * transfer.
+ *
+ * @param hcd The HCD state structure for the DWC OTG controller.
+ * @param qh QH for a periodic endpoint.
+ *
+ * @return 0 if successful, negative error code otherwise.
+ */
+static int check_max_xfer_size(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+{
+	int status;
+	uint32_t max_xfer_size;
+	uint32_t max_channel_xfer_size;
+
+	status = 0;
+
+	max_xfer_size = dwc_max_packet(qh->maxp) * dwc_hb_mult(qh->maxp);
+	max_channel_xfer_size = hcd->core_if->core_params->max_transfer_size;
+
+	if (max_xfer_size > max_channel_xfer_size) {
+		DWC_INFO("%s: Periodic xfer length %d > " "max xfer length for channel %d\n",
+				__func__, max_xfer_size, max_channel_xfer_size);	//NOTICE
+		status = -DWC_E_NO_SPACE;
+	}
+
+	return status;
+}
+
+/**
+ * Schedules an interrupt or isochronous transfer in the periodic schedule.
+ *
+ * @param hcd The HCD state structure for the DWC OTG controller.
+ * @param qh QH for the periodic transfer. The QH should already contain the
+ * scheduling information.
+ *
+ * @return 0 if successful, negative error code otherwise.
+ */
+static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+{
+	int status = 0;
+
+	status = periodic_channel_available(hcd);
+	if (status) {
+		DWC_INFO("%s: No host channel available for periodic " "transfer.\n", __func__);	//NOTICE
+		return status;
+	}
+
+	status = check_periodic_bandwidth(hcd, qh);
+	if (status) {
+		DWC_INFO("%s: Insufficient periodic bandwidth for " "periodic transfer.\n", __func__);	//NOTICE
+		return status;
+	}
+
+	status = check_max_xfer_size(hcd, qh);
+	if (status) {
+		DWC_INFO("%s: Channel max transfer size too small " "for periodic transfer.\n", __func__);	//NOTICE
+		return status;
+	}
+
+	if (hcd->core_if->dma_desc_enable) {
+		/* Don't rely on SOF and start in ready schedule */
+		DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_ready, &qh->qh_list_entry);
+	}
+	else {
+	/* Always start in the inactive schedule. */
+	DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_inactive, &qh->qh_list_entry);
+	}
+
+	/* Reserve the periodic channel. */
+	hcd->periodic_channels++;
+
+	/* Update claimed usecs per (micro)frame. */
+	hcd->periodic_usecs += qh->usecs;
+
+	return status;
+}
+
+/**
+ * This function adds a QH to either the non periodic or periodic schedule if
+ * it is not already in the schedule. If the QH is already in the schedule, no
+ * action is taken.
+ *
+ * @return 0 if successful, negative error code otherwise.
+ */
+int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+{
+	int status = 0;
+	gintmsk_data_t intr_mask = {.d32 = 0 };
+
+	if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
+		/* QH already in a schedule. */
+		return status;
+	}
+
+	/* Add the new QH to the appropriate schedule */
+	if (dwc_qh_is_non_per(qh)) {
+		/* Always start in the inactive schedule. */
+		DWC_LIST_INSERT_TAIL(&hcd->non_periodic_sched_inactive,
+				     &qh->qh_list_entry);
+	} else {
+		status = schedule_periodic(hcd, qh);
+		if ( !hcd->periodic_qh_count ) {
+			intr_mask.b.sofintr = 1;
+			DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk,
+								intr_mask.d32, intr_mask.d32);
+		}
+		hcd->periodic_qh_count++;
+	}
+
+	return status;
+}
+
+/**
+ * Removes an interrupt or isochronous transfer from the periodic schedule.
+ *
+ * @param hcd The HCD state structure for the DWC OTG controller.
+ * @param qh QH for the periodic transfer.
+ */
+static void deschedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+{
+	DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
+
+	/* Release the periodic channel reservation. */
+	hcd->periodic_channels--;
+
+	/* Update claimed usecs per (micro)frame. */
+	hcd->periodic_usecs -= qh->usecs;
+}
+
+/** 
+ * Removes a QH from either the non-periodic or periodic schedule.  Memory is
+ * not freed.
+ *
+ * @param hcd The HCD state structure.
+ * @param qh QH to remove from schedule. */
+void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+{
+	gintmsk_data_t intr_mask = {.d32 = 0 };
+
+	if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
+		/* QH is not in a schedule. */
+		return;
+	}
+
+	if (dwc_qh_is_non_per(qh)) {
+		if (hcd->non_periodic_qh_ptr == &qh->qh_list_entry) {
+			hcd->non_periodic_qh_ptr =
+			    hcd->non_periodic_qh_ptr->next;
+		}
+		DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
+	} else {
+		deschedule_periodic(hcd, qh);
+		hcd->periodic_qh_count--;
+		if( !hcd->periodic_qh_count ) {
+			intr_mask.b.sofintr = 1;
+				DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk,
+									intr_mask.d32, 0);
+		}
+	}
+}
+
+/**
+ * Deactivates a QH. For non-periodic QHs, removes the QH from the active
+ * non-periodic schedule. The QH is added to the inactive non-periodic
+ * schedule if any QTDs are still attached to the QH.
+ *
+ * For periodic QHs, the QH is removed from the periodic queued schedule. If
+ * there are any QTDs still attached to the QH, the QH is added to either the
+ * periodic inactive schedule or the periodic ready schedule and its next
+ * scheduled frame is calculated. The QH is placed in the ready schedule if
+ * the scheduled frame has been reached already. Otherwise it's placed in the
+ * inactive schedule. If there are no QTDs attached to the QH, the QH is
+ * completely removed from the periodic schedule.
+ */
+void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
+			       int sched_next_periodic_split)
+{	
+	if (dwc_qh_is_non_per(qh)) {
+		dwc_otg_hcd_qh_remove(hcd, qh);
+		if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
+			/* Add back to inactive non-periodic schedule. */
+			dwc_otg_hcd_qh_add(hcd, qh);
+		}
+	} else {
+		uint16_t frame_number = dwc_otg_hcd_get_frame_number(hcd);
+
+		if (qh->do_split) {
+			/* Schedule the next continuing periodic split transfer */
+			if (sched_next_periodic_split) {
+
+				qh->sched_frame = frame_number;
+				if (dwc_frame_num_le(frame_number,
+						     dwc_frame_num_inc
+						     (qh->start_split_frame,
+						      1))) {
+					/*
+					 * Allow one frame to elapse after start
+					 * split microframe before scheduling
+					 * complete split, but DONT if we are
+					 * doing the next start split in the
+					 * same frame for an ISOC out.
+					 */
+					if ((qh->ep_type != UE_ISOCHRONOUS) ||
+					    (qh->ep_is_in != 0)) {
+						qh->sched_frame =
+						    dwc_frame_num_inc(qh->sched_frame, 1);
+					}
+				}
+			} else {
+				qh->sched_frame =
+				    dwc_frame_num_inc(qh->start_split_frame,
+						      qh->interval);
+				if (dwc_frame_num_le
+				    (qh->sched_frame, frame_number)) {
+					qh->sched_frame = frame_number;
+				}
+				qh->sched_frame |= 0x7;
+				qh->start_split_frame = qh->sched_frame;
+			}
+		} else {
+			qh->sched_frame =
+			    dwc_frame_num_inc(qh->sched_frame, qh->interval);
+			if (dwc_frame_num_le(qh->sched_frame, frame_number)) {
+				qh->sched_frame = frame_number;
+			}
+		}
+
+		if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
+			dwc_otg_hcd_qh_remove(hcd, qh);
+		} else {
+			/*
+			 * Remove from periodic_sched_queued and move to
+			 * appropriate queue.
+			 */
+			if (qh->sched_frame == frame_number) {
+				DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
+						   &qh->qh_list_entry);
+			} else {
+				DWC_LIST_MOVE_HEAD
+				    (&hcd->periodic_sched_inactive,
+				     &qh->qh_list_entry);
+			}
+		}
+	}
+}
+
+/** 
+ * This function allocates and initializes a QTD. 
+ *
+ * @param urb The URB to create a QTD from.  Each URB-QTD pair will end up
+ * 	      pointing to each other so each pair should have a unique correlation.
+ * @param atomic_alloc Flag to do atomic alloc if needed
+ *
+ * @return Returns pointer to the newly allocated QTD, or NULL on error. */
+dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb, int atomic_alloc)
+{
+	dwc_otg_qtd_t *qtd;
+
+	qtd = dwc_otg_hcd_qtd_alloc(atomic_alloc);
+	if (qtd == NULL) {
+		return NULL;
+	}
+
+	dwc_otg_hcd_qtd_init(qtd, urb);
+	return qtd;
+}
+
+/** 
+ * Initializes a QTD structure.
+ *
+ * @param qtd The QTD to initialize.
+ * @param urb The URB to use for initialization.  */
+void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb)
+{
+	dwc_memset(qtd, 0, sizeof(dwc_otg_qtd_t));
+	qtd->urb = urb;
+	if (dwc_otg_hcd_get_pipe_type(&urb->pipe_info) == UE_CONTROL) {
+		/*
+		 * The only time the QTD data toggle is used is on the data
+		 * phase of control transfers. This phase always starts with
+		 * DATA1.
+		 */
+		qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
+		qtd->control_phase = DWC_OTG_CONTROL_SETUP;
+	}
+
+	/* start split */
+	qtd->complete_split = 0;
+	qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
+	qtd->isoc_split_offset = 0;
+	qtd->in_process = 0;
+
+	/* Store the qtd ptr in the urb to reference what QTD. */
+	urb->qtd = qtd;
+	return;
+}
+
+/**
+ * This function adds a QTD to the QTD-list of a QH.  It will find the correct
+ * QH to place the QTD into.  If it does not find a QH, then it will create a
+ * new QH. If the QH to which the QTD is added is not currently scheduled, it
+ * is placed into the proper schedule based on its EP type.
+ *
+ * @param[in] qtd The QTD to add
+ * @param[in] hcd The DWC HCD structure
+ * @param[out] qh out parameter to return queue head
+ * @param atomic_alloc Flag to do atomic alloc if needed
+ *
+ * @return 0 if successful, negative error code otherwise.
+ */
+int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd,
+			dwc_otg_hcd_t * hcd, dwc_otg_qh_t ** qh, int atomic_alloc)
+{
+	int retval = 0;
+	dwc_irqflags_t flags;
+
+	dwc_otg_hcd_urb_t *urb = qtd->urb;
+
+	/*
+	 * Get the QH which holds the QTD-list to insert to. Create QH if it
+	 * doesn't exist.
+	 */
+	if (*qh == NULL) {
+		*qh = dwc_otg_hcd_qh_create(hcd, urb, atomic_alloc);
+		if (*qh == NULL) {
+			retval = -1;
+			goto done;
+		}
+	}
+	DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
+	retval = dwc_otg_hcd_qh_add(hcd, *qh);
+	if (retval == 0) {
+		DWC_CIRCLEQ_INSERT_TAIL(&((*qh)->qtd_list), qtd,
+					qtd_list_entry);
+	}
+	DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
+
+done:
+
+	return retval;
+}
+
+#endif /* DWC_DEVICE_ONLY */
diff --git a/drivers/usb/dwc_otg/dwc_otg_os_dep.h b/drivers/usb/dwc_otg/dwc_otg_os_dep.h
new file mode 100644
index 0000000..1f8db73
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_os_dep.h
@@ -0,0 +1,111 @@
+#ifndef _DWC_OS_DEP_H_
+#define _DWC_OS_DEP_H_
+
+/**
+ * @file
+ *
+ * This file contains OS dependent structures.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/dma-mapping.h>
+#include <linux/jiffies.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <linux/stat.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+# include <linux/irq.h>
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
+# include <linux/usb/ch9.h>
+#else
+# include <linux/usb_ch9.h>
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+# include <linux/usb/gadget.h>
+#else
+# include <linux/usb_gadget.h>
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+# include <asm/irq.h>
+#endif
+
+#ifdef PCI_INTERFACE
+# include <asm/io.h>
+#endif
+
+#ifdef LM_INTERFACE
+# include <asm/unaligned.h>
+# include <asm/sizes.h>
+# include <asm/param.h>
+# include <asm/io.h>
+# include <asm/arch/lm.h>
+# include <asm/arch/irqs.h>
+# include <asm/arch/regs-irq.h>
+#else
+# include <asm/unaligned.h>
+# include <asm/sizes.h>
+# include <asm/param.h>
+# include <asm/io.h>
+# include <mach/irqs.h>
+#endif
+
+/** The OS page size */
+#define DWC_OS_PAGE_SIZE	PAGE_SIZE
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
+typedef int gfp_t;
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+# define IRQF_SHARED SA_SHIRQ
+#endif
+
+typedef struct os_dependent {
+	/** Base address returned from ioremap() */
+	void *base;
+
+	/** Register offset for Diagnostic API */
+	uint32_t reg_offset;
+
+#ifdef LM_INTERFACE
+	struct lm_device *lmdev;
+#elif  defined(PCI_INTERFACE)
+	struct pci_dev *pcidev;
+
+	/** Start address of a PCI region */
+	resource_size_t rsrc_start;
+	
+	/** Length address of a PCI region */
+	resource_size_t rsrc_len;
+#else
+	struct device *parent;	
+#endif
+} os_dependent_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DWC_OS_DEP_H_ */
diff --git a/drivers/usb/dwc_otg/dwc_otg_pcd.c b/drivers/usb/dwc_otg/dwc_otg_pcd.c
new file mode 100644
index 0000000..e6792e9
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_pcd.c
@@ -0,0 +1,2634 @@
+/* ==========================================================================
+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.c $
+ * $Revision: #99 $
+ * $Date: 2011/10/24 $
+ * $Change: 1871160 $
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+#ifndef DWC_HOST_ONLY
+
+/** @file
+ * This file implements PCD Core. All code in this file is portable and doesn't
+ * use any OS specific functions.
+ * PCD Core provides Interface, defined in <code><dwc_otg_pcd_if.h></code>
+ * header file, which can be used to implement OS specific PCD interface.
+ *
+ * An important function of the PCD is managing interrupts generated
+ * by the DWC_otg controller. The implementation of the DWC_otg device
+ * mode interrupt service routines is in dwc_otg_pcd_intr.c.
+ *
+ * @todo Add Device Mode test modes (Test J mode, Test K mode, etc).
+ * @todo Does it work when the request size is greater than DEPTSIZ
+ * transfer size
+ *
+ */
+
+#include "dwc_otg_pcd.h"
+
+#ifdef DWC_UTE_CFI
+#include "dwc_otg_cfi.h"
+
+extern int init_cfi(cfiobject_t * cfiobj);
+#endif
+
+/**
+ * Choose endpoint from ep arrays using usb_ep structure.
+ */
+static dwc_otg_pcd_ep_t *get_ep_from_handle(dwc_otg_pcd_t * pcd, void *handle)
+{
+	int i;
+	if (pcd->ep0.priv == handle) {
+		return &pcd->ep0;
+	}
+	for (i = 0; i < MAX_EPS_CHANNELS - 1; i++) {
+		if (pcd->in_ep[i].priv == handle)
+			return &pcd->in_ep[i];
+		if (pcd->out_ep[i].priv == handle)
+			return &pcd->out_ep[i];
+	}
+
+	return NULL;
+}
+
+/**
+ * This function completes a request.  It call's the request call back.
+ */
+void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep, dwc_otg_pcd_request_t * req,
+			  int32_t status)
+{
+	unsigned stopped = ep->stopped;
+	
+	DWC_DEBUGPL(DBG_PCDV, "%s(ep %p req %p)\n", __func__, ep, req);
+	DWC_CIRCLEQ_REMOVE_INIT(&ep->queue, req, queue_entry);
+
+	/* don't modify queue heads during completion callback */
+	ep->stopped = 1;
+	/* spin_unlock/spin_lock now done in fops->complete() */
+	ep->pcd->fops->complete(ep->pcd, ep->priv, req->priv, status,
+				req->actual);
+
+	if (ep->pcd->request_pending > 0) {
+		--ep->pcd->request_pending;
+	}
+
+	ep->stopped = stopped;
+	DWC_FREE(req);
+}
+
+/**
+ * This function terminates all the requsts in the EP request queue.
+ */
+void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep)
+{
+	dwc_otg_pcd_request_t *req;
+
+	ep->stopped = 1;
+
+	/* called with irqs blocked?? */
+	while (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
+		req = DWC_CIRCLEQ_FIRST(&ep->queue);
+		dwc_otg_request_done(ep, req, -DWC_E_SHUTDOWN);
+	}
+}
+
+void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd,
+		       const struct dwc_otg_pcd_function_ops *fops)
+{
+	pcd->fops = fops;
+}
+
+/**
+ * PCD Callback function for initializing the PCD when switching to
+ * device mode.
+ *
+ * @param p void pointer to the <code>dwc_otg_pcd_t</code>
+ */
+static int32_t dwc_otg_pcd_start_cb(void *p)
+{
+	dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+
+	/*
+	 * Initialized the Core for Device mode.
+	 */
+	if (dwc_otg_is_device_mode(core_if)) {
+		dwc_otg_core_dev_init(core_if);
+		/* Set core_if's lock pointer to the pcd->lock */
+		core_if->lock = pcd->lock;
+	}
+	return 1;
+}
+
+/** CFI-specific buffer allocation function for EP */
+#ifdef DWC_UTE_CFI
+uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr,
+			      size_t buflen, int flags)
+{
+	dwc_otg_pcd_ep_t *ep;
+	ep = get_ep_from_handle(pcd, pep);
+	if (!ep) {
+		DWC_WARN("bad ep\n");
+		return -DWC_E_INVALID;
+	}
+
+	return pcd->cfi->ops.ep_alloc_buf(pcd->cfi, pcd, ep, addr, buflen,
+					  flags);
+}
+#else
+uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr,
+			      size_t buflen, int flags);
+#endif
+
+/**
+ * PCD Callback function for notifying the PCD when resuming from
+ * suspend.
+ *
+ * @param p void pointer to the <code>dwc_otg_pcd_t</code>
+ */
+static int32_t dwc_otg_pcd_resume_cb(void *p)
+{
+	dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
+
+	if (pcd->fops->resume) {
+		pcd->fops->resume(pcd);
+	}
+
+	/* Stop the SRP timeout timer. */
+	if ((GET_CORE_IF(pcd)->core_params->phy_type != DWC_PHY_TYPE_PARAM_FS)
+	    || (!GET_CORE_IF(pcd)->core_params->i2c_enable)) {
+		if (GET_CORE_IF(pcd)->srp_timer_started) {
+			GET_CORE_IF(pcd)->srp_timer_started = 0;
+			DWC_TIMER_CANCEL(GET_CORE_IF(pcd)->srp_timer);
+		}
+	}
+	return 1;
+}
+
+/**
+ * PCD Callback function for notifying the PCD device is suspended.
+ *
+ * @param p void pointer to the <code>dwc_otg_pcd_t</code>
+ */
+static int32_t dwc_otg_pcd_suspend_cb(void *p)
+{
+	dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
+
+	if (pcd->fops->suspend) {
+		DWC_SPINUNLOCK(pcd->lock);
+		pcd->fops->suspend(pcd);
+		DWC_SPINLOCK(pcd->lock);
+	}
+
+	return 1;
+}
+
+/**
+ * PCD Callback function for stopping the PCD when switching to Host
+ * mode.
+ *
+ * @param p void pointer to the <code>dwc_otg_pcd_t</code>
+ */
+static int32_t dwc_otg_pcd_stop_cb(void *p)
+{
+	dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
+	extern void dwc_otg_pcd_stop(dwc_otg_pcd_t * _pcd);
+
+	dwc_otg_pcd_stop(pcd);
+	return 1;
+}
+
+/**
+ * PCD Callback structure for handling mode switching.
+ */
+static dwc_otg_cil_callbacks_t pcd_callbacks = {
+	.start = dwc_otg_pcd_start_cb,
+	.stop = dwc_otg_pcd_stop_cb,
+	.suspend = dwc_otg_pcd_suspend_cb,
+	.resume_wakeup = dwc_otg_pcd_resume_cb,
+	.p = 0,			/* Set at registration */
+};
+
+/**
+ * This function allocates a DMA Descriptor chain for the Endpoint
+ * buffer to be used for a transfer to/from the specified endpoint.
+ */
+dwc_otg_dev_dma_desc_t *dwc_otg_ep_alloc_desc_chain(dwc_dma_t * dma_desc_addr,
+						    uint32_t count)
+{
+	return DWC_DMA_ALLOC_ATOMIC(count * sizeof(dwc_otg_dev_dma_desc_t), 
+							dma_desc_addr);
+}
+
+/**
+ * This function frees a DMA Descriptor chain that was allocated by ep_alloc_desc.
+ */
+void dwc_otg_ep_free_desc_chain(dwc_otg_dev_dma_desc_t * desc_addr,
+				uint32_t dma_desc_addr, uint32_t count)
+{
+	DWC_DMA_FREE(count * sizeof(dwc_otg_dev_dma_desc_t), desc_addr,
+		     dma_desc_addr);
+}
+
+#ifdef DWC_EN_ISOC
+
+/**
+ * This function initializes a descriptor chain for Isochronous transfer
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param dwc_ep The EP to start the transfer on.
+ *
+ */
+void dwc_otg_iso_ep_start_ddma_transfer(dwc_otg_core_if_t * core_if,
+					dwc_ep_t * dwc_ep)
+{
+
+	dsts_data_t dsts = {.d32 = 0 };
+	depctl_data_t depctl = {.d32 = 0 };
+	volatile uint32_t *addr;
+	int i, j;
+	uint32_t len;
+
+	if (dwc_ep->is_in)
+		dwc_ep->desc_cnt = dwc_ep->buf_proc_intrvl / dwc_ep->bInterval;
+	else
+		dwc_ep->desc_cnt =
+		    dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
+		    dwc_ep->bInterval;
+
+	/** Allocate descriptors for double buffering */
+	dwc_ep->iso_desc_addr =
+	    dwc_otg_ep_alloc_desc_chain(&dwc_ep->iso_dma_desc_addr,
+					dwc_ep->desc_cnt * 2);
+	if (dwc_ep->desc_addr) {
+		DWC_WARN("%s, can't allocate DMA descriptor chain\n", __func__);
+		return;
+	}
+
+	dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
+
+	/** ISO OUT EP */
+	if (dwc_ep->is_in == 0) {
+		dev_dma_desc_sts_t sts = {.d32 = 0 };
+		dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr;
+		dma_addr_t dma_ad;
+		uint32_t data_per_desc;
+		dwc_otg_dev_out_ep_regs_t *out_regs =
+		    core_if->dev_if->out_ep_regs[dwc_ep->num];
+		int offset;
+
+		addr = &core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl;
+		dma_ad = (dma_addr_t) DWC_READ_REG32(&(out_regs->doepdma));
+
+		/** Buffer 0 descriptors setup */
+		dma_ad = dwc_ep->dma_addr0;
+
+		sts.b_iso_out.bs = BS_HOST_READY;
+		sts.b_iso_out.rxsts = 0;
+		sts.b_iso_out.l = 0;
+		sts.b_iso_out.sp = 0;
+		sts.b_iso_out.ioc = 0;
+		sts.b_iso_out.pid = 0;
+		sts.b_iso_out.framenum = 0;
+
+		offset = 0;
+		for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
+		     i += dwc_ep->pkt_per_frm) {
+
+			for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
+				uint32_t len = (j + 1) * dwc_ep->maxpacket;
+				if (len > dwc_ep->data_per_frame)
+					data_per_desc =
+					    dwc_ep->data_per_frame -
+					    j * dwc_ep->maxpacket;
+				else
+					data_per_desc = dwc_ep->maxpacket;
+				len = data_per_desc % 4;
+				if (len)
+					data_per_desc += 4 - len;
+
+				sts.b_iso_out.rxbytes = data_per_desc;
+				dma_desc->buf = dma_ad;
+				dma_desc->status.d32 = sts.d32;
+
+				offset += data_per_desc;
+				dma_desc++;
+				dma_ad += data_per_desc;
+			}
+		}
+
+		for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
+			uint32_t len = (j + 1) * dwc_ep->maxpacket;
+			if (len > dwc_ep->data_per_frame)
+				data_per_desc =
+				    dwc_ep->data_per_frame -
+				    j * dwc_ep->maxpacket;
+			else
+				data_per_desc = dwc_ep->maxpacket;
+			len = data_per_desc % 4;
+			if (len)
+				data_per_desc += 4 - len;
+			sts.b_iso_out.rxbytes = data_per_desc;
+			dma_desc->buf = dma_ad;
+			dma_desc->status.d32 = sts.d32;
+
+			offset += data_per_desc;
+			dma_desc++;
+			dma_ad += data_per_desc;
+		}
+
+		sts.b_iso_out.ioc = 1;
+		len = (j + 1) * dwc_ep->maxpacket;
+		if (len > dwc_ep->data_per_frame)
+			data_per_desc =
+			    dwc_ep->data_per_frame - j * dwc_ep->maxpacket;
+		else
+			data_per_desc = dwc_ep->maxpacket;
+		len = data_per_desc % 4;
+		if (len)
+			data_per_desc += 4 - len;
+		sts.b_iso_out.rxbytes = data_per_desc;
+
+		dma_desc->buf = dma_ad;
+		dma_desc->status.d32 = sts.d32;
+		dma_desc++;
+
+		/** Buffer 1 descriptors setup */
+		sts.b_iso_out.ioc = 0;
+		dma_ad = dwc_ep->dma_addr1;
+
+		offset = 0;
+		for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
+		     i += dwc_ep->pkt_per_frm) {
+			for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
+				uint32_t len = (j + 1) * dwc_ep->maxpacket;
+				if (len > dwc_ep->data_per_frame)
+					data_per_desc =
+					    dwc_ep->data_per_frame -
+					    j * dwc_ep->maxpacket;
+				else
+					data_per_desc = dwc_ep->maxpacket;
+				len = data_per_desc % 4;
+				if (len)
+					data_per_desc += 4 - len;
+
+				data_per_desc =
+				    sts.b_iso_out.rxbytes = data_per_desc;
+				dma_desc->buf = dma_ad;
+				dma_desc->status.d32 = sts.d32;
+
+				offset += data_per_desc;
+				dma_desc++;
+				dma_ad += data_per_desc;
+			}
+		}
+		for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
+			data_per_desc =
+			    ((j + 1) * dwc_ep->maxpacket >
+			     dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
+			    j * dwc_ep->maxpacket : dwc_ep->maxpacket;
+			data_per_desc +=
+			    (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
+			sts.b_iso_out.rxbytes = data_per_desc;
+			dma_desc->buf = dma_ad;
+			dma_desc->status.d32 = sts.d32;
+
+			offset += data_per_desc;
+			dma_desc++;
+			dma_ad += data_per_desc;
+		}
+
+		sts.b_iso_out.ioc = 1;
+		sts.b_iso_out.l = 1;
+		data_per_desc =
+		    ((j + 1) * dwc_ep->maxpacket >
+		     dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
+		    j * dwc_ep->maxpacket : dwc_ep->maxpacket;
+		data_per_desc +=
+		    (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
+		sts.b_iso_out.rxbytes = data_per_desc;
+
+		dma_desc->buf = dma_ad;
+		dma_desc->status.d32 = sts.d32;
+
+		dwc_ep->next_frame = 0;
+
+		/** Write dma_ad into DOEPDMA register */
+		DWC_WRITE_REG32(&(out_regs->doepdma),
+				(uint32_t) dwc_ep->iso_dma_desc_addr);
+
+	}
+	/** ISO IN EP */
+	else {
+		dev_dma_desc_sts_t sts = {.d32 = 0 };
+		dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr;
+		dma_addr_t dma_ad;
+		dwc_otg_dev_in_ep_regs_t *in_regs =
+		    core_if->dev_if->in_ep_regs[dwc_ep->num];
+		unsigned int frmnumber;
+		fifosize_data_t txfifosize, rxfifosize;
+
+		txfifosize.d32 =
+		    DWC_READ_REG32(&core_if->dev_if->
+				   in_ep_regs[dwc_ep->num]->dtxfsts);
+		rxfifosize.d32 =
+		    DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
+
+		addr = &core_if->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
+
+		dma_ad = dwc_ep->dma_addr0;
+
+		dsts.d32 =
+		    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
+
+		sts.b_iso_in.bs = BS_HOST_READY;
+		sts.b_iso_in.txsts = 0;
+		sts.b_iso_in.sp =
+		    (dwc_ep->data_per_frame % dwc_ep->maxpacket) ? 1 : 0;
+		sts.b_iso_in.ioc = 0;
+		sts.b_iso_in.pid = dwc_ep->pkt_per_frm;
+
+		frmnumber = dwc_ep->next_frame;
+
+		sts.b_iso_in.framenum = frmnumber;
+		sts.b_iso_in.txbytes = dwc_ep->data_per_frame;
+		sts.b_iso_in.l = 0;
+
+		/** Buffer 0 descriptors setup */
+		for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
+			dma_desc->buf = dma_ad;
+			dma_desc->status.d32 = sts.d32;
+			dma_desc++;
+
+			dma_ad += dwc_ep->data_per_frame;
+			sts.b_iso_in.framenum += dwc_ep->bInterval;
+		}
+
+		sts.b_iso_in.ioc = 1;
+		dma_desc->buf = dma_ad;
+		dma_desc->status.d32 = sts.d32;
+		++dma_desc;
+
+		/** Buffer 1 descriptors setup */
+		sts.b_iso_in.ioc = 0;
+		dma_ad = dwc_ep->dma_addr1;
+
+		for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
+		     i += dwc_ep->pkt_per_frm) {
+			dma_desc->buf = dma_ad;
+			dma_desc->status.d32 = sts.d32;
+			dma_desc++;
+
+			dma_ad += dwc_ep->data_per_frame;
+			sts.b_iso_in.framenum += dwc_ep->bInterval;
+
+			sts.b_iso_in.ioc = 0;
+		}
+		sts.b_iso_in.ioc = 1;
+		sts.b_iso_in.l = 1;
+
+		dma_desc->buf = dma_ad;
+		dma_desc->status.d32 = sts.d32;
+
+		dwc_ep->next_frame = sts.b_iso_in.framenum + dwc_ep->bInterval;
+
+		/** Write dma_ad into diepdma register */
+		DWC_WRITE_REG32(&(in_regs->diepdma),
+				(uint32_t) dwc_ep->iso_dma_desc_addr);
+	}
+	/** Enable endpoint, clear nak  */
+	depctl.d32 = 0;
+	depctl.b.epena = 1;
+	depctl.b.usbactep = 1;
+	depctl.b.cnak = 1;
+
+	DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
+	depctl.d32 = DWC_READ_REG32(addr);
+}
+
+/**
+ * This function initializes a descriptor chain for Isochronous transfer
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param ep The EP to start the transfer on.
+ *
+ */
+void dwc_otg_iso_ep_start_buf_transfer(dwc_otg_core_if_t * core_if,
+				       dwc_ep_t * ep)
+{
+	depctl_data_t depctl = {.d32 = 0 };
+	volatile uint32_t *addr;
+
+	if (ep->is_in) {
+		addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
+	} else {
+		addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
+	}
+
+	if (core_if->dma_enable == 0 || core_if->dma_desc_enable != 0) {
+		return;
+	} else {
+		deptsiz_data_t deptsiz = {.d32 = 0 };
+
+		ep->xfer_len =
+		    ep->data_per_frame * ep->buf_proc_intrvl / ep->bInterval;
+		ep->pkt_cnt =
+		    (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
+		ep->xfer_count = 0;
+		ep->xfer_buff =
+		    (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0;
+		ep->dma_addr =
+		    (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0;
+
+		if (ep->is_in) {
+			/* Program the transfer size and packet count
+			 *      as follows: xfersize = N * maxpacket +
+			 *      short_packet pktcnt = N + (short_packet
+			 *      exist ? 1 : 0) 
+			 */
+			deptsiz.b.mc = ep->pkt_per_frm;
+			deptsiz.b.xfersize = ep->xfer_len;
+			deptsiz.b.pktcnt =
+			    (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
+			DWC_WRITE_REG32(&core_if->dev_if->
+					in_ep_regs[ep->num]->dieptsiz,
+					deptsiz.d32);
+
+			/* Write the DMA register */
+			DWC_WRITE_REG32(&
+					(core_if->dev_if->
+					 in_ep_regs[ep->num]->diepdma),
+					(uint32_t) ep->dma_addr);
+
+		} else {
+			deptsiz.b.pktcnt =
+			    (ep->xfer_len + (ep->maxpacket - 1)) /
+			    ep->maxpacket;
+			deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
+
+			DWC_WRITE_REG32(&core_if->dev_if->
+					out_ep_regs[ep->num]->doeptsiz,
+					deptsiz.d32);
+
+			/* Write the DMA register */
+			DWC_WRITE_REG32(&
+					(core_if->dev_if->
+					 out_ep_regs[ep->num]->doepdma),
+					(uint32_t) ep->dma_addr);
+
+		}
+		/** Enable endpoint, clear nak  */
+		depctl.d32 = 0;
+		depctl.b.epena = 1;
+		depctl.b.cnak = 1;
+
+		DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
+	}
+}
+
+/**
+ * This function does the setup for a data transfer for an EP and
+ * starts the transfer. For an IN transfer, the packets will be
+ * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers,
+ * the packets are unloaded from the Rx FIFO in the ISR.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param ep The EP to start the transfer on.
+ */
+
+static void dwc_otg_iso_ep_start_transfer(dwc_otg_core_if_t * core_if,
+					  dwc_ep_t * ep)
+{
+	if (core_if->dma_enable) {
+		if (core_if->dma_desc_enable) {
+			if (ep->is_in) {
+				ep->desc_cnt = ep->pkt_cnt / ep->pkt_per_frm;
+			} else {
+				ep->desc_cnt = ep->pkt_cnt;
+			}
+			dwc_otg_iso_ep_start_ddma_transfer(core_if, ep);
+		} else {
+			if (core_if->pti_enh_enable) {
+				dwc_otg_iso_ep_start_buf_transfer(core_if, ep);
+			} else {
+				ep->cur_pkt_addr =
+				    (ep->proc_buf_num) ? ep->
+				    xfer_buff1 : ep->xfer_buff0;
+				ep->cur_pkt_dma_addr =
+				    (ep->proc_buf_num) ? ep->
+				    dma_addr1 : ep->dma_addr0;
+				dwc_otg_iso_ep_start_frm_transfer(core_if, ep);
+			}
+		}
+	} else {
+		ep->cur_pkt_addr =
+		    (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0;
+		ep->cur_pkt_dma_addr =
+		    (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0;
+		dwc_otg_iso_ep_start_frm_transfer(core_if, ep);
+	}
+}
+
+/**
+ * This function stops transfer for an EP and
+ * resets the ep's variables. 
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param ep The EP to start the transfer on.
+ */
+
+void dwc_otg_iso_ep_stop_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+{
+	depctl_data_t depctl = {.d32 = 0 };
+	volatile uint32_t *addr;
+
+	if (ep->is_in == 1) {
+		addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
+	} else {
+		addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
+	}
+
+	/* disable the ep */
+	depctl.d32 = DWC_READ_REG32(addr);
+
+	depctl.b.epdis = 1;
+	depctl.b.snak = 1;
+
+	DWC_WRITE_REG32(addr, depctl.d32);
+
+	if (core_if->dma_desc_enable &&
+	    ep->iso_desc_addr && ep->iso_dma_desc_addr) {
+		dwc_otg_ep_free_desc_chain(ep->iso_desc_addr,
+					   ep->iso_dma_desc_addr,
+					   ep->desc_cnt * 2);
+	}
+
+	/* reset varibales */
+	ep->dma_addr0 = 0;
+	ep->dma_addr1 = 0;
+	ep->xfer_buff0 = 0;
+	ep->xfer_buff1 = 0;
+	ep->data_per_frame = 0;
+	ep->data_pattern_frame = 0;
+	ep->sync_frame = 0;
+	ep->buf_proc_intrvl = 0;
+	ep->bInterval = 0;
+	ep->proc_buf_num = 0;
+	ep->pkt_per_frm = 0;
+	ep->pkt_per_frm = 0;
+	ep->desc_cnt = 0;
+	ep->iso_desc_addr = 0;
+	ep->iso_dma_desc_addr = 0;
+}
+
+int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle,
+			     uint8_t * buf0, uint8_t * buf1, dwc_dma_t dma0,
+			     dwc_dma_t dma1, int sync_frame, int dp_frame,
+			     int data_per_frame, int start_frame,
+			     int buf_proc_intrvl, void *req_handle,
+			     int atomic_alloc)
+{
+	dwc_otg_pcd_ep_t *ep;
+	dwc_irqflags_t flags = 0;
+	dwc_ep_t *dwc_ep;
+	int32_t frm_data;
+	dsts_data_t dsts;
+	dwc_otg_core_if_t *core_if;
+
+	ep = get_ep_from_handle(pcd, ep_handle);
+
+	if (!ep || !ep->desc || ep->dwc_ep.num == 0) {
+		DWC_WARN("bad ep\n");
+		return -DWC_E_INVALID;
+	}
+
+	DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
+	core_if = GET_CORE_IF(pcd);
+	dwc_ep = &ep->dwc_ep;
+
+	if (ep->iso_req_handle) {
+		DWC_WARN("ISO request in progress\n");
+	}
+
+	dwc_ep->dma_addr0 = dma0;
+	dwc_ep->dma_addr1 = dma1;
+
+	dwc_ep->xfer_buff0 = buf0;
+	dwc_ep->xfer_buff1 = buf1;
+
+	dwc_ep->data_per_frame = data_per_frame;
+
+	/** @todo - pattern data support is to be implemented in the future */
+	dwc_ep->data_pattern_frame = dp_frame;
+	dwc_ep->sync_frame = sync_frame;
+
+	dwc_ep->buf_proc_intrvl = buf_proc_intrvl;
+
+	dwc_ep->bInterval = 1 << (ep->desc->bInterval - 1);
+
+	dwc_ep->proc_buf_num = 0;
+
+	dwc_ep->pkt_per_frm = 0;
+	frm_data = ep->dwc_ep.data_per_frame;
+	while (frm_data > 0) {
+		dwc_ep->pkt_per_frm++;
+		frm_data -= ep->dwc_ep.maxpacket;
+	}
+
+	dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
+
+	if (start_frame == -1) {
+		dwc_ep->next_frame = dsts.b.soffn + 1;
+		if (dwc_ep->bInterval != 1) {
+			dwc_ep->next_frame =
+			    dwc_ep->next_frame + (dwc_ep->bInterval - 1 -
+						  dwc_ep->next_frame %
+						  dwc_ep->bInterval);
+		}
+	} else {
+		dwc_ep->next_frame = start_frame;
+	}
+
+	if (!core_if->pti_enh_enable) {
+		dwc_ep->pkt_cnt =
+		    dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
+		    dwc_ep->bInterval;
+	} else {
+		dwc_ep->pkt_cnt =
+		    (dwc_ep->data_per_frame *
+		     (dwc_ep->buf_proc_intrvl / dwc_ep->bInterval)
+		     - 1 + dwc_ep->maxpacket) / dwc_ep->maxpacket;
+	}
+
+	if (core_if->dma_desc_enable) {
+		dwc_ep->desc_cnt =
+		    dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
+		    dwc_ep->bInterval;
+	}
+
+	if (atomic_alloc) {
+		dwc_ep->pkt_info =
+		    DWC_ALLOC_ATOMIC(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
+	} else {
+		dwc_ep->pkt_info =
+		    DWC_ALLOC(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
+	}
+	if (!dwc_ep->pkt_info) {
+		DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+		return -DWC_E_NO_MEMORY;
+	}
+	if (core_if->pti_enh_enable) {
+		dwc_memset(dwc_ep->pkt_info, 0,
+			   sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
+	}
+
+	dwc_ep->cur_pkt = 0;
+	ep->iso_req_handle = req_handle;
+
+	DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+	dwc_otg_iso_ep_start_transfer(core_if, dwc_ep);
+	return 0;
+}
+
+int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle,
+			    void *req_handle)
+{
+	dwc_irqflags_t flags = 0;
+	dwc_otg_pcd_ep_t *ep;
+	dwc_ep_t *dwc_ep;
+
+	ep = get_ep_from_handle(pcd, ep_handle);
+	if (!ep || !ep->desc || ep->dwc_ep.num == 0) {
+		DWC_WARN("bad ep\n");
+		return -DWC_E_INVALID;
+	}
+	dwc_ep = &ep->dwc_ep;
+
+	dwc_otg_iso_ep_stop_transfer(GET_CORE_IF(pcd), dwc_ep);
+
+	DWC_FREE(dwc_ep->pkt_info);
+	DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
+	if (ep->iso_req_handle != req_handle) {
+		DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+		return -DWC_E_INVALID;
+	}
+
+	DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+
+	ep->iso_req_handle = 0;
+	return 0;
+}
+
+/**
+ * This function is used for perodical data exchnage between PCD and gadget drivers.
+ * for Isochronous EPs
+ *
+ *	- Every time a sync period completes this function is called to
+ *	  perform data exchange between PCD and gadget
+ */
+void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep,
+			     void *req_handle)
+{
+	int i;
+	dwc_ep_t *dwc_ep;
+
+	dwc_ep = &ep->dwc_ep;
+
+	DWC_SPINUNLOCK(ep->pcd->lock);
+	pcd->fops->isoc_complete(pcd, ep->priv, ep->iso_req_handle,
+				 dwc_ep->proc_buf_num ^ 0x1);
+	DWC_SPINLOCK(ep->pcd->lock);
+
+	for (i = 0; i < dwc_ep->pkt_cnt; ++i) {
+		dwc_ep->pkt_info[i].status = 0;
+		dwc_ep->pkt_info[i].offset = 0;
+		dwc_ep->pkt_info[i].length = 0;
+	}
+}
+
+int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd, void *ep_handle,
+				     void *iso_req_handle)
+{
+	dwc_otg_pcd_ep_t *ep;
+	dwc_ep_t *dwc_ep;
+
+	ep = get_ep_from_handle(pcd, ep_handle);
+	if (!ep->desc || ep->dwc_ep.num == 0) {
+		DWC_WARN("bad ep\n");
+		return -DWC_E_INVALID;
+	}
+	dwc_ep = &ep->dwc_ep;
+
+	return dwc_ep->pkt_cnt;
+}
+
+void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd, void *ep_handle,
+				       void *iso_req_handle, int packet,
+				       int *status, int *actual, int *offset)
+{
+	dwc_otg_pcd_ep_t *ep;
+	dwc_ep_t *dwc_ep;
+
+	ep = get_ep_from_handle(pcd, ep_handle);
+	if (!ep)
+		DWC_WARN("bad ep\n");
+
+	dwc_ep = &ep->dwc_ep;
+
+	*status = dwc_ep->pkt_info[packet].status;
+	*actual = dwc_ep->pkt_info[packet].length;
+	*offset = dwc_ep->pkt_info[packet].offset;
+}
+
+#endif /* DWC_EN_ISOC */
+
+static void dwc_otg_pcd_init_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * pcd_ep,
+				uint32_t is_in, uint32_t ep_num)
+{
+	/* Init EP structure */
+	pcd_ep->desc = 0;
+	pcd_ep->pcd = pcd;
+	pcd_ep->stopped = 1;
+	pcd_ep->queue_sof = 0;
+
+	/* Init DWC ep structure */
+	pcd_ep->dwc_ep.is_in = is_in;
+	pcd_ep->dwc_ep.num = ep_num;
+	pcd_ep->dwc_ep.active = 0;
+	pcd_ep->dwc_ep.tx_fifo_num = 0;
+	/* Control until ep is actvated */
+	pcd_ep->dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
+	pcd_ep->dwc_ep.maxpacket = MAX_PACKET_SIZE;
+	pcd_ep->dwc_ep.dma_addr = 0;
+	pcd_ep->dwc_ep.start_xfer_buff = 0;
+	pcd_ep->dwc_ep.xfer_buff = 0;
+	pcd_ep->dwc_ep.xfer_len = 0;
+	pcd_ep->dwc_ep.xfer_count = 0;
+	pcd_ep->dwc_ep.sent_zlp = 0;
+	pcd_ep->dwc_ep.total_len = 0;
+	pcd_ep->dwc_ep.desc_addr = 0;
+	pcd_ep->dwc_ep.dma_desc_addr = 0;
+	DWC_CIRCLEQ_INIT(&pcd_ep->queue);
+}
+
+/**
+ * Initialize ep's
+ */
+static void dwc_otg_pcd_reinit(dwc_otg_pcd_t * pcd)
+{
+	int i;
+	uint32_t hwcfg1;
+	dwc_otg_pcd_ep_t *ep;
+	int in_ep_cntr, out_ep_cntr;
+	uint32_t num_in_eps = (GET_CORE_IF(pcd))->dev_if->num_in_eps;
+	uint32_t num_out_eps = (GET_CORE_IF(pcd))->dev_if->num_out_eps;
+
+	/**
+	 * Initialize the EP0 structure.
+	 */
+	ep = &pcd->ep0;
+	dwc_otg_pcd_init_ep(pcd, ep, 0, 0);
+
+	in_ep_cntr = 0;
+	hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 3;
+	for (i = 1; in_ep_cntr < num_in_eps; i++) {
+		if ((hwcfg1 & 0x1) == 0) {
+			dwc_otg_pcd_ep_t *ep = &pcd->in_ep[in_ep_cntr];
+			in_ep_cntr++;
+			/**
+			 * @todo NGS: Add direction to EP, based on contents
+			 * of HWCFG1.  Need a copy of HWCFG1 in pcd structure?
+			 * sprintf(";r
+			 */
+			dwc_otg_pcd_init_ep(pcd, ep, 1 /* IN */ , i);
+
+			DWC_CIRCLEQ_INIT(&ep->queue);
+		}
+		hwcfg1 >>= 2;
+	}
+
+	out_ep_cntr = 0;
+	hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 2;
+	for (i = 1; out_ep_cntr < num_out_eps; i++) {
+		if ((hwcfg1 & 0x1) == 0) {
+			dwc_otg_pcd_ep_t *ep = &pcd->out_ep[out_ep_cntr];
+			out_ep_cntr++;
+			/**
+			 * @todo NGS: Add direction to EP, based on contents
+			 * of HWCFG1.  Need a copy of HWCFG1 in pcd structure?
+			 * sprintf(";r
+			 */
+			dwc_otg_pcd_init_ep(pcd, ep, 0 /* OUT */ , i);
+			DWC_CIRCLEQ_INIT(&ep->queue);
+		}
+		hwcfg1 >>= 2;
+	}
+
+	pcd->ep0state = EP0_DISCONNECT;
+	pcd->ep0.dwc_ep.maxpacket = MAX_EP0_SIZE;
+	pcd->ep0.dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
+}
+
+/**
+ * This function is called when the SRP timer expires. The SRP should
+ * complete within 6 seconds.
+ */
+static void srp_timeout(void *ptr)
+{
+	gotgctl_data_t gotgctl;
+	dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
+	volatile uint32_t *addr = &core_if->core_global_regs->gotgctl;
+
+	gotgctl.d32 = DWC_READ_REG32(addr);
+
+	core_if->srp_timer_started = 0;
+	
+	if (core_if->adp_enable) {
+		if (gotgctl.b.bsesvld == 0) {
+			gpwrdn_data_t gpwrdn = {.d32 = 0 };
+			DWC_PRINTF("SRP Timeout BSESSVLD = 0\n");
+			/* Power off the core */
+			if (core_if->power_down == 2) {
+				gpwrdn.b.pwrdnswtch = 1;
+				DWC_MODIFY_REG32(&core_if->core_global_regs->
+					gpwrdn, gpwrdn.d32, 0);
+			}
+
+			gpwrdn.d32 = 0;
+			gpwrdn.b.pmuintsel = 1;
+			gpwrdn.b.pmuactv = 1;
+			DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
+			dwc_otg_adp_probe_start(core_if);
+		} else {
+			DWC_PRINTF("SRP Timeout BSESSVLD = 1\n");
+			core_if->op_state = B_PERIPHERAL;
+			dwc_otg_core_init(core_if);
+			dwc_otg_enable_global_interrupts(core_if);
+			cil_pcd_start(core_if);
+		}
+	}
+
+	if ((core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS) &&
+	    (core_if->core_params->i2c_enable)) {
+		DWC_PRINTF("SRP Timeout\n");
+
+		if ((core_if->srp_success) && (gotgctl.b.bsesvld)) {
+			if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
+				core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
+			}
+
+			/* Clear Session Request */
+			gotgctl.d32 = 0;
+			gotgctl.b.sesreq = 1;
+			DWC_MODIFY_REG32(&core_if->core_global_regs->gotgctl,
+					 gotgctl.d32, 0);
+
+			core_if->srp_success = 0;
+		} else {
+			__DWC_ERROR("Device not connected/responding\n");
+			gotgctl.b.sesreq = 0;
+			DWC_WRITE_REG32(addr, gotgctl.d32);
+		}
+	} else if (gotgctl.b.sesreq) {
+		DWC_PRINTF("SRP Timeout\n");
+
+		__DWC_ERROR("Device not connected/responding\n");
+		gotgctl.b.sesreq = 0;
+		DWC_WRITE_REG32(addr, gotgctl.d32);
+	} else {
+		DWC_PRINTF(" SRP GOTGCTL=%0x\n", gotgctl.d32);
+	}
+}
+
+/**
+ * Tasklet
+ *
+ */
+extern void start_next_request(dwc_otg_pcd_ep_t * ep);
+
+static void start_xfer_tasklet_func(void *data)
+{
+	dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data;
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+
+	int i;
+	depctl_data_t diepctl;
+
+	DWC_DEBUGPL(DBG_PCDV, "Start xfer tasklet\n");
+
+	diepctl.d32 = DWC_READ_REG32(&core_if->dev_if->in_ep_regs[0]->diepctl);
+
+	if (pcd->ep0.queue_sof) {
+		pcd->ep0.queue_sof = 0;
+		start_next_request(&pcd->ep0);
+		// break;
+	}
+
+	for (i = 0; i < core_if->dev_if->num_in_eps; i++) {
+		depctl_data_t diepctl;
+		diepctl.d32 =
+		    DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl);
+
+		if (pcd->in_ep[i].queue_sof) {
+			pcd->in_ep[i].queue_sof = 0;
+			start_next_request(&pcd->in_ep[i]);
+			// break;
+		}
+	}
+
+	return;
+}
+
+/**
+ * This function initialized the PCD portion of the driver.
+ *
+ */
+dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if)
+{
+	dwc_otg_pcd_t *pcd = NULL;
+	dwc_otg_dev_if_t *dev_if;
+	int i;
+
+	/*
+	 * Allocate PCD structure
+	 */
+	pcd = DWC_ALLOC(sizeof(dwc_otg_pcd_t));
+
+	if (pcd == NULL) {
+		return NULL;
+	}
+
+	pcd->lock = DWC_SPINLOCK_ALLOC();
+	if (!pcd->lock) {
+		DWC_ERROR("Could not allocate lock for pcd");
+		DWC_FREE(pcd);
+		return NULL;
+	}
+	/* Set core_if's lock pointer to hcd->lock */
+	core_if->lock = pcd->lock;
+	pcd->core_if = core_if;
+
+	dev_if = core_if->dev_if;
+	dev_if->isoc_ep = NULL;
+
+	if (core_if->hwcfg4.b.ded_fifo_en) {
+		DWC_PRINTF("Dedicated Tx FIFOs mode\n");
+	} else {
+		DWC_PRINTF("Shared Tx FIFO mode\n");
+	}
+
+	/*
+	 * Initialized the Core for Device mode here if there is nod ADP support. 
+	 * Otherwise it will be done later in dwc_otg_adp_start routine.
+	 */																				 
+	if (dwc_otg_is_device_mode(core_if) /*&& !core_if->adp_enable*/) {
+		dwc_otg_core_dev_init(core_if);
+	}
+
+	/*
+	 * Register the PCD Callbacks.
+	 */
+	dwc_otg_cil_register_pcd_callbacks(core_if, &pcd_callbacks, pcd);
+
+	/*
+	 * Initialize the DMA buffer for SETUP packets
+	 */
+	if (GET_CORE_IF(pcd)->dma_enable) {
+		pcd->setup_pkt =
+		    DWC_DMA_ALLOC(sizeof(*pcd->setup_pkt) * 5,
+				  &pcd->setup_pkt_dma_handle);
+		if (pcd->setup_pkt == NULL) {
+			DWC_FREE(pcd);
+			return NULL;
+		}
+
+		pcd->status_buf =
+		    DWC_DMA_ALLOC(sizeof(uint16_t),
+				  &pcd->status_buf_dma_handle);
+		if (pcd->status_buf == NULL) {
+			DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5,
+				     pcd->setup_pkt, pcd->setup_pkt_dma_handle);
+			DWC_FREE(pcd);
+			return NULL;
+		}
+
+		if (GET_CORE_IF(pcd)->dma_desc_enable) {
+			dev_if->setup_desc_addr[0] =
+			    dwc_otg_ep_alloc_desc_chain(&dev_if->
+							dma_setup_desc_addr[0],
+							1);
+			dev_if->setup_desc_addr[1] =
+			    dwc_otg_ep_alloc_desc_chain(&dev_if->
+							dma_setup_desc_addr[1],
+							1);
+			dev_if->in_desc_addr =
+			    dwc_otg_ep_alloc_desc_chain(&dev_if->
+							dma_in_desc_addr, 1);
+			dev_if->out_desc_addr =
+			    dwc_otg_ep_alloc_desc_chain(&dev_if->
+							dma_out_desc_addr, 1);
+
+			if (dev_if->setup_desc_addr[0] == 0
+			    || dev_if->setup_desc_addr[1] == 0
+			    || dev_if->in_desc_addr == 0
+			    || dev_if->out_desc_addr == 0) {
+
+				if (dev_if->out_desc_addr)
+					dwc_otg_ep_free_desc_chain(dev_if->
+								   out_desc_addr,
+								   dev_if->
+								   dma_out_desc_addr,
+								   1);
+				if (dev_if->in_desc_addr)
+					dwc_otg_ep_free_desc_chain(dev_if->
+								   in_desc_addr,
+								   dev_if->
+								   dma_in_desc_addr,
+								   1);
+				if (dev_if->setup_desc_addr[1])
+					dwc_otg_ep_free_desc_chain(dev_if->
+								   setup_desc_addr
+								   [1],
+								   dev_if->
+								   dma_setup_desc_addr
+								   [1], 1);
+				if (dev_if->setup_desc_addr[0])
+					dwc_otg_ep_free_desc_chain(dev_if->
+								   setup_desc_addr
+								   [0],
+								   dev_if->
+								   dma_setup_desc_addr
+								   [0], 1);
+
+				DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5,
+					     pcd->setup_pkt,
+					     pcd->setup_pkt_dma_handle);
+				DWC_DMA_FREE(sizeof(*pcd->status_buf),
+					     pcd->status_buf,
+					     pcd->status_buf_dma_handle);
+
+				DWC_FREE(pcd);
+
+				return NULL;
+			}
+		}
+	} else {
+		pcd->setup_pkt = DWC_ALLOC(sizeof(*pcd->setup_pkt) * 5);
+		if (pcd->setup_pkt == NULL) {
+			DWC_FREE(pcd);
+			return NULL;
+		}
+
+		pcd->status_buf = DWC_ALLOC(sizeof(uint16_t));
+		if (pcd->status_buf == NULL) {
+			DWC_FREE(pcd->setup_pkt);
+			DWC_FREE(pcd);
+			return NULL;
+		}
+	}
+
+	dwc_otg_pcd_reinit(pcd);
+
+	/* Allocate the cfi object for the PCD */
+#ifdef DWC_UTE_CFI
+	pcd->cfi = DWC_ALLOC(sizeof(cfiobject_t));
+	if (NULL == pcd->cfi)
+		goto fail;
+	if (init_cfi(pcd->cfi)) {
+		CFI_INFO("%s: Failed to init the CFI object\n", __func__);
+		goto fail;
+	}
+#endif
+
+	/* Initialize tasklets */
+	pcd->start_xfer_tasklet = DWC_TASK_ALLOC("xfer_tasklet",
+						 start_xfer_tasklet_func, pcd);
+	pcd->test_mode_tasklet = DWC_TASK_ALLOC("test_mode_tasklet",
+						do_test_mode, pcd);
+
+	/* Initialize SRP timer */
+	core_if->srp_timer = DWC_TIMER_ALLOC("SRP TIMER", srp_timeout, core_if);
+	
+	if (core_if->core_params->dev_out_nak) {
+		/** 
+		* Initialize xfer timeout timer. Implemented for
+		* 2.93a feature "Device DDMA OUT NAK Enhancement"
+		*/
+		for(i = 0; i < MAX_EPS_CHANNELS; i++) {
+			pcd->core_if->ep_xfer_timer[i] =
+				DWC_TIMER_ALLOC("ep timer", ep_xfer_timeout,
+				&pcd->core_if->ep_xfer_info[i]);
+		}
+	}
+	
+	return pcd;
+#ifdef DWC_UTE_CFI
+fail:
+#endif
+	if (pcd->setup_pkt)
+		DWC_FREE(pcd->setup_pkt);
+	if (pcd->status_buf)
+		DWC_FREE(pcd->status_buf);
+#ifdef DWC_UTE_CFI
+	if (pcd->cfi)
+		DWC_FREE(pcd->cfi);
+#endif
+	if (pcd)
+		DWC_FREE(pcd);
+	return NULL;
+
+}
+
+/**
+ * Remove PCD specific data
+ */
+void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd)
+{
+	dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
+	int i;
+	if (pcd->core_if->core_params->dev_out_nak) {
+		for (i = 0; i < MAX_EPS_CHANNELS; i++) {
+			DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[i]);
+			pcd->core_if->ep_xfer_info[i].state = 0;
+		}
+	}
+
+	if (GET_CORE_IF(pcd)->dma_enable) {
+		DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5, pcd->setup_pkt,
+			     pcd->setup_pkt_dma_handle);
+		DWC_DMA_FREE(sizeof(uint16_t), pcd->status_buf,
+			     pcd->status_buf_dma_handle);
+		if (GET_CORE_IF(pcd)->dma_desc_enable) {
+			dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[0],
+						   dev_if->dma_setup_desc_addr
+						   [0], 1);
+			dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[1],
+						   dev_if->dma_setup_desc_addr
+						   [1], 1);
+			dwc_otg_ep_free_desc_chain(dev_if->in_desc_addr,
+						   dev_if->dma_in_desc_addr, 1);
+			dwc_otg_ep_free_desc_chain(dev_if->out_desc_addr,
+						   dev_if->dma_out_desc_addr,
+						   1);
+		}
+	} else {
+		DWC_FREE(pcd->setup_pkt);
+		DWC_FREE(pcd->status_buf);
+	}
+	DWC_SPINLOCK_FREE(pcd->lock);
+	/* Set core_if's lock pointer to NULL */
+	pcd->core_if->lock = NULL;
+
+	DWC_TASK_FREE(pcd->start_xfer_tasklet);
+	DWC_TASK_FREE(pcd->test_mode_tasklet);
+	if (pcd->core_if->core_params->dev_out_nak) {
+		for (i = 0; i < MAX_EPS_CHANNELS; i++) {
+			if (pcd->core_if->ep_xfer_timer[i]) {
+					DWC_TIMER_FREE(pcd->core_if->ep_xfer_timer[i]);
+			}
+		}
+	}
+
+/* Release the CFI object's dynamic memory */
+#ifdef DWC_UTE_CFI
+	if (pcd->cfi->ops.release) {
+		pcd->cfi->ops.release(pcd->cfi);
+	}
+#endif
+
+	DWC_FREE(pcd);
+}
+
+/**
+ * Returns whether registered pcd is dual speed or not
+ */
+uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd)
+{
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+
+	if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) ||
+	    ((core_if->hwcfg2.b.hs_phy_type == 2) &&
+	     (core_if->hwcfg2.b.fs_phy_type == 1) &&
+	     (core_if->core_params->ulpi_fs_ls))) {
+		return 0;
+	}
+
+	return 1;
+}
+
+/**
+ * Returns whether registered pcd is OTG capable or not
+ */
+uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd)
+{
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+	gusbcfg_data_t usbcfg = {.d32 = 0 };
+
+	usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
+	if (!usbcfg.b.srpcap || !usbcfg.b.hnpcap) {
+		return 0;
+	}
+
+	return 1;
+}
+
+/**
+ * This function assigns periodic Tx FIFO to an periodic EP
+ * in shared Tx FIFO mode
+ */
+static uint32_t assign_tx_fifo(dwc_otg_core_if_t * core_if)
+{
+	uint32_t TxMsk = 1;
+	int i;
+
+	for (i = 0; i < core_if->hwcfg4.b.num_in_eps; ++i) {
+		if ((TxMsk & core_if->tx_msk) == 0) {
+			core_if->tx_msk |= TxMsk;
+			return i + 1;
+		}
+		TxMsk <<= 1;
+	}
+	return 0;
+}
+
+/**
+ * This function assigns periodic Tx FIFO to an periodic EP
+ * in shared Tx FIFO mode
+ */
+static uint32_t assign_perio_tx_fifo(dwc_otg_core_if_t * core_if)
+{
+	uint32_t PerTxMsk = 1;
+	int i;
+	for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; ++i) {
+		if ((PerTxMsk & core_if->p_tx_msk) == 0) {
+			core_if->p_tx_msk |= PerTxMsk;
+			return i + 1;
+		}
+		PerTxMsk <<= 1;
+	}
+	return 0;
+}
+
+/**
+ * This function releases periodic Tx FIFO
+ * in shared Tx FIFO mode
+ */
+static void release_perio_tx_fifo(dwc_otg_core_if_t * core_if,
+				  uint32_t fifo_num)
+{
+	core_if->p_tx_msk =
+	    (core_if->p_tx_msk & (1 << (fifo_num - 1))) ^ core_if->p_tx_msk;
+}
+
+/**
+ * This function releases periodic Tx FIFO
+ * in shared Tx FIFO mode
+ */
+static void release_tx_fifo(dwc_otg_core_if_t * core_if, uint32_t fifo_num)
+{
+	core_if->tx_msk =
+	    (core_if->tx_msk & (1 << (fifo_num - 1))) ^ core_if->tx_msk;
+}
+
+/**
+ * This function is being called from gadget 
+ * to enable PCD endpoint.
+ */
+int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd,
+			  const uint8_t * ep_desc, void *usb_ep)
+{
+	int num, dir;
+	dwc_otg_pcd_ep_t *ep = NULL;
+	const usb_endpoint_descriptor_t *desc;
+	dwc_irqflags_t flags;
+	fifosize_data_t dptxfsiz = {.d32 = 0 };
+	gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
+	gdfifocfg_data_t gdfifocfgbase = {.d32 = 0 };
+	int retval = 0;
+	int i, epcount;
+
+	desc = (const usb_endpoint_descriptor_t *)ep_desc;
+
+	if (!desc) {
+		pcd->ep0.priv = usb_ep;
+		ep = &pcd->ep0;
+		retval = -DWC_E_INVALID;
+		goto out;
+	}
+
+	num = UE_GET_ADDR(desc->bEndpointAddress);
+	dir = UE_GET_DIR(desc->bEndpointAddress);
+
+	if (!desc->wMaxPacketSize) {
+		DWC_WARN("bad maxpacketsize\n");
+		retval = -DWC_E_INVALID;
+		goto out;
+	}
+
+	if (dir == UE_DIR_IN) {
+		epcount = pcd->core_if->dev_if->num_in_eps;
+		for (i = 0; i < epcount; i++) {
+			if (num == pcd->in_ep[i].dwc_ep.num) {
+				ep = &pcd->in_ep[i];
+				break;
+			}
+		}
+	} else {
+		epcount = pcd->core_if->dev_if->num_out_eps;
+		for (i = 0; i < epcount; i++) {
+			if (num == pcd->out_ep[i].dwc_ep.num) {
+				ep = &pcd->out_ep[i];
+				break;
+			}
+		}
+	}
+
+	if (!ep) {
+		DWC_WARN("bad address\n");
+		retval = -DWC_E_INVALID;
+		goto out;
+	}
+
+	DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
+
+	ep->desc = desc;
+	ep->priv = usb_ep;
+
+	/*
+	 * Activate the EP
+	 */
+	ep->stopped = 0;
+
+	ep->dwc_ep.is_in = (dir == UE_DIR_IN);
+	ep->dwc_ep.maxpacket = UGETW(desc->wMaxPacketSize);
+
+	ep->dwc_ep.type = desc->bmAttributes & UE_XFERTYPE;
+
+	if (ep->dwc_ep.is_in) {
+		if (!GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
+			ep->dwc_ep.tx_fifo_num = 0;
+
+			if (ep->dwc_ep.type == UE_ISOCHRONOUS) {
+				/*
+				 * if ISOC EP then assign a Periodic Tx FIFO.
+				 */
+				ep->dwc_ep.tx_fifo_num =
+				    assign_perio_tx_fifo(GET_CORE_IF(pcd));
+			}
+		} else {
+			/*
+			 * if Dedicated FIFOs mode is on then assign a Tx FIFO.
+			 */
+			ep->dwc_ep.tx_fifo_num =
+			    assign_tx_fifo(GET_CORE_IF(pcd));
+		}
+
+		/* Calculating EP info controller base address */
+		if (ep->dwc_ep.tx_fifo_num && GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
+			gdfifocfg.d32 =
+			    DWC_READ_REG32(&GET_CORE_IF(pcd)->core_global_regs->
+					   gdfifocfg);
+			gdfifocfgbase.d32 = gdfifocfg.d32 >> 16;
+			dptxfsiz.d32 =
+			    (DWC_READ_REG32
+			     (&GET_CORE_IF(pcd)->
+			      core_global_regs->dtxfsiz[ep->dwc_ep.
+							tx_fifo_num-1]) >> 16);
+			gdfifocfg.b.epinfobase =
+			    gdfifocfgbase.d32 + dptxfsiz.d32;
+			DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->
+					gdfifocfg, gdfifocfg.d32);
+		}
+	}
+	/* Set initial data PID. */
+	if (ep->dwc_ep.type == UE_BULK) {
+		ep->dwc_ep.data_pid_start = 0;
+	}
+
+	/* Alloc DMA Descriptors */
+	if (GET_CORE_IF(pcd)->dma_desc_enable) {
+#ifndef DWC_UTE_PER_IO
+		if (ep->dwc_ep.type != UE_ISOCHRONOUS) {
+#endif
+			ep->dwc_ep.desc_addr =
+			    dwc_otg_ep_alloc_desc_chain(&ep->
+							dwc_ep.dma_desc_addr,
+							MAX_DMA_DESC_CNT);
+			if (!ep->dwc_ep.desc_addr) {
+				DWC_WARN("%s, can't allocate DMA descriptor\n",
+					 __func__);
+				retval = -DWC_E_SHUTDOWN;
+				DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+				goto out;
+			}
+#ifndef DWC_UTE_PER_IO
+		}
+#endif
+	}
+
+	DWC_DEBUGPL(DBG_PCD, "Activate %s: type=%d, mps=%d desc=%p\n",
+		    (ep->dwc_ep.is_in ? "IN" : "OUT"),
+		    ep->dwc_ep.type, ep->dwc_ep.maxpacket, ep->desc);
+#ifdef DWC_UTE_PER_IO
+	ep->dwc_ep.xiso_bInterval = 1 << (ep->desc->bInterval - 1);
+#endif
+	if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
+		ep->dwc_ep.bInterval = 1 << (ep->desc->bInterval - 1);
+		ep->dwc_ep.frame_num = 0xFFFFFFFF;
+	}	 	
+
+	dwc_otg_ep_activate(GET_CORE_IF(pcd), &ep->dwc_ep);
+
+#ifdef DWC_UTE_CFI
+	if (pcd->cfi->ops.ep_enable) {
+		pcd->cfi->ops.ep_enable(pcd->cfi, pcd, ep);
+	}
+#endif
+
+	DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+
+out:
+	return retval;
+}
+
+/**
+ * This function is being called from gadget 
+ * to disable PCD endpoint.
+ */
+int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle)
+{
+	dwc_otg_pcd_ep_t *ep;
+	dwc_irqflags_t flags;
+	dwc_otg_dev_dma_desc_t *desc_addr;
+	dwc_dma_t dma_desc_addr;
+	gdfifocfg_data_t gdfifocfgbase = {.d32 = 0 };
+	gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
+	fifosize_data_t dptxfsiz = {.d32 = 0 };
+
+	ep = get_ep_from_handle(pcd, ep_handle);
+
+	if (!ep || !ep->desc) {
+		DWC_DEBUGPL(DBG_PCD, "bad ep address\n");
+		return -DWC_E_INVALID;
+	}
+
+	DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
+
+	dwc_otg_request_nuke(ep);
+
+	dwc_otg_ep_deactivate(GET_CORE_IF(pcd), &ep->dwc_ep);
+	if (pcd->core_if->core_params->dev_out_nak)
+	{
+		DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[ep->dwc_ep.num]);
+		pcd->core_if->ep_xfer_info[ep->dwc_ep.num].state = 0;
+	}
+	ep->desc = NULL;
+	ep->stopped = 1;
+
+	gdfifocfg.d32 =
+	    DWC_READ_REG32(&GET_CORE_IF(pcd)->core_global_regs->gdfifocfg);
+	gdfifocfgbase.d32 = gdfifocfg.d32 >> 16;
+
+	if (ep->dwc_ep.is_in) {
+		if (GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
+			/* Flush the Tx FIFO */
+			dwc_otg_flush_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
+		}
+		release_perio_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
+		release_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
+		if (GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
+			/* Decreasing EPinfo Base Addr */
+			dptxfsiz.d32 =
+			    (DWC_READ_REG32
+			     (&GET_CORE_IF(pcd)->
+		      		core_global_regs->dtxfsiz[ep->dwc_ep.tx_fifo_num-1]) >> 16);
+			gdfifocfg.b.epinfobase = gdfifocfgbase.d32 - dptxfsiz.d32;
+			DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gdfifocfg,
+					gdfifocfg.d32);
+		}
+	}
+
+	/* Free DMA Descriptors */
+	if (GET_CORE_IF(pcd)->dma_desc_enable) {
+		if (ep->dwc_ep.type != UE_ISOCHRONOUS) {
+			desc_addr = ep->dwc_ep.desc_addr;
+			dma_desc_addr = ep->dwc_ep.dma_desc_addr;
+
+			/* Cannot call dma_free_coherent() with IRQs disabled */
+			DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+			dwc_otg_ep_free_desc_chain(desc_addr, dma_desc_addr,
+						   MAX_DMA_DESC_CNT);
+
+			goto out_unlocked;
+		}
+	}
+	DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+
+out_unlocked:
+	DWC_DEBUGPL(DBG_PCD, "%d %s disabled\n", ep->dwc_ep.num,
+		    ep->dwc_ep.is_in ? "IN" : "OUT");
+	return 0;
+
+}
+
+/******************************************************************************/
+#ifdef DWC_UTE_PER_IO
+
+/**
+ * Free the request and its extended parts
+ *
+ */
+void dwc_pcd_xiso_ereq_free(dwc_otg_pcd_ep_t * ep, dwc_otg_pcd_request_t * req)
+{
+	DWC_FREE(req->ext_req.per_io_frame_descs);
+	DWC_FREE(req);
+}
+
+/**
+ * Start the next request in the endpoint's queue.
+ *
+ */
+int dwc_otg_pcd_xiso_start_next_request(dwc_otg_pcd_t * pcd,
+					dwc_otg_pcd_ep_t * ep)
+{
+	int i;
+	dwc_otg_pcd_request_t *req = NULL;
+	dwc_ep_t *dwcep = NULL;
+	struct dwc_iso_xreq_port *ereq = NULL;
+	struct dwc_iso_pkt_desc_port *ddesc_iso;
+	uint16_t nat;
+	depctl_data_t diepctl;
+
+	dwcep = &ep->dwc_ep;
+
+	if (dwcep->xiso_active_xfers > 0) {
+#if 0	//Disable this to decrease s/w overhead that is crucial for Isoc transfers
+		DWC_WARN("There are currently active transfers for EP%d \
+				(active=%d; queued=%d)", dwcep->num, dwcep->xiso_active_xfers, 
+				dwcep->xiso_queued_xfers);
+#endif
+		return 0;
+	}
+
+	nat = UGETW(ep->desc->wMaxPacketSize);
+	nat = (nat >> 11) & 0x03;
+
+	if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
+		req = DWC_CIRCLEQ_FIRST(&ep->queue);
+		ereq = &req->ext_req;
+		ep->stopped = 0;
+
+		/* Get the frame number */
+		dwcep->xiso_frame_num =
+		    dwc_otg_get_frame_number(GET_CORE_IF(pcd));
+		DWC_DEBUG("FRM_NUM=%d", dwcep->xiso_frame_num);
+
+		ddesc_iso = ereq->per_io_frame_descs;
+
+		if (dwcep->is_in) {
+			/* Setup DMA Descriptor chain for IN Isoc request */
+			for (i = 0; i < ereq->pio_pkt_count; i++) {
+				//if ((i % (nat + 1)) == 0)
+				if ( i > 0 )
+					dwcep->xiso_frame_num = (dwcep->xiso_bInterval +
+										dwcep->xiso_frame_num) & 0x3FFF;
+				dwcep->desc_addr[i].buf =
+				    req->dma + ddesc_iso[i].offset;
+				dwcep->desc_addr[i].status.b_iso_in.txbytes =
+				    ddesc_iso[i].length;
+				dwcep->desc_addr[i].status.b_iso_in.framenum =
+				    dwcep->xiso_frame_num;
+				dwcep->desc_addr[i].status.b_iso_in.bs =
+				    BS_HOST_READY;
+				dwcep->desc_addr[i].status.b_iso_in.txsts = 0;
+				dwcep->desc_addr[i].status.b_iso_in.sp =
+				    (ddesc_iso[i].length %
+				     dwcep->maxpacket) ? 1 : 0;
+				dwcep->desc_addr[i].status.b_iso_in.ioc = 0;
+				dwcep->desc_addr[i].status.b_iso_in.pid = nat + 1;
+				dwcep->desc_addr[i].status.b_iso_in.l = 0;
+
+				/* Process the last descriptor */
+				if (i == ereq->pio_pkt_count - 1) {
+					dwcep->desc_addr[i].status.b_iso_in.ioc = 1;
+					dwcep->desc_addr[i].status.b_iso_in.l = 1;
+				}
+			}
+
+			/* Setup and start the transfer for this endpoint */
+			dwcep->xiso_active_xfers++;
+			DWC_WRITE_REG32(&GET_CORE_IF(pcd)->dev_if->
+					in_ep_regs[dwcep->num]->diepdma,
+					dwcep->dma_desc_addr);
+			diepctl.d32 = 0;
+			diepctl.b.epena = 1;
+			diepctl.b.cnak = 1;
+			DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->dev_if->
+					 in_ep_regs[dwcep->num]->diepctl, 0,
+					 diepctl.d32);
+		} else {
+			/* Setup DMA Descriptor chain for OUT Isoc request */
+			for (i = 0; i < ereq->pio_pkt_count; i++) {
+				//if ((i % (nat + 1)) == 0)
+				dwcep->xiso_frame_num = (dwcep->xiso_bInterval + 
+										dwcep->xiso_frame_num) & 0x3FFF;
+				dwcep->desc_addr[i].buf =
+				    req->dma + ddesc_iso[i].offset;
+				dwcep->desc_addr[i].status.b_iso_out.rxbytes =
+				    ddesc_iso[i].length;
+				dwcep->desc_addr[i].status.b_iso_out.framenum =
+				    dwcep->xiso_frame_num;
+				dwcep->desc_addr[i].status.b_iso_out.bs =
+				    BS_HOST_READY;
+				dwcep->desc_addr[i].status.b_iso_out.rxsts = 0;
+				dwcep->desc_addr[i].status.b_iso_out.sp =
+				    (ddesc_iso[i].length %
+				     dwcep->maxpacket) ? 1 : 0;
+				dwcep->desc_addr[i].status.b_iso_out.ioc = 0;
+				dwcep->desc_addr[i].status.b_iso_out.pid = nat + 1;
+				dwcep->desc_addr[i].status.b_iso_out.l = 0;
+				
+				/* Process the last descriptor */
+				if (i == ereq->pio_pkt_count - 1) {
+					dwcep->desc_addr[i].status.b_iso_out.ioc = 1;
+					dwcep->desc_addr[i].status.b_iso_out.l = 1;
+				}			
+			}
+			
+			/* Setup and start the transfer for this endpoint */
+			dwcep->xiso_active_xfers++;
+			DWC_WRITE_REG32(&GET_CORE_IF(pcd)->dev_if->
+					out_ep_regs[dwcep->num]->doepdma,
+					dwcep->dma_desc_addr);
+			diepctl.d32 = 0;
+			diepctl.b.epena = 1;
+			diepctl.b.cnak = 1;
+			DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->dev_if->
+					 out_ep_regs[dwcep->num]->doepctl, 0,
+					 diepctl.d32);
+		}
+
+	} else {
+		ep->stopped = 1;
+	}
+
+	return 0;
+}
+
+/**
+ *	- Remove the request from the queue
+ */
+void complete_xiso_ep(dwc_otg_pcd_ep_t * ep)
+{
+	dwc_otg_pcd_request_t *req = NULL;
+	struct dwc_iso_xreq_port *ereq = NULL;
+	struct dwc_iso_pkt_desc_port *ddesc_iso = NULL;
+	dwc_ep_t *dwcep = NULL;
+	int i;
+
+	//DWC_DEBUG();
+	dwcep = &ep->dwc_ep;
+
+	/* Get the first pending request from the queue */
+	if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
+		req = DWC_CIRCLEQ_FIRST(&ep->queue);
+		if (!req) {
+			DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
+			return;
+		}
+		dwcep->xiso_active_xfers--;
+		dwcep->xiso_queued_xfers--;
+		/* Remove this request from the queue */
+		DWC_CIRCLEQ_REMOVE_INIT(&ep->queue, req, queue_entry);
+	} else {
+		DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
+		return;
+	}
+
+	ep->stopped = 1;
+	ereq = &req->ext_req;
+	ddesc_iso = ereq->per_io_frame_descs;
+
+	if (dwcep->xiso_active_xfers < 0) {
+		DWC_WARN("EP#%d (xiso_active_xfers=%d)", dwcep->num,
+			 dwcep->xiso_active_xfers);
+	}
+
+	/* Fill the Isoc descs of portable extended req from dma descriptors */
+	for (i = 0; i < ereq->pio_pkt_count; i++) {
+		if (dwcep->is_in) {	/* IN endpoints */
+			ddesc_iso[i].actual_length = ddesc_iso[i].length -
+			    dwcep->desc_addr[i].status.b_iso_in.txbytes;
+			ddesc_iso[i].status =
+			    dwcep->desc_addr[i].status.b_iso_in.txsts;
+		} else {	/* OUT endpoints */
+			ddesc_iso[i].actual_length = ddesc_iso[i].length -
+			    dwcep->desc_addr[i].status.b_iso_out.rxbytes;
+			ddesc_iso[i].status =
+			    dwcep->desc_addr[i].status.b_iso_out.rxsts;
+		}
+	}
+
+	DWC_SPINUNLOCK(ep->pcd->lock);
+
+	/* Call the completion function in the non-portable logic */
+	ep->pcd->fops->xisoc_complete(ep->pcd, ep->priv, req->priv, 0,
+				      &req->ext_req);
+
+	DWC_SPINLOCK(ep->pcd->lock);
+
+	/* Free the request - specific freeing needed for extended request object */
+	dwc_pcd_xiso_ereq_free(ep, req);
+
+	/* Start the next request */
+	dwc_otg_pcd_xiso_start_next_request(ep->pcd, ep);
+
+	return;
+}
+
+/**
+ * Create and initialize the Isoc pkt descriptors of the extended request.
+ *
+ */
+static int dwc_otg_pcd_xiso_create_pkt_descs(dwc_otg_pcd_request_t * req,
+					     void *ereq_nonport,
+					     int atomic_alloc)
+{
+	struct dwc_iso_xreq_port *ereq = NULL;
+	struct dwc_iso_xreq_port *req_mapped = NULL;
+	struct dwc_iso_pkt_desc_port *ipds = NULL;	/* To be created in this function */
+	uint32_t pkt_count;
+	int i;
+
+	ereq = &req->ext_req;
+	req_mapped = (struct dwc_iso_xreq_port *)ereq_nonport;
+	pkt_count = req_mapped->pio_pkt_count;
+
+	/* Create the isoc descs */
+	if (atomic_alloc) {
+		ipds = DWC_ALLOC_ATOMIC(sizeof(*ipds) * pkt_count);
+	} else {
+		ipds = DWC_ALLOC(sizeof(*ipds) * pkt_count);
+	}
+
+	if (!ipds) {
+		DWC_ERROR("Failed to allocate isoc descriptors");
+		return -DWC_E_NO_MEMORY;
+	}
+
+	/* Initialize the extended request fields */
+	ereq->per_io_frame_descs = ipds;
+	ereq->error_count = 0;
+	ereq->pio_alloc_pkt_count = pkt_count;
+	ereq->pio_pkt_count = pkt_count;
+	ereq->tr_sub_flags = req_mapped->tr_sub_flags;
+
+	/* Init the Isoc descriptors */
+	for (i = 0; i < pkt_count; i++) {
+		ipds[i].length = req_mapped->per_io_frame_descs[i].length;
+		ipds[i].offset = req_mapped->per_io_frame_descs[i].offset;
+		ipds[i].status = req_mapped->per_io_frame_descs[i].status;	/* 0 */
+		ipds[i].actual_length =
+		    req_mapped->per_io_frame_descs[i].actual_length;
+	}
+
+	return 0;
+}
+
+static void prn_ext_request(struct dwc_iso_xreq_port *ereq)
+{
+	struct dwc_iso_pkt_desc_port *xfd = NULL;
+	int i;
+
+	DWC_DEBUG("per_io_frame_descs=%p", ereq->per_io_frame_descs);
+	DWC_DEBUG("tr_sub_flags=%d", ereq->tr_sub_flags);
+	DWC_DEBUG("error_count=%d", ereq->error_count);
+	DWC_DEBUG("pio_alloc_pkt_count=%d", ereq->pio_alloc_pkt_count);
+	DWC_DEBUG("pio_pkt_count=%d", ereq->pio_pkt_count);
+	DWC_DEBUG("res=%d", ereq->res);
+
+	for (i = 0; i < ereq->pio_pkt_count; i++) {
+		xfd = &ereq->per_io_frame_descs[0];
+		DWC_DEBUG("FD #%d", i);
+
+		DWC_DEBUG("xfd->actual_length=%d", xfd->actual_length);
+		DWC_DEBUG("xfd->length=%d", xfd->length);
+		DWC_DEBUG("xfd->offset=%d", xfd->offset);
+		DWC_DEBUG("xfd->status=%d", xfd->status);
+	}
+}
+
+/**
+ *
+ */
+int dwc_otg_pcd_xiso_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
+			      uint8_t * buf, dwc_dma_t dma_buf, uint32_t buflen,
+			      int zero, void *req_handle, int atomic_alloc,
+			      void *ereq_nonport)
+{
+	dwc_otg_pcd_request_t *req = NULL;
+	dwc_otg_pcd_ep_t *ep;
+	dwc_irqflags_t flags;
+	int res;
+
+	ep = get_ep_from_handle(pcd, ep_handle);
+	if (!ep) {
+		DWC_WARN("bad ep\n");
+		return -DWC_E_INVALID;
+	}
+
+	/* We support this extension only for DDMA mode */
+	if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC)
+		if (!GET_CORE_IF(pcd)->dma_desc_enable)
+			return -DWC_E_INVALID;
+
+	/* Create a dwc_otg_pcd_request_t object */
+	if (atomic_alloc) {
+		req = DWC_ALLOC_ATOMIC(sizeof(*req));
+	} else {
+		req = DWC_ALLOC(sizeof(*req));
+	}
+
+	if (!req) {
+		return -DWC_E_NO_MEMORY;
+	}
+
+	/* Create the Isoc descs for this request which shall be the exact match
+	 * of the structure sent to us from the non-portable logic */
+	res =
+	    dwc_otg_pcd_xiso_create_pkt_descs(req, ereq_nonport, atomic_alloc);
+	if (res) {
+		DWC_WARN("Failed to init the Isoc descriptors");
+		DWC_FREE(req);
+		return res;
+	}
+
+	DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
+
+	DWC_CIRCLEQ_INIT_ENTRY(req, queue_entry);
+	req->buf = buf;
+	req->dma = dma_buf;
+	req->length = buflen;
+	req->sent_zlp = zero;
+	req->priv = req_handle;
+
+	//DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
+	ep->dwc_ep.dma_addr = dma_buf;
+	ep->dwc_ep.start_xfer_buff = buf;
+	ep->dwc_ep.xfer_buff = buf;
+	ep->dwc_ep.xfer_len = 0;
+	ep->dwc_ep.xfer_count = 0;
+	ep->dwc_ep.sent_zlp = 0;
+	ep->dwc_ep.total_len = buflen;
+
+	/* Add this request to the tail */
+	DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
+	ep->dwc_ep.xiso_queued_xfers++;
+
+//DWC_DEBUG("CP_0");
+//DWC_DEBUG("req->ext_req.tr_sub_flags=%d", req->ext_req.tr_sub_flags);
+//prn_ext_request((struct dwc_iso_xreq_port *) ereq_nonport);
+//prn_ext_request(&req->ext_req);
+
+	//DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+
+	/* If the req->status == ASAP  then check if there is any active transfer
+	 * for this endpoint. If no active transfers, then get the first entry
+	 * from the queue and start that transfer
+	 */
+	if (req->ext_req.tr_sub_flags == DWC_EREQ_TF_ASAP) {
+		res = dwc_otg_pcd_xiso_start_next_request(pcd, ep);
+		if (res) {
+			DWC_WARN("Failed to start the next Isoc transfer");
+			DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+			DWC_FREE(req);
+			return res;
+		}
+	}
+
+	DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+	return 0;
+}
+
+#endif
+/* END ifdef DWC_UTE_PER_IO ***************************************************/
+int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
+			 uint8_t * buf, dwc_dma_t dma_buf, uint32_t buflen,
+			 int zero, void *req_handle, int atomic_alloc)
+{
+	dwc_irqflags_t flags;
+	dwc_otg_pcd_request_t *req;
+	dwc_otg_pcd_ep_t *ep;
+	uint32_t max_transfer;
+
+	ep = get_ep_from_handle(pcd, ep_handle);
+	if (!ep || (!ep->desc && ep->dwc_ep.num != 0)) {
+		DWC_WARN("bad ep\n");
+		return -DWC_E_INVALID;
+	}
+
+	if (atomic_alloc) {
+		req = DWC_ALLOC_ATOMIC(sizeof(*req));
+	} else {
+		req = DWC_ALLOC(sizeof(*req));
+	}
+
+	if (!req) {
+		return -DWC_E_NO_MEMORY;
+	}
+	DWC_CIRCLEQ_INIT_ENTRY(req, queue_entry);
+	if (!GET_CORE_IF(pcd)->core_params->opt) {
+		if (ep->dwc_ep.num != 0) {
+			DWC_ERROR("queue req %p, len %d buf %p\n",
+				  req_handle, buflen, buf);
+		}
+	}
+
+	req->buf = buf;
+	req->dma = dma_buf;
+	req->length = buflen;
+	req->sent_zlp = zero;
+	req->priv = req_handle;
+	req->dw_align_buf = NULL;
+	if ((dma_buf & 0x3) && GET_CORE_IF(pcd)->dma_enable
+			&& !GET_CORE_IF(pcd)->dma_desc_enable)
+		req->dw_align_buf = DWC_DMA_ALLOC(buflen,
+				 &req->dw_align_buf_dma);
+	DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
+
+	/*
+	 * After adding request to the queue for IN ISOC wait for In Token Received
+	 * when TX FIFO is empty interrupt and for OUT ISOC wait for OUT Token 
+	 * Received when EP is disabled interrupt to obtain starting microframe
+	 * (odd/even) start transfer
+	 */
+	if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC)
+	{
+		if (req != 0) {
+			depctl_data_t depctl = {.d32 = DWC_READ_REG32(&pcd->core_if->dev_if->in_ep_regs[ep->dwc_ep.num]->diepctl)};
+			++pcd->request_pending;
+
+			DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
+			if (ep->dwc_ep.is_in)
+			{
+				depctl.b.cnak = 1;
+				DWC_WRITE_REG32(&pcd->core_if->dev_if->in_ep_regs[ep->dwc_ep.num]->diepctl, depctl.d32);
+			}
+			
+			DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+		}
+		return 0;
+	}
+
+	/*
+	 * For EP0 IN without premature status, zlp is required?
+	 */
+	if (ep->dwc_ep.num == 0 && ep->dwc_ep.is_in) {
+		DWC_DEBUGPL(DBG_PCDV, "%d-OUT ZLP\n", ep->dwc_ep.num);
+		//_req->zero = 1;
+	}
+
+	/* Start the transfer */
+	if (DWC_CIRCLEQ_EMPTY(&ep->queue) && !ep->stopped) {
+		/* EP0 Transfer? */
+		if (ep->dwc_ep.num == 0) {
+			switch (pcd->ep0state) {
+			case EP0_IN_DATA_PHASE:
+				DWC_DEBUGPL(DBG_PCD,
+					    "%s ep0: EP0_IN_DATA_PHASE\n",
+					    __func__);
+				break;
+
+			case EP0_OUT_DATA_PHASE:
+				DWC_DEBUGPL(DBG_PCD,
+					    "%s ep0: EP0_OUT_DATA_PHASE\n",
+					    __func__);
+				if (pcd->request_config) {
+					/* Complete STATUS PHASE */
+					ep->dwc_ep.is_in = 1;
+					pcd->ep0state = EP0_IN_STATUS_PHASE;
+				}
+				break;
+
+			case EP0_IN_STATUS_PHASE:
+				DWC_DEBUGPL(DBG_PCD,
+					    "%s ep0: EP0_IN_STATUS_PHASE\n",
+					    __func__);
+				break;
+
+			default:
+				DWC_DEBUGPL(DBG_ANY, "ep0: odd state %d\n",
+					    pcd->ep0state);
+				DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+				return -DWC_E_SHUTDOWN;
+			}
+
+			ep->dwc_ep.dma_addr = dma_buf;
+			ep->dwc_ep.start_xfer_buff = buf;
+			ep->dwc_ep.xfer_buff = buf;
+			ep->dwc_ep.xfer_len = buflen;
+			ep->dwc_ep.xfer_count = 0;
+			ep->dwc_ep.sent_zlp = 0;
+			ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
+
+			if (zero) {
+				if ((ep->dwc_ep.xfer_len %
+				     ep->dwc_ep.maxpacket == 0)
+				    && (ep->dwc_ep.xfer_len != 0)) {
+					ep->dwc_ep.sent_zlp = 1;
+				}
+
+			}
+
+			dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd),
+						   &ep->dwc_ep);
+		}		// non-ep0 endpoints
+		else {
+#ifdef DWC_UTE_CFI
+			if (ep->dwc_ep.buff_mode != BM_STANDARD) {
+				/* store the request length */
+				ep->dwc_ep.cfi_req_len = buflen;
+				pcd->cfi->ops.build_descriptors(pcd->cfi, pcd,
+								ep, req);
+			} else {
+#endif
+				max_transfer =
+				    GET_CORE_IF(ep->pcd)->
+				    core_params->max_transfer_size;
+
+				/* Setup and start the Transfer */
+				if (req->dw_align_buf){
+					if (ep->dwc_ep.is_in)
+						dwc_memcpy(req->dw_align_buf, buf, buflen);
+					ep->dwc_ep.dma_addr = req->dw_align_buf_dma;
+					ep->dwc_ep.start_xfer_buff = req->dw_align_buf;
+                                        ep->dwc_ep.xfer_buff = req->dw_align_buf;
+				} else {
+					ep->dwc_ep.dma_addr = dma_buf;
+					ep->dwc_ep.start_xfer_buff = buf;
+                                        ep->dwc_ep.xfer_buff = buf;	
+				}
+				ep->dwc_ep.xfer_len = 0;
+				ep->dwc_ep.xfer_count = 0;
+				ep->dwc_ep.sent_zlp = 0;
+				ep->dwc_ep.total_len = buflen;
+
+				ep->dwc_ep.maxxfer = max_transfer;
+				if (GET_CORE_IF(pcd)->dma_desc_enable) {
+					uint32_t out_max_xfer =
+					    DDMA_MAX_TRANSFER_SIZE -
+					    (DDMA_MAX_TRANSFER_SIZE % 4);
+					if (ep->dwc_ep.is_in) {
+						if (ep->dwc_ep.maxxfer >
+						    DDMA_MAX_TRANSFER_SIZE) {
+							ep->dwc_ep.maxxfer =
+							    DDMA_MAX_TRANSFER_SIZE;
+						}
+					} else {
+						if (ep->dwc_ep.maxxfer >
+						    out_max_xfer) {
+							ep->dwc_ep.maxxfer =
+							    out_max_xfer;
+						}
+					}
+				}
+				if (ep->dwc_ep.maxxfer < ep->dwc_ep.total_len) {
+					ep->dwc_ep.maxxfer -=
+					    (ep->dwc_ep.maxxfer %
+					     ep->dwc_ep.maxpacket);
+				}
+
+				if (zero) {
+					if ((ep->dwc_ep.total_len %
+					     ep->dwc_ep.maxpacket == 0)
+					    && (ep->dwc_ep.total_len != 0)) {
+						ep->dwc_ep.sent_zlp = 1;
+					}
+				}
+#ifdef DWC_UTE_CFI
+			}
+#endif
+			dwc_otg_ep_start_transfer(GET_CORE_IF(pcd),
+						  &ep->dwc_ep);
+		}
+	}
+
+	if (req != 0) {
+		++pcd->request_pending;
+		DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
+		if (ep->dwc_ep.is_in && ep->stopped
+		    && !(GET_CORE_IF(pcd)->dma_enable)) {
+			/** @todo NGS Create a function for this. */
+			diepmsk_data_t diepmsk = {.d32 = 0 };
+			diepmsk.b.intktxfemp = 1;
+			if (GET_CORE_IF(pcd)->multiproc_int_enable) {
+				DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->dev_if->
+						 dev_global_regs->
+						 diepeachintmsk[ep->dwc_ep.num],
+						 0, diepmsk.d32);
+			} else {
+				DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->dev_if->
+						 dev_global_regs->diepmsk, 0,
+						 diepmsk.d32);
+			}
+
+		}
+	}
+	DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+
+	return 0;
+}
+
+int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle,
+			   void *req_handle)
+{
+	dwc_irqflags_t flags;
+	dwc_otg_pcd_request_t *req;
+	dwc_otg_pcd_ep_t *ep;
+
+	ep = get_ep_from_handle(pcd, ep_handle);
+	if (!ep || (!ep->desc && ep->dwc_ep.num != 0)) {
+		DWC_WARN("bad argument\n");
+		return -DWC_E_INVALID;
+	}
+
+	DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
+
+	/* make sure it's actually queued on this endpoint */
+	DWC_CIRCLEQ_FOREACH(req, &ep->queue, queue_entry) {
+		if (req->priv == (void *)req_handle) {
+			break;
+		}
+	}
+
+	if (req->priv != (void *)req_handle) {
+		DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+		return -DWC_E_INVALID;
+	}
+
+	if (!DWC_CIRCLEQ_EMPTY_ENTRY(req, queue_entry)) {
+		dwc_otg_request_done(ep, req, -DWC_E_RESTART);
+	} else {
+		req = NULL;
+	}
+
+	DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+
+	return req ? 0 : -DWC_E_SHUTDOWN;
+
+}
+
+int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value)
+{
+	dwc_otg_pcd_ep_t *ep;
+	dwc_irqflags_t flags;
+	int retval = 0;
+
+	ep = get_ep_from_handle(pcd, ep_handle);
+
+	if (!ep || (!ep->desc && ep != &pcd->ep0) ||
+	    (ep->desc && (ep->desc->bmAttributes == UE_ISOCHRONOUS))) {
+		DWC_WARN("%s, bad ep\n", __func__);
+		return -DWC_E_INVALID;
+	}
+
+	DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
+	if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
+		DWC_WARN("%d %s XFer In process\n", ep->dwc_ep.num,
+			 ep->dwc_ep.is_in ? "IN" : "OUT");
+		retval = -DWC_E_AGAIN;
+	} else if (value == 0) {
+		dwc_otg_ep_clear_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
+	} else if (value == 1) {
+		if (ep->dwc_ep.is_in == 1 && GET_CORE_IF(pcd)->dma_desc_enable) {
+			dtxfsts_data_t txstatus;
+			fifosize_data_t txfifosize;
+
+			txfifosize.d32 =
+			    DWC_READ_REG32(&GET_CORE_IF(pcd)->core_global_regs->
+					   dtxfsiz[ep->dwc_ep.tx_fifo_num]);
+			txstatus.d32 =
+			    DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if->
+					   in_ep_regs[ep->dwc_ep.num]->dtxfsts);
+
+			if (txstatus.b.txfspcavail < txfifosize.b.depth) {
+				DWC_WARN("%s() Data In Tx Fifo\n", __func__);
+				retval = -DWC_E_AGAIN;
+			} else {
+				if (ep->dwc_ep.num == 0) {
+					pcd->ep0state = EP0_STALL;
+				}
+
+				ep->stopped = 1;
+				dwc_otg_ep_set_stall(GET_CORE_IF(pcd),
+						     &ep->dwc_ep);
+			}
+		} else {
+			if (ep->dwc_ep.num == 0) {
+				pcd->ep0state = EP0_STALL;
+			}
+
+			ep->stopped = 1;
+			dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
+		}
+	} else if (value == 2) {
+		ep->dwc_ep.stall_clear_flag = 0;
+	} else if (value == 3) {
+		ep->dwc_ep.stall_clear_flag = 1;
+	}
+
+	DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+
+	return retval;
+}
+
+/**
+ * This function initiates remote wakeup of the host from suspend state.
+ */
+void dwc_otg_pcd_rem_wkup_from_suspend(dwc_otg_pcd_t * pcd, int set)
+{
+	dctl_data_t dctl = { 0 };
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+	dsts_data_t dsts;
+
+	dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
+	if (!dsts.b.suspsts) {
+		DWC_WARN("Remote wakeup while is not in suspend state\n");
+	}
+	/* Check if DEVICE_REMOTE_WAKEUP feature enabled */
+	if (pcd->remote_wakeup_enable) {
+		if (set) {
+
+			if (core_if->adp_enable) {
+				gpwrdn_data_t gpwrdn;
+
+				dwc_otg_adp_probe_stop(core_if);
+
+				/* Mask SRP detected interrupt from Power Down Logic */
+				gpwrdn.d32 = 0;
+				gpwrdn.b.srp_det_msk = 1;
+				DWC_MODIFY_REG32(&core_if->core_global_regs->
+						 gpwrdn, gpwrdn.d32, 0);
+
+				/* Disable Power Down Logic */
+				gpwrdn.d32 = 0;
+				gpwrdn.b.pmuactv = 1;
+				DWC_MODIFY_REG32(&core_if->core_global_regs->
+						 gpwrdn, gpwrdn.d32, 0);
+
+				/*
+				 * Initialize the Core for Device mode.
+				 */
+				core_if->op_state = B_PERIPHERAL;
+				dwc_otg_core_init(core_if);
+				dwc_otg_enable_global_interrupts(core_if);
+				cil_pcd_start(core_if);
+
+				dwc_otg_initiate_srp(core_if);
+			}
+
+			dctl.b.rmtwkupsig = 1;
+			DWC_MODIFY_REG32(&core_if->dev_if->
+					 dev_global_regs->dctl, 0, dctl.d32);
+			DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n");
+
+			dwc_mdelay(2);
+			DWC_MODIFY_REG32(&core_if->dev_if->
+					 dev_global_regs->dctl, dctl.d32, 0);
+			DWC_DEBUGPL(DBG_PCD, "Clear Remote Wakeup\n");
+		}
+	} else {
+		DWC_DEBUGPL(DBG_PCD, "Remote Wakeup is disabled\n");
+	}
+}
+
+#ifdef CONFIG_USB_DWC_OTG_LPM
+/**
+ * This function initiates remote wakeup of the host from L1 sleep state.
+ */
+void dwc_otg_pcd_rem_wkup_from_sleep(dwc_otg_pcd_t * pcd, int set)
+{
+	glpmcfg_data_t lpmcfg;
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+
+	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
+
+	/* Check if we are in L1 state */
+	if (!lpmcfg.b.prt_sleep_sts) {
+		DWC_DEBUGPL(DBG_PCD, "Device is not in sleep state\n");
+		return;
+	}
+
+	/* Check if host allows remote wakeup */
+	if (!lpmcfg.b.rem_wkup_en) {
+		DWC_DEBUGPL(DBG_PCD, "Host does not allow remote wakeup\n");
+		return;
+	}
+
+	/* Check if Resume OK */
+	if (!lpmcfg.b.sleep_state_resumeok) {
+		DWC_DEBUGPL(DBG_PCD, "Sleep state resume is not OK\n");
+		return;
+	}
+
+	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
+	lpmcfg.b.en_utmi_sleep = 0;
+	lpmcfg.b.hird_thres &= (~(1 << 4));
+	DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
+
+	if (set) {
+		dctl_data_t dctl = {.d32 = 0 };
+		dctl.b.rmtwkupsig = 1;
+		/* Set RmtWkUpSig bit to start remote wakup signaling.
+		 * Hardware will automatically clear this bit.
+		 */
+		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl,
+				 0, dctl.d32);
+		DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n");
+	}
+
+}
+#endif
+
+/**
+ * Performs remote wakeup.
+ */
+void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set)
+{
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+	dwc_irqflags_t flags;
+	if (dwc_otg_is_device_mode(core_if)) {
+		DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
+#ifdef CONFIG_USB_DWC_OTG_LPM
+		if (core_if->lx_state == DWC_OTG_L1) {
+			dwc_otg_pcd_rem_wkup_from_sleep(pcd, set);
+		} else {
+#endif
+			dwc_otg_pcd_rem_wkup_from_suspend(pcd, set);
+#ifdef CONFIG_USB_DWC_OTG_LPM
+		}
+#endif
+		DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+	}
+	return;
+}
+
+void dwc_otg_pcd_disconnect_us(dwc_otg_pcd_t * pcd, int no_of_usecs)
+{
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+	dctl_data_t dctl = { 0 };
+
+	if (dwc_otg_is_device_mode(core_if)) {
+		dctl.b.sftdiscon = 1;
+		DWC_PRINTF("Soft disconnect for %d useconds\n",no_of_usecs);
+		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
+		dwc_udelay(no_of_usecs);
+		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32,0);
+		
+	} else{
+		DWC_PRINTF("NOT SUPPORTED IN HOST MODE\n");
+	}
+	return;
+
+}
+
+int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd)
+{
+	dsts_data_t dsts;
+	gotgctl_data_t gotgctl;
+
+	/*
+	 * This function starts the Protocol if no session is in progress. If
+	 * a session is already in progress, but the device is suspended,
+	 * remote wakeup signaling is started.
+	 */
+
+	/* Check if valid session */
+	gotgctl.d32 =
+	    DWC_READ_REG32(&(GET_CORE_IF(pcd)->core_global_regs->gotgctl));
+	if (gotgctl.b.bsesvld) {
+		/* Check if suspend state */
+		dsts.d32 =
+		    DWC_READ_REG32(&
+				   (GET_CORE_IF(pcd)->dev_if->
+				    dev_global_regs->dsts));
+		if (dsts.b.suspsts) {
+			dwc_otg_pcd_remote_wakeup(pcd, 1);
+		}
+	} else {
+		dwc_otg_pcd_initiate_srp(pcd);
+	}
+
+	return 0;
+
+}
+
+/**
+ * Start the SRP timer to detect when the SRP does not complete within
+ * 6 seconds.
+ *
+ * @param pcd the pcd structure.
+ */
+void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd)
+{
+	dwc_irqflags_t flags;
+	DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
+	dwc_otg_initiate_srp(GET_CORE_IF(pcd));
+	DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+}
+
+int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd)
+{
+	return dwc_otg_get_frame_number(GET_CORE_IF(pcd));
+}
+
+int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd)
+{
+	return GET_CORE_IF(pcd)->core_params->lpm_enable;
+}
+
+uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd)
+{
+	return pcd->b_hnp_enable;
+}
+
+uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd)
+{
+	return pcd->a_hnp_support;
+}
+
+uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd)
+{
+	return pcd->a_alt_hnp_support;
+}
+
+int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd)
+{
+	return pcd->remote_wakeup_enable;
+}
+
+#endif /* DWC_HOST_ONLY */
diff --git a/drivers/usb/dwc_otg/dwc_otg_pcd.h b/drivers/usb/dwc_otg/dwc_otg_pcd.h
new file mode 100644
index 0000000..4b2dde9
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_pcd.h
@@ -0,0 +1,262 @@
+/* ==========================================================================
+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.h $
+ * $Revision: #46 $
+ * $Date: 2011/10/20 $
+ * $Change: 1870124 $
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+#ifndef DWC_HOST_ONLY
+#if !defined(__DWC_PCD_H__)
+#define __DWC_PCD_H__
+
+#include "dwc_otg_os_dep.h"
+#include "usb.h"
+#include "dwc_otg_cil.h"
+#include "dwc_otg_pcd_if.h"
+struct cfiobject;
+
+/**
+ * @file
+ *
+ * This file contains the structures, constants, and interfaces for
+ * the Perpherial Contoller Driver (PCD).
+ *
+ * The Peripheral Controller Driver (PCD) for Linux will implement the
+ * Gadget API, so that the existing Gadget drivers can be used. For
+ * the Mass Storage Function driver the File-backed USB Storage Gadget
+ * (FBS) driver will be used.  The FBS driver supports the
+ * Control-Bulk (CB), Control-Bulk-Interrupt (CBI), and Bulk-Only
+ * transports.
+ *
+ */
+
+/** Invalid DMA Address */
+#define DWC_DMA_ADDR_INVALID	(~(dwc_dma_t)0)
+
+/** Max Transfer size for any EP */
+#define DDMA_MAX_TRANSFER_SIZE 65535
+
+/**
+ * Get the pointer to the core_if from the pcd pointer.
+ */
+#define GET_CORE_IF( _pcd ) (_pcd->core_if)
+
+/**
+ * States of EP0.
+ */
+typedef enum ep0_state {
+	EP0_DISCONNECT,		/* no host */
+	EP0_IDLE,
+	EP0_IN_DATA_PHASE,
+	EP0_OUT_DATA_PHASE,
+	EP0_IN_STATUS_PHASE,
+	EP0_OUT_STATUS_PHASE,
+	EP0_STALL,
+} ep0state_e;
+
+/** Fordward declaration.*/
+struct dwc_otg_pcd;
+
+/** DWC_otg iso request structure.
+ *
+ */
+typedef struct usb_iso_request dwc_otg_pcd_iso_request_t;
+
+#ifdef DWC_UTE_PER_IO
+
+/**
+ * This shall be the exact analogy of the same type structure defined in the
+ * usb_gadget.h. Each descriptor contains
+ */
+struct dwc_iso_pkt_desc_port {
+	uint32_t offset;
+	uint32_t length;	/* expected length */
+	uint32_t actual_length;
+	uint32_t status;
+};
+
+struct dwc_iso_xreq_port {
+	/** transfer/submission flag */
+	uint32_t tr_sub_flags;
+	/** Start the request ASAP */
+#define DWC_EREQ_TF_ASAP		0x00000002
+	/** Just enqueue the request w/o initiating a transfer */
+#define DWC_EREQ_TF_ENQUEUE		0x00000004
+
+	/**
+	* count of ISO packets attached to this request - shall
+	* not exceed the pio_alloc_pkt_count
+	*/
+	uint32_t pio_pkt_count;
+	/** count of ISO packets allocated for this request */
+	uint32_t pio_alloc_pkt_count;
+	/** number of ISO packet errors */
+	uint32_t error_count;
+	/** reserved for future extension */
+	uint32_t res;
+	/** Will be allocated and freed in the UTE gadget and based on the CFC value */
+	struct dwc_iso_pkt_desc_port *per_io_frame_descs;
+};
+#endif
+/** DWC_otg request structure.
+ * This structure is a list of requests.
+ */
+typedef struct dwc_otg_pcd_request {
+	void *priv;
+	void *buf;
+	dwc_dma_t dma;
+	uint32_t length;
+	uint32_t actual;
+	unsigned sent_zlp:1;
+    /**
+     * Used instead of original buffer if
+     * it(physical address) is not dword-aligned.
+     **/
+     uint8_t *dw_align_buf;
+     dwc_dma_t dw_align_buf_dma;
+
+	 DWC_CIRCLEQ_ENTRY(dwc_otg_pcd_request) queue_entry;
+#ifdef DWC_UTE_PER_IO
+	struct dwc_iso_xreq_port ext_req;
+	//void *priv_ereq_nport; /*  */
+#endif
+} dwc_otg_pcd_request_t;
+
+DWC_CIRCLEQ_HEAD(req_list, dwc_otg_pcd_request);
+
+/**	  PCD EP structure.
+ * This structure describes an EP, there is an array of EPs in the PCD
+ * structure.
+ */
+typedef struct dwc_otg_pcd_ep {
+	/** USB EP Descriptor */
+	const usb_endpoint_descriptor_t *desc;
+
+	/** queue of dwc_otg_pcd_requests. */
+	struct req_list queue;
+	unsigned stopped:1;
+	unsigned disabling:1;
+	unsigned dma:1;
+	unsigned queue_sof:1;
+
+#ifdef DWC_EN_ISOC
+	/** ISOC req handle passed */
+	void *iso_req_handle;
+#endif				//_EN_ISOC_
+
+	/** DWC_otg ep data. */
+	dwc_ep_t dwc_ep;
+
+	/** Pointer to PCD */
+	struct dwc_otg_pcd *pcd;
+
+	void *priv;
+} dwc_otg_pcd_ep_t;
+
+/** DWC_otg PCD Structure.
+ * This structure encapsulates the data for the dwc_otg PCD.
+ */
+struct dwc_otg_pcd {
+	const struct dwc_otg_pcd_function_ops *fops;
+	/** The DWC otg device pointer */
+	struct dwc_otg_device *otg_dev;
+	/** Core Interface */
+	dwc_otg_core_if_t *core_if;
+	/** State of EP0 */
+	ep0state_e ep0state;
+	/** EP0 Request is pending */
+	unsigned ep0_pending:1;
+	/** Indicates when SET CONFIGURATION Request is in process */
+	unsigned request_config:1;
+	/** The state of the Remote Wakeup Enable. */
+	unsigned remote_wakeup_enable:1;
+	/** The state of the B-Device HNP Enable. */
+	unsigned b_hnp_enable:1;
+	/** The state of A-Device HNP Support. */
+	unsigned a_hnp_support:1;
+	/** The state of the A-Device Alt HNP support. */
+	unsigned a_alt_hnp_support:1;
+	/** Count of pending Requests */
+	unsigned request_pending;
+
+	/** SETUP packet for EP0
+	 * This structure is allocated as a DMA buffer on PCD initialization
+	 * with enough space for up to 3 setup packets.
+	 */
+	union {
+		usb_device_request_t req;
+		uint32_t d32[2];
+	} *setup_pkt;
+
+	dwc_dma_t setup_pkt_dma_handle;
+
+	/** 2-byte dma buffer used to return status from GET_STATUS */
+	uint16_t *status_buf;
+	dwc_dma_t status_buf_dma_handle;
+
+	/** EP0 */
+	dwc_otg_pcd_ep_t ep0;
+
+	/** Array of IN EPs. */
+	dwc_otg_pcd_ep_t in_ep[MAX_EPS_CHANNELS - 1];
+	/** Array of OUT EPs. */
+	dwc_otg_pcd_ep_t out_ep[MAX_EPS_CHANNELS - 1];
+	/** number of valid EPs in the above array. */
+//        unsigned      num_eps : 4;
+	dwc_spinlock_t *lock;
+
+	/** Tasklet to defer starting of TEST mode transmissions until
+	 *	Status Phase has been completed.
+	 */
+	dwc_tasklet_t *test_mode_tasklet;
+
+	/** Tasklet to delay starting of xfer in DMA mode */
+	dwc_tasklet_t *start_xfer_tasklet;
+
+	/** The test mode to enter when the tasklet is executed. */
+	unsigned test_mode;
+	/** The cfi_api structure that implements most of the CFI API
+	 * and OTG specific core configuration functionality
+	 */
+#ifdef DWC_UTE_CFI
+	struct cfiobject *cfi;
+#endif
+
+};
+
+//FIXME this functions should be static, and this prototypes should be removed
+extern void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep);
+extern void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep,
+				 dwc_otg_pcd_request_t * req, int32_t status);
+
+void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep,
+			     void *req_handle);
+
+extern void do_test_mode(void *data);
+#endif
+#endif /* DWC_HOST_ONLY */
diff --git a/drivers/usb/dwc_otg/dwc_otg_pcd_if.h b/drivers/usb/dwc_otg/dwc_otg_pcd_if.h
new file mode 100644
index 0000000..6283867
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_pcd_if.h
@@ -0,0 +1,357 @@
+/* ==========================================================================
+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_if.h $
+ * $Revision: #11 $
+ * $Date: 2011/10/26 $
+ * $Change: 1873028 $
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+#ifndef DWC_HOST_ONLY
+
+#if !defined(__DWC_PCD_IF_H__)
+#define __DWC_PCD_IF_H__
+
+//#include "dwc_os.h"
+#include "dwc_otg_core_if.h"
+
+/** @file
+ * This file defines DWC_OTG PCD Core API.
+ */
+
+struct dwc_otg_pcd;
+typedef struct dwc_otg_pcd dwc_otg_pcd_t;
+
+/** Maxpacket size for EP0 */
+#define MAX_EP0_SIZE	64
+/** Maxpacket size for any EP */
+#define MAX_PACKET_SIZE 1024
+
+/** @name Function Driver Callbacks */
+/** @{ */
+
+/** This function will be called whenever a previously queued request has
+ * completed.  The status value will be set to -DWC_E_SHUTDOWN to indicated a
+ * failed or aborted transfer, or -DWC_E_RESTART to indicate the device was reset,
+ * or -DWC_E_TIMEOUT to indicate it timed out, or -DWC_E_INVALID to indicate invalid
+ * parameters. */
+typedef int (*dwc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
+				    void *req_handle, int32_t status,
+				    uint32_t actual);
+/**
+ * This function will be called whenever a previousle queued ISOC request has
+ * completed. Count of ISOC packets could be read using dwc_otg_pcd_get_iso_packet_count
+ * function.
+ * The status of each ISOC packet could be read using dwc_otg_pcd_get_iso_packet_*
+ * functions.
+ */
+typedef int (*dwc_isoc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
+					 void *req_handle, int proc_buf_num);
+/** This function should handle any SETUP request that cannot be handled by the
+ * PCD Core.  This includes most GET_DESCRIPTORs, SET_CONFIGS, Any
+ * class-specific requests, etc.  The function must non-blocking.
+ *
+ * Returns 0 on success.
+ * Returns -DWC_E_NOT_SUPPORTED if the request is not supported.
+ * Returns -DWC_E_INVALID if the setup request had invalid parameters or bytes.
+ * Returns -DWC_E_SHUTDOWN on any other error. */
+typedef int (*dwc_setup_cb_t) (dwc_otg_pcd_t * pcd, uint8_t * bytes);
+/** This is called whenever the device has been disconnected.  The function
+ * driver should take appropriate action to clean up all pending requests in the
+ * PCD Core, remove all endpoints (except ep0), and initialize back to reset
+ * state. */
+typedef int (*dwc_disconnect_cb_t) (dwc_otg_pcd_t * pcd);
+/** This function is called when device has been connected. */
+typedef int (*dwc_connect_cb_t) (dwc_otg_pcd_t * pcd, int speed);
+/** This function is called when device has been suspended */
+typedef int (*dwc_suspend_cb_t) (dwc_otg_pcd_t * pcd);
+/** This function is called when device has received LPM tokens, i.e.
+ * device has been sent to sleep state. */
+typedef int (*dwc_sleep_cb_t) (dwc_otg_pcd_t * pcd);
+/** This function is called when device has been resumed
+ * from suspend(L2) or L1 sleep state. */
+typedef int (*dwc_resume_cb_t) (dwc_otg_pcd_t * pcd);
+/** This function is called whenever hnp params has been changed.
+ * User can call get_b_hnp_enable, get_a_hnp_support, get_a_alt_hnp_support functions
+ * to get hnp parameters. */
+typedef int (*dwc_hnp_params_changed_cb_t) (dwc_otg_pcd_t * pcd);
+/** This function is called whenever USB RESET is detected. */
+typedef int (*dwc_reset_cb_t) (dwc_otg_pcd_t * pcd);
+
+typedef int (*cfi_setup_cb_t) (dwc_otg_pcd_t * pcd, void *ctrl_req_bytes);
+
+/**
+ *
+ * @param ep_handle	Void pointer to the usb_ep structure
+ * @param ereq_port Pointer to the extended request structure created in the
+ *					portable part.
+ */
+typedef int (*xiso_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
+				     void *req_handle, int32_t status,
+				     void *ereq_port);
+/** Function Driver Ops Data Structure */
+struct dwc_otg_pcd_function_ops {
+	dwc_connect_cb_t connect;
+	dwc_disconnect_cb_t disconnect;
+	dwc_setup_cb_t setup;
+	dwc_completion_cb_t complete;
+	dwc_isoc_completion_cb_t isoc_complete;
+	dwc_suspend_cb_t suspend;
+	dwc_sleep_cb_t sleep;
+	dwc_resume_cb_t resume;
+	dwc_reset_cb_t reset;
+	dwc_hnp_params_changed_cb_t hnp_changed;
+	cfi_setup_cb_t cfi_setup;
+#ifdef DWC_UTE_PER_IO
+	xiso_completion_cb_t xisoc_complete;
+#endif
+};
+/** @} */
+
+/** @name Function Driver Functions */
+/** @{ */
+
+/** Call this function to get pointer on dwc_otg_pcd_t,
+ * this pointer will be used for all PCD API functions.
+ *
+ * @param core_if The DWC_OTG Core
+ */
+extern dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if);
+
+/** Frees PCD allocated by dwc_otg_pcd_init
+ *
+ * @param pcd The PCD
+ */
+extern void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd);
+
+/** Call this to bind the function driver to the PCD Core.
+ *
+ * @param pcd Pointer on dwc_otg_pcd_t returned by dwc_otg_pcd_init function.
+ * @param fops The Function Driver Ops data structure containing pointers to all callbacks.
+ */
+extern void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd,
+			      const struct dwc_otg_pcd_function_ops *fops);
+
+/** Enables an endpoint for use.  This function enables an endpoint in
+ * the PCD.  The endpoint is described by the ep_desc which has the
+ * same format as a USB ep descriptor.  The ep_handle parameter is used to refer
+ * to the endpoint from other API functions and in callbacks.  Normally this
+ * should be called after a SET_CONFIGURATION/SET_INTERFACE to configure the
+ * core for that interface.
+ *
+ * Returns -DWC_E_INVALID if invalid parameters were passed.
+ * Returns -DWC_E_SHUTDOWN if any other error ocurred.
+ * Returns 0 on success.
+ *
+ * @param pcd The PCD
+ * @param ep_desc Endpoint descriptor
+ * @param usb_ep Handle on endpoint, that will be used to identify endpoint.
+ */
+extern int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd,
+				 const uint8_t * ep_desc, void *usb_ep);
+
+/** Disable the endpoint referenced by ep_handle.
+ *
+ * Returns -DWC_E_INVALID if invalid parameters were passed.
+ * Returns -DWC_E_SHUTDOWN if any other error occurred.
+ * Returns 0 on success. */
+extern int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle);
+
+/** Queue a data transfer request on the endpoint referenced by ep_handle.
+ * After the transfer is completes, the complete callback will be called with
+ * the request status.
+ *
+ * @param pcd The PCD
+ * @param ep_handle The handle of the endpoint
+ * @param buf The buffer for the data
+ * @param dma_buf The DMA buffer for the data
+ * @param buflen The length of the data transfer
+ * @param zero Specifies whether to send zero length last packet.
+ * @param req_handle Set this handle to any value to use to reference this
+ * request in the ep_dequeue function or from the complete callback
+ * @param atomic_alloc If driver need to perform atomic allocations
+ * for internal data structures.
+ *
+ * Returns -DWC_E_INVALID if invalid parameters were passed.
+ * Returns -DWC_E_SHUTDOWN if any other error ocurred.
+ * Returns 0 on success. */
+extern int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
+				uint8_t * buf, dwc_dma_t dma_buf,
+				uint32_t buflen, int zero, void *req_handle,
+				int atomic_alloc);
+#ifdef DWC_UTE_PER_IO
+/**
+ *
+ * @param ereq_nonport	Pointer to the extended request part of the
+ *						usb_request structure defined in usb_gadget.h file.
+ */
+extern int dwc_otg_pcd_xiso_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
+				     uint8_t * buf, dwc_dma_t dma_buf,
+				     uint32_t buflen, int zero,
+				     void *req_handle, int atomic_alloc,
+				     void *ereq_nonport);
+
+#endif
+
+/** De-queue the specified data transfer that has not yet completed.
+ *
+ * Returns -DWC_E_INVALID if invalid parameters were passed.
+ * Returns -DWC_E_SHUTDOWN if any other error ocurred.
+ * Returns 0 on success. */
+extern int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle,
+				  void *req_handle);
+
+/** Halt (STALL) an endpoint or clear it.
+ *
+ * Returns -DWC_E_INVALID if invalid parameters were passed.
+ * Returns -DWC_E_SHUTDOWN if any other error ocurred.
+ * Returns -DWC_E_AGAIN if the STALL cannot be sent and must be tried again later
+ * Returns 0 on success. */
+extern int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value);
+
+/** This function should be called on every hardware interrupt */
+extern int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t * pcd);
+
+/** This function returns current frame number */
+extern int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd);
+
+/**
+ * Start isochronous transfers on the endpoint referenced by ep_handle.
+ * For isochronous transfers duble buffering is used.
+ * After processing each of buffers comlete callback will be called with
+ * status for each transaction.
+ *
+ * @param pcd The PCD
+ * @param ep_handle The handle of the endpoint
+ * @param buf0 The virtual address of first data buffer
+ * @param buf1 The virtual address of second data buffer
+ * @param dma0 The DMA address of first data buffer
+ * @param dma1 The DMA address of second data buffer
+ * @param sync_frame Data pattern frame number
+ * @param dp_frame Data size for pattern frame
+ * @param data_per_frame Data size for regular frame
+ * @param start_frame Frame number to start transfers, if -1 then start transfers ASAP.
+ * @param buf_proc_intrvl Interval of ISOC Buffer processing
+ * @param req_handle Handle of ISOC request
+ * @param atomic_alloc Specefies whether to perform atomic allocation for
+ * 			internal data structures.
+ *
+ * Returns -DWC_E_NO_MEMORY if there is no enough memory.
+ * Returns -DWC_E_INVALID if incorrect arguments are passed to the function.
+ * Returns -DW_E_SHUTDOWN for any other error.
+ * Returns 0 on success
+ */
+extern int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle,
+				    uint8_t * buf0, uint8_t * buf1,
+				    dwc_dma_t dma0, dwc_dma_t dma1,
+				    int sync_frame, int dp_frame,
+				    int data_per_frame, int start_frame,
+				    int buf_proc_intrvl, void *req_handle,
+				    int atomic_alloc);
+
+/** Stop ISOC transfers on endpoint referenced by ep_handle.
+ *
+ * @param pcd The PCD
+ * @param ep_handle The handle of the endpoint
+ * @param req_handle Handle of ISOC request
+ *
+ * Returns -DWC_E_INVALID if incorrect arguments are passed to the function
+ * Returns 0 on success
+ */
+int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle,
+			    void *req_handle);
+
+/** Get ISOC packet status.
+ *
+ * @param pcd The PCD
+ * @param ep_handle The handle of the endpoint
+ * @param iso_req_handle Isochronoush request handle
+ * @param packet Number of packet
+ * @param status Out parameter for returning status
+ * @param actual Out parameter for returning actual length
+ * @param offset Out parameter for returning offset
+ *
+ */
+extern void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd,
+					      void *ep_handle,
+					      void *iso_req_handle, int packet,
+					      int *status, int *actual,
+					      int *offset);
+
+/** Get ISOC packet count.
+ *
+ * @param pcd The PCD
+ * @param ep_handle The handle of the endpoint
+ * @param iso_req_handle
+ */
+extern int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd,
+					    void *ep_handle,
+					    void *iso_req_handle);
+
+/** This function starts the SRP Protocol if no session is in progress. If
+ * a session is already in progress, but the device is suspended,
+ * remote wakeup signaling is started.
+ */
+extern int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd);
+
+/** This function returns 1 if LPM support is enabled, and 0 otherwise. */
+extern int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd);
+
+/** This function returns 1 if remote wakeup is allowed and 0, otherwise. */
+extern int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd);
+
+/** Initiate SRP */
+extern void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd);
+
+/** Starts remote wakeup signaling. */
+extern void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set);
+
+/** Starts micorsecond soft disconnect. */
+extern void dwc_otg_pcd_disconnect_us(dwc_otg_pcd_t * pcd, int no_of_usecs);
+/** This function returns whether device is dualspeed.*/
+extern uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd);
+
+/** This function returns whether device is otg. */
+extern uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd);
+
+/** These functions allow to get hnp parameters */
+extern uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd);
+extern uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd);
+extern uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd);
+
+/** CFI specific Interface functions */
+/** Allocate a cfi buffer */
+extern uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep,
+				     dwc_dma_t * addr, size_t buflen,
+				     int flags);
+
+/******************************************************************************/
+
+/** @} */
+
+#endif				/* __DWC_PCD_IF_H__ */
+
+#endif				/* DWC_HOST_ONLY */
diff --git a/drivers/usb/dwc_otg/dwc_otg_pcd_intr.c b/drivers/usb/dwc_otg/dwc_otg_pcd_intr.c
new file mode 100644
index 0000000..32286fd
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_pcd_intr.c
@@ -0,0 +1,4815 @@
+/* ==========================================================================
+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_intr.c $
+ * $Revision: #113 $
+ * $Date: 2011/10/24 $
+ * $Change: 1871160 $
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+#ifndef DWC_HOST_ONLY
+
+#include "dwc_otg_pcd.h"
+
+#ifdef DWC_UTE_CFI
+#include "dwc_otg_cfi.h"
+#endif
+
+#ifdef DWC_UTE_PER_IO
+extern void complete_xiso_ep(dwc_otg_pcd_ep_t * ep);
+#endif
+//#define PRINT_CFI_DMA_DESCS
+
+#define DEBUG_EP0
+
+/**
+ * This function updates OTG.
+ */
+static void dwc_otg_pcd_update_otg(dwc_otg_pcd_t * pcd, const unsigned reset)
+{
+
+	if (reset) {
+		pcd->b_hnp_enable = 0;
+		pcd->a_hnp_support = 0;
+		pcd->a_alt_hnp_support = 0;
+	}
+
+	if (pcd->fops->hnp_changed) {
+		pcd->fops->hnp_changed(pcd);
+	}
+}
+
+/** @file
+ * This file contains the implementation of the PCD Interrupt handlers.
+ *
+ * The PCD handles the device interrupts.  Many conditions can cause a
+ * device interrupt. When an interrupt occurs, the device interrupt
+ * service routine determines the cause of the interrupt and
+ * dispatches handling to the appropriate function. These interrupt
+ * handling functions are described below.
+ * All interrupt registers are processed from LSB to MSB.
+ */
+
+/**
+ * This function prints the ep0 state for debug purposes.
+ */
+static inline void print_ep0_state(dwc_otg_pcd_t * pcd)
+{
+#ifdef DEBUG
+	char str[40];
+
+	switch (pcd->ep0state) {
+	case EP0_DISCONNECT:
+		dwc_strcpy(str, "EP0_DISCONNECT");
+		break;
+	case EP0_IDLE:
+		dwc_strcpy(str, "EP0_IDLE");
+		break;
+	case EP0_IN_DATA_PHASE:
+		dwc_strcpy(str, "EP0_IN_DATA_PHASE");
+		break;
+	case EP0_OUT_DATA_PHASE:
+		dwc_strcpy(str, "EP0_OUT_DATA_PHASE");
+		break;
+	case EP0_IN_STATUS_PHASE:
+		dwc_strcpy(str, "EP0_IN_STATUS_PHASE");
+		break;
+	case EP0_OUT_STATUS_PHASE:
+		dwc_strcpy(str, "EP0_OUT_STATUS_PHASE");
+		break;
+	case EP0_STALL:
+		dwc_strcpy(str, "EP0_STALL");
+		break;
+	default:
+		dwc_strcpy(str, "EP0_INVALID");
+	}
+
+	DWC_DEBUGPL(DBG_ANY, "%s(%d)\n", str, pcd->ep0state);
+#endif
+}
+
+/**
+ * This function calculate the size of the payload in the memory 
+ * for out endpoints and prints size for debug purposes(used in 
+ * 2.93a DevOutNak feature).
+ */
+static inline void print_memory_payload(dwc_otg_pcd_t * pcd,  dwc_ep_t * ep)
+{
+#ifdef DEBUG
+	deptsiz_data_t deptsiz_init = {.d32 = 0 };
+	deptsiz_data_t deptsiz_updt = {.d32 = 0 };
+	int pack_num;
+	unsigned payload;
+	
+	deptsiz_init.d32 = pcd->core_if->start_doeptsiz_val[ep->num];
+	deptsiz_updt.d32 =
+		DWC_READ_REG32(&pcd->core_if->dev_if->
+						out_ep_regs[ep->num]->doeptsiz);
+	/* Payload will be */
+	payload = deptsiz_init.b.xfersize - deptsiz_updt.b.xfersize;
+	/* Packet count is decremented every time a packet
+	 * is written to the RxFIFO not in to the external memory
+	 * So, if payload == 0, then it means no packet was sent to ext memory*/
+	pack_num = (!payload) ? 0 : (deptsiz_init.b.pktcnt - deptsiz_updt.b.pktcnt);
+	DWC_DEBUGPL(DBG_PCDV,
+		"Payload for EP%d-%s\n",
+		ep->num, (ep->is_in ? "IN" : "OUT"));
+	DWC_DEBUGPL(DBG_PCDV,
+		"Number of transfered bytes = 0x%08x\n", payload);
+	DWC_DEBUGPL(DBG_PCDV,
+		"Number of transfered packets = %d\n", pack_num);	
+#endif	
+}
+
+
+#ifdef DWC_UTE_CFI
+static inline void print_desc(struct dwc_otg_dma_desc *ddesc,
+			      const uint8_t * epname, int descnum)
+{
+	CFI_INFO
+	    ("%s DMA_DESC(%d) buf=0x%08x bytes=0x%04x; sp=0x%x; l=0x%x; sts=0x%02x; bs=0x%02x\n",
+	     epname, descnum, ddesc->buf, ddesc->status.b.bytes,
+	     ddesc->status.b.sp, ddesc->status.b.l, ddesc->status.b.sts,
+	     ddesc->status.b.bs);
+}
+#endif
+
+/**
+ * This function returns pointer to in ep struct with number ep_num
+ */
+static inline dwc_otg_pcd_ep_t *get_in_ep(dwc_otg_pcd_t * pcd, uint32_t ep_num)
+{
+	int i;
+	int num_in_eps = GET_CORE_IF(pcd)->dev_if->num_in_eps;
+	if (ep_num == 0) {
+		return &pcd->ep0;
+	} else {
+		for (i = 0; i < num_in_eps; ++i) {
+			if (pcd->in_ep[i].dwc_ep.num == ep_num)
+				return &pcd->in_ep[i];
+		}
+		return 0;
+	}
+}
+
+/**
+ * This function returns pointer to out ep struct with number ep_num
+ */
+static inline dwc_otg_pcd_ep_t *get_out_ep(dwc_otg_pcd_t * pcd, uint32_t ep_num)
+{
+	int i;
+	int num_out_eps = GET_CORE_IF(pcd)->dev_if->num_out_eps;
+	if (ep_num == 0) {
+		return &pcd->ep0;
+	} else {
+		for (i = 0; i < num_out_eps; ++i) {
+			if (pcd->out_ep[i].dwc_ep.num == ep_num)
+				return &pcd->out_ep[i];
+		}
+		return 0;
+	}
+}
+
+/**
+ * This functions gets a pointer to an EP from the wIndex address
+ * value of the control request.
+ */
+dwc_otg_pcd_ep_t *get_ep_by_addr(dwc_otg_pcd_t * pcd, u16 wIndex)
+{
+	dwc_otg_pcd_ep_t *ep;
+	uint32_t ep_num = UE_GET_ADDR(wIndex);
+
+	if (ep_num == 0) {
+		ep = &pcd->ep0;
+	} else if (UE_GET_DIR(wIndex) == UE_DIR_IN) {	/* in ep */
+		ep = &pcd->in_ep[ep_num - 1];
+	} else {
+		ep = &pcd->out_ep[ep_num - 1];
+	}
+
+	return ep;
+}
+
+/**
+ * This function checks the EP request queue, if the queue is not
+ * empty the next request is started.
+ */
+void start_next_request(dwc_otg_pcd_ep_t * ep)
+{
+	dwc_otg_pcd_request_t *req = 0;
+	uint32_t max_transfer =
+	    GET_CORE_IF(ep->pcd)->core_params->max_transfer_size;
+
+#ifdef DWC_UTE_CFI
+	struct dwc_otg_pcd *pcd;
+	pcd = ep->pcd;
+#endif
+
+	if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
+		req = DWC_CIRCLEQ_FIRST(&ep->queue);
+
+#ifdef DWC_UTE_CFI
+		if (ep->dwc_ep.buff_mode != BM_STANDARD) {
+			ep->dwc_ep.cfi_req_len = req->length;
+			pcd->cfi->ops.build_descriptors(pcd->cfi, pcd, ep, req);
+		} else {
+#endif
+			/* Setup and start the Transfer */
+			if (req->dw_align_buf) {
+				ep->dwc_ep.dma_addr = req->dw_align_buf_dma;
+				ep->dwc_ep.start_xfer_buff = req->dw_align_buf;
+				ep->dwc_ep.xfer_buff = req->dw_align_buf;
+			} else {
+				ep->dwc_ep.dma_addr = req->dma;
+				ep->dwc_ep.start_xfer_buff = req->buf;
+				ep->dwc_ep.xfer_buff = req->buf;
+			}
+			ep->dwc_ep.sent_zlp = 0;
+			ep->dwc_ep.total_len = req->length;
+			ep->dwc_ep.xfer_len = 0;
+			ep->dwc_ep.xfer_count = 0;
+
+			ep->dwc_ep.maxxfer = max_transfer;
+			if (GET_CORE_IF(ep->pcd)->dma_desc_enable) {
+				uint32_t out_max_xfer = DDMA_MAX_TRANSFER_SIZE
+				    - (DDMA_MAX_TRANSFER_SIZE % 4);
+				if (ep->dwc_ep.is_in) {
+					if (ep->dwc_ep.maxxfer >
+					    DDMA_MAX_TRANSFER_SIZE) {
+						ep->dwc_ep.maxxfer =
+						    DDMA_MAX_TRANSFER_SIZE;
+					}
+				} else {
+					if (ep->dwc_ep.maxxfer > out_max_xfer) {
+						ep->dwc_ep.maxxfer =
+						    out_max_xfer;
+					}
+				}
+			}
+			if (ep->dwc_ep.maxxfer < ep->dwc_ep.total_len) {
+				ep->dwc_ep.maxxfer -=
+				    (ep->dwc_ep.maxxfer % ep->dwc_ep.maxpacket);
+			}
+			if (req->sent_zlp) {
+				if ((ep->dwc_ep.total_len %
+				     ep->dwc_ep.maxpacket == 0)
+				    && (ep->dwc_ep.total_len != 0)) {
+					ep->dwc_ep.sent_zlp = 1;
+				}
+
+			}
+#ifdef DWC_UTE_CFI
+		}
+#endif
+		dwc_otg_ep_start_transfer(GET_CORE_IF(ep->pcd), &ep->dwc_ep);
+	} else if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
+		DWC_PRINTF("There are no more ISOC requests \n");
+		ep->dwc_ep.frame_num = 0xFFFFFFFF;
+	}
+}
+
+/**
+ * This function handles the SOF Interrupts. At this time the SOF
+ * Interrupt is disabled.
+ */
+int32_t dwc_otg_pcd_handle_sof_intr(dwc_otg_pcd_t * pcd)
+{
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+
+	gintsts_data_t gintsts;
+
+	DWC_DEBUGPL(DBG_PCD, "SOF\n");
+
+	/* Clear interrupt */
+	gintsts.d32 = 0;
+	gintsts.b.sofintr = 1;
+	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
+
+	return 1;
+}
+
+/**
+ * This function handles the Rx Status Queue Level Interrupt, which
+ * indicates that there is a least one packet in the Rx FIFO.  The
+ * packets are moved from the FIFO to memory, where they will be
+ * processed when the Endpoint Interrupt Register indicates Transfer
+ * Complete or SETUP Phase Done.
+ *
+ * Repeat the following until the Rx Status Queue is empty:
+ *	 -# Read the Receive Status Pop Register (GRXSTSP) to get Packet
+ *		info
+ *	 -# If Receive FIFO is empty then skip to step Clear the interrupt
+ *		and exit
+ *	 -# If SETUP Packet call dwc_otg_read_setup_packet to copy the
+ *		SETUP data to the buffer
+ *	 -# If OUT Data Packet call dwc_otg_read_packet to copy the data
+ *		to the destination buffer
+ */
+int32_t dwc_otg_pcd_handle_rx_status_q_level_intr(dwc_otg_pcd_t * pcd)
+{
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+	gintmsk_data_t gintmask = {.d32 = 0 };
+	device_grxsts_data_t status;
+	dwc_otg_pcd_ep_t *ep;
+	gintsts_data_t gintsts;
+#ifdef DEBUG
+	static char *dpid_str[] = { "D0", "D2", "D1", "MDATA" };
+#endif
+
+	//DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _pcd);
+	/* Disable the Rx Status Queue Level interrupt */
+	gintmask.b.rxstsqlvl = 1;
+	DWC_MODIFY_REG32(&global_regs->gintmsk, gintmask.d32, 0);
+
+	/* Get the Status from the top of the FIFO */
+	status.d32 = DWC_READ_REG32(&global_regs->grxstsp);
+
+	DWC_DEBUGPL(DBG_PCD, "EP:%d BCnt:%d DPID:%s "
+		    "pktsts:%x Frame:%d(0x%0x)\n",
+		    status.b.epnum, status.b.bcnt,
+		    dpid_str[status.b.dpid],
+		    status.b.pktsts, status.b.fn, status.b.fn);
+	/* Get pointer to EP structure */
+	ep = get_out_ep(pcd, status.b.epnum);
+
+	switch (status.b.pktsts) {
+	case DWC_DSTS_GOUT_NAK:
+		DWC_DEBUGPL(DBG_PCDV, "Global OUT NAK\n");
+		break;
+	case DWC_STS_DATA_UPDT:
+		DWC_DEBUGPL(DBG_PCDV, "OUT Data Packet\n");
+		if (status.b.bcnt && ep->dwc_ep.xfer_buff) {
+			/** @todo NGS Check for buffer overflow? */
+			dwc_otg_read_packet(core_if,
+					    ep->dwc_ep.xfer_buff,
+					    status.b.bcnt);
+			ep->dwc_ep.xfer_count += status.b.bcnt;
+			ep->dwc_ep.xfer_buff += status.b.bcnt;
+		}
+		break;
+	case DWC_STS_XFER_COMP:
+		DWC_DEBUGPL(DBG_PCDV, "OUT Complete\n");
+		break;
+	case DWC_DSTS_SETUP_COMP:
+#ifdef DEBUG_EP0
+		DWC_DEBUGPL(DBG_PCDV, "Setup Complete\n");
+#endif
+		break;
+	case DWC_DSTS_SETUP_UPDT:
+		dwc_otg_read_setup_packet(core_if, pcd->setup_pkt->d32);
+#ifdef DEBUG_EP0
+		DWC_DEBUGPL(DBG_PCD,
+			    "SETUP PKT: %02x.%02x v%04x i%04x l%04x\n",
+			    pcd->setup_pkt->req.bmRequestType,
+			    pcd->setup_pkt->req.bRequest,
+			    UGETW(pcd->setup_pkt->req.wValue),
+			    UGETW(pcd->setup_pkt->req.wIndex),
+			    UGETW(pcd->setup_pkt->req.wLength));
+#endif
+		ep->dwc_ep.xfer_count += status.b.bcnt;
+		break;
+	default:
+		DWC_DEBUGPL(DBG_PCDV, "Invalid Packet Status (0x%0x)\n",
+			    status.b.pktsts);
+		break;
+	}
+
+	/* Enable the Rx Status Queue Level interrupt */
+	DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmask.d32);
+	/* Clear interrupt */
+	gintsts.d32 = 0;
+	gintsts.b.rxstsqlvl = 1;
+	DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
+
+	//DWC_DEBUGPL(DBG_PCDV, "EXIT: %s\n", __func__);
+	return 1;
+}
+
+/**
+ * This function examines the Device IN Token Learning Queue to
+ * determine the EP number of the last IN token received.  This
+ * implementation is for the Mass Storage device where there are only
+ * 2 IN EPs (Control-IN and BULK-IN).
+ *
+ * The EP numbers for the first six IN Tokens are in DTKNQR1 and there
+ * are 8 EP Numbers in each of the other possible DTKNQ Registers.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ *
+ */
+static inline int get_ep_of_last_in_token(dwc_otg_core_if_t * core_if)
+{
+	dwc_otg_device_global_regs_t *dev_global_regs =
+	    core_if->dev_if->dev_global_regs;
+	const uint32_t TOKEN_Q_DEPTH = core_if->hwcfg2.b.dev_token_q_depth;
+	/* Number of Token Queue Registers */
+	const int DTKNQ_REG_CNT = (TOKEN_Q_DEPTH + 7) / 8;
+	dtknq1_data_t dtknqr1;
+	uint32_t in_tkn_epnums[4];
+	int ndx = 0;
+	int i = 0;
+	volatile uint32_t *addr = &dev_global_regs->dtknqr1;
+	int epnum = 0;
+
+	//DWC_DEBUGPL(DBG_PCD,"dev_token_q_depth=%d\n",TOKEN_Q_DEPTH);
+
+	/* Read the DTKNQ Registers */
+	for (i = 0; i < DTKNQ_REG_CNT; i++) {
+		in_tkn_epnums[i] = DWC_READ_REG32(addr);
+		DWC_DEBUGPL(DBG_PCDV, "DTKNQR%d=0x%08x\n", i + 1,
+			    in_tkn_epnums[i]);
+		if (addr == &dev_global_regs->dvbusdis) {
+			addr = &dev_global_regs->dtknqr3_dthrctl;
+		} else {
+			++addr;
+		}
+
+	}
+
+	/* Copy the DTKNQR1 data to the bit field. */
+	dtknqr1.d32 = in_tkn_epnums[0];
+	/* Get the EP numbers */
+	in_tkn_epnums[0] = dtknqr1.b.epnums0_5;
+	ndx = dtknqr1.b.intknwptr - 1;
+
+	//DWC_DEBUGPL(DBG_PCDV,"ndx=%d\n",ndx);
+	if (ndx == -1) {
+		/** @todo Find a simpler way to calculate the max
+		 * queue position.*/
+		int cnt = TOKEN_Q_DEPTH;
+		if (TOKEN_Q_DEPTH <= 6) {
+			cnt = TOKEN_Q_DEPTH - 1;
+		} else if (TOKEN_Q_DEPTH <= 14) {
+			cnt = TOKEN_Q_DEPTH - 7;
+		} else if (TOKEN_Q_DEPTH <= 22) {
+			cnt = TOKEN_Q_DEPTH - 15;
+		} else {
+			cnt = TOKEN_Q_DEPTH - 23;
+		}
+		epnum = (in_tkn_epnums[DTKNQ_REG_CNT - 1] >> (cnt * 4)) & 0xF;
+	} else {
+		if (ndx <= 5) {
+			epnum = (in_tkn_epnums[0] >> (ndx * 4)) & 0xF;
+		} else if (ndx <= 13) {
+			ndx -= 6;
+			epnum = (in_tkn_epnums[1] >> (ndx * 4)) & 0xF;
+		} else if (ndx <= 21) {
+			ndx -= 14;
+			epnum = (in_tkn_epnums[2] >> (ndx * 4)) & 0xF;
+		} else if (ndx <= 29) {
+			ndx -= 22;
+			epnum = (in_tkn_epnums[3] >> (ndx * 4)) & 0xF;
+		}
+	}
+	//DWC_DEBUGPL(DBG_PCD,"epnum=%d\n",epnum);
+	return epnum;
+}
+
+/**
+ * This interrupt occurs when the non-periodic Tx FIFO is half-empty.
+ * The active request is checked for the next packet to be loaded into
+ * the non-periodic Tx FIFO.
+ */
+int32_t dwc_otg_pcd_handle_np_tx_fifo_empty_intr(dwc_otg_pcd_t * pcd)
+{
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+	dwc_otg_dev_in_ep_regs_t *ep_regs;
+	gnptxsts_data_t txstatus = {.d32 = 0 };
+	gintsts_data_t gintsts;
+
+	int epnum = 0;
+	dwc_otg_pcd_ep_t *ep = 0;
+	uint32_t len = 0;
+	int dwords;
+
+	/* Get the epnum from the IN Token Learning Queue. */
+	epnum = get_ep_of_last_in_token(core_if);
+	ep = get_in_ep(pcd, epnum);
+
+	DWC_DEBUGPL(DBG_PCD, "NP TxFifo Empty: %d \n", epnum);
+
+	ep_regs = core_if->dev_if->in_ep_regs[epnum];
+
+	len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
+	if (len > ep->dwc_ep.maxpacket) {
+		len = ep->dwc_ep.maxpacket;
+	}
+	dwords = (len + 3) / 4;
+
+	/* While there is space in the queue and space in the FIFO and
+	 * More data to tranfer, Write packets to the Tx FIFO */
+	txstatus.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
+	DWC_DEBUGPL(DBG_PCDV, "b4 GNPTXSTS=0x%08x\n", txstatus.d32);
+
+	while (txstatus.b.nptxqspcavail > 0 &&
+	       txstatus.b.nptxfspcavail > dwords &&
+	       ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len) {
+		/* Write the FIFO */
+		dwc_otg_ep_write_packet(core_if, &ep->dwc_ep, 0);
+		len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
+
+		if (len > ep->dwc_ep.maxpacket) {
+			len = ep->dwc_ep.maxpacket;
+		}
+
+		dwords = (len + 3) / 4;
+		txstatus.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
+		DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n", txstatus.d32);
+	}
+
+	DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n",
+		    DWC_READ_REG32(&global_regs->gnptxsts));
+
+	/* Clear interrupt */
+	gintsts.d32 = 0;
+	gintsts.b.nptxfempty = 1;
+	DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
+
+	return 1;
+}
+
+/**
+ * This function is called when dedicated Tx FIFO Empty interrupt occurs.
+ * The active request is checked for the next packet to be loaded into
+ * apropriate Tx FIFO.
+ */
+static int32_t write_empty_tx_fifo(dwc_otg_pcd_t * pcd, uint32_t epnum)
+{
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+	dwc_otg_dev_in_ep_regs_t *ep_regs;
+	dtxfsts_data_t txstatus = {.d32 = 0 };
+	dwc_otg_pcd_ep_t *ep = 0;
+	uint32_t len = 0;
+	int dwords;
+
+	ep = get_in_ep(pcd, epnum);
+
+	DWC_DEBUGPL(DBG_PCD, "Dedicated TxFifo Empty: %d \n", epnum);
+
+	ep_regs = core_if->dev_if->in_ep_regs[epnum];
+
+	len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
+
+	if (len > ep->dwc_ep.maxpacket) {
+		len = ep->dwc_ep.maxpacket;
+	}
+
+	dwords = (len + 3) / 4;
+
+	/* While there is space in the queue and space in the FIFO and
+	 * More data to tranfer, Write packets to the Tx FIFO */
+	txstatus.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
+	DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum, txstatus.d32);
+
+	while (txstatus.b.txfspcavail > dwords &&
+	       ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len &&
+	       ep->dwc_ep.xfer_len != 0) {
+		/* Write the FIFO */
+		dwc_otg_ep_write_packet(core_if, &ep->dwc_ep, 0);
+
+		len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
+		if (len > ep->dwc_ep.maxpacket) {
+			len = ep->dwc_ep.maxpacket;
+		}
+
+		dwords = (len + 3) / 4;
+		txstatus.d32 =
+		    DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
+		DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", epnum,
+			    txstatus.d32);
+	}
+
+	DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum,
+		    DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts));
+
+	return 1;
+}
+
+/**
+ * This function is called when the Device is disconnected. It stops
+ * any active requests and informs the Gadget driver of the
+ * disconnect.
+ */
+void dwc_otg_pcd_stop(dwc_otg_pcd_t * pcd)
+{
+	int i, num_in_eps, num_out_eps;
+	dwc_otg_pcd_ep_t *ep;
+
+	gintmsk_data_t intr_mask = {.d32 = 0 };
+
+	DWC_SPINLOCK(pcd->lock);
+
+	num_in_eps = GET_CORE_IF(pcd)->dev_if->num_in_eps;
+	num_out_eps = GET_CORE_IF(pcd)->dev_if->num_out_eps;
+
+	DWC_DEBUGPL(DBG_PCDV, "%s() \n", __func__);
+	/* don't disconnect drivers more than once */
+	if (pcd->ep0state == EP0_DISCONNECT) {
+		DWC_DEBUGPL(DBG_ANY, "%s() Already Disconnected\n", __func__);
+		DWC_SPINUNLOCK(pcd->lock);
+		return;
+	}
+	pcd->ep0state = EP0_DISCONNECT;
+
+	/* Reset the OTG state. */
+	dwc_otg_pcd_update_otg(pcd, 1);
+
+	/* Disable the NP Tx Fifo Empty Interrupt. */
+	intr_mask.b.nptxfempty = 1;
+	DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
+			 intr_mask.d32, 0);
+
+	/* Flush the FIFOs */
+	/**@todo NGS Flush Periodic FIFOs */
+	dwc_otg_flush_tx_fifo(GET_CORE_IF(pcd), 0x10);
+	dwc_otg_flush_rx_fifo(GET_CORE_IF(pcd));
+
+	/* prevent new request submissions, kill any outstanding requests  */
+	ep = &pcd->ep0;
+	dwc_otg_request_nuke(ep);
+	/* prevent new request submissions, kill any outstanding requests  */
+	for (i = 0; i < num_in_eps; i++) {
+		dwc_otg_pcd_ep_t *ep = &pcd->in_ep[i];
+		dwc_otg_request_nuke(ep);
+	}
+	/* prevent new request submissions, kill any outstanding requests  */
+	for (i = 0; i < num_out_eps; i++) {
+		dwc_otg_pcd_ep_t *ep = &pcd->out_ep[i];
+		dwc_otg_request_nuke(ep);
+	}
+
+	/* report disconnect; the driver is already quiesced */
+	if (pcd->fops->disconnect) {
+		DWC_SPINUNLOCK(pcd->lock);
+		pcd->fops->disconnect(pcd);
+		DWC_SPINLOCK(pcd->lock);
+	}
+	DWC_SPINUNLOCK(pcd->lock);
+}
+
+/**
+ * This interrupt indicates that ...
+ */
+int32_t dwc_otg_pcd_handle_i2c_intr(dwc_otg_pcd_t * pcd)
+{
+	gintmsk_data_t intr_mask = {.d32 = 0 };
+	gintsts_data_t gintsts;
+
+	DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "i2cintr");
+	intr_mask.b.i2cintr = 1;
+	DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
+			 intr_mask.d32, 0);
+
+	/* Clear interrupt */
+	gintsts.d32 = 0;
+	gintsts.b.i2cintr = 1;
+	DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
+			gintsts.d32);
+	return 1;
+}
+
+/**
+ * This interrupt indicates that ...
+ */
+int32_t dwc_otg_pcd_handle_early_suspend_intr(dwc_otg_pcd_t * pcd)
+{
+	gintsts_data_t gintsts;
+#if defined(VERBOSE)
+	DWC_PRINTF("Early Suspend Detected\n");
+#endif
+
+	/* Clear interrupt */
+	gintsts.d32 = 0;
+	gintsts.b.erlysuspend = 1;
+	DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
+			gintsts.d32);
+	return 1;
+}
+
+/**
+ * This function configures EPO to receive SETUP packets.
+ *
+ * @todo NGS: Update the comments from the HW FS.
+ *
+ *	-# Program the following fields in the endpoint specific registers
+ *	for Control OUT EP 0, in order to receive a setup packet
+ *	- DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back
+ *	  setup packets)
+ *	- DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back
+ *	  to back setup packets)
+ *		- In DMA mode, DOEPDMA0 Register with a memory address to
+ *		  store any setup packets received
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param pcd	  Programming view of the PCD.
+ */
+static inline void ep0_out_start(dwc_otg_core_if_t * core_if,
+				 dwc_otg_pcd_t * pcd)
+{
+	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+	deptsiz0_data_t doeptsize0 = {.d32 = 0 };
+	dwc_otg_dev_dma_desc_t *dma_desc;
+	depctl_data_t doepctl = {.d32 = 0 };
+
+#ifdef VERBOSE
+	DWC_DEBUGPL(DBG_PCDV, "%s() doepctl0=%0x\n", __func__,
+		    DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl));
+#endif
+
+	doeptsize0.b.supcnt = 3;
+	doeptsize0.b.pktcnt = 1;
+	doeptsize0.b.xfersize = 8 * 3;
+
+	if (core_if->dma_enable) {
+		if (!core_if->dma_desc_enable) {
+			/** put here as for Hermes mode deptisz register should not be written */
+			DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doeptsiz,
+					doeptsize0.d32);
+
+			/** @todo dma needs to handle multiple setup packets (up to 3) */
+			DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepdma,
+					pcd->setup_pkt_dma_handle);
+		} else {
+			dev_if->setup_desc_index =
+			    (dev_if->setup_desc_index + 1) & 1;
+			dma_desc =
+			    dev_if->setup_desc_addr[dev_if->setup_desc_index];
+
+			/** DMA Descriptor Setup */
+			dma_desc->status.b.bs = BS_HOST_BUSY;
+			dma_desc->status.b.l = 1;
+			dma_desc->status.b.ioc = 1;
+			dma_desc->status.b.bytes = pcd->ep0.dwc_ep.maxpacket;
+			dma_desc->buf = pcd->setup_pkt_dma_handle;
+			dma_desc->status.b.sts = 0;
+			dma_desc->status.b.bs = BS_HOST_READY;
+
+			/** DOEPDMA0 Register write */
+			DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepdma,
+					dev_if->
+					dma_setup_desc_addr
+					[dev_if->setup_desc_index]);
+		}
+
+	} else {
+		/** put here as for Hermes mode deptisz register should not be written */
+		DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doeptsiz,
+				doeptsize0.d32);
+	}
+
+	/** DOEPCTL0 Register write */
+	doepctl.b.epena = 1;
+	doepctl.b.cnak = 1;
+	DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32);
+
+#ifdef VERBOSE
+	DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n",
+		    DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl));
+	DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n",
+		    DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl));
+#endif
+}
+
+/**
+ * This interrupt occurs when a USB Reset is detected. When the USB
+ * Reset Interrupt occurs the device state is set to DEFAULT and the
+ * EP0 state is set to IDLE.
+ *	-#	Set the NAK bit for all OUT endpoints (DOEPCTLn.SNAK = 1)
+ *	-#	Unmask the following interrupt bits
+ *		- DAINTMSK.INEP0 = 1 (Control 0 IN endpoint)
+ *	- DAINTMSK.OUTEP0 = 1 (Control 0 OUT endpoint)
+ *	- DOEPMSK.SETUP = 1
+ *	- DOEPMSK.XferCompl = 1
+ *	- DIEPMSK.XferCompl = 1
+ *	- DIEPMSK.TimeOut = 1
+ *	-# Program the following fields in the endpoint specific registers
+ *	for Control OUT EP 0, in order to receive a setup packet
+ *	- DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back
+ *	  setup packets)
+ *	- DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back
+ *	  to back setup packets)
+ *		- In DMA mode, DOEPDMA0 Register with a memory address to
+ *		  store any setup packets received
+ * At this point, all the required initialization, except for enabling
+ * the control 0 OUT endpoint is done, for receiving SETUP packets.
+ */
+int32_t dwc_otg_pcd_handle_usb_reset_intr(dwc_otg_pcd_t * pcd)
+{
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+	depctl_data_t doepctl = {.d32 = 0 };
+	depctl_data_t diepctl = {.d32 = 0 };
+	daint_data_t daintmsk = {.d32 = 0 };
+	doepmsk_data_t doepmsk = {.d32 = 0 };
+	diepmsk_data_t diepmsk = {.d32 = 0 };
+	dcfg_data_t dcfg = {.d32 = 0 };
+	grstctl_t resetctl = {.d32 = 0 };
+	dctl_data_t dctl = {.d32 = 0 };
+	int i = 0;
+	gintsts_data_t gintsts;
+	pcgcctl_data_t power = {.d32 = 0 };
+
+	power.d32 = DWC_READ_REG32(core_if->pcgcctl);
+	if (power.b.stoppclk) {
+		power.d32 = 0;
+		power.b.stoppclk = 1;
+		DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0);
+
+		power.b.pwrclmp = 1;
+		DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0);
+
+		power.b.rstpdwnmodule = 1;
+		DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0);
+	}
+
+	core_if->lx_state = DWC_OTG_L0;
+
+	DWC_PRINTF("USB RESET\n");
+#ifdef DWC_EN_ISOC
+	for (i = 1; i < 16; ++i) {
+		dwc_otg_pcd_ep_t *ep;
+		dwc_ep_t *dwc_ep;
+		ep = get_in_ep(pcd, i);
+		if (ep != 0) {
+			dwc_ep = &ep->dwc_ep;
+			dwc_ep->next_frame = 0xffffffff;
+		}
+	}
+#endif /* DWC_EN_ISOC */
+
+	/* reset the HNP settings */
+	dwc_otg_pcd_update_otg(pcd, 1);
+
+	/* Clear the Remote Wakeup Signalling */
+	dctl.b.rmtwkupsig = 1;
+	DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
+
+	/* Set NAK for all OUT EPs */
+	doepctl.b.snak = 1;
+	for (i = 0; i <= dev_if->num_out_eps; i++) {
+		DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, doepctl.d32);
+	}
+
+	/* Flush the NP Tx FIFO */
+	dwc_otg_flush_tx_fifo(core_if, 0x10);
+	/* Flush the Learning Queue */
+	resetctl.b.intknqflsh = 1;
+	DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32);
+
+	if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable) {
+		core_if->start_predict = 0;
+		for (i = 0; i<= core_if->dev_if->num_in_eps; ++i) {
+			core_if->nextep_seq[i] = 0xff;	// 0xff - EP not active
+		}
+		core_if->nextep_seq[0] = 0;	
+		core_if->first_in_nextep_seq = 0;
+		diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
+		diepctl.b.nextep = 0;
+		DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
+		
+		/* Update IN Endpoint Mismatch Count by active IN NP EP count + 1 */
+		dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
+		dcfg.b.epmscnt = 2;
+		DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
+
+		DWC_DEBUGPL(DBG_PCDV,"%s first_in_nextep_seq= %2d; nextep_seq[]:\n", 
+			__func__, core_if->first_in_nextep_seq);
+		for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
+			DWC_DEBUGPL(DBG_PCDV, "%2d\n", core_if->nextep_seq[i]);
+		}
+	}
+
+	if (core_if->multiproc_int_enable) {
+		daintmsk.b.inep0 = 1;
+		daintmsk.b.outep0 = 1;
+		DWC_WRITE_REG32(&dev_if->dev_global_regs->deachintmsk,
+				daintmsk.d32);
+
+		doepmsk.b.setup = 1;
+		doepmsk.b.xfercompl = 1;
+		doepmsk.b.ahberr = 1;
+		doepmsk.b.epdisabled = 1;
+
+		if (core_if->dma_desc_enable) {
+			doepmsk.b.stsphsercvd = 1;
+			doepmsk.b.bna = 1;
+		}
+/*		
+		doepmsk.b.babble = 1;
+		doepmsk.b.nyet = 1;
+		
+		if (core_if->dma_enable) {
+			doepmsk.b.nak = 1;
+		}
+*/
+		DWC_WRITE_REG32(&dev_if->dev_global_regs->doepeachintmsk[0],
+				doepmsk.d32);
+
+		diepmsk.b.xfercompl = 1;
+		diepmsk.b.timeout = 1;
+		diepmsk.b.epdisabled = 1;
+		diepmsk.b.ahberr = 1;
+		diepmsk.b.intknepmis = 1; 
+		if (!core_if->en_multiple_tx_fifo && core_if->dma_enable)
+			diepmsk.b.intknepmis = 0; 
+
+/*		if (core_if->dma_desc_enable) {
+			diepmsk.b.bna = 1;
+		}
+*/
+/*		
+		if (core_if->dma_enable) {
+			diepmsk.b.nak = 1;
+		}
+*/
+		DWC_WRITE_REG32(&dev_if->dev_global_regs->diepeachintmsk[0],
+				diepmsk.d32);
+	} else {
+		daintmsk.b.inep0 = 1;
+		daintmsk.b.outep0 = 1;
+		DWC_WRITE_REG32(&dev_if->dev_global_regs->daintmsk,
+				daintmsk.d32);
+
+		doepmsk.b.setup = 1;
+		doepmsk.b.xfercompl = 1;
+		doepmsk.b.ahberr = 1;
+		doepmsk.b.epdisabled = 1;
+
+		if (core_if->dma_desc_enable) {
+			doepmsk.b.stsphsercvd = 1;
+			doepmsk.b.bna = 1;
+		}
+		DWC_WRITE_REG32(&dev_if->dev_global_regs->doepmsk, doepmsk.d32);
+
+		diepmsk.b.xfercompl = 1;
+		diepmsk.b.timeout = 1;
+		diepmsk.b.epdisabled = 1;
+		diepmsk.b.ahberr = 1;
+		if (!core_if->en_multiple_tx_fifo && core_if->dma_enable)
+			diepmsk.b.intknepmis = 0; 
+/*
+		if (core_if->dma_desc_enable) {
+			diepmsk.b.bna = 1;
+		}
+*/
+
+		DWC_WRITE_REG32(&dev_if->dev_global_regs->diepmsk, diepmsk.d32);
+	}
+
+	/* Reset Device Address */
+	dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
+	dcfg.b.devaddr = 0;
+	DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
+
+	/* setup EP0 to receive SETUP packets */
+	ep0_out_start(core_if, pcd);
+
+	/* Clear interrupt */
+	gintsts.d32 = 0;
+	gintsts.b.usbreset = 1;
+	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
+
+	return 1;
+}
+
+/**
+ * Get the device speed from the device status register and convert it
+ * to USB speed constant.
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ */
+static int get_device_speed(dwc_otg_core_if_t * core_if)
+{
+	dsts_data_t dsts;
+	int speed = 0;
+	dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
+
+	switch (dsts.b.enumspd) {
+	case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
+		speed = USB_SPEED_HIGH;
+		break;
+	case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
+	case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:
+		speed = USB_SPEED_FULL;
+		break;
+
+	case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:
+		speed = USB_SPEED_LOW;
+		break;
+	}
+
+	return speed;
+}
+
+/**
+ * Read the device status register and set the device speed in the
+ * data structure.
+ * Set up EP0 to receive SETUP packets by calling dwc_ep0_activate.
+ */
+int32_t dwc_otg_pcd_handle_enum_done_intr(dwc_otg_pcd_t * pcd)
+{
+	dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
+	gintsts_data_t gintsts;
+	gusbcfg_data_t gusbcfg;
+	dwc_otg_core_global_regs_t *global_regs =
+	    GET_CORE_IF(pcd)->core_global_regs;
+	uint8_t utmi16b, utmi8b;
+	int speed;
+	DWC_DEBUGPL(DBG_PCD, "SPEED ENUM\n");
+
+	if (GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_2_60a) {
+		utmi16b = 6;	//vahrama old value was 6;
+		utmi8b = 9;
+	} else {
+		utmi16b = 4;
+		utmi8b = 8;
+	}
+	dwc_otg_ep0_activate(GET_CORE_IF(pcd), &ep0->dwc_ep);
+
+#ifdef DEBUG_EP0
+	print_ep0_state(pcd);
+#endif
+
+	if (pcd->ep0state == EP0_DISCONNECT) {
+		pcd->ep0state = EP0_IDLE;
+	} else if (pcd->ep0state == EP0_STALL) {
+		pcd->ep0state = EP0_IDLE;
+	}
+
+	pcd->ep0state = EP0_IDLE;
+
+	ep0->stopped = 0;
+
+	speed = get_device_speed(GET_CORE_IF(pcd));
+	pcd->fops->connect(pcd, speed);
+
+	/* Set USB turnaround time based on device speed and PHY interface. */
+	gusbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
+	if (speed == USB_SPEED_HIGH) {
+		if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
+		    DWC_HWCFG2_HS_PHY_TYPE_ULPI) {
+			/* ULPI interface */
+			gusbcfg.b.usbtrdtim = 9;
+		}
+		if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
+		    DWC_HWCFG2_HS_PHY_TYPE_UTMI) {
+			/* UTMI+ interface */
+			if (GET_CORE_IF(pcd)->hwcfg4.b.utmi_phy_data_width == 0) {
+				gusbcfg.b.usbtrdtim = utmi8b;
+			} else if (GET_CORE_IF(pcd)->hwcfg4.
+				   b.utmi_phy_data_width == 1) {
+				gusbcfg.b.usbtrdtim = utmi16b;
+			} else if (GET_CORE_IF(pcd)->
+				   core_params->phy_utmi_width == 8) {
+				gusbcfg.b.usbtrdtim = utmi8b;
+			} else {
+				gusbcfg.b.usbtrdtim = utmi16b;
+			}
+		}
+		if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
+		    DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI) {
+			/* UTMI+  OR  ULPI interface */
+			if (gusbcfg.b.ulpi_utmi_sel == 1) {
+				/* ULPI interface */
+				gusbcfg.b.usbtrdtim = 9;
+			} else {
+				/* UTMI+ interface */
+				if (GET_CORE_IF(pcd)->
+				    core_params->phy_utmi_width == 16) {
+					gusbcfg.b.usbtrdtim = utmi16b;
+				} else {
+					gusbcfg.b.usbtrdtim = utmi8b;
+				}
+			}
+		}
+	} else {
+		/* Full or low speed */
+		gusbcfg.b.usbtrdtim = 9;
+	}
+	DWC_WRITE_REG32(&global_regs->gusbcfg, gusbcfg.d32);
+
+	/* Clear interrupt */
+	gintsts.d32 = 0;
+	gintsts.b.enumdone = 1;
+	DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
+			gintsts.d32);
+	return 1;
+}
+
+/**
+ * This interrupt indicates that the ISO OUT Packet was dropped due to
+ * Rx FIFO full or Rx Status Queue Full.  If this interrupt occurs
+ * read all the data from the Rx FIFO.
+ */
+int32_t dwc_otg_pcd_handle_isoc_out_packet_dropped_intr(dwc_otg_pcd_t * pcd)
+{
+	gintmsk_data_t intr_mask = {.d32 = 0 };
+	gintsts_data_t gintsts;
+
+	DWC_WARN("INTERRUPT Handler not implemented for %s\n",
+		 "ISOC Out Dropped");
+
+	intr_mask.b.isooutdrop = 1;
+	DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
+			 intr_mask.d32, 0);
+
+	/* Clear interrupt */
+	gintsts.d32 = 0;
+	gintsts.b.isooutdrop = 1;
+	DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
+			gintsts.d32);
+
+	return 1;
+}
+
+/**
+ * This interrupt indicates the end of the portion of the micro-frame
+ * for periodic transactions.  If there is a periodic transaction for
+ * the next frame, load the packets into the EP periodic Tx FIFO.
+ */
+int32_t dwc_otg_pcd_handle_end_periodic_frame_intr(dwc_otg_pcd_t * pcd)
+{
+	gintmsk_data_t intr_mask = {.d32 = 0 };
+	gintsts_data_t gintsts;
+	DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "EOP");
+
+	intr_mask.b.eopframe = 1;
+	DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
+			 intr_mask.d32, 0);
+
+	/* Clear interrupt */
+	gintsts.d32 = 0;
+	gintsts.b.eopframe = 1;
+	DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
+			gintsts.d32);
+
+	return 1;
+}
+
+/**
+ * This interrupt indicates that EP of the packet on the top of the
+ * non-periodic Tx FIFO does not match EP of the IN Token received.
+ *
+ * The "Device IN Token Queue" Registers are read to determine the
+ * order the IN Tokens have been received. The non-periodic Tx FIFO
+ * is flushed, so it can be reloaded in the order seen in the IN Token
+ * Queue.
+ */
+int32_t dwc_otg_pcd_handle_ep_mismatch_intr(dwc_otg_pcd_t * pcd)
+{
+	gintsts_data_t gintsts;
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+	dctl_data_t dctl;
+	gintmsk_data_t intr_mask = {.d32 = 0 };
+
+	if (!core_if->en_multiple_tx_fifo && core_if->dma_enable) {
+		core_if->start_predict = 1;
+	
+		DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, core_if);
+	
+		gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
+		if (!gintsts.b.ginnakeff) {
+			/* Disable EP Mismatch interrupt */
+			intr_mask.d32 = 0;
+			intr_mask.b.epmismatch = 1;
+			DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, intr_mask.d32, 0);
+			/* Enable the Global IN NAK Effective Interrupt */
+			intr_mask.d32 = 0;
+			intr_mask.b.ginnakeff = 1;
+			DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, intr_mask.d32);
+			/* Set the global non-periodic IN NAK handshake */
+			dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
+			dctl.b.sgnpinnak = 1;
+			DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
+		} else {
+			DWC_PRINTF("gintsts.b.ginnakeff = 1! dctl.b.sgnpinnak not set\n");
+		}
+		/* Disabling of all EP's will be done in dwc_otg_pcd_handle_in_nak_effective()
+		 * handler after Global IN NAK Effective interrupt will be asserted */
+	}
+	/* Clear interrupt */
+	gintsts.d32 = 0;
+	gintsts.b.epmismatch = 1;
+	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
+
+	return 1;
+}
+
+/**
+ * This interrupt is valid only in DMA mode. This interrupt indicates that the
+ * core has stopped fetching data for IN endpoints due to the unavailability of
+ * TxFIFO space or Request Queue space. This interrupt is used by the
+ * application for an endpoint mismatch algorithm.
+ * 
+ * @param pcd The PCD 
+ */
+int32_t dwc_otg_pcd_handle_ep_fetsusp_intr(dwc_otg_pcd_t * pcd)
+{
+	gintsts_data_t gintsts;
+	gintmsk_data_t gintmsk_data;
+	dctl_data_t dctl;
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, core_if);
+	
+	/* Clear the global non-periodic IN NAK handshake */
+	dctl.d32 = 0;
+	dctl.b.cgnpinnak = 1;
+	DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32); 
+	
+	/* Mask GINTSTS.FETSUSP interrupt */
+	gintmsk_data.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
+	gintmsk_data.b.fetsusp = 0;
+	DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk_data.d32);
+
+	/* Clear interrupt */
+	gintsts.d32 = 0;
+	gintsts.b.fetsusp = 1;
+	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
+
+	return 1;
+}
+/**
+ * This funcion stalls EP0.
+ */
+static inline void ep0_do_stall(dwc_otg_pcd_t * pcd, const int err_val)
+{
+	dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
+	usb_device_request_t *ctrl = &pcd->setup_pkt->req;
+	DWC_WARN("req %02x.%02x protocol STALL; err %d\n",
+		 ctrl->bmRequestType, ctrl->bRequest, err_val);
+
+	ep0->dwc_ep.is_in = 1;
+	dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep0->dwc_ep);
+	pcd->ep0.stopped = 1;
+	pcd->ep0state = EP0_IDLE;
+	ep0_out_start(GET_CORE_IF(pcd), pcd);
+}
+
+/**
+ * This functions delegates the setup command to the gadget driver.
+ */
+static inline void do_gadget_setup(dwc_otg_pcd_t * pcd,
+				   usb_device_request_t * ctrl)
+{
+	int ret = 0;
+	DWC_SPINUNLOCK(pcd->lock);
+	ret = pcd->fops->setup(pcd, (uint8_t *) ctrl);
+	DWC_SPINLOCK(pcd->lock);
+	if (ret < 0) {
+		ep0_do_stall(pcd, ret);
+	}
+
+	/** @todo This is a g_file_storage gadget driver specific
+	 * workaround: a DELAYED_STATUS result from the fsg_setup
+	 * routine will result in the gadget queueing a EP0 IN status
+	 * phase for a two-stage control transfer. Exactly the same as
+	 * a SET_CONFIGURATION/SET_INTERFACE except that this is a class
+	 * specific request.  Need a generic way to know when the gadget
+	 * driver will queue the status phase. Can we assume when we
+	 * call the gadget driver setup() function that it will always
+	 * queue and require the following flag? Need to look into
+	 * this.
+	 */
+
+	if (ret == 256 + 999) {
+		pcd->request_config = 1;
+	}
+}
+
+#ifdef DWC_UTE_CFI
+/**
+ * This functions delegates the CFI setup commands to the gadget driver.
+ * This function will return a negative value to indicate a failure.
+ */
+static inline int cfi_gadget_setup(dwc_otg_pcd_t * pcd,
+				   struct cfi_usb_ctrlrequest *ctrl_req)
+{
+	int ret = 0;
+
+	if (pcd->fops && pcd->fops->cfi_setup) {
+		DWC_SPINUNLOCK(pcd->lock);
+		ret = pcd->fops->cfi_setup(pcd, ctrl_req);
+		DWC_SPINLOCK(pcd->lock);
+		if (ret < 0) {
+			ep0_do_stall(pcd, ret);
+			return ret;
+		}
+	}
+
+	return ret;
+}
+#endif
+
+/**
+ * This function starts the Zero-Length Packet for the IN status phase
+ * of a 2 stage control transfer.
+ */
+static inline void do_setup_in_status_phase(dwc_otg_pcd_t * pcd)
+{
+	dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
+	if (pcd->ep0state == EP0_STALL) {
+		return;
+	}
+
+	pcd->ep0state = EP0_IN_STATUS_PHASE;
+
+	/* Prepare for more SETUP Packets */
+	DWC_DEBUGPL(DBG_PCD, "EP0 IN ZLP\n");
+	ep0->dwc_ep.xfer_len = 0;
+	ep0->dwc_ep.xfer_count = 0;
+	ep0->dwc_ep.is_in = 1;
+	ep0->dwc_ep.dma_addr = pcd->setup_pkt_dma_handle;
+	dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
+
+	/* Prepare for more SETUP Packets */
+	//ep0_out_start(GET_CORE_IF(pcd), pcd);
+}
+
+/**
+ * This function starts the Zero-Length Packet for the OUT status phase
+ * of a 2 stage control transfer.
+ */
+static inline void do_setup_out_status_phase(dwc_otg_pcd_t * pcd)
+{
+	dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
+	if (pcd->ep0state == EP0_STALL) {
+		DWC_DEBUGPL(DBG_PCD, "EP0 STALLED\n");
+		return;
+	}
+	pcd->ep0state = EP0_OUT_STATUS_PHASE;
+
+	DWC_DEBUGPL(DBG_PCD, "EP0 OUT ZLP\n");
+	ep0->dwc_ep.xfer_len = 0;
+	ep0->dwc_ep.xfer_count = 0;
+	ep0->dwc_ep.is_in = 0;
+	ep0->dwc_ep.dma_addr = pcd->setup_pkt_dma_handle;
+	dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
+
+	/* Prepare for more SETUP Packets */
+	if (GET_CORE_IF(pcd)->dma_enable == 0) {
+		ep0_out_start(GET_CORE_IF(pcd), pcd);
+	}
+}
+
+/**
+ * Clear the EP halt (STALL) and if pending requests start the
+ * transfer.
+ */
+static inline void pcd_clear_halt(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep)
+{
+	if (ep->dwc_ep.stall_clear_flag == 0)
+		dwc_otg_ep_clear_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
+
+	/* Reactive the EP */
+	dwc_otg_ep_activate(GET_CORE_IF(pcd), &ep->dwc_ep);
+	if (ep->stopped) {
+		ep->stopped = 0;
+		/* If there is a request in the EP queue start it */
+
+		/** @todo FIXME: this causes an EP mismatch in DMA mode.
+		 * epmismatch not yet implemented. */
+
+		/*
+		 * Above fixme is solved by implmenting a tasklet to call the
+		 * start_next_request(), outside of interrupt context at some
+		 * time after the current time, after a clear-halt setup packet.
+		 * Still need to implement ep mismatch in the future if a gadget
+		 * ever uses more than one endpoint at once
+		 */
+		ep->queue_sof = 1;
+		DWC_TASK_SCHEDULE(pcd->start_xfer_tasklet);
+	}
+	/* Start Control Status Phase */
+	do_setup_in_status_phase(pcd);
+}
+
+/**
+ * This function is called when the SET_FEATURE TEST_MODE Setup packet
+ * is sent from the host.  The Device Control register is written with
+ * the Test Mode bits set to the specified Test Mode.  This is done as
+ * a tasklet so that the "Status" phase of the control transfer
+ * completes before transmitting the TEST packets.
+ *
+ * @todo This has not been tested since the tasklet struct was put
+ * into the PCD struct!
+ *
+ */
+void do_test_mode(void *data)
+{
+	dctl_data_t dctl;
+	dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data;
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+	int test_mode = pcd->test_mode;
+
+//        DWC_WARN("%s() has not been tested since being rewritten!\n", __func__);
+
+	dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
+	switch (test_mode) {
+	case 1:		// TEST_J
+		dctl.b.tstctl = 1;
+		break;
+
+	case 2:		// TEST_K
+		dctl.b.tstctl = 2;
+		break;
+
+	case 3:		// TEST_SE0_NAK
+		dctl.b.tstctl = 3;
+		break;
+
+	case 4:		// TEST_PACKET
+		dctl.b.tstctl = 4;
+		break;
+
+	case 5:		// TEST_FORCE_ENABLE
+		dctl.b.tstctl = 5;
+		break;
+	}
+	DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
+}
+
+/**
+ * This function process the GET_STATUS Setup Commands.
+ */
+static inline void do_get_status(dwc_otg_pcd_t * pcd)
+{
+	usb_device_request_t ctrl = pcd->setup_pkt->req;
+	dwc_otg_pcd_ep_t *ep;
+	dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
+	uint16_t *status = pcd->status_buf;
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+
+#ifdef DEBUG_EP0
+	DWC_DEBUGPL(DBG_PCD,
+		    "GET_STATUS %02x.%02x v%04x i%04x l%04x\n",
+		    ctrl.bmRequestType, ctrl.bRequest,
+		    UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
+		    UGETW(ctrl.wLength));
+#endif
+
+	switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
+	case UT_DEVICE:
+		if(UGETW(ctrl.wIndex) == 0xF000) { /* OTG Status selector */
+			DWC_PRINTF("wIndex - %d\n", UGETW(ctrl.wIndex));
+			DWC_PRINTF("OTG VERSION - %d\n", core_if->otg_ver);
+			DWC_PRINTF("OTG CAP - %d, %d\n", core_if->core_params->otg_cap,
+						DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE);
+			if(core_if->otg_ver == 1 && 
+			core_if->core_params->otg_cap == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
+				uint8_t *otgsts = (uint8_t*)pcd->status_buf;
+				*otgsts = (core_if->otg_sts & 0x1);
+				pcd->ep0_pending = 1;
+				ep0->dwc_ep.start_xfer_buff = (uint8_t *) otgsts;
+				ep0->dwc_ep.xfer_buff = (uint8_t *) otgsts;
+				ep0->dwc_ep.dma_addr = pcd->status_buf_dma_handle;
+				ep0->dwc_ep.xfer_len = 1;
+				ep0->dwc_ep.xfer_count = 0;
+				ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len;
+				dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
+				return;
+			} else {
+				ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
+				return;
+			}
+			break;
+		} else {
+			*status = 0x1;	/* Self powered */
+			*status |= pcd->remote_wakeup_enable << 1;
+			break;
+		}
+	case UT_INTERFACE:
+		*status = 0;
+		break;
+
+	case UT_ENDPOINT:
+		ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
+		if (ep == 0 || UGETW(ctrl.wLength) > 2) {
+			ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
+			return;
+		}
+		/** @todo check for EP stall */
+		*status = ep->stopped;
+		break;
+	}
+	pcd->ep0_pending = 1;
+	ep0->dwc_ep.start_xfer_buff = (uint8_t *) status;
+	ep0->dwc_ep.xfer_buff = (uint8_t *) status;
+	ep0->dwc_ep.dma_addr = pcd->status_buf_dma_handle;
+	ep0->dwc_ep.xfer_len = 2;
+	ep0->dwc_ep.xfer_count = 0;
+	ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len;
+	dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
+}
+
+/**
+ * This function process the SET_FEATURE Setup Commands.
+ */
+static inline void do_set_feature(dwc_otg_pcd_t * pcd)
+{
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+	usb_device_request_t ctrl = pcd->setup_pkt->req;
+	dwc_otg_pcd_ep_t *ep = 0;
+	int32_t otg_cap_param = core_if->core_params->otg_cap;
+	gotgctl_data_t gotgctl = {.d32 = 0 };
+
+	DWC_DEBUGPL(DBG_PCD, "SET_FEATURE:%02x.%02x v%04x i%04x l%04x\n",
+		    ctrl.bmRequestType, ctrl.bRequest,
+		    UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
+		    UGETW(ctrl.wLength));
+	DWC_DEBUGPL(DBG_PCD, "otg_cap=%d\n", otg_cap_param);
+
+	switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
+	case UT_DEVICE:
+		switch (UGETW(ctrl.wValue)) {
+		case UF_DEVICE_REMOTE_WAKEUP:
+			pcd->remote_wakeup_enable = 1;
+			break;
+
+		case UF_TEST_MODE:
+			/* Setup the Test Mode tasklet to do the Test
+			 * Packet generation after the SETUP Status
+			 * phase has completed. */
+
+			/** @todo This has not been tested since the
+			 * tasklet struct was put into the PCD
+			 * struct! */
+			pcd->test_mode = UGETW(ctrl.wIndex) >> 8;
+			DWC_TASK_SCHEDULE(pcd->test_mode_tasklet);
+			break;
+
+		case UF_DEVICE_B_HNP_ENABLE:
+			DWC_DEBUGPL(DBG_PCDV,
+				    "SET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n");
+
+			/* dev may initiate HNP */
+			if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
+				pcd->b_hnp_enable = 1;
+				dwc_otg_pcd_update_otg(pcd, 0);
+				DWC_DEBUGPL(DBG_PCD, "Request B HNP\n");
+				/**@todo Is the gotgctl.devhnpen cleared
+				 * by a USB Reset? */
+				gotgctl.b.devhnpen = 1;
+				gotgctl.b.hnpreq = 1;
+				DWC_WRITE_REG32(&global_regs->gotgctl,
+						gotgctl.d32);
+			} else {
+				ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
+				return;
+			}
+			break;
+
+		case UF_DEVICE_A_HNP_SUPPORT:
+			/* RH port supports HNP */
+			DWC_DEBUGPL(DBG_PCDV,
+				    "SET_FEATURE: USB_DEVICE_A_HNP_SUPPORT\n");
+			if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
+				pcd->a_hnp_support = 1;
+				dwc_otg_pcd_update_otg(pcd, 0);
+			} else {
+				ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
+				return;
+			}
+			break;
+
+		case UF_DEVICE_A_ALT_HNP_SUPPORT:
+			/* other RH port does */
+			DWC_DEBUGPL(DBG_PCDV,
+				    "SET_FEATURE: USB_DEVICE_A_ALT_HNP_SUPPORT\n");
+			if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
+				pcd->a_alt_hnp_support = 1;
+				dwc_otg_pcd_update_otg(pcd, 0);
+			} else {
+				ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
+				return;
+			}
+			break;
+
+		default:
+			ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
+			return;
+
+		}
+		do_setup_in_status_phase(pcd);
+		break;
+
+	case UT_INTERFACE:
+		do_gadget_setup(pcd, &ctrl);
+		break;
+
+	case UT_ENDPOINT:
+		if (UGETW(ctrl.wValue) == UF_ENDPOINT_HALT) {
+			ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
+			if (ep == 0) {
+				ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
+				return;
+			}
+			ep->stopped = 1;
+			dwc_otg_ep_set_stall(core_if, &ep->dwc_ep);
+		}
+		do_setup_in_status_phase(pcd);
+		break;
+	}
+}
+
+/**
+ * This function process the CLEAR_FEATURE Setup Commands.
+ */
+static inline void do_clear_feature(dwc_otg_pcd_t * pcd)
+{
+	usb_device_request_t ctrl = pcd->setup_pkt->req;
+	dwc_otg_pcd_ep_t *ep = 0;
+
+	DWC_DEBUGPL(DBG_PCD,
+		    "CLEAR_FEATURE:%02x.%02x v%04x i%04x l%04x\n",
+		    ctrl.bmRequestType, ctrl.bRequest,
+		    UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
+		    UGETW(ctrl.wLength));
+
+	switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
+	case UT_DEVICE:
+		switch (UGETW(ctrl.wValue)) {
+		case UF_DEVICE_REMOTE_WAKEUP:
+			pcd->remote_wakeup_enable = 0;
+			break;
+
+		case UF_TEST_MODE:
+			/** @todo Add CLEAR_FEATURE for TEST modes. */
+			break;
+
+		default:
+			ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
+			return;
+		}
+		do_setup_in_status_phase(pcd);
+		break;
+
+	case UT_ENDPOINT:
+		ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
+		if (ep == 0) {
+			ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
+			return;
+		}
+
+		pcd_clear_halt(pcd, ep);
+
+		break;
+	}
+}
+
+/**
+ * This function process the SET_ADDRESS Setup Commands.
+ */
+static inline void do_set_address(dwc_otg_pcd_t * pcd)
+{
+	dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
+	usb_device_request_t ctrl = pcd->setup_pkt->req;
+
+	if (ctrl.bmRequestType == UT_DEVICE) {
+		dcfg_data_t dcfg = {.d32 = 0 };
+
+#ifdef DEBUG_EP0
+//                      DWC_DEBUGPL(DBG_PCDV, "SET_ADDRESS:%d\n", ctrl.wValue);
+#endif
+		dcfg.b.devaddr = UGETW(ctrl.wValue);
+		DWC_MODIFY_REG32(&dev_if->dev_global_regs->dcfg, 0, dcfg.d32);
+		do_setup_in_status_phase(pcd);
+	}
+}
+
+/**
+ *	This function processes SETUP commands. In Linux, the USB Command
+ *	processing is done in two places - the first being the PCD and the
+ *	second in the Gadget Driver (for example, the File-Backed Storage
+ *	Gadget Driver).
+ *
+ * <table>
+ * <tr><td>Command	</td><td>Driver </td><td>Description</td></tr>
+ *
+ * <tr><td>GET_STATUS </td><td>PCD </td><td>Command is processed as
+ * defined in chapter 9 of the USB 2.0 Specification chapter 9
+ * </td></tr>
+ *
+ * <tr><td>CLEAR_FEATURE </td><td>PCD </td><td>The Device and Endpoint
+ * requests are the ENDPOINT_HALT feature is procesed, all others the
+ * interface requests are ignored.</td></tr>
+ *
+ * <tr><td>SET_FEATURE </td><td>PCD </td><td>The Device and Endpoint
+ * requests are processed by the PCD.  Interface requests are passed
+ * to the Gadget Driver.</td></tr>
+ *
+ * <tr><td>SET_ADDRESS </td><td>PCD </td><td>Program the DCFG reg,
+ * with device address received </td></tr>
+ *
+ * <tr><td>GET_DESCRIPTOR </td><td>Gadget Driver </td><td>Return the
+ * requested descriptor</td></tr>
+ *
+ * <tr><td>SET_DESCRIPTOR </td><td>Gadget Driver </td><td>Optional -
+ * not implemented by any of the existing Gadget Drivers.</td></tr>
+ *
+ * <tr><td>SET_CONFIGURATION </td><td>Gadget Driver </td><td>Disable
+ * all EPs and enable EPs for new configuration.</td></tr>
+ *
+ * <tr><td>GET_CONFIGURATION </td><td>Gadget Driver </td><td>Return
+ * the current configuration</td></tr>
+ *
+ * <tr><td>SET_INTERFACE </td><td>Gadget Driver </td><td>Disable all
+ * EPs and enable EPs for new configuration.</td></tr>
+ *
+ * <tr><td>GET_INTERFACE </td><td>Gadget Driver </td><td>Return the
+ * current interface.</td></tr>
+ *
+ * <tr><td>SYNC_FRAME </td><td>PCD </td><td>Display debug
+ * message.</td></tr>
+ * </table>
+ *
+ * When the SETUP Phase Done interrupt occurs, the PCD SETUP commands are
+ * processed by pcd_setup. Calling the Function Driver's setup function from
+ * pcd_setup processes the gadget SETUP commands.
+ */
+static inline void pcd_setup(dwc_otg_pcd_t * pcd)
+{
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+	usb_device_request_t ctrl = pcd->setup_pkt->req;
+	dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
+
+	deptsiz0_data_t doeptsize0 = {.d32 = 0 };
+
+#ifdef DWC_UTE_CFI
+	int retval = 0;
+	struct cfi_usb_ctrlrequest cfi_req;
+#endif
+
+#ifdef DEBUG_EP0
+	DWC_DEBUGPL(DBG_PCD, "SETUP %02x.%02x v%04x i%04x l%04x\n",
+		    ctrl.bmRequestType, ctrl.bRequest,
+		    UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
+		    UGETW(ctrl.wLength));
+#endif
+
+	doeptsize0.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doeptsiz);
+
+	/** @todo handle > 1 setup packet , assert error for now */
+
+	if (core_if->dma_enable && core_if->dma_desc_enable == 0
+	    && (doeptsize0.b.supcnt < 2)) {
+		DWC_ERROR
+		    ("\n\n-----------	 CANNOT handle > 1 setup packet in DMA mode\n\n");
+	}
+
+	/* Clean up the request queue */
+	dwc_otg_request_nuke(ep0);
+	ep0->stopped = 0;
+
+	if (ctrl.bmRequestType & UE_DIR_IN) {
+		ep0->dwc_ep.is_in = 1;
+		pcd->ep0state = EP0_IN_DATA_PHASE;
+	} else {
+		ep0->dwc_ep.is_in = 0;
+		pcd->ep0state = EP0_OUT_DATA_PHASE;
+	}
+
+	if (UGETW(ctrl.wLength) == 0) {
+		ep0->dwc_ep.is_in = 1;
+		pcd->ep0state = EP0_IN_STATUS_PHASE;
+	}
+
+	if (UT_GET_TYPE(ctrl.bmRequestType) != UT_STANDARD) {
+
+#ifdef DWC_UTE_CFI
+		DWC_MEMCPY(&cfi_req, &ctrl, sizeof(usb_device_request_t));
+
+		//printk(KERN_ALERT "CFI: req_type=0x%02x; req=0x%02x\n", 
+				ctrl.bRequestType, ctrl.bRequest);
+		if (UT_GET_TYPE(cfi_req.bRequestType) == UT_VENDOR) {
+			if (cfi_req.bRequest > 0xB0 && cfi_req.bRequest < 0xBF) {
+				retval = cfi_setup(pcd, &cfi_req);
+				if (retval < 0) {
+					ep0_do_stall(pcd, retval);
+					pcd->ep0_pending = 0;
+					return;
+				}
+
+				/* if need gadget setup then call it and check the retval */
+				if (pcd->cfi->need_gadget_att) {
+					retval =
+					    cfi_gadget_setup(pcd,
+							     &pcd->
+							     cfi->ctrl_req);
+					if (retval < 0) {
+						pcd->ep0_pending = 0;
+						return;
+					}
+				}
+
+				if (pcd->cfi->need_status_in_complete) {
+					do_setup_in_status_phase(pcd);
+				}
+				return;
+			}
+		}
+#endif
+
+		/* handle non-standard (class/vendor) requests in the gadget driver */
+		do_gadget_setup(pcd, &ctrl);
+		return;
+	}
+
+	/** @todo NGS: Handle bad setup packet? */
+
+///////////////////////////////////////////
+//// --- Standard Request handling --- ////
+
+	switch (ctrl.bRequest) {
+	case UR_GET_STATUS:
+		do_get_status(pcd);
+		break;
+
+	case UR_CLEAR_FEATURE:
+		do_clear_feature(pcd);
+		break;
+
+	case UR_SET_FEATURE:
+		do_set_feature(pcd);
+		break;
+
+	case UR_SET_ADDRESS:
+		do_set_address(pcd);
+		break;
+
+	case UR_SET_INTERFACE:
+	case UR_SET_CONFIG:
+//              _pcd->request_config = 1;       /* Configuration changed */
+		do_gadget_setup(pcd, &ctrl);
+		break;
+
+	case UR_SYNCH_FRAME:
+		do_gadget_setup(pcd, &ctrl);
+		break;
+
+	default:
+		/* Call the Gadget Driver's setup functions */
+		do_gadget_setup(pcd, &ctrl);
+		break;
+	}
+}
+
+/**
+ * This function completes the ep0 control transfer.
+ */
+static int32_t ep0_complete_request(dwc_otg_pcd_ep_t * ep)
+{
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
+	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+	dwc_otg_dev_in_ep_regs_t *in_ep_regs =
+	    dev_if->in_ep_regs[ep->dwc_ep.num];
+#ifdef DEBUG_EP0
+	dwc_otg_dev_out_ep_regs_t *out_ep_regs =
+	    dev_if->out_ep_regs[ep->dwc_ep.num];
+#endif
+	deptsiz0_data_t deptsiz;
+	dev_dma_desc_sts_t desc_sts;
+	dwc_otg_pcd_request_t *req;
+	int is_last = 0;
+	dwc_otg_pcd_t *pcd = ep->pcd;
+
+#ifdef DWC_UTE_CFI
+	struct cfi_usb_ctrlrequest *ctrlreq;
+	int retval = -DWC_E_NOT_SUPPORTED;
+#endif
+
+	if (pcd->ep0_pending && DWC_CIRCLEQ_EMPTY(&ep->queue)) {
+		if (ep->dwc_ep.is_in) {
+#ifdef DEBUG_EP0
+			DWC_DEBUGPL(DBG_PCDV, "Do setup OUT status phase\n");
+#endif
+			do_setup_out_status_phase(pcd);
+		} else {
+#ifdef DEBUG_EP0
+			DWC_DEBUGPL(DBG_PCDV, "Do setup IN status phase\n");
+#endif
+
+#ifdef DWC_UTE_CFI
+			ctrlreq = &pcd->cfi->ctrl_req;
+
+			if (UT_GET_TYPE(ctrlreq->bRequestType) == UT_VENDOR) {
+				if (ctrlreq->bRequest > 0xB0
+				    && ctrlreq->bRequest < 0xBF) {
+
+					/* Return if the PCD failed to handle the request */
+					if ((retval =
+					     pcd->cfi->ops.
+					     ctrl_write_complete(pcd->cfi,
+								 pcd)) < 0) {
+						CFI_INFO
+						    ("ERROR setting a new value in the PCD(%d)\n",
+						     retval);
+						ep0_do_stall(pcd, retval);
+						pcd->ep0_pending = 0;
+						return 0;
+					}
+
+					/* If the gadget needs to be notified on the request */
+					if (pcd->cfi->need_gadget_att == 1) {
+						//retval = do_gadget_setup(pcd, &pcd->cfi->ctrl_req);
+						retval =
+						    cfi_gadget_setup(pcd,
+								     &pcd->cfi->
+								     ctrl_req);
+
+						/* Return from the function if the gadget failed to process
+						 * the request properly - this should never happen !!!
+						 */
+						if (retval < 0) {
+							CFI_INFO
+							    ("ERROR setting a new value in the gadget(%d)\n",
+							     retval);
+							pcd->ep0_pending = 0;
+							return 0;
+						}
+					}
+
+					CFI_INFO("%s: RETVAL=%d\n", __func__,
+						 retval);
+					/* If we hit here then the PCD and the gadget has properly
+					 * handled the request - so send the ZLP IN to the host.
+					 */
+					/* @todo: MAS - decide whether we need to start the setup
+					 * stage based on the need_setup value of the cfi object
+					 */
+					do_setup_in_status_phase(pcd);
+					pcd->ep0_pending = 0;
+					return 1;
+				}
+			}
+#endif
+
+			do_setup_in_status_phase(pcd);
+		}
+		pcd->ep0_pending = 0;
+		return 1;
+	}
+
+	if (DWC_CIRCLEQ_EMPTY(&ep->queue)) {
+		return 0;
+	}
+	req = DWC_CIRCLEQ_FIRST(&ep->queue);
+
+	if (pcd->ep0state == EP0_OUT_STATUS_PHASE
+	    || pcd->ep0state == EP0_IN_STATUS_PHASE) {
+		is_last = 1;
+	} else if (ep->dwc_ep.is_in) {
+		deptsiz.d32 = DWC_READ_REG32(&in_ep_regs->dieptsiz);
+		if (core_if->dma_desc_enable != 0)
+			desc_sts = dev_if->in_desc_addr->status;
+#ifdef DEBUG_EP0
+		DWC_DEBUGPL(DBG_PCDV, "%d len=%d  xfersize=%d pktcnt=%d\n",
+			    ep->dwc_ep.num, ep->dwc_ep.xfer_len,
+			    deptsiz.b.xfersize, deptsiz.b.pktcnt);
+#endif
+
+		if (((core_if->dma_desc_enable == 0)
+		     && (deptsiz.b.xfersize == 0))
+		    || ((core_if->dma_desc_enable != 0)
+			&& (desc_sts.b.bytes == 0))) {
+			req->actual = ep->dwc_ep.xfer_count;
+			/* Is a Zero Len Packet needed? */
+			if (req->sent_zlp) {
+#ifdef DEBUG_EP0
+				DWC_DEBUGPL(DBG_PCD, "Setup Rx ZLP\n");
+#endif
+				req->sent_zlp = 0;
+			}
+			do_setup_out_status_phase(pcd);
+		}
+	} else {
+		/* ep0-OUT */
+#ifdef DEBUG_EP0
+		deptsiz.d32 = DWC_READ_REG32(&out_ep_regs->doeptsiz);
+		DWC_DEBUGPL(DBG_PCDV, "%d len=%d xsize=%d pktcnt=%d\n",
+			    ep->dwc_ep.num, ep->dwc_ep.xfer_len,
+			    deptsiz.b.xfersize, deptsiz.b.pktcnt);
+#endif
+		req->actual = ep->dwc_ep.xfer_count;
+
+		/* Is a Zero Len Packet needed? */
+		if (req->sent_zlp) {
+#ifdef DEBUG_EP0
+			DWC_DEBUGPL(DBG_PCDV, "Setup Tx ZLP\n");
+#endif
+			req->sent_zlp = 0;
+		}
+		if (core_if->dma_desc_enable == 0)
+			do_setup_in_status_phase(pcd);
+	}
+
+	/* Complete the request */
+	if (is_last) {
+		dwc_otg_request_done(ep, req, 0);
+		ep->dwc_ep.start_xfer_buff = 0;
+		ep->dwc_ep.xfer_buff = 0;
+		ep->dwc_ep.xfer_len = 0;
+		return 1;
+	}
+	return 0;
+}
+
+#ifdef DWC_UTE_CFI
+/**
+ * This function calculates traverses all the CFI DMA descriptors and
+ * and accumulates the bytes that are left to be transfered.
+ *
+ * @return The total bytes left to transfered, or a negative value as failure
+ */
+static inline int cfi_calc_desc_residue(dwc_otg_pcd_ep_t * ep)
+{
+	int32_t ret = 0;
+	int i;
+	struct dwc_otg_dma_desc *ddesc = NULL;
+	struct cfi_ep *cfiep;
+
+	/* See if the pcd_ep has its respective cfi_ep mapped */
+	cfiep = get_cfi_ep_by_pcd_ep(ep->pcd->cfi, ep);
+	if (!cfiep) {
+		CFI_INFO("%s: Failed to find ep\n", __func__);
+		return -1;
+	}
+
+	ddesc = ep->dwc_ep.descs;
+
+	for (i = 0; (i < cfiep->desc_count) && (i < MAX_DMA_DESCS_PER_EP); i++) {
+
+#if defined(PRINT_CFI_DMA_DESCS)
+		print_desc(ddesc, ep->ep.name, i);
+#endif
+		ret += ddesc->status.b.bytes;
+		ddesc++;
+	}
+
+	if (ret)
+		CFI_INFO("!!!!!!!!!! WARNING (%s) - residue=%d\n", __func__,
+			 ret);
+
+	return ret;
+}
+#endif
+
+/**
+ * This function completes the request for the EP. If there are
+ * additional requests for the EP in the queue they will be started.
+ */
+static void complete_ep(dwc_otg_pcd_ep_t * ep)
+{
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
+	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+	dwc_otg_dev_in_ep_regs_t *in_ep_regs =
+	    dev_if->in_ep_regs[ep->dwc_ep.num];
+	deptsiz_data_t deptsiz;
+	dev_dma_desc_sts_t desc_sts;
+	dwc_otg_pcd_request_t *req = 0;
+	dwc_otg_dev_dma_desc_t *dma_desc;
+	uint32_t byte_count = 0;
+	int is_last = 0;
+	int i;
+
+	DWC_DEBUGPL(DBG_PCDV, "%s() %d-%s\n", __func__, ep->dwc_ep.num,
+		    (ep->dwc_ep.is_in ? "IN" : "OUT"));
+
+	/* Get any pending requests */
+	if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
+		req = DWC_CIRCLEQ_FIRST(&ep->queue);
+		if (!req) {
+			DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
+			return;
+		}
+	} else {
+		DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
+		return;
+	}
+
+	DWC_DEBUGPL(DBG_PCD, "Requests %d\n", ep->pcd->request_pending);
+
+	if (ep->dwc_ep.is_in) {
+		deptsiz.d32 = DWC_READ_REG32(&in_ep_regs->dieptsiz);
+
+		if (core_if->dma_enable) {
+			if (core_if->dma_desc_enable == 0) {
+				if (deptsiz.b.xfersize == 0
+				    && deptsiz.b.pktcnt == 0) {
+					byte_count =
+					    ep->dwc_ep.xfer_len -
+					    ep->dwc_ep.xfer_count;
+
+					ep->dwc_ep.xfer_buff += byte_count;
+					ep->dwc_ep.dma_addr += byte_count;
+					ep->dwc_ep.xfer_count += byte_count;
+
+					DWC_DEBUGPL(DBG_PCDV,
+						    "%d-%s len=%d  xfersize=%d pktcnt=%d\n",
+						    ep->dwc_ep.num,
+						    (ep->dwc_ep.
+						     is_in ? "IN" : "OUT"),
+						    ep->dwc_ep.xfer_len,
+						    deptsiz.b.xfersize,
+						    deptsiz.b.pktcnt);
+
+					if (ep->dwc_ep.xfer_len <
+					    ep->dwc_ep.total_len) {
+						dwc_otg_ep_start_transfer
+						    (core_if, &ep->dwc_ep);
+					} else if (ep->dwc_ep.sent_zlp) {
+						/*     
+						 * This fragment of code should initiate 0
+						 * length transfer in case if it is queued
+						 * a transfer with size divisible to EPs max
+						 * packet size and with usb_request zero field
+						 * is set, which means that after data is transfered,
+						 * it is also should be transfered
+						 * a 0 length packet at the end. For Slave and
+						 * Buffer DMA modes in this case SW has
+						 * to initiate 2 transfers one with transfer size,
+						 * and the second with 0 size. For Descriptor
+						 * DMA mode SW is able to initiate a transfer,
+						 * which will handle all the packets including
+						 * the last  0 length.
+						 */
+						ep->dwc_ep.sent_zlp = 0;
+						dwc_otg_ep_start_zl_transfer
+						    (core_if, &ep->dwc_ep);
+					} else {
+						is_last = 1;
+					}
+				} else {
+					if(ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC)
+					{
+						req->actual = 0;
+						dwc_otg_request_done(ep, req, 0);
+
+						ep->dwc_ep.start_xfer_buff = 0;
+						ep->dwc_ep.xfer_buff = 0;
+						ep->dwc_ep.xfer_len = 0;
+
+						/* If there is a request in the queue start it. */
+						start_next_request(ep);
+					} else
+						DWC_WARN
+						("Incomplete transfer (%d - %s [siz=%d pkt=%d])\n",
+						ep->dwc_ep.num,
+						(ep->dwc_ep.is_in ? "IN" : "OUT"),
+						deptsiz.b.xfersize,
+						deptsiz.b.pktcnt);
+				}
+			} else {
+				dma_desc = ep->dwc_ep.desc_addr;
+				byte_count = 0;
+				ep->dwc_ep.sent_zlp = 0;
+
+#ifdef DWC_UTE_CFI
+				CFI_INFO("%s: BUFFER_MODE=%d\n", __func__,
+					 ep->dwc_ep.buff_mode);
+				if (ep->dwc_ep.buff_mode != BM_STANDARD) {
+					int residue;
+
+					residue = cfi_calc_desc_residue(ep);
+					if (residue < 0)
+						return;
+
+					byte_count = residue;
+				} else {
+#endif
+					for (i = 0; i < ep->dwc_ep.desc_cnt;
+					     ++i) {
+					desc_sts = dma_desc->status;
+					byte_count += desc_sts.b.bytes;
+					dma_desc++;
+				}
+#ifdef DWC_UTE_CFI
+				}
+#endif
+				if (byte_count == 0) {
+					ep->dwc_ep.xfer_count =
+					    ep->dwc_ep.total_len;
+					is_last = 1;
+				} else {
+					DWC_WARN("Incomplete transfer\n");
+				}
+			}
+		} else {
+			if (deptsiz.b.xfersize == 0 && deptsiz.b.pktcnt == 0) {
+				DWC_DEBUGPL(DBG_PCDV,
+					    "%d-%s len=%d  xfersize=%d pktcnt=%d\n",
+					    ep->dwc_ep.num,
+					    ep->dwc_ep.is_in ? "IN" : "OUT",
+					    ep->dwc_ep.xfer_len,
+					    deptsiz.b.xfersize,
+					    deptsiz.b.pktcnt);
+
+				/*      Check if the whole transfer was completed, 
+				 *      if no, setup transfer for next portion of data
+				 */
+				if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
+					dwc_otg_ep_start_transfer(core_if,
+								  &ep->dwc_ep);
+				} else if (ep->dwc_ep.sent_zlp) {
+					/*     
+					 * This fragment of code should initiate 0
+					 * length trasfer in case if it is queued
+					 * a trasfer with size divisible to EPs max
+					 * packet size and with usb_request zero field
+					 * is set, which means that after data is transfered,
+					 * it is also should be transfered
+					 * a 0 length packet at the end. For Slave and
+					 * Buffer DMA modes in this case SW has
+					 * to initiate 2 transfers one with transfer size,
+					 * and the second with 0 size. For Desriptor
+					 * DMA mode SW is able to initiate a transfer,
+					 * which will handle all the packets including
+					 * the last  0 legth.
+					 */
+					ep->dwc_ep.sent_zlp = 0;
+					dwc_otg_ep_start_zl_transfer(core_if,
+								     &ep->dwc_ep);
+				} else {
+					is_last = 1;
+				}
+			} else {
+				DWC_WARN
+				    ("Incomplete transfer (%d-%s [siz=%d pkt=%d])\n",
+				     ep->dwc_ep.num,
+				     (ep->dwc_ep.is_in ? "IN" : "OUT"),
+				     deptsiz.b.xfersize, deptsiz.b.pktcnt);
+			}
+		}
+	} else {
+		dwc_otg_dev_out_ep_regs_t *out_ep_regs =
+		    dev_if->out_ep_regs[ep->dwc_ep.num];
+		desc_sts.d32 = 0;
+		if (core_if->dma_enable) {
+			if (core_if->dma_desc_enable) {
+				dma_desc = ep->dwc_ep.desc_addr;
+				byte_count = 0;
+				ep->dwc_ep.sent_zlp = 0;
+
+#ifdef DWC_UTE_CFI
+				CFI_INFO("%s: BUFFER_MODE=%d\n", __func__,
+					 ep->dwc_ep.buff_mode);
+				if (ep->dwc_ep.buff_mode != BM_STANDARD) {
+					int residue;
+					residue = cfi_calc_desc_residue(ep);
+					if (residue < 0)
+						return;
+					byte_count = residue;
+				} else {
+#endif
+
+					for (i = 0; i < ep->dwc_ep.desc_cnt;
+					     ++i) {
+						desc_sts = dma_desc->status;
+						byte_count += desc_sts.b.bytes;
+						dma_desc++;
+					}
+
+#ifdef DWC_UTE_CFI
+				}
+#endif
+				/* Checking for interrupt Out transfers with not 
+				 * dword aligned mps sizes 
+				 */
+				if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_INTR &&
+							(ep->dwc_ep.maxpacket%4)) {
+					ep->dwc_ep.xfer_count = ep->dwc_ep.total_len - byte_count;
+					if ((ep->dwc_ep.xfer_len % ep->dwc_ep.maxpacket) &&
+						(ep->dwc_ep.xfer_len/ep->dwc_ep.maxpacket < MAX_DMA_DESC_CNT))
+						ep->dwc_ep.xfer_len -=
+							(ep->dwc_ep.desc_cnt - 1) * ep->dwc_ep.maxpacket +
+									ep->dwc_ep.xfer_len % ep->dwc_ep.maxpacket;
+					else						
+						ep->dwc_ep.xfer_len -=
+									ep->dwc_ep.desc_cnt * ep->dwc_ep.maxpacket;
+					if (ep->dwc_ep.xfer_len > 0) {
+                                        	dwc_otg_ep_start_transfer(core_if,
+                                                                  &ep->dwc_ep);
+					} else {
+						is_last = 1;
+					}
+				} else {
+					ep->dwc_ep.xfer_count = ep->dwc_ep.total_len
+						- byte_count +
+						((4 - (ep->dwc_ep.total_len & 0x3)) & 0x3);
+					is_last = 1;
+				}	
+			} else {
+				deptsiz.d32 = 0;
+				deptsiz.d32 =
+				    DWC_READ_REG32(&out_ep_regs->doeptsiz);
+
+				byte_count = (ep->dwc_ep.xfer_len -
+					      ep->dwc_ep.xfer_count -
+					      deptsiz.b.xfersize);
+				ep->dwc_ep.xfer_buff += byte_count;
+				ep->dwc_ep.dma_addr += byte_count;
+				ep->dwc_ep.xfer_count += byte_count;
+
+				/*      Check if the whole transfer was completed, 
+				 *      if no, setup transfer for next portion of data
+				 */
+				if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
+					dwc_otg_ep_start_transfer(core_if,
+								  &ep->dwc_ep);
+				} else if (ep->dwc_ep.sent_zlp) {
+					/*     
+					 * This fragment of code should initiate 0
+					 * length trasfer in case if it is queued
+					 * a trasfer with size divisible to EPs max
+					 * packet size and with usb_request zero field
+					 * is set, which means that after data is transfered,
+					 * it is also should be transfered
+					 * a 0 length packet at the end. For Slave and
+					 * Buffer DMA modes in this case SW has
+					 * to initiate 2 transfers one with transfer size,
+					 * and the second with 0 size. For Desriptor
+					 * DMA mode SW is able to initiate a transfer,
+					 * which will handle all the packets including
+					 * the last  0 legth.
+					 */
+					ep->dwc_ep.sent_zlp = 0;
+					dwc_otg_ep_start_zl_transfer(core_if,
+								     &ep->dwc_ep);
+				} else {
+					is_last = 1;
+				}
+			}
+		} else {
+			/*      Check if the whole transfer was completed, 
+			 *      if no, setup transfer for next portion of data
+			 */
+			if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
+				dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep);
+			} else if (ep->dwc_ep.sent_zlp) {
+				/*     
+				 * This fragment of code should initiate 0
+				 * length transfer in case if it is queued
+				 * a transfer with size divisible to EPs max
+				 * packet size and with usb_request zero field
+				 * is set, which means that after data is transfered,
+				 * it is also should be transfered
+				 * a 0 length packet at the end. For Slave and
+				 * Buffer DMA modes in this case SW has
+				 * to initiate 2 transfers one with transfer size,
+				 * and the second with 0 size. For Descriptor
+				 * DMA mode SW is able to initiate a transfer,
+				 * which will handle all the packets including
+				 * the last  0 length.
+				 */
+				ep->dwc_ep.sent_zlp = 0;
+				dwc_otg_ep_start_zl_transfer(core_if,
+							     &ep->dwc_ep);
+			} else {
+				is_last = 1;
+			}
+		}
+
+		DWC_DEBUGPL(DBG_PCDV,
+			    "addr %p,	 %d-%s len=%d cnt=%d xsize=%d pktcnt=%d\n",
+			    &out_ep_regs->doeptsiz, ep->dwc_ep.num,
+			    ep->dwc_ep.is_in ? "IN" : "OUT",
+			    ep->dwc_ep.xfer_len, ep->dwc_ep.xfer_count,
+			    deptsiz.b.xfersize, deptsiz.b.pktcnt);
+	}
+
+	/* Complete the request */
+	if (is_last) {
+#ifdef DWC_UTE_CFI
+		if (ep->dwc_ep.buff_mode != BM_STANDARD) {
+			req->actual = ep->dwc_ep.cfi_req_len - byte_count;
+		} else {
+#endif
+			req->actual = ep->dwc_ep.xfer_count;
+#ifdef DWC_UTE_CFI
+		}
+#endif
+		if (req->dw_align_buf) {
+			if (!ep->dwc_ep.is_in) {
+				dwc_memcpy(req->buf, req->dw_align_buf, req->length); 
+			}
+			DWC_DMA_FREE(req->length, req->dw_align_buf,
+				     req->dw_align_buf_dma);
+		}
+
+		dwc_otg_request_done(ep, req, 0);
+
+		ep->dwc_ep.start_xfer_buff = 0;
+		ep->dwc_ep.xfer_buff = 0;
+		ep->dwc_ep.xfer_len = 0;
+
+		/* If there is a request in the queue start it. */
+		start_next_request(ep);
+	}
+}
+
+#ifdef DWC_EN_ISOC
+
+/**
+ * This function BNA interrupt for Isochronous EPs
+ *
+ */
+static void dwc_otg_pcd_handle_iso_bna(dwc_otg_pcd_ep_t * ep)
+{
+	dwc_ep_t *dwc_ep = &ep->dwc_ep;
+	volatile uint32_t *addr;
+	depctl_data_t depctl = {.d32 = 0 };
+	dwc_otg_pcd_t *pcd = ep->pcd;
+	dwc_otg_dev_dma_desc_t *dma_desc;
+	int i;
+
+	dma_desc =
+	    dwc_ep->iso_desc_addr + dwc_ep->desc_cnt * (dwc_ep->proc_buf_num);
+
+	if (dwc_ep->is_in) {
+		dev_dma_desc_sts_t sts = {.d32 = 0 };
+		for (i = 0; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
+			sts.d32 = dma_desc->status.d32;
+			sts.b_iso_in.bs = BS_HOST_READY;
+			dma_desc->status.d32 = sts.d32;
+		}
+	} else {
+		dev_dma_desc_sts_t sts = {.d32 = 0 };
+		for (i = 0; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
+			sts.d32 = dma_desc->status.d32;
+			sts.b_iso_out.bs = BS_HOST_READY;
+			dma_desc->status.d32 = sts.d32;
+		}
+	}
+
+	if (dwc_ep->is_in == 0) {
+		addr =
+		    &GET_CORE_IF(pcd)->dev_if->out_ep_regs[dwc_ep->
+							   num]->doepctl;
+	} else {
+		addr =
+		    &GET_CORE_IF(pcd)->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
+	}
+	depctl.b.epena = 1;
+	DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
+}
+
+/**
+ * This function sets latest iso packet information(non-PTI mode)
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param ep The EP to start the transfer on.
+ *
+ */
+void set_current_pkt_info(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+{
+	deptsiz_data_t deptsiz = {.d32 = 0 };
+	dma_addr_t dma_addr;
+	uint32_t offset;
+
+	if (ep->proc_buf_num)
+		dma_addr = ep->dma_addr1;
+	else
+		dma_addr = ep->dma_addr0;
+
+	if (ep->is_in) {
+		deptsiz.d32 =
+		    DWC_READ_REG32(&core_if->dev_if->
+				   in_ep_regs[ep->num]->dieptsiz);
+		offset = ep->data_per_frame;
+	} else {
+		deptsiz.d32 =
+		    DWC_READ_REG32(&core_if->dev_if->
+				   out_ep_regs[ep->num]->doeptsiz);
+		offset =
+		    ep->data_per_frame +
+		    (0x4 & (0x4 - (ep->data_per_frame & 0x3)));
+	}
+
+	if (!deptsiz.b.xfersize) {
+		ep->pkt_info[ep->cur_pkt].length = ep->data_per_frame;
+		ep->pkt_info[ep->cur_pkt].offset =
+		    ep->cur_pkt_dma_addr - dma_addr;
+		ep->pkt_info[ep->cur_pkt].status = 0;
+	} else {
+		ep->pkt_info[ep->cur_pkt].length = ep->data_per_frame;
+		ep->pkt_info[ep->cur_pkt].offset =
+		    ep->cur_pkt_dma_addr - dma_addr;
+		ep->pkt_info[ep->cur_pkt].status = -DWC_E_NO_DATA;
+	}
+	ep->cur_pkt_addr += offset;
+	ep->cur_pkt_dma_addr += offset;
+	ep->cur_pkt++;
+}
+
+/**
+ * This function sets latest iso packet information(DDMA mode)
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param dwc_ep The EP to start the transfer on.
+ *
+ */
+static void set_ddma_iso_pkts_info(dwc_otg_core_if_t * core_if,
+				   dwc_ep_t * dwc_ep)
+{
+	dwc_otg_dev_dma_desc_t *dma_desc;
+	dev_dma_desc_sts_t sts = {.d32 = 0 };
+	iso_pkt_info_t *iso_packet;
+	uint32_t data_per_desc;
+	uint32_t offset;
+	int i, j;
+
+	iso_packet = dwc_ep->pkt_info;
+
+	/** Reinit closed DMA Descriptors*/
+	/** ISO OUT EP */
+	if (dwc_ep->is_in == 0) {
+		dma_desc =
+		    dwc_ep->iso_desc_addr +
+		    dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
+		offset = 0;
+
+		for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
+		     i += dwc_ep->pkt_per_frm) {
+			for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
+				data_per_desc =
+				    ((j + 1) * dwc_ep->maxpacket >
+				     dwc_ep->
+				     data_per_frame) ? dwc_ep->data_per_frame -
+				    j * dwc_ep->maxpacket : dwc_ep->maxpacket;
+				data_per_desc +=
+				    (data_per_desc % 4) ? (4 -
+							   data_per_desc %
+							   4) : 0;
+
+				sts.d32 = dma_desc->status.d32;
+
+				/* Write status in iso_packet_decsriptor  */
+				iso_packet->status =
+				    sts.b_iso_out.rxsts +
+				    (sts.b_iso_out.bs ^ BS_DMA_DONE);
+				if (iso_packet->status) {
+					iso_packet->status = -DWC_E_NO_DATA;
+				}
+
+				/* Received data length */
+				if (!sts.b_iso_out.rxbytes) {
+					iso_packet->length =
+					    data_per_desc -
+					    sts.b_iso_out.rxbytes;
+				} else {
+					iso_packet->length =
+					    data_per_desc -
+					    sts.b_iso_out.rxbytes + (4 -
+								     dwc_ep->data_per_frame
+								     % 4);
+				}
+
+				iso_packet->offset = offset;
+
+				offset += data_per_desc;
+				dma_desc++;
+				iso_packet++;
+			}
+		}
+
+		for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
+			data_per_desc =
+			    ((j + 1) * dwc_ep->maxpacket >
+			     dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
+			    j * dwc_ep->maxpacket : dwc_ep->maxpacket;
+			data_per_desc +=
+			    (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
+
+			sts.d32 = dma_desc->status.d32;
+
+			/* Write status in iso_packet_decsriptor  */
+			iso_packet->status =
+			    sts.b_iso_out.rxsts +
+			    (sts.b_iso_out.bs ^ BS_DMA_DONE);
+			if (iso_packet->status) {
+				iso_packet->status = -DWC_E_NO_DATA;
+			}
+
+			/* Received data length */
+			iso_packet->length =
+			    dwc_ep->data_per_frame - sts.b_iso_out.rxbytes;
+
+			iso_packet->offset = offset;
+
+			offset += data_per_desc;
+			iso_packet++;
+			dma_desc++;
+		}
+
+		sts.d32 = dma_desc->status.d32;
+
+		/* Write status in iso_packet_decsriptor  */
+		iso_packet->status =
+		    sts.b_iso_out.rxsts + (sts.b_iso_out.bs ^ BS_DMA_DONE);
+		if (iso_packet->status) {
+			iso_packet->status = -DWC_E_NO_DATA;
+		}
+		/* Received data length */
+		if (!sts.b_iso_out.rxbytes) {
+			iso_packet->length =
+			    dwc_ep->data_per_frame - sts.b_iso_out.rxbytes;
+		} else {
+			iso_packet->length =
+			    dwc_ep->data_per_frame - sts.b_iso_out.rxbytes +
+			    (4 - dwc_ep->data_per_frame % 4);
+		}
+
+		iso_packet->offset = offset;
+	} else {
+/** ISO IN EP */
+
+		dma_desc =
+		    dwc_ep->iso_desc_addr +
+		    dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
+
+		for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
+			sts.d32 = dma_desc->status.d32;
+
+			/* Write status in iso packet descriptor */
+			iso_packet->status =
+			    sts.b_iso_in.txsts +
+			    (sts.b_iso_in.bs ^ BS_DMA_DONE);
+			if (iso_packet->status != 0) {
+				iso_packet->status = -DWC_E_NO_DATA;
+
+			}
+			/* Bytes has been transfered */
+			iso_packet->length =
+			    dwc_ep->data_per_frame - sts.b_iso_in.txbytes;
+
+			dma_desc++;
+			iso_packet++;
+		}
+
+		sts.d32 = dma_desc->status.d32;
+		while (sts.b_iso_in.bs == BS_DMA_BUSY) {
+			sts.d32 = dma_desc->status.d32;
+		}
+
+		/* Write status in iso packet descriptor ??? do be done with ERROR codes */
+		iso_packet->status =
+		    sts.b_iso_in.txsts + (sts.b_iso_in.bs ^ BS_DMA_DONE);
+		if (iso_packet->status != 0) {
+			iso_packet->status = -DWC_E_NO_DATA;
+		}
+
+		/* Bytes has been transfered */
+		iso_packet->length =
+		    dwc_ep->data_per_frame - sts.b_iso_in.txbytes;
+	}
+}
+
+/**
+ * This function reinitialize DMA Descriptors for Isochronous transfer
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param dwc_ep The EP to start the transfer on.
+ *
+ */
+static void reinit_ddma_iso_xfer(dwc_otg_core_if_t * core_if, dwc_ep_t * dwc_ep)
+{
+	int i, j;
+	dwc_otg_dev_dma_desc_t *dma_desc;
+	dma_addr_t dma_ad;
+	volatile uint32_t *addr;
+	dev_dma_desc_sts_t sts = {.d32 = 0 };
+	uint32_t data_per_desc;
+
+	if (dwc_ep->is_in == 0) {
+		addr = &core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl;
+	} else {
+		addr = &core_if->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
+	}
+
+	if (dwc_ep->proc_buf_num == 0) {
+		/** Buffer 0 descriptors setup */
+		dma_ad = dwc_ep->dma_addr0;
+	} else {
+		/** Buffer 1 descriptors setup */
+		dma_ad = dwc_ep->dma_addr1;
+	}
+
+	/** Reinit closed DMA Descriptors*/
+	/** ISO OUT EP */
+	if (dwc_ep->is_in == 0) {
+		dma_desc =
+		    dwc_ep->iso_desc_addr +
+		    dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
+
+		sts.b_iso_out.bs = BS_HOST_READY;
+		sts.b_iso_out.rxsts = 0;
+		sts.b_iso_out.l = 0;
+		sts.b_iso_out.sp = 0;
+		sts.b_iso_out.ioc = 0;
+		sts.b_iso_out.pid = 0;
+		sts.b_iso_out.framenum = 0;
+
+		for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
+		     i += dwc_ep->pkt_per_frm) {
+			for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
+				data_per_desc =
+				    ((j + 1) * dwc_ep->maxpacket >
+				     dwc_ep->
+				     data_per_frame) ? dwc_ep->data_per_frame -
+				    j * dwc_ep->maxpacket : dwc_ep->maxpacket;
+				data_per_desc +=
+				    (data_per_desc % 4) ? (4 -
+							   data_per_desc %
+							   4) : 0;
+				sts.b_iso_out.rxbytes = data_per_desc;
+				dma_desc->buf = dma_ad;
+				dma_desc->status.d32 = sts.d32;
+
+				dma_ad += data_per_desc;
+				dma_desc++;
+			}
+		}
+
+		for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
+
+			data_per_desc =
+			    ((j + 1) * dwc_ep->maxpacket >
+			     dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
+			    j * dwc_ep->maxpacket : dwc_ep->maxpacket;
+			data_per_desc +=
+			    (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
+			sts.b_iso_out.rxbytes = data_per_desc;
+
+			dma_desc->buf = dma_ad;
+			dma_desc->status.d32 = sts.d32;
+
+			dma_desc++;
+			dma_ad += data_per_desc;
+		}
+
+		sts.b_iso_out.ioc = 1;
+		sts.b_iso_out.l = dwc_ep->proc_buf_num;
+
+		data_per_desc =
+		    ((j + 1) * dwc_ep->maxpacket >
+		     dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
+		    j * dwc_ep->maxpacket : dwc_ep->maxpacket;
+		data_per_desc +=
+		    (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
+		sts.b_iso_out.rxbytes = data_per_desc;
+
+		dma_desc->buf = dma_ad;
+		dma_desc->status.d32 = sts.d32;
+	} else {
+/** ISO IN EP */
+
+		dma_desc =
+		    dwc_ep->iso_desc_addr +
+		    dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
+
+		sts.b_iso_in.bs = BS_HOST_READY;
+		sts.b_iso_in.txsts = 0;
+		sts.b_iso_in.sp = 0;
+		sts.b_iso_in.ioc = 0;
+		sts.b_iso_in.pid = dwc_ep->pkt_per_frm;
+		sts.b_iso_in.framenum = dwc_ep->next_frame;
+		sts.b_iso_in.txbytes = dwc_ep->data_per_frame;
+		sts.b_iso_in.l = 0;
+
+		for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
+			dma_desc->buf = dma_ad;
+			dma_desc->status.d32 = sts.d32;
+
+			sts.b_iso_in.framenum += dwc_ep->bInterval;
+			dma_ad += dwc_ep->data_per_frame;
+			dma_desc++;
+		}
+
+		sts.b_iso_in.ioc = 1;
+		sts.b_iso_in.l = dwc_ep->proc_buf_num;
+
+		dma_desc->buf = dma_ad;
+		dma_desc->status.d32 = sts.d32;
+
+		dwc_ep->next_frame =
+		    sts.b_iso_in.framenum + dwc_ep->bInterval * 1;
+	}
+	dwc_ep->proc_buf_num = (dwc_ep->proc_buf_num ^ 1) & 0x1;
+}
+
+/**
+ * This function is to handle Iso EP transfer complete interrupt
+ * in case Iso out packet was dropped
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param dwc_ep The EP for wihich transfer complete was asserted
+ *
+ */
+static uint32_t handle_iso_out_pkt_dropped(dwc_otg_core_if_t * core_if,
+					   dwc_ep_t * dwc_ep)
+{
+	uint32_t dma_addr;
+	uint32_t drp_pkt;
+	uint32_t drp_pkt_cnt;
+	deptsiz_data_t deptsiz = {.d32 = 0 };
+	depctl_data_t depctl = {.d32 = 0 };
+	int i;
+
+	deptsiz.d32 =
+	    DWC_READ_REG32(&core_if->dev_if->
+			   out_ep_regs[dwc_ep->num]->doeptsiz);
+
+	drp_pkt = dwc_ep->pkt_cnt - deptsiz.b.pktcnt;
+	drp_pkt_cnt = dwc_ep->pkt_per_frm - (drp_pkt % dwc_ep->pkt_per_frm);
+
+	/* Setting dropped packets status */
+	for (i = 0; i < drp_pkt_cnt; ++i) {
+		dwc_ep->pkt_info[drp_pkt].status = -DWC_E_NO_DATA;
+		drp_pkt++;
+		deptsiz.b.pktcnt--;
+	}
+
+	if (deptsiz.b.pktcnt > 0) {
+		deptsiz.b.xfersize =
+		    dwc_ep->xfer_len - (dwc_ep->pkt_cnt -
+					deptsiz.b.pktcnt) * dwc_ep->maxpacket;
+	} else {
+		deptsiz.b.xfersize = 0;
+		deptsiz.b.pktcnt = 0;
+	}
+
+	DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doeptsiz,
+			deptsiz.d32);
+
+	if (deptsiz.b.pktcnt > 0) {
+		if (dwc_ep->proc_buf_num) {
+			dma_addr =
+			    dwc_ep->dma_addr1 + dwc_ep->xfer_len -
+			    deptsiz.b.xfersize;
+		} else {
+			dma_addr =
+			    dwc_ep->dma_addr0 + dwc_ep->xfer_len -
+			    deptsiz.b.xfersize;;
+		}
+
+		DWC_WRITE_REG32(&core_if->dev_if->
+				out_ep_regs[dwc_ep->num]->doepdma, dma_addr);
+
+		/** Re-enable endpoint, clear nak  */
+		depctl.d32 = 0;
+		depctl.b.epena = 1;
+		depctl.b.cnak = 1;
+
+		DWC_MODIFY_REG32(&core_if->dev_if->
+				 out_ep_regs[dwc_ep->num]->doepctl, depctl.d32,
+				 depctl.d32);
+		return 0;
+	} else {
+		return 1;
+	}
+}
+
+/**
+ * This function sets iso packets information(PTI mode)
+ *
+ * @param core_if Programming view of DWC_otg controller.
+ * @param ep The EP to start the transfer on.
+ *
+ */
+static uint32_t set_iso_pkts_info(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+{
+	int i, j;
+	dma_addr_t dma_ad;
+	iso_pkt_info_t *packet_info = ep->pkt_info;
+	uint32_t offset;
+	uint32_t frame_data;
+	deptsiz_data_t deptsiz;
+
+	if (ep->proc_buf_num == 0) {
+		/** Buffer 0 descriptors setup */
+		dma_ad = ep->dma_addr0;
+	} else {
+		/** Buffer 1 descriptors setup */
+		dma_ad = ep->dma_addr1;
+	}
+
+	if (ep->is_in) {
+		deptsiz.d32 =
+		    DWC_READ_REG32(&core_if->dev_if->
+				   in_ep_regs[ep->num]->dieptsiz);
+	} else {
+		deptsiz.d32 =
+		    DWC_READ_REG32(&core_if->dev_if->
+				   out_ep_regs[ep->num]->doeptsiz);
+	}
+
+	if (!deptsiz.b.xfersize) {
+		offset = 0;
+		for (i = 0; i < ep->pkt_cnt; i += ep->pkt_per_frm) {
+			frame_data = ep->data_per_frame;
+			for (j = 0; j < ep->pkt_per_frm; ++j) {
+
+				/* Packet status - is not set as initially
+				 * it is set to 0 and if packet was sent
+				 successfully, status field will remain 0*/
+
+				/* Bytes has been transfered */
+				packet_info->length =
+				    (ep->maxpacket <
+				     frame_data) ? ep->maxpacket : frame_data;
+
+				/* Received packet offset */
+				packet_info->offset = offset;
+				offset += packet_info->length;
+				frame_data -= packet_info->length;
+
+				packet_info++;
+			}
+		}
+		return 1;
+	} else {
+		/* This is a workaround for in case of Transfer Complete with
+		 * PktDrpSts interrupts merging - in this case Transfer complete
+		 * interrupt for Isoc Out Endpoint is asserted without PktDrpSts
+		 * set and with DOEPTSIZ register non zero. Investigations showed,
+		 * that this happens when Out packet is dropped, but because of
+		 * interrupts merging during first interrupt handling PktDrpSts
+		 * bit is cleared and for next merged interrupts it is not reset.
+		 * In this case SW hadles the interrupt as if PktDrpSts bit is set.
+		 */
+		if (ep->is_in) {
+			return 1;
+		} else {
+			return handle_iso_out_pkt_dropped(core_if, ep);
+		}
+	}
+}
+
+/**
+ * This function is to handle Iso EP transfer complete interrupt
+ *
+ * @param pcd The PCD
+ * @param ep The EP for which transfer complete was asserted
+ *
+ */
+static void complete_iso_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep)
+{
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
+	dwc_ep_t *dwc_ep = &ep->dwc_ep;
+	uint8_t is_last = 0;
+
+	if (ep->dwc_ep.next_frame == 0xffffffff) {
+		DWC_WARN("Next frame is not set!\n");
+		return;
+	}
+
+	if (core_if->dma_enable) {
+		if (core_if->dma_desc_enable) {
+			set_ddma_iso_pkts_info(core_if, dwc_ep);
+			reinit_ddma_iso_xfer(core_if, dwc_ep);
+			is_last = 1;
+		} else {
+			if (core_if->pti_enh_enable) {
+				if (set_iso_pkts_info(core_if, dwc_ep)) {
+					dwc_ep->proc_buf_num =
+					    (dwc_ep->proc_buf_num ^ 1) & 0x1;
+					dwc_otg_iso_ep_start_buf_transfer
+					    (core_if, dwc_ep);
+					is_last = 1;
+				}
+			} else {
+				set_current_pkt_info(core_if, dwc_ep);
+				if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
+					is_last = 1;
+					dwc_ep->cur_pkt = 0;
+					dwc_ep->proc_buf_num =
+					    (dwc_ep->proc_buf_num ^ 1) & 0x1;
+					if (dwc_ep->proc_buf_num) {
+						dwc_ep->cur_pkt_addr =
+						    dwc_ep->xfer_buff1;
+						dwc_ep->cur_pkt_dma_addr =
+						    dwc_ep->dma_addr1;
+					} else {
+						dwc_ep->cur_pkt_addr =
+						    dwc_ep->xfer_buff0;
+						dwc_ep->cur_pkt_dma_addr =
+						    dwc_ep->dma_addr0;
+					}
+
+				}
+				dwc_otg_iso_ep_start_frm_transfer(core_if,
+								  dwc_ep);
+			}
+		}
+	} else {
+		set_current_pkt_info(core_if, dwc_ep);
+		if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
+			is_last = 1;
+			dwc_ep->cur_pkt = 0;
+			dwc_ep->proc_buf_num = (dwc_ep->proc_buf_num ^ 1) & 0x1;
+			if (dwc_ep->proc_buf_num) {
+				dwc_ep->cur_pkt_addr = dwc_ep->xfer_buff1;
+				dwc_ep->cur_pkt_dma_addr = dwc_ep->dma_addr1;
+			} else {
+				dwc_ep->cur_pkt_addr = dwc_ep->xfer_buff0;
+				dwc_ep->cur_pkt_dma_addr = dwc_ep->dma_addr0;
+			}
+
+		}
+		dwc_otg_iso_ep_start_frm_transfer(core_if, dwc_ep);
+	}
+	if (is_last)
+		dwc_otg_iso_buffer_done(pcd, ep, ep->iso_req_handle);
+}
+#endif /* DWC_EN_ISOC */
+
+/**
+ * This function handle BNA interrupt for Non Isochronous EPs
+ *
+ */
+static void dwc_otg_pcd_handle_noniso_bna(dwc_otg_pcd_ep_t * ep)
+{
+	dwc_ep_t *dwc_ep = &ep->dwc_ep;
+	volatile uint32_t *addr;
+	depctl_data_t depctl = {.d32 = 0 };
+	dwc_otg_pcd_t *pcd = ep->pcd;
+	dwc_otg_dev_dma_desc_t *dma_desc;
+	dev_dma_desc_sts_t sts = {.d32 = 0 };
+	dwc_otg_core_if_t *core_if = ep->pcd->core_if;
+	int i, start;
+
+	if (!dwc_ep->desc_cnt)
+		DWC_WARN("Descriptor count = %d\n", dwc_ep->desc_cnt);
+
+	if (core_if->core_params->cont_on_bna && !dwc_ep->is_in
+							&& dwc_ep->type != DWC_OTG_EP_TYPE_CONTROL) {
+		uint32_t doepdma;
+		dwc_otg_dev_out_ep_regs_t *out_regs =
+			core_if->dev_if->out_ep_regs[dwc_ep->num];
+		doepdma = DWC_READ_REG32(&(out_regs->doepdma));
+		start = (doepdma - dwc_ep->dma_desc_addr)/sizeof(dwc_otg_dev_dma_desc_t);
+		dma_desc = &(dwc_ep->desc_addr[start]);
+	} else {
+		start = 0;
+		dma_desc = dwc_ep->desc_addr;
+	}
+	
+
+	for (i = start; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
+		sts.d32 = dma_desc->status.d32;
+		sts.b.bs = BS_HOST_READY;
+		dma_desc->status.d32 = sts.d32;
+	}
+
+	if (dwc_ep->is_in == 0) {
+		addr =
+		    &GET_CORE_IF(pcd)->dev_if->out_ep_regs[dwc_ep->
+							   num]->doepctl;
+	} else {
+		addr =
+		    &GET_CORE_IF(pcd)->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
+	}
+	depctl.b.epena = 1;
+	depctl.b.cnak = 1;
+	DWC_MODIFY_REG32(addr, 0, depctl.d32);
+}
+
+/**
+ * This function handles EP0 Control transfers.
+ *
+ * The state of the control tranfers are tracked in
+ * <code>ep0state</code>.
+ */
+static void handle_ep0(dwc_otg_pcd_t * pcd)
+{
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+	dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
+	dev_dma_desc_sts_t desc_sts;
+	deptsiz0_data_t deptsiz;
+	uint32_t byte_count;
+
+#ifdef DEBUG_EP0
+	DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__);
+	print_ep0_state(pcd);
+#endif
+
+//      DWC_PRINTF("HANDLE EP0\n");
+
+	switch (pcd->ep0state) {
+	case EP0_DISCONNECT:
+		break;
+
+	case EP0_IDLE:
+		pcd->request_config = 0;
+
+		pcd_setup(pcd);
+		break;
+
+	case EP0_IN_DATA_PHASE:
+#ifdef DEBUG_EP0
+		DWC_DEBUGPL(DBG_PCD, "DATA_IN EP%d-%s: type=%d, mps=%d\n",
+			    ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"),
+			    ep0->dwc_ep.type, ep0->dwc_ep.maxpacket);
+#endif
+
+		if (core_if->dma_enable != 0) {
+			/*
+			 * For EP0 we can only program 1 packet at a time so we
+			 * need to do the make calculations after each complete.
+			 * Call write_packet to make the calculations, as in
+			 * slave mode, and use those values to determine if we
+			 * can complete.
+			 */
+			if (core_if->dma_desc_enable == 0) {
+				deptsiz.d32 =
+				    DWC_READ_REG32(&core_if->
+						   dev_if->in_ep_regs[0]->
+						   dieptsiz);
+				byte_count =
+				    ep0->dwc_ep.xfer_len - deptsiz.b.xfersize;
+			} else {
+				desc_sts =
+				    core_if->dev_if->in_desc_addr->status;
+				byte_count =
+				    ep0->dwc_ep.xfer_len - desc_sts.b.bytes;
+			}
+			ep0->dwc_ep.xfer_count += byte_count;
+			ep0->dwc_ep.xfer_buff += byte_count;
+			ep0->dwc_ep.dma_addr += byte_count;
+		}
+		if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len) {
+			dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
+						      &ep0->dwc_ep);
+			DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
+		} else if (ep0->dwc_ep.sent_zlp) {
+			dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
+						      &ep0->dwc_ep);
+			ep0->dwc_ep.sent_zlp = 0;
+			DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
+		} else {
+			ep0_complete_request(ep0);
+			DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n");
+		}
+		break;
+	case EP0_OUT_DATA_PHASE:
+#ifdef DEBUG_EP0
+		DWC_DEBUGPL(DBG_PCD, "DATA_OUT EP%d-%s: type=%d, mps=%d\n",
+			    ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"),
+			    ep0->dwc_ep.type, ep0->dwc_ep.maxpacket);
+#endif
+		if (core_if->dma_enable != 0) {
+			if (core_if->dma_desc_enable == 0) {
+				deptsiz.d32 =
+				    DWC_READ_REG32(&core_if->
+						   dev_if->out_ep_regs[0]->
+						   doeptsiz);
+				byte_count =
+				    ep0->dwc_ep.maxpacket - deptsiz.b.xfersize;
+			} else {
+				desc_sts =
+				    core_if->dev_if->out_desc_addr->status;
+				byte_count =
+				    ep0->dwc_ep.maxpacket - desc_sts.b.bytes;
+			}
+			ep0->dwc_ep.xfer_count += byte_count;
+			ep0->dwc_ep.xfer_buff += byte_count;
+			ep0->dwc_ep.dma_addr += byte_count;
+		}
+		if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len) {
+			dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
+						      &ep0->dwc_ep);
+			DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
+		} else if (ep0->dwc_ep.sent_zlp) {
+			dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
+						      &ep0->dwc_ep);
+			ep0->dwc_ep.sent_zlp = 0;
+			DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
+		} else {
+			ep0_complete_request(ep0);
+			DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n");
+		}
+		break;
+
+	case EP0_IN_STATUS_PHASE:
+	case EP0_OUT_STATUS_PHASE:
+		DWC_DEBUGPL(DBG_PCD, "CASE: EP0_STATUS\n");
+		ep0_complete_request(ep0);
+		pcd->ep0state = EP0_IDLE;
+		ep0->stopped = 1;
+		ep0->dwc_ep.is_in = 0;	/* OUT for next SETUP */
+
+		/* Prepare for more SETUP Packets */
+		if (core_if->dma_enable) {
+			ep0_out_start(core_if, pcd);
+		}
+		break;
+
+	case EP0_STALL:
+		DWC_ERROR("EP0 STALLed, should not get here pcd_setup()\n");
+		break;
+	}
+#ifdef DEBUG_EP0
+	print_ep0_state(pcd);
+#endif
+}
+
+/**
+ * Restart transfer
+ */
+static void restart_transfer(dwc_otg_pcd_t * pcd, const uint32_t epnum)
+{
+	dwc_otg_core_if_t *core_if;
+	dwc_otg_dev_if_t *dev_if;
+	deptsiz_data_t dieptsiz = {.d32 = 0 };
+	dwc_otg_pcd_ep_t *ep;
+
+	ep = get_in_ep(pcd, epnum);
+
+#ifdef DWC_EN_ISOC
+	if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
+		return;
+	}
+#endif /* DWC_EN_ISOC  */
+
+	core_if = GET_CORE_IF(pcd);
+	dev_if = core_if->dev_if;
+
+	dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dieptsiz);
+
+	DWC_DEBUGPL(DBG_PCD, "xfer_buff=%p xfer_count=%0x xfer_len=%0x"
+		    " stopped=%d\n", ep->dwc_ep.xfer_buff,
+		    ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len, ep->stopped);
+	/*
+	 * If xfersize is 0 and pktcnt in not 0, resend the last packet.
+	 */
+	if (dieptsiz.b.pktcnt && dieptsiz.b.xfersize == 0 &&
+	    ep->dwc_ep.start_xfer_buff != 0) {
+		if (ep->dwc_ep.total_len <= ep->dwc_ep.maxpacket) {
+			ep->dwc_ep.xfer_count = 0;
+			ep->dwc_ep.xfer_buff = ep->dwc_ep.start_xfer_buff;
+			ep->dwc_ep.xfer_len = ep->dwc_ep.xfer_count;
+		} else {
+			ep->dwc_ep.xfer_count -= ep->dwc_ep.maxpacket;
+			/* convert packet size to dwords. */
+			ep->dwc_ep.xfer_buff -= ep->dwc_ep.maxpacket;
+			ep->dwc_ep.xfer_len = ep->dwc_ep.xfer_count;
+		}
+		ep->stopped = 0;
+		DWC_DEBUGPL(DBG_PCD, "xfer_buff=%p xfer_count=%0x "
+			    "xfer_len=%0x stopped=%d\n",
+			    ep->dwc_ep.xfer_buff,
+			    ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len,
+			    ep->stopped);
+		if (epnum == 0) {
+			dwc_otg_ep0_start_transfer(core_if, &ep->dwc_ep);
+		} else {
+			dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep);
+		}
+	}
+}
+
+/*
+ * This function create new nextep sequnce based on Learn Queue.
+ *
+ * @param core_if Programming view of DWC_otg controller
+ */
+void predict_nextep_seq( dwc_otg_core_if_t * core_if)
+{
+	dwc_otg_device_global_regs_t *dev_global_regs =
+	    core_if->dev_if->dev_global_regs;
+	const uint32_t TOKEN_Q_DEPTH = core_if->hwcfg2.b.dev_token_q_depth;
+	/* Number of Token Queue Registers */
+	const int DTKNQ_REG_CNT = (TOKEN_Q_DEPTH + 7) / 8;
+	dtknq1_data_t dtknqr1;
+	uint32_t in_tkn_epnums[4];
+	uint8_t seqnum[MAX_EPS_CHANNELS];
+	uint8_t intkn_seq[TOKEN_Q_DEPTH];
+	grstctl_t resetctl = {.d32 = 0 };
+	uint8_t temp;
+	int ndx = 0;
+	int start = 0;
+	int end = 0;
+	int sort_done = 0;
+	int i = 0;
+	volatile uint32_t *addr = &dev_global_regs->dtknqr1;
+
+
+	DWC_DEBUGPL(DBG_PCD,"dev_token_q_depth=%d\n",TOKEN_Q_DEPTH);
+
+	/* Read the DTKNQ Registers */
+	for (i = 0; i < DTKNQ_REG_CNT; i++) {
+		in_tkn_epnums[i] = DWC_READ_REG32(addr);
+		DWC_DEBUGPL(DBG_PCDV, "DTKNQR%d=0x%08x\n", i + 1,
+			    in_tkn_epnums[i]);
+		if (addr == &dev_global_regs->dvbusdis) {
+			addr = &dev_global_regs->dtknqr3_dthrctl;
+		} else {
+			++addr;
+		}
+
+	}
+
+	/* Copy the DTKNQR1 data to the bit field. */
+	dtknqr1.d32 = in_tkn_epnums[0];
+	if (dtknqr1.b.wrap_bit) {
+		ndx = dtknqr1.b.intknwptr;
+		end = ndx -1;
+		if (end < 0) 
+			end = TOKEN_Q_DEPTH -1;
+	} else {
+		ndx = 0;
+		end = dtknqr1.b.intknwptr -1;
+		if (end < 0) 
+			end = 0;
+	}
+	start = ndx;
+	
+	/* Fill seqnum[] by initial values: EP number + 31 */
+	for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
+		seqnum[i] = i +31;
+	}
+	
+	/* Fill intkn_seq[] from in_tkn_epnums[0] */
+	for (i=0; i < 6; i++) 
+		intkn_seq[i] = (in_tkn_epnums[0] >> ((7-i) * 4)) & 0xf;
+	
+	if (TOKEN_Q_DEPTH > 6) {
+		/* Fill intkn_seq[] from in_tkn_epnums[1] */
+		for (i=6; i < 14; i++) 
+			intkn_seq[i] = (in_tkn_epnums[1] >> ((7-(i-6)) * 4)) & 0xf;
+	}
+	
+	if (TOKEN_Q_DEPTH > 14) {
+		/* Fill intkn_seq[] from in_tkn_epnums[1] */
+		for (i=14; i < 22; i++) 
+			intkn_seq[i] = (in_tkn_epnums[2] >> ((7-(i-14)) * 4)) & 0xf;
+	}
+
+	if (TOKEN_Q_DEPTH > 22) {
+		/* Fill intkn_seq[] from in_tkn_epnums[1] */
+		for (i=22; i < 30; i++) 
+			intkn_seq[i] = (in_tkn_epnums[3] >> ((7-(i-22)) * 4)) & 0xf;
+	}
+
+	DWC_DEBUGPL(DBG_PCDV,"%s start=%d end=%d intkn_seq[]:\n", __func__, start, end);
+	for (i=0; i<TOKEN_Q_DEPTH; i++) 
+		DWC_DEBUGPL(DBG_PCDV,"%d\n", intkn_seq[i]);
+
+	/* Update seqnum based on intkn_seq[] */
+	i = 0;
+	do {
+		seqnum[intkn_seq[ndx]] = i;
+		ndx++;
+		i++;
+		if (ndx == TOKEN_Q_DEPTH) 
+			ndx = 0;
+	} while ( i < TOKEN_Q_DEPTH );
+	
+	/* Mark non active EP's in seqnum[] by 0xff */
+	for (i=0; i<=core_if->dev_if->num_in_eps; i++) {
+		if (core_if->nextep_seq[i] == 0xff )
+			seqnum[i] = 0xff;
+	}
+	
+	/* Sort seqnum[] */
+	sort_done = 0;
+	while (!sort_done) {
+		sort_done = 1;
+		for (i=0; i<core_if->dev_if->num_in_eps; i++) {
+			if (seqnum[i] > seqnum[i+1]) {
+				temp = seqnum[i];
+				seqnum[i] = seqnum[i+1];
+				seqnum[i+1] = temp;
+				sort_done = 0;
+			}
+		}
+	}
+
+	ndx = start + seqnum[0];
+	if (ndx >= TOKEN_Q_DEPTH) 
+		ndx = ndx % TOKEN_Q_DEPTH;
+	core_if->first_in_nextep_seq = intkn_seq[ndx];
+	
+	/* Update seqnum[] by EP numbers  */
+	for (i=0; i<=core_if->dev_if->num_in_eps; i++) {
+		ndx = start + i;
+		if (seqnum[i] < 31) {
+			ndx = start + seqnum[i];
+			if (ndx >= TOKEN_Q_DEPTH) 
+				ndx = ndx % TOKEN_Q_DEPTH;
+			seqnum[i] = intkn_seq[ndx];
+		} else {
+			if (seqnum[i] < 0xff) {
+				seqnum[i] = seqnum[i] - 31;
+			} else {
+				break;
+			}
+		}
+	}
+
+	/* Update nextep_seq[] based on seqnum[] */
+	for (i=0; i<core_if->dev_if->num_in_eps; i++) {
+		if (seqnum[i] != 0xff) {
+			if (seqnum[i+1] != 0xff) {
+				core_if->nextep_seq[seqnum[i]] = seqnum[i+1];
+			} else {
+				core_if->nextep_seq[seqnum[i]] = core_if->first_in_nextep_seq;
+				break;
+			}
+		} else {
+			break;
+		}
+	}
+	
+	DWC_DEBUGPL(DBG_PCDV, "%s first_in_nextep_seq= %2d; nextep_seq[]:\n", 
+		__func__, core_if->first_in_nextep_seq);
+	for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
+		DWC_DEBUGPL(DBG_PCDV,"%2d\n", core_if->nextep_seq[i]);
+	}
+
+	/* Flush the Learning Queue */
+	resetctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->grstctl);
+	resetctl.b.intknqflsh = 1;
+	DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32);
+	
+
+}
+
+/**
+ * handle the IN EP disable interrupt.
+ */
+static inline void handle_in_ep_disable_intr(dwc_otg_pcd_t * pcd,
+					     const uint32_t epnum)
+{
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+	deptsiz_data_t dieptsiz = {.d32 = 0 };
+	dctl_data_t dctl = {.d32 = 0 };
+	dwc_otg_pcd_ep_t *ep;
+	dwc_ep_t *dwc_ep;
+	gintmsk_data_t gintmsk_data;
+	depctl_data_t depctl;
+	uint32_t diepdma;
+	uint32_t remain_to_transfer = 0;
+	uint8_t i;
+	uint32_t xfer_size;
+	
+	ep = get_in_ep(pcd, epnum);
+	dwc_ep = &ep->dwc_ep;
+
+	if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
+		dwc_otg_flush_tx_fifo(core_if, dwc_ep->tx_fifo_num);
+		complete_ep(ep);
+		return;
+	}
+
+	DWC_DEBUGPL(DBG_PCD, "diepctl%d=%0x\n", epnum,
+		    DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl));
+	dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dieptsiz);
+	depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
+
+	DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n",
+		    dieptsiz.b.pktcnt, dieptsiz.b.xfersize);
+	
+	if ((core_if->start_predict == 0) || (depctl.b.eptype & 1)) { 
+		if (ep->stopped) {
+			if (core_if->en_multiple_tx_fifo)
+				/* Flush the Tx FIFO */
+				dwc_otg_flush_tx_fifo(core_if, dwc_ep->tx_fifo_num);
+			/* Clear the Global IN NP NAK */
+			dctl.d32 = 0;
+			dctl.b.cgnpinnak = 1;
+			DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32); 
+			/* Restart the transaction */
+			if (dieptsiz.b.pktcnt != 0 || dieptsiz.b.xfersize != 0) {
+				restart_transfer(pcd, epnum);
+			}
+		} else {
+			/* Restart the transaction */
+			if (dieptsiz.b.pktcnt != 0 || dieptsiz.b.xfersize != 0) {
+				restart_transfer(pcd, epnum);
+			}
+			DWC_DEBUGPL(DBG_ANY, "STOPPED!!!\n");
+		}
+		return;
+	}
+
+	if (core_if->start_predict > 2) {	// NP IN EP
+		core_if->start_predict--;
+		return;
+	}
+
+	core_if->start_predict--;
+	
+	if (core_if->start_predict == 1) {	// All NP IN Ep's disabled now
+
+		predict_nextep_seq(core_if);
+			
+		/* Update all active IN EP's NextEP field based of nextep_seq[] */
+		for ( i = 0; i <= core_if->dev_if->num_in_eps; i++) {
+			depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
+			if (core_if->nextep_seq[i] != 0xff) {	// Active NP IN EP
+				depctl.b.nextep = core_if->nextep_seq[i];
+				DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
+			}
+		}
+		/* Flush Shared NP TxFIFO */
+		dwc_otg_flush_tx_fifo(core_if, 0);
+		/* Rewind buffers */
+		if (!core_if->dma_desc_enable) {		
+			i = core_if->first_in_nextep_seq;
+			do {
+				ep = get_in_ep(pcd, i);
+				dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz);
+				xfer_size = ep->dwc_ep.total_len - ep->dwc_ep.xfer_count;
+				if (xfer_size > ep->dwc_ep.maxxfer) 
+					xfer_size = ep->dwc_ep.maxxfer;
+				depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
+				if (dieptsiz.b.pktcnt != 0) {
+					if (xfer_size == 0) {
+						remain_to_transfer = 0;
+					} else {
+						if ((xfer_size % ep->dwc_ep.maxpacket) == 0) {
+							remain_to_transfer = 
+								dieptsiz.b.pktcnt * ep->dwc_ep.maxpacket;
+						} else {
+							remain_to_transfer = ((dieptsiz.b.pktcnt -1) * ep->dwc_ep.maxpacket) 
+								+ (xfer_size % ep->dwc_ep.maxpacket);
+						}
+					}
+					diepdma = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepdma);
+					dieptsiz.b.xfersize = remain_to_transfer;
+					DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->dieptsiz, dieptsiz.d32);
+					diepdma = ep->dwc_ep.dma_addr + (xfer_size - remain_to_transfer);
+					DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepdma, diepdma);
+				}
+				i = core_if->nextep_seq[i];
+			} while (i != core_if->first_in_nextep_seq);
+		} else { // dma_desc_enable
+				DWC_PRINTF("%s Learning Queue not supported in DDMA\n", __func__);
+		}
+				
+		/* Restart transfers in predicted sequences */
+		i = core_if->first_in_nextep_seq;
+		do {
+			dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz);
+			depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
+			if (dieptsiz.b.pktcnt != 0) {
+				depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
+				depctl.b.epena = 1;
+				depctl.b.cnak = 1;
+				DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
+			}
+			i = core_if->nextep_seq[i];
+		} while (i != core_if->first_in_nextep_seq);
+
+		/* Clear the global non-periodic IN NAK handshake */
+		dctl.d32 = 0;
+		dctl.b.cgnpinnak = 1;
+		DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32); 
+			
+		/* Unmask EP Mismatch interrupt */
+		gintmsk_data.d32 = 0;
+		gintmsk_data.b.epmismatch = 1;
+		DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, gintmsk_data.d32);
+		
+		core_if->start_predict = 0;
+
+	} 
+}
+
+/**
+ * Handler for the IN EP timeout handshake interrupt.
+ */
+static inline void handle_in_ep_timeout_intr(dwc_otg_pcd_t * pcd,
+					     const uint32_t epnum)
+{
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+
+#ifdef DEBUG
+	deptsiz_data_t dieptsiz = {.d32 = 0 };
+	uint32_t num = 0;
+#endif
+	dctl_data_t dctl = {.d32 = 0 };
+	dwc_otg_pcd_ep_t *ep;
+
+	gintmsk_data_t intr_mask = {.d32 = 0 };
+
+	ep = get_in_ep(pcd, epnum);
+
+	/* Disable the NP Tx Fifo Empty Interrrupt */
+	if (!core_if->dma_enable) {
+		intr_mask.b.nptxfempty = 1;
+		DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
+				 intr_mask.d32, 0);
+	}
+	/** @todo NGS Check EP type.
+	 * Implement for Periodic EPs */
+	/*
+	 * Non-periodic EP
+	 */
+	/* Enable the Global IN NAK Effective Interrupt */
+	intr_mask.b.ginnakeff = 1;
+	DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, intr_mask.d32);
+
+	/* Set Global IN NAK */
+	dctl.b.sgnpinnak = 1;
+	DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
+
+	ep->stopped = 1;
+
+#ifdef DEBUG
+	dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[num]->dieptsiz);
+	DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n",
+		    dieptsiz.b.pktcnt, dieptsiz.b.xfersize);
+#endif
+
+#ifdef DISABLE_PERIODIC_EP
+	/*
+	 * Set the NAK bit for this EP to
+	 * start the disable process.
+	 */
+	diepctl.d32 = 0;
+	diepctl.b.snak = 1;
+	DWC_MODIFY_REG32(&dev_if->in_ep_regs[num]->diepctl, diepctl.d32,
+			 diepctl.d32);
+	ep->disabling = 1;
+	ep->stopped = 1;
+#endif
+}
+
+/**
+ * Handler for the IN EP NAK interrupt.
+ */
+static inline int32_t handle_in_ep_nak_intr(dwc_otg_pcd_t * pcd,
+					    const uint32_t epnum)
+{
+	/** @todo implement ISR */
+	dwc_otg_core_if_t *core_if;
+	diepmsk_data_t intr_mask = {.d32 = 0 };
+
+	DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "IN EP NAK");
+	core_if = GET_CORE_IF(pcd);
+	intr_mask.b.nak = 1;
+
+	if (core_if->multiproc_int_enable) {
+		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
+				 diepeachintmsk[epnum], intr_mask.d32, 0);
+	} else {
+		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->diepmsk,
+				 intr_mask.d32, 0);
+	}
+
+	return 1;
+}
+
+/**
+ * Handler for the OUT EP Babble interrupt.
+ */
+static inline int32_t handle_out_ep_babble_intr(dwc_otg_pcd_t * pcd,
+						const uint32_t epnum)
+{
+	/** @todo implement ISR */
+	dwc_otg_core_if_t *core_if;
+	doepmsk_data_t intr_mask = {.d32 = 0 };
+
+	DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
+		   "OUT EP Babble");
+	core_if = GET_CORE_IF(pcd);
+	intr_mask.b.babble = 1;
+
+	if (core_if->multiproc_int_enable) {
+		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
+				 doepeachintmsk[epnum], intr_mask.d32, 0);
+	} else {
+		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
+				 intr_mask.d32, 0);
+	}
+
+	return 1;
+}
+
+/**
+ * Handler for the OUT EP NAK interrupt.
+ */
+static inline int32_t handle_out_ep_nak_intr(dwc_otg_pcd_t * pcd,
+					     const uint32_t epnum)
+{
+	/** @todo implement ISR */
+	dwc_otg_core_if_t *core_if;
+	doepmsk_data_t intr_mask = {.d32 = 0 };
+
+	DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "OUT EP NAK");
+	core_if = GET_CORE_IF(pcd);
+	intr_mask.b.nak = 1;
+
+	if (core_if->multiproc_int_enable) {
+		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
+				 doepeachintmsk[epnum], intr_mask.d32, 0);
+	} else {
+		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
+				 intr_mask.d32, 0);
+	}
+
+	return 1;
+}
+
+/**
+ * Handler for the OUT EP NYET interrupt.
+ */
+static inline int32_t handle_out_ep_nyet_intr(dwc_otg_pcd_t * pcd,
+					      const uint32_t epnum)
+{
+	/** @todo implement ISR */
+	dwc_otg_core_if_t *core_if;
+	doepmsk_data_t intr_mask = {.d32 = 0 };
+
+	DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "OUT EP NYET");
+	core_if = GET_CORE_IF(pcd);
+	intr_mask.b.nyet = 1;
+
+	if (core_if->multiproc_int_enable) {
+		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
+				 doepeachintmsk[epnum], intr_mask.d32, 0);
+	} else {
+		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
+				 intr_mask.d32, 0);
+	}
+
+	return 1;
+}
+
+/**
+ * This interrupt indicates that an IN EP has a pending Interrupt.
+ * The sequence for handling the IN EP interrupt is shown below:
+ * -#	Read the Device All Endpoint Interrupt register
+ * -#	Repeat the following for each IN EP interrupt bit set (from
+ *		LSB to MSB).
+ * -#	Read the Device Endpoint Interrupt (DIEPINTn) register
+ * -#	If "Transfer Complete" call the request complete function
+ * -#	If "Endpoint Disabled" complete the EP disable procedure.
+ * -#	If "AHB Error Interrupt" log error
+ * -#	If "Time-out Handshake" log error
+ * -#	If "IN Token Received when TxFIFO Empty" write packet to Tx
+ *		FIFO.
+ * -#	If "IN Token EP Mismatch" (disable, this is handled by EP
+ *		Mismatch Interrupt)
+ */
+static int32_t dwc_otg_pcd_handle_in_ep_intr(dwc_otg_pcd_t * pcd)
+{
+#define CLEAR_IN_EP_INTR(__core_if,__epnum,__intr) \
+do { \
+		diepint_data_t diepint = {.d32=0}; \
+		diepint.b.__intr = 1; \
+		DWC_WRITE_REG32(&__core_if->dev_if->in_ep_regs[__epnum]->diepint, \
+		diepint.d32); \
+} while (0)
+
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+	diepint_data_t diepint = {.d32 = 0 };
+	depctl_data_t depctl = {.d32 = 0 };
+	uint32_t ep_intr;
+	uint32_t epnum = 0;
+	dwc_otg_pcd_ep_t *ep;
+	dwc_ep_t *dwc_ep;
+	gintmsk_data_t intr_mask = {.d32 = 0 };
+
+	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, pcd);
+
+	/* Read in the device interrupt bits */
+	ep_intr = dwc_otg_read_dev_all_in_ep_intr(core_if);
+
+	/* Service the Device IN interrupts for each endpoint */
+	while (ep_intr) {
+		if (ep_intr & 0x1) {
+			uint32_t empty_msk;
+			/* Get EP pointer */
+			ep = get_in_ep(pcd, epnum);
+			dwc_ep = &ep->dwc_ep;
+
+			depctl.d32 =
+			    DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
+			empty_msk =
+			    DWC_READ_REG32(&dev_if->
+					   dev_global_regs->dtknqr4_fifoemptymsk);
+
+			DWC_DEBUGPL(DBG_PCDV,
+				    "IN EP INTERRUPT - %d\nepmty_msk - %8x  diepctl - %8x\n",
+				    epnum, empty_msk, depctl.d32);
+
+			DWC_DEBUGPL(DBG_PCD,
+				    "EP%d-%s: type=%d, mps=%d\n",
+				    dwc_ep->num, (dwc_ep->is_in ? "IN" : "OUT"),
+				    dwc_ep->type, dwc_ep->maxpacket);
+
+			diepint.d32 =
+			    dwc_otg_read_dev_in_ep_intr(core_if, dwc_ep);
+
+			DWC_DEBUGPL(DBG_PCDV,
+				    "EP %d Interrupt Register - 0x%x\n", epnum,
+				    diepint.d32);
+			/* Transfer complete */
+			if (diepint.b.xfercompl) {
+				/* Disable the NP Tx FIFO Empty
+				 * Interrrupt */
+				if (core_if->en_multiple_tx_fifo == 0) {
+					intr_mask.b.nptxfempty = 1;
+					DWC_MODIFY_REG32
+					    (&core_if->core_global_regs->gintmsk,
+					     intr_mask.d32, 0);
+				} else {
+					/* Disable the Tx FIFO Empty Interrupt for this EP */
+					uint32_t fifoemptymsk =
+					    0x1 << dwc_ep->num;
+					DWC_MODIFY_REG32(&core_if->
+							 dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
+							 fifoemptymsk, 0);
+				}
+				/* Clear the bit in DIEPINTn for this interrupt */
+				CLEAR_IN_EP_INTR(core_if, epnum, xfercompl);
+
+				/* Complete the transfer */
+				if (epnum == 0) {
+					handle_ep0(pcd);
+				}
+#ifdef DWC_EN_ISOC
+				else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
+					if (!ep->stopped)
+						complete_iso_ep(pcd, ep);
+				}
+#endif /* DWC_EN_ISOC */
+#ifdef DWC_UTE_PER_IO
+				else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
+					if (!ep->stopped)
+						complete_xiso_ep(ep);
+				}
+#endif /* DWC_UTE_PER_IO */
+				else {
+					if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC && 
+							dwc_ep->bInterval > 1) {
+						dwc_ep->frame_num += dwc_ep->bInterval;
+						if (dwc_ep->frame_num > 0x3FFF)
+						{
+							dwc_ep->frm_overrun = 1;
+							dwc_ep->frame_num &= 0x3FFF;
+						} else 
+							dwc_ep->frm_overrun = 0;
+					}
+					complete_ep(ep);
+					if(diepint.b.nak)
+						CLEAR_IN_EP_INTR(core_if, epnum, nak);
+				}
+			}
+			/* Endpoint disable      */
+			if (diepint.b.epdisabled) {
+				DWC_DEBUGPL(DBG_ANY, "EP%d IN disabled\n",
+					    epnum);
+				handle_in_ep_disable_intr(pcd, epnum);
+
+				/* Clear the bit in DIEPINTn for this interrupt */
+				CLEAR_IN_EP_INTR(core_if, epnum, epdisabled);
+			}
+			/* AHB Error */
+			if (diepint.b.ahberr) {
+				DWC_ERROR("EP%d IN AHB Error\n", epnum);
+				/* Clear the bit in DIEPINTn for this interrupt */
+				CLEAR_IN_EP_INTR(core_if, epnum, ahberr);
+			}
+			/* TimeOUT Handshake (non-ISOC IN EPs) */
+			if (diepint.b.timeout) {
+				DWC_ERROR("EP%d IN Time-out\n", epnum);
+				handle_in_ep_timeout_intr(pcd, epnum);
+
+				CLEAR_IN_EP_INTR(core_if, epnum, timeout);
+			}
+			/** IN Token received with TxF Empty */
+			if (diepint.b.intktxfemp) {
+				DWC_DEBUGPL(DBG_ANY,
+					    "EP%d IN TKN TxFifo Empty\n",
+					    epnum);
+				if (!ep->stopped && epnum != 0) {
+
+					diepmsk_data_t diepmsk = {.d32 = 0 };
+					diepmsk.b.intktxfemp = 1;
+
+					if (core_if->multiproc_int_enable) {
+						DWC_MODIFY_REG32
+						    (&dev_if->dev_global_regs->diepeachintmsk
+						     [epnum], diepmsk.d32, 0);
+					} else {
+						DWC_MODIFY_REG32
+						    (&dev_if->dev_global_regs->diepmsk,
+						     diepmsk.d32, 0);
+					}
+				} else if (core_if->dma_desc_enable
+					   && epnum == 0
+					   && pcd->ep0state ==
+					   EP0_OUT_STATUS_PHASE) {
+					// EP0 IN set STALL
+					depctl.d32 =
+					    DWC_READ_REG32(&dev_if->in_ep_regs
+							   [epnum]->diepctl);
+
+					/* set the disable and stall bits */
+					if (depctl.b.epena) {
+						depctl.b.epdis = 1;
+					}
+					depctl.b.stall = 1;
+					DWC_WRITE_REG32(&dev_if->in_ep_regs
+							[epnum]->diepctl,
+							depctl.d32);
+				}
+				CLEAR_IN_EP_INTR(core_if, epnum, intktxfemp);
+			}
+			/** IN Token Received with EP mismatch */
+			if (diepint.b.intknepmis) {
+				DWC_DEBUGPL(DBG_ANY,
+					    "EP%d IN TKN EP Mismatch\n", epnum);
+				CLEAR_IN_EP_INTR(core_if, epnum, intknepmis);				
+			}
+			/** IN Endpoint NAK Effective */
+			if (diepint.b.inepnakeff) {
+				DWC_DEBUGPL(DBG_ANY,
+					    "EP%d IN EP NAK Effective\n",
+					    epnum);
+				/* Periodic EP */
+				if (ep->disabling) {
+					depctl.d32 = 0;
+					depctl.b.snak = 1;
+					depctl.b.epdis = 1;
+					DWC_MODIFY_REG32(&dev_if->in_ep_regs
+							 [epnum]->diepctl,
+							 depctl.d32,
+							 depctl.d32);
+				}
+				CLEAR_IN_EP_INTR(core_if, epnum, inepnakeff);
+
+			}
+
+			/** IN EP Tx FIFO Empty Intr */
+			if (diepint.b.emptyintr) {
+				DWC_DEBUGPL(DBG_ANY,
+					    "EP%d Tx FIFO Empty Intr \n",
+					    epnum);
+				write_empty_tx_fifo(pcd, epnum);
+
+				CLEAR_IN_EP_INTR(core_if, epnum, emptyintr);
+
+			}
+
+			/** IN EP BNA Intr */
+			if (diepint.b.bna) {
+				CLEAR_IN_EP_INTR(core_if, epnum, bna);
+				if (core_if->dma_desc_enable) {
+#ifdef DWC_EN_ISOC
+					if (dwc_ep->type ==
+					    DWC_OTG_EP_TYPE_ISOC) {
+						/*
+						 * This checking is performed to prevent first "false" BNA
+						 * handling occuring right after reconnect
+						 */
+						if (dwc_ep->next_frame !=
+						    0xffffffff)
+							dwc_otg_pcd_handle_iso_bna(ep);
+					} else
+#endif				/* DWC_EN_ISOC */
+					{
+						dwc_otg_pcd_handle_noniso_bna(ep);
+					}
+				}
+			}
+			/* NAK Interrutp */
+			if (diepint.b.nak) {
+				DWC_DEBUGPL(DBG_ANY, "EP%d IN NAK Interrupt\n",
+					    epnum);
+				if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC)
+				{
+					depctl_data_t depctl;
+					if (ep->dwc_ep.frame_num == 0xFFFFFFFF) 
+					{
+						ep->dwc_ep.frame_num = core_if->frame_num;
+						if (ep->dwc_ep.bInterval > 1) 
+						{
+							depctl.d32 = 0;
+							depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
+							if (ep->dwc_ep.frame_num & 0x1) {
+								depctl.b.setd1pid = 1;
+								depctl.b.setd0pid = 0;
+							} else {
+								depctl.b.setd0pid = 1;
+								depctl.b.setd1pid = 0;
+							}
+							DWC_WRITE_REG32(&dev_if->in_ep_regs[epnum]->diepctl, depctl.d32);
+						}
+						start_next_request(ep);
+					}
+					ep->dwc_ep.frame_num += ep->dwc_ep.bInterval;
+					if (dwc_ep->frame_num > 0x3FFF)
+					{
+						dwc_ep->frm_overrun = 1;
+						dwc_ep->frame_num &= 0x3FFF;
+					} else 
+						dwc_ep->frm_overrun = 0;
+				}
+
+				CLEAR_IN_EP_INTR(core_if, epnum, nak);
+			}
+		}
+		epnum++;
+		ep_intr >>= 1;
+	}
+
+	return 1;
+#undef CLEAR_IN_EP_INTR
+}
+
+/**
+ * This interrupt indicates that an OUT EP has a pending Interrupt.
+ * The sequence for handling the OUT EP interrupt is shown below:
+ * -#	Read the Device All Endpoint Interrupt register
+ * -#	Repeat the following for each OUT EP interrupt bit set (from
+ *		LSB to MSB).
+ * -#	Read the Device Endpoint Interrupt (DOEPINTn) register
+ * -#	If "Transfer Complete" call the request complete function
+ * -#	If "Endpoint Disabled" complete the EP disable procedure.
+ * -#	If "AHB Error Interrupt" log error
+ * -#	If "Setup Phase Done" process Setup Packet (See Standard USB
+ *		Command Processing)
+ */
+static int32_t dwc_otg_pcd_handle_out_ep_intr(dwc_otg_pcd_t * pcd)
+{
+#define CLEAR_OUT_EP_INTR(__core_if,__epnum,__intr) \
+do { \
+		doepint_data_t doepint = {.d32=0}; \
+		doepint.b.__intr = 1; \
+		DWC_WRITE_REG32(&__core_if->dev_if->out_ep_regs[__epnum]->doepint, \
+		doepint.d32); \
+} while (0)
+
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+	uint32_t ep_intr;
+	doepint_data_t doepint = {.d32 = 0 };
+	uint32_t epnum = 0;
+	dwc_otg_pcd_ep_t *ep;
+	dwc_ep_t *dwc_ep;
+	dctl_data_t dctl = {.d32 = 0 };
+	gintmsk_data_t gintmsk = {.d32 = 0 };
+
+
+	DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__);
+
+	/* Read in the device interrupt bits */
+	ep_intr = dwc_otg_read_dev_all_out_ep_intr(core_if);
+
+	while (ep_intr) {
+		if (ep_intr & 0x1) {
+			/* Get EP pointer */
+			ep = get_out_ep(pcd, epnum);
+			dwc_ep = &ep->dwc_ep;
+
+#ifdef VERBOSE
+			DWC_DEBUGPL(DBG_PCDV,
+				    "EP%d-%s: type=%d, mps=%d\n",
+				    dwc_ep->num, (dwc_ep->is_in ? "IN" : "OUT"),
+				    dwc_ep->type, dwc_ep->maxpacket);
+#endif
+			doepint.d32 =
+			    dwc_otg_read_dev_out_ep_intr(core_if, dwc_ep);
+
+			/* Transfer complete */
+			if (doepint.b.xfercompl) {
+
+				if (epnum == 0) {
+					/* Clear the bit in DOEPINTn for this interrupt */
+					CLEAR_OUT_EP_INTR(core_if, epnum,
+							  xfercompl);
+					if (core_if->dma_desc_enable == 0
+					    || pcd->ep0state != EP0_IDLE)
+						handle_ep0(pcd);
+#ifdef DWC_EN_ISOC
+				} else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
+					if (doepint.b.pktdrpsts == 0) {
+						/* Clear the bit in DOEPINTn for this interrupt */
+						CLEAR_OUT_EP_INTR(core_if,
+								  epnum,
+								  xfercompl);
+						complete_iso_ep(pcd, ep);
+					} else {
+
+						doepint_data_t doepint = {.d32 = 0 };
+						doepint.b.xfercompl = 1;
+						doepint.b.pktdrpsts = 1;
+						DWC_WRITE_REG32
+						    (&core_if->dev_if->out_ep_regs
+						     [epnum]->doepint,
+						     doepint.d32);
+						if (handle_iso_out_pkt_dropped
+						    (core_if, dwc_ep)) {
+							complete_iso_ep(pcd,
+									ep);
+						}
+					}
+#endif /* DWC_EN_ISOC */
+#ifdef DWC_UTE_PER_IO
+				} else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
+					CLEAR_OUT_EP_INTR(core_if, epnum, xfercompl);
+					if (!ep->stopped)
+						complete_xiso_ep(ep);
+#endif /* DWC_UTE_PER_IO */
+				} else {
+					/* Clear the bit in DOEPINTn for this interrupt */
+					CLEAR_OUT_EP_INTR(core_if, epnum,
+							  xfercompl);
+
+					if (core_if->core_params->dev_out_nak) {
+						DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[epnum]);
+						pcd->core_if->ep_xfer_info[epnum].state = 0;
+#ifdef DEBUG
+						print_memory_payload(pcd, dwc_ep);
+#endif
+					}
+					complete_ep(ep);						
+				}
+
+			}
+
+			/* Endpoint disable      */
+			if (doepint.b.epdisabled) {
+
+				/* Clear the bit in DOEPINTn for this interrupt */
+				CLEAR_OUT_EP_INTR(core_if, epnum, epdisabled);
+				if (core_if->core_params->dev_out_nak) {
+#ifdef DEBUG
+					print_memory_payload(pcd, dwc_ep);
+#endif
+					/* In case of timeout condition */
+					if (core_if->ep_xfer_info[epnum].state == 2) {
+						dctl.d32 = DWC_READ_REG32(&core_if->dev_if->
+										dev_global_regs->dctl);
+						dctl.b.cgoutnak = 1;
+						DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl,
+																dctl.d32);
+						/* Unmask goutnakeff interrupt which was masked
+						 * during handle nak out interrupt */
+						gintmsk.b.goutnakeff = 1;
+						DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
+																0, gintmsk.d32);
+					
+						complete_ep(ep);
+					}
+				}
+				if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC)
+				{
+					dctl_data_t dctl;
+					gintmsk_data_t intr_mask = {.d32 = 0};
+					dwc_otg_pcd_request_t *req = 0;
+
+					dctl.d32 = DWC_READ_REG32(&core_if->dev_if->
+						dev_global_regs->dctl);
+					dctl.b.cgoutnak = 1;
+					DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl,
+						dctl.d32);
+
+					intr_mask.d32 = 0;
+					intr_mask.b.incomplisoout = 1;	   
+
+					/* Get any pending requests */
+					if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
+						req = DWC_CIRCLEQ_FIRST(&ep->queue);
+						if (!req) {
+							DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
+						} else {
+							dwc_otg_request_done(ep, req, 0);
+							start_next_request(ep);
+						}
+					} else {
+						DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
+					}
+				}
+			}
+			/* AHB Error */
+			if (doepint.b.ahberr) {
+				DWC_ERROR("EP%d OUT AHB Error\n", epnum);
+				DWC_ERROR("EP%d DEPDMA=0x%08x \n",
+					  epnum, core_if->dev_if->out_ep_regs[epnum]->doepdma);
+				CLEAR_OUT_EP_INTR(core_if, epnum, ahberr);
+			}
+			/* Setup Phase Done (contorl EPs) */
+			if (doepint.b.setup) {
+#ifdef DEBUG_EP0
+				DWC_DEBUGPL(DBG_PCD, "EP%d SETUP Done\n",
+					    epnum);
+#endif
+				CLEAR_OUT_EP_INTR(core_if, epnum, setup);
+
+				handle_ep0(pcd);
+			}
+
+			/** OUT EP BNA Intr */
+			if (doepint.b.bna) {
+				CLEAR_OUT_EP_INTR(core_if, epnum, bna);
+				if (core_if->dma_desc_enable) {
+#ifdef DWC_EN_ISOC
+					if (dwc_ep->type ==
+					    DWC_OTG_EP_TYPE_ISOC) {
+						/*
+						 * This checking is performed to prevent first "false" BNA
+						 * handling occuring right after reconnect
+						 */
+						if (dwc_ep->next_frame !=
+						    0xffffffff)
+							dwc_otg_pcd_handle_iso_bna(ep);
+					} else
+#endif				/* DWC_EN_ISOC */
+					{
+						dwc_otg_pcd_handle_noniso_bna(ep);
+					}
+				}
+			}
+			if (doepint.b.stsphsercvd) {
+				CLEAR_OUT_EP_INTR(core_if, epnum, stsphsercvd);
+				if (core_if->dma_desc_enable) {
+					do_setup_in_status_phase(pcd);
+				}
+			}
+			/* Babble Interrutp */
+			if (doepint.b.babble) {
+				DWC_DEBUGPL(DBG_ANY, "EP%d OUT Babble\n",
+					    epnum);
+				handle_out_ep_babble_intr(pcd, epnum);
+
+				CLEAR_OUT_EP_INTR(core_if, epnum, babble);
+			}
+			if (doepint.b.outtknepdis)
+			{
+				DWC_DEBUGPL(DBG_ANY, "EP%d OUT Token received when EP is \
+					disabled\n",epnum);
+				if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC)
+				{
+					doepmsk_data_t doepmsk = {.d32 = 0};
+					ep->dwc_ep.frame_num = core_if->frame_num;
+					if (ep->dwc_ep.bInterval > 1) 
+					{
+						depctl_data_t depctl;
+						depctl.d32 = DWC_READ_REG32(&core_if->dev_if->
+													out_ep_regs[epnum]->doepctl);
+						if (ep->dwc_ep.frame_num & 0x1) {
+							depctl.b.setd1pid = 1;
+							depctl.b.setd0pid = 0;
+						} else {
+							depctl.b.setd0pid = 1;
+							depctl.b.setd1pid = 0;
+						}
+						DWC_WRITE_REG32(&core_if->dev_if->
+										out_ep_regs[epnum]->doepctl, depctl.d32);
+					}
+					start_next_request(ep);
+					doepmsk.b.outtknepdis = 1;
+					DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk, 
+								 doepmsk.d32, 0);
+				}
+				CLEAR_OUT_EP_INTR(core_if, epnum, outtknepdis);
+			}
+			
+			/* NAK Interrutp */
+			if (doepint.b.nak) {
+				DWC_DEBUGPL(DBG_ANY, "EP%d OUT NAK\n", epnum);
+				handle_out_ep_nak_intr(pcd, epnum);
+
+				CLEAR_OUT_EP_INTR(core_if, epnum, nak);
+			}
+			/* NYET Interrutp */
+			if (doepint.b.nyet) {
+				DWC_DEBUGPL(DBG_ANY, "EP%d OUT NYET\n", epnum);
+				handle_out_ep_nyet_intr(pcd, epnum);
+
+				CLEAR_OUT_EP_INTR(core_if, epnum, nyet);
+			}
+		}
+
+		epnum++;
+		ep_intr >>= 1;
+	}
+
+	return 1;
+
+#undef CLEAR_OUT_EP_INTR
+}
+static int drop_transfer(uint32_t trgt_fr, uint32_t curr_fr, uint8_t frm_overrun)
+{
+	int retval = 0;
+	if(!frm_overrun && curr_fr >= trgt_fr) 
+		retval = 1;
+	else if (frm_overrun && (curr_fr >= trgt_fr && ((curr_fr - trgt_fr) < 0x3FFF/2)))
+		retval = 1;
+	return retval;
+}
+/**
+ * Incomplete ISO IN Transfer Interrupt.
+ * This interrupt indicates one of the following conditions occurred
+ * while transmitting an ISOC transaction.
+ * - Corrupted IN Token for ISOC EP.
+ * - Packet not complete in FIFO.
+ * The follow actions will be taken:
+ *	-#	Determine the EP
+ *	-#	Set incomplete flag in dwc_ep structure
+ *	-#	Disable EP; when "Endpoint Disabled" interrupt is received
+ *		Flush FIFO
+ */
+int32_t dwc_otg_pcd_handle_incomplete_isoc_in_intr(dwc_otg_pcd_t * pcd)
+{
+	gintsts_data_t gintsts;
+
+#ifdef DWC_EN_ISOC
+	dwc_otg_dev_if_t *dev_if;
+	deptsiz_data_t deptsiz = {.d32 = 0 };
+	depctl_data_t depctl = {.d32 = 0 };
+	dsts_data_t dsts = {.d32 = 0 };
+	dwc_ep_t *dwc_ep;
+	int i;
+
+	dev_if = GET_CORE_IF(pcd)->dev_if;
+
+	for (i = 1; i <= dev_if->num_in_eps; ++i) {
+		dwc_ep = &pcd->in_ep[i].dwc_ep;
+		if (dwc_ep->active && dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
+			deptsiz.d32 =
+			    DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz);
+			depctl.d32 =
+			    DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
+
+			if (depctl.b.epdis && deptsiz.d32) {
+				set_current_pkt_info(GET_CORE_IF(pcd), dwc_ep);
+				if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
+					dwc_ep->cur_pkt = 0;
+					dwc_ep->proc_buf_num =
+					    (dwc_ep->proc_buf_num ^ 1) & 0x1;
+
+					if (dwc_ep->proc_buf_num) {
+						dwc_ep->cur_pkt_addr =
+						    dwc_ep->xfer_buff1;
+						dwc_ep->cur_pkt_dma_addr =
+						    dwc_ep->dma_addr1;
+					} else {
+						dwc_ep->cur_pkt_addr =
+						    dwc_ep->xfer_buff0;
+						dwc_ep->cur_pkt_dma_addr =
+						    dwc_ep->dma_addr0;
+					}
+
+				}
+
+				dsts.d32 =
+				    DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if->
+						   dev_global_regs->dsts);
+				dwc_ep->next_frame = dsts.b.soffn;
+
+				dwc_otg_iso_ep_start_frm_transfer(GET_CORE_IF
+								  (pcd),
+								  dwc_ep);
+			}
+		}
+	}
+
+#else
+	depctl_data_t depctl = {.d32 = 0 };
+	dwc_ep_t *dwc_ep;
+	dwc_otg_dev_if_t *dev_if;
+	int i;
+	dev_if = GET_CORE_IF(pcd)->dev_if;
+
+	DWC_DEBUGPL(DBG_PCD,"Incomplete ISO IN \n");
+	
+	for (i = 1; i <= dev_if->num_in_eps; ++i) {
+		dwc_ep = &pcd->in_ep[i-1].dwc_ep;
+		depctl.d32 =
+			DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
+		if (depctl.b.epena && dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
+			if (drop_transfer(dwc_ep->frame_num, GET_CORE_IF(pcd)->frame_num, 
+							dwc_ep->frm_overrun))
+			{
+				depctl.d32 =
+					DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
+				depctl.b.snak = 1;
+				depctl.b.epdis = 1;
+				DWC_MODIFY_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32, depctl.d32);
+			}
+		}
+	}
+
+	/*intr_mask.b.incomplisoin = 1;
+	DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
+			 intr_mask.d32, 0);	 */
+#endif				//DWC_EN_ISOC
+
+	/* Clear interrupt */
+	gintsts.d32 = 0;
+	gintsts.b.incomplisoin = 1;
+	DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
+			gintsts.d32);
+
+	return 1;
+}
+
+/**
+ * Incomplete ISO OUT Transfer Interrupt.
+ *
+ * This interrupt indicates that the core has dropped an ISO OUT
+ * packet. The following conditions can be the cause:
+ * - FIFO Full, the entire packet would not fit in the FIFO.
+ * - CRC Error
+ * - Corrupted Token
+ * The follow actions will be taken:
+ *	-#	Determine the EP
+ *	-#	Set incomplete flag in dwc_ep structure
+ *	-#	Read any data from the FIFO
+ *	-#	Disable EP. When "Endpoint Disabled" interrupt is received
+ *		re-enable EP.
+ */
+int32_t dwc_otg_pcd_handle_incomplete_isoc_out_intr(dwc_otg_pcd_t * pcd)
+{
+
+	gintsts_data_t gintsts;
+
+#ifdef DWC_EN_ISOC
+	dwc_otg_dev_if_t *dev_if;
+	deptsiz_data_t deptsiz = {.d32 = 0 };
+	depctl_data_t depctl = {.d32 = 0 };
+	dsts_data_t dsts = {.d32 = 0 };
+	dwc_ep_t *dwc_ep;
+	int i;
+
+	dev_if = GET_CORE_IF(pcd)->dev_if;
+
+	for (i = 1; i <= dev_if->num_out_eps; ++i) {
+		dwc_ep = &pcd->in_ep[i].dwc_ep;
+		if (pcd->out_ep[i].dwc_ep.active &&
+		    pcd->out_ep[i].dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
+			deptsiz.d32 =
+			    DWC_READ_REG32(&dev_if->out_ep_regs[i]->doeptsiz);
+			depctl.d32 =
+			    DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl);
+
+			if (depctl.b.epdis && deptsiz.d32) {
+				set_current_pkt_info(GET_CORE_IF(pcd),
+						     &pcd->out_ep[i].dwc_ep);
+				if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
+					dwc_ep->cur_pkt = 0;
+					dwc_ep->proc_buf_num =
+					    (dwc_ep->proc_buf_num ^ 1) & 0x1;
+
+					if (dwc_ep->proc_buf_num) {
+						dwc_ep->cur_pkt_addr =
+						    dwc_ep->xfer_buff1;
+						dwc_ep->cur_pkt_dma_addr =
+						    dwc_ep->dma_addr1;
+					} else {
+						dwc_ep->cur_pkt_addr =
+						    dwc_ep->xfer_buff0;
+						dwc_ep->cur_pkt_dma_addr =
+						    dwc_ep->dma_addr0;
+					}
+
+				}
+
+				dsts.d32 =
+				    DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if->
+						   dev_global_regs->dsts);
+				dwc_ep->next_frame = dsts.b.soffn;
+
+				dwc_otg_iso_ep_start_frm_transfer(GET_CORE_IF
+								  (pcd),
+								  dwc_ep);
+			}
+		}
+	}
+#else
+	/** @todo implement ISR */
+	gintmsk_data_t intr_mask = {.d32 = 0 };
+	dwc_otg_core_if_t *core_if;
+	deptsiz_data_t deptsiz = {.d32 = 0 };
+	depctl_data_t depctl = {.d32 = 0 };
+	dctl_data_t dctl = {.d32 = 0 };
+	dwc_ep_t *dwc_ep = NULL;
+	int i;
+	core_if = GET_CORE_IF(pcd);
+
+	for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
+		dwc_ep = &pcd->out_ep[i].dwc_ep;
+		depctl.d32 =
+			DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl);
+		if (depctl.b.epena && depctl.b.dpid == (core_if->frame_num & 0x1)) {
+			core_if->dev_if->isoc_ep = dwc_ep;	
+			deptsiz.d32 =
+					DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doeptsiz);
+				break;
+		}
+	}
+	dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
+	gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
+	intr_mask.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
+
+	if (!intr_mask.b.goutnakeff) {
+		/* Unmask it */
+		intr_mask.b.goutnakeff = 1;
+		DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, intr_mask.d32);
+ 	}
+	if (!gintsts.b.goutnakeff) {
+		dctl.b.sgoutnak = 1;
+	}
+	DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
+
+	depctl.d32 = DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl);
+	if (depctl.b.epena) {
+		depctl.b.epdis = 1;
+		depctl.b.snak = 1;
+	}
+	DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl, depctl.d32);
+
+	intr_mask.d32 = 0;
+	intr_mask.b.incomplisoout = 1;
+		
+#endif /* DWC_EN_ISOC */
+
+	/* Clear interrupt */
+	gintsts.d32 = 0;
+	gintsts.b.incomplisoout = 1;
+	DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
+			gintsts.d32);
+
+	return 1;
+}
+
+/**
+ * This function handles the Global IN NAK Effective interrupt.
+ *
+ */
+int32_t dwc_otg_pcd_handle_in_nak_effective(dwc_otg_pcd_t * pcd)
+{
+	dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
+	depctl_data_t diepctl = {.d32 = 0 };
+	gintmsk_data_t intr_mask = {.d32 = 0 };
+	gintsts_data_t gintsts;
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+	int i;
+
+	DWC_DEBUGPL(DBG_PCD, "Global IN NAK Effective\n");
+
+	/* Disable all active IN EPs */
+	for (i = 0; i <= dev_if->num_in_eps; i++) {
+		diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
+		if (!(diepctl.b.eptype & 1) && diepctl.b.epena) {
+			if (core_if->start_predict > 0)
+				core_if->start_predict++;
+			diepctl.b.epdis = 1;
+			diepctl.b.snak = 1;
+			DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, diepctl.d32);
+		}						
+	}
+	
+
+	/* Disable the Global IN NAK Effective Interrupt */
+	intr_mask.b.ginnakeff = 1;
+	DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
+			 intr_mask.d32, 0);
+
+	/* Clear interrupt */
+	gintsts.d32 = 0;
+	gintsts.b.ginnakeff = 1;
+	DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
+			gintsts.d32);
+
+	return 1;
+}
+
+/**
+ * OUT NAK Effective.
+ *
+ */
+int32_t dwc_otg_pcd_handle_out_nak_effective(dwc_otg_pcd_t * pcd)
+{
+	dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
+	gintmsk_data_t intr_mask = {.d32 = 0 };
+	gintsts_data_t gintsts;
+	depctl_data_t doepctl;
+	int i;
+
+	/* Disable the Global OUT NAK Effective Interrupt */
+	intr_mask.b.goutnakeff = 1;
+	DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
+		intr_mask.d32, 0);
+	
+	/* If DEV OUT NAK enabled*/
+	if (pcd->core_if->core_params->dev_out_nak) {
+		/* Run over all out endpoints to determine the ep number on
+		 * which the timeout has happened 
+		 */
+		for (i = 0; i <= dev_if->num_out_eps; i++) {
+			if ( pcd->core_if->ep_xfer_info[i].state == 2 )
+				break;
+		}
+		if (i > dev_if->num_out_eps) {
+			dctl_data_t dctl;
+			dctl.d32 = DWC_READ_REG32(&dev_if->
+				dev_global_regs->dctl);
+			dctl.b.cgoutnak = 1;
+			DWC_WRITE_REG32(&dev_if->dev_global_regs->dctl,
+				dctl.d32);
+			goto out;
+		}
+
+		/* Disable the endpoint */
+		doepctl.d32 = DWC_READ_REG32(&dev_if->
+										out_ep_regs[i]->doepctl);
+		if (doepctl.b.epena) {
+			doepctl.b.epdis = 1;
+			doepctl.b.snak = 1;
+		}
+		DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, doepctl.d32);
+		return 1;
+	}
+	/* We come here from Incomplete ISO OUT handler */
+	if(dev_if->isoc_ep)
+	{
+		dwc_ep_t *dwc_ep = (dwc_ep_t *)dev_if->isoc_ep;
+		uint32_t epnum = dwc_ep->num;
+		doepint_data_t doepint;
+		doepint.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[dwc_ep->num]->doepint);
+		dev_if->isoc_ep = NULL;
+		doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[epnum]->doepctl);
+		DWC_PRINTF("Before disable DOEPCTL = %08x\n", doepctl.d32);
+		if (doepctl.b.epena) {
+			doepctl.b.epdis = 1;
+			doepctl.b.snak = 1;
+		}
+		DWC_WRITE_REG32(&dev_if->out_ep_regs[epnum]->doepctl, doepctl.d32);
+		return 1;
+	} else
+		DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
+			   "Global OUT NAK Effective\n");
+	
+out:
+	/* Clear interrupt */
+	gintsts.d32 = 0;
+	gintsts.b.goutnakeff = 1;
+	DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
+			gintsts.d32);
+
+	return 1;
+}
+
+/**
+ * PCD interrupt handler.
+ *
+ * The PCD handles the device interrupts.  Many conditions can cause a
+ * device interrupt. When an interrupt occurs, the device interrupt
+ * service routine determines the cause of the interrupt and
+ * dispatches handling to the appropriate function. These interrupt
+ * handling functions are described below.
+ *
+ * All interrupt registers are processed from LSB to MSB.
+ *
+ */
+int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t * pcd)
+{
+	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+#ifdef VERBOSE
+	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+#endif
+	gintsts_data_t gintr_status;
+	int32_t retval = 0;
+
+	/* Exit from ISR if core is hibernated */
+	if (core_if->hibernation_suspend == 1) {
+		return retval;
+	}
+#ifdef VERBOSE
+	DWC_DEBUGPL(DBG_ANY, "%s() gintsts=%08x	 gintmsk=%08x\n",
+		    __func__,
+		    DWC_READ_REG32(&global_regs->gintsts),
+		    DWC_READ_REG32(&global_regs->gintmsk));
+#endif
+
+	if (dwc_otg_is_device_mode(core_if)) {
+		DWC_SPINLOCK(pcd->lock);
+#ifdef VERBOSE
+		DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%08x  gintmsk=%08x\n",
+			    __func__,
+			    DWC_READ_REG32(&global_regs->gintsts),
+			    DWC_READ_REG32(&global_regs->gintmsk));
+#endif
+
+		gintr_status.d32 = dwc_otg_read_core_intr(core_if);
+
+		DWC_DEBUGPL(DBG_PCDV, "%s: gintsts&gintmsk=%08x\n",
+			    __func__, gintr_status.d32);
+
+		if (gintr_status.b.sofintr) {
+			retval |= dwc_otg_pcd_handle_sof_intr(pcd);
+		}
+		if (gintr_status.b.rxstsqlvl) {
+			retval |=
+			    dwc_otg_pcd_handle_rx_status_q_level_intr(pcd);
+		}
+		if (gintr_status.b.nptxfempty) {
+			retval |= dwc_otg_pcd_handle_np_tx_fifo_empty_intr(pcd);
+		}
+		if (gintr_status.b.goutnakeff) {
+			retval |= dwc_otg_pcd_handle_out_nak_effective(pcd);
+		}
+		if (gintr_status.b.i2cintr) {
+			retval |= dwc_otg_pcd_handle_i2c_intr(pcd);
+		}
+		if (gintr_status.b.erlysuspend) {
+			retval |= dwc_otg_pcd_handle_early_suspend_intr(pcd);
+		}
+		if (gintr_status.b.usbreset) {
+			retval |= dwc_otg_pcd_handle_usb_reset_intr(pcd);
+		}
+		if (gintr_status.b.enumdone) {
+			retval |= dwc_otg_pcd_handle_enum_done_intr(pcd);
+		}
+		if (gintr_status.b.isooutdrop) {
+			retval |=
+			    dwc_otg_pcd_handle_isoc_out_packet_dropped_intr
+			    (pcd);
+		}
+		if (gintr_status.b.eopframe) {
+			retval |=
+			    dwc_otg_pcd_handle_end_periodic_frame_intr(pcd);
+		}
+		if (gintr_status.b.inepint) {
+			if (!core_if->multiproc_int_enable) {
+				retval |= dwc_otg_pcd_handle_in_ep_intr(pcd);
+			}
+		}
+		if (gintr_status.b.outepintr) {
+			if (!core_if->multiproc_int_enable) {
+				retval |= dwc_otg_pcd_handle_out_ep_intr(pcd);
+			}
+		}
+		if (gintr_status.b.epmismatch) {
+			retval |= dwc_otg_pcd_handle_ep_mismatch_intr(pcd);
+		}
+		if (gintr_status.b.fetsusp) {
+			retval |= dwc_otg_pcd_handle_ep_fetsusp_intr(pcd);
+		}
+		if (gintr_status.b.ginnakeff) {
+			retval |= dwc_otg_pcd_handle_in_nak_effective(pcd);
+		}
+		if (gintr_status.b.incomplisoin) {
+			retval |=
+			    dwc_otg_pcd_handle_incomplete_isoc_in_intr(pcd);
+		}
+		if (gintr_status.b.incomplisoout) {
+			retval |=
+			    dwc_otg_pcd_handle_incomplete_isoc_out_intr(pcd);
+		}
+
+		/* In MPI mode Device Endpoints interrupts are asserted
+		 * without setting outepintr and inepint bits set, so these
+		 * Interrupt handlers are called without checking these bit-fields
+		 */
+		if (core_if->multiproc_int_enable) {
+			retval |= dwc_otg_pcd_handle_in_ep_intr(pcd);
+			retval |= dwc_otg_pcd_handle_out_ep_intr(pcd);
+		}
+#ifdef VERBOSE
+		DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%0x\n", __func__,
+			    DWC_READ_REG32(&global_regs->gintsts));
+#endif
+		DWC_SPINUNLOCK(pcd->lock);
+	}
+	return retval;
+}
+
+#endif /* DWC_HOST_ONLY */
diff --git a/drivers/usb/dwc_otg/dwc_otg_pcd_linux.c b/drivers/usb/dwc_otg/dwc_otg_pcd_linux.c
new file mode 100644
index 0000000..387d725
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_pcd_linux.c
@@ -0,0 +1,1320 @@
+ /* ==========================================================================
+  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_linux.c $
+  * $Revision: #19 $
+  * $Date: 2011/10/26 $
+  * $Change: 1873028 $
+  *
+  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+  * otherwise expressly agreed to in writing between Synopsys and you.
+  *
+  * The Software IS NOT an item of Licensed Software or Licensed Product under
+  * any End User Software License Agreement or Agreement for Licensed Product
+  * with Synopsys or any supplement thereto. You are permitted to use and
+  * redistribute this Software in source and binary forms, with or without
+  * modification, provided that redistributions of source code must retain this
+  * notice. You may not view, use, disclose, copy or distribute this file or
+  * any information contained herein except pursuant to this license grant from
+  * Synopsys. If you do not agree with this notice, including the disclaimer
+  * below, then you are not authorized to use the Software.
+  *
+  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+  * DAMAGE.
+  * ========================================================================== */
+#ifndef DWC_HOST_ONLY
+
+/** @file
+ * This file implements the Peripheral Controller Driver.
+ *
+ * The Peripheral Controller Driver (PCD) is responsible for
+ * translating requests from the Function Driver into the appropriate
+ * actions on the DWC_otg controller. It isolates the Function Driver
+ * from the specifics of the controller by providing an API to the
+ * Function Driver.
+ *
+ * The Peripheral Controller Driver for Linux will implement the
+ * Gadget API, so that the existing Gadget drivers can be used.
+ * (Gadget Driver is the Linux terminology for a Function Driver.)
+ *
+ * The Linux Gadget API is defined in the header file
+ * <code><linux/usb_gadget.h></code>.  The USB EP operations API is
+ * defined in the structure <code>usb_ep_ops</code> and the USB
+ * Controller API is defined in the structure
+ * <code>usb_gadget_ops</code>.
+ *
+ */
+
+#include "dwc_otg_os_dep.h"
+#include "dwc_otg_pcd_if.h"
+#include "dwc_otg_pcd.h"
+#include "dwc_otg_driver.h"
+#include "dwc_otg_dbg.h"
+
+static struct gadget_wrapper {
+	dwc_otg_pcd_t *pcd;
+
+	struct usb_gadget gadget;
+	struct usb_gadget_driver *driver;
+
+	struct usb_ep ep0;
+	struct usb_ep in_ep[16];
+	struct usb_ep out_ep[16];
+
+} *gadget_wrapper;
+
+/* Display the contents of the buffer */
+extern void dump_msg(const u8 * buf, unsigned int length);
+/**
+ * Get the dwc_otg_pcd_ep_t* from usb_ep* pointer - NULL in case
+ * if the endpoint is not found
+ */
+static struct dwc_otg_pcd_ep *ep_from_handle(dwc_otg_pcd_t * pcd, void *handle)
+{
+	int i;
+	if (pcd->ep0.priv == handle) {
+		return &pcd->ep0;
+	}
+
+	for (i = 0; i < MAX_EPS_CHANNELS - 1; i++) {
+		if (pcd->in_ep[i].priv == handle)
+			return &pcd->in_ep[i];
+		if (pcd->out_ep[i].priv == handle)
+			return &pcd->out_ep[i];
+	}
+
+	return NULL;
+}
+
+/* USB Endpoint Operations */
+/*
+ * The following sections briefly describe the behavior of the Gadget
+ * API endpoint operations implemented in the DWC_otg driver
+ * software. Detailed descriptions of the generic behavior of each of
+ * these functions can be found in the Linux header file
+ * include/linux/usb_gadget.h.
+ *
+ * The Gadget API provides wrapper functions for each of the function
+ * pointers defined in usb_ep_ops. The Gadget Driver calls the wrapper
+ * function, which then calls the underlying PCD function. The
+ * following sections are named according to the wrapper
+ * functions. Within each section, the corresponding DWC_otg PCD
+ * function name is specified.
+ *
+ */
+
+/**
+ * This function is called by the Gadget Driver for each EP to be
+ * configured for the current configuration (SET_CONFIGURATION).
+ *
+ * This function initializes the dwc_otg_ep_t data structure, and then
+ * calls dwc_otg_ep_activate.
+ */
+static int ep_enable(struct usb_ep *usb_ep,
+		     const struct usb_endpoint_descriptor *ep_desc)
+{
+	int retval;
+
+	DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, ep_desc);
+
+	if (!usb_ep || !ep_desc || ep_desc->bDescriptorType != USB_DT_ENDPOINT) {
+		DWC_WARN("%s, bad ep or descriptor\n", __func__);
+		return -EINVAL;
+	}
+	if (usb_ep == &gadget_wrapper->ep0) {
+		DWC_WARN("%s, bad ep(0)\n", __func__);
+		return -EINVAL;
+	}
+
+	/* Check FIFO size? */
+	if (!ep_desc->wMaxPacketSize) {
+		DWC_WARN("%s, bad %s maxpacket\n", __func__, usb_ep->name);
+		return -ERANGE;
+	}
+
+	if (!gadget_wrapper->driver ||
+	    gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
+		DWC_WARN("%s, bogus device state\n", __func__);
+		return -ESHUTDOWN;
+	}
+
+	/* Delete after check - MAS */
+#if 0
+	nat = (uint32_t) ep_desc->wMaxPacketSize;
+	printk(KERN_ALERT "%s: nat (before) =%d\n", __func__, nat);
+	nat = (nat >> 11) & 0x03;
+	printk(KERN_ALERT "%s: nat (after) =%d\n", __func__, nat);
+#endif
+	retval = dwc_otg_pcd_ep_enable(gadget_wrapper->pcd,
+				       (const uint8_t *)ep_desc,
+				       (void *)usb_ep);
+	if (retval) {
+		DWC_WARN("dwc_otg_pcd_ep_enable failed\n");
+		return -EINVAL;
+	}
+
+	usb_ep->maxpacket = le16_to_cpu(ep_desc->wMaxPacketSize);
+
+	return 0;
+}
+
+/**
+ * This function is called when an EP is disabled due to disconnect or
+ * change in configuration. Any pending requests will terminate with a
+ * status of -ESHUTDOWN.
+ *
+ * This function modifies the dwc_otg_ep_t data structure for this EP,
+ * and then calls dwc_otg_ep_deactivate.
+ */
+static int ep_disable(struct usb_ep *usb_ep)
+{
+	int retval;
+
+	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, usb_ep);
+	if (!usb_ep) {
+		DWC_DEBUGPL(DBG_PCD, "%s, %s not enabled\n", __func__,
+			    usb_ep ? usb_ep->name : NULL);
+		return -EINVAL;
+	}
+
+	retval = dwc_otg_pcd_ep_disable(gadget_wrapper->pcd, usb_ep);
+	if (retval) {
+		retval = -EINVAL;
+	}
+
+	return retval;
+}
+
+/**
+ * This function allocates a request object to use with the specified
+ * endpoint.
+ *
+ * @param ep The endpoint to be used with with the request
+ * @param gfp_flags the GFP_* flags to use.
+ */
+static struct usb_request *dwc_otg_pcd_alloc_request(struct usb_ep *ep,
+						     gfp_t gfp_flags)
+{
+	struct usb_request *usb_req;
+
+	DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d)\n", __func__, ep, gfp_flags);
+	if (0 == ep) {
+		DWC_WARN("%s() %s\n", __func__, "Invalid EP!\n");
+		return 0;
+	}
+	usb_req = kmalloc(sizeof(*usb_req), gfp_flags);
+	if (0 == usb_req) {
+		DWC_WARN("%s() %s\n", __func__, "request allocation failed!\n");
+		return 0;
+	}
+	memset(usb_req, 0, sizeof(*usb_req));
+	usb_req->dma = DWC_DMA_ADDR_INVALID;
+
+	return usb_req;
+}
+
+/**
+ * This function frees a request object.
+ *
+ * @param ep The endpoint associated with the request
+ * @param req The request being freed
+ */
+static void dwc_otg_pcd_free_request(struct usb_ep *ep, struct usb_request *req)
+{
+	DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, ep, req);
+
+	if (0 == ep || 0 == req) {
+		DWC_WARN("%s() %s\n", __func__,
+			 "Invalid ep or req argument!\n");
+		return;
+	}
+
+	kfree(req);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+/**
+ * This function allocates an I/O buffer to be used for a transfer
+ * to/from the specified endpoint.
+ *
+ * @param usb_ep The endpoint to be used with with the request
+ * @param bytes The desired number of bytes for the buffer
+ * @param dma Pointer to the buffer's DMA address; must be valid
+ * @param gfp_flags the GFP_* flags to use.
+ * @return address of a new buffer or null is buffer could not be allocated.
+ */
+static void *dwc_otg_pcd_alloc_buffer(struct usb_ep *usb_ep, unsigned bytes,
+				      dma_addr_t * dma, gfp_t gfp_flags)
+{
+	void *buf;
+	dwc_otg_pcd_t *pcd = 0;
+
+	pcd = gadget_wrapper->pcd;
+
+	DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d,%p,%0x)\n", __func__, usb_ep, bytes,
+		    dma, gfp_flags);
+
+	/* Check dword alignment */
+	if ((bytes & 0x3UL) != 0) {
+		DWC_WARN("%s() Buffer size is not a multiple of"
+			 "DWORD size (%d)", __func__, bytes);
+	}
+
+	buf = dma_alloc_coherent(NULL, bytes, dma, gfp_flags);
+
+	/* Check dword alignment */
+	if (((int)buf & 0x3UL) != 0) {
+		DWC_WARN("%s() Buffer is not DWORD aligned (%p)",
+			 __func__, buf);
+	}
+
+	return buf;
+}
+
+/**
+ * This function frees an I/O buffer that was allocated by alloc_buffer.
+ *
+ * @param usb_ep the endpoint associated with the buffer
+ * @param buf address of the buffer
+ * @param dma The buffer's DMA address
+ * @param bytes The number of bytes of the buffer
+ */
+static void dwc_otg_pcd_free_buffer(struct usb_ep *usb_ep, void *buf,
+				    dma_addr_t dma, unsigned bytes)
+{
+	dwc_otg_pcd_t *pcd = 0;
+
+	pcd = gadget_wrapper->pcd;
+
+	DWC_DEBUGPL(DBG_PCDV, "%s(%p,%0x,%d)\n", __func__, buf, dma, bytes);
+
+	dma_free_coherent(NULL, bytes, buf, dma);
+}
+#endif
+
+/**
+ * This function is used to submit an I/O Request to an EP.
+ *
+ *	- When the request completes the request's completion callback
+ *	  is called to return the request to the driver.
+ *	- An EP, except control EPs, may have multiple requests
+ *	  pending.
+ *	- Once submitted the request cannot be examined or modified.
+ *	- Each request is turned into one or more packets.
+ *	- A BULK EP can queue any amount of data; the transfer is
+ *	  packetized.
+ *	- Zero length Packets are specified with the request 'zero'
+ *	  flag.
+ */
+static int ep_queue(struct usb_ep *usb_ep, struct usb_request *usb_req,
+		    gfp_t gfp_flags)
+{
+	dwc_otg_pcd_t *pcd;
+	struct dwc_otg_pcd_ep *ep = NULL;
+	int retval = 0, is_isoc_ep = 0;
+	dma_addr_t dma_addr = DWC_DMA_ADDR_INVALID;
+
+	DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p,%d)\n",
+		    __func__, usb_ep, usb_req, gfp_flags);
+
+	if (!usb_req || !usb_req->complete || !usb_req->buf) {
+		DWC_WARN("bad params\n");
+		return -EINVAL;
+	}
+
+	if (!usb_ep) {
+		DWC_WARN("bad ep\n");
+		return -EINVAL;
+	}
+
+	pcd = gadget_wrapper->pcd;
+	if (!gadget_wrapper->driver ||
+	    gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
+		DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
+			    gadget_wrapper->gadget.speed);
+		DWC_WARN("bogus device state\n");
+		return -ESHUTDOWN;
+	}
+
+	DWC_DEBUGPL(DBG_PCD, "%s queue req %p, len %d buf %p\n",
+		    usb_ep->name, usb_req, usb_req->length, usb_req->buf);
+
+	usb_req->status = -EINPROGRESS;
+	usb_req->actual = 0;
+
+	ep = ep_from_handle(pcd, usb_ep);
+	if (ep == NULL)
+		is_isoc_ep = 0;
+	else
+		is_isoc_ep = (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) ? 1 : 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+	dma_addr = usb_req->dma;
+#else
+	if (GET_CORE_IF(pcd)->dma_enable) {
+		struct pci_dev *dev = gadget_wrapper->pcd->otg_dev->os_dep.pcidev;
+		if (usb_req->length != 0 && usb_req->dma == DWC_DMA_ADDR_INVALID) {
+			dma_addr = pci_map_single(dev, usb_req->buf, usb_req->length,
+					ep->dwc_ep.is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+		}
+	}
+#endif
+
+#ifdef DWC_UTE_PER_IO
+	if (is_isoc_ep == 1) {
+		retval = dwc_otg_pcd_xiso_ep_queue(pcd, usb_ep, usb_req->buf, dma_addr,
+			usb_req->length, usb_req->zero, usb_req,
+			gfp_flags == GFP_ATOMIC ? 1 : 0, &usb_req->ext_req);
+		if (retval)
+			return -EINVAL;
+
+		return 0;
+	}
+#endif
+	retval = dwc_otg_pcd_ep_queue(pcd, usb_ep, usb_req->buf, dma_addr,
+				      usb_req->length, usb_req->zero, usb_req,
+				      gfp_flags == GFP_ATOMIC ? 1 : 0);
+	if (retval) {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * This function cancels an I/O request from an EP.
+ */
+static int ep_dequeue(struct usb_ep *usb_ep, struct usb_request *usb_req)
+{
+	DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, usb_req);
+
+	if (!usb_ep || !usb_req) {
+		DWC_WARN("bad argument\n");
+		return -EINVAL;
+	}
+	if (!gadget_wrapper->driver ||
+	    gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
+		DWC_WARN("bogus device state\n");
+		return -ESHUTDOWN;
+	}
+	if (dwc_otg_pcd_ep_dequeue(gadget_wrapper->pcd, usb_ep, usb_req)) {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * usb_ep_set_halt stalls an endpoint.
+ *
+ * usb_ep_clear_halt clears an endpoint halt and resets its data
+ * toggle.
+ *
+ * Both of these functions are implemented with the same underlying
+ * function. The behavior depends on the value argument.
+ *
+ * @param[in] usb_ep the Endpoint to halt or clear halt.
+ * @param[in] value
+ *	- 0 means clear_halt.
+ *	- 1 means set_halt,
+ *	- 2 means clear stall lock flag.
+ *	- 3 means set  stall lock flag.
+ */
+static int ep_halt(struct usb_ep *usb_ep, int value)
+{
+	int retval = 0;
+
+	DWC_DEBUGPL(DBG_PCD, "HALT %s %d\n", usb_ep->name, value);
+
+	if (!usb_ep) {
+		DWC_WARN("bad ep\n");
+		return -EINVAL;
+	}
+
+	retval = dwc_otg_pcd_ep_halt(gadget_wrapper->pcd, usb_ep, value);
+	if (retval == -DWC_E_AGAIN) {
+		return -EAGAIN;
+	} else if (retval) {
+		retval = -EINVAL;
+	}
+
+	return retval;
+}
+
+#ifdef DWC_EN_ISOC
+/**
+ * This function is used to submit an ISOC Transfer Request to an EP.
+ *
+ *	- Every time a sync period completes the request's completion callback
+ *	  is called to provide data to the gadget driver.
+ *	- Once submitted the request cannot be modified.
+ *	- Each request is turned into periodic data packets untill ISO
+ *	  Transfer is stopped..
+ */
+static int iso_ep_start(struct usb_ep *usb_ep, struct usb_iso_request *req,
+			gfp_t gfp_flags)
+{
+	int retval = 0;
+
+	if (!req || !req->process_buffer || !req->buf0 || !req->buf1) {
+		DWC_WARN("bad params\n");
+		return -EINVAL;
+	}
+
+	if (!usb_ep) {
+		DWC_PRINTF("bad params\n");
+		return -EINVAL;
+	}
+
+	req->status = -EINPROGRESS;
+
+	retval =
+	    dwc_otg_pcd_iso_ep_start(gadget_wrapper->pcd, usb_ep, req->buf0,
+				     req->buf1, req->dma0, req->dma1,
+				     req->sync_frame, req->data_pattern_frame,
+				     req->data_per_frame,
+				     req->flags & USB_REQ_ISO_ASAP ? -1 : req->
+				     start_frame, req->buf_proc_intrvl, req,
+				     gfp_flags == GFP_ATOMIC ? 1 : 0);
+
+	if (retval) {
+		return -EINVAL;
+	}
+
+	return retval;
+}
+
+/**
+ * This function stops ISO EP Periodic Data Transfer.
+ */
+static int iso_ep_stop(struct usb_ep *usb_ep, struct usb_iso_request *req)
+{
+	int retval = 0;
+	if (!usb_ep) {
+		DWC_WARN("bad ep\n");
+	}
+
+	if (!gadget_wrapper->driver ||
+	    gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
+		DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
+			    gadget_wrapper->gadget.speed);
+		DWC_WARN("bogus device state\n");
+	}
+
+	dwc_otg_pcd_iso_ep_stop(gadget_wrapper->pcd, usb_ep, req);
+	if (retval) {
+		retval = -EINVAL;
+	}
+
+	return retval;
+}
+
+static struct usb_iso_request *alloc_iso_request(struct usb_ep *ep,
+						 int packets, gfp_t gfp_flags)
+{
+	struct usb_iso_request *pReq = NULL;
+	uint32_t req_size;
+
+	req_size = sizeof(struct usb_iso_request);
+	req_size +=
+	    (2 * packets * (sizeof(struct usb_gadget_iso_packet_descriptor)));
+
+	pReq = kmalloc(req_size, gfp_flags);
+	if (!pReq) {
+		DWC_WARN("Can't allocate Iso Request\n");
+		return 0;
+	}
+	pReq->iso_packet_desc0 = (void *)(pReq + 1);
+
+	pReq->iso_packet_desc1 = pReq->iso_packet_desc0 + packets;
+
+	return pReq;
+}
+
+static void free_iso_request(struct usb_ep *ep, struct usb_iso_request *req)
+{
+	kfree(req);
+}
+
+static struct usb_isoc_ep_ops dwc_otg_pcd_ep_ops = {
+	.ep_ops = {
+		   .enable = ep_enable,
+		   .disable = ep_disable,
+
+		   .alloc_request = dwc_otg_pcd_alloc_request,
+		   .free_request = dwc_otg_pcd_free_request,
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+		   .alloc_buffer = dwc_otg_pcd_alloc_buffer,
+		   .free_buffer = dwc_otg_pcd_free_buffer,
+#endif
+
+		   .queue = ep_queue,
+		   .dequeue = ep_dequeue,
+
+		   .set_halt = ep_halt,
+		   .fifo_status = 0,
+		   .fifo_flush = 0,
+		   },
+	.iso_ep_start = iso_ep_start,
+	.iso_ep_stop = iso_ep_stop,
+	.alloc_iso_request = alloc_iso_request,
+	.free_iso_request = free_iso_request,
+};
+
+#else
+
+static struct usb_ep_ops dwc_otg_pcd_ep_ops = {
+	.enable = ep_enable,
+	.disable = ep_disable,
+
+	.alloc_request = dwc_otg_pcd_alloc_request,
+	.free_request = dwc_otg_pcd_free_request,
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+	.alloc_buffer = dwc_otg_pcd_alloc_buffer,
+	.free_buffer = dwc_otg_pcd_free_buffer,
+#endif
+
+	.queue = ep_queue,
+	.dequeue = ep_dequeue,
+
+	.set_halt = ep_halt,
+	.fifo_status = 0,
+	.fifo_flush = 0,
+
+};
+
+#endif /* _EN_ISOC_ */
+/*	Gadget Operations */
+/**
+ * The following gadget operations will be implemented in the DWC_otg
+ * PCD. Functions in the API that are not described below are not
+ * implemented.
+ *
+ * The Gadget API provides wrapper functions for each of the function
+ * pointers defined in usb_gadget_ops. The Gadget Driver calls the
+ * wrapper function, which then calls the underlying PCD function. The
+ * following sections are named according to the wrapper functions
+ * (except for ioctl, which doesn't have a wrapper function). Within
+ * each section, the corresponding DWC_otg PCD function name is
+ * specified.
+ *
+ */
+
+/**
+ *Gets the USB Frame number of the last SOF.
+ */
+static int get_frame_number(struct usb_gadget *gadget)
+{
+	struct gadget_wrapper *d;
+
+	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
+
+	if (gadget == 0) {
+		return -ENODEV;
+	}
+
+	d = container_of(gadget, struct gadget_wrapper, gadget);
+	return dwc_otg_pcd_get_frame_number(d->pcd);
+}
+
+#ifdef CONFIG_USB_DWC_OTG_LPM
+static int test_lpm_enabled(struct usb_gadget *gadget)
+{
+	struct gadget_wrapper *d;
+
+	d = container_of(gadget, struct gadget_wrapper, gadget);
+
+	return dwc_otg_pcd_is_lpm_enabled(d->pcd);
+}
+#endif
+
+/**
+ * Initiates Session Request Protocol (SRP) to wakeup the host if no
+ * session is in progress. If a session is already in progress, but
+ * the device is suspended, remote wakeup signaling is started.
+ *
+ */
+static int wakeup(struct usb_gadget *gadget)
+{
+	struct gadget_wrapper *d;
+
+	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
+
+	if (gadget == 0) {
+		return -ENODEV;
+	} else {
+		d = container_of(gadget, struct gadget_wrapper, gadget);
+	}
+	dwc_otg_pcd_wakeup(d->pcd);
+	return 0;
+}
+
+static const struct usb_gadget_ops dwc_otg_pcd_ops = {
+	.get_frame = get_frame_number,
+	.wakeup = wakeup,
+#ifdef CONFIG_USB_DWC_OTG_LPM
+	.lpm_support = test_lpm_enabled,
+#endif
+	// current versions must always be self-powered
+};
+
+static int _setup(dwc_otg_pcd_t * pcd, uint8_t * bytes)
+{
+	int retval = -DWC_E_NOT_SUPPORTED;
+	if (gadget_wrapper->driver && gadget_wrapper->driver->setup) {
+		retval = gadget_wrapper->driver->setup(&gadget_wrapper->gadget,
+						       (struct usb_ctrlrequest
+							*)bytes);
+	}
+
+	if (retval == -ENOTSUPP) {
+		retval = -DWC_E_NOT_SUPPORTED;
+	} else if (retval < 0) {
+		retval = -DWC_E_INVALID;
+	}
+
+	return retval;
+}
+
+#ifdef DWC_EN_ISOC
+static int _isoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle,
+			  void *req_handle, int proc_buf_num)
+{
+	int i, packet_count;
+	struct usb_gadget_iso_packet_descriptor *iso_packet = 0;
+	struct usb_iso_request *iso_req = req_handle;
+
+	if (proc_buf_num) {
+		iso_packet = iso_req->iso_packet_desc1;
+	} else {
+		iso_packet = iso_req->iso_packet_desc0;
+	}
+	packet_count =
+	    dwc_otg_pcd_get_iso_packet_count(pcd, ep_handle, req_handle);
+	for (i = 0; i < packet_count; ++i) {
+		int status;
+		int actual;
+		int offset;
+		dwc_otg_pcd_get_iso_packet_params(pcd, ep_handle, req_handle,
+						  i, &status, &actual, &offset);
+		switch (status) {
+		case -DWC_E_NO_DATA:
+			status = -ENODATA;
+			break;
+		default:
+			if (status) {
+				DWC_PRINTF("unknown status in isoc packet\n");
+			}
+
+		}
+		iso_packet[i].status = status;
+		iso_packet[i].offset = offset;
+		iso_packet[i].actual_length = actual;
+	}
+
+	iso_req->status = 0;
+	iso_req->process_buffer(ep_handle, iso_req);
+
+	return 0;
+}
+#endif /* DWC_EN_ISOC */
+
+#ifdef DWC_UTE_PER_IO
+/**
+ * Copy the contents of the extended request to the Linux usb_request's
+ * extended part and call the gadget's completion.
+ *
+ * @param pcd			Pointer to the pcd structure
+ * @param ep_handle		Void pointer to the usb_ep structure
+ * @param req_handle	Void pointer to the usb_request structure
+ * @param status		Request status returned from the portable logic
+ * @param ereq_port		Void pointer to the extended request structure
+ *						created in the the portable part that contains the
+ *						results of the processed iso packets.
+ */
+static int _xisoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle,
+			   void *req_handle, int32_t status, void *ereq_port)
+{
+	struct dwc_ute_iso_req_ext *ereqorg = NULL;
+	struct dwc_iso_xreq_port *ereqport = NULL;
+	struct dwc_ute_iso_packet_descriptor *desc_org = NULL;
+	int i;
+	struct usb_request *req;
+	//struct dwc_ute_iso_packet_descriptor *
+	//int status = 0;
+
+	req = (struct usb_request *)req_handle;
+	ereqorg = &req->ext_req;
+	ereqport = (struct dwc_iso_xreq_port *)ereq_port;
+	desc_org = ereqorg->per_io_frame_descs;
+
+	if (req && req->complete) {
+		/* Copy the request data from the portable logic to our request */
+		for (i = 0; i < ereqport->pio_pkt_count; i++) {
+			desc_org[i].actual_length =
+			    ereqport->per_io_frame_descs[i].actual_length;
+			desc_org[i].status =
+			    ereqport->per_io_frame_descs[i].status;
+		}
+
+		switch (status) {
+		case -DWC_E_SHUTDOWN:
+			req->status = -ESHUTDOWN;
+			break;
+		case -DWC_E_RESTART:
+			req->status = -ECONNRESET;
+			break;
+		case -DWC_E_INVALID:
+			req->status = -EINVAL;
+			break;
+		case -DWC_E_TIMEOUT:
+			req->status = -ETIMEDOUT;
+			break;
+		default:
+			req->status = status;
+		}
+
+		/* And call the gadget's completion */
+		req->complete(ep_handle, req);
+	}
+
+	return 0;
+}
+#endif /* DWC_UTE_PER_IO */
+static int _complete(dwc_otg_pcd_t * pcd, void *ep_handle,
+		     void *req_handle, int32_t status, uint32_t actual)
+{
+	struct usb_request *req = (struct usb_request *)req_handle;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27)
+	struct dwc_otg_pcd_ep *ep = NULL;
+#endif
+#ifdef PCI_INTERFACE
+	struct pci_dev *dev = NULL;
+#endif
+
+	if (req && req->complete) {
+		switch (status) {
+		case -DWC_E_SHUTDOWN:
+			req->status = -ESHUTDOWN;
+			break;
+		case -DWC_E_RESTART:
+			req->status = -ECONNRESET;
+			break;
+		case -DWC_E_INVALID:
+			req->status = -EINVAL;
+			break;
+		case -DWC_E_TIMEOUT:
+			req->status = -ETIMEDOUT;
+			break;
+		default:
+			req->status = status;
+
+		}
+
+		req->actual = actual;
+		DWC_SPINUNLOCK(pcd->lock);
+		req->complete(ep_handle, req);
+		DWC_SPINLOCK(pcd->lock);
+	}
+#ifdef PCI_INTERFACE
+	dev = gadget_wrapper->pcd->otg_dev->os_dep.pcidev;
+	ep = ep_from_handle(pcd, ep_handle);
+	if (GET_CORE_IF(pcd)->dma_enable) {
+		if (req->length != 0)
+			pci_unmap_single(dev, req->dma, req->length,
+					 ep->dwc_ep.
+					 is_in ? PCI_DMA_TODEVICE :
+					 PCI_DMA_FROMDEVICE);
+	}
+#endif
+
+	return 0;
+}
+
+static int _connect(dwc_otg_pcd_t * pcd, int speed)
+{
+	gadget_wrapper->gadget.speed = speed;
+	return 0;
+}
+
+static int _disconnect(dwc_otg_pcd_t * pcd)
+{
+	if (gadget_wrapper->driver && gadget_wrapper->driver->disconnect) {
+		gadget_wrapper->driver->disconnect(&gadget_wrapper->gadget);
+	}
+	return 0;
+}
+
+static int _resume(dwc_otg_pcd_t * pcd)
+{
+	if (gadget_wrapper->driver && gadget_wrapper->driver->resume) {
+		gadget_wrapper->driver->resume(&gadget_wrapper->gadget);
+	}
+
+	return 0;
+}
+
+static int _suspend(dwc_otg_pcd_t * pcd)
+{
+	if (gadget_wrapper->driver && gadget_wrapper->driver->suspend) {
+		gadget_wrapper->driver->suspend(&gadget_wrapper->gadget);
+	}
+	return 0;
+}
+
+/**
+ * This function updates the otg values in the gadget structure.
+ */
+static int _hnp_changed(dwc_otg_pcd_t * pcd)
+{
+
+	if (!gadget_wrapper->gadget.is_otg)
+		return 0;
+
+	gadget_wrapper->gadget.b_hnp_enable = get_b_hnp_enable(pcd);
+	gadget_wrapper->gadget.a_hnp_support = get_a_hnp_support(pcd);
+	gadget_wrapper->gadget.a_alt_hnp_support = get_a_alt_hnp_support(pcd);
+	return 0;
+}
+
+static int _reset(dwc_otg_pcd_t * pcd)
+{
+	return 0;
+}
+
+#ifdef DWC_UTE_CFI
+static int _cfi_setup(dwc_otg_pcd_t * pcd, void *cfi_req)
+{
+	int retval = -DWC_E_INVALID;
+	if (gadget_wrapper->driver->cfi_feature_setup) {
+		retval =
+		    gadget_wrapper->driver->
+		    cfi_feature_setup(&gadget_wrapper->gadget,
+				      (struct cfi_usb_ctrlrequest *)cfi_req);
+	}
+
+	return retval;
+}
+#endif
+
+static const struct dwc_otg_pcd_function_ops fops = {
+	.complete = _complete,
+#ifdef DWC_EN_ISOC
+	.isoc_complete = _isoc_complete,
+#endif
+	.setup = _setup,
+	.disconnect = _disconnect,
+	.connect = _connect,
+	.resume = _resume,
+	.suspend = _suspend,
+	.hnp_changed = _hnp_changed,
+	.reset = _reset,
+#ifdef DWC_UTE_CFI
+	.cfi_setup = _cfi_setup,
+#endif
+#ifdef DWC_UTE_PER_IO
+	.xisoc_complete = _xisoc_complete,
+#endif
+};
+
+/**
+ * This function is the top level PCD interrupt handler.
+ */
+static irqreturn_t dwc_otg_pcd_irq(int irq, void *dev)
+{
+	dwc_otg_pcd_t *pcd = dev;
+	int32_t retval = IRQ_NONE;
+
+	retval = dwc_otg_pcd_handle_intr(pcd);
+	if (retval != 0) {
+		S3C2410X_CLEAR_EINTPEND();
+	}
+	return IRQ_RETVAL(retval);
+}
+
+/**
+ * This function initialized the usb_ep structures to there default
+ * state.
+ *
+ * @param d Pointer on gadget_wrapper.
+ */
+void gadget_add_eps(struct gadget_wrapper *d)
+{
+	static const char *names[] = {
+
+		"ep0",
+		"ep1in",
+		"ep2in",
+		"ep3in",
+		"ep4in",
+		"ep5in",
+		"ep6in",
+		"ep7in",
+		"ep8in",
+		"ep9in",
+		"ep10in",
+		"ep11in",
+		"ep12in",
+		"ep13in",
+		"ep14in",
+		"ep15in",
+		"ep1out",
+		"ep2out",
+		"ep3out",
+		"ep4out",
+		"ep5out",
+		"ep6out",
+		"ep7out",
+		"ep8out",
+		"ep9out",
+		"ep10out",
+		"ep11out",
+		"ep12out",
+		"ep13out",
+		"ep14out",
+		"ep15out"
+	};
+
+	int i;
+	struct usb_ep *ep;
+	int8_t dev_endpoints;
+
+	DWC_DEBUGPL(DBG_PCDV, "%s\n", __func__);
+
+	INIT_LIST_HEAD(&d->gadget.ep_list);
+	d->gadget.ep0 = &d->ep0;
+	d->gadget.speed = USB_SPEED_UNKNOWN;
+
+	INIT_LIST_HEAD(&d->gadget.ep0->ep_list);
+
+	/**
+	 * Initialize the EP0 structure.
+	 */
+	ep = &d->ep0;
+
+	/* Init the usb_ep structure. */
+	ep->name = names[0];
+	ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
+
+	/**
+	 * @todo NGS: What should the max packet size be set to
+	 * here?  Before EP type is set?
+	 */
+	ep->maxpacket = MAX_PACKET_SIZE;
+	dwc_otg_pcd_ep_enable(d->pcd, NULL, ep);
+
+	list_add_tail(&ep->ep_list, &d->gadget.ep_list);
+
+	/**
+	 * Initialize the EP structures.
+	 */
+	dev_endpoints = d->pcd->core_if->dev_if->num_in_eps;
+
+	for (i = 0; i < dev_endpoints; i++) {
+		ep = &d->in_ep[i];
+
+		/* Init the usb_ep structure. */
+		ep->name = names[d->pcd->in_ep[i].dwc_ep.num];
+		ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
+
+		/**
+		 * @todo NGS: What should the max packet size be set to
+		 * here?  Before EP type is set?
+		 */
+		ep->maxpacket = MAX_PACKET_SIZE;
+		list_add_tail(&ep->ep_list, &d->gadget.ep_list);
+	}
+
+	dev_endpoints = d->pcd->core_if->dev_if->num_out_eps;
+
+	for (i = 0; i < dev_endpoints; i++) {
+		ep = &d->out_ep[i];
+
+		/* Init the usb_ep structure. */
+		ep->name = names[15 + d->pcd->out_ep[i].dwc_ep.num];
+		ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
+
+		/**
+		 * @todo NGS: What should the max packet size be set to
+		 * here?  Before EP type is set?
+		 */
+		ep->maxpacket = MAX_PACKET_SIZE;
+
+		list_add_tail(&ep->ep_list, &d->gadget.ep_list);
+	}
+
+	/* remove ep0 from the list.  There is a ep0 pointer. */
+	list_del_init(&d->ep0.ep_list);
+
+	d->ep0.maxpacket = MAX_EP0_SIZE;
+}
+
+/**
+ * This function releases the Gadget device.
+ * required by device_unregister().
+ *
+ * @todo Should this do something?	Should it free the PCD?
+ */
+static void dwc_otg_pcd_gadget_release(struct device *dev)
+{
+	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, dev);
+}
+
+static struct gadget_wrapper *alloc_wrapper(
+#ifdef LM_INTERFACE
+	struct lm_device *_dev
+#elif  defined(PCI_INTERFACE)
+	struct pci_dev *_dev
+#endif
+    )
+{
+	static char pcd_name[] = "dwc_otg_pcd";
+#ifdef LM_INTERFACE
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
+#elif defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
+#endif
+
+	struct gadget_wrapper *d;
+	int retval;
+
+	d = DWC_ALLOC(sizeof(*d));
+	if (d == NULL) {
+		return NULL;
+	}
+
+	memset(d, 0, sizeof(*d));
+
+	d->gadget.name = pcd_name;
+	d->pcd = otg_dev->pcd;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
+	strcpy(d->gadget.dev.bus_id, "gadget");
+#else
+	dev_set_name(&d->gadget.dev, "%s", "gadget");
+#endif
+
+	d->gadget.dev.parent = &_dev->dev;
+	d->gadget.dev.release = dwc_otg_pcd_gadget_release;
+	d->gadget.ops = &dwc_otg_pcd_ops;
+	d->gadget.is_dualspeed = dwc_otg_pcd_is_dualspeed(otg_dev->pcd);
+	d->gadget.is_otg = dwc_otg_pcd_is_otg(otg_dev->pcd);
+
+	d->driver = 0;
+	/* Register the gadget device */
+	retval = device_register(&d->gadget.dev);
+	if (retval != 0) {
+		DWC_ERROR("device_register failed\n");
+		DWC_FREE(d);
+		return NULL;
+	}
+
+	return d;
+}
+
+static void free_wrapper(struct gadget_wrapper *d)
+{
+	if (d->driver) {
+		/* should have been done already by driver model core */
+		DWC_WARN("driver '%s' is still registered\n",
+			 d->driver->driver.name);
+		usb_gadget_unregister_driver(d->driver);
+	}
+
+	device_unregister(&d->gadget.dev);
+	DWC_FREE(d);
+}
+
+/**
+ * This function initialized the PCD portion of the driver.
+ *
+ */
+int pcd_init(
+#ifdef LM_INTERFACE
+	struct lm_device *_dev
+#elif  defined(PCI_INTERFACE)
+	struct pci_dev *_dev
+#else
+	struct platform_device *_dev
+#endif
+    )
+{
+#ifdef LM_INTERFACE
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
+#elif  defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
+#endif
+
+	int retval = 0;
+
+	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _dev);
+
+	otg_dev->pcd = dwc_otg_pcd_init(otg_dev->core_if);
+
+	if (!otg_dev->pcd) {
+		DWC_ERROR("dwc_otg_pcd_init failed\n");
+		return -ENOMEM;
+	}
+
+	otg_dev->pcd->otg_dev = otg_dev;
+	gadget_wrapper = alloc_wrapper(_dev);
+
+	/*
+	 * Initialize EP structures
+	 */
+	gadget_add_eps(gadget_wrapper);
+	/*
+	 * Setup interupt handler
+	 */
+	DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n", _dev->irq);
+	retval = request_irq(_dev->irq, dwc_otg_pcd_irq,
+			     IRQF_SHARED | IRQF_DISABLED,
+			     gadget_wrapper->gadget.name, otg_dev->pcd);
+	if (retval != 0) {
+		DWC_ERROR("request of irq%d failed\n", _dev->irq);
+		free_wrapper(gadget_wrapper);
+		return -EBUSY;
+	}
+
+	dwc_otg_pcd_start(gadget_wrapper->pcd, &fops);
+
+	return retval;
+}
+
+/**
+ * Cleanup the PCD.
+ */
+void pcd_remove(
+#ifdef LM_INTERFACE
+	struct lm_device *_dev
+#elif  defined(PCI_INTERFACE)
+	struct pci_dev *_dev
+#endif
+    )
+{
+#ifdef LM_INTERFACE
+	dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
+#elif  defined(PCI_INTERFACE)
+	dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
+#endif
+	dwc_otg_pcd_t *pcd = otg_dev->pcd;
+
+	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _dev);
+
+	/*
+	 * Free the IRQ
+	 */
+	free_irq(_dev->irq, pcd);
+	dwc_otg_pcd_remove(otg_dev->pcd);
+	free_wrapper(gadget_wrapper);
+	otg_dev->pcd = 0;
+}
+
+/**
+ * This function registers a gadget driver with the PCD.
+ *
+ * When a driver is successfully registered, it will receive control
+ * requests including set_configuration(), which enables non-control
+ * requests.  then usb traffic follows until a disconnect is reported.
+ * then a host may connect again, or the driver might get unbound.
+ *
+ * @param driver The driver being registered
+ * @param bind The bind function of gadget driver
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+#else
+int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *))
+#endif
+{
+	int retval;
+
+	DWC_DEBUGPL(DBG_PCD, "registering gadget driver '%s'\n",
+		    driver->driver.name);
+
+	if (!driver || driver->speed == USB_SPEED_UNKNOWN ||
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
+	    !driver->bind ||
+#else
+		!bind ||
+#endif
+	    !driver->unbind || !driver->disconnect || !driver->setup) {
+		DWC_DEBUGPL(DBG_PCDV, "EINVAL\n");
+		return -EINVAL;
+	}
+	if (gadget_wrapper == 0) {
+		DWC_DEBUGPL(DBG_PCDV, "ENODEV\n");
+		return -ENODEV;
+	}
+	if (gadget_wrapper->driver != 0) {
+		DWC_DEBUGPL(DBG_PCDV, "EBUSY (%p)\n", gadget_wrapper->driver);
+		return -EBUSY;
+	}
+
+	/* hook up the driver */
+	gadget_wrapper->driver = driver;
+	gadget_wrapper->gadget.dev.driver = &driver->driver;
+
+	DWC_DEBUGPL(DBG_PCD, "bind to driver %s\n", driver->driver.name);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
+	retval = driver->bind(&gadget_wrapper->gadget);
+#else
+	retval = bind(&gadget_wrapper->gadget);
+#endif
+	if (retval) {
+		DWC_ERROR("bind to driver %s --> error %d\n",
+			  driver->driver.name, retval);
+		gadget_wrapper->driver = 0;
+		gadget_wrapper->gadget.dev.driver = 0;
+		return retval;
+	}
+	DWC_DEBUGPL(DBG_ANY, "registered gadget driver '%s'\n",
+		    driver->driver.name);
+	return 0;
+}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
+EXPORT_SYMBOL(usb_gadget_register_driver);
+#else
+EXPORT_SYMBOL(usb_gadget_probe_driver);
+#endif
+
+/**
+ * This function unregisters a gadget driver
+ *
+ * @param driver The driver being unregistered
+ */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	//DWC_DEBUGPL(DBG_PCDV,"%s(%p)\n", __func__, _driver);
+
+	if (gadget_wrapper == 0) {
+		DWC_DEBUGPL(DBG_ANY, "%s Return(%d): s_pcd==0\n", __func__,
+			    -ENODEV);
+		return -ENODEV;
+	}
+	if (driver == 0 || driver != gadget_wrapper->driver) {
+		DWC_DEBUGPL(DBG_ANY, "%s Return(%d): driver?\n", __func__,
+			    -EINVAL);
+		return -EINVAL;
+	}
+
+	driver->unbind(&gadget_wrapper->gadget);
+	gadget_wrapper->driver = 0;
+
+	DWC_DEBUGPL(DBG_ANY, "unregistered driver '%s'\n", driver->driver.name);
+	return 0;
+}
+
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+#endif /* DWC_HOST_ONLY */
diff --git a/drivers/usb/dwc_otg/dwc_otg_regs.h b/drivers/usb/dwc_otg/dwc_otg_regs.h
new file mode 100644
index 0000000..8dc648b
--- /dev/null
+++ b/drivers/usb/dwc_otg/dwc_otg_regs.h
@@ -0,0 +1,2545 @@
+/* ==========================================================================
+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_regs.h $
+ * $Revision: #97 $
+ * $Date: 2011/10/24 $
+ * $Change: 1871160 $
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+#ifndef __DWC_OTG_REGS_H__
+#define __DWC_OTG_REGS_H__
+
+#include "dwc_otg_core_if.h"
+
+/**
+ * @file
+ *
+ * This file contains the data structures for accessing the DWC_otg core registers.
+ *
+ * The application interfaces with the HS OTG core by reading from and
+ * writing to the Control and Status Register (CSR) space through the
+ * AHB Slave interface. These registers are 32 bits wide, and the
+ * addresses are 32-bit-block aligned.
+ * CSRs are classified as follows:
+ * - Core Global Registers
+ * - Device Mode Registers
+ * - Device Global Registers
+ * - Device Endpoint Specific Registers
+ * - Host Mode Registers
+ * - Host Global Registers
+ * - Host Port CSRs
+ * - Host Channel Specific Registers
+ *
+ * Only the Core Global registers can be accessed in both Device and
+ * Host modes. When the HS OTG core is operating in one mode, either
+ * Device or Host, the application must not access registers from the
+ * other mode. When the core switches from one mode to another, the
+ * registers in the new mode of operation must be reprogrammed as they
+ * would be after a power-on reset.
+ */
+
+/****************************************************************************/
+/** DWC_otg Core registers . 
+ * The dwc_otg_core_global_regs structure defines the size
+ * and relative field offsets for the Core Global registers.
+ */
+typedef struct dwc_otg_core_global_regs {
+	/** OTG Control and Status Register.  <i>Offset: 000h</i> */
+	volatile uint32_t gotgctl;
+	/** OTG Interrupt Register.	 <i>Offset: 004h</i> */
+	volatile uint32_t gotgint;
+	/**Core AHB Configuration Register.	 <i>Offset: 008h</i> */
+	volatile uint32_t gahbcfg;
+
+#define DWC_GLBINTRMASK		0x0001
+#define DWC_DMAENABLE		0x0020
+#define DWC_NPTXEMPTYLVL_EMPTY	0x0080
+#define DWC_NPTXEMPTYLVL_HALFEMPTY	0x0000
+#define DWC_PTXEMPTYLVL_EMPTY	0x0100
+#define DWC_PTXEMPTYLVL_HALFEMPTY	0x0000
+
+	/**Core USB Configuration Register.	 <i>Offset: 00Ch</i> */
+	volatile uint32_t gusbcfg;
+	/**Core Reset Register.	 <i>Offset: 010h</i> */
+	volatile uint32_t grstctl;
+	/**Core Interrupt Register.	 <i>Offset: 014h</i> */
+	volatile uint32_t gintsts;
+	/**Core Interrupt Mask Register.  <i>Offset: 018h</i> */
+	volatile uint32_t gintmsk;
+	/**Receive Status Queue Read Register (Read Only).	<i>Offset: 01Ch</i> */
+	volatile uint32_t grxstsr;
+	/**Receive Status Queue Read & POP Register (Read Only).  <i>Offset: 020h</i>*/
+	volatile uint32_t grxstsp;
+	/**Receive FIFO Size Register.	<i>Offset: 024h</i> */
+	volatile uint32_t grxfsiz;
+	/**Non Periodic Transmit FIFO Size Register.  <i>Offset: 028h</i> */
+	volatile uint32_t gnptxfsiz;
+	/**Non Periodic Transmit FIFO/Queue Status Register (Read
+	 * Only). <i>Offset: 02Ch</i> */
+	volatile uint32_t gnptxsts;
+	/**I2C Access Register.	 <i>Offset: 030h</i> */
+	volatile uint32_t gi2cctl;
+	/**PHY Vendor Control Register.	 <i>Offset: 034h</i> */
+	volatile uint32_t gpvndctl;
+	/**General Purpose Input/Output Register.  <i>Offset: 038h</i> */
+	volatile uint32_t ggpio;
+	/**User ID Register.  <i>Offset: 03Ch</i> */
+	volatile uint32_t guid;
+	/**Synopsys ID Register (Read Only).  <i>Offset: 040h</i> */
+	volatile uint32_t gsnpsid;
+	/**User HW Config1 Register (Read Only).  <i>Offset: 044h</i> */
+	volatile uint32_t ghwcfg1;
+	/**User HW Config2 Register (Read Only).  <i>Offset: 048h</i> */
+	volatile uint32_t ghwcfg2;
+#define DWC_SLAVE_ONLY_ARCH 0
+#define DWC_EXT_DMA_ARCH 1
+#define DWC_INT_DMA_ARCH 2
+
+#define DWC_MODE_HNP_SRP_CAPABLE	0
+#define DWC_MODE_SRP_ONLY_CAPABLE	1
+#define DWC_MODE_NO_HNP_SRP_CAPABLE		2
+#define DWC_MODE_SRP_CAPABLE_DEVICE		3
+#define DWC_MODE_NO_SRP_CAPABLE_DEVICE	4
+#define DWC_MODE_SRP_CAPABLE_HOST	5
+#define DWC_MODE_NO_SRP_CAPABLE_HOST	6
+
+	/**User HW Config3 Register (Read Only).  <i>Offset: 04Ch</i> */
+	volatile uint32_t ghwcfg3;
+	/**User HW Config4 Register (Read Only).  <i>Offset: 050h</i>*/
+	volatile uint32_t ghwcfg4;
+	/** Core LPM Configuration register <i>Offset: 054h</i>*/
+	volatile uint32_t glpmcfg;
+	/** Global PowerDn Register <i>Offset: 058h</i> */
+	volatile uint32_t gpwrdn;
+	/** Global DFIFO SW Config Register  <i>Offset: 05Ch</i> */
+	volatile uint32_t gdfifocfg;
+	/** ADP Control Register  <i>Offset: 060h</i> */
+	volatile uint32_t adpctl;
+	/** Reserved  <i>Offset: 064h-0FFh</i> */
+	volatile uint32_t reserved39[39];
+	/** Host Periodic Transmit FIFO Size Register. <i>Offset: 100h</i> */
+	volatile uint32_t hptxfsiz;
+	/** Device Periodic Transmit FIFO#n Register if dedicated fifos are disabled,
+		otherwise Device Transmit FIFO#n Register.
+	 * <i>Offset: 104h + (FIFO_Number-1)*04h, 1 <= FIFO Number <= 15 (1<=n<=15).</i> */
+	volatile uint32_t dtxfsiz[15];
+} dwc_otg_core_global_regs_t;
+
+/**
+ * This union represents the bit fields of the Core OTG Control
+ * and Status Register (GOTGCTL).  Set the bits using the bit
+ * fields then write the <i>d32</i> value to the register.
+ */
+typedef union gotgctl_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		unsigned sesreqscs:1;
+		unsigned sesreq:1;
+		unsigned vbvalidoven:1;
+		unsigned vbvalidovval:1;
+		unsigned avalidoven:1;
+		unsigned avalidovval:1;
+		unsigned bvalidoven:1;
+		unsigned bvalidovval:1;
+		unsigned hstnegscs:1;
+		unsigned hnpreq:1;
+		unsigned hstsethnpen:1;
+		unsigned devhnpen:1;
+		unsigned reserved12_15:4;
+		unsigned conidsts:1;
+		unsigned dbnctime:1;
+		unsigned asesvld:1;
+		unsigned bsesvld:1;
+		unsigned otgver:1;
+		unsigned reserved1:1;
+		unsigned multvalidbc:5;
+		unsigned chirpen:1;
+		unsigned reserved28_31:4;
+	} b;
+} gotgctl_data_t;
+
+/**
+ * This union represents the bit fields of the Core OTG Interrupt Register
+ * (GOTGINT).  Set/clear the bits using the bit fields then write the <i>d32</i>
+ * value to the register.
+ */
+typedef union gotgint_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		/** Current Mode */
+		unsigned reserved0_1:2;
+
+		/** Session End Detected */
+		unsigned sesenddet:1;
+
+		unsigned reserved3_7:5;
+
+		/** Session Request Success Status Change */
+		unsigned sesreqsucstschng:1;
+		/** Host Negotiation Success Status Change */
+		unsigned hstnegsucstschng:1;
+
+		unsigned reserved10_16:7;
+
+		/** Host Negotiation Detected */
+		unsigned hstnegdet:1;
+		/** A-Device Timeout Change */
+		unsigned adevtoutchng:1;
+		/** Debounce Done */
+		unsigned debdone:1;
+		/** Multi-Valued input changed */
+		unsigned mvic:1;
+
+		unsigned reserved31_21:11;
+
+	} b;
+} gotgint_data_t;
+
+/**
+ * This union represents the bit fields of the Core AHB Configuration
+ * Register (GAHBCFG). Set/clear the bits using the bit fields then
+ * write the <i>d32</i> value to the register.
+ */
+typedef union gahbcfg_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		unsigned glblintrmsk:1;
+#define DWC_GAHBCFG_GLBINT_ENABLE		1
+
+		unsigned hburstlen:4;
+#define DWC_GAHBCFG_INT_DMA_BURST_SINGLE	0
+#define DWC_GAHBCFG_INT_DMA_BURST_INCR		1
+#define DWC_GAHBCFG_INT_DMA_BURST_INCR4		3
+#define DWC_GAHBCFG_INT_DMA_BURST_INCR8		5
+#define DWC_GAHBCFG_INT_DMA_BURST_INCR16	7
+
+		unsigned dmaenable:1;
+#define DWC_GAHBCFG_DMAENABLE			1
+		unsigned reserved:1;
+		unsigned nptxfemplvl_txfemplvl:1;
+		unsigned ptxfemplvl:1;
+#define DWC_GAHBCFG_TXFEMPTYLVL_EMPTY		1
+#define DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY	0
+		unsigned reserved9_20:12;
+		unsigned remmemsupp:1;
+		unsigned notialldmawrit:1;
+		unsigned ahbsingle:1;
+		unsigned reserved24_31:8;
+	} b;
+} gahbcfg_data_t;
+
+/**
+ * This union represents the bit fields of the Core USB Configuration
+ * Register (GUSBCFG). Set the bits using the bit fields then write
+ * the <i>d32</i> value to the register.
+ */
+typedef union gusbcfg_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		unsigned toutcal:3;
+		unsigned phyif:1;
+		unsigned ulpi_utmi_sel:1;
+		unsigned fsintf:1;
+		unsigned physel:1;
+		unsigned ddrsel:1;
+		unsigned srpcap:1;
+		unsigned hnpcap:1;
+		unsigned usbtrdtim:4;
+		unsigned reserved1:1;
+		unsigned phylpwrclksel:1;
+		unsigned otgutmifssel:1;
+		unsigned ulpi_fsls:1;
+		unsigned ulpi_auto_res:1;
+		unsigned ulpi_clk_sus_m:1;
+		unsigned ulpi_ext_vbus_drv:1;
+		unsigned ulpi_int_vbus_indicator:1;
+		unsigned term_sel_dl_pulse:1;
+		unsigned indicator_complement:1;
+		unsigned indicator_pass_through:1;
+		unsigned ulpi_int_prot_dis:1;
+		unsigned ic_usb_cap:1;
+		unsigned ic_traffic_pull_remove:1;
+		unsigned tx_end_delay:1;
+		unsigned force_host_mode:1;
+		unsigned force_dev_mode:1;
+		unsigned reserved31:1;
+	} b;
+} gusbcfg_data_t;
+
+/**
+ * This union represents the bit fields of the Core Reset Register
+ * (GRSTCTL).  Set/clear the bits using the bit fields then write the
+ * <i>d32</i> value to the register.
+ */
+typedef union grstctl_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		/** Core Soft Reset (CSftRst) (Device and Host)
+		 *
+		 * The application can flush the control logic in the
+		 * entire core using this bit. This bit resets the
+		 * pipelines in the AHB Clock domain as well as the
+		 * PHY Clock domain.
+		 *
+		 * The state machines are reset to an IDLE state, the
+		 * control bits in the CSRs are cleared, all the
+		 * transmit FIFOs and the receive FIFO are flushed.
+		 *
+		 * The status mask bits that control the generation of
+		 * the interrupt, are cleared, to clear the
+		 * interrupt. The interrupt status bits are not
+		 * cleared, so the application can get the status of
+		 * any events that occurred in the core after it has
+		 * set this bit.
+		 *
+		 * Any transactions on the AHB are terminated as soon
+		 * as possible following the protocol. Any
+		 * transactions on the USB are terminated immediately.
+		 *
+		 * The configuration settings in the CSRs are
+		 * unchanged, so the software doesn't have to
+		 * reprogram these registers (Device
+		 * Configuration/Host Configuration/Core System
+		 * Configuration/Core PHY Configuration).
+		 *
+		 * The application can write to this bit, any time it
+		 * wants to reset the core. This is a self clearing
+		 * bit and the core clears this bit after all the
+		 * necessary logic is reset in the core, which may
+		 * take several clocks, depending on the current state
+		 * of the core.
+		 */
+		unsigned csftrst:1;
+		/** Hclk Soft Reset
+		 *
+		 * The application uses this bit to reset the control logic in
+		 * the AHB clock domain. Only AHB clock domain pipelines are
+		 * reset.
+		 */
+		unsigned hsftrst:1;
+		/** Host Frame Counter Reset (Host Only)<br>
+		 *
+		 * The application can reset the (micro)frame number
+		 * counter inside the core, using this bit. When the
+		 * (micro)frame counter is reset, the subsequent SOF
+		 * sent out by the core, will have a (micro)frame
+		 * number of 0.
+		 */
+		unsigned hstfrm:1;
+		/** In Token Sequence Learning Queue Flush
+		 * (INTknQFlsh) (Device Only)
+		 */
+		unsigned intknqflsh:1;
+		/** RxFIFO Flush (RxFFlsh) (Device and Host)
+		 *
+		 * The application can flush the entire Receive FIFO
+		 * using this bit. The application must first
+		 * ensure that the core is not in the middle of a
+		 * transaction. The application should write into
+		 * this bit, only after making sure that neither the
+		 * DMA engine is reading from the RxFIFO nor the MAC
+		 * is writing the data in to the FIFO. The
+		 * application should wait until the bit is cleared
+		 * before performing any other operations. This bit
+		 * will takes 8 clocks (slowest of PHY or AHB clock)
+		 * to clear.
+		 */
+		unsigned rxfflsh:1;
+		/** TxFIFO Flush (TxFFlsh) (Device and Host). 
+		 *
+		 * This bit is used to selectively flush a single or
+		 * all transmit FIFOs. The application must first
+		 * ensure that the core is not in the middle of a
+		 * transaction. The application should write into
+		 * this bit, only after making sure that neither the
+		 * DMA engine is writing into the TxFIFO nor the MAC
+		 * is reading the data out of the FIFO. The
+		 * application should wait until the core clears this
+		 * bit, before performing any operations. This bit
+		 * will takes 8 clocks (slowest of PHY or AHB clock)
+		 * to clear.
+		 */
+		unsigned txfflsh:1;
+
+		/** TxFIFO Number (TxFNum) (Device and Host).
+		 *
+		 * This is the FIFO number which needs to be flushed,
+		 * using the TxFIFO Flush bit. This field should not
+		 * be changed until the TxFIFO Flush bit is cleared by
+		 * the core.
+		 *	 - 0x0 : Non Periodic TxFIFO Flush
+		 *	 - 0x1 : Periodic TxFIFO #1 Flush in device mode
+		 *	   or Periodic TxFIFO in host mode
+		 *	 - 0x2 : Periodic TxFIFO #2 Flush in device mode.
+		 *	 - ...
+		 *	 - 0xF : Periodic TxFIFO #15 Flush in device mode
+		 *	 - 0x10: Flush all the Transmit NonPeriodic and
+		 *	   Transmit Periodic FIFOs in the core
+		 */
+		unsigned txfnum:5;
+		/** Reserved */
+		unsigned reserved11_29:19;
+		/** DMA Request Signal.	 Indicated DMA request is in
+		 * probress. Used for debug purpose. */
+		unsigned dmareq:1;
+		/** AHB Master Idle.  Indicates the AHB Master State
+		 * Machine is in IDLE condition. */
+		unsigned ahbidle:1;
+	} b;
+} grstctl_t;
+
+/**
+ * This union represents the bit fields of the Core Interrupt Mask
+ * Register (GINTMSK). Set/clear the bits using the bit fields then
+ * write the <i>d32</i> value to the register.
+ */
+typedef union gintmsk_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		unsigned reserved0:1;
+		unsigned modemismatch:1;
+		unsigned otgintr:1;
+		unsigned sofintr:1;
+		unsigned rxstsqlvl:1;
+		unsigned nptxfempty:1;
+		unsigned ginnakeff:1;
+		unsigned goutnakeff:1;
+		unsigned ulpickint:1;
+		unsigned i2cintr:1;
+		unsigned erlysuspend:1;
+		unsigned usbsuspend:1;
+		unsigned usbreset:1;
+		unsigned enumdone:1;
+		unsigned isooutdrop:1;
+		unsigned eopframe:1;
+		unsigned restoredone:1;
+		unsigned epmismatch:1;
+		unsigned inepintr:1;
+		unsigned outepintr:1;
+		unsigned incomplisoin:1;
+		unsigned incomplisoout:1;
+		unsigned fetsusp:1;
+		unsigned resetdet:1;
+		unsigned portintr:1;
+		unsigned hcintr:1;
+		unsigned ptxfempty:1;
+		unsigned lpmtranrcvd:1;
+		unsigned conidstschng:1;
+		unsigned disconnect:1;
+		unsigned sessreqintr:1;
+		unsigned wkupintr:1;
+	} b;
+} gintmsk_data_t;
+/**
+ * This union represents the bit fields of the Core Interrupt Register
+ * (GINTSTS).  Set/clear the bits using the bit fields then write the
+ * <i>d32</i> value to the register.
+ */
+typedef union gintsts_data {
+	/** raw register data */
+	uint32_t d32;
+#define DWC_SOF_INTR_MASK 0x0008
+	/** register bits */
+	struct {
+#define DWC_HOST_MODE 1
+		unsigned curmode:1;
+		unsigned modemismatch:1;
+		unsigned otgintr:1;
+		unsigned sofintr:1;
+		unsigned rxstsqlvl:1;
+		unsigned nptxfempty:1;
+		unsigned ginnakeff:1;
+		unsigned goutnakeff:1;
+		unsigned ulpickint:1;
+		unsigned i2cintr:1;
+		unsigned erlysuspend:1;
+		unsigned usbsuspend:1;
+		unsigned usbreset:1;
+		unsigned enumdone:1;
+		unsigned isooutdrop:1;
+		unsigned eopframe:1;
+		unsigned restoredone:1;
+		unsigned epmismatch:1;
+		unsigned inepint:1;
+		unsigned outepintr:1;
+		unsigned incomplisoin:1;
+		unsigned incomplisoout:1;
+		unsigned fetsusp:1;
+		unsigned resetdet:1;
+		unsigned portintr:1;
+		unsigned hcintr:1;
+		unsigned ptxfempty:1;
+		unsigned lpmtranrcvd:1;
+		unsigned conidstschng:1;
+		unsigned disconnect:1;
+		unsigned sessreqintr:1;
+		unsigned wkupintr:1;
+	} b;
+} gintsts_data_t;
+
+/**
+ * This union represents the bit fields in the Device Receive Status Read and
+ * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i>
+ * element then read out the bits using the <i>b</i>it elements.
+ */
+typedef union device_grxsts_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		unsigned epnum:4;
+		unsigned bcnt:11;
+		unsigned dpid:2;
+
+#define DWC_STS_DATA_UPDT		0x2	// OUT Data Packet
+#define DWC_STS_XFER_COMP		0x3	// OUT Data Transfer Complete
+
+#define DWC_DSTS_GOUT_NAK		0x1	// Global OUT NAK
+#define DWC_DSTS_SETUP_COMP		0x4	// Setup Phase Complete
+#define DWC_DSTS_SETUP_UPDT 0x6	// SETUP Packet
+		unsigned pktsts:4;
+		unsigned fn:4;
+		unsigned reserved25_31:7;
+	} b;
+} device_grxsts_data_t;
+
+/**
+ * This union represents the bit fields in the Host Receive Status Read and
+ * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i>
+ * element then read out the bits using the <i>b</i>it elements.
+ */
+typedef union host_grxsts_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		unsigned chnum:4;
+		unsigned bcnt:11;
+		unsigned dpid:2;
+
+		unsigned pktsts:4;
+#define DWC_GRXSTS_PKTSTS_IN			  0x2
+#define DWC_GRXSTS_PKTSTS_IN_XFER_COMP	  0x3
+#define DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR 0x5
+#define DWC_GRXSTS_PKTSTS_CH_HALTED		  0x7
+
+		unsigned reserved21_31:11;
+	} b;
+} host_grxsts_data_t;
+
+/**
+ * This union represents the bit fields in the FIFO Size Registers (HPTXFSIZ,
+ * GNPTXFSIZ, DPTXFSIZn, DIEPTXFn). Read the register into the <i>d32</i> element 
+ * then read out the bits using the <i>b</i>it elements.
+ */
+typedef union fifosize_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		unsigned startaddr:16;
+		unsigned depth:16;
+	} b;
+} fifosize_data_t;
+
+/**
+ * This union represents the bit fields in the Non-Periodic Transmit
+ * FIFO/Queue Status Register (GNPTXSTS). Read the register into the
+ * <i>d32</i> element then read out the bits using the <i>b</i>it
+ * elements.
+ */
+typedef union gnptxsts_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		unsigned nptxfspcavail:16;
+		unsigned nptxqspcavail:8;
+		/** Top of the Non-Periodic Transmit Request Queue
+		 *	- bit 24 - Terminate (Last entry for the selected
+		 *	  channel/EP)
+		 *	- bits 26:25 - Token Type
+		 *	  - 2'b00 - IN/OUT
+		 *	  - 2'b01 - Zero Length OUT
+		 *	  - 2'b10 - PING/Complete Split
+		 *	  - 2'b11 - Channel Halt
+		 *	- bits 30:27 - Channel/EP Number
+		 */
+		unsigned nptxqtop_terminate:1;
+		unsigned nptxqtop_token:2;
+		unsigned nptxqtop_chnep:4;
+		unsigned reserved:1;
+	} b;
+} gnptxsts_data_t;
+
+/**
+ * This union represents the bit fields in the Transmit
+ * FIFO Status Register (DTXFSTS). Read the register into the
+ * <i>d32</i> element then read out the bits using the <i>b</i>it
+ * elements.
+ */
+typedef union dtxfsts_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		unsigned txfspcavail:16;
+		unsigned reserved:16;
+	} b;
+} dtxfsts_data_t;
+
+/**
+ * This union represents the bit fields in the I2C Control Register
+ * (I2CCTL). Read the register into the <i>d32</i> element then read out the
+ * bits using the <i>b</i>it elements.
+ */
+typedef union gi2cctl_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		unsigned rwdata:8;
+		unsigned regaddr:8;
+		unsigned addr:7;
+		unsigned i2cen:1;
+		unsigned ack:1;
+		unsigned i2csuspctl:1;
+		unsigned i2cdevaddr:2;
+		unsigned i2cdatse0:1;
+		unsigned reserved:1;
+		unsigned rw:1;
+		unsigned bsydne:1;
+	} b;
+} gi2cctl_data_t;
+
+/**
+ * This union represents the bit fields in the PHY Vendor Control Register
+ * (GPVNDCTL). Read the register into the <i>d32</i> element then read out the
+ * bits using the <i>b</i>it elements.
+ */
+typedef union gpvndctl_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		unsigned regdata:8;
+		unsigned vctrl:8;
+		unsigned regaddr16_21:6;
+		unsigned regwr:1;
+		unsigned reserved23_24:2;
+		unsigned newregreq:1;
+		unsigned vstsbsy:1;
+		unsigned vstsdone:1;
+		unsigned reserved28_30:3;
+		unsigned disulpidrvr:1;
+	} b;
+} gpvndctl_data_t;
+
+/**
+ * This union represents the bit fields in the General Purpose 
+ * Input/Output Register (GGPIO).
+ * Read the register into the <i>d32</i> element then read out the
+ * bits using the <i>b</i>it elements.
+ */
+typedef union ggpio_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		unsigned gpi:16;
+		unsigned gpo:16;
+	} b;
+} ggpio_data_t;
+
+/**
+ * This union represents the bit fields in the User ID Register
+ * (GUID). Read the register into the <i>d32</i> element then read out the
+ * bits using the <i>b</i>it elements.
+ */
+typedef union guid_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		unsigned rwdata:32;
+	} b;
+} guid_data_t;
+
+/**
+ * This union represents the bit fields in the Synopsys ID Register
+ * (GSNPSID). Read the register into the <i>d32</i> element then read out the
+ * bits using the <i>b</i>it elements.
+ */
+typedef union gsnpsid_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		unsigned rwdata:32;
+	} b;
+} gsnpsid_data_t;
+
+/**
+ * This union represents the bit fields in the User HW Config1
+ * Register.  Read the register into the <i>d32</i> element then read
+ * out the bits using the <i>b</i>it elements.
+ */
+typedef union hwcfg1_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		unsigned ep_dir0:2;
+		unsigned ep_dir1:2;
+		unsigned ep_dir2:2;
+		unsigned ep_dir3:2;
+		unsigned ep_dir4:2;
+		unsigned ep_dir5:2;
+		unsigned ep_dir6:2;
+		unsigned ep_dir7:2;
+		unsigned ep_dir8:2;
+		unsigned ep_dir9:2;
+		unsigned ep_dir10:2;
+		unsigned ep_dir11:2;
+		unsigned ep_dir12:2;
+		unsigned ep_dir13:2;
+		unsigned ep_dir14:2;
+		unsigned ep_dir15:2;
+	} b;
+} hwcfg1_data_t;
+
+/**
+ * This union represents the bit fields in the User HW Config2
+ * Register.  Read the register into the <i>d32</i> element then read
+ * out the bits using the <i>b</i>it elements.
+ */
+typedef union hwcfg2_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		/* GHWCFG2 */
+		unsigned op_mode:3;
+#define DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG 0
+#define DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG 1
+#define DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG 2
+#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3
+#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4
+#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST 5
+#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6
+
+		unsigned architecture:2;
+		unsigned point2point:1;
+		unsigned hs_phy_type:2;
+#define DWC_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0
+#define DWC_HWCFG2_HS_PHY_TYPE_UTMI 1
+#define DWC_HWCFG2_HS_PHY_TYPE_ULPI 2
+#define DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3
+
+		unsigned fs_phy_type:2;
+		unsigned num_dev_ep:4;
+		unsigned num_host_chan:4;
+		unsigned perio_ep_supported:1;
+		unsigned dynamic_fifo:1;
+		unsigned multi_proc_int:1;
+		unsigned reserved21:1;
+		unsigned nonperio_tx_q_depth:2;
+		unsigned host_perio_tx_q_depth:2;
+		unsigned dev_token_q_depth:5;
+		unsigned otg_enable_ic_usb:1;
+	} b;
+} hwcfg2_data_t;
+
+/**
+ * This union represents the bit fields in the User HW Config3
+ * Register.  Read the register into the <i>d32</i> element then read
+ * out the bits using the <i>b</i>it elements.
+ */
+typedef union hwcfg3_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		/* GHWCFG3 */
+		unsigned xfer_size_cntr_width:4;
+		unsigned packet_size_cntr_width:3;
+		unsigned otg_func:1;
+		unsigned i2c:1;
+		unsigned vendor_ctrl_if:1;
+		unsigned optional_features:1;
+		unsigned synch_reset_type:1;
+		unsigned adp_supp:1;
+		unsigned otg_enable_hsic:1;
+		unsigned bc_support:1;
+		unsigned otg_lpm_en:1;
+		unsigned dfifo_depth:16;
+	} b;
+} hwcfg3_data_t;
+
+/**
+ * This union represents the bit fields in the User HW Config4
+ * Register.  Read the register into the <i>d32</i> element then read
+ * out the bits using the <i>b</i>it elements.
+ */
+typedef union hwcfg4_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		unsigned num_dev_perio_in_ep:4;
+		unsigned power_optimiz:1;
+		unsigned min_ahb_freq:1;
+		unsigned part_power_down:1;
+		unsigned reserved:7;
+		unsigned utmi_phy_data_width:2;
+		unsigned num_dev_mode_ctrl_ep:4;
+		unsigned iddig_filt_en:1;
+		unsigned vbus_valid_filt_en:1;
+		unsigned a_valid_filt_en:1;
+		unsigned b_valid_filt_en:1;
+		unsigned session_end_filt_en:1;
+		unsigned ded_fifo_en:1;
+		unsigned num_in_eps:4;
+		unsigned desc_dma:1;
+		unsigned desc_dma_dyn:1;
+	} b;
+} hwcfg4_data_t;
+
+/**
+ * This union represents the bit fields of the Core LPM Configuration
+ * Register (GLPMCFG). Set the bits using bit fields then write
+ * the <i>d32</i> value to the register.
+ */
+typedef union glpmctl_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		/** LPM-Capable (LPMCap) (Device and Host)
+		 * The application uses this bit to control
+		 * the DWC_otg core LPM capabilities.
+		 */
+		unsigned lpm_cap_en:1;
+		/** LPM response programmed by application (AppL1Res) (Device)
+		 * Handshake response to LPM token pre-programmed
+		 * by device application software.
+		 */
+		unsigned appl_resp:1;
+		/** Host Initiated Resume Duration (HIRD) (Device and Host)
+		 * In Host mode this field indicates the value of HIRD
+		 * to be sent in an LPM transaction.
+		 * In Device mode this field is updated with the
+		 * Received LPM Token HIRD bmAttribute
+		 * when an ACK/NYET/STALL response is sent
+		 * to an LPM transaction.
+		 */
+		unsigned hird:4;
+		/** RemoteWakeEnable (bRemoteWake) (Device and Host)
+		 * In Host mode this bit indicates the value of remote
+		 * wake up to be sent in wIndex field of LPM transaction.
+		 * In Device mode this field is updated with the
+		 * Received LPM Token bRemoteWake bmAttribute
+		 * when an ACK/NYET/STALL response is sent
+		 * to an LPM transaction.
+		 */
+		unsigned rem_wkup_en:1;
+		/** Enable utmi_sleep_n (EnblSlpM) (Device and Host)
+		 * The application uses this bit to control
+		 * the utmi_sleep_n assertion to the PHY when in L1 state.
+		 */
+		unsigned en_utmi_sleep:1;
+		/** HIRD Threshold (HIRD_Thres) (Device and Host)
+		 */
+		unsigned hird_thres:5;
+		/** LPM Response (CoreL1Res) (Device and Host)
+		 * In Host mode this bit contains handsake response to
+		 * LPM transaction.
+		 * In Device mode the response of the core to
+		 * LPM transaction received is reflected in these two bits.
+		 	- 0x0 : ERROR (No handshake response)
+			- 0x1 : STALL
+			- 0x2 : NYET
+			- 0x3 : ACK			
+		 */
+		unsigned lpm_resp:2;
+		/** Port Sleep Status (SlpSts) (Device and Host)
+		 * This bit is set as long as a Sleep condition
+		 * is present on the USB bus.
+		 */
+		unsigned prt_sleep_sts:1;
+		/** Sleep State Resume OK (L1ResumeOK) (Device and Host)
+		 * Indicates that the application or host
+		 * can start resume from Sleep state.
+		 */
+		unsigned sleep_state_resumeok:1;
+		/** LPM channel Index (LPM_Chnl_Indx) (Host)
+		 * The channel number on which the LPM transaction
+		 * has to be applied while sending
+		 * an LPM transaction to the local device.
+		 */
+		unsigned lpm_chan_index:4;
+		/** LPM Retry Count (LPM_Retry_Cnt) (Host)
+		 * Number host retries that would be performed
+		 * if the device response was not valid response.
+		 */
+		unsigned retry_count:3;
+		/** Send LPM Transaction (SndLPM) (Host)
+		 * When set by application software,
+		 * an LPM transaction containing two tokens
+		 * is sent.
+		 */
+		unsigned send_lpm:1;
+		/** LPM Retry status (LPM_RetryCnt_Sts) (Host)
+		 * Number of LPM Host Retries still remaining
+		 * to be transmitted for the current LPM sequence
+		 */
+		unsigned retry_count_sts:3;
+		unsigned reserved28_29:2;
+		/** In host mode once this bit is set, the host
+		 * configures to drive the HSIC Idle state on the bus.
+		 * It then waits for the  device to initiate the Connect sequence.
+		 * In device mode once this bit is set, the device waits for
+		 * the HSIC Idle line state on the bus. Upon receving the Idle
+		 * line state, it initiates the HSIC Connect sequence.
+		 */
+		unsigned hsic_connect:1;
+		/** This bit overrides and functionally inverts
+		 * the if_select_hsic input port signal.
+		 */
+		unsigned inv_sel_hsic:1;
+	} b;
+} glpmcfg_data_t;
+
+/**
+ * This union represents the bit fields of the Core ADP Timer, Control and
+ * Status Register (ADPTIMCTLSTS). Set the bits using bit fields then write
+ * the <i>d32</i> value to the register.
+ */
+typedef union adpctl_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		/** Probe Discharge (PRB_DSCHG)
+		 *  These bits set the times for TADP_DSCHG. 
+		 *  These bits are defined as follows:
+		 *  2'b00 - 4 msec
+		 *  2'b01 - 8 msec
+		 *  2'b10 - 16 msec
+		 *  2'b11 - 32 msec
+		 */
+		unsigned prb_dschg:2;
+		/** Probe Delta (PRB_DELTA)
+		 *  These bits set the resolution for RTIM   value.
+		 *  The bits are defined in units of 32 kHz clock cycles as follows:
+		 *  2'b00  -  1 cycles
+		 *  2'b01  -  2 cycles
+		 *  2'b10 -  3 cycles
+		 *  2'b11 - 4 cycles
+		 *  For example if this value is chosen to 2'b01, it means that RTIM
+		 *  increments for every 3(three) 32Khz clock cycles.
+		 */
+		unsigned prb_delta:2;
+		/** Probe Period (PRB_PER)
+		 *  These bits sets the TADP_PRD as shown in Figure 4 as follows:
+		 *  2'b00  -  0.625 to 0.925 sec (typical 0.775 sec)
+		 *  2'b01  -  1.25 to 1.85 sec (typical 1.55 sec)
+		 *  2'b10  -  1.9 to 2.6 sec (typical 2.275 sec)
+		 *  2'b11  -  Reserved
+		 */
+		unsigned prb_per:2;
+		/** These bits capture the latest time it took for VBUS to ramp from 
+		 *  VADP_SINK to VADP_PRB. 
+		 *  0x000  -  1 cycles
+		 *  0x001  -  2 cycles
+		 *  0x002  -  3 cycles
+		 *  etc
+		 *  0x7FF  -  2048 cycles
+		 *  A time of 1024 cycles at 32 kHz corresponds to a time of 32 msec.
+		*/
+		unsigned rtim:11;
+		/** Enable Probe (EnaPrb)
+		 *  When programmed to 1'b1, the core performs a probe operation.
+		 *  This bit is valid only if OTG_Ver = 1'b1.
+		 */
+		unsigned enaprb:1;
+		/** Enable Sense (EnaSns)
+		 *  When programmed to 1'b1, the core performs a Sense operation.
+		 *  This bit is valid only if OTG_Ver = 1'b1.
+		 */
+		unsigned enasns:1;
+		/** ADP Reset (ADPRes)
+		 *  When set, ADP controller is reset.
+		 *  This bit is valid only if OTG_Ver = 1'b1.
+ 		 */
+		unsigned adpres:1;
+		/** ADP Enable (ADPEn)
+		 *  When set, the core performs either ADP probing or sensing
+		 *  based on EnaPrb or EnaSns.
+		 *  This bit is valid only if OTG_Ver = 1'b1.
+		 */
+		unsigned adpen:1;
+		/** ADP Probe Interrupt (ADP_PRB_INT)
+		 *  When this bit is set, it means that the VBUS
+		 *  voltage is greater than VADP_PRB or VADP_PRB is reached.
+		 *  This bit is valid only if OTG_Ver = 1'b1.
+		 */
+		unsigned adp_prb_int:1;
+		/**
+		 *  ADP Sense Interrupt (ADP_SNS_INT)
+		 *  When this bit is set, it means that the VBUS voltage is greater than 
+		 *  VADP_SNS value or VADP_SNS is reached.
+		 *  This bit is valid only if OTG_Ver = 1'b1.
+		 */
+		unsigned adp_sns_int:1;
+		/** ADP Tomeout Interrupt (ADP_TMOUT_INT)
+		 *  This bit is relevant only for an ADP probe.
+		 *  When this bit is set, it means that the ramp time has
+		 *  completed ie ADPCTL.RTIM has reached its terminal value
+		 *  of 0x7FF.  This is a debug feature that allows software
+		 *  to read the ramp time after each cycle.
+		 *  This bit is valid only if OTG_Ver = 1'b1.
+		 */
+		unsigned adp_tmout_int:1;
+		/** ADP Probe Interrupt Mask (ADP_PRB_INT_MSK)
+		 *  When this bit is set, it unmasks the interrupt due to ADP_PRB_INT.
+		 *  This bit is valid only if OTG_Ver = 1'b1.
+		 */
+		unsigned adp_prb_int_msk:1;
+		/** ADP Sense Interrupt Mask (ADP_SNS_INT_MSK)
+		 *  When this bit is set, it unmasks the interrupt due to ADP_SNS_INT.
+		 *  This bit is valid only if OTG_Ver = 1'b1.
+		 */
+		unsigned adp_sns_int_msk:1;
+		/** ADP Timoeout Interrupt Mask (ADP_TMOUT_MSK)
+		 *  When this bit is set, it unmasks the interrupt due to ADP_TMOUT_INT.
+		 *  This bit is valid only if OTG_Ver = 1'b1.
+		 */
+		unsigned adp_tmout_int_msk:1;
+		/** Access Request
+		 * 2'b00 - Read/Write Valid (updated by the core) 
+		 * 2'b01 - Read
+		 * 2'b00 - Write
+		 * 2'b00 - Reserved
+		 */
+		unsigned ar:2;
+		 /** Reserved */
+		unsigned reserved29_31:3;
+	} b;
+} adpctl_data_t;
+
+////////////////////////////////////////////
+// Device Registers
+/**
+ * Device Global Registers. <i>Offsets 800h-BFFh</i>
+ *
+ * The following structures define the size and relative field offsets
+ * for the Device Mode Registers.
+ *
+ * <i>These registers are visible only in Device mode and must not be
+ * accessed in Host mode, as the results are unknown.</i>
+ */
+typedef struct dwc_otg_dev_global_regs {
+	/** Device Configuration Register. <i>Offset 800h</i> */
+	volatile uint32_t dcfg;
+	/** Device Control Register. <i>Offset: 804h</i> */
+	volatile uint32_t dctl;
+	/** Device Status Register (Read Only). <i>Offset: 808h</i> */
+	volatile uint32_t dsts;
+	/** Reserved. <i>Offset: 80Ch</i> */
+	uint32_t unused;
+	/** Device IN Endpoint Common Interrupt Mask
+	 * Register. <i>Offset: 810h</i> */
+	volatile uint32_t diepmsk;
+	/** Device OUT Endpoint Common Interrupt Mask
+	 * Register. <i>Offset: 814h</i> */
+	volatile uint32_t doepmsk;
+	/** Device All Endpoints Interrupt Register.  <i>Offset: 818h</i> */
+	volatile uint32_t daint;
+	/** Device All Endpoints Interrupt Mask Register.  <i>Offset:
+	 * 81Ch</i> */
+	volatile uint32_t daintmsk;
+	/** Device IN Token Queue Read Register-1 (Read Only).
+	 * <i>Offset: 820h</i> */
+	volatile uint32_t dtknqr1;
+	/** Device IN Token Queue Read Register-2 (Read Only).
+	 * <i>Offset: 824h</i> */
+	volatile uint32_t dtknqr2;
+	/** Device VBUS	 discharge Register.  <i>Offset: 828h</i> */
+	volatile uint32_t dvbusdis;
+	/** Device VBUS Pulse Register.	 <i>Offset: 82Ch</i> */
+	volatile uint32_t dvbuspulse;
+	/** Device IN Token Queue Read Register-3 (Read Only). /
+	 *	Device Thresholding control register (Read/Write)
+	 * <i>Offset: 830h</i> */
+	volatile uint32_t dtknqr3_dthrctl;
+	/** Device IN Token Queue Read Register-4 (Read Only). /
+	 *	Device IN EPs empty Inr. Mask Register (Read/Write)
+	 * <i>Offset: 834h</i> */
+	volatile uint32_t dtknqr4_fifoemptymsk;
+	/** Device Each Endpoint Interrupt Register (Read Only). /
+	 * <i>Offset: 838h</i> */
+	volatile uint32_t deachint;
+	/** Device Each Endpoint Interrupt mask Register (Read/Write). /
+	 * <i>Offset: 83Ch</i> */
+	volatile uint32_t deachintmsk;
+	/** Device Each In Endpoint Interrupt mask Register (Read/Write). /
+	 * <i>Offset: 840h</i> */
+	volatile uint32_t diepeachintmsk[MAX_EPS_CHANNELS];
+	/** Device Each Out Endpoint Interrupt mask Register (Read/Write). /
+	 * <i>Offset: 880h</i> */
+	volatile uint32_t doepeachintmsk[MAX_EPS_CHANNELS];
+} dwc_otg_device_global_regs_t;
+
+/**
+ * This union represents the bit fields in the Device Configuration
+ * Register.  Read the register into the <i>d32</i> member then
+ * set/clear the bits using the <i>b</i>it elements.  Write the
+ * <i>d32</i> member to the dcfg register.
+ */
+typedef union dcfg_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		/** Device Speed */
+		unsigned devspd:2;
+		/** Non Zero Length Status OUT Handshake */
+		unsigned nzstsouthshk:1;
+#define DWC_DCFG_SEND_STALL 1
+
+		unsigned ena32khzs:1;
+		/** Device Addresses */
+		unsigned devaddr:7;
+		/** Periodic Frame Interval */
+		unsigned perfrint:2;
+#define DWC_DCFG_FRAME_INTERVAL_80 0
+#define DWC_DCFG_FRAME_INTERVAL_85 1
+#define DWC_DCFG_FRAME_INTERVAL_90 2
+#define DWC_DCFG_FRAME_INTERVAL_95 3
+		
+		/** Enable Device OUT NAK for bulk in DDMA mode */
+		unsigned endevoutnak:1;
+
+		unsigned reserved14_17:4;
+		/** In Endpoint Mis-match count */
+		unsigned epmscnt:5;
+		/** Enable Descriptor DMA in Device mode */
+		unsigned descdma:1;
+		unsigned perschintvl:2;
+		unsigned resvalid:6;
+	} b;
+} dcfg_data_t;
+
+/**
+ * This union represents the bit fields in the Device Control
+ * Register.  Read the register into the <i>d32</i> member then
+ * set/clear the bits using the <i>b</i>it elements.
+ */
+typedef union dctl_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		/** Remote Wakeup */
+		unsigned rmtwkupsig:1;
+		/** Soft Disconnect */
+		unsigned sftdiscon:1;
+		/** Global Non-Periodic IN NAK Status */
+		unsigned gnpinnaksts:1;
+		/** Global OUT NAK Status */
+		unsigned goutnaksts:1;
+		/** Test Control */
+		unsigned tstctl:3;
+		/** Set Global Non-Periodic IN NAK */
+		unsigned sgnpinnak:1;
+		/** Clear Global Non-Periodic IN NAK */
+		unsigned cgnpinnak:1;
+		/** Set Global OUT NAK */
+		unsigned sgoutnak:1;
+		/** Clear Global OUT NAK */
+		unsigned cgoutnak:1;
+		/** Power-On Programming Done */
+		unsigned pwronprgdone:1;
+		/** Reserved */
+		unsigned reserved:1;
+		/** Global Multi Count */
+		unsigned gmc:2;
+		/** Ignore Frame Number for ISOC EPs */
+		unsigned ifrmnum:1;
+		/** NAK on Babble */
+		unsigned nakonbble:1;
+		/** Enable Continue on BNA */
+		unsigned encontonbna:1;
+
+		unsigned reserved18_31:14;
+	} b;
+} dctl_data_t;
+
+/**
+ * This union represents the bit fields in the Device Status
+ * Register.  Read the register into the <i>d32</i> member then
+ * set/clear the bits using the <i>b</i>it elements.
+ */
+typedef union dsts_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		/** Suspend Status */
+		unsigned suspsts:1;
+		/** Enumerated Speed */
+		unsigned enumspd:2;
+#define DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0
+#define DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1
+#define DWC_DSTS_ENUMSPD_LS_PHY_6MHZ		   2
+#define DWC_DSTS_ENUMSPD_FS_PHY_48MHZ		   3
+		/** Erratic Error */
+		unsigned errticerr:1;
+		unsigned reserved4_7:4;
+		/** Frame or Microframe Number of the received SOF */
+		unsigned soffn:14;
+		unsigned reserved22_31:10;
+	} b;
+} dsts_data_t;
+
+/**
+ * This union represents the bit fields in the Device IN EP Interrupt
+ * Register and the Device IN EP Common Mask Register.
+ *
+ * - Read the register into the <i>d32</i> member then set/clear the
+ *	 bits using the <i>b</i>it elements.
+ */
+typedef union diepint_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		/** Transfer complete mask */
+		unsigned xfercompl:1;
+		/** Endpoint disable mask */
+		unsigned epdisabled:1;
+		/** AHB Error mask */
+		unsigned ahberr:1;
+		/** TimeOUT Handshake mask (non-ISOC EPs) */
+		unsigned timeout:1;
+		/** IN Token received with TxF Empty mask */
+		unsigned intktxfemp:1;
+		/** IN Token Received with EP mismatch mask */
+		unsigned intknepmis:1;
+		/** IN Endpoint NAK Effective mask */
+		unsigned inepnakeff:1;
+		/** Reserved */
+		unsigned emptyintr:1;
+
+		unsigned txfifoundrn:1;
+
+		/** BNA Interrupt mask */
+		unsigned bna:1;
+
+		unsigned reserved10_12:3;
+		/** BNA Interrupt mask */
+		unsigned nak:1;
+
+		unsigned reserved14_31:18;
+	} b;
+} diepint_data_t;
+
+/**
+ * This union represents the bit fields in the Device IN EP
+ * Common/Dedicated Interrupt Mask Register.
+ */
+typedef union diepint_data diepmsk_data_t;
+
+/**
+ * This union represents the bit fields in the Device OUT EP Interrupt
+ * Registerand Device OUT EP Common Interrupt Mask Register.
+ *
+ * - Read the register into the <i>d32</i> member then set/clear the
+ *	 bits using the <i>b</i>it elements.
+ */
+typedef union doepint_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		/** Transfer complete */
+		unsigned xfercompl:1;
+		/** Endpoint disable  */
+		unsigned epdisabled:1;
+		/** AHB Error */
+		unsigned ahberr:1;
+		/** Setup Phase Done (contorl EPs) */
+		unsigned setup:1;
+		/** OUT Token Received when Endpoint Disabled */
+		unsigned outtknepdis:1;
+
+		unsigned stsphsercvd:1;
+		/** Back-to-Back SETUP Packets Received */
+		unsigned back2backsetup:1;
+
+		unsigned reserved7:1;
+		/** OUT packet Error */
+		unsigned outpkterr:1;
+		/** BNA Interrupt */
+		unsigned bna:1;
+
+		unsigned reserved10:1;
+		/** Packet Drop Status */
+		unsigned pktdrpsts:1;
+		/** Babble Interrupt */
+		unsigned babble:1;
+		/** NAK Interrupt */
+		unsigned nak:1;
+		/** NYET Interrupt */
+		unsigned nyet:1;
+
+		unsigned reserved15_31:17;
+	} b;
+} doepint_data_t;
+
+/**
+ * This union represents the bit fields in the Device OUT EP
+ * Common/Dedicated Interrupt Mask Register.
+ */
+typedef union doepint_data doepmsk_data_t;
+
+/**
+ * This union represents the bit fields in the Device All EP Interrupt
+ * and Mask Registers.
+ * - Read the register into the <i>d32</i> member then set/clear the
+ *	 bits using the <i>b</i>it elements.
+ */
+typedef union daint_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		/** IN Endpoint bits */
+		unsigned in:16;
+		/** OUT Endpoint bits */
+		unsigned out:16;
+	} ep;
+	struct {
+		/** IN Endpoint bits */
+		unsigned inep0:1;
+		unsigned inep1:1;
+		unsigned inep2:1;
+		unsigned inep3:1;
+		unsigned inep4:1;
+		unsigned inep5:1;
+		unsigned inep6:1;
+		unsigned inep7:1;
+		unsigned inep8:1;
+		unsigned inep9:1;
+		unsigned inep10:1;
+		unsigned inep11:1;
+		unsigned inep12:1;
+		unsigned inep13:1;
+		unsigned inep14:1;
+		unsigned inep15:1;
+		/** OUT Endpoint bits */
+		unsigned outep0:1;
+		unsigned outep1:1;
+		unsigned outep2:1;
+		unsigned outep3:1;
+		unsigned outep4:1;
+		unsigned outep5:1;
+		unsigned outep6:1;
+		unsigned outep7:1;
+		unsigned outep8:1;
+		unsigned outep9:1;
+		unsigned outep10:1;
+		unsigned outep11:1;
+		unsigned outep12:1;
+		unsigned outep13:1;
+		unsigned outep14:1;
+		unsigned outep15:1;
+	} b;
+} daint_data_t;
+
+/**
+ * This union represents the bit fields in the Device IN Token Queue
+ * Read Registers.
+ * - Read the register into the <i>d32</i> member.
+ * - READ-ONLY Register
+ */
+typedef union dtknq1_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		/** In Token Queue Write Pointer */
+		unsigned intknwptr:5;
+		/** Reserved */
+		unsigned reserved05_06:2;
+		/** write pointer has wrapped. */
+		unsigned wrap_bit:1;
+		/** EP Numbers of IN Tokens 0 ... 4 */
+		unsigned epnums0_5:24;
+	} b;
+} dtknq1_data_t;
+
+/**
+ * This union represents Threshold control Register
+ * - Read and write the register into the <i>d32</i> member.
+ * - READ-WRITABLE Register
+ */
+typedef union dthrctl_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		/** non ISO Tx Thr. Enable */
+		unsigned non_iso_thr_en:1;
+		/** ISO Tx Thr. Enable */
+		unsigned iso_thr_en:1;
+		/** Tx Thr. Length */
+		unsigned tx_thr_len:9;
+		/** AHB Threshold ratio */
+		unsigned ahb_thr_ratio:2;
+		/** Reserved */
+		unsigned reserved13_15:3;
+		/** Rx Thr. Enable */
+		unsigned rx_thr_en:1;
+		/** Rx Thr. Length */
+		unsigned rx_thr_len:9;
+		unsigned reserved26:1;
+		/** Arbiter Parking Enable*/
+		unsigned arbprken:1;
+		/** Reserved */
+		unsigned reserved28_31:4;
+	} b;
+} dthrctl_data_t;
+
+/**
+ * Device Logical IN Endpoint-Specific Registers. <i>Offsets
+ * 900h-AFCh</i>
+ *
+ * There will be one set of endpoint registers per logical endpoint
+ * implemented.
+ *
+ * <i>These registers are visible only in Device mode and must not be
+ * accessed in Host mode, as the results are unknown.</i>
+ */
+typedef struct dwc_otg_dev_in_ep_regs {
+	/** Device IN Endpoint Control Register. <i>Offset:900h +
+	 * (ep_num * 20h) + 00h</i> */
+	volatile uint32_t diepctl;
+	/** Reserved. <i>Offset:900h + (ep_num * 20h) + 04h</i> */
+	uint32_t reserved04;
+	/** Device IN Endpoint Interrupt Register. <i>Offset:900h +
+	 * (ep_num * 20h) + 08h</i> */
+	volatile uint32_t diepint;
+	/** Reserved. <i>Offset:900h + (ep_num * 20h) + 0Ch</i> */
+	uint32_t reserved0C;
+	/** Device IN Endpoint Transfer Size
+	 * Register. <i>Offset:900h + (ep_num * 20h) + 10h</i> */
+	volatile uint32_t dieptsiz;
+	/** Device IN Endpoint DMA Address Register. <i>Offset:900h +
+	 * (ep_num * 20h) + 14h</i> */
+	volatile uint32_t diepdma;
+	/** Device IN Endpoint Transmit FIFO Status Register. <i>Offset:900h +
+	 * (ep_num * 20h) + 18h</i> */
+	volatile uint32_t dtxfsts;
+	/** Device IN Endpoint DMA Buffer Register. <i>Offset:900h +
+	 * (ep_num * 20h) + 1Ch</i> */
+	volatile uint32_t diepdmab;
+} dwc_otg_dev_in_ep_regs_t;
+
+/**
+ * Device Logical OUT Endpoint-Specific Registers. <i>Offsets:
+ * B00h-CFCh</i>
+ *
+ * There will be one set of endpoint registers per logical endpoint
+ * implemented.
+ *
+ * <i>These registers are visible only in Device mode and must not be
+ * accessed in Host mode, as the results are unknown.</i>
+ */
+typedef struct dwc_otg_dev_out_ep_regs {
+	/** Device OUT Endpoint Control Register. <i>Offset:B00h +
+	 * (ep_num * 20h) + 00h</i> */
+	volatile uint32_t doepctl;
+	/** Reserved. <i>Offset:B00h + (ep_num * 20h) + 04h</i> */
+	uint32_t reserved04;
+	/** Device OUT Endpoint Interrupt Register. <i>Offset:B00h +
+	 * (ep_num * 20h) + 08h</i> */
+	volatile uint32_t doepint;
+	/** Reserved. <i>Offset:B00h + (ep_num * 20h) + 0Ch</i> */
+	uint32_t reserved0C;
+	/** Device OUT Endpoint Transfer Size Register. <i>Offset:
+	 * B00h + (ep_num * 20h) + 10h</i> */
+	volatile uint32_t doeptsiz;
+	/** Device OUT Endpoint DMA Address Register. <i>Offset:B00h
+	 * + (ep_num * 20h) + 14h</i> */
+	volatile uint32_t doepdma;
+	/** Reserved. <i>Offset:B00h + 	 * (ep_num * 20h) + 18h</i> */
+	uint32_t unused;
+	/** Device OUT Endpoint DMA Buffer Register. <i>Offset:B00h
+	 * + (ep_num * 20h) + 1Ch</i> */
+	uint32_t doepdmab;
+} dwc_otg_dev_out_ep_regs_t;
+
+/**
+ * This union represents the bit fields in the Device EP Control
+ * Register.  Read the register into the <i>d32</i> member then
+ * set/clear the bits using the <i>b</i>it elements.
+ */
+typedef union depctl_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		/** Maximum Packet Size
+		 * IN/OUT EPn
+		 * IN/OUT EP0 - 2 bits
+		 *	 2'b00: 64 Bytes
+		 *	 2'b01: 32
+		 *	 2'b10: 16
+		 *	 2'b11: 8 */
+		unsigned mps:11;
+#define DWC_DEP0CTL_MPS_64	 0
+#define DWC_DEP0CTL_MPS_32	 1
+#define DWC_DEP0CTL_MPS_16	 2
+#define DWC_DEP0CTL_MPS_8	 3
+
+		/** Next Endpoint
+		 * IN EPn/IN EP0
+		 * OUT EPn/OUT EP0 - reserved */
+		unsigned nextep:4;
+
+		/** USB Active Endpoint */
+		unsigned usbactep:1;
+
+		/** Endpoint DPID (INTR/Bulk IN and OUT endpoints)
+		 * This field contains the PID of the packet going to
+		 * be received or transmitted on this endpoint. The
+		 * application should program the PID of the first
+		 * packet going to be received or transmitted on this
+		 * endpoint , after the endpoint is
+		 * activated. Application use the SetD1PID and
+		 * SetD0PID fields of this register to program either
+		 * D0 or D1 PID.
+		 *
+		 * The encoding for this field is
+		 *	 - 0: D0
+		 *	 - 1: D1
+		 */
+		unsigned dpid:1;
+
+		/** NAK Status */
+		unsigned naksts:1;
+
+		/** Endpoint Type
+		 *	2'b00: Control
+		 *	2'b01: Isochronous
+		 *	2'b10: Bulk
+		 *	2'b11: Interrupt */
+		unsigned eptype:2;
+
+		/** Snoop Mode
+		 * OUT EPn/OUT EP0
+		 * IN EPn/IN EP0 - reserved */
+		unsigned snp:1;
+
+		/** Stall Handshake */
+		unsigned stall:1;
+
+		/** Tx Fifo Number
+		 * IN EPn/IN EP0
+		 * OUT EPn/OUT EP0 - reserved */
+		unsigned txfnum:4;
+
+		/** Clear NAK */
+		unsigned cnak:1;
+		/** Set NAK */
+		unsigned snak:1;
+		/** Set DATA0 PID (INTR/Bulk IN and OUT endpoints)
+		 * Writing to this field sets the Endpoint DPID (DPID)
+		 * field in this register to DATA0. Set Even
+		 * (micro)frame (SetEvenFr) (ISO IN and OUT Endpoints)
+		 * Writing to this field sets the Even/Odd
+		 * (micro)frame (EO_FrNum) field to even (micro)
+		 * frame.
+		 */
+		unsigned setd0pid:1;
+		/** Set DATA1 PID (INTR/Bulk IN and OUT endpoints)
+		 * Writing to this field sets the Endpoint DPID (DPID)
+		 * field in this register to DATA1 Set Odd
+		 * (micro)frame (SetOddFr) (ISO IN and OUT Endpoints)
+		 * Writing to this field sets the Even/Odd
+		 * (micro)frame (EO_FrNum) field to odd (micro) frame.
+		 */
+		unsigned setd1pid:1;
+
+		/** Endpoint Disable */
+		unsigned epdis:1;
+		/** Endpoint Enable */
+		unsigned epena:1;
+	} b;
+} depctl_data_t;
+
+/**
+ * This union represents the bit fields in the Device EP Transfer
+ * Size Register.  Read the register into the <i>d32</i> member then
+ * set/clear the bits using the <i>b</i>it elements.
+ */
+typedef union deptsiz_data {
+		/** raw register data */
+	uint32_t d32;
+		/** register bits */
+	struct {
+		/** Transfer size */
+		unsigned xfersize:19;
+/** Max packet count for EP (pow(2,10)-1) */
+#define MAX_PKT_CNT 1023
+		/** Packet Count */
+		unsigned pktcnt:10;
+		/** Multi Count - Periodic IN endpoints */
+		unsigned mc:2;
+		unsigned reserved:1;
+	} b;
+} deptsiz_data_t;
+
+/**
+ * This union represents the bit fields in the Device EP 0 Transfer
+ * Size Register.  Read the register into the <i>d32</i> member then
+ * set/clear the bits using the <i>b</i>it elements.
+ */
+typedef union deptsiz0_data {
+		/** raw register data */
+	uint32_t d32;
+		/** register bits */
+	struct {
+		/** Transfer size */
+		unsigned xfersize:7;
+				/** Reserved */
+		unsigned reserved7_18:12;
+		/** Packet Count */
+		unsigned pktcnt:2;
+				/** Reserved */
+		unsigned reserved21_28:8;
+				/**Setup Packet Count (DOEPTSIZ0 Only) */
+		unsigned supcnt:2;
+		unsigned reserved31;
+	} b;
+} deptsiz0_data_t;
+
+/////////////////////////////////////////////////
+// DMA Descriptor Specific Structures
+//
+
+/** Buffer status definitions */
+
+#define BS_HOST_READY	0x0
+#define BS_DMA_BUSY		0x1
+#define BS_DMA_DONE		0x2
+#define BS_HOST_BUSY	0x3
+
+/** Receive/Transmit status definitions */
+
+#define RTS_SUCCESS		0x0
+#define RTS_BUFFLUSH	0x1
+#define RTS_RESERVED	0x2
+#define RTS_BUFERR		0x3
+
+/**
+ * This union represents the bit fields in the DMA Descriptor
+ * status quadlet. Read the quadlet into the <i>d32</i> member then
+ * set/clear the bits using the <i>b</i>it, <i>b_iso_out</i> and
+ * <i>b_iso_in</i> elements.
+ */
+typedef union dev_dma_desc_sts {
+		/** raw register data */
+	uint32_t d32;
+		/** quadlet bits */
+	struct {
+		/** Received number of bytes */
+		unsigned bytes:16;
+		/** NAK bit - only for OUT EPs */
+		unsigned nak:1;
+		unsigned reserved17_22:6;
+		/** Multiple Transfer - only for OUT EPs */
+		unsigned mtrf:1;
+		/** Setup Packet received - only for OUT EPs */
+		unsigned sr:1;
+		/** Interrupt On Complete */
+		unsigned ioc:1;
+		/** Short Packet */
+		unsigned sp:1;
+		/** Last */
+		unsigned l:1;
+		/** Receive Status */
+		unsigned sts:2;
+		/** Buffer Status */
+		unsigned bs:2;
+	} b;
+
+//#ifdef DWC_EN_ISOC
+		/** iso out quadlet bits */
+	struct {
+		/** Received number of bytes */
+		unsigned rxbytes:11;
+
+		unsigned reserved11:1;
+		/** Frame Number */
+		unsigned framenum:11;
+		/** Received ISO Data PID */
+		unsigned pid:2;
+		/** Interrupt On Complete */
+		unsigned ioc:1;
+		/** Short Packet */
+		unsigned sp:1;
+		/** Last */
+		unsigned l:1;
+		/** Receive Status */
+		unsigned rxsts:2;
+		/** Buffer Status */
+		unsigned bs:2;
+	} b_iso_out;
+
+		/** iso in quadlet bits */
+	struct {
+		/** Transmited number of bytes */
+		unsigned txbytes:12;
+		/** Frame Number */
+		unsigned framenum:11;
+		/** Transmited ISO Data PID */
+		unsigned pid:2;
+		/** Interrupt On Complete */
+		unsigned ioc:1;
+		/** Short Packet */
+		unsigned sp:1;
+		/** Last */
+		unsigned l:1;
+		/** Transmit Status */
+		unsigned txsts:2;
+		/** Buffer Status */
+		unsigned bs:2;
+	} b_iso_in;
+//#endif                                /* DWC_EN_ISOC */
+} dev_dma_desc_sts_t;
+
+/**
+ * DMA Descriptor structure
+ *
+ * DMA Descriptor structure contains two quadlets:
+ * Status quadlet and Data buffer pointer.
+ */
+typedef struct dwc_otg_dev_dma_desc {
+	/** DMA Descriptor status quadlet */
+	dev_dma_desc_sts_t status;
+	/** DMA Descriptor data buffer pointer */
+	uint32_t buf;
+} dwc_otg_dev_dma_desc_t;
+
+/**
+ * The dwc_otg_dev_if structure contains information needed to manage
+ * the DWC_otg controller acting in device mode. It represents the
+ * programming view of the device-specific aspects of the controller.
+ */
+typedef struct dwc_otg_dev_if {
+	/** Pointer to device Global registers.
+	 * Device Global Registers starting at offset 800h
+	 */
+	dwc_otg_device_global_regs_t *dev_global_regs;
+#define DWC_DEV_GLOBAL_REG_OFFSET 0x800
+
+	/**
+	 * Device Logical IN Endpoint-Specific Registers 900h-AFCh
+	 */
+	dwc_otg_dev_in_ep_regs_t *in_ep_regs[MAX_EPS_CHANNELS];
+#define DWC_DEV_IN_EP_REG_OFFSET 0x900
+#define DWC_EP_REG_OFFSET 0x20
+
+	/** Device Logical OUT Endpoint-Specific Registers B00h-CFCh */
+	dwc_otg_dev_out_ep_regs_t *out_ep_regs[MAX_EPS_CHANNELS];
+#define DWC_DEV_OUT_EP_REG_OFFSET 0xB00
+
+	/* Device configuration information */
+	uint8_t speed;				 /**< Device Speed	0: Unknown, 1: LS, 2:FS, 3: HS */
+	uint8_t num_in_eps;		 /**< Number # of Tx EP range: 0-15 exept ep0 */
+	uint8_t num_out_eps;		 /**< Number # of Rx EP range: 0-15 exept ep 0*/
+
+	/** Size of periodic FIFOs (Bytes) */
+	uint16_t perio_tx_fifo_size[MAX_PERIO_FIFOS];
+
+	/** Size of Tx FIFOs (Bytes) */
+	uint16_t tx_fifo_size[MAX_TX_FIFOS];
+
+	/** Thresholding enable flags and length varaiables **/
+	uint16_t rx_thr_en;
+	uint16_t iso_tx_thr_en;
+	uint16_t non_iso_tx_thr_en;
+
+	uint16_t rx_thr_length;
+	uint16_t tx_thr_length;
+
+	/**
+	 * Pointers to the DMA Descriptors for EP0 Control
+	 * transfers (virtual and physical)
+	 */
+
+	/** 2 descriptors for SETUP packets */
+	dwc_dma_t dma_setup_desc_addr[2];
+	dwc_otg_dev_dma_desc_t *setup_desc_addr[2];
+
+	/** Pointer to Descriptor with latest SETUP packet */
+	dwc_otg_dev_dma_desc_t *psetup;
+
+	/** Index of current SETUP handler descriptor */
+	uint32_t setup_desc_index;
+
+	/** Descriptor for Data In or Status In phases */
+	dwc_dma_t dma_in_desc_addr;
+	dwc_otg_dev_dma_desc_t *in_desc_addr;
+
+	/** Descriptor for Data Out or Status Out phases */
+	dwc_dma_t dma_out_desc_addr;
+	dwc_otg_dev_dma_desc_t *out_desc_addr;
+
+	/** Setup Packet Detected - if set clear NAK when queueing */
+	uint32_t spd;
+	/** Isoc ep pointer on which incomplete happens */
+	void *isoc_ep;
+
+} dwc_otg_dev_if_t;
+
+/////////////////////////////////////////////////
+// Host Mode Register Structures
+//
+/**
+ * The Host Global Registers structure defines the size and relative
+ * field offsets for the Host Mode Global Registers.  Host Global
+ * Registers offsets 400h-7FFh.
+*/
+typedef struct dwc_otg_host_global_regs {
+	/** Host Configuration Register.   <i>Offset: 400h</i> */
+	volatile uint32_t hcfg;
+	/** Host Frame Interval Register.	<i>Offset: 404h</i> */
+	volatile uint32_t hfir;
+	/** Host Frame Number / Frame Remaining Register. <i>Offset: 408h</i> */
+	volatile uint32_t hfnum;
+	/** Reserved.	<i>Offset: 40Ch</i> */
+	uint32_t reserved40C;
+	/** Host Periodic Transmit FIFO/ Queue Status Register. <i>Offset: 410h</i> */
+	volatile uint32_t hptxsts;
+	/** Host All Channels Interrupt Register. <i>Offset: 414h</i> */
+	volatile uint32_t haint;
+	/** Host All Channels Interrupt Mask Register. <i>Offset: 418h</i> */
+	volatile uint32_t haintmsk;
+	/** Host Frame List Base Address Register . <i>Offset: 41Ch</i> */
+	volatile uint32_t hflbaddr;
+} dwc_otg_host_global_regs_t;
+
+/**
+ * This union represents the bit fields in the Host Configuration Register.
+ * Read the register into the <i>d32</i> member then set/clear the bits using
+ * the <i>b</i>it elements. Write the <i>d32</i> member to the hcfg register.
+ */
+typedef union hcfg_data {
+	/** raw register data */
+	uint32_t d32;
+
+	/** register bits */
+	struct {
+		/** FS/LS Phy Clock Select */
+		unsigned fslspclksel:2;
+#define DWC_HCFG_30_60_MHZ 0
+#define DWC_HCFG_48_MHZ	   1
+#define DWC_HCFG_6_MHZ	   2
+
+		/** FS/LS Only Support */
+		unsigned fslssupp:1;
+		unsigned reserved3_6:4;
+		/** Enable 32-KHz Suspend Mode */
+		unsigned ena32khzs:1;
+		/** Resume Validation Periiod */
+		unsigned resvalid:8;
+		unsigned reserved16_22:7;
+		/** Enable Scatter/gather DMA in Host mode */
+		unsigned descdma:1;
+		/** Frame List Entries */
+		unsigned frlisten:2;
+		/** Enable Periodic Scheduling */
+		unsigned perschedena:1;
+		unsigned reserved27_30:4;
+		unsigned modechtimen:1;
+	} b;
+} hcfg_data_t;
+
+/**
+ * This union represents the bit fields in the Host Frame Remaing/Number
+ * Register. 
+ */
+typedef union hfir_data {
+	/** raw register data */
+	uint32_t d32;
+
+	/** register bits */
+	struct {
+		unsigned frint:16;
+		unsigned hfirrldctrl:1;
+		unsigned reserved:15;
+	} b;
+} hfir_data_t;
+
+/**
+ * This union represents the bit fields in the Host Frame Remaing/Number
+ * Register. 
+ */
+typedef union hfnum_data {
+	/** raw register data */
+	uint32_t d32;
+
+	/** register bits */
+	struct {
+		unsigned frnum:16;
+#define DWC_HFNUM_MAX_FRNUM 0x3FFF
+		unsigned frrem:16;
+	} b;
+} hfnum_data_t;
+
+typedef union hptxsts_data {
+	/** raw register data */
+	uint32_t d32;
+
+	/** register bits */
+	struct {
+		unsigned ptxfspcavail:16;
+		unsigned ptxqspcavail:8;
+		/** Top of the Periodic Transmit Request Queue
+		 *	- bit 24 - Terminate (last entry for the selected channel)
+		 *	- bits 26:25 - Token Type
+		 *	  - 2'b00 - Zero length
+		 *	  - 2'b01 - Ping
+		 *	  - 2'b10 - Disable
+		 *	- bits 30:27 - Channel Number
+		 *	- bit 31 - Odd/even microframe
+		 */
+		unsigned ptxqtop_terminate:1;
+		unsigned ptxqtop_token:2;
+		unsigned ptxqtop_chnum:4;
+		unsigned ptxqtop_odd:1;
+	} b;
+} hptxsts_data_t;
+
+/**
+ * This union represents the bit fields in the Host Port Control and Status
+ * Register. Read the register into the <i>d32</i> member then set/clear the
+ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
+ * hprt0 register.
+ */
+typedef union hprt0_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		unsigned prtconnsts:1;
+		unsigned prtconndet:1;
+		unsigned prtena:1;
+		unsigned prtenchng:1;
+		unsigned prtovrcurract:1;
+		unsigned prtovrcurrchng:1;
+		unsigned prtres:1;
+		unsigned prtsusp:1;
+		unsigned prtrst:1;
+		unsigned reserved9:1;
+		unsigned prtlnsts:2;
+		unsigned prtpwr:1;
+		unsigned prttstctl:4;
+		unsigned prtspd:2;
+#define DWC_HPRT0_PRTSPD_HIGH_SPEED 0
+#define DWC_HPRT0_PRTSPD_FULL_SPEED 1
+#define DWC_HPRT0_PRTSPD_LOW_SPEED	2
+		unsigned reserved19_31:13;
+	} b;
+} hprt0_data_t;
+
+/**
+ * This union represents the bit fields in the Host All Interrupt
+ * Register. 
+ */
+typedef union haint_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		unsigned ch0:1;
+		unsigned ch1:1;
+		unsigned ch2:1;
+		unsigned ch3:1;
+		unsigned ch4:1;
+		unsigned ch5:1;
+		unsigned ch6:1;
+		unsigned ch7:1;
+		unsigned ch8:1;
+		unsigned ch9:1;
+		unsigned ch10:1;
+		unsigned ch11:1;
+		unsigned ch12:1;
+		unsigned ch13:1;
+		unsigned ch14:1;
+		unsigned ch15:1;
+		unsigned reserved:16;
+	} b;
+
+	struct {
+		unsigned chint:16;
+		unsigned reserved:16;
+	} b2;
+} haint_data_t;
+
+/**
+ * This union represents the bit fields in the Host All Interrupt
+ * Register. 
+ */
+typedef union haintmsk_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		unsigned ch0:1;
+		unsigned ch1:1;
+		unsigned ch2:1;
+		unsigned ch3:1;
+		unsigned ch4:1;
+		unsigned ch5:1;
+		unsigned ch6:1;
+		unsigned ch7:1;
+		unsigned ch8:1;
+		unsigned ch9:1;
+		unsigned ch10:1;
+		unsigned ch11:1;
+		unsigned ch12:1;
+		unsigned ch13:1;
+		unsigned ch14:1;
+		unsigned ch15:1;
+		unsigned reserved:16;
+	} b;
+
+	struct {
+		unsigned chint:16;
+		unsigned reserved:16;
+	} b2;
+} haintmsk_data_t;
+
+/**
+ * Host Channel Specific Registers. <i>500h-5FCh</i>
+ */
+typedef struct dwc_otg_hc_regs {
+	/** Host Channel 0 Characteristic Register. <i>Offset: 500h + (chan_num * 20h) + 00h</i> */
+	volatile uint32_t hcchar;
+	/** Host Channel 0 Split Control Register. <i>Offset: 500h + (chan_num * 20h) + 04h</i> */
+	volatile uint32_t hcsplt;
+	/** Host Channel 0 Interrupt Register. <i>Offset: 500h + (chan_num * 20h) + 08h</i> */
+	volatile uint32_t hcint;
+	/** Host Channel 0 Interrupt Mask Register. <i>Offset: 500h + (chan_num * 20h) + 0Ch</i> */
+	volatile uint32_t hcintmsk;
+	/** Host Channel 0 Transfer Size Register. <i>Offset: 500h + (chan_num * 20h) + 10h</i> */
+	volatile uint32_t hctsiz;
+	/** Host Channel 0 DMA Address Register. <i>Offset: 500h + (chan_num * 20h) + 14h</i> */
+	volatile uint32_t hcdma;
+	volatile uint32_t reserved;
+	/** Host Channel 0 DMA Buffer Address Register. <i>Offset: 500h + (chan_num * 20h) + 1Ch</i> */
+	volatile uint32_t hcdmab;
+} dwc_otg_hc_regs_t;
+
+/**
+ * This union represents the bit fields in the Host Channel Characteristics
+ * Register. Read the register into the <i>d32</i> member then set/clear the
+ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
+ * hcchar register.
+ */
+typedef union hcchar_data {
+	/** raw register data */
+	uint32_t d32;
+
+	/** register bits */
+	struct {
+		/** Maximum packet size in bytes */
+		unsigned mps:11;
+
+		/** Endpoint number */
+		unsigned epnum:4;
+
+		/** 0: OUT, 1: IN */
+		unsigned epdir:1;
+
+		unsigned reserved:1;
+
+		/** 0: Full/high speed device, 1: Low speed device */
+		unsigned lspddev:1;
+
+		/** 0: Control, 1: Isoc, 2: Bulk, 3: Intr */
+		unsigned eptype:2;
+
+		/** Packets per frame for periodic transfers. 0 is reserved. */
+		unsigned multicnt:2;
+
+		/** Device address */
+		unsigned devaddr:7;
+
+		/**
+		 * Frame to transmit periodic transaction.
+		 * 0: even, 1: odd
+		 */
+		unsigned oddfrm:1;
+
+		/** Channel disable */
+		unsigned chdis:1;
+
+		/** Channel enable */
+		unsigned chen:1;
+	} b;
+} hcchar_data_t;
+
+typedef union hcsplt_data {
+	/** raw register data */
+	uint32_t d32;
+
+	/** register bits */
+	struct {
+		/** Port Address */
+		unsigned prtaddr:7;
+
+		/** Hub Address */
+		unsigned hubaddr:7;
+
+		/** Transaction Position */
+		unsigned xactpos:2;
+#define DWC_HCSPLIT_XACTPOS_MID 0
+#define DWC_HCSPLIT_XACTPOS_END 1
+#define DWC_HCSPLIT_XACTPOS_BEGIN 2
+#define DWC_HCSPLIT_XACTPOS_ALL 3
+
+		/** Do Complete Split */
+		unsigned compsplt:1;
+
+		/** Reserved */
+		unsigned reserved:14;
+
+		/** Split Enble */
+		unsigned spltena:1;
+	} b;
+} hcsplt_data_t;
+
+/**
+ * This union represents the bit fields in the Host All Interrupt
+ * Register. 
+ */
+typedef union hcint_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		/** Transfer Complete */
+		unsigned xfercomp:1;
+		/** Channel Halted */
+		unsigned chhltd:1;
+		/** AHB Error */
+		unsigned ahberr:1;
+		/** STALL Response Received */
+		unsigned stall:1;
+		/** NAK Response Received */
+		unsigned nak:1;
+		/** ACK Response Received */
+		unsigned ack:1;
+		/** NYET Response Received */
+		unsigned nyet:1;
+		/** Transaction Err */
+		unsigned xacterr:1;
+		/** Babble Error */
+		unsigned bblerr:1;
+		/** Frame Overrun */
+		unsigned frmovrun:1;
+		/** Data Toggle Error */
+		unsigned datatglerr:1;
+		/** Buffer Not Available (only for DDMA mode) */
+		unsigned bna:1;
+		/** Exessive transaction error (only for DDMA mode) */
+		unsigned xcs_xact:1;
+		/** Frame List Rollover interrupt */
+		unsigned frm_list_roll:1;
+		/** Reserved */
+		unsigned reserved14_31:18;
+	} b;
+} hcint_data_t;
+
+/**
+ * This union represents the bit fields in the Host Channel Interrupt Mask
+ * Register. Read the register into the <i>d32</i> member then set/clear the
+ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
+ * hcintmsk register.
+ */
+typedef union hcintmsk_data {
+	/** raw register data */
+	uint32_t d32;
+
+	/** register bits */
+	struct {
+		unsigned xfercompl:1;
+		unsigned chhltd:1;
+		unsigned ahberr:1;
+		unsigned stall:1;
+		unsigned nak:1;
+		unsigned ack:1;
+		unsigned nyet:1;
+		unsigned xacterr:1;
+		unsigned bblerr:1;
+		unsigned frmovrun:1;
+		unsigned datatglerr:1;
+		unsigned bna:1;
+		unsigned xcs_xact:1;
+		unsigned frm_list_roll:1;
+		unsigned reserved14_31:18;
+	} b;
+} hcintmsk_data_t;
+
+/**
+ * This union represents the bit fields in the Host Channel Transfer Size
+ * Register. Read the register into the <i>d32</i> member then set/clear the
+ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
+ * hcchar register.
+ */
+
+typedef union hctsiz_data {
+	/** raw register data */
+	uint32_t d32;
+
+	/** register bits */
+	struct {
+		/** Total transfer size in bytes */
+		unsigned xfersize:19;
+
+		/** Data packets to transfer */
+		unsigned pktcnt:10;
+
+		/**
+		 * Packet ID for next data packet
+		 * 0: DATA0
+		 * 1: DATA2
+		 * 2: DATA1
+		 * 3: MDATA (non-Control), SETUP (Control)
+		 */
+		unsigned pid:2;
+#define DWC_HCTSIZ_DATA0 0
+#define DWC_HCTSIZ_DATA1 2
+#define DWC_HCTSIZ_DATA2 1
+#define DWC_HCTSIZ_MDATA 3
+#define DWC_HCTSIZ_SETUP 3
+
+		/** Do PING protocol when 1 */
+		unsigned dopng:1;
+	} b;
+
+	/** register bits */
+	struct {
+		/** Scheduling information */
+		unsigned schinfo:8;
+
+		/** Number of transfer descriptors.
+		 * Max value:
+		 * 64 in general,
+		 * 256 only for HS isochronous endpoint.
+		 */
+		unsigned ntd:8;
+
+		/** Data packets to transfer */
+		unsigned reserved16_28:13;
+
+		/**
+		 * Packet ID for next data packet
+		 * 0: DATA0
+		 * 1: DATA2
+		 * 2: DATA1
+		 * 3: MDATA (non-Control)
+		 */
+		unsigned pid:2;
+
+		/** Do PING protocol when 1 */
+		unsigned dopng:1;
+	} b_ddma;
+} hctsiz_data_t;
+
+/**
+ * This union represents the bit fields in the Host DMA Address 
+ * Register used in Descriptor DMA mode.
+ */
+typedef union hcdma_data {
+	/** raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		unsigned reserved0_2:3;
+		/** Current Transfer Descriptor. Not used for ISOC */
+		unsigned ctd:8;
+		/** Start Address of Descriptor List */
+		unsigned dma_addr:21;
+	} b;
+} hcdma_data_t;
+
+/**
+ * This union represents the bit fields in the DMA Descriptor
+ * status quadlet for host mode. Read the quadlet into the <i>d32</i> member then
+ * set/clear the bits using the <i>b</i>it elements.
+ */
+typedef union host_dma_desc_sts {
+	/** raw register data */
+	uint32_t d32;
+	/** quadlet bits */
+
+	/* for non-isochronous  */
+	struct {
+		/** Number of bytes */
+		unsigned n_bytes:17;
+		/** QTD offset to jump when Short Packet received - only for IN EPs */
+		unsigned qtd_offset:6;
+		/**
+		 * Set to request the core to jump to alternate QTD if
+		 * Short Packet received - only for IN EPs
+		 */
+		unsigned a_qtd:1;
+		 /**
+		  * Setup Packet bit. When set indicates that buffer contains
+		  * setup packet.
+		  */
+		unsigned sup:1;
+		/** Interrupt On Complete */
+		unsigned ioc:1;
+		/** End of List */
+		unsigned eol:1;
+		unsigned reserved27:1;
+		/** Rx/Tx Status */
+		unsigned sts:2;
+#define DMA_DESC_STS_PKTERR	1
+		unsigned reserved30:1;
+		/** Active Bit */
+		unsigned a:1;
+	} b;
+	/* for isochronous */
+	struct {
+		/** Number of bytes */
+		unsigned n_bytes:12;
+		unsigned reserved12_24:13;
+		/** Interrupt On Complete */
+		unsigned ioc:1;
+		unsigned reserved26_27:2;
+		/** Rx/Tx Status */
+		unsigned sts:2;
+		unsigned reserved30:1;
+		/** Active Bit */
+		unsigned a:1;
+	} b_isoc;
+} host_dma_desc_sts_t;
+
+#define	MAX_DMA_DESC_SIZE		131071
+#define MAX_DMA_DESC_NUM_GENERIC	64
+#define MAX_DMA_DESC_NUM_HS_ISOC	256
+#define MAX_FRLIST_EN_NUM		64
+/**
+ * Host-mode DMA Descriptor structure
+ *
+ * DMA Descriptor structure contains two quadlets:
+ * Status quadlet and Data buffer pointer.
+ */
+typedef struct dwc_otg_host_dma_desc {
+	/** DMA Descriptor status quadlet */
+	host_dma_desc_sts_t status;
+	/** DMA Descriptor data buffer pointer */
+	uint32_t buf;
+} dwc_otg_host_dma_desc_t;
+
+/** OTG Host Interface Structure.
+ *
+ * The OTG Host Interface Structure structure contains information
+ * needed to manage the DWC_otg controller acting in host mode. It
+ * represents the programming view of the host-specific aspects of the
+ * controller.
+ */
+typedef struct dwc_otg_host_if {
+	/** Host Global Registers starting at offset 400h.*/
+	dwc_otg_host_global_regs_t *host_global_regs;
+#define DWC_OTG_HOST_GLOBAL_REG_OFFSET 0x400
+
+	/** Host Port 0 Control and Status Register */
+	volatile uint32_t *hprt0;
+#define DWC_OTG_HOST_PORT_REGS_OFFSET 0x440
+
+	/** Host Channel Specific Registers at offsets 500h-5FCh. */
+	dwc_otg_hc_regs_t *hc_regs[MAX_EPS_CHANNELS];
+#define DWC_OTG_HOST_CHAN_REGS_OFFSET 0x500
+#define DWC_OTG_CHAN_REGS_OFFSET 0x20
+
+	/* Host configuration information */
+	/** Number of Host Channels (range: 1-16) */
+	uint8_t num_host_channels;
+	/** Periodic EPs supported (0: no, 1: yes) */
+	uint8_t perio_eps_supported;
+	/** Periodic Tx FIFO Size (Only 1 host periodic Tx FIFO) */
+	uint16_t perio_tx_fifo_size;
+
+} dwc_otg_host_if_t;
+
+/**
+ * This union represents the bit fields in the Power and Clock Gating Control
+ * Register. Read the register into the <i>d32</i> member then set/clear the
+ * bits using the <i>b</i>it elements.
+ */
+typedef union pcgcctl_data {
+	/** raw register data */
+	uint32_t d32;
+
+	/** register bits */
+	struct {
+		/** Stop Pclk */
+		unsigned stoppclk:1;
+		/** Gate Hclk */
+		unsigned gatehclk:1;
+		/** Power Clamp */
+		unsigned pwrclmp:1;
+		/** Reset Power Down Modules */
+		unsigned rstpdwnmodule:1;
+		/** Reserved */
+		unsigned reserved:1;
+		/** Enable Sleep Clock Gating (Enbl_L1Gating) */
+		unsigned enbl_sleep_gating:1;
+		/** PHY In Sleep (PhySleep) */
+		unsigned phy_in_sleep:1;
+		/** Deep Sleep*/
+		unsigned deep_sleep:1;
+		unsigned resetaftsusp:1;
+		unsigned restoremode:1;
+		unsigned reserved10_12:3;
+		unsigned ess_reg_restored:1;
+		unsigned prt_clk_sel:2;
+		unsigned port_power:1;
+		unsigned max_xcvrselect:2;
+		unsigned max_termsel:1;
+		unsigned mac_dev_addr:7;
+		unsigned p2hd_dev_enum_spd:2;
+		unsigned p2hd_prt_spd:2;
+		unsigned if_dev_mode:1;
+	} b;
+} pcgcctl_data_t;
+
+/**
+ * This union represents the bit fields in the Global Data FIFO Software
+ * Configuration Register. Read the register into the <i>d32</i> member then
+ * set/clear the bits using the <i>b</i>it elements.
+ */
+typedef union gdfifocfg_data {
+	/* raw register data */
+	uint32_t d32;
+	/** register bits */
+	struct {
+		/** OTG Data FIFO depth */
+		unsigned gdfifocfg:16;
+		/** Start address of EP info controller */
+		unsigned epinfobase:16;
+	} b;
+} gdfifocfg_data_t;
+
+/**
+ * This union represents the bit fields in the Global Power Down Register
+ * Register. Read the register into the <i>d32</i> member then set/clear the
+ * bits using the <i>b</i>it elements.
+ */
+typedef union gpwrdn_data {
+	/* raw register data */
+	uint32_t d32;
+
+	/** register bits */
+	struct {
+		/** PMU Interrupt Select */
+		unsigned pmuintsel:1;
+		/** PMU Active */
+		unsigned pmuactv:1;
+		/** Restore */
+		unsigned restore:1;
+		/** Power Down Clamp */
+		unsigned pwrdnclmp:1;
+		/** Power Down Reset */
+		unsigned pwrdnrstn:1;
+		/** Power Down Switch */
+		unsigned pwrdnswtch:1;
+		/** Disable VBUS */
+		unsigned dis_vbus:1;
+		/** Line State Change */
+		unsigned lnstschng:1;
+		/** Line state change mask */
+		unsigned lnstchng_msk:1;
+		/** Reset Detected */
+		unsigned rst_det:1;
+		/** Reset Detect mask */
+		unsigned rst_det_msk:1;
+		/** Disconnect Detected */
+		unsigned disconn_det:1;
+		/** Disconnect Detect mask */
+		unsigned disconn_det_msk:1;
+		/** Connect Detected*/
+		unsigned connect_det:1;
+		/** Connect Detected Mask*/
+		unsigned connect_det_msk:1;
+		/** SRP Detected */
+		unsigned srp_det:1;
+		/** SRP Detect mask */
+		unsigned srp_det_msk:1;
+		/** Status Change Interrupt */
+		unsigned sts_chngint:1;
+		/** Status Change Interrupt Mask */
+		unsigned sts_chngint_msk:1;
+		/** Line State */
+		unsigned linestate:2;
+		/** Indicates current mode(status of IDDIG signal) */
+		unsigned idsts:1;
+		/** B Session Valid signal status*/
+		unsigned bsessvld:1;
+		/** ADP Event Detected */
+		unsigned adp_int:1;
+		/** Multi Valued ID pin */
+		unsigned mult_val_id_bc:5;
+		/** Reserved 24_31 */
+		unsigned reserved29_31:3;
+	} b;
+} gpwrdn_data_t;
+
+#endif
diff --git a/drivers/usb/dwc_otg/linux/dwc_otg_plat.h b/drivers/usb/dwc_otg/linux/dwc_otg_plat.h
new file mode 100644
index 0000000..36e1846
--- /dev/null
+++ b/drivers/usb/dwc_otg/linux/dwc_otg_plat.h
@@ -0,0 +1,268 @@
+/* ==========================================================================
+ * $File: //dwh/usb_iip/dev/software/otg/linux/platform/dwc_otg_plat.h $
+ * $Revision: 1.2 $
+ * $Date: 2008-11-21 05:39:16 $
+ * $Change: 1064915 $
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+#if !defined(__DWC_OTG_PLAT_H__)
+#define __DWC_OTG_PLAT_H__
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+
+/**
+ * @file
+ *
+ * This file contains the Platform Specific constants, interfaces
+ * (functions and macros) for Linux.
+ *
+ */
+//#if !defined(__LINUX_ARM_ARCH__)
+//#error "The contents of this file is Linux specific!!!"
+//#endif
+
+/**
+ * Reads the content of a register.
+ *
+ * @param reg address of register to read.
+ * @return contents of the register.
+ *
+
+ * Usage:<br>
+ * <code>uint32_t dev_ctl = dwc_read_reg32(&dev_regs->dctl);</code>
+ */
+static __inline__ uint32_t dwc_read_reg32( volatile uint32_t *reg)
+{
+        return readl(reg);
+};
+
+/**
+ * Writes a register with a 32 bit value.
+ *
+ * @param reg address of register to read.
+ * @param value to write to _reg.
+ *
+ * Usage:<br>
+ * <code>dwc_write_reg32(&dev_regs->dctl, 0); </code>
+ */
+static __inline__ void dwc_write_reg32( volatile uint32_t *reg, const uint32_t value)
+{
+        writel( value, reg );
+};
+
+/**
+ * This function modifies bit values in a register.  Using the
+ * algorithm: (reg_contents & ~clear_mask) | set_mask.
+ *
+ * @param reg address of register to read.
+ * @param clear_mask bit mask to be cleared.
+ * @param set_mask bit mask to be set.
+ *
+ * Usage:<br>
+ * <code> // Clear the SOF Interrupt Mask bit and <br>
+ * // set the OTG Interrupt mask bit, leaving all others as they were.
+ *    dwc_modify_reg32(&dev_regs->gintmsk, DWC_SOF_INT, DWC_OTG_INT);</code>
+ */
+static __inline__
+ void dwc_modify_reg32( volatile uint32_t *reg, const uint32_t clear_mask, const uint32_t set_mask)
+{
+        writel( (readl(reg) & ~clear_mask) | set_mask, reg );
+};
+
+
+/**
+ * Wrapper for the OS micro-second delay function.
+ * @param[in] usecs Microseconds of delay
+ */
+static __inline__ void UDELAY( const uint32_t usecs )
+{
+        udelay( usecs );
+}
+
+/**
+ * Wrapper for the OS milli-second delay function.
+ * @param[in] msecs milliseconds of delay
+ */
+static __inline__ void MDELAY( const uint32_t msecs )
+{
+        mdelay( msecs );
+}
+
+/**
+ * Wrapper for the Linux spin_lock.  On the ARM (Integrator)
+ * spin_lock() is a nop.
+ *
+ * @param lock Pointer to the spinlock.
+ */
+static __inline__ void SPIN_LOCK( spinlock_t *lock )
+{
+        spin_lock(lock);
+}
+
+/**
+ * Wrapper for the Linux spin_unlock.  On the ARM (Integrator)
+ * spin_lock() is a nop.
+ *
+ * @param lock Pointer to the spinlock.
+ */
+static __inline__ void SPIN_UNLOCK( spinlock_t *lock )
+{
+        spin_unlock(lock);
+}
+
+/**
+ * Wrapper (macro) for the Linux spin_lock_irqsave.  On the ARM
+ * (Integrator) spin_lock() is a nop.
+ *
+ * @param l Pointer to the spinlock.
+ * @param f unsigned long for irq flags storage.
+ */
+#define SPIN_LOCK_IRQSAVE( l, f )  spin_lock_irqsave(l,f);
+//#define SPIN_LOCK_IRQSAVE( l, f )  local_irq_save (f);
+
+/**
+ * Wrapper (macro) for the Linux spin_unlock_irqrestore.  On the ARM
+ * (Integrator) spin_lock() is a nop.
+ *
+ * @param l Pointer to the spinlock.
+ * @param f unsigned long for irq flags storage.
+ */
+#define SPIN_UNLOCK_IRQRESTORE( l,f ) spin_unlock_irqrestore(l,f);
+//#define SPIN_UNLOCK_IRQRESTORE( l,f ) local_irq_restore (f);
+
+/*
+ * Debugging support vanishes in non-debug builds.
+ */
+
+
+/**
+ * The Debug Level bit-mask variable.
+ */
+extern uint32_t g_dbg_lvl;
+/**
+ * Set the Debug Level variable.
+ */
+static inline uint32_t SET_DEBUG_LEVEL( const uint32_t new )
+{
+        uint32_t old = g_dbg_lvl;
+        g_dbg_lvl = new;
+        return old;
+}
+
+/** When debug level has the DBG_CIL bit set, display CIL Debug messages. */
+#define DBG_CIL		(0x2)
+/** When debug level has the DBG_CILV bit set, display CIL Verbose debug
+ * messages */
+#define DBG_CILV	(0x20)
+/**  When debug level has the DBG_PCD bit set, display PCD (Device) debug
+ *  messages */
+#define DBG_PCD		(0x4)
+/** When debug level has the DBG_PCDV set, display PCD (Device) Verbose debug
+ * messages */
+#define DBG_PCDV	(0x40)
+/** When debug level has the DBG_HCD bit set, display Host debug messages */
+#define DBG_HCD		(0x8)
+/** When debug level has the DBG_HCDV bit set, display Verbose Host debug
+ * messages */
+#define DBG_HCDV	(0x80)
+/** When debug level has the DBG_HCD_URB bit set, display enqueued URBs in host
+ *  mode. */
+#define DBG_HCD_URB	(0x800)
+
+/** When debug level has any bit set, display debug messages */
+#define DBG_ANY		(0xFF)
+
+/** All debug messages off */
+#define DBG_OFF		0
+
+/** Prefix string for DWC_DEBUG print macros. */
+#define USB_DWC "dwc_otg: "
+
+/**
+ * Print a debug message when the Global debug level variable contains
+ * the bit defined in <code>lvl</code>.
+ *
+ * @param[in] lvl - Debug level, use one of the DBG_ constants above.
+ * @param[in] x - like printf
+ *
+ *    Example:<p>
+ * <code>
+ *      DWC_DEBUGPL( DBG_ANY, "%s(%p)\n", __func__, _reg_base_addr);
+ * </code>
+ * <br>
+ * results in:<br>
+ * <code>
+ * usb-DWC_otg: dwc_otg_cil_init(ca867000)
+ * </code>
+ */
+#ifdef DEBUG
+
+# define DWC_DEBUGPL(lvl, x...) do{ if ((lvl)&g_dbg_lvl)printk( KERN_DEBUG USB_DWC x ); }while(0)
+//# define DWC_DEBUGPL(lvl, x...) printk(x)
+
+# define DWC_DEBUGP(x...)	DWC_DEBUGPL(DBG_ANY, x )
+
+# define CHK_DEBUG_LEVEL(level) ((level) & g_dbg_lvl)
+//# define CHK_DEBUG_LEVEL(level) 1
+
+#else
+
+# define DWC_DEBUGPL(lvl, x...) do{}while(0)
+# define DWC_DEBUGP(x...)
+
+# define CHK_DEBUG_LEVEL(level) (0)
+
+#endif /*DEBUG*/
+
+/**
+ * Print an Error message.
+ */
+#define DWC_ERROR(x...) printk( KERN_ERR USB_DWC x )
+//#define DWC_ERROR(x...) printk( x )
+
+/**
+ * Print a Warning message.
+ */
+#define DWC_WARN(x...) printk( KERN_WARNING USB_DWC x )
+/**
+ * Print a notice (normal but significant message).
+ */
+#define DWC_NOTICE(x...) printk( KERN_NOTICE USB_DWC x )
+/**
+ *  Basic message printing.
+ */
+#define DWC_PRINT(x...) printk( KERN_INFO USB_DWC x )
+
+#endif
+
diff --git a/drivers/usb/dwc_otg/usb.h b/drivers/usb/dwc_otg/usb.h
new file mode 100644
index 0000000..27bda82
--- /dev/null
+++ b/drivers/usb/dwc_otg/usb.h
@@ -0,0 +1,946 @@
+/*
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (lennart@augustsson.net) at
+ * Carlstedt Research & Technology.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Modified by Synopsys, Inc, 12/12/2007 */
+
+
+#ifndef _USB_H_
+#define _USB_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The USB records contain some unaligned little-endian word
+ * components.  The U[SG]ETW macros take care of both the alignment
+ * and endian problem and should always be used to access non-byte
+ * values.
+ */
+typedef u_int8_t uByte;
+typedef u_int8_t uWord[2];
+typedef u_int8_t uDWord[4];
+
+#define USETW2(w,h,l) ((w)[0] = (u_int8_t)(l), (w)[1] = (u_int8_t)(h))
+#define UCONSTW(x)	{ (x) & 0xff, ((x) >> 8) & 0xff }
+#define UCONSTDW(x)	{ (x) & 0xff, ((x) >> 8) & 0xff, \
+			  ((x) >> 16) & 0xff, ((x) >> 24) & 0xff }
+
+#if 1
+#define UGETW(w) ((w)[0] | ((w)[1] << 8))
+#define USETW(w,v) ((w)[0] = (u_int8_t)(v), (w)[1] = (u_int8_t)((v) >> 8))
+#define UGETDW(w) ((w)[0] | ((w)[1] << 8) | ((w)[2] << 16) | ((w)[3] << 24))
+#define USETDW(w,v) ((w)[0] = (u_int8_t)(v), \
+		     (w)[1] = (u_int8_t)((v) >> 8), \
+		     (w)[2] = (u_int8_t)((v) >> 16), \
+		     (w)[3] = (u_int8_t)((v) >> 24))
+#else
+/*
+ * On little-endian machines that can handle unanliged accesses
+ * (e.g. i386) these macros can be replaced by the following.
+ */
+#define UGETW(w) (*(u_int16_t *)(w))
+#define USETW(w,v) (*(u_int16_t *)(w) = (v))
+#define UGETDW(w) (*(u_int32_t *)(w))
+#define USETDW(w,v) (*(u_int32_t *)(w) = (v))
+#endif
+
+/*
+ * Macros for accessing UAS IU fields, which are big-endian
+ */
+#define IUSETW2(w,h,l) ((w)[0] = (u_int8_t)(h), (w)[1] = (u_int8_t)(l))
+#define IUCONSTW(x)	{ ((x) >> 8) & 0xff, (x) & 0xff }
+#define IUCONSTDW(x)	{ ((x) >> 24) & 0xff, ((x) >> 16) & 0xff, \
+			((x) >> 8) & 0xff, (x) & 0xff }
+#define IUGETW(w) (((w)[0] << 8) | (w)[1])
+#define IUSETW(w,v) ((w)[0] = (u_int8_t)((v) >> 8), (w)[1] = (u_int8_t)(v))
+#define IUGETDW(w) (((w)[0] << 24) | ((w)[1] << 16) | ((w)[2] << 8) | (w)[3])
+#define IUSETDW(w,v) ((w)[0] = (u_int8_t)((v) >> 24), \
+		      (w)[1] = (u_int8_t)((v) >> 16), \
+		      (w)[2] = (u_int8_t)((v) >> 8), \
+		      (w)[3] = (u_int8_t)(v))
+
+#define UPACKED __attribute__((__packed__))
+
+typedef struct {
+	uByte		bmRequestType;
+	uByte		bRequest;
+	uWord		wValue;
+	uWord		wIndex;
+	uWord		wLength;
+} UPACKED usb_device_request_t;
+
+#define UT_GET_DIR(a) ((a) & 0x80)
+#define UT_WRITE		0x00
+#define UT_READ			0x80
+
+#define UT_GET_TYPE(a) ((a) & 0x60)
+#define UT_STANDARD		0x00
+#define UT_CLASS		0x20
+#define UT_VENDOR		0x40
+
+#define UT_GET_RECIPIENT(a) ((a) & 0x1f)
+#define UT_DEVICE		0x00
+#define UT_INTERFACE		0x01
+#define UT_ENDPOINT		0x02
+#define UT_OTHER		0x03
+
+#define UT_READ_DEVICE		(UT_READ  | UT_STANDARD | UT_DEVICE)
+#define UT_READ_INTERFACE	(UT_READ  | UT_STANDARD | UT_INTERFACE)
+#define UT_READ_ENDPOINT	(UT_READ  | UT_STANDARD | UT_ENDPOINT)
+#define UT_WRITE_DEVICE		(UT_WRITE | UT_STANDARD | UT_DEVICE)
+#define UT_WRITE_INTERFACE	(UT_WRITE | UT_STANDARD | UT_INTERFACE)
+#define UT_WRITE_ENDPOINT	(UT_WRITE | UT_STANDARD | UT_ENDPOINT)
+#define UT_READ_CLASS_DEVICE	(UT_READ  | UT_CLASS | UT_DEVICE)
+#define UT_READ_CLASS_INTERFACE	(UT_READ  | UT_CLASS | UT_INTERFACE)
+#define UT_READ_CLASS_OTHER	(UT_READ  | UT_CLASS | UT_OTHER)
+#define UT_READ_CLASS_ENDPOINT	(UT_READ  | UT_CLASS | UT_ENDPOINT)
+#define UT_WRITE_CLASS_DEVICE	(UT_WRITE | UT_CLASS | UT_DEVICE)
+#define UT_WRITE_CLASS_INTERFACE (UT_WRITE | UT_CLASS | UT_INTERFACE)
+#define UT_WRITE_CLASS_OTHER	(UT_WRITE | UT_CLASS | UT_OTHER)
+#define UT_WRITE_CLASS_ENDPOINT	(UT_WRITE | UT_CLASS | UT_ENDPOINT)
+#define UT_READ_VENDOR_DEVICE	(UT_READ  | UT_VENDOR | UT_DEVICE)
+#define UT_READ_VENDOR_INTERFACE (UT_READ  | UT_VENDOR | UT_INTERFACE)
+#define UT_READ_VENDOR_OTHER	(UT_READ  | UT_VENDOR | UT_OTHER)
+#define UT_READ_VENDOR_ENDPOINT	(UT_READ  | UT_VENDOR | UT_ENDPOINT)
+#define UT_WRITE_VENDOR_DEVICE	(UT_WRITE | UT_VENDOR | UT_DEVICE)
+#define UT_WRITE_VENDOR_INTERFACE (UT_WRITE | UT_VENDOR | UT_INTERFACE)
+#define UT_WRITE_VENDOR_OTHER	(UT_WRITE | UT_VENDOR | UT_OTHER)
+#define UT_WRITE_VENDOR_ENDPOINT (UT_WRITE | UT_VENDOR | UT_ENDPOINT)
+
+/* Requests */
+#define UR_GET_STATUS		0x00
+#define  USTAT_STANDARD_STATUS  0x00
+#define  WUSTAT_WUSB_FEATURE    0x01
+#define  WUSTAT_CHANNEL_INFO    0x02
+#define  WUSTAT_RECEIVED_DATA   0x03
+#define  WUSTAT_MAS_AVAILABILITY 0x04
+#define  WUSTAT_CURRENT_TRANSMIT_POWER 0x05
+#define UR_CLEAR_FEATURE	0x01
+#define UR_SET_FEATURE		0x03
+#define UR_SET_AND_TEST_FEATURE 0x0c
+#define UR_SET_ADDRESS		0x05
+#define UR_GET_DESCRIPTOR	0x06
+#define  UDESC_DEVICE		0x01
+#define  UDESC_CONFIG		0x02
+#define  UDESC_STRING		0x03
+#define  UDESC_INTERFACE	0x04
+#define  UDESC_ENDPOINT		0x05
+#define  UDESC_SS_USB_COMPANION	0x30
+#define  UDESC_DEVICE_QUALIFIER	0x06
+#define  UDESC_OTHER_SPEED_CONFIGURATION 0x07
+#define  UDESC_INTERFACE_POWER	0x08
+#define  UDESC_OTG		0x09
+#define  WUDESC_SECURITY	0x0c
+#define  WUDESC_KEY		0x0d
+#define   WUD_GET_KEY_INDEX(_wValue_) ((_wValue_) & 0xf)
+#define   WUD_GET_KEY_TYPE(_wValue_) (((_wValue_) & 0x30) >> 4)
+#define    WUD_KEY_TYPE_ASSOC    0x01
+#define    WUD_KEY_TYPE_GTK      0x02
+#define   WUD_GET_KEY_ORIGIN(_wValue_) (((_wValue_) & 0x40) >> 6)
+#define    WUD_KEY_ORIGIN_HOST   0x00
+#define    WUD_KEY_ORIGIN_DEVICE 0x01
+#define  WUDESC_ENCRYPTION_TYPE	0x0e
+#define  WUDESC_BOS		0x0f
+#define  WUDESC_DEVICE_CAPABILITY 0x10
+#define  WUDESC_WIRELESS_ENDPOINT_COMPANION 0x11
+#define  UDESC_BOS		0x0f
+#define  UDESC_DEVICE_CAPABILITY 0x10
+#define  UDESC_CS_DEVICE	0x21	/* class specific */
+#define  UDESC_CS_CONFIG	0x22
+#define  UDESC_CS_STRING	0x23
+#define  UDESC_CS_INTERFACE	0x24
+#define  UDESC_CS_ENDPOINT	0x25
+#define  UDESC_HUB		0x29
+#define UR_SET_DESCRIPTOR	0x07
+#define UR_GET_CONFIG		0x08
+#define UR_SET_CONFIG		0x09
+#define UR_GET_INTERFACE	0x0a
+#define UR_SET_INTERFACE	0x0b
+#define UR_SYNCH_FRAME		0x0c
+#define WUR_SET_ENCRYPTION      0x0d
+#define WUR_GET_ENCRYPTION	0x0e
+#define WUR_SET_HANDSHAKE	0x0f
+#define WUR_GET_HANDSHAKE	0x10
+#define WUR_SET_CONNECTION	0x11
+#define WUR_SET_SECURITY_DATA	0x12
+#define WUR_GET_SECURITY_DATA	0x13
+#define WUR_SET_WUSB_DATA	0x14
+#define  WUDATA_DRPIE_INFO	0x01
+#define  WUDATA_TRANSMIT_DATA	0x02
+#define  WUDATA_TRANSMIT_PARAMS	0x03
+#define  WUDATA_RECEIVE_PARAMS	0x04
+#define  WUDATA_TRANSMIT_POWER	0x05
+#define WUR_LOOPBACK_DATA_WRITE	0x15
+#define WUR_LOOPBACK_DATA_READ	0x16
+#define WUR_SET_INTERFACE_DS	0x17
+
+/* Feature numbers */
+#define UF_ENDPOINT_HALT	0
+#define UF_DEVICE_REMOTE_WAKEUP	1
+#define UF_TEST_MODE		2
+#define UF_DEVICE_B_HNP_ENABLE	3
+#define UF_DEVICE_A_HNP_SUPPORT	4
+#define UF_DEVICE_A_ALT_HNP_SUPPORT 5
+#define WUF_WUSB		3
+#define  WUF_TX_DRPIE		0x0
+#define  WUF_DEV_XMIT_PACKET	0x1
+#define  WUF_COUNT_PACKETS	0x2
+#define  WUF_CAPTURE_PACKETS	0x3
+#define UF_FUNCTION_SUSPEND	0
+#define UF_U1_ENABLE		48
+#define UF_U2_ENABLE		49
+#define UF_LTM_ENABLE		50
+
+/* Class requests from the USB 2.0 hub spec, table 11-15 */
+#define UCR_CLEAR_HUB_FEATURE		(0x2000 | UR_CLEAR_FEATURE)
+#define UCR_CLEAR_PORT_FEATURE		(0x2300 | UR_CLEAR_FEATURE)
+#define UCR_GET_HUB_DESCRIPTOR		(0xa000 | UR_GET_DESCRIPTOR)
+#define UCR_GET_HUB_STATUS		(0xa000 | UR_GET_STATUS)
+#define UCR_GET_PORT_STATUS		(0xa300 | UR_GET_STATUS)
+#define UCR_SET_HUB_FEATURE		(0x2000 | UR_SET_FEATURE)
+#define UCR_SET_PORT_FEATURE		(0x2300 | UR_SET_FEATURE)
+#define UCR_SET_AND_TEST_PORT_FEATURE	(0xa300 | UR_SET_AND_TEST_FEATURE)
+
+#ifdef _MSC_VER
+#include <pshpack1.h>
+#endif
+
+typedef struct {
+	uByte		bLength;
+	uByte		bDescriptorType;
+	uByte		bDescriptorSubtype;
+} UPACKED usb_descriptor_t;
+
+typedef struct {
+	uByte		bLength;
+	uByte		bDescriptorType;
+} UPACKED usb_descriptor_header_t;
+
+typedef struct {
+	uByte		bLength;
+	uByte		bDescriptorType;
+	uWord		bcdUSB;
+#define UD_USB_2_0		0x0200
+#define UD_IS_USB2(d) (UGETW((d)->bcdUSB) >= UD_USB_2_0)
+	uByte		bDeviceClass;
+	uByte		bDeviceSubClass;
+	uByte		bDeviceProtocol;
+	uByte		bMaxPacketSize;
+	/* The fields below are not part of the initial descriptor. */
+	uWord		idVendor;
+	uWord		idProduct;
+	uWord		bcdDevice;
+	uByte		iManufacturer;
+	uByte		iProduct;
+	uByte		iSerialNumber;
+	uByte		bNumConfigurations;
+} UPACKED usb_device_descriptor_t;
+#define USB_DEVICE_DESCRIPTOR_SIZE 18
+
+typedef struct {
+	uByte		bLength;
+	uByte		bDescriptorType;
+	uWord		wTotalLength;
+	uByte		bNumInterface;
+	uByte		bConfigurationValue;
+	uByte		iConfiguration;
+#define UC_ATT_ONE		(1 << 7)	/* must be set */
+#define UC_ATT_SELFPOWER	(1 << 6)	/* self powered */
+#define UC_ATT_WAKEUP		(1 << 5)	/* can wakeup */
+#define UC_ATT_BATTERY		(1 << 4)	/* battery powered */
+	uByte		bmAttributes;
+#define UC_BUS_POWERED		0x80
+#define UC_SELF_POWERED		0x40
+#define UC_REMOTE_WAKEUP	0x20
+	uByte		bMaxPower; /* max current in 2 mA units */
+#define UC_POWER_FACTOR 2
+} UPACKED usb_config_descriptor_t;
+#define USB_CONFIG_DESCRIPTOR_SIZE 9
+
+typedef struct {
+	uByte		bLength;
+	uByte		bDescriptorType;
+	uByte		bInterfaceNumber;
+	uByte		bAlternateSetting;
+	uByte		bNumEndpoints;
+	uByte		bInterfaceClass;
+	uByte		bInterfaceSubClass;
+	uByte		bInterfaceProtocol;
+	uByte		iInterface;
+} UPACKED usb_interface_descriptor_t;
+#define USB_INTERFACE_DESCRIPTOR_SIZE 9
+
+typedef struct {
+	uByte		bLength;
+	uByte		bDescriptorType;
+	uByte		bEndpointAddress;
+#define UE_GET_DIR(a)	((a) & 0x80)
+#define UE_SET_DIR(a,d)	((a) | (((d)&1) << 7))
+#define UE_DIR_IN	0x80
+#define UE_DIR_OUT	0x00
+#define UE_ADDR		0x0f
+#define UE_GET_ADDR(a)	((a) & UE_ADDR)
+	uByte		bmAttributes;
+#define UE_XFERTYPE	0x03
+#define  UE_CONTROL	0x00
+#define  UE_ISOCHRONOUS	0x01
+#define  UE_BULK	0x02
+#define  UE_INTERRUPT	0x03
+#define UE_GET_XFERTYPE(a)	((a) & UE_XFERTYPE)
+#define UE_ISO_TYPE	0x0c
+#define  UE_ISO_ASYNC	0x04
+#define  UE_ISO_ADAPT	0x08
+#define  UE_ISO_SYNC	0x0c
+#define UE_GET_ISO_TYPE(a)	((a) & UE_ISO_TYPE)
+	uWord		wMaxPacketSize;
+	uByte		bInterval;
+} UPACKED usb_endpoint_descriptor_t;
+#define USB_ENDPOINT_DESCRIPTOR_SIZE 7
+
+typedef struct ss_endpoint_companion_descriptor {
+	uByte bLength;
+	uByte bDescriptorType;
+	uByte bMaxBurst;
+#define USSE_GET_MAX_STREAMS(a)		((a) & 0x1f)
+#define USSE_SET_MAX_STREAMS(a, b)	((a) | ((b) & 0x1f))
+#define USSE_GET_MAX_PACKET_NUM(a)	((a) & 0x03)
+#define USSE_SET_MAX_PACKET_NUM(a, b)	((a) | ((b) & 0x03))
+	uByte bmAttributes;
+	uWord wBytesPerInterval;
+} UPACKED ss_endpoint_companion_descriptor_t;
+#define USB_SS_ENDPOINT_COMPANION_DESCRIPTOR_SIZE 6
+
+typedef struct {
+	uByte		bLength;
+	uByte		bDescriptorType;
+	uWord		bString[127];
+} UPACKED usb_string_descriptor_t;
+#define USB_MAX_STRING_LEN 128
+#define USB_LANGUAGE_TABLE 0	/* # of the string language id table */
+
+/* Hub specific request */
+#define UR_GET_BUS_STATE	0x02
+#define UR_CLEAR_TT_BUFFER	0x08
+#define UR_RESET_TT		0x09
+#define UR_GET_TT_STATE		0x0a
+#define UR_STOP_TT		0x0b
+
+/* Hub features */
+#define UHF_C_HUB_LOCAL_POWER	0
+#define UHF_C_HUB_OVER_CURRENT	1
+#define UHF_PORT_CONNECTION	0
+#define UHF_PORT_ENABLE		1
+#define UHF_PORT_SUSPEND	2
+#define UHF_PORT_OVER_CURRENT	3
+#define UHF_PORT_RESET		4
+#define UHF_PORT_L1		5
+#define UHF_PORT_POWER		8
+#define UHF_PORT_LOW_SPEED	9
+#define UHF_PORT_HIGH_SPEED	10
+#define UHF_C_PORT_CONNECTION	16
+#define UHF_C_PORT_ENABLE	17
+#define UHF_C_PORT_SUSPEND	18
+#define UHF_C_PORT_OVER_CURRENT	19
+#define UHF_C_PORT_RESET	20
+#define UHF_C_PORT_L1		23
+#define UHF_PORT_TEST		21
+#define UHF_PORT_INDICATOR	22
+
+typedef struct {
+	uByte		bDescLength;
+	uByte		bDescriptorType;
+	uByte		bNbrPorts;
+	uWord		wHubCharacteristics;
+#define UHD_PWR			0x0003
+#define  UHD_PWR_GANGED		0x0000
+#define  UHD_PWR_INDIVIDUAL	0x0001
+#define  UHD_PWR_NO_SWITCH	0x0002
+#define UHD_COMPOUND		0x0004
+#define UHD_OC			0x0018
+#define  UHD_OC_GLOBAL		0x0000
+#define  UHD_OC_INDIVIDUAL	0x0008
+#define  UHD_OC_NONE		0x0010
+#define UHD_TT_THINK		0x0060
+#define  UHD_TT_THINK_8		0x0000
+#define  UHD_TT_THINK_16	0x0020
+#define  UHD_TT_THINK_24	0x0040
+#define  UHD_TT_THINK_32	0x0060
+#define UHD_PORT_IND		0x0080
+	uByte		bPwrOn2PwrGood;	/* delay in 2 ms units */
+#define UHD_PWRON_FACTOR 2
+	uByte		bHubContrCurrent;
+	uByte		DeviceRemovable[32]; /* max 255 ports */
+#define UHD_NOT_REMOV(desc, i) \
+    (((desc)->DeviceRemovable[(i)/8] >> ((i) % 8)) & 1)
+	/* deprecated */ uByte		PortPowerCtrlMask[1];
+} UPACKED usb_hub_descriptor_t;
+#define USB_HUB_DESCRIPTOR_SIZE 9 /* includes deprecated PortPowerCtrlMask */
+
+typedef struct {
+	uByte		bLength;
+	uByte		bDescriptorType;
+	uWord		bcdUSB;
+	uByte		bDeviceClass;
+	uByte		bDeviceSubClass;
+	uByte		bDeviceProtocol;
+	uByte		bMaxPacketSize0;
+	uByte		bNumConfigurations;
+	uByte		bReserved;
+} UPACKED usb_device_qualifier_t;
+#define USB_DEVICE_QUALIFIER_SIZE 10
+
+typedef struct {
+	uByte		bLength;
+	uByte		bDescriptorType;
+	uByte		bmAttributes;
+#define UOTG_SRP	0x01
+#define UOTG_HNP	0x02
+} UPACKED usb_otg_descriptor_t;
+
+/* OTG feature selectors */
+#define UOTG_B_HNP_ENABLE	3
+#define UOTG_A_HNP_SUPPORT	4
+#define UOTG_A_ALT_HNP_SUPPORT	5
+
+typedef struct {
+	uWord		wStatus;
+/* Device status flags */
+#define UDS_SELF_POWERED		0x0001
+#define UDS_REMOTE_WAKEUP		0x0002
+/* Endpoint status flags */
+#define UES_HALT			0x0001
+} UPACKED usb_status_t;
+
+typedef struct {
+	uWord		wHubStatus;
+#define UHS_LOCAL_POWER			0x0001
+#define UHS_OVER_CURRENT		0x0002
+	uWord		wHubChange;
+} UPACKED usb_hub_status_t;
+
+typedef struct {
+	uWord		wPortStatus;
+#define UPS_CURRENT_CONNECT_STATUS	0x0001
+#define UPS_PORT_ENABLED		0x0002
+#define UPS_SUSPEND			0x0004
+#define UPS_OVERCURRENT_INDICATOR	0x0008
+#define UPS_RESET			0x0010
+#define UPS_PORT_POWER			0x0100
+#define UPS_LOW_SPEED			0x0200
+#define UPS_HIGH_SPEED			0x0400
+#define UPS_PORT_TEST			0x0800
+#define UPS_PORT_INDICATOR		0x1000
+	uWord		wPortChange;
+#define UPS_C_CONNECT_STATUS		0x0001
+#define UPS_C_PORT_ENABLED		0x0002
+#define UPS_C_SUSPEND			0x0004
+#define UPS_C_OVERCURRENT_INDICATOR	0x0008
+#define UPS_C_PORT_RESET		0x0010
+} UPACKED usb_port_status_t;
+
+#ifdef _MSC_VER
+#include <poppack.h>
+#endif
+
+/* Device class codes */
+#define UDCLASS_IN_INTERFACE	0x00
+#define UDCLASS_COMM		0x02
+#define UDCLASS_HUB		0x09
+#define  UDSUBCLASS_HUB		0x00
+#define  UDPROTO_FSHUB		0x00
+#define  UDPROTO_HSHUBSTT	0x01
+#define  UDPROTO_HSHUBMTT	0x02
+#define UDCLASS_DIAGNOSTIC	0xdc
+#define UDCLASS_WIRELESS	0xe0
+#define  UDSUBCLASS_RF		0x01
+#define   UDPROTO_BLUETOOTH	0x01
+#define UDCLASS_VENDOR		0xff
+
+/* Interface class codes */
+#define UICLASS_UNSPEC		0x00
+
+#define UICLASS_AUDIO		0x01
+#define  UISUBCLASS_AUDIOCONTROL	1
+#define  UISUBCLASS_AUDIOSTREAM		2
+#define  UISUBCLASS_MIDISTREAM		3
+
+#define UICLASS_CDC		0x02 /* communication */
+#define  UISUBCLASS_DIRECT_LINE_CONTROL_MODEL	1
+#define  UISUBCLASS_ABSTRACT_CONTROL_MODEL	2
+#define  UISUBCLASS_TELEPHONE_CONTROL_MODEL	3
+#define  UISUBCLASS_MULTICHANNEL_CONTROL_MODEL	4
+#define  UISUBCLASS_CAPI_CONTROLMODEL		5
+#define  UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL 6
+#define  UISUBCLASS_ATM_NETWORKING_CONTROL_MODEL 7
+#define   UIPROTO_CDC_AT			1
+
+#define UICLASS_HID		0x03
+#define  UISUBCLASS_BOOT	1
+#define  UIPROTO_BOOT_KEYBOARD	1
+
+#define UICLASS_PHYSICAL	0x05
+
+#define UICLASS_IMAGE		0x06
+
+#define UICLASS_PRINTER		0x07
+#define  UISUBCLASS_PRINTER	1
+#define  UIPROTO_PRINTER_UNI	1
+#define  UIPROTO_PRINTER_BI	2
+#define  UIPROTO_PRINTER_1284	3
+
+#define UICLASS_MASS		0x08
+#define  UISUBCLASS_RBC		1
+#define  UISUBCLASS_SFF8020I	2
+#define  UISUBCLASS_QIC157	3
+#define  UISUBCLASS_UFI		4
+#define  UISUBCLASS_SFF8070I	5
+#define  UISUBCLASS_SCSI	6
+#define  UIPROTO_MASS_CBI_I	0
+#define  UIPROTO_MASS_CBI	1
+#define  UIPROTO_MASS_BBB_OLD	2	/* Not in the spec anymore */
+#define  UIPROTO_MASS_BBB	80	/* 'P' for the Iomega Zip drive */
+
+#define UICLASS_HUB		0x09
+#define  UISUBCLASS_HUB		0
+#define  UIPROTO_FSHUB		0
+#define  UIPROTO_HSHUBSTT	0 /* Yes, same as previous */
+#define  UIPROTO_HSHUBMTT	1
+
+#define UICLASS_CDC_DATA	0x0a
+#define  UISUBCLASS_DATA		0
+#define   UIPROTO_DATA_ISDNBRI		0x30    /* Physical iface */
+#define   UIPROTO_DATA_HDLC		0x31    /* HDLC */
+#define   UIPROTO_DATA_TRANSPARENT	0x32    /* Transparent */
+#define   UIPROTO_DATA_Q921M		0x50    /* Management for Q921 */
+#define   UIPROTO_DATA_Q921		0x51    /* Data for Q921 */
+#define   UIPROTO_DATA_Q921TM		0x52    /* TEI multiplexer for Q921 */
+#define   UIPROTO_DATA_V42BIS		0x90    /* Data compression */
+#define   UIPROTO_DATA_Q931		0x91    /* Euro-ISDN */
+#define   UIPROTO_DATA_V120		0x92    /* V.24 rate adaption */
+#define   UIPROTO_DATA_CAPI		0x93    /* CAPI 2.0 commands */
+#define   UIPROTO_DATA_HOST_BASED	0xfd    /* Host based driver */
+#define   UIPROTO_DATA_PUF		0xfe    /* see Prot. Unit Func. Desc.*/
+#define   UIPROTO_DATA_VENDOR		0xff    /* Vendor specific */
+
+#define UICLASS_SMARTCARD	0x0b
+
+/*#define UICLASS_FIRM_UPD	0x0c*/
+
+#define UICLASS_SECURITY	0x0d
+
+#define UICLASS_DIAGNOSTIC	0xdc
+
+#define UICLASS_WIRELESS	0xe0
+#define  UISUBCLASS_RF			0x01
+#define   UIPROTO_BLUETOOTH		0x01
+
+#define UICLASS_APPL_SPEC	0xfe
+#define  UISUBCLASS_FIRMWARE_DOWNLOAD	1
+#define  UISUBCLASS_IRDA		2
+#define  UIPROTO_IRDA			0
+
+#define UICLASS_VENDOR		0xff
+
+#define USB_HUB_MAX_DEPTH 5
+
+/*
+ * Minimum time a device needs to be powered down to go through
+ * a power cycle.  XXX Are these time in the spec?
+ */
+#define USB_POWER_DOWN_TIME	200 /* ms */
+#define USB_PORT_POWER_DOWN_TIME	100 /* ms */
+
+#if 0
+/* These are the values from the spec. */
+#define USB_PORT_RESET_DELAY	10  /* ms */
+#define USB_PORT_ROOT_RESET_DELAY 50  /* ms */
+#define USB_PORT_RESET_RECOVERY	10  /* ms */
+#define USB_PORT_POWERUP_DELAY	100 /* ms */
+#define USB_SET_ADDRESS_SETTLE	2   /* ms */
+#define USB_RESUME_DELAY	(20*5)  /* ms */
+#define USB_RESUME_WAIT		10  /* ms */
+#define USB_RESUME_RECOVERY	10  /* ms */
+#define USB_EXTRA_POWER_UP_TIME	0   /* ms */
+#else
+/* Allow for marginal (i.e. non-conforming) devices. */
+#define USB_PORT_RESET_DELAY	50  /* ms */
+#define USB_PORT_ROOT_RESET_DELAY 250  /* ms */
+#define USB_PORT_RESET_RECOVERY	250  /* ms */
+#define USB_PORT_POWERUP_DELAY	300 /* ms */
+#define USB_SET_ADDRESS_SETTLE	10  /* ms */
+#define USB_RESUME_DELAY	(50*5)  /* ms */
+#define USB_RESUME_WAIT		50  /* ms */
+#define USB_RESUME_RECOVERY	50  /* ms */
+#define USB_EXTRA_POWER_UP_TIME	20  /* ms */
+#endif
+
+#define USB_MIN_POWER		100 /* mA */
+#define USB_MAX_POWER		500 /* mA */
+
+#define USB_BUS_RESET_DELAY	100 /* ms XXX?*/
+
+#define USB_UNCONFIG_NO 0
+#define USB_UNCONFIG_INDEX (-1)
+
+/*** ioctl() related stuff ***/
+
+struct usb_ctl_request {
+	int	ucr_addr;
+	usb_device_request_t ucr_request;
+	void	*ucr_data;
+	int	ucr_flags;
+#define USBD_SHORT_XFER_OK	0x04	/* allow short reads */
+	int	ucr_actlen;		/* actual length transferred */
+};
+
+struct usb_alt_interface {
+	int	uai_config_index;
+	int	uai_interface_index;
+	int	uai_alt_no;
+};
+
+#define USB_CURRENT_CONFIG_INDEX (-1)
+#define USB_CURRENT_ALT_INDEX (-1)
+
+struct usb_config_desc {
+	int	ucd_config_index;
+	usb_config_descriptor_t ucd_desc;
+};
+
+struct usb_interface_desc {
+	int	uid_config_index;
+	int	uid_interface_index;
+	int	uid_alt_index;
+	usb_interface_descriptor_t uid_desc;
+};
+
+struct usb_endpoint_desc {
+	int	ued_config_index;
+	int	ued_interface_index;
+	int	ued_alt_index;
+	int	ued_endpoint_index;
+	usb_endpoint_descriptor_t ued_desc;
+};
+
+struct usb_full_desc {
+	int	ufd_config_index;
+	u_int	ufd_size;
+	u_char	*ufd_data;
+};
+
+struct usb_string_desc {
+	int	usd_string_index;
+	int	usd_language_id;
+	usb_string_descriptor_t usd_desc;
+};
+
+struct usb_ctl_report_desc {
+	int	ucrd_size;
+	u_char	ucrd_data[1024];	/* filled data size will vary */
+};
+
+typedef struct { u_int32_t cookie; } usb_event_cookie_t;
+
+#define USB_MAX_DEVNAMES 4
+#define USB_MAX_DEVNAMELEN 16
+struct usb_device_info {
+	u_int8_t	udi_bus;
+	u_int8_t	udi_addr;	/* device address */
+	usb_event_cookie_t udi_cookie;
+	char		udi_product[USB_MAX_STRING_LEN];
+	char		udi_vendor[USB_MAX_STRING_LEN];
+	char		udi_release[8];
+	u_int16_t	udi_productNo;
+	u_int16_t	udi_vendorNo;
+	u_int16_t	udi_releaseNo;
+	u_int8_t	udi_class;
+	u_int8_t	udi_subclass;
+	u_int8_t	udi_protocol;
+	u_int8_t	udi_config;
+	u_int8_t	udi_speed;
+#define USB_SPEED_UNKNOWN	0
+#define USB_SPEED_LOW		1
+#define USB_SPEED_FULL		2
+#define USB_SPEED_HIGH		3
+#define USB_SPEED_VARIABLE	4
+#define USB_SPEED_SUPER		5
+	int		udi_power;	/* power consumption in mA, 0 if selfpowered */
+	int		udi_nports;
+	char		udi_devnames[USB_MAX_DEVNAMES][USB_MAX_DEVNAMELEN];
+	u_int8_t	udi_ports[16];/* hub only: addresses of devices on ports */
+#define USB_PORT_ENABLED 0xff
+#define USB_PORT_SUSPENDED 0xfe
+#define USB_PORT_POWERED 0xfd
+#define USB_PORT_DISABLED 0xfc
+};
+
+struct usb_ctl_report {
+	int	ucr_report;
+	u_char	ucr_data[1024];	/* filled data size will vary */
+};
+
+struct usb_device_stats {
+	u_long	uds_requests[4];	/* indexed by transfer type UE_* */
+};
+
+#define WUSB_MIN_IE			0x80
+#define WUSB_WCTA_IE			0x80
+#define WUSB_WCONNECTACK_IE		0x81
+#define WUSB_WHOSTINFO_IE		0x82
+#define  WUHI_GET_CA(_bmAttributes_) ((_bmAttributes_) & 0x3)
+#define   WUHI_CA_RECONN		0x00
+#define   WUHI_CA_LIMITED		0x01
+#define   WUHI_CA_ALL			0x03
+#define  WUHI_GET_MLSI(_bmAttributes_) (((_bmAttributes_) & 0x38) >> 3)
+#define WUSB_WCHCHANGEANNOUNCE_IE	0x83
+#define WUSB_WDEV_DISCONNECT_IE		0x84
+#define WUSB_WHOST_DISCONNECT_IE	0x85
+#define WUSB_WRELEASE_CHANNEL_IE	0x86
+#define WUSB_WWORK_IE			0x87
+#define WUSB_WCHANNEL_STOP_IE		0x88
+#define WUSB_WDEV_KEEPALIVE_IE		0x89
+#define WUSB_WISOCH_DISCARD_IE		0x8A
+#define WUSB_WRESETDEVICE_IE		0x8B
+#define WUSB_WXMIT_PACKET_ADJUST_IE	0x8C
+#define WUSB_MAX_IE			0x8C
+
+/* Device Notification Types */
+
+#define WUSB_DN_MIN			0x01
+#define WUSB_DN_CONNECT			0x01
+# define WUSB_DA_OLDCONN	0x00
+# define WUSB_DA_NEWCONN	0x01
+# define WUSB_DA_SELF_BEACON	0x02
+# define WUSB_DA_DIR_BEACON	0x04
+# define WUSB_DA_NO_BEACON	0x06
+#define WUSB_DN_DISCONNECT		0x02
+#define WUSB_DN_EPRDY			0x03
+#define WUSB_DN_MASAVAILCHANGED		0x04
+#define WUSB_DN_REMOTEWAKEUP		0x05
+#define WUSB_DN_SLEEP			0x06
+#define WUSB_DN_ALIVE			0x07
+#define WUSB_DN_MAX			0x07
+
+#ifdef _MSC_VER
+#include <pshpack1.h>
+#endif
+
+/* WUSB Handshake Data.  Used during the SET/GET HANDSHAKE requests */
+typedef struct wusb_hndshk_data {
+	uByte bMessageNumber;
+	uByte bStatus;
+	uByte tTKID[3];
+	uByte bReserved;
+	uByte CDID[16];
+	uByte Nonce[16];
+	uByte MIC[8];
+} UPACKED wusb_hndshk_data_t;
+#define WUSB_HANDSHAKE_LEN_FOR_MIC	38
+
+/* WUSB Connection Context */
+typedef struct wusb_conn_context {
+	uByte CHID [16];
+	uByte CDID [16];
+	uByte CK [16];
+} UPACKED wusb_conn_context_t;
+
+/* WUSB Security Descriptor */
+typedef struct wusb_security_desc {
+	uByte bLength;
+	uByte bDescriptorType;
+	uWord wTotalLength;
+	uByte bNumEncryptionTypes;
+} UPACKED wusb_security_desc_t;
+
+/* WUSB Encryption Type Descriptor */
+typedef struct wusb_encrypt_type_desc {
+	uByte bLength;
+	uByte bDescriptorType;
+
+	uByte bEncryptionType;
+#define WUETD_UNSECURE		0
+#define WUETD_WIRED		1
+#define WUETD_CCM_1		2
+#define WUETD_RSA_1		3
+
+	uByte bEncryptionValue;
+	uByte bAuthKeyIndex;
+} UPACKED wusb_encrypt_type_desc_t;
+
+/* WUSB Key Descriptor */
+typedef struct wusb_key_desc {
+	uByte bLength;
+	uByte bDescriptorType;
+	uByte tTKID[3];
+	uByte bReserved;
+	uByte KeyData[1];	/* variable length */
+} UPACKED wusb_key_desc_t;
+
+/* WUSB BOS Descriptor (Binary device Object Store) */
+typedef struct wusb_bos_desc {
+	uByte bLength;
+	uByte bDescriptorType;
+	uWord wTotalLength;
+	uByte bNumDeviceCaps;
+} UPACKED wusb_bos_desc_t;
+
+#define USB_DEVICE_CAPABILITY_20_EXTENSION	0x02
+typedef struct usb_dev_cap_20_ext_desc {
+	uByte bLength;
+	uByte bDescriptorType;
+	uByte bDevCapabilityType;
+#define USB_20_EXT_LPM				0x02
+	uDWord bmAttributes;
+} UPACKED usb_dev_cap_20_ext_desc_t;
+
+#define USB_DEVICE_CAPABILITY_SS_USB		0x03
+typedef struct usb_dev_cap_ss_usb {
+	uByte bLength;
+	uByte bDescriptorType;
+	uByte bDevCapabilityType;
+#define USB_DC_SS_USB_LTM_CAPABLE		0x02
+	uByte bmAttributes;
+#define USB_DC_SS_USB_SPEED_SUPPORT_LOW		0x01
+#define USB_DC_SS_USB_SPEED_SUPPORT_FULL	0x02
+#define USB_DC_SS_USB_SPEED_SUPPORT_HIGH	0x04
+#define USB_DC_SS_USB_SPEED_SUPPORT_SS		0x08
+	uWord wSpeedsSupported;
+	uByte bFunctionalitySupport;
+	uByte bU1DevExitLat;
+	uWord wU2DevExitLat;
+} UPACKED usb_dev_cap_ss_usb_t;
+
+#define USB_DEVICE_CAPABILITY_CONTAINER_ID	0x04
+typedef struct usb_dev_cap_container_id {
+	uByte bLength;
+	uByte bDescriptorType;
+	uByte bDevCapabilityType;
+	uByte bReserved;
+	uByte containerID[16];
+} UPACKED usb_dev_cap_container_id_t;
+
+/* Device Capability Type Codes */
+#define WUSB_DEVICE_CAPABILITY_WIRELESS_USB 0x01
+
+/* Device Capability Descriptor */
+typedef struct wusb_dev_cap_desc {
+	uByte bLength;
+	uByte bDescriptorType;
+	uByte bDevCapabilityType;
+	uByte caps[1];	/* Variable length */
+} UPACKED wusb_dev_cap_desc_t;
+
+/* Device Capability Descriptor */
+typedef struct wusb_dev_cap_uwb_desc {
+	uByte bLength;
+	uByte bDescriptorType;
+	uByte bDevCapabilityType;
+	uByte bmAttributes;
+	uWord wPHYRates;	/* Bitmap */
+	uByte bmTFITXPowerInfo;
+	uByte bmFFITXPowerInfo;
+	uWord bmBandGroup;
+	uByte bReserved;
+} UPACKED wusb_dev_cap_uwb_desc_t;
+
+/* Wireless USB Endpoint Companion Descriptor */
+typedef struct wusb_endpoint_companion_desc {
+	uByte bLength;
+	uByte bDescriptorType;
+	uByte bMaxBurst;
+	uByte bMaxSequence;
+	uWord wMaxStreamDelay;
+	uWord wOverTheAirPacketSize;
+	uByte bOverTheAirInterval;
+	uByte bmCompAttributes;
+} UPACKED wusb_endpoint_companion_desc_t;
+
+/* Wireless USB Numeric Association M1 Data Structure */
+typedef struct wusb_m1_data {
+	uByte version;
+	uWord langId;
+	uByte deviceFriendlyNameLength;
+	uByte sha_256_m3[32];
+	uByte deviceFriendlyName[256];
+} UPACKED wusb_m1_data_t;
+
+typedef struct wusb_m2_data {
+	uByte version;
+	uWord langId;
+	uByte hostFriendlyNameLength;
+	uByte pkh[384];
+	uByte hostFriendlyName[256];
+} UPACKED wusb_m2_data_t;
+
+typedef struct wusb_m3_data {
+	uByte pkd[384];
+	uByte nd;
+} UPACKED wusb_m3_data_t;
+
+typedef struct wusb_m4_data {
+	uDWord _attributeTypeIdAndLength_1;
+	uWord  associationTypeId;
+
+	uDWord _attributeTypeIdAndLength_2;
+	uWord  associationSubTypeId;
+
+	uDWord _attributeTypeIdAndLength_3;
+	uDWord length;
+
+	uDWord _attributeTypeIdAndLength_4;
+	uDWord associationStatus;
+
+	uDWord _attributeTypeIdAndLength_5;
+	uByte  chid[16];
+
+	uDWord _attributeTypeIdAndLength_6;
+	uByte  cdid[16];
+
+	uDWord _attributeTypeIdAndLength_7;
+	uByte  bandGroups[2];
+} UPACKED wusb_m4_data_t;
+
+#ifdef _MSC_VER
+#include <poppack.h>
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _USB_H_ */
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 060e0e2..5d2d92d 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -27,6 +27,11 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called xhci-hcd.
 
+config USB_XHCI_PLATFORM
+        tristate
+        depends on USB_XHCI_HCD
+	default y
+
 config USB_XHCI_HCD_DEBUGGING
 	bool "Debugging for the xHCI host controller"
 	depends on USB_XHCI_HCD
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 7ca290f..383fc37 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -15,6 +15,10 @@
 xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o
 xhci-hcd-$(CONFIG_PCI)	+= xhci-pci.o
 
+ifneq ($(CONFIG_USB_XHCI_PLATFORM), )
+	xhci-hcd-y		+= xhci-plat.o xhci-comcerto2000.o
+endif
+
 obj-$(CONFIG_USB_WHCI_HCD)	+= whci/
 
 obj-$(CONFIG_PCI)		+= pci-quirks.o
diff --git a/drivers/usb/host/xhci-comcerto2000.c b/drivers/usb/host/xhci-comcerto2000.c
new file mode 100644
index 0000000..de92ccc
--- /dev/null
+++ b/drivers/usb/host/xhci-comcerto2000.c
@@ -0,0 +1,203 @@
+/*
+ * xhci-comcerto.c - Comcerto-2000 Platform specific routienes.
+ *
+ * Author: Makarand Pawagi
+ */
+
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "xhci.h"
+
+#include <linux/clk.h>
+#include <mach/reset.h>
+#include <mach/hardware.h>
+
+extern int usb3_clk_internal;
+/* USB 3.0 clock */
+static struct clk *usb3_clk;
+
+#ifdef CONFIG_PM
+
+u32 usb3_suspended = 0;
+
+int comcerto_xhci_bus_suspend(struct usb_hcd *hcd)
+{
+	int error_status = 0;
+	int val;
+
+	if (usb3_suspended) {
+		pr_err("comcerto_xhci_bus_suspend: USB 3.0 Already Suspended \n");
+		return error_status;
+	}
+
+	error_status = xhci_bus_suspend(hcd);
+
+	if (!error_status) {
+
+		/* APPLYING THE RESET TO USB3 UTMI */
+		c2000_block_reset(COMPONENT_UTMI_USB1, 1);
+
+		/* APPLYING THE RESET TO USB3 PHY */
+		c2000_block_reset(COMPONENT_USB1_PHY, 1);
+
+		/* Disable the Clock */
+		clk_disable(usb3_clk);
+
+		usb3_suspended = 1;
+	}
+
+	return error_status;
+}
+
+int comcerto_xhci_bus_resume(struct usb_hcd *hcd)
+{
+	int val;
+	int error_status = 0;
+
+	if (!usb3_suspended) {
+		pr_err("comcerto_xhci_bus_resume: USB 3.0 Already in Resume state \n");
+		return error_status;
+	}
+
+	/* Enable the Clock */
+	if (clk_enable(usb3_clk)){
+		pr_err("comcerto_start_xhc:Unable to enable the usb1 clock \n");
+	}
+
+	/* Bring usb3 PHY out of reset */
+	c2000_block_reset(COMPONENT_USB1_PHY, 0);
+
+	for (val = 0 ; val < 50 ; val++)
+		udelay(1000);
+
+    /* Bring usb3 UTMI out of reset */
+	c2000_block_reset(COMPONENT_UTMI_USB1, 0);
+
+	for (val = 0 ; val < 50 ; val++)
+		udelay(1000);
+
+	error_status = xhci_bus_resume(hcd);
+
+	if (error_status) {
+		/* xhci_bus_resume is not successfull keep USB3 in suspend mode */
+
+		/* Put USB3 PHY, UTMI and Controller in Reset */
+
+		/* APPLYING THE RESET TO USB3 UTMI */
+		c2000_block_reset(COMPONENT_UTMI_USB1, 1);
+
+		/* APPLYING THE RESET TO USB3 PHY */
+		c2000_block_reset(COMPONENT_USB1_PHY, 1);
+
+		/* Disable the Clock */
+		clk_disable(usb3_clk);
+
+		return error_status;
+	}
+
+	usb3_suspended = 0;
+
+	return error_status;
+}
+#endif
+
+static void comcerto_usb3_phy_init(void)
+{
+	u32 val;
+
+        writel(0x00E00080, USB3_PHY_BASE + 0x10);
+
+	//Configuration for internal clock
+	if(usb3_clk_internal)
+	{
+		printk(KERN_INFO "USB3.0 clock selected: internal\n", __func__);
+
+		if(HAL_get_ref_clk() == REF_CLK_24MHZ)
+			val = 0x420E82A8;
+		else
+			val = 0x420E82A9;
+	}
+	else
+	{
+		val = 0x4209927A;
+		printk(KERN_INFO "USB3.0 clock selected: external\n", __func__);
+	}
+
+	writel(val, USB3_PHY_BASE + 0x20);
+        writel(0x69C34F53, USB3_PHY_BASE + 0x24);
+        writel(0x0005D815, USB3_PHY_BASE + 0x28);
+        writel(0x00000801, USB3_PHY_BASE + 0x2C);
+}
+
+
+void comcerto_start_xhci(void)
+{
+        u32 val;
+
+        printk(KERN_INFO "### %s\n", __func__);
+
+#if defined(CONFIG_C2K_MFCN_EVM)
+	printk("%s: Reseting usb3...\n", __func__);
+	GPIO_reset_external_device(COMPONENT_USB_HUB, 0);
+#endif
+		/* Enable the USB 3.0 controller clock */
+		/* Get the usb3 clock structure  */
+		usb3_clk = clk_get(NULL,"usb1");
+
+		/* Enable the Clock */
+		if (clk_enable(usb3_clk)){
+			pr_err("comcerto_start_xhci:Unable to enable the usb1 clock \n");
+		}
+
+		/* APPLYING THE RESET TO USB3 UTMI */
+		c2000_block_reset(COMPONENT_UTMI_USB1, 1);
+
+		/* APPLYING THE RESET TO USB3 PHY */
+		c2000_block_reset(COMPONENT_USB1_PHY, 1);
+
+		/* APLLYING RESET TO USB3 AXI RESET */
+		c2000_block_reset(COMPONENT_AXI_USB1, 1);
+
+		comcerto_usb3_phy_init();
+
+
+		/* Bring usb3 PHY out of reset */
+		c2000_block_reset(COMPONENT_USB1_PHY, 0);
+
+		udelay(1000);
+
+		/* Bring usb3 UTMI out of reset */
+		c2000_block_reset(COMPONENT_UTMI_USB1, 0);
+
+		udelay(1000);
+
+		/* Bring usb3 Controller out of reset */
+		c2000_block_reset(COMPONENT_AXI_USB1, 0);
+
+		udelay(1000);
+}
+
+void comcerto_stop_xhci(void)
+{
+        u32 val;
+
+        printk(KERN_INFO "### %s\n", __func__);
+
+		/* APPLYING THE RESET TO USB3 UTMI */
+		c2000_block_reset(COMPONENT_UTMI_USB1, 1);
+
+		/* APPLYING THE RESET TO USB3 PHY */
+		c2000_block_reset(COMPONENT_USB1_PHY, 1);
+
+		/* APLLYING RESET TO USB3 AXI RESET */
+		c2000_block_reset(COMPONENT_AXI_USB1, 1);
+
+		/* Disable the Clock */
+		clk_disable(usb3_clk);
+
+		/* Release the clock */
+		clk_put(usb3_clk);
+}
+
diff --git a/drivers/usb/host/xhci-comcerto2000.h b/drivers/usb/host/xhci-comcerto2000.h
new file mode 100644
index 0000000..02b36e0
--- /dev/null
+++ b/drivers/usb/host/xhci-comcerto2000.h
@@ -0,0 +1,24 @@
+/*
+ * xhci-comcerto.h - Comcerto-2000 Platform specific routienes.
+ *
+ * Author: Makarand Pawagi
+ */
+
+
+#ifndef __XHCI_COMCERTO_2000_H__
+#define __XHCI_COMCERTO_2000_H__
+
+
+
+/* Exported Functions */
+
+
+extern void comcerto_start_xhci(void);
+extern void comcerto_stop_xhci(void);
+
+extern int comcerto_xhci_bus_resume(struct usb_hcd *hcd);
+extern int comcerto_xhci_bus_suspend(struct usb_hcd *hcd);
+
+
+
+#endif /* __XHCI_COMCERTO_2000_H__ */
diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c
index e9b0f04..4b436f5 100644
--- a/drivers/usb/host/xhci-dbg.c
+++ b/drivers/usb/host/xhci-dbg.c
@@ -119,7 +119,7 @@
 	xhci_dbg(xhci, "  Event Interrupts %s\n",
 			(temp & CMD_EIE) ? "enabled " : "disabled");
 	xhci_dbg(xhci, "  Host System Error Interrupts %s\n",
-			(temp & CMD_EIE) ? "enabled " : "disabled");
+			(temp & CMD_HSEIE) ? "enabled " : "disabled");
 	xhci_dbg(xhci, "  HC has %sfinished light reset\n",
 			(temp & CMD_LRESET) ? "not " : "");
 }
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index fd8a2c2..78e98a6 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -57,10 +57,8 @@
 	desc->bHubContrCurrent = 0;
 
 	desc->bNbrPorts = ports;
-	/* Ugh, these should be #defines, FIXME */
-	/* Using table 11-13 in USB 2.0 spec. */
 	temp = 0;
-	/* Bits 1:0 - support port power switching, or power always on */
+	/* Bits 1:0 - support per-port power switching, or power always on */
 	if (HCC_PPC(xhci->hcc_params))
 		temp |= 0x0001;
 	else
@@ -86,9 +84,9 @@
 	ports = xhci->num_usb2_ports;
 
 	xhci_common_hub_descriptor(xhci, desc, ports);
-	desc->bDescriptorType = 0x29;
+	desc->bDescriptorType = USB_DT_HUB;
 	temp = 1 + (ports / 8);
-	desc->bDescLength = 7 + 2 * temp;
+	desc->bDescLength = USB_DT_HUB_NONVAR_SIZE + 2 * temp;
 
 	/* The Device Removable bits are reported on a byte granularity.
 	 * If the port doesn't exist within that byte, the bit is set to 0.
@@ -137,8 +135,8 @@
 
 	ports = xhci->num_usb3_ports;
 	xhci_common_hub_descriptor(xhci, desc, ports);
-	desc->bDescriptorType = 0x2a;
-	desc->bDescLength = 12;
+	desc->bDescriptorType = USB_DT_SS_HUB;
+	desc->bDescLength = USB_DT_SS_HUB_SIZE;
 
 	/* header decode latency should be zero for roothubs,
 	 * see section 4.23.5.2.
@@ -424,6 +422,34 @@
 	xhci_writel(xhci, temp, port_array[port_id]);
 }
 
+#if 0
+void xhci_set_remote_wake_mask(struct xhci_hcd *xhci,
+		__le32 __iomem **port_array, int port_id, u16 wake_mask)
+{
+	u32 temp;
+
+	temp = xhci_readl(xhci, port_array[port_id]);
+	temp = xhci_port_state_to_neutral(temp);
+
+	if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_CONNECT)
+		temp |= PORT_WKCONN_E;
+	else
+		temp &= ~PORT_WKCONN_E;
+
+	if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT)
+		temp |= PORT_WKDISC_E;
+	else
+		temp &= ~PORT_WKDISC_E;
+
+	if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT)
+		temp |= PORT_WKOC_E;
+	else
+		temp &= ~PORT_WKOC_E;
+
+	xhci_writel(xhci, temp, port_array[port_id]);
+}
+#endif
+
 /* Test and clear port RWC bit */
 void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
 				int port_id, u32 port_bit)
@@ -486,6 +512,7 @@
 	int slot_id;
 	struct xhci_bus_state *bus_state;
 	u16 link_state = 0;
+	u16 wake_mask = 0;
 
 	max_ports = xhci_get_ports(hcd, &port_array);
 	bus_state = &xhci->bus_state[hcd_index(hcd)];
@@ -627,6 +654,8 @@
 	case SetPortFeature:
 		if (wValue == USB_PORT_FEAT_LINK_STATE)
 			link_state = (wIndex & 0xff00) >> 3;
+		if (wValue == USB_PORT_FEAT_REMOTE_WAKE_MASK)
+			wake_mask = wIndex & 0xff00;
 		wIndex &= 0xff;
 		if (!wIndex || wIndex > max_ports)
 			goto error;
@@ -737,6 +766,16 @@
 			temp = xhci_readl(xhci, port_array[wIndex]);
 			xhci_dbg(xhci, "set port reset, actual port %d status  = 0x%x\n", wIndex, temp);
 			break;
+#if 0
+		case USB_PORT_FEAT_REMOTE_WAKE_MASK:
+			xhci_set_remote_wake_mask(xhci, port_array,
+					wIndex, wake_mask);
+			temp = xhci_readl(xhci, port_array[wIndex]);
+			xhci_dbg(xhci, "set port remote wake mask, "
+					"actual port %d status  = 0x%x\n",
+					wIndex, temp);
+			break;
+#endif
 		case USB_PORT_FEAT_BH_PORT_RESET:
 			temp |= PORT_WR;
 			xhci_writel(xhci, temp, port_array[wIndex]);
@@ -917,6 +956,10 @@
 			t2 |= PORT_LINK_STROBE | XDEV_U3;
 			set_bit(port_index, &bus_state->bus_suspended);
 		}
+		/* USB core sets remote wake mask for USB 3.0 hubs,
+		 * including the USB 3.0 roothub, but only if CONFIG_USB_SUSPEND
+		 * is enabled, so also enable remote wake here.
+		 */
 		if (hcd->self.root_hub->do_remote_wakeup) {
 			if (t1 & PORT_CONNECT) {
 				t2 |= PORT_WKOC_E | PORT_WKDISC_E;
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index a40ab98..98d4c07 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -34,25 +34,29 @@
  * Section 4.11.1.1:
  * "All components of all Command and Transfer TRBs shall be initialized to '0'"
  */
-static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, gfp_t flags)
+static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci,
+					unsigned int cycle_state, gfp_t flags)
 {
 	struct xhci_segment *seg;
 	dma_addr_t	dma;
+	int		i;
 
 	seg = kzalloc(sizeof *seg, flags);
 	if (!seg)
 		return NULL;
-	xhci_dbg(xhci, "Allocating priv segment structure at %p\n", seg);
 
 	seg->trbs = dma_pool_alloc(xhci->segment_pool, flags, &dma);
 	if (!seg->trbs) {
 		kfree(seg);
 		return NULL;
 	}
-	xhci_dbg(xhci, "// Allocating segment at %p (virtual) 0x%llx (DMA)\n",
-			seg->trbs, (unsigned long long)dma);
 
 	memset(seg->trbs, 0, SEGMENT_SIZE);
+	/* If the cycle state is 0, set the cycle bit to 1 for all the TRBs */
+	if (cycle_state == 0) {
+		for (i = 0; i < TRBS_PER_SEGMENT; i++)
+			seg->trbs[i].link.control |= TRB_CYCLE;
+	}
 	seg->dma = dma;
 	seg->next = NULL;
 
@@ -62,15 +66,26 @@
 static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg)
 {
 	if (seg->trbs) {
-		xhci_dbg(xhci, "Freeing DMA segment at %p (virtual) 0x%llx (DMA)\n",
-				seg->trbs, (unsigned long long)seg->dma);
 		dma_pool_free(xhci->segment_pool, seg->trbs, seg->dma);
 		seg->trbs = NULL;
 	}
-	xhci_dbg(xhci, "Freeing priv segment structure at %p\n", seg);
 	kfree(seg);
 }
 
+static void xhci_free_segments_for_ring(struct xhci_hcd *xhci,
+				struct xhci_segment *first)
+{
+	struct xhci_segment *seg;
+
+	seg = first->next;
+	while (seg != first) {
+		struct xhci_segment *next = seg->next;
+		xhci_segment_free(xhci, seg);
+		seg = next;
+	}
+	xhci_segment_free(xhci, first);
+}
+
 /*
  * Make the prev segment point to the next segment.
  *
@@ -79,14 +94,14 @@
  * related flags, such as End TRB, Toggle Cycle, and no snoop.
  */
 static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
-		struct xhci_segment *next, bool link_trbs, bool isoc)
+		struct xhci_segment *next, enum xhci_ring_type type)
 {
 	u32 val;
 
 	if (!prev || !next)
 		return;
 	prev->next = next;
-	if (link_trbs) {
+	if (type != TYPE_EVENT) {
 		prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr =
 			cpu_to_le64(next->dma);
 
@@ -97,39 +112,55 @@
 		/* Always set the chain bit with 0.95 hardware */
 		/* Set chain bit for isoc rings on AMD 0.96 host */
 		if (xhci_link_trb_quirk(xhci) ||
-				(isoc && (xhci->quirks & XHCI_AMD_0x96_HOST)))
+				(type == TYPE_ISOC &&
+				 (xhci->quirks & XHCI_AMD_0x96_HOST)))
 			val |= TRB_CHAIN;
 		prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val);
 	}
-	xhci_dbg(xhci, "Linking segment 0x%llx to segment 0x%llx (DMA)\n",
-			(unsigned long long)prev->dma,
-			(unsigned long long)next->dma);
+}
+
+/*
+ * Link the ring to the new segments.
+ * Set Toggle Cycle for the new ring if needed.
+ */
+static void xhci_link_rings(struct xhci_hcd *xhci, struct xhci_ring *ring,
+		struct xhci_segment *first, struct xhci_segment *last,
+		unsigned int num_segs)
+{
+	struct xhci_segment *next;
+
+	if (!ring || !first || !last)
+		return;
+
+	next = ring->enq_seg->next;
+	xhci_link_segments(xhci, ring->enq_seg, first, ring->type);
+	xhci_link_segments(xhci, last, next, ring->type);
+	ring->num_segs += num_segs;
+	ring->num_trbs_free += (TRBS_PER_SEGMENT - 1) * num_segs;
+
+	if (ring->type != TYPE_EVENT && ring->enq_seg == ring->last_seg) {
+		ring->last_seg->trbs[TRBS_PER_SEGMENT-1].link.control
+			&= ~cpu_to_le32(LINK_TOGGLE);
+		last->trbs[TRBS_PER_SEGMENT-1].link.control
+			|= cpu_to_le32(LINK_TOGGLE);
+		ring->last_seg = last;
+	}
 }
 
 /* XXX: Do we need the hcd structure in all these functions? */
 void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring)
 {
-	struct xhci_segment *seg;
-	struct xhci_segment *first_seg;
-
 	if (!ring)
 		return;
-	if (ring->first_seg) {
-		first_seg = ring->first_seg;
-		seg = first_seg->next;
-		xhci_dbg(xhci, "Freeing ring at %p\n", ring);
-		while (seg != first_seg) {
-			struct xhci_segment *next = seg->next;
-			xhci_segment_free(xhci, seg);
-			seg = next;
-		}
-		xhci_segment_free(xhci, first_seg);
-		ring->first_seg = NULL;
-	}
+
+	if (ring->first_seg)
+		xhci_free_segments_for_ring(xhci, ring->first_seg);
+
 	kfree(ring);
 }
 
-static void xhci_initialize_ring_info(struct xhci_ring *ring)
+static void xhci_initialize_ring_info(struct xhci_ring *ring,
+					unsigned int cycle_state)
 {
 	/* The ring is empty, so the enqueue pointer == dequeue pointer */
 	ring->enqueue = ring->first_seg->trbs;
@@ -139,11 +170,53 @@
 	/* The ring is initialized to 0. The producer must write 1 to the cycle
 	 * bit to handover ownership of the TRB, so PCS = 1.  The consumer must
 	 * compare CCS to the cycle bit to check ownership, so CCS = 1.
+	 *
+	 * New rings are initialized with cycle state equal to 1; if we are
+	 * handling ring expansion, set the cycle state equal to the old ring.
 	 */
-	ring->cycle_state = 1;
+	ring->cycle_state = cycle_state;
 	/* Not necessary for new rings, but needed for re-initialized rings */
 	ring->enq_updates = 0;
 	ring->deq_updates = 0;
+
+	/*
+	 * Each segment has a link TRB, and leave an extra TRB for SW
+	 * accounting purpose
+	 */
+	ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1;
+}
+
+/* Allocate segments and link them for a ring */
+static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
+		struct xhci_segment **first, struct xhci_segment **last,
+		unsigned int num_segs, unsigned int cycle_state,
+		enum xhci_ring_type type, gfp_t flags)
+{
+	struct xhci_segment *prev;
+
+	prev = xhci_segment_alloc(xhci, cycle_state, flags);
+	if (!prev)
+		return -ENOMEM;
+	num_segs--;
+
+	*first = prev;
+	while (num_segs > 0) {
+		struct xhci_segment	*next;
+
+		next = xhci_segment_alloc(xhci, cycle_state, flags);
+		if (!next) {
+			xhci_free_segments_for_ring(xhci, *first);
+			return -ENOMEM;
+		}
+		xhci_link_segments(xhci, prev, next, type);
+
+		prev = next;
+		num_segs--;
+	}
+	xhci_link_segments(xhci, prev, *first, type);
+	*last = prev;
+
+	return 0;
 }
 
 /**
@@ -154,48 +227,34 @@
  * See section 4.9.1 and figures 15 and 16.
  */
 static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
-		unsigned int num_segs, bool link_trbs, bool isoc, gfp_t flags)
+		unsigned int num_segs, unsigned int cycle_state,
+		enum xhci_ring_type type, gfp_t flags)
 {
 	struct xhci_ring	*ring;
-	struct xhci_segment	*prev;
+	int ret;
 
 	ring = kzalloc(sizeof *(ring), flags);
-	xhci_dbg(xhci, "Allocating ring at %p\n", ring);
 	if (!ring)
 		return NULL;
 
+	ring->num_segs = num_segs;
 	INIT_LIST_HEAD(&ring->td_list);
+	ring->type = type;
 	if (num_segs == 0)
 		return ring;
 
-	ring->first_seg = xhci_segment_alloc(xhci, flags);
-	if (!ring->first_seg)
+	ret = xhci_alloc_segments_for_ring(xhci, &ring->first_seg,
+			&ring->last_seg, num_segs, cycle_state, type, flags);
+	if (ret)
 		goto fail;
-	num_segs--;
 
-	prev = ring->first_seg;
-	while (num_segs > 0) {
-		struct xhci_segment	*next;
-
-		next = xhci_segment_alloc(xhci, flags);
-		if (!next)
-			goto fail;
-		xhci_link_segments(xhci, prev, next, link_trbs, isoc);
-
-		prev = next;
-		num_segs--;
-	}
-	xhci_link_segments(xhci, prev, ring->first_seg, link_trbs, isoc);
-
-	if (link_trbs) {
+	/* Only event ring does not use link TRB */
+	if (type != TYPE_EVENT) {
 		/* See section 4.9.2.1 and 6.4.4.1 */
-		prev->trbs[TRBS_PER_SEGMENT-1].link.control |=
+		ring->last_seg->trbs[TRBS_PER_SEGMENT - 1].link.control |=
 			cpu_to_le32(LINK_TOGGLE);
-		xhci_dbg(xhci, "Wrote link toggle flag to"
-				" segment %p (virtual), 0x%llx (DMA)\n",
-				prev, (unsigned long long)prev->dma);
 	}
-	xhci_initialize_ring_info(ring);
+	xhci_initialize_ring_info(ring, cycle_state);
 	return ring;
 
 fail:
@@ -231,23 +290,64 @@
  * pointers to the beginning of the ring.
  */
 static void xhci_reinit_cached_ring(struct xhci_hcd *xhci,
-		struct xhci_ring *ring, bool isoc)
+			struct xhci_ring *ring, unsigned int cycle_state,
+			enum xhci_ring_type type)
 {
 	struct xhci_segment	*seg = ring->first_seg;
+	int i;
+
 	do {
 		memset(seg->trbs, 0,
 				sizeof(union xhci_trb)*TRBS_PER_SEGMENT);
+		if (cycle_state == 0) {
+			for (i = 0; i < TRBS_PER_SEGMENT; i++)
+				seg->trbs[i].link.control |= TRB_CYCLE;
+		}
 		/* All endpoint rings have link TRBs */
-		xhci_link_segments(xhci, seg, seg->next, 1, isoc);
+		xhci_link_segments(xhci, seg, seg->next, type);
 		seg = seg->next;
 	} while (seg != ring->first_seg);
-	xhci_initialize_ring_info(ring);
+	ring->type = type;
+	xhci_initialize_ring_info(ring, cycle_state);
 	/* td list should be empty since all URBs have been cancelled,
 	 * but just in case...
 	 */
 	INIT_LIST_HEAD(&ring->td_list);
 }
 
+/*
+ * Expand an existing ring.
+ * Look for a cached ring or allocate a new ring which has same segment numbers
+ * and link the two rings.
+ */
+int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
+				unsigned int num_trbs, gfp_t flags)
+{
+	struct xhci_segment	*first;
+	struct xhci_segment	*last;
+	unsigned int		num_segs;
+	unsigned int		num_segs_needed;
+	int			ret;
+
+	num_segs_needed = (num_trbs + (TRBS_PER_SEGMENT - 1) - 1) /
+				(TRBS_PER_SEGMENT - 1);
+
+	/* Allocate number of segments we needed, or double the ring size */
+	num_segs = ring->num_segs > num_segs_needed ?
+			ring->num_segs : num_segs_needed;
+
+	ret = xhci_alloc_segments_for_ring(xhci, &first, &last,
+			num_segs, ring->cycle_state, ring->type, flags);
+	if (ret)
+		return -ENOMEM;
+
+	xhci_link_rings(xhci, ring, first, last, num_segs);
+	xhci_dbg(xhci, "ring expansion succeed, now has %d segments\n",
+			ring->num_segs);
+
+	return 0;
+}
+
 #define CTX_SIZE(_hcc) (HCC_64BYTE_CONTEXT(_hcc) ? 64 : 32)
 
 static struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci,
@@ -542,7 +642,7 @@
 	 */
 	for (cur_stream = 1; cur_stream < num_streams; cur_stream++) {
 		stream_info->stream_rings[cur_stream] =
-			xhci_ring_alloc(xhci, 1, true, false, mem_flags);
+			xhci_ring_alloc(xhci, 2, 1, TYPE_STREAM, mem_flags);
 		cur_ring = stream_info->stream_rings[cur_stream];
 		if (!cur_ring)
 			goto cleanup_rings;
@@ -857,7 +957,7 @@
 	}
 
 	/* Allocate endpoint 0 ring */
-	dev->eps[0].ring = xhci_ring_alloc(xhci, 1, true, false, flags);
+	dev->eps[0].ring = xhci_ring_alloc(xhci, 2, 1, TYPE_CTRL, flags);
 	if (!dev->eps[0].ring)
 		goto fail;
 
@@ -1295,24 +1395,16 @@
 	struct xhci_ring *ep_ring;
 	unsigned int max_packet;
 	unsigned int max_burst;
+	enum xhci_ring_type type;
 	u32 max_esit_payload;
 
 	ep_index = xhci_get_endpoint_index(&ep->desc);
 	ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
 
+	type = usb_endpoint_type(&ep->desc);
 	/* Set up the endpoint ring */
-	/*
-	 * Isochronous endpoint ring needs bigger size because one isoc URB
-	 * carries multiple packets and it will insert multiple tds to the
-	 * ring.
-	 * This should be replaced with dynamic ring resizing in the future.
-	 */
-	if (usb_endpoint_xfer_isoc(&ep->desc))
-		virt_dev->eps[ep_index].new_ring =
-			xhci_ring_alloc(xhci, 8, true, true, mem_flags);
-	else
-		virt_dev->eps[ep_index].new_ring =
-			xhci_ring_alloc(xhci, 1, true, false, mem_flags);
+	virt_dev->eps[ep_index].new_ring =
+		xhci_ring_alloc(xhci, 2, 1, type, mem_flags);
 	if (!virt_dev->eps[ep_index].new_ring) {
 		/* Attempt to use the ring cache */
 		if (virt_dev->num_rings_cached == 0)
@@ -1322,7 +1414,7 @@
 		virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL;
 		virt_dev->num_rings_cached--;
 		xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring,
-			usb_endpoint_xfer_isoc(&ep->desc) ? true : false);
+					1, type);
 	}
 	virt_dev->eps[ep_index].skip = false;
 	ep_ring = virt_dev->eps[ep_index].new_ring;
@@ -1697,6 +1789,7 @@
 	xhci_dbg(xhci, "Freed event ring\n");
 
 	xhci->cmd_ring_reserved_trbs = 0;
+
 	if (xhci->cmd_ring)
 		xhci_ring_free(xhci, xhci->cmd_ring);
 	xhci->cmd_ring = NULL;
@@ -2165,7 +2258,7 @@
 	unsigned int	val, val2;
 	u64		val_64;
 	struct xhci_segment	*seg;
-	u32 page_size;
+	u32 page_size, temp;
 	int i;
 
 	page_size = xhci_readl(xhci, &xhci->op_regs->page_size);
@@ -2243,7 +2336,7 @@
 		goto fail;
 
 	/* Set up the command ring to have one segments for now. */
-	xhci->cmd_ring = xhci_ring_alloc(xhci, 1, true, false, flags);
+	xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, flags);
 	if (!xhci->cmd_ring)
 		goto fail;
 	xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring);
@@ -2274,7 +2367,7 @@
 	 * the event ring segment table (ERST).  Section 4.9.3.
 	 */
 	xhci_dbg(xhci, "// Allocating event ring\n");
-	xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, false, false,
+	xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
 						flags);
 	if (!xhci->event_ring)
 		goto fail;
@@ -2348,6 +2441,15 @@
 
 	INIT_LIST_HEAD(&xhci->lpm_failed_devs);
 
+	/* Enable USB 3.0 device notifications for function remote wake, which
+	 * is necessary for allowing USB 3.0 devices to do remote wakeup from
+	 * U3 (device suspend).
+	 */
+	temp = xhci_readl(xhci, &xhci->op_regs->dev_notification);
+	temp &= ~DEV_NOTE_MASK;
+	temp |= DEV_NOTE_FWAKE;
+	xhci_writel(xhci, temp, &xhci->op_regs->dev_notification);
+
 	return 0;
 
 fail:
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index daf5754..19e8921 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -329,7 +329,7 @@
 	return pci_register_driver(&xhci_pci_driver);
 }
 
-void __exit xhci_unregister_pci(void)
+void xhci_unregister_pci(void)
 {
 	pci_unregister_driver(&xhci_pci_driver);
 }
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
new file mode 100644
index 0000000..3288465
--- /dev/null
+++ b/drivers/usb/host/xhci-plat.c
@@ -0,0 +1,224 @@
+/*
+ * xhci-plat.c - xHCI host controller driver platform Bus Glue.
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * A lot of code borrowed from the Linux xHCI driver.
+ *
+ * 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/platform_device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "xhci.h"
+#include "xhci-comcerto2000.h"
+
+
+
+static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
+{
+	/*
+	 * As of now platform drivers don't provide MSI support so we ensure
+	 * here that the generic code does not try to make a pci_dev from our
+	 * dev struct in order to setup MSI
+	 */
+	xhci->quirks |= XHCI_BROKEN_MSI;
+}
+
+/* called during probe() after chip reset completes */
+static int xhci_plat_setup(struct usb_hcd *hcd)
+{
+	return xhci_gen_setup(hcd, xhci_plat_quirks);
+}
+
+static const struct hc_driver xhci_plat_xhci_driver = {
+	.description =		"xhci-hcd",
+	.product_desc =		"xHCI Host Controller",
+	.hcd_priv_size =	sizeof(struct xhci_hcd *),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			xhci_irq,
+	.flags =		HCD_MEMORY | HCD_USB3 | HCD_SHARED,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.reset =		xhci_plat_setup,
+	.start =		xhci_run,
+	.stop =			xhci_stop,
+	.shutdown =		xhci_shutdown,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		xhci_urb_enqueue,
+	.urb_dequeue =		xhci_urb_dequeue,
+	.alloc_dev =		xhci_alloc_dev,
+	.free_dev =		xhci_free_dev,
+	.alloc_streams =	xhci_alloc_streams,
+	.free_streams =		xhci_free_streams,
+	.add_endpoint =		xhci_add_endpoint,
+	.drop_endpoint =	xhci_drop_endpoint,
+	.endpoint_reset =	xhci_endpoint_reset,
+	.check_bandwidth =	xhci_check_bandwidth,
+	.reset_bandwidth =	xhci_reset_bandwidth,
+	.address_device =	xhci_address_device,
+	.update_hub_device =	xhci_update_hub_device,
+	.reset_device =		xhci_discover_or_reset_device,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	xhci_get_frame,
+
+	/* Root hub support */
+	.hub_control =		xhci_hub_control,
+	.hub_status_data =	xhci_hub_status_data,
+#ifdef CONFIG_PM	
+	.bus_suspend =		comcerto_xhci_bus_suspend,
+	.bus_resume =		comcerto_xhci_bus_resume,
+#endif
+};
+
+static int xhci_plat_probe(struct platform_device *pdev)
+{
+	const struct hc_driver	*driver;
+	struct xhci_hcd		*xhci;
+	struct resource         *res;
+	struct usb_hcd		*hcd;
+	int			ret;
+	int			irq;
+
+	printk(KERN_INFO "## %s\n",__func__);
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	/* Do the Platform specific initializations */
+	comcerto_start_xhci();
+
+	driver = &xhci_plat_xhci_driver;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return -ENODEV;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
+	if (!hcd)
+		return -ENOMEM;
+
+	hcd->rsrc_start = res->start;
+	hcd->rsrc_len = resource_size(res);
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
+				driver->description)) {
+		dev_dbg(&pdev->dev, "controller already in use\n");
+		ret = -EBUSY;
+		goto put_hcd;
+	}
+
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		dev_dbg(&pdev->dev, "error mapping memory\n");
+		ret = -EFAULT;
+		goto release_mem_region;
+	}
+#if 1
+	writel(readl(hcd->regs + 0xc200) & 0x7FFFFFFF, hcd->regs + 0xc200);
+	writel(readl(hcd->regs + 0xc2c0) & 0x7FFFFFFF, hcd->regs + 0xc2c0);
+	writel(0x5Dc11000, hcd->regs + 0xc110);
+#endif
+
+	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
+	if (ret)
+		goto unmap_registers;
+
+	/* USB 2.0 roothub is stored in the platform_device now. */
+	hcd = dev_get_drvdata(&pdev->dev);
+	xhci = hcd_to_xhci(hcd);
+	xhci->shared_hcd = usb_create_shared_hcd(driver, &pdev->dev,
+			dev_name(&pdev->dev), hcd);
+	if (!xhci->shared_hcd) {
+		ret = -ENOMEM;
+		goto dealloc_usb2_hcd;
+	}
+
+	/*
+	 * Set the xHCI pointer before xhci_plat_setup() (aka hcd_driver.reset)
+	 * is called by usb_add_hcd().
+	 */
+	*((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci;
+
+	ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
+	if (ret)
+		goto put_usb3_hcd;
+
+	return 0;
+
+put_usb3_hcd:
+	usb_put_hcd(xhci->shared_hcd);
+
+dealloc_usb2_hcd:
+	usb_remove_hcd(hcd);
+
+unmap_registers:
+	iounmap(hcd->regs);
+
+release_mem_region:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+put_hcd:
+	usb_put_hcd(hcd);
+
+	return ret;
+}
+
+static int xhci_plat_remove(struct platform_device *dev)
+{
+	struct usb_hcd	*hcd = platform_get_drvdata(dev);
+	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
+
+	usb_remove_hcd(xhci->shared_hcd);
+	usb_put_hcd(xhci->shared_hcd);
+
+	usb_remove_hcd(hcd);
+	iounmap(hcd->regs);
+	usb_put_hcd(hcd);
+
+	/* Do the Platform specific shutdown */
+	comcerto_stop_xhci();
+
+	kfree(xhci);
+
+	return 0;
+}
+
+static struct platform_driver usb_xhci_driver = {
+	.probe	= xhci_plat_probe,
+	.remove	= xhci_plat_remove,
+	.driver	= {
+		.name = "xhci-hcd",
+	},
+};
+MODULE_ALIAS("platform:xhci-hcd");
+
+int xhci_register_plat(void)
+{
+	return platform_driver_register(&usb_xhci_driver);
+}
+
+void xhci_unregister_plat(void)
+{
+	platform_driver_unregister(&usb_xhci_driver);
+}
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index fb0981e..1e4b126 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -143,22 +143,26 @@
  * See Cycle bit rules. SW is the consumer for the event ring only.
  * Don't make a ring full of link TRBs.  That would be dumb and this would loop.
  */
-static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer)
+static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring)
 {
-	union xhci_trb *next = ++(ring->dequeue);
+	union xhci_trb *next;
 	unsigned long long addr;
 
 	ring->deq_updates++;
+
+	/* If this is not event ring, there is one more usable TRB */
+	if (ring->type != TYPE_EVENT &&
+			!last_trb(xhci, ring, ring->deq_seg, ring->dequeue))
+		ring->num_trbs_free++;
+	next = ++(ring->dequeue);
+
 	/* Update the dequeue pointer further if that was a link TRB or we're at
 	 * the end of an event ring segment (which doesn't have link TRBS)
 	 */
 	while (last_trb(xhci, ring, ring->deq_seg, next)) {
-		if (consumer && last_trb_on_last_seg(xhci, ring, ring->deq_seg, next)) {
+		if (ring->type == TYPE_EVENT &&	last_trb_on_last_seg(xhci,
+				ring, ring->deq_seg, next)) {
 			ring->cycle_state = (ring->cycle_state ? 0 : 1);
-			if (!in_interrupt())
-				xhci_dbg(xhci, "Toggle cycle state for ring %p = %i\n",
-						ring,
-						(unsigned int) ring->cycle_state);
 		}
 		ring->deq_seg = ring->deq_seg->next;
 		ring->dequeue = ring->deq_seg->trbs;
@@ -185,13 +189,17 @@
  *			prepare_transfer()?
  */
 static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
-		bool consumer, bool more_trbs_coming, bool isoc)
+			bool more_trbs_coming)
 {
 	u32 chain;
 	union xhci_trb *next;
 	unsigned long long addr;
 
 	chain = le32_to_cpu(ring->enqueue->generic.field[3]) & TRB_CHAIN;
+	/* If this is not event ring, there is one less usable TRB */
+	if (ring->type != TYPE_EVENT &&
+			!last_trb(xhci, ring, ring->enq_seg, ring->enqueue))
+		ring->num_trbs_free--;
 	next = ++(ring->enqueue);
 
 	ring->enq_updates++;
@@ -199,42 +207,38 @@
 	 * the end of an event ring segment (which doesn't have link TRBS)
 	 */
 	while (last_trb(xhci, ring, ring->enq_seg, next)) {
-		if (!consumer) {
-			if (ring != xhci->event_ring) {
-				/*
-				 * If the caller doesn't plan on enqueueing more
-				 * TDs before ringing the doorbell, then we
-				 * don't want to give the link TRB to the
-				 * hardware just yet.  We'll give the link TRB
-				 * back in prepare_ring() just before we enqueue
-				 * the TD at the top of the ring.
-				 */
-				if (!chain && !more_trbs_coming)
-					break;
+		if (ring->type != TYPE_EVENT) {
+			/*
+			 * If the caller doesn't plan on enqueueing more
+			 * TDs before ringing the doorbell, then we
+			 * don't want to give the link TRB to the
+			 * hardware just yet.  We'll give the link TRB
+			 * back in prepare_ring() just before we enqueue
+			 * the TD at the top of the ring.
+			 */
+			if (!chain && !more_trbs_coming)
+				break;
 
-				/* If we're not dealing with 0.95 hardware or
-				 * isoc rings on AMD 0.96 host,
-				 * carry over the chain bit of the previous TRB
-				 * (which may mean the chain bit is cleared).
-				 */
-				if (!(isoc && (xhci->quirks & XHCI_AMD_0x96_HOST))
+			/* If we're not dealing with 0.95 hardware or
+			 * isoc rings on AMD 0.96 host,
+			 * carry over the chain bit of the previous TRB
+			 * (which may mean the chain bit is cleared).
+			 */
+			if (!(ring->type == TYPE_ISOC &&
+					(xhci->quirks & XHCI_AMD_0x96_HOST))
 						&& !xhci_link_trb_quirk(xhci)) {
-					next->link.control &=
-						cpu_to_le32(~TRB_CHAIN);
-					next->link.control |=
-						cpu_to_le32(chain);
-				}
-				/* Give this link TRB to the hardware */
-				wmb();
-				next->link.control ^= cpu_to_le32(TRB_CYCLE);
+				next->link.control &=
+					cpu_to_le32(~TRB_CHAIN);
+				next->link.control |=
+					cpu_to_le32(chain);
 			}
+			/* Give this link TRB to the hardware */
+			wmb();
+			next->link.control ^= cpu_to_le32(TRB_CYCLE);
+
 			/* Toggle the cycle bit after the last ring segment. */
 			if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {
 				ring->cycle_state = (ring->cycle_state ? 0 : 1);
-				if (!in_interrupt())
-					xhci_dbg(xhci, "Toggle cycle state for ring %p = %i\n",
-							ring,
-							(unsigned int) ring->cycle_state);
 			}
 		}
 		ring->enq_seg = ring->enq_seg->next;
@@ -245,55 +249,23 @@
 }
 
 /*
- * Check to see if there's room to enqueue num_trbs on the ring.  See rules
- * above.
- * FIXME: this would be simpler and faster if we just kept track of the number
- * of free TRBs in a ring.
+ * Check to see if there's room to enqueue num_trbs on the ring and make sure
+ * enqueue pointer will not advance into dequeue segment. See rules above.
  */
-static int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring,
+static inline int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring,
 		unsigned int num_trbs)
 {
-	int i;
-	union xhci_trb *enq = ring->enqueue;
-	struct xhci_segment *enq_seg = ring->enq_seg;
-	struct xhci_segment *cur_seg;
-	unsigned int left_on_ring;
+	int num_trbs_in_deq_seg;
 
-	/* If we are currently pointing to a link TRB, advance the
-	 * enqueue pointer before checking for space */
-	while (last_trb(xhci, ring, enq_seg, enq)) {
-		enq_seg = enq_seg->next;
-		enq = enq_seg->trbs;
-	}
+	if (ring->num_trbs_free < num_trbs)
+		return 0;
 
-	/* Check if ring is empty */
-	if (enq == ring->dequeue) {
-		/* Can't use link trbs */
-		left_on_ring = TRBS_PER_SEGMENT - 1;
-		for (cur_seg = enq_seg->next; cur_seg != enq_seg;
-				cur_seg = cur_seg->next)
-			left_on_ring += TRBS_PER_SEGMENT - 1;
-
-		/* Always need one TRB free in the ring. */
-		left_on_ring -= 1;
-		if (num_trbs > left_on_ring) {
-			xhci_warn(xhci, "Not enough room on ring; "
-					"need %u TRBs, %u TRBs left\n",
-					num_trbs, left_on_ring);
+	if (ring->type != TYPE_COMMAND && ring->type != TYPE_EVENT) {
+		num_trbs_in_deq_seg = ring->dequeue - ring->deq_seg->trbs;
+		if (ring->num_trbs_free < num_trbs + num_trbs_in_deq_seg)
 			return 0;
-		}
-		return 1;
 	}
-	/* Make sure there's an extra empty TRB available */
-	for (i = 0; i <= num_trbs; ++i) {
-		if (enq == ring->dequeue)
-			return 0;
-		enq++;
-		while (last_trb(xhci, ring, enq_seg, enq)) {
-			enq_seg = enq_seg->next;
-			enq = enq_seg->trbs;
-		}
-	}
+
 	return 1;
 }
 
@@ -560,12 +532,9 @@
 					cpu_to_le32(TRB_CYCLE);
 			cur_trb->generic.field[3] |= cpu_to_le32(
 				TRB_TYPE(TRB_TR_NOOP));
-			xhci_dbg(xhci, "Cancel TRB %p (0x%llx dma) "
-					"in seg %p (0x%llx dma)\n",
-					cur_trb,
-					(unsigned long long)xhci_trb_virt_to_dma(cur_seg, cur_trb),
-					cur_seg,
-					(unsigned long long)cur_seg->dma);
+			xhci_dbg(xhci, "TRB to noop at offset 0x%llx\n",
+					(unsigned long long)
+					xhci_trb_virt_to_dma(cur_seg, cur_trb));
 		}
 		if (cur_trb == cur_td->last_trb)
 			break;
@@ -705,9 +674,9 @@
 	 */
 	list_for_each(entry, &ep->cancelled_td_list) {
 		cur_td = list_entry(entry, struct xhci_td, cancelled_td_list);
-		xhci_dbg(xhci, "Cancelling TD starting at %p, 0x%llx (dma).\n",
-				cur_td->first_trb,
-				(unsigned long long)xhci_trb_virt_to_dma(cur_td->start_seg, cur_td->first_trb));
+		xhci_dbg(xhci, "Removing canceled TD starting at 0x%llx (dma).\n",
+				(unsigned long long)xhci_trb_virt_to_dma(
+					cur_td->start_seg, cur_td->first_trb));
 		ep_ring = xhci_urb_to_transfer_ring(xhci, cur_td->urb);
 		if (!ep_ring) {
 			/* This shouldn't happen unless a driver is mucking
@@ -903,6 +872,43 @@
 	xhci_dbg(xhci, "xHCI host controller is dead.\n");
 }
 
+
+static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci,
+		struct xhci_virt_device *dev,
+		struct xhci_ring *ep_ring,
+		unsigned int ep_index)
+{
+	union xhci_trb *dequeue_temp;
+	int num_trbs_free_temp;
+	bool revert = false;
+
+	num_trbs_free_temp = ep_ring->num_trbs_free;
+	dequeue_temp = ep_ring->dequeue;
+
+	while (ep_ring->dequeue != dev->eps[ep_index].queued_deq_ptr) {
+		/* We have more usable TRBs */
+		ep_ring->num_trbs_free++;
+		ep_ring->dequeue++;
+		if (last_trb(xhci, ep_ring, ep_ring->deq_seg,
+				ep_ring->dequeue)) {
+			if (ep_ring->dequeue ==
+					dev->eps[ep_index].queued_deq_ptr)
+				break;
+			ep_ring->deq_seg = ep_ring->deq_seg->next;
+			ep_ring->dequeue = ep_ring->deq_seg->trbs;
+		}
+		if (ep_ring->dequeue == dequeue_temp) {
+			revert = true;
+			break;
+		}
+	}
+
+	if (revert) {
+		xhci_dbg(xhci, "Unable to find new dequeue pointer\n");
+		ep_ring->num_trbs_free = num_trbs_free_temp;
+	}
+}
+
 /*
  * When we get a completion for a Set Transfer Ring Dequeue Pointer command,
  * we need to clear the set deq pending flag in the endpoint ring state, so that
@@ -984,8 +990,8 @@
 			/* Update the ring's dequeue segment and dequeue pointer
 			 * to reflect the new position.
 			 */
-			ep_ring->deq_seg = dev->eps[ep_index].queued_deq_seg;
-			ep_ring->dequeue = dev->eps[ep_index].queued_deq_ptr;
+			update_ring_for_set_deq_completion(xhci, dev,
+				ep_ring, ep_index);
 		} else {
 			xhci_warn(xhci, "Mismatch between completed Set TR Deq "
 					"Ptr command & xHCI internal state.\n");
@@ -1196,7 +1202,7 @@
 		xhci->error_bitmask |= 1 << 6;
 		break;
 	}
-	inc_deq(xhci, xhci->cmd_ring, false);
+	inc_deq(xhci, xhci->cmd_ring);
 }
 
 static void handle_vendor_event(struct xhci_hcd *xhci,
@@ -1248,6 +1254,28 @@
 	return num_similar_speed_ports;
 }
 
+#if 0
+static void handle_device_notification(struct xhci_hcd *xhci,
+		union xhci_trb *event)
+{
+	u32 slot_id;
+	struct usb_device *udev;
+
+	slot_id = TRB_TO_SLOT_ID(event->generic.field[3]);
+	if (!xhci->devs[slot_id]) {
+		xhci_warn(xhci, "Device Notification event for "
+				"unused slot %u\n", slot_id);
+		return;
+	}
+
+	xhci_dbg(xhci, "Device Wake Notification event for slot ID %u\n",
+			slot_id);
+	udev = xhci->devs[slot_id]->udev;
+	if (udev && udev->parent)
+		usb_wakeup_notification(udev->parent, udev->portnum);
+}
+#endif
+
 static void handle_port_status(struct xhci_hcd *xhci,
 		union xhci_trb *event)
 {
@@ -1332,7 +1360,14 @@
 		}
 
 		if (DEV_SUPERSPEED(temp)) {
-			xhci_dbg(xhci, "resume SS port %d\n", port_id);
+			xhci_dbg(xhci, "remote wake SS port %d\n", port_id);
+			/* Set a flag to say the port signaled remote wakeup,
+			 * so we can tell the difference between the end of
+			 * device and host initiated resume.
+			 */
+			bus_state->port_remote_wakeup |= 1 << faked_port_index;
+			xhci_test_and_clear_bit(xhci, port_array,
+					faked_port_index, PORT_PLC);
 			xhci_set_link_state(xhci, port_array, faked_port_index,
 						XDEV_U0);
 			slot_id = xhci_find_slot_id_by_port(hcd, xhci,
@@ -1356,13 +1391,40 @@
 		}
 	}
 
+#if 0
+	if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_U0 &&
+			DEV_SUPERSPEED(temp)) {
+		xhci_dbg(xhci, "resume SS port %d finished\n", port_id);
+		/* We've just brought the device into U0 through either the
+		 * Resume state after a device remote wakeup, or through the
+		 * U3Exit state after a host-initiated resume.  If it's a device
+		 * initiated remote wake, don't pass up the link state change,
+		 * so the roothub behavior is consistent with external
+		 * USB 3.0 hub behavior.
+		 */
+		slot_id = xhci_find_slot_id_by_port(hcd, xhci,
+				faked_port_index + 1);
+		if (slot_id && xhci->devs[slot_id])
+			xhci_ring_device(xhci, slot_id);
+		if (bus_state->port_remote_wakeup && (1 << faked_port_index)) {
+			bus_state->port_remote_wakeup &=
+				~(1 << faked_port_index);
+			xhci_test_and_clear_bit(xhci, port_array,
+					faked_port_index, PORT_PLC);
+			usb_wakeup_notification(hcd->self.root_hub,
+					faked_port_index + 1);
+			bogus_port_status = true;
+			goto cleanup;
+		}
+	}
+#endif
 	if (hcd->speed != HCD_USB3)
 		xhci_test_and_clear_bit(xhci, port_array, faked_port_index,
 					PORT_PLC);
 
 cleanup:
 	/* Update event ring dequeue pointer before dropping the lock */
-	inc_deq(xhci, xhci->event_ring, true);
+	inc_deq(xhci, xhci->event_ring);
 
 	/* Don't make the USB core poll the roothub if we got a bad port status
 	 * change event.  Besides, at that point we can't tell which roothub
@@ -1557,8 +1619,8 @@
 		} else {
 			/* Update ring dequeue pointer */
 			while (ep_ring->dequeue != td->last_trb)
-				inc_deq(xhci, ep_ring, false);
-			inc_deq(xhci, ep_ring, false);
+				inc_deq(xhci, ep_ring);
+			inc_deq(xhci, ep_ring);
 		}
 
 td_cleanup:
@@ -1628,7 +1690,6 @@
 	ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
 	trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
 
-	xhci_debug_trb(xhci, xhci->event_ring->dequeue);
 	switch (trb_comp_code) {
 	case COMP_SUCCESS:
 		if (event_trb == ep_ring->dequeue) {
@@ -1644,7 +1705,6 @@
 		}
 		break;
 	case COMP_SHORT_TX:
-		xhci_warn(xhci, "WARN: short transfer on control ep\n");
 		if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
 			*status = -EREMOTEIO;
 		else
@@ -1813,8 +1873,8 @@
 
 	/* Update ring dequeue pointer */
 	while (ep_ring->dequeue != td->last_trb)
-		inc_deq(xhci, ep_ring, false);
-	inc_deq(xhci, ep_ring, false);
+		inc_deq(xhci, ep_ring);
+	inc_deq(xhci, ep_ring);
 
 	return finish_td(xhci, td, NULL, event, ep, status, true);
 }
@@ -1955,6 +2015,16 @@
 	xdev = xhci->devs[slot_id];
 	if (!xdev) {
 		xhci_err(xhci, "ERROR Transfer event pointed to bad slot\n");
+		xhci_err(xhci, "@%016llx %08x %08x %08x %08x\n",
+			 (unsigned long long) xhci_trb_virt_to_dma(
+				 xhci->event_ring->deq_seg,
+				 xhci->event_ring->dequeue),
+			 lower_32_bits(le64_to_cpu(event->buffer)),
+			 upper_32_bits(le64_to_cpu(event->buffer)),
+			 le32_to_cpu(event->transfer_len),
+			 le32_to_cpu(event->flags));
+		xhci_dbg(xhci, "Event ring:\n");
+		xhci_debug_segment(xhci, xhci->event_ring->deq_seg);
 		return -ENODEV;
 	}
 
@@ -1968,6 +2038,16 @@
 	    EP_STATE_DISABLED) {
 		xhci_err(xhci, "ERROR Transfer event for disabled endpoint "
 				"or incorrect stream ring\n");
+		xhci_err(xhci, "@%016llx %08x %08x %08x %08x\n",
+			 (unsigned long long) xhci_trb_virt_to_dma(
+				 xhci->event_ring->deq_seg,
+				 xhci->event_ring->dequeue),
+			 lower_32_bits(le64_to_cpu(event->buffer)),
+			 upper_32_bits(le64_to_cpu(event->buffer)),
+			 le32_to_cpu(event->transfer_len),
+			 le32_to_cpu(event->flags));
+		xhci_dbg(xhci, "Event ring:\n");
+		xhci_debug_segment(xhci, xhci->event_ring->deq_seg);
 		return -ENODEV;
 	}
 
@@ -2001,7 +2081,7 @@
 		xhci_dbg(xhci, "Stopped on No-op or Link TRB\n");
 		break;
 	case COMP_STALL:
-		xhci_warn(xhci, "WARN: Stalled endpoint\n");
+		xhci_dbg(xhci, "Stalled endpoint\n");
 		ep->ep_state |= EP_HALTED;
 		status = -EPIPE;
 		break;
@@ -2011,11 +2091,11 @@
 		break;
 	case COMP_SPLIT_ERR:
 	case COMP_TX_ERR:
-		xhci_warn(xhci, "WARN: transfer error on endpoint\n");
+		xhci_dbg(xhci, "Transfer error on endpoint\n");
 		status = -EPROTO;
 		break;
 	case COMP_BABBLE:
-		xhci_warn(xhci, "WARN: babble error on endpoint\n");
+		xhci_dbg(xhci, "Babble error on endpoint\n");
 		status = -EOVERFLOW;
 		break;
 	case COMP_DB_ERR:
@@ -2191,7 +2271,7 @@
 		 * Will roll back to continue process missed tds.
 		 */
 		if (trb_comp_code == COMP_MISSED_INT || !ep->skip) {
-			inc_deq(xhci, xhci->event_ring, true);
+			inc_deq(xhci, xhci->event_ring);
 		}
 
 		if (ret) {
@@ -2285,6 +2365,11 @@
 		else
 			update_ptrs = 0;
 		break;
+#if 0
+	case TRB_TYPE(TRB_DEV_NOTE):
+		handle_device_notification(xhci, event);
+		break;
+#endif
 	default:
 		if ((le32_to_cpu(event->event_cmd.flags) & TRB_TYPE_BITMASK) >=
 		    TRB_TYPE(48))
@@ -2303,7 +2388,7 @@
 
 	if (update_ptrs)
 		/* Update SW event ring dequeue pointer */
-		inc_deq(xhci, xhci->event_ring, true);
+		inc_deq(xhci, xhci->event_ring);
 
 	/* Are there more items on the event ring?  Caller will call us again to
 	 * check.
@@ -2354,7 +2439,7 @@
 	/* FIXME when MSI-X is supported and there are multiple vectors */
 	/* Clear the MSI-X event interrupt status */
 
-	if (hcd->irq != -1) {
+	if (hcd->irq) {
 		u32 irq_pending;
 		/* Acknowledge the PCI interrupt */
 		irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending);
@@ -2406,17 +2491,7 @@
 
 irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd)
 {
-	irqreturn_t ret;
-	struct xhci_hcd *xhci;
-
-	xhci = hcd_to_xhci(hcd);
-	set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
-	if (xhci->shared_hcd)
-		set_bit(HCD_FLAG_SAW_IRQ, &xhci->shared_hcd->flags);
-
-	ret = xhci_irq(hcd);
-
-	return ret;
+	return xhci_irq(hcd);
 }
 
 /****		Endpoint Ring Operations	****/
@@ -2429,7 +2504,7 @@
  *			prepare_transfer()?
  */
 static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
-		bool consumer, bool more_trbs_coming, bool isoc,
+		bool more_trbs_coming,
 		u32 field1, u32 field2, u32 field3, u32 field4)
 {
 	struct xhci_generic_trb *trb;
@@ -2439,7 +2514,7 @@
 	trb->field[1] = cpu_to_le32(field2);
 	trb->field[2] = cpu_to_le32(field3);
 	trb->field[3] = cpu_to_le32(field4);
-	inc_enq(xhci, ring, consumer, more_trbs_coming, isoc);
+	inc_enq(xhci, ring, more_trbs_coming);
 }
 
 /*
@@ -2447,8 +2522,10 @@
  * FIXME allocate segments if the ring is full.
  */
 static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
-		u32 ep_state, unsigned int num_trbs, bool isoc, gfp_t mem_flags)
+		u32 ep_state, unsigned int num_trbs, gfp_t mem_flags)
 {
+	unsigned int num_trbs_needed;
+
 	/* Make sure the endpoint has been added to xHC schedule */
 	switch (ep_state) {
 	case EP_STATE_DISABLED:
@@ -2476,11 +2553,25 @@
 		 */
 		return -EINVAL;
 	}
-	if (!room_on_ring(xhci, ep_ring, num_trbs)) {
-		/* FIXME allocate more room */
-		xhci_err(xhci, "ERROR no room on ep ring\n");
-		return -ENOMEM;
-	}
+
+	while (1) {
+		if (room_on_ring(xhci, ep_ring, num_trbs))
+			break;
+
+		if (ep_ring == xhci->cmd_ring) {
+			xhci_err(xhci, "Do not support expand command ring\n");
+			return -ENOMEM;
+		}
+
+		xhci_dbg(xhci, "ERROR no room on ep ring, "
+					"try ring expansion\n");
+		num_trbs_needed = num_trbs - ep_ring->num_trbs_free;
+		if (xhci_ring_expansion(xhci, ep_ring, num_trbs_needed,
+					mem_flags)) {
+			xhci_err(xhci, "Ring expansion failed\n");
+			return -ENOMEM;
+		}
+	};
 
 	if (enqueue_is_link_trb(ep_ring)) {
 		struct xhci_ring *ring = ep_ring;
@@ -2492,8 +2583,9 @@
 			/* If we're not dealing with 0.95 hardware or isoc rings
 			 * on AMD 0.96 host, clear the chain bit.
 			 */
-			if (!xhci_link_trb_quirk(xhci) && !(isoc &&
-					(xhci->quirks & XHCI_AMD_0x96_HOST)))
+			if (!xhci_link_trb_quirk(xhci) &&
+					!(ring->type == TYPE_ISOC &&
+					 (xhci->quirks & XHCI_AMD_0x96_HOST)))
 				next->link.control &= cpu_to_le32(~TRB_CHAIN);
 			else
 				next->link.control |= cpu_to_le32(TRB_CHAIN);
@@ -2504,11 +2596,6 @@
 			/* Toggle the cycle bit after the last ring segment. */
 			if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {
 				ring->cycle_state = (ring->cycle_state ? 0 : 1);
-				if (!in_interrupt()) {
-					xhci_dbg(xhci, "queue_trb: Toggle cycle "
-						"state for ring %p = %i\n",
-						ring, (unsigned int)ring->cycle_state);
-				}
 			}
 			ring->enq_seg = ring->enq_seg->next;
 			ring->enqueue = ring->enq_seg->trbs;
@@ -2526,7 +2613,6 @@
 		unsigned int num_trbs,
 		struct urb *urb,
 		unsigned int td_index,
-		bool isoc,
 		gfp_t mem_flags)
 {
 	int ret;
@@ -2544,7 +2630,7 @@
 
 	ret = prepare_ring(xhci, ep_ring,
 			   le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK,
-			   num_trbs, isoc, mem_flags);
+			   num_trbs, mem_flags);
 	if (ret)
 		return ret;
 
@@ -2580,10 +2666,8 @@
 	num_sgs = urb->num_mapped_sgs;
 	temp = urb->transfer_buffer_length;
 
-	xhci_dbg(xhci, "count sg list trbs: \n");
 	num_trbs = 0;
 	for_each_sg(urb->sg, sg, num_sgs, i) {
-		unsigned int previous_total_trbs = num_trbs;
 		unsigned int len = sg_dma_len(sg);
 
 		/* Scatter gather list entries may cross 64KB boundaries */
@@ -2598,22 +2682,11 @@
 			num_trbs++;
 			running_total += TRB_MAX_BUFF_SIZE;
 		}
-		xhci_dbg(xhci, " sg #%d: dma = %#llx, len = %#x (%d), num_trbs = %d\n",
-				i, (unsigned long long)sg_dma_address(sg),
-				len, len, num_trbs - previous_total_trbs);
-
 		len = min_t(int, len, temp);
 		temp -= len;
 		if (temp == 0)
 			break;
 	}
-	xhci_dbg(xhci, "\n");
-	if (!in_interrupt())
-		xhci_dbg(xhci, "ep %#x - urb len = %d, sglist used, "
-				"num_trbs = %d\n",
-				urb->ep->desc.bEndpointAddress,
-				urb->transfer_buffer_length,
-				num_trbs);
 	return num_trbs;
 }
 
@@ -2687,7 +2760,7 @@
 				urb->dev->speed == USB_SPEED_FULL)
 			urb->interval /= 8;
 	}
-	return xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index);
+	return xhci_queue_bulk_tx(xhci, mem_flags, urb, slot_id, ep_index);
 }
 
 /*
@@ -2767,7 +2840,7 @@
 
 	trb_buff_len = prepare_transfer(xhci, xhci->devs[slot_id],
 			ep_index, urb->stream_id,
-			num_trbs, urb, 0, false, mem_flags);
+			num_trbs, urb, 0, mem_flags);
 	if (trb_buff_len < 0)
 		return trb_buff_len;
 
@@ -2799,8 +2872,6 @@
 	trb_buff_len = min_t(int, trb_buff_len, this_sg_len);
 	if (trb_buff_len > urb->transfer_buffer_length)
 		trb_buff_len = urb->transfer_buffer_length;
-	xhci_dbg(xhci, "First length to xfer from 1st sglist entry = %u\n",
-			trb_buff_len);
 
 	first_trb = true;
 	/* Queue the first TRB, even if it's zero-length */
@@ -2832,11 +2903,6 @@
 		if (usb_urb_dir_in(urb))
 			field |= TRB_ISP;
 
-		xhci_dbg(xhci, " sg entry: dma = %#x, len = %#x (%d), "
-				"64KB boundary at %#x, end dma = %#x\n",
-				(unsigned int) addr, trb_buff_len, trb_buff_len,
-				(unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1),
-				(unsigned int) addr + trb_buff_len);
 		if (TRB_MAX_BUFF_SIZE -
 				(addr & (TRB_MAX_BUFF_SIZE - 1)) < trb_buff_len) {
 			xhci_warn(xhci, "WARN: sg dma xfer crosses 64KB boundaries!\n");
@@ -2862,7 +2928,7 @@
 			more_trbs_coming = true;
 		else
 			more_trbs_coming = false;
-		queue_trb(xhci, ep_ring, false, more_trbs_coming, false,
+		queue_trb(xhci, ep_ring, more_trbs_coming,
 				lower_32_bits(addr),
 				upper_32_bits(addr),
 				length_field,
@@ -2942,18 +3008,9 @@
 	}
 	/* FIXME: this doesn't deal with URB_ZERO_PACKET - need one more */
 
-	if (!in_interrupt())
-		xhci_dbg(xhci, "ep %#x - urb len = %#x (%d), "
-				"addr = %#llx, num_trbs = %d\n",
-				urb->ep->desc.bEndpointAddress,
-				urb->transfer_buffer_length,
-				urb->transfer_buffer_length,
-				(unsigned long long)urb->transfer_dma,
-				num_trbs);
-
 	ret = prepare_transfer(xhci, xhci->devs[slot_id],
 			ep_index, urb->stream_id,
-			num_trbs, urb, 0, false, mem_flags);
+			num_trbs, urb, 0, mem_flags);
 	if (ret < 0)
 		return ret;
 
@@ -3025,7 +3082,7 @@
 			more_trbs_coming = true;
 		else
 			more_trbs_coming = false;
-		queue_trb(xhci, ep_ring, false, more_trbs_coming, false,
+		queue_trb(xhci, ep_ring, more_trbs_coming,
 				lower_32_bits(addr),
 				upper_32_bits(addr),
 				length_field,
@@ -3071,9 +3128,6 @@
 	if (!urb->setup_packet)
 		return -EINVAL;
 
-	if (!in_interrupt())
-		xhci_dbg(xhci, "Queueing ctrl tx for slot id %d, ep %d\n",
-				slot_id, ep_index);
 	/* 1 TRB for setup, 1 for status */
 	num_trbs = 2;
 	/*
@@ -3085,7 +3139,7 @@
 		num_trbs++;
 	ret = prepare_transfer(xhci, xhci->devs[slot_id],
 			ep_index, urb->stream_id,
-			num_trbs, urb, 0, false, mem_flags);
+			num_trbs, urb, 0, mem_flags);
 	if (ret < 0)
 		return ret;
 
@@ -3118,7 +3172,7 @@
 		}
 	}
 
-	queue_trb(xhci, ep_ring, false, true, false,
+	queue_trb(xhci, ep_ring, true,
 		  setup->bRequestType | setup->bRequest << 8 | le16_to_cpu(setup->wValue) << 16,
 		  le16_to_cpu(setup->wIndex) | le16_to_cpu(setup->wLength) << 16,
 		  TRB_LEN(8) | TRB_INTR_TARGET(0),
@@ -3138,7 +3192,7 @@
 	if (urb->transfer_buffer_length > 0) {
 		if (setup->bRequestType & USB_DIR_IN)
 			field |= TRB_DIR_IN;
-		queue_trb(xhci, ep_ring, false, true, false,
+		queue_trb(xhci, ep_ring, true,
 				lower_32_bits(urb->transfer_dma),
 				upper_32_bits(urb->transfer_dma),
 				length_field,
@@ -3154,7 +3208,7 @@
 		field = 0;
 	else
 		field = TRB_DIR_IN;
-	queue_trb(xhci, ep_ring, false, false, false,
+	queue_trb(xhci, ep_ring, false,
 			0,
 			0,
 			TRB_INTR_TARGET(0),
@@ -3265,15 +3319,6 @@
 		return -EINVAL;
 	}
 
-	if (!in_interrupt())
-		xhci_dbg(xhci, "ep %#x - urb len = %#x (%d),"
-				" addr = %#llx, num_tds = %d\n",
-				urb->ep->desc.bEndpointAddress,
-				urb->transfer_buffer_length,
-				urb->transfer_buffer_length,
-				(unsigned long long)urb->transfer_dma,
-				num_tds);
-
 	start_addr = (u64) urb->transfer_dma;
 	start_trb = &ep_ring->enqueue->generic;
 	start_cycle = ep_ring->cycle_state;
@@ -3303,8 +3348,7 @@
 		trbs_per_td = count_isoc_trbs_needed(xhci, urb, i);
 
 		ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index,
-				urb->stream_id, trbs_per_td, urb, i, true,
-				mem_flags);
+				urb->stream_id, trbs_per_td, urb, i, mem_flags);
 		if (ret < 0) {
 			if (i == 0)
 				return ret;
@@ -3374,7 +3418,7 @@
 				remainder |
 				TRB_INTR_TARGET(0);
 
-			queue_trb(xhci, ep_ring, false, more_trbs_coming, true,
+			queue_trb(xhci, ep_ring, more_trbs_coming,
 				lower_32_bits(addr),
 				upper_32_bits(addr),
 				length_field,
@@ -3421,6 +3465,7 @@
 	ep_ring->enqueue = urb_priv->td[0]->first_trb;
 	ep_ring->enq_seg = urb_priv->td[0]->start_seg;
 	ep_ring->cycle_state = start_cycle;
+	ep_ring->num_trbs_free = ep_ring->num_trbs_free_temp;
 	usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb);
 	return ret;
 }
@@ -3457,7 +3502,7 @@
 	 * Do not insert any td of the urb to the ring if the check failed.
 	 */
 	ret = prepare_ring(xhci, ep_ring, le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK,
-			   num_trbs, true, mem_flags);
+			   num_trbs, mem_flags);
 	if (ret)
 		return ret;
 
@@ -3493,7 +3538,9 @@
 				urb->dev->speed == USB_SPEED_FULL)
 			urb->interval /= 8;
 	}
-	return xhci_queue_isoc_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index);
+	ep_ring->num_trbs_free_temp = ep_ring->num_trbs_free;
+
+	return xhci_queue_isoc_tx(xhci, mem_flags, urb, slot_id, ep_index);
 }
 
 /****		Command Ring Operations		****/
@@ -3516,7 +3563,7 @@
 		reserved_trbs++;
 
 	ret = prepare_ring(xhci, xhci->cmd_ring, EP_STATE_RUNNING,
-			reserved_trbs, false, GFP_ATOMIC);
+			reserved_trbs, GFP_ATOMIC);
 	if (ret < 0) {
 		xhci_err(xhci, "ERR: No room for command on command ring\n");
 		if (command_must_succeed)
@@ -3524,8 +3571,8 @@
 					"unfailable commands failed.\n");
 		return ret;
 	}
-	queue_trb(xhci, xhci->cmd_ring, false, false, false, field1, field2,
-			field3,	field4 | xhci->cmd_ring->cycle_state);
+	queue_trb(xhci, xhci->cmd_ring, false, field1, field2, field3,
+			field4 | xhci->cmd_ring->cycle_state);
 	return 0;
 }
 
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 05f82e9..4acfe22 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -106,6 +106,9 @@
 			STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC);
 	if (!ret)
 		xhci->xhc_state |= XHCI_STATE_HALTED;
+	else
+		xhci_warn(xhci, "Host not halted after %u microseconds.\n",
+				XHCI_MAX_HALT_USEC);
 	return ret;
 }
 
@@ -200,14 +203,14 @@
 
 	ret = pci_enable_msi(pdev);
 	if (ret) {
-		xhci_err(xhci, "failed to allocate MSI entry\n");
+		xhci_dbg(xhci, "failed to allocate MSI entry\n");
 		return ret;
 	}
 
 	ret = request_irq(pdev->irq, (irq_handler_t)xhci_msi_irq,
 				0, "xhci_hcd", xhci_to_hcd(xhci));
 	if (ret) {
-		xhci_err(xhci, "disable MSI interrupt\n");
+		xhci_dbg(xhci, "disable MSI interrupt\n");
 		pci_disable_msi(pdev);
 	}
 
@@ -224,13 +227,13 @@
 	int ret;
 
 	/* return if using legacy interrupt */
-	if (xhci_to_hcd(xhci)->irq >= 0)
+	if (xhci_to_hcd(xhci)->irq > 0)
 		return;
 
 	ret = xhci_free_msi(xhci);
 	if (!ret)
 		return;
-	if (pdev->irq >= 0)
+	if (pdev->irq > 0)
 		free_irq(pdev->irq, xhci_to_hcd(xhci));
 
 	return;
@@ -270,7 +273,7 @@
 
 	ret = pci_enable_msix(pdev, xhci->msix_entries, xhci->msix_count);
 	if (ret) {
-		xhci_err(xhci, "Failed to enable MSI-X\n");
+		xhci_dbg(xhci, "Failed to enable MSI-X\n");
 		goto free_entries;
 	}
 
@@ -286,7 +289,7 @@
 	return ret;
 
 disable_msix:
-	xhci_err(xhci, "disable MSI-X interrupt\n");
+	xhci_dbg(xhci, "disable MSI-X interrupt\n");
 	xhci_free_irq(xhci);
 	pci_disable_msix(pdev);
 free_entries:
@@ -341,7 +344,7 @@
 	/* unregister the legacy interrupt */
 	if (hcd->irq)
 		free_irq(hcd->irq, hcd);
-	hcd->irq = -1;
+	hcd->irq = 0;
 
 	ret = xhci_setup_msix(xhci);
 	if (ret)
@@ -349,7 +352,7 @@
 		ret = xhci_setup_msi(xhci);
 
 	if (!ret)
-		/* hcd->irq is -1, we have MSI */
+		/* hcd->irq is 0, we have MSI */
 		return 0;
 
 	if (!pdev->irq) {
@@ -730,6 +733,7 @@
 	ring->enq_seg = ring->deq_seg;
 	ring->enqueue = ring->dequeue;
 
+	ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1;
 	/*
 	 * Ring is now zeroed, so the HW should look for change of ownership
 	 * when the cycle bit is set to 1.
@@ -1339,9 +1343,6 @@
 		goto done;
 	}
 
-	xhci_dbg(xhci, "Cancel URB %p\n", urb);
-	xhci_dbg(xhci, "Event ring:\n");
-	xhci_debug_ring(xhci, xhci->event_ring);
 	ep_index = xhci_get_endpoint_index(&urb->ep->desc);
 	ep = &xhci->devs[urb->dev->slot_id]->eps[ep_index];
 	ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
@@ -1350,12 +1351,18 @@
 		goto done;
 	}
 
-	xhci_dbg(xhci, "Endpoint ring:\n");
-	xhci_debug_ring(xhci, ep_ring);
-
 	urb_priv = urb->hcpriv;
+	i = urb_priv->td_cnt;
+	if (i < urb_priv->length)
+		xhci_dbg(xhci, "Cancel URB %p, dev %s, ep 0x%x, "
+				"starting at offset 0x%llx\n",
+				urb, urb->dev->devpath,
+				urb->ep->desc.bEndpointAddress,
+				(unsigned long long) xhci_trb_virt_to_dma(
+					urb_priv->td[i]->start_seg,
+					urb_priv->td[i]->first_trb));
 
-	for (i = urb_priv->td_cnt; i < urb_priv->length; i++) {
+	for (; i < urb_priv->length; i++) {
 		td = urb_priv->td[i];
 		list_add_tail(&td->cancelled_td_list, &ep->cancelled_td_list);
 	}
@@ -3612,26 +3619,38 @@
 	3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000};
 
 /* Calculate HIRD/BESL for USB2 PORTPMSC*/
-static int xhci_calculate_hird_besl(int u2del, bool use_besl)
+static int xhci_calculate_hird_besl(struct xhci_hcd *xhci,
+					struct usb_device *udev)
 {
-	int hird;
+	int u2del, besl, besl_host;
+	int besl_device = 0;
+	u32 field;
 
-	if (use_besl) {
-		for (hird = 0; hird < 16; hird++) {
-			if (xhci_besl_encoding[hird] >= u2del)
+	u2del = HCS_U2_LATENCY(xhci->hcs_params3);
+	field = le32_to_cpu(udev->bos->ext_cap->bmAttributes);
+
+	if (field & USB_BESL_SUPPORT) {
+		for (besl_host = 0; besl_host < 16; besl_host++) {
+			if (xhci_besl_encoding[besl_host] >= u2del)
 				break;
 		}
+		/* Use baseline BESL value as default */
+		if (field & USB_BESL_BASELINE_VALID)
+			besl_device = USB_GET_BESL_BASELINE(field);
+		else if (field & USB_BESL_DEEP_VALID)
+			besl_device = USB_GET_BESL_DEEP(field);
 	} else {
 		if (u2del <= 50)
-			hird = 0;
+			besl_host = 0;
 		else
-			hird = (u2del - 51) / 75 + 1;
-
-		if (hird > 15)
-			hird = 15;
+			besl_host = (u2del - 51) / 75 + 1;
 	}
 
-	return hird;
+	besl = besl_host + besl_device;
+	if (besl > 15)
+		besl = 15;
+
+	return besl;
 }
 
 static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd,
@@ -3644,7 +3663,7 @@
 	u32		temp, dev_id;
 	unsigned int	port_num;
 	unsigned long	flags;
-	int		u2del, hird;
+	int		hird;
 	int		ret;
 
 	if (hcd->speed == HCD_USB3 || !xhci->sw_lpm_support ||
@@ -3690,12 +3709,7 @@
 	 * HIRD or BESL shoule be used. See USB2.0 LPM errata.
 	 */
 	pm_addr = port_array[port_num] + 1;
-	u2del = HCS_U2_LATENCY(xhci->hcs_params3);
-	if (le32_to_cpu(udev->bos->ext_cap->bmAttributes) & (1 << 2))
-		hird = xhci_calculate_hird_besl(u2del, 1);
-	else
-		hird = xhci_calculate_hird_besl(u2del, 0);
-
+	hird = xhci_calculate_hird_besl(xhci, udev);
 	temp = PORT_L1DS(udev->slot_id) | PORT_HIRD(hird);
 	xhci_writel(xhci, temp, pm_addr);
 
@@ -3774,7 +3788,7 @@
 	u32		temp;
 	unsigned int	port_num;
 	unsigned long	flags;
-	int		u2del, hird;
+	int		hird;
 
 	if (hcd->speed == HCD_USB3 || !xhci->hw_lpm_support ||
 			!udev->lpm_capable)
@@ -3797,11 +3811,7 @@
 	xhci_dbg(xhci, "%s port %d USB2 hardware LPM\n",
 			enable ? "enable" : "disable", port_num);
 
-	u2del = HCS_U2_LATENCY(xhci->hcs_params3);
-	if (le32_to_cpu(udev->bos->ext_cap->bmAttributes) & (1 << 2))
-		hird = xhci_calculate_hird_besl(u2del, 1);
-	else
-		hird = xhci_calculate_hird_besl(u2del, 0);
+	hird = xhci_calculate_hird_besl(xhci, udev);
 
 	if (enable) {
 		temp &= ~PORT_HIRD_MASK;
@@ -3962,7 +3972,8 @@
 	int			retval;
 	u32			temp;
 
-	hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2;
+	/* Accept arbitrarily long scatter-gather lists */
+	hcd->self.sg_tablesize = ~0;
 
 	if (usb_hcd_is_primary_hcd(hcd)) {
 		xhci = kzalloc(sizeof(struct xhci_hcd), GFP_KERNEL);
@@ -4057,6 +4068,11 @@
 		printk(KERN_DEBUG "Problem registering PCI driver.");
 		return retval;
 	}
+	retval = xhci_register_plat();
+	if (retval < 0) {
+		printk(KERN_DEBUG "Problem registering platform driver.");
+		goto unreg_pci;
+	}
 	/*
 	 * Check the compiler generated sizes of structures that must be laid
 	 * out in specific ways for hardware access.
@@ -4076,11 +4092,15 @@
 	BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8);
 	BUILD_BUG_ON(sizeof(struct xhci_doorbell_array) != 256*32/8);
 	return 0;
+unreg_pci:
+	xhci_unregister_pci();
+	return retval;
 }
 module_init(xhci_hcd_init);
 
 static void __exit xhci_hcd_cleanup(void)
 {
 	xhci_unregister_pci();
+	xhci_unregister_plat();
 }
 module_exit(xhci_hcd_cleanup);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 7a56805..ec29483 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1231,10 +1231,7 @@
 /* Allow two commands + a link TRB, along with any reserved command TRBs */
 #define MAX_RSVD_CMD_TRBS	(TRBS_PER_SEGMENT - 3)
 #define SEGMENT_SIZE		(TRBS_PER_SEGMENT*16)
-/* SEGMENT_SHIFT should be log2(SEGMENT_SIZE).
- * Change this if you change TRBS_PER_SEGMENT!
- */
-#define SEGMENT_SHIFT		10
+#define SEGMENT_SHIFT		(__ffs(SEGMENT_SIZE))
 /* TRB buffer pointers can't cross 64KB boundaries */
 #define TRB_MAX_BUFF_SHIFT		16
 #define TRB_MAX_BUFF_SIZE	(1 << TRB_MAX_BUFF_SHIFT)
@@ -1261,8 +1258,19 @@
 	int new_cycle_state;
 };
 
+enum xhci_ring_type {
+	TYPE_CTRL = 0,
+	TYPE_ISOC,
+	TYPE_BULK,
+	TYPE_INTR,
+	TYPE_STREAM,
+	TYPE_COMMAND,
+	TYPE_EVENT,
+};
+
 struct xhci_ring {
 	struct xhci_segment	*first_seg;
+	struct xhci_segment	*last_seg;
 	union  xhci_trb		*enqueue;
 	struct xhci_segment	*enq_seg;
 	unsigned int		enq_updates;
@@ -1277,6 +1285,10 @@
 	 */
 	u32			cycle_state;
 	unsigned int		stream_id;
+	unsigned int		num_segs;
+	unsigned int		num_trbs_free;
+	unsigned int		num_trbs_free_temp;
+	enum xhci_ring_type	type;
 	bool			last_td_was_short;
 };
 
@@ -1352,6 +1364,7 @@
 	/* ports suspend status arrays - max 31 ports for USB2, 15 for USB3 */
 	u32			port_c_suspend;
 	u32			suspended_ports;
+	u32			port_remote_wakeup;
 	unsigned long		resume_done[USB_MAXCHILDREN];
 };
 
@@ -1363,7 +1376,7 @@
 		return 1;
 }
 
-/* There is one ehci_hci structure per controller */
+/* There is one xhci_hcd structure per controller */
 struct xhci_hcd {
 	struct usb_hcd *main_hcd;
 	struct usb_hcd *shared_hcd;
@@ -1618,6 +1631,8 @@
 		struct usb_device *udev, struct usb_host_endpoint *ep,
 		gfp_t mem_flags);
 void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring);
+int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
+				unsigned int num_trbs, gfp_t flags);
 void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci,
 		struct xhci_virt_device *virt_dev,
 		unsigned int ep_index);
@@ -1657,6 +1672,17 @@
 static inline void xhci_unregister_pci(void) {}
 #endif
 
+#if defined(CONFIG_USB_XHCI_PLATFORM) \
+	|| defined(CONFIG_USB_XHCI_PLATFORM_MODULE)
+int xhci_register_plat(void);
+void xhci_unregister_plat(void);
+#else
+static inline int xhci_register_plat(void)
+{ return 0; }
+static inline void xhci_unregister_plat(void)
+{  }
+#endif
+
 /* xHCI host controller glue */
 typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
 void xhci_quiesce(struct xhci_hcd *xhci);
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 79fd606..ad7818a 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -343,6 +343,17 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called imx2_wdt.
 
+config COMCERTO_WATCHDOG
+	tristate "Comcerto Watchdog"
+	depends on ARCH_COMCERTO
+	help
+	  Say Y here if to include support for the watchdog timer in
+	  Comcerto device.
+
+	  This driver can be built as a module by choosing M.
+	  The module will be called comcerto_wdt
+
+
 # AVR32 Architecture
 
 config AT32AP700X_WDT
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index fe893e9..0ffbb99 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -53,6 +53,7 @@
 obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o
 obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
 obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
+obj-$(CONFIG_COMCERTO_WATCHDOG) += comcerto_wdt.o
 
 # AVR32 Architecture
 obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
diff --git a/drivers/watchdog/comcerto_wdt.c b/drivers/watchdog/comcerto_wdt.c
new file mode 100644
index 0000000..d89aeb2
--- /dev/null
+++ b/drivers/watchdog/comcerto_wdt.c
@@ -0,0 +1,406 @@
+/*
+ *  drivers/char/watchdog/comcerto_wdt.c
+ *
+ *  Copyright (C) 2004,2005,2013 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/watchdog.h>
+#include <linux/clk.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <mach/hardware.h>
+#include <mach/wdt.h>
+#include <mach/reset.h>
+
+#define WDT_NAME					"comcerto_wdt"
+#define WDT_DEFAULT_TIMEOUT				5
+#define WDT_MAX_TIMEOUT					(0xffffffff / COMCERTO_AHBCLK)
+
+static unsigned long COMCERTO_AHBCLK;
+static int wd_heartbeat = WDT_DEFAULT_TIMEOUT;
+static int nowayout = WATCHDOG_NOWAYOUT;
+static struct clk *clk_axi;
+
+module_param(wd_heartbeat, int, 0);
+MODULE_PARM_DESC(wd_heartbeat, "Watchdog heartbeat in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIMEOUT) ")");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+#endif
+
+static unsigned long comcerto_wdt_busy;
+static char expect_close;
+static spinlock_t wdt_lock;
+
+/*
+ * Inform whether the boot was caused by AXI watchdog or not.
+ * If the boot was caused by AXI WDT, the WD status is cleared from
+ * reset control register.
+ */
+static int comcerto_wdt_rst_status(void)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&wdt_lock, flags);
+
+	if(__raw_readl(GNRL_DEVICE_STATUS) & AXI_WD_RST_ACTIVATED) {
+		__raw_writel(WD_STATUS_CLR | __raw_readl(DEVICE_RST_CNTRL), DEVICE_RST_CNTRL);
+		ret = 1;
+	}
+
+	spin_unlock_irqrestore(&wdt_lock, flags);
+
+	return ret;
+}
+
+/*
+ * Set a new heartbeat value for the watchdog device. If the heartbeat value is
+ * incorrect we keep the old value and return -EINVAL. If successfull we return 0.
+ */
+static int comcerto_wdt_set_heartbeat(int t)
+{
+	if (t < 1 || t > WDT_MAX_TIMEOUT)
+		return -EINVAL;
+
+	wd_heartbeat = t;
+	return 0;
+}
+
+/*
+ * Write wd_heartbeat to high bound register.
+ */
+static void comcerto_wdt_set_timeout(void)
+{
+	__raw_writel(wd_heartbeat * COMCERTO_AHBCLK, COMCERTO_TIMER_WDT_HIGH_BOUND);
+}
+
+/*
+ * Disable the watchdog.
+ */
+static void comcerto_wdt_stop(void)
+{
+	unsigned long flags;
+	u32 wdt_control;
+
+	spin_lock_irqsave(&wdt_lock, flags);
+
+	wdt_control = __raw_readl(COMCERTO_TIMER_WDT_CONTROL);
+
+	__raw_writel(wdt_control & ~COMCERTO_TIMER_WDT_CONTROL_TIMER_ENABLE, COMCERTO_TIMER_WDT_CONTROL);
+
+	spin_unlock_irqrestore(&wdt_lock, flags);
+
+	comcerto_wdt_set_timeout();
+}
+
+/*
+ * Enable the watchdog.
+ */
+static void comcerto_wdt_start(void)
+{
+	unsigned long flags;
+	u32 wdt_control;
+
+	spin_lock_irqsave(&wdt_lock, flags);
+
+	wdt_control = __raw_readl(COMCERTO_TIMER_WDT_CONTROL);
+
+	__raw_writel(wdt_control | COMCERTO_TIMER_WDT_CONTROL_TIMER_ENABLE, COMCERTO_TIMER_WDT_CONTROL);
+
+	comcerto_rst_cntrl_set(AXI_WD_RST_EN);
+
+	spin_unlock_irqrestore(&wdt_lock, flags);
+}
+
+/*
+ * Disable WDT and:
+ * - set max. possible timeout to avoid reset, it can occur
+ * since current counter value could be bigger then
+ * high bound one at the moment
+ * Function is called once at start (while configuration),
+ * and it's safe not to disable/enable IRQs.
+ */
+static void comcerto_wdt_config(void)
+{
+	comcerto_wdt_stop();
+
+	__raw_writel(~0, COMCERTO_TIMER_WDT_HIGH_BOUND);			/* write max timout */
+}
+
+/*
+ * Watchdog device is opened, and watchdog starts running.
+ */
+static int comcerto_wdt_open(struct inode *inode, struct file *file)
+{
+	if (test_and_set_bit(0, &comcerto_wdt_busy))
+		return -EBUSY;
+
+	comcerto_wdt_set_timeout();
+	comcerto_wdt_start();
+
+	return nonseekable_open(inode, file);
+}
+
+/*
+ * Release the watchdog device.
+ * If CONFIG_WATCHDOG_NOWAYOUT is NOT defined and expect_close == 42
+ * i.e. magic char 'V' has been passed while write() then the watchdog
+ * is also disabled.
+ */
+static int comcerto_wdt_release(struct inode *inode, struct file *file)
+{
+	if (expect_close == 42) {
+		comcerto_wdt_stop();	/* disable the watchdog when file is closed */
+		clear_bit(0, &comcerto_wdt_busy);
+	} else {
+		printk(KERN_CRIT "%s: closed unexpectedly. WDT will not stop!\n", WDT_NAME);
+	}
+
+	expect_close = 0;
+	return 0;
+}
+
+/*
+ * Handle commands from user-space.
+ */
+static long comcerto_wdt_ioctl(struct file *file, uint cmd, ulong arg)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	int new_value;
+	int err;
+	static struct watchdog_info comcerto_wdt_info = {
+		.options = 	WDIOF_SETTIMEOUT |
+				WDIOF_MAGICCLOSE |
+				WDIOF_KEEPALIVEPING,
+		.firmware_version = 1,
+	};
+
+	switch(cmd) {
+	case WDIOC_KEEPALIVE:
+		comcerto_wdt_set_timeout();
+		break;
+
+	case WDIOC_GETSUPPORT:
+		strncpy(comcerto_wdt_info.identity, WDT_NAME, sizeof(comcerto_wdt_info.identity));
+		if (copy_to_user(argp, &comcerto_wdt_info, sizeof(comcerto_wdt_info)) != 0) {
+			err = -EFAULT;
+			goto err;
+		}
+		break;
+
+	case WDIOC_SETTIMEOUT:
+		if (get_user(new_value, p)) {
+			err = -EFAULT;
+			goto err;
+		}
+
+		if (comcerto_wdt_set_heartbeat(new_value)) {
+			err = -EINVAL;
+			goto err;
+		}
+
+		comcerto_wdt_set_timeout();
+
+		return put_user(wd_heartbeat, p);
+		break;
+
+	case WDIOC_GETTIMEOUT:
+		return put_user(wd_heartbeat, p);
+		break;
+
+	case WDIOC_GETSTATUS:
+		return put_user(0, p);
+		break;
+
+	case WDIOC_GETBOOTSTATUS:
+		return put_user(comcerto_wdt_rst_status(), p);
+		break;
+
+	case WDIOC_SETOPTIONS:
+		if (get_user(new_value, p)) {
+			err = -EFAULT;
+			goto err;
+		}
+
+		if (new_value & WDIOS_DISABLECARD)
+			comcerto_wdt_stop();
+
+		if (new_value & WDIOS_ENABLECARD)
+			comcerto_wdt_start();
+
+		break;
+
+	default:
+		err = -ENOIOCTLCMD;
+		goto err;
+		break;
+	}
+
+	return 0;
+
+err:
+	return err;
+}
+
+/*
+ * Pat the watchdog whenever device is written to.
+ */
+static ssize_t comcerto_wdt_write(struct file *file, const char *buf, size_t len, loff_t *ppos)
+{
+	if (len) {
+		if (!nowayout) {
+			size_t i;
+			char c;
+
+			/* in case it was set long ago */
+			expect_close = 0;
+
+			for (i = 0; i != len; i++) {
+				if (get_user(c, buf + i))
+					return -EFAULT;
+
+				if (c == 'V')
+					expect_close = 42;
+			}
+		}
+
+		comcerto_wdt_set_timeout();
+	}
+
+	return len;
+}
+
+static const struct file_operations comcerto_wdt_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.unlocked_ioctl	= comcerto_wdt_ioctl,
+	.open		= comcerto_wdt_open,
+	.release	= comcerto_wdt_release,
+	.write		= comcerto_wdt_write,
+};
+
+static struct miscdevice comcerto_wdt_miscdev = {
+	.minor		= WATCHDOG_MINOR,
+	.name		= WDT_NAME,
+	.fops		= &comcerto_wdt_fops,
+};
+
+static int __init comcerto_wdt_probe(struct platform_device *pdev)
+{
+	int res;
+
+	if (comcerto_wdt_miscdev.parent)
+		return -EBUSY;
+
+	clk_axi = clk_get(NULL, "axi");
+
+	if (IS_ERR(clk_axi)){
+		pr_err("%s: Unable to obtain axi clock: %ld\n",__func__,PTR_ERR(clk_axi));
+		/* System cannot proceed from here */
+		BUG();
+	}
+
+	res = clk_enable(clk_axi);
+	if (res){
+		pr_err("%s: axi clock failed to enable:\n", __func__);
+		goto err_clk;
+	}
+
+	COMCERTO_AHBCLK = clk_get_rate(clk_axi);
+
+	comcerto_wdt_miscdev.parent = &pdev->dev;
+	comcerto_wdt_config();
+
+	res = misc_register(&comcerto_wdt_miscdev);
+	if (res)
+		goto err_misc;
+
+	printk(KERN_INFO "%s: support registered\n", WDT_NAME);
+
+        /* check that the heartbeat value is within range; if not reset to the default */
+        if (comcerto_wdt_set_heartbeat(wd_heartbeat)) {
+                comcerto_wdt_set_heartbeat(WDT_DEFAULT_TIMEOUT);
+
+                printk(KERN_INFO "%s: wd_heartbeat value is out of range: 1..%lu, using %d\n",
+                        WDT_NAME, WDT_MAX_TIMEOUT, WDT_DEFAULT_TIMEOUT);
+        }
+
+	return 0;
+
+err_misc:
+	clk_disable(clk_axi);
+err_clk:
+	clk_put(clk_axi);
+
+	return res;
+}
+
+static int __exit comcerto_wdt_remove(struct platform_device *pdev)
+{
+	int res;
+
+
+	clk_disable(clk_axi);
+	clk_put(clk_axi);
+	res = misc_deregister(&comcerto_wdt_miscdev);
+	if (!res)
+		comcerto_wdt_miscdev.parent = NULL;
+
+	return res;
+}
+
+static struct platform_driver comcerto_wdt_driver = {
+	.probe		= comcerto_wdt_probe,
+	.remove		= __exit_p(comcerto_wdt_remove),
+	.driver		= {
+		.name	= WDT_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init comcerto_wdt_init(void)
+{
+        spin_lock_init(&wdt_lock);
+
+	return platform_driver_register(&comcerto_wdt_driver);
+}
+
+static void __exit comcerto_wdt_exit(void)
+{
+	platform_driver_unregister(&comcerto_wdt_driver);
+}
+
+module_init(comcerto_wdt_init);
+module_exit(comcerto_wdt_exit);
+
+MODULE_AUTHOR("Mindspeed Technologies, Inc.");
+MODULE_DESCRIPTION("Watchdog driver for Comcerto 2000 devices");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 97fbe93..a6a9129 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -30,6 +30,16 @@
 #include <linux/statfs.h>
 #include <linux/compat.h>
 #include <linux/slab.h>
+
+#if defined(CONFIG_COMCERTO_IMPROVED_SPLICE)
+#include <linux/socket.h>
+#include <net/sock.h>
+#include <linux/net.h>
+#if defined(CONFIG_COMCERTO_SPLICE_USE_MDMA)
+#include <mach/hardware.h>
+#endif
+#endif
+
 #include "ctree.h"
 #include "disk-io.h"
 #include "transaction.h"
@@ -1718,6 +1728,173 @@
 	return ret;
 }
 
+#if defined(CONFIG_COMCERTO_IMPROVED_SPLICE)
+static ssize_t btrfs_splice_from_socket(struct file *file, struct socket *sock,
+					loff_t __user *ppos, size_t count)
+{
+	struct inode *inode = fdentry(file)->d_inode;
+	struct btrfs_root *root = BTRFS_I(inode)->root;
+	struct page **pages = NULL;
+	struct kvec *iov = NULL;
+	struct msghdr msg;
+	long recvtimeo;
+	ssize_t copied = 0;
+	size_t offset, offset_tmp;
+	int num_pages, dirty_pages;
+	int err = 0;
+	loff_t start_pos;
+	loff_t pos = file->f_pos;
+	int i;
+	unsigned count_tmp = count;
+
+#define ERROR_OUT do {mutex_unlock(&inode->i_mutex); goto out;} while(0)
+
+	if (!count)
+		return 0;
+
+	if (ppos && copy_from_user(&pos, ppos, sizeof pos))
+		return -EFAULT;
+	offset = pos & (PAGE_CACHE_SIZE - 1);
+	num_pages = (offset + count + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+#if defined(CONFIG_COMCERTO_SPLICE_USE_MDMA)
+	if (num_pages > MDMA_OUTBOUND_BUF_DESC)
+		ERROR_OUT;
+#endif
+	start_pos = round_down(pos, root->sectorsize);
+
+	if (!(pages = kmalloc(num_pages * sizeof(struct page *), GFP_KERNEL)) ||
+		!(iov = kmalloc(num_pages * sizeof(*iov), GFP_KERNEL)))
+		ERROR_OUT;
+
+	vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
+	current->backing_dev_info = inode->i_mapping->backing_dev_info;
+
+	mutex_lock(&inode->i_mutex);
+
+	if ((err = generic_write_checks(file, &pos, &count,
+					S_ISBLK(inode->i_mode))))
+		ERROR_OUT;
+
+	if ((err = file_remove_suid(file)))
+		ERROR_OUT;
+
+	if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) {
+                err = -EROFS;
+		ERROR_OUT;
+	}
+
+	if ((err = btrfs_update_time(file)))
+		ERROR_OUT;
+
+	BTRFS_I(inode)->sequence++;
+	if (start_pos > i_size_read(inode) &&
+		(err = btrfs_cont_expand(inode, i_size_read(inode), start_pos)))
+		ERROR_OUT;
+
+	if ((err = btrfs_delalloc_reserve_space(inode,
+					num_pages << PAGE_CACHE_SHIFT)))
+		goto out_free;
+
+	if ((err = prepare_pages(root, file, pages, num_pages,
+					pos, pos >> PAGE_CACHE_SHIFT,
+					count, false))) {
+		btrfs_delalloc_release_space(inode,
+					num_pages << PAGE_CACHE_SHIFT);
+		goto out_free;
+	}
+
+	for (i = 0, offset_tmp = offset; i < num_pages; i++) {
+		unsigned bytes = PAGE_CACHE_SIZE - offset_tmp;
+
+		if (bytes > count_tmp)
+			bytes = count_tmp;
+		iov[i].iov_base = kmap(pages[i]) + offset_tmp;
+		iov[i].iov_len = bytes;
+		offset_tmp = 0;
+		count_tmp -= bytes;
+	}
+
+        /* IOV is ready, receive the date from socket now */
+	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
+	msg.msg_iov = (struct iovec *)&iov[0];
+	msg.msg_iovlen = num_pages;
+	msg.msg_control = NULL;
+	msg.msg_controllen = 0;
+	msg.msg_flags = MSG_KERNSPACE;
+
+	recvtimeo = sock->sk->sk_rcvtimeo;
+	sock->sk->sk_rcvtimeo = 8 * HZ;
+	copied = kernel_recvmsg(sock, &msg, iov, num_pages, count,
+                             MSG_WAITALL | MSG_NOCATCHSIG);
+	sock->sk->sk_rcvtimeo = recvtimeo;
+
+	if (copied < 0) {
+		err = copied;
+		copied = 0;
+	}
+
+	/* FIXME:
+	 * The following results in at least one dirty_page even for copied==0
+	 * unless offset==0, but otherwise the fir page would be corrupted
+	 * for an unknown reason.
+	 */
+	dirty_pages = (copied + offset + PAGE_CACHE_SIZE - 1) >>
+					PAGE_CACHE_SHIFT;
+
+	for (i = 0; i < num_pages; i++)
+		kunmap(pages[i]);
+	if (dirty_pages < num_pages) {
+		if (1||dirty_pages) {
+			spin_lock(&BTRFS_I(inode)->lock);
+			BTRFS_I(inode)->outstanding_extents++;
+			spin_unlock(&BTRFS_I(inode)->lock);
+		}
+		btrfs_delalloc_release_space(inode,
+                                        (num_pages - dirty_pages) <<
+                                        PAGE_CACHE_SHIFT);
+	}
+
+	if (dirty_pages) {
+		if ((err = btrfs_dirty_pages(root, inode, pages,
+					dirty_pages, pos, copied, NULL))) {
+			btrfs_delalloc_release_space(inode,
+					dirty_pages << PAGE_CACHE_SHIFT);
+			btrfs_drop_pages(pages, num_pages);
+			goto out_free;
+                }
+	}
+
+	btrfs_drop_pages(pages, num_pages);
+	cond_resched();
+
+	balance_dirty_pages_ratelimited_nr(inode->i_mapping, dirty_pages);
+	if (dirty_pages < (root->leafsize >> PAGE_CACHE_SHIFT) + 1)
+		btrfs_btree_balance_dirty(root, 1);
+
+	pos += copied;
+
+out_free:
+	mutex_unlock(&inode->i_mutex);
+
+	if (copied > 0) {
+		file->f_pos = pos;
+		if (ppos && copy_to_user(ppos, &pos, sizeof *ppos))
+			err = -EFAULT;
+	}
+
+	BTRFS_I(inode)->last_trans = root->fs_info->generation + 1;
+	if (copied > 0 || err == -EIOCBQUEUED)
+		err = generic_write_sync(file, pos, copied);
+out:
+	kfree(iov);
+	kfree(pages);
+	current->backing_dev_info = NULL;
+
+	return err ? err : copied;
+}
+#endif
+
 static int find_desired_extent(struct inode *inode, loff_t *offset, int origin)
 {
 	struct btrfs_root *root = BTRFS_I(inode)->root;
@@ -1879,6 +2056,9 @@
 	.write		= do_sync_write,
 	.aio_read       = generic_file_aio_read,
 	.splice_read	= generic_file_splice_read,
+#if defined(CONFIG_COMCERTO_IMPROVED_SPLICE)
+	.splice_from_socket	= btrfs_splice_from_socket,
+#endif
 	.aio_write	= btrfs_file_aio_write,
 	.mmap		= btrfs_file_mmap,
 	.open		= generic_file_open,
diff --git a/fs/exec.c b/fs/exec.c
index 160cd2f..47982f5 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -624,7 +624,7 @@
 		 * when the old and new regions overlap clear from new_end.
 		 */
 		free_pgd_range(&tlb, new_end, old_end, new_end,
-			vma->vm_next ? vma->vm_next->vm_start : 0);
+			vma->vm_next ? vma->vm_next->vm_start : mm->task_size);
 	} else {
 		/*
 		 * otherwise, clean from old_start; this is done to not touch
@@ -633,7 +633,7 @@
 		 * for the others its just a little faster.
 		 */
 		free_pgd_range(&tlb, old_start, old_end, new_end,
-			vma->vm_next ? vma->vm_next->vm_start : 0);
+			vma->vm_next ? vma->vm_next->vm_start : mm->task_size);
 	}
 	tlb_finish_mmu(&tlb, new_end, old_end);
 
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index cb70f18..d9ee0fd 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -243,7 +243,11 @@
 	.release	= ext4_release_file,
 	.fsync		= ext4_sync_file,
 	.splice_read	= generic_file_splice_read,
+#if defined(CONFIG_COMCERTO_IMPROVED_SPLICE)
+	.splice_write	= comcerto_file_splice_write,
+#else
 	.splice_write	= generic_file_splice_write,
+#endif
 	.fallocate	= ext4_fallocate,
 };
 
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index a071348..0a6eeff 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -3107,6 +3107,10 @@
 	ext4_group_t		i, ngroups = ext4_get_groups_count(sb);
 	int			s, j, count = 0;
 
+	if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_BIGALLOC))
+		return (ext4_bg_has_super(sb, grp) + ext4_bg_num_gdb(sb, grp) +
+			sbi->s_itb_per_group + 2);
+
 	first_block = le32_to_cpu(sbi->s_es->s_first_data_block) +
 		(grp * EXT4_BLOCKS_PER_GROUP(sb));
 	last_block = first_block + EXT4_BLOCKS_PER_GROUP(sb) - 1;
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 22764c7..0ffe61f 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -142,6 +142,7 @@
 	}
 	return ret;
 }
+EXPORT_SYMBOL(sys_dup);
 
 #define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME)
 
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c
index e3024ed..04109f9 100644
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -22,6 +22,10 @@
 
 #define DEFAULT_EMPTY_SCAN_SIZE 256
 
+#if defined CONFIG_MTD_NAND_COMCERTO
+#define BIT_FLIP_TOLERENCE	7
+#endif
+
 #define noisy_printk(noise, args...) do { \
 	if (*(noise)) { \
 		printk(KERN_NOTICE args); \
@@ -64,6 +68,17 @@
 		return DEFAULT_EMPTY_SCAN_SIZE;
 }
 
+#if defined CONFIG_MTD_NAND_COMCERTO
+static inline uint32_t count_zero_bits( uint32_t value) {
+	uint32_t num_zeros = 0;
+	size_t i;
+	for (i = 0; i < sizeof value; ++i, value >>= 1) {
+		if ((value & 1) == 0)
+			++num_zeros;
+	}
+}
+#endif
+
 static int file_dirty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
 {
 	int ret;
@@ -589,6 +604,34 @@
 		else
 			return BLK_STATE_ALLFF;	/* OK to erase if all blocks are like this */
 	}
+
+#if defined CONFIG_MTD_NAND_COMCERTO
+	else if (cleanmarkerfound) {
+			ofs = 0;
+			uint32_t num_zeros = 0;
+			while((ofs < max_ofs) && (num_zeros < BIT_FLIP_TOLERENCE)) {
+				if (!(*(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF))
+					num_zeros = count_zero_bits(*(uint32_t *)(&buf[ofs]));
+				ofs += 4;
+			}
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
+		if ((num_zeros < BIT_FLIP_TOLERENCE) && jffs2_cleanmarker_oob(c)) {
+			/* scan oob, take care of cleanmarker */
+			int ret = jffs2_check_oob_empty(c, jeb, cleanmarkerfound);
+			D2(printk(KERN_NOTICE "jffs2_check_oob_empty returned %d\n",ret));
+			switch (ret) {
+			case 0:		return cleanmarkerfound ? BLK_STATE_CLEANMARKER : BLK_STATE_ALLFF;
+			case 1: 	return BLK_STATE_ALLDIRTY;
+			default: 	return ret;
+			}
+		} else {
+			return BLK_STATE_ALLDIRTY;
+		}
+#endif
+
+	}
+#endif
+
 	if (ofs) {
 		D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset,
 			  jeb->offset + ofs));
diff --git a/fs/splice.c b/fs/splice.c
index 014fcb4..3b0d632 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -32,6 +32,11 @@
 #include <linux/security.h>
 #include <linux/gfp.h>
 #include <linux/socket.h>
+#include <linux/time.h>
+
+#include <net/sock.h>
+#include <linux/net.h>
+#include <linux/genalloc.h>
 
 /*
  * Attempt to steal a page from a pipe buffer. This should perhaps go into
@@ -335,7 +340,11 @@
 	/*
 	 * Lookup the (hopefully) full range of pages we need.
 	 */
+#ifdef CONFIG_COMCERTO_SPLICE_READ_NOCONTIG
+	spd.nr_pages = find_get_pages(mapping, index, nr_pages, spd.pages);
+#else
 	spd.nr_pages = find_get_pages_contig(mapping, index, nr_pages, spd.pages);
+#endif
 	index += spd.nr_pages;
 
 	/*
@@ -840,6 +849,380 @@
 }
 EXPORT_SYMBOL(splice_from_pipe_feed);
 
+
+#if defined(CONFIG_COMCERTO_IMPROVED_SPLICE)
+#if !defined(CONFIG_COMCERTO_SPLICE_USE_MDMA)
+#define MSPD_SPLICE_NUM_DMA		100
+#else
+#define MSPD_SPLICE_NUM_DMA		MDMA_OUTBOUND_BUF_DESC
+#endif
+
+#if defined(CONFIG_COMCERTO_SPLICE_PROF)
+unsigned int enable_splice_prof = 0;
+#endif
+
+int comcerto_splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_desc *sd)
+{
+	struct page **mspd_splice_pages;
+	void **mspd_splice_fsdata;
+	struct pipe_buffer *buf;
+	const struct pipe_buf_operations *ops;
+	int ret, ret2 = 0, remaining;
+	unsigned int curbuf, nrbufs, len, nrbufs_len, done;
+	loff_t pos, offset;
+	struct file *file = sd->u.file;
+	struct address_space *mapping = file->f_mapping;
+	struct page **page;
+	void **fsdata;
+	unsigned int size;
+#if !defined(CONFIG_COMCERTO_SPLICE_USE_MDMA)
+	unsigned int buf_len, buf_offset;
+	char *src, *dst;
+#else
+	struct comcerto_dma_sg *sg;
+#endif
+
+	size = (sizeof(struct page *) + sizeof(void *)) * MSPD_SPLICE_NUM_DMA;
+
+#if defined(CONFIG_COMCERTO_SPLICE_USE_MDMA)
+	size = ALIGN(size, 8) + sizeof(struct comcerto_dma_sg);
+#endif
+
+	mspd_splice_pages = kmalloc(size, GFP_KERNEL);
+	if (!mspd_splice_pages)
+		return -ENOMEM;
+
+	mspd_splice_fsdata = (void **)(mspd_splice_pages + MSPD_SPLICE_NUM_DMA);
+
+#if defined(CONFIG_COMCERTO_SPLICE_USE_MDMA)
+	sg = (struct comcerto_dma_sg *)(mspd_splice_fsdata + MSPD_SPLICE_NUM_DMA);
+	sg = PTR_ALIGN(sg, 8);
+#endif
+
+start:
+#if defined(CONFIG_COMCERTO_SPLICE_USE_MDMA)
+	comcerto_dma_sg_init(sg);
+#endif
+
+	//Compute length to transfer (in bytes), and make sure data is there
+	nrbufs_len = 0;
+	nrbufs = pipe->nrbufs;
+	curbuf = pipe->curbuf;
+	while (nrbufs) {
+		buf = pipe->bufs + curbuf;
+
+		ret = buf->ops->confirm(pipe, buf);
+		if (unlikely(ret)) {
+			printk(KERN_WARNING "%s: buf->ops->confirm() failed(%d)\n", __func__, ret);
+			if (ret == -ENODATA)
+				ret = 0;
+			goto err;
+		}
+
+#if defined(CONFIG_COMCERTO_SPLICE_USE_MDMA)
+		// Is there a risk of getting the same page more than once (several buffers in a single page)?
+		ret = comcerto_dma_sg_add_input(sg, page_address(buf->page) + buf->offset, buf->len, 0);
+		if (unlikely(ret)) {
+			printk(KERN_WARNING "%s: out of input bdescs\n", __func__);
+			break; //We will transfer what we could up to the previous buffer, based on nrbufs_len
+		}
+#endif
+
+		nrbufs_len += buf->len;
+
+		if (nrbufs_len > sd->total_len) {
+			nrbufs_len = sd->total_len;
+			break;
+		}
+
+		// - 2 because first and last pages could be almost empty depending on alignment
+		if (nrbufs_len > (MSPD_SPLICE_NUM_DMA - 2)*PAGE_CACHE_SIZE) {
+			nrbufs_len = (MSPD_SPLICE_NUM_DMA - 2)*PAGE_CACHE_SIZE;
+			break;
+		}
+		curbuf = (curbuf + 1) & (pipe->buffers - 1);
+		nrbufs--;
+	}
+
+	if (unlikely(nrbufs_len == 0)) {
+		printk(KERN_WARNING "%s: nrbufs_len == 0\n", __func__);
+		ret = 0;
+		goto err;
+	}
+
+//	printk("BLA nrbufs_len: %d\n", nrbufs_len);
+
+	/* Allocate as many destinations pages as needed.
+	 * First and last pages are likely not to be filled, but the ones in-between will.
+	 * If some allocations fail, finish the work on the allocated pages.
+	 */
+	page = &mspd_splice_pages[0];
+	fsdata = &mspd_splice_fsdata[0];
+
+	pos = sd->pos;
+	offset = pos & ~PAGE_CACHE_MASK;
+	len = nrbufs_len;
+
+	if (likely(len + offset > PAGE_CACHE_SIZE))
+		len = PAGE_CACHE_SIZE - offset;
+
+	ret = pagecache_write_begin(file, mapping, pos, len,
+			AOP_FLAG_UNINTERRUPTIBLE, page, fsdata);
+	if (unlikely(ret))
+		goto err;		// We failed early, so we still have an easy way out
+
+#if defined(CONFIG_COMCERTO_SPLICE_USE_MDMA)
+	comcerto_dma_sg_add_output(sg, page_address(*page) + offset, len, 1); //Don't check result since we should have at least one entry at this point
+#endif
+
+	pos += len;
+	remaining = nrbufs_len - len;
+	page++;
+	fsdata++;
+
+	while (remaining > PAGE_CACHE_SIZE) {
+		ret = pagecache_write_begin(file, mapping, pos, PAGE_CACHE_SIZE,
+				AOP_FLAG_UNINTERRUPTIBLE, page, fsdata);
+
+		if (unlikely(ret))
+			goto write_begin_done;
+
+#if defined(CONFIG_COMCERTO_SPLICE_USE_MDMA)
+		ret = comcerto_dma_sg_add_output(sg, page_address(*page), PAGE_CACHE_SIZE, 1);
+		if (unlikely(ret)) {
+			pagecache_write_end(file, mapping, pos, PAGE_CACHE_SIZE, 0, *page, *fsdata);
+			goto write_begin_done;
+		}
+#endif
+		pos += PAGE_CACHE_SIZE;
+		remaining -= PAGE_CACHE_SIZE;
+		page++;
+		fsdata++;
+	}
+
+	if (remaining) {
+		ret = pagecache_write_begin(file, mapping, pos, remaining,
+						AOP_FLAG_UNINTERRUPTIBLE, page, fsdata);
+
+		if (unlikely(ret))
+			goto write_begin_done;
+
+#if defined(CONFIG_COMCERTO_SPLICE_USE_MDMA)
+		ret = comcerto_dma_sg_add_output(sg, page_address(*page), remaining, 1);
+		if (unlikely(ret)) {
+			pagecache_write_end(file, mapping, pos, remaining, 0, *page, *fsdata);
+			goto write_begin_done;
+		}
+#endif
+		remaining = 0;
+	}
+
+write_begin_done:
+	// Couldn't allocate all pages or bdescs, so update the total length accordingly
+	if (unlikely(remaining))
+		nrbufs_len = nrbufs_len - remaining;
+
+	//Now do the copies
+#if defined(CONFIG_COMCERTO_SPLICE_USE_MDMA)
+
+	comcerto_dma_get();
+
+	comcerto_dma_sg_setup(sg, nrbufs_len);
+
+	comcerto_dma_start();
+	comcerto_dma_wait();
+	comcerto_dma_put();
+
+	comcerto_dma_sg_cleanup(sg, nrbufs_len);
+#else
+	remaining = nrbufs_len;
+	curbuf = pipe->curbuf;
+	buf = pipe->bufs + curbuf;
+	buf_len = buf->len;
+	buf_offset = buf->offset;
+	src = buf->ops->map(pipe, buf, 1);
+	pos = sd->pos;
+	offset = pos & ~PAGE_CACHE_MASK;
+	page = &mspd_splice_pages[0];
+	dst = kmap_atomic(*page, KM_USER1);
+
+	while (remaining) {
+		len = remaining;
+		if (len + offset > PAGE_CACHE_SIZE)
+			len = PAGE_CACHE_SIZE - offset;
+		if (len > buf_len)
+			len = buf_len;
+
+		memcpy(dst + offset, src + buf_offset, len);
+
+		buf_len -= len;
+		buf_offset += len;
+		remaining -= len;
+		pos += len;
+		offset = pos & ~PAGE_CACHE_MASK;
+
+		if (!offset) {
+			/* FIXME if this was the last page we should still flush/unmap, even if it's not a full page */
+			/* ... actually it looks ok, the unmap is done outside the loop */
+			flush_dcache_page(*page);
+			kunmap_atomic(dst, KM_USER1);
+			if (remaining) {
+				page++;
+				dst = kmap_atomic(*page, KM_USER1);
+			}
+		}
+
+		if (!buf_len) {
+			buf->ops->unmap(pipe, buf, src);
+			if (remaining) {
+				curbuf = (curbuf + 1) & (pipe->buffers - 1);
+				buf = pipe->bufs + curbuf;
+				buf_len = buf->len;
+				buf_offset = buf->offset;
+				src = buf->ops->map(pipe, buf, 1);
+			}
+		}
+	}
+
+	if (offset) {
+		flush_dcache_page(*page);
+		kunmap_atomic(dst, KM_USER1);
+	}
+
+	if (buf_len)
+		buf->ops->unmap(pipe, buf, src);
+#endif
+
+
+	//loop on write_end, update sd fields
+	page = &mspd_splice_pages[0];
+	fsdata = &mspd_splice_fsdata[0];
+	offset = sd->pos & ~PAGE_CACHE_MASK;
+	pos = sd->pos;
+	remaining = nrbufs_len;
+	len = nrbufs_len;
+	done = 0;
+
+	if (likely(len + offset > PAGE_CACHE_SIZE))
+		len = PAGE_CACHE_SIZE - offset;
+
+	ret = pagecache_write_end(file, mapping, pos, len, len,
+			*page, *fsdata);
+
+	/* In case of error or short write we need to report error to the caller */
+	/* If there was already a previous error, just continue doing the pagecache_write_end() cleanup */
+	/* Otherwise keep track of how many bytes we have succefully written and that an error happened */
+	if (unlikely(ret != len)) {
+		printk(KERN_ERR "Failed on write_end, continuing with other buffers\n");
+
+		/* Only report error to caller if nothing has been done */
+		ret2 = ret;
+		nrbufs_len = (ret > 0) ? ret: 0;
+	}
+
+	pos += len;
+	done += len;
+	remaining -= len;
+
+	page++;
+	fsdata++;
+
+	while (remaining > PAGE_CACHE_SIZE) {
+		ret = pagecache_write_end(file, mapping, pos, PAGE_CACHE_SIZE, PAGE_CACHE_SIZE,
+				*page, *fsdata);
+
+		if (unlikely((ret != PAGE_CACHE_SIZE) && !ret2)) {
+			printk(KERN_ERR "Failed on write_end, continuing with other buffers\n");
+
+			nrbufs_len = done;
+
+			if (ret >= 0)
+				nrbufs_len += ret;
+
+			ret2 = nrbufs_len;
+		}
+
+		pos += PAGE_CACHE_SIZE;
+		done += PAGE_CACHE_SIZE;
+		remaining -= PAGE_CACHE_SIZE;
+
+		page++;
+		fsdata++;
+	}
+
+	if (remaining) {
+		ret = pagecache_write_end(file, mapping, pos, remaining, remaining,
+					*page, *fsdata);
+
+		if (unlikely((ret != remaining) && !ret2)) {
+			printk(KERN_ERR "Failed on write_end, continuing with other buffers\n");
+
+			nrbufs_len = done;
+
+			if (ret >= 0)
+				nrbufs_len += ret;
+
+			ret2 = nrbufs_len;
+		}
+	}
+
+	sd->num_spliced += nrbufs_len;
+	sd->len -= nrbufs_len;
+	sd->pos += nrbufs_len;
+	sd->total_len -= nrbufs_len;
+
+	//loop on pipe buffers to release them
+	remaining = nrbufs_len;
+	buf = pipe->bufs + pipe->curbuf;
+
+	while (remaining && (remaining >= buf->len)) {
+		ops = buf->ops;
+
+		remaining -= buf->len;
+		buf->len = 0;
+		buf->ops = NULL;
+		ops->release(pipe, buf);
+		pipe->nrbufs--;
+		pipe->curbuf = (pipe->curbuf + 1) & (pipe->buffers - 1);
+		buf = pipe->bufs + pipe->curbuf;
+	}
+
+	// Last buffer, might not be empty
+	if (remaining) {
+		buf->len -= remaining;
+		buf->offset += remaining;
+	}
+
+	if (pipe->inode)
+		sd->need_wakeup = true;
+
+	if (!sd->total_len) {
+		kfree(mspd_splice_pages);
+		return 0;
+	}
+
+	if (ret2) {
+		if (ret2 > 0)
+			ret = 0;
+		else
+			ret = ret2;
+
+		goto err;
+	}
+
+	if (pipe->nrbufs)
+		goto start;
+
+	ret = 1;
+
+err:
+	kfree(mspd_splice_pages);
+
+	return ret;
+}
+EXPORT_SYMBOL(comcerto_splice_from_pipe_feed);
+#endif
+
 /**
  * splice_from_pipe_next - wait for some data to splice from
  * @pipe:	pipe to splice from
@@ -1042,6 +1425,113 @@
 
 EXPORT_SYMBOL(generic_file_splice_write);
 
+#if defined(CONFIG_COMCERTO_SPLICE_PROF)
+unsigned int splicew_time_counter[256];
+unsigned int splicew_reqtime_counter[256];
+unsigned int splicew_data_counter[256];
+static struct timeval last_splicew;
+unsigned int init_splicew_prof = 0;
+#endif
+
+#if defined(CONFIG_COMCERTO_IMPROVED_SPLICE)
+ssize_t
+comcerto_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
+			  loff_t *ppos, size_t len, unsigned int flags)
+{
+	struct address_space *mapping = out->f_mapping;
+	struct inode *inode = mapping->host;
+	struct splice_desc sd = {
+		.total_len = len,
+		.flags = flags,
+		.pos = *ppos,
+		.u.file = out,
+	};
+	ssize_t ret;
+#if defined(CONFIG_COMCERTO_SPLICE_PROF)
+	struct timeval now;
+	int diff_time_ms;
+#endif
+
+	pipe_lock(pipe);
+
+#if defined(CONFIG_COMCERTO_SPLICE_PROF)
+	if (enable_splice_prof) {
+		do_gettimeofday(&now);
+		if (init_splicew_prof) {
+			diff_time_ms = ((now.tv_sec - last_splicew.tv_sec) * 1000) + ((now.tv_usec - last_splicew.tv_usec) / 1000);
+			if (diff_time_ms < 1000) {
+				splicew_time_counter[diff_time_ms >> 3]++;
+			}
+			else {
+				splicew_time_counter[255]++;
+			}
+		}
+		last_splicew = now;
+		if (len < (1 <<21))
+			splicew_data_counter[(len >> 13) & 0xFF]++;
+		else
+			splicew_data_counter[255]++;
+	}
+#endif
+
+	splice_from_pipe_begin(&sd);
+	do {
+		ret = splice_from_pipe_next(pipe, &sd);
+		if (ret <= 0)
+			break;
+
+		mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
+		ret = file_remove_suid(out);
+		if (!ret) {
+			file_update_time(out);
+			ret = comcerto_splice_from_pipe_feed(pipe, &sd);
+		}
+		mutex_unlock(&inode->i_mutex);
+	} while (ret > 0);
+	splice_from_pipe_end(pipe, &sd);
+
+	pipe_unlock(pipe);
+
+	if (sd.num_spliced)
+		ret = sd.num_spliced;
+
+	if (ret > 0) {
+		unsigned long nr_pages;
+		int err;
+
+		nr_pages = (ret + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+
+		err = generic_write_sync(out, *ppos, ret);
+		if (err)
+			ret = err;
+		else
+			*ppos += ret;
+		balance_dirty_pages_ratelimited_nr(mapping, nr_pages);
+	}
+
+#if defined(CONFIG_COMCERTO_SPLICE_PROF)
+	if (enable_splice_prof) {
+		do_gettimeofday(&now);
+		
+		diff_time_ms = ((now.tv_sec - last_splicew.tv_sec) * 1000) + ((now.tv_usec - last_splicew.tv_usec) / 1000);
+		if (diff_time_ms < 1000) {//Don't record useless data
+			splicew_reqtime_counter[diff_time_ms >> 3]++;
+		}
+		else
+			splicew_reqtime_counter[255]++;
+
+		if(!init_splicew_prof)
+			init_splicew_prof = 1;
+
+		last_splicew = now;
+	}
+#endif
+	return ret;
+}
+
+EXPORT_SYMBOL(comcerto_file_splice_write);
+#endif
+
 static int write_pipe_buf(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
 			  struct splice_desc *sd)
 {
@@ -1692,30 +2182,39 @@
 		int, fd_out, loff_t __user *, off_out,
 		size_t, len, unsigned int, flags)
 {
-	long error;
-	struct file *in, *out;
+	int error = -EBADF;
+	struct file *in, *out = NULL;
 	int fput_in, fput_out;
+	struct socket *sock = NULL;
 
 	if (unlikely(!len))
 		return 0;
 
-	error = -EBADF;
-	in = fget_light(fd_in, &fput_in);
-	if (in) {
-		if (in->f_mode & FMODE_READ) {
-			out = fget_light(fd_out, &fput_out);
-			if (out) {
-				if (out->f_mode & FMODE_WRITE)
-					error = do_splice(in, off_in,
-							  out, off_out,
-							  len, flags);
-				fput_light(out, fput_out);
-			}
-		}
+	if (!(out = fget_light(fd_out, &fput_out)))
+		return -EBADF;
 
+	if (!(out->f_mode & FMODE_WRITE))
+		goto out;
+
+	/* Check if fd_in is a socket while out_fd is NOT a pipe. */
+	if (!get_pipe_info(out) &&
+		(sock = sockfd_lookup(fd_in, &error))) {
+#if defined(CONFIG_COMCERTO_IMPROVED_SPLICE)
+		if (sock->sk && out->f_op->splice_from_socket)
+			error = out->f_op->splice_from_socket(out, sock,
+								off_out, len);
+#endif
+		fput(sock->file);
+	} else
+	{
+		if (!(in = fget_light(fd_in, &fput_in)))
+			goto out;
+		if ((in->f_mode & FMODE_READ))
+			error = do_splice(in, off_in, out, off_out, len, flags);
 		fput_light(in, fput_in);
 	}
-
+out:
+	fput_light(out, fput_out);
 	return error;
 }
 
@@ -1725,7 +2224,7 @@
  */
 static int ipipe_prep(struct pipe_inode_info *pipe, unsigned int flags)
 {
-	int ret;
+	int ret = 0;
 
 	/*
 	 * Check ->nrbufs without the inode lock first. This function
@@ -1734,7 +2233,6 @@
 	if (pipe->nrbufs)
 		return 0;
 
-	ret = 0;
 	pipe_lock(pipe);
 
 	while (!pipe->nrbufs) {
@@ -1763,7 +2261,7 @@
  */
 static int opipe_prep(struct pipe_inode_info *pipe, unsigned int flags)
 {
-	int ret;
+	int ret = 0;
 
 	/*
 	 * Check ->nrbufs without the inode lock first. This function
@@ -1772,7 +2270,6 @@
 	if (pipe->nrbufs < pipe->buffers)
 		return 0;
 
-	ret = 0;
 	pipe_lock(pipe);
 
 	while (pipe->nrbufs >= pipe->buffers) {
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
index b1038bd..a165ab8 100644
--- a/include/linux/backing-dev.h
+++ b/include/linux/backing-dev.h
@@ -108,6 +108,10 @@
 	struct dentry *debug_dir;
 	struct dentry *debug_stats;
 #endif
+
+#ifdef CONFIG_ARCH_M86XXX
+	unsigned int cpu0_bind;
+#endif
 };
 
 int bdi_init(struct backing_dev_info *bdi);
diff --git a/include/linux/bitops.h b/include/linux/bitops.h
index fc8a3ff..d756d92 100644
--- a/include/linux/bitops.h
+++ b/include/linux/bitops.h
@@ -26,6 +26,23 @@
 	     (bit) < (size); \
 	     (bit) = find_next_bit((addr), (size), (bit) + 1))
 
+/* same as for_each_set_bit() but use bit as value to start with */
+#define for_each_set_bit_from(bit, addr, size) \
+	for ((bit) = find_next_bit((addr), (size), (bit));      \
+		(bit) < (size);                                    \
+		(bit) = find_next_bit((addr), (size), (bit) + 1))
+
+#define for_each_clear_bit(bit, addr, size) \
+	for ((bit) = find_first_zero_bit((addr), (size));       \
+		(bit) < (size);                                    \
+		(bit) = find_next_zero_bit((addr), (size), (bit) + 1))
+
+/* same as for_each_clear_bit() but use bit as value to start with */
+#define for_each_clear_bit_from(bit, addr, size) \
+	for ((bit) = find_next_zero_bit((addr), (size), (bit)); \
+		(bit) < (size);                                    \
+		(bit) = find_next_zero_bit((addr), (size), (bit) + 1))
+		
 static __inline__ int get_bitmask_order(unsigned int count)
 {
 	int order;
diff --git a/include/linux/c2k-devfreq.h b/include/linux/c2k-devfreq.h
new file mode 100644
index 0000000..3fae95e
--- /dev/null
+++ b/include/linux/c2k-devfreq.h
@@ -0,0 +1,137 @@
+#ifndef _C2K_DEVFREQ_H
+#define _C2K_DEVFREQ_H
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/opp.h>
+#include <linux/devfreq.h>
+
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/jiffies.h>
+
+#define C2K_DEVFREQ_DEBUG
+#ifdef C2K_DEVFREQ_DEBUG
+        #define c2k_devfreq_debug(fmt, arg...)   printk(fmt, ##arg)
+#else
+        #define c2k_devfreq_debug(fmt, arg...)     ;
+#endif
+
+#define C2K_DEVFREQ_USE_KTIME
+typedef struct devfreq_perf_counters {
+#ifdef C2K_DEVFREQ_USE_KTIME
+	ktime_t fentry_time; /* ktime at the enrty of a func */
+	ktime_t start_time; /* starting ktime for every busy/total \
+			     load cal in the last x seconds*/
+	ktime_t prev_count; /* prev ktime count */
+	s64 busy_time; /* total execution ktime count in the last \
+			      x seconds */
+#else
+	unsigned long fentry_time; /* jiffies at the enrty of a func */
+	unsigned long start_time; /* starting jiffies for every busy/total \
+					     load cal in the last x seconds*/
+	unsigned long prev_count; /* last jiffies count */
+	unsigned long busy_time; /* total execution jiffies count in the last \
+				      x seconds */
+#endif
+}devfreq_counters;
+
+struct c2k_devfreq_opp_table {
+	unsigned int idx;
+	unsigned long freq; /* MHz */
+	unsigned long volt; /* uVolt */
+};
+
+struct c2k_devfreq_data{
+	devfreq_counters *dpc; 
+	struct device *dev; /* provided by driver */
+	struct regulator *vdd_int; /* if not provided by driver, use default */
+	struct opp *curr_opp;
+	struct notifier_block *pm_notifier; /* if not provided by driver, use default */
+	struct c2k_devfreq_opp_table *opp_table; /* provided by driver */
+	struct devfreq_dev_profile *devfreq_profile; /* provided by driver */
+	const struct devfreq_governor *gov; /* provided by driver */
+	struct clk *clk;
+	int (*set_freq)(struct c2k_devfreq_data *data, unsigned long *freq);
+
+	int disabled;
+	unsigned long max_freq;
+	unsigned long min_freq;
+	struct mutex lock;
+};
+
+#ifdef C2K_DEVFREQ_USE_KTIME
+/* using ktime */
+	#define devfreq_func_start(dc) do {\
+		(dc)->fentry_time = ktime_get();\
+	}while(0)
+
+	#define devfreq_func_end(dc) do {\
+		(dc)->prev_count = ktime_get();\
+		(dc)->busy_time += ktime_to_ns(ktime_sub((dc)->prev_count, \
+					(dc)->fentry_time));\
+	}while(0)
+
+	#define module_busy_time(dc)	((dc)->busy_time)
+
+	#define module_busy_plus_not_busy_time(dc) \
+		ktime_to_ns(ktime_sub(ktime_get(), (dc)->start_time))
+
+	#define devfreq_reset_counters(dc) do { \
+		(dc)->start_time = ktime_get();\
+	}while(0)
+#else
+	#define devfreq_func_start(dc) \
+		(dc)->fentry_time = jiffies
+
+	#define devfreq_fun_end(dc) do { \
+		(dc)->prev_count = (jiffies)-((dc)->fentry_time);\
+		(dc)->busy_time += (dc)->prev_count;\
+	}while(0)
+
+	#define module_busy_time(dc) \
+		jiffies_to_usecs((dc)->busy_time)
+
+	#define module_busy_plus_not_busy_time(dc) \
+		jiffies_to_usecs(((jiffies) - (dc)->start_time))
+
+	#define devfreq_reset_counters(dc) do { \
+		(dc)->fentry_time = 0UL; \
+		(dc)->prev_count = 0UL; \
+		(dc)->busy_time = 0UL; \
+		(dc)->start_time = jiffies;\
+	}while(0)
+#endif
+
+#if 0
+static int devfreq_counters_init(struct c2k_devfreq_data *data)
+{
+	devfreq_counters **dc = &data->dpc;
+
+	*dc = kzalloc(sizeof (devfreq_counters), GFP_KERNEL);
+        if (dc == NULL) {
+	        printk ("%s: Cannot allocate memory for devfreq_counters.\n"\
+			, __func__);
+	        return -ENOMEM;
+	}
+
+#ifdef C2K_DEVFREQ_USE_KTIME
+	(*dc)->start_time = ktime_get();
+#else
+	(*dc)->fentry_time = 0UL;
+	(*dc)->prev_count = 0UL;
+	(*dc)->busy_time = 0UL;
+	(*dc)->start_time = jiffies;
+#endif
+	return 0;
+}
+#endif
+
+extern int c2k_driver_devfreq(struct device *dev, struct c2k_devfreq_data *data);
+
+#endif
diff --git a/include/linux/cryptodev.h b/include/linux/cryptodev.h
new file mode 100644
index 0000000..9185082
--- /dev/null
+++ b/include/linux/cryptodev.h
@@ -0,0 +1,561 @@
+/*	$FreeBSD: src/sys/opencrypto/cryptodev.h,v 1.25 2007/05/09 19:37:02 gnn Exp $	*/
+/*	$OpenBSD: cryptodev.h,v 1.31 2002/06/11 11:14:29 beck Exp $	*/
+
+/*-
+ * Linux port done by David McCullough <david_mccullough@mcafee.com>
+ * Copyright (C) 2006-2010 David McCullough
+ * Copyright (C) 2004-2005 Intel Corporation.
+ * The license and original author are listed below.
+ *
+ * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
+ * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting
+ *
+ * This code was written by Angelos D. Keromytis in Athens, Greece, in
+ * February 2000. Network Security Technologies Inc. (NSTI) kindly
+ * supported the development of this code.
+ *
+ * Copyright (c) 2000 Angelos D. Keromytis
+ *
+ * Permission to use, copy, and modify this software with or without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all source code copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Copyright (c) 2001 Theo de Raadt
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Effort sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F30602-01-2-0537.
+ *
+ */
+
+#ifndef _CRYPTO_CRYPTO_H_
+#define _CRYPTO_CRYPTO_H_
+
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+#include <linux/in.h>
+#endif
+
+
+/* Some initial values */
+#define CRYPTO_DRIVERS_INITIAL	4
+#define CRYPTO_SW_SESSIONS	32
+
+/* Hash values */
+#define NULL_HASH_LEN		0
+#define MD5_HASH_LEN		16
+#define SHA1_HASH_LEN		20
+#define RIPEMD160_HASH_LEN	20
+#define SHA2_256_HASH_LEN	32
+#define SHA2_384_HASH_LEN	48
+#define SHA2_512_HASH_LEN	64
+#define MD5_KPDK_HASH_LEN	16
+#define SHA1_KPDK_HASH_LEN	20
+/* Maximum hash algorithm result length */
+#define HASH_MAX_LEN		SHA2_512_HASH_LEN /* Keep this updated */
+
+/* HMAC values */
+#define NULL_HMAC_BLOCK_LEN			1
+#define MD5_HMAC_BLOCK_LEN			64
+#define SHA1_HMAC_BLOCK_LEN			64
+#define RIPEMD160_HMAC_BLOCK_LEN	64
+#define SHA2_256_HMAC_BLOCK_LEN		64
+#define SHA2_384_HMAC_BLOCK_LEN		128
+#define SHA2_512_HMAC_BLOCK_LEN		128
+/* Maximum HMAC block length */
+#define HMAC_MAX_BLOCK_LEN		SHA2_512_HMAC_BLOCK_LEN /* Keep this updated */
+#define HMAC_IPAD_VAL			0x36
+#define HMAC_OPAD_VAL			0x5C
+
+/* Encryption algorithm block sizes */
+#define NULL_BLOCK_LEN			1
+#define DES_BLOCK_LEN			8
+#define DES3_BLOCK_LEN			8
+#define BLOWFISH_BLOCK_LEN		8
+#define SKIPJACK_BLOCK_LEN		8
+#define CAST128_BLOCK_LEN		8
+#define RIJNDAEL128_BLOCK_LEN	16
+#define AES_BLOCK_LEN			RIJNDAEL128_BLOCK_LEN
+#define CAMELLIA_BLOCK_LEN		16
+#define ARC4_BLOCK_LEN			1
+#define EALG_MAX_BLOCK_LEN		AES_BLOCK_LEN /* Keep this updated */
+
+/* Encryption algorithm min and max key sizes */
+#define NULL_MIN_KEY_LEN		0
+#define NULL_MAX_KEY_LEN		0
+#define DES_MIN_KEY_LEN			8
+#define DES_MAX_KEY_LEN			8
+#define DES3_MIN_KEY_LEN		24
+#define DES3_MAX_KEY_LEN		24
+#define BLOWFISH_MIN_KEY_LEN	4
+#define BLOWFISH_MAX_KEY_LEN	56
+#define SKIPJACK_MIN_KEY_LEN	10
+#define SKIPJACK_MAX_KEY_LEN	10
+#define CAST128_MIN_KEY_LEN		5
+#define CAST128_MAX_KEY_LEN		16
+#define RIJNDAEL128_MIN_KEY_LEN	16
+#define RIJNDAEL128_MAX_KEY_LEN	32
+#define AES_MIN_KEY_LEN			RIJNDAEL128_MIN_KEY_LEN
+#define AES_MAX_KEY_LEN			RIJNDAEL128_MAX_KEY_LEN
+#define CAMELLIA_MIN_KEY_LEN	16
+#define CAMELLIA_MAX_KEY_LEN	32
+#define ARC4_MIN_KEY_LEN		1
+#define ARC4_MAX_KEY_LEN		256
+
+/* Max size of data that can be processed */
+#define CRYPTO_MAX_DATA_LEN		64*1024 - 1
+
+#define CRYPTO_ALGORITHM_MIN	1
+#define CRYPTO_DES_CBC			1
+#define CRYPTO_3DES_CBC			2
+#define CRYPTO_BLF_CBC			3
+#define CRYPTO_CAST_CBC			4
+#define CRYPTO_SKIPJACK_CBC		5
+#define CRYPTO_MD5_HMAC			6
+#define CRYPTO_SHA1_HMAC		7
+#define CRYPTO_RIPEMD160_HMAC	8
+#define CRYPTO_MD5_KPDK			9
+#define CRYPTO_SHA1_KPDK		10
+#define CRYPTO_RIJNDAEL128_CBC	11 /* 128 bit blocksize */
+#define CRYPTO_AES_CBC			11 /* 128 bit blocksize -- the same as above */
+#define CRYPTO_ARC4				12
+#define CRYPTO_MD5				13
+#define CRYPTO_SHA1				14
+#define CRYPTO_NULL_HMAC		15
+#define CRYPTO_NULL_CBC			16
+#define CRYPTO_DEFLATE_COMP		17 /* Deflate compression algorithm */
+#define CRYPTO_SHA2_256_HMAC	18
+#define CRYPTO_SHA2_384_HMAC	19
+#define CRYPTO_SHA2_512_HMAC	20
+#define CRYPTO_CAMELLIA_CBC		21
+#define CRYPTO_SHA2_256			22
+#define CRYPTO_SHA2_384			23
+#define CRYPTO_SHA2_512			24
+#define CRYPTO_RIPEMD160		25
+#define	CRYPTO_LZS_COMP			26
+#define CRYPTO_ESP_RFC2406 		27
+//#define CRYPTO_ESP_RFC2406_TRANSPORT 20
+#define CRYPTO_ESP_RFC4303  		28
+#define CRYPTO_ESP4_RFC4303  		28
+#define CRYPTO_ESP6_RFC4303  		29
+#define CRYPTO_AH			30
+#define CRYPTO_AH4			30
+#define CRYPTO_AH6			31
+#define CRYPTO_SHA2_HMAC		32 /*TODO is it a duplicate entry*/
+#define CRYPTO_ALGORITHM_MAX		32 /* Keep updated - see below */
+
+/* Algorithm flags */
+#define CRYPTO_ALG_FLAG_SUPPORTED	0x01 /* Algorithm is supported */
+#define CRYPTO_ALG_FLAG_RNG_ENABLE	0x02 /* Has HW RNG for DH/DSA */
+#define CRYPTO_ALG_FLAG_DSA_SHA		0x04 /* Can do SHA on msg */
+
+/*
+ * Crypto driver/device flags.  They can set in the crid
+ * parameter when creating a session or submitting a key
+ * op to affect the device/driver assigned.  If neither
+ * of these are specified then the crid is assumed to hold
+ * the driver id of an existing (and suitable) device that
+ * must be used to satisfy the request.
+ */
+#define CRYPTO_FLAG_HARDWARE	0x01000000	/* hardware accelerated */
+#define CRYPTO_FLAG_SOFTWARE	0x02000000	/* software implementation */
+
+/* NB: deprecated */
+struct session_op {
+	u_int32_t	cipher;		/* ie. CRYPTO_DES_CBC */
+	u_int32_t	mac;		/* ie. CRYPTO_MD5_HMAC */
+
+	u_int32_t	keylen;		/* cipher key */
+	caddr_t		key;
+	int		mackeylen;	/* mac key */
+	caddr_t		mackey;
+
+  	u_int32_t	ses;		/* returns: session # */ 
+};
+
+struct session2_op {
+	u_int32_t	cipher;		/* ie. CRYPTO_DES_CBC */
+	u_int32_t	mac;		/* ie. CRYPTO_MD5_HMAC */
+
+	u_int32_t	keylen;		/* cipher key */
+	caddr_t		key;
+	int		mackeylen;	/* mac key */
+	caddr_t		mackey;
+
+  	u_int32_t	ses;		/* returns: session # */ 
+	int		crid;		/* driver id + flags (rw) */
+	int		pad[4];		/* for future expansion */
+};
+
+struct crypt_op {
+	u_int32_t	ses;
+	u_int16_t	op;		/* i.e. COP_ENCRYPT */
+#define COP_NONE	0
+#define COP_ENCRYPT	1
+#define COP_DECRYPT	2
+	u_int16_t	flags;
+#define	COP_F_BATCH	0x0008		/* Batch op if possible */
+	u_int		len;
+	caddr_t		src, dst;	/* become iov[] inside kernel */
+	caddr_t		mac;		/* must be big enough for chosen MAC */
+	caddr_t		iv;
+};
+
+/*
+ * Parameters for looking up a crypto driver/device by
+ * device name or by id.  The latter are returned for
+ * created sessions (crid) and completed key operations.
+ */
+struct crypt_find_op {
+	int		crid;		/* driver id + flags */
+	char		name[32];	/* device/driver name */
+};
+
+/* bignum parameter, in packed bytes, ... */
+struct crparam {
+	caddr_t		crp_p;
+	u_int		crp_nbits;
+};
+
+#define CRK_MAXPARAM	8
+
+struct crypt_kop {
+	u_int		crk_op;		/* ie. CRK_MOD_EXP or other */
+	u_int		crk_status;	/* return status */
+	u_short		crk_iparams;	/* # of input parameters */
+	u_short		crk_oparams;	/* # of output parameters */
+	u_int		crk_crid;	/* NB: only used by CIOCKEY2 (rw) */
+	struct crparam	crk_param[CRK_MAXPARAM];
+};
+#define CRK_ALGORITM_MIN	0
+#define CRK_MOD_EXP		0
+#define CRK_MOD_EXP_CRT		1
+#define CRK_DSA_SIGN		2
+#define CRK_DSA_VERIFY		3
+#define CRK_DH_COMPUTE_KEY	4
+#define CRK_ALGORITHM_MAX	4 /* Keep updated - see below */
+
+#define CRF_MOD_EXP		(1 << CRK_MOD_EXP)
+#define CRF_MOD_EXP_CRT		(1 << CRK_MOD_EXP_CRT)
+#define CRF_DSA_SIGN		(1 << CRK_DSA_SIGN)
+#define CRF_DSA_VERIFY		(1 << CRK_DSA_VERIFY)
+#define CRF_DH_COMPUTE_KEY	(1 << CRK_DH_COMPUTE_KEY)
+
+/*
+ * done against open of /dev/crypto, to get a cloned descriptor.
+ * Please use F_SETFD against the cloned descriptor.
+ */
+#define CRIOGET		_IOWR('c', 100, u_int32_t)
+#define CRIOASYMFEAT	CIOCASYMFEAT
+#define CRIOFINDDEV	CIOCFINDDEV
+
+/* the following are done against the cloned descriptor */
+#define CIOCGSESSION	_IOWR('c', 101, struct session_op)
+#define CIOCFSESSION	_IOW('c', 102, u_int32_t)
+#define CIOCCRYPT	_IOWR('c', 103, struct crypt_op)
+#define CIOCKEY		_IOWR('c', 104, struct crypt_kop)
+#define CIOCASYMFEAT	_IOR('c', 105, u_int32_t)
+#define CIOCGSESSION2	_IOWR('c', 106, struct session2_op)
+#define CIOCKEY2	_IOWR('c', 107, struct crypt_kop)
+#define CIOCFINDDEV	_IOWR('c', 108, struct crypt_find_op)
+
+struct cryptotstat {
+	struct timespec	acc;		/* total accumulated time */
+	struct timespec	min;		/* min time */
+	struct timespec	max;		/* max time */
+	u_int32_t	count;		/* number of observations */
+};
+
+struct cryptostats {
+	u_int32_t	cs_ops;		/* symmetric crypto ops submitted */
+	u_int32_t	cs_errs;	/* symmetric crypto ops that failed */
+	u_int32_t	cs_kops;	/* asymetric/key ops submitted */
+	u_int32_t	cs_kerrs;	/* asymetric/key ops that failed */
+	u_int32_t	cs_intrs;	/* crypto swi thread activations */
+	u_int32_t	cs_rets;	/* crypto return thread activations */
+	u_int32_t	cs_blocks;	/* symmetric op driver block */
+	u_int32_t	cs_kblocks;	/* symmetric op driver block */
+	/*
+	 * When CRYPTO_TIMING is defined at compile time and the
+	 * sysctl debug.crypto is set to 1, the crypto system will
+	 * accumulate statistics about how long it takes to process
+	 * crypto requests at various points during processing.
+	 */
+	struct cryptotstat cs_invoke;	/* crypto_dipsatch -> crypto_invoke */
+	struct cryptotstat cs_done;	/* crypto_invoke -> crypto_done */
+	struct cryptotstat cs_cb;	/* crypto_done -> callback */
+	struct cryptotstat cs_finis;	/* callback -> callback return */
+
+	u_int32_t	cs_drops;		/* crypto ops dropped due to congestion */
+};
+
+#ifdef __KERNEL__
+
+/* Standard initialization structure beginning */
+struct cryptoini {
+	int		cri_alg;	/* Algorithm to use */
+	int		cri_flags;
+	union {
+		struct {
+			int		cri_mlen;	/* Number of bytes we want from the
+					   entire hash. 0 means all. */
+			int			cri_klen;	/* Key length, in bits */
+			caddr_t		cri_key;	/* key to use */
+			u_int8_t	cri_iv[EALG_MAX_BLOCK_LEN];	/* IV to use */
+		} cri_alg;
+		struct {
+			u_int32_t basealg;
+			struct sockaddr_in tun_source;
+			struct sockaddr_in tun_destination;
+			int tun_df_mode;
+			int tun_ds_mode;
+		 	int tun_ttl_value;
+		 	int tun_replay_windowsize;
+		 	int spivalue ;
+		 	int replayinit;  /* set to 0 to disable replay on receive */
+		 	u_int64_t time_hard_lifetime;
+		 	u_int64_t time_soft_lifetime;
+		 	u_int64_t byte_hard_lifetime;
+		 	u_int64_t byte_soft_lifetime;
+		} cri_pack;	
+	} u;
+	struct cryptoini *cri_next;
+};
+#define cri_mlen		u.cri_alg.cri_mlen
+#define cri_klen		u.cri_alg.cri_klen
+#define cri_key			u.cri_alg.cri_key
+#define cri_iv			u.cri_alg.cri_iv
+#define crip_basealg			u.cri_pack.basealg
+#define crip_tun_source 		u.cri_pack.tun_source
+#define crip_tun_destination	u.cri_pack.tun_destination
+#define crip_tun_df_mode		u.cri_pack.tun_df_mode
+#define crip_tun_ds_mode	u.cri_pack.tun_ds_mode
+#define crip_tun_ttl_value	u.cri_pack.tun_ttl_value
+#define crip_tun_replay_windowsize u.cri_pack.tun_replay_windowsize
+#define crip_spivalue 		u.cri_pack.spivalue
+#define crip_replayinit		u.cri_pack.replayinit
+#define crip_time_hard_lifetime 	 u.cri_pack.time_hard_lifetime
+#define crip_time_soft_lifetime 	 u.cri_pack.time_soft_lifetime
+#define crip_byte_hard_lifetime 	 u.cri_pack.byte_hard_lifetime
+#define crip_byte_soft_lifetime 	 u.cri_pack.byte_soft_lifetime
+
+/* Describe boundaries of a single crypto operation */
+struct cryptodesc {
+	int		crd_skip;	/* How many bytes to ignore from start */
+	int		crd_len;	/* How many bytes to process */
+	int		crd_inject;	/* Where to inject results, if applicable */
+	int		crd_flags;
+
+#define CRD_F_ENCRYPT		0x01	/* Set when doing encryption */
+#define CRD_F_IV_PRESENT	0x02	/* When encrypting, IV is already in
+					   place, so don't copy. */
+#define CRD_F_IV_EXPLICIT	0x04	/* IV explicitly provided */
+#define CRD_F_DSA_SHA_NEEDED	0x08	/* Compute SHA-1 of buffer for DSA */
+#define CRD_F_KEY_EXPLICIT	0x10	/* Key explicitly provided */
+#define CRD_F_COMP		0x0f    /* Set when doing compression */
+
+	struct cryptoini	CRD_INI; /* Initialization/context data */
+#define crd_iv		CRD_INI.cri_iv
+#define crd_key		CRD_INI.cri_key
+#define crd_alg		CRD_INI.cri_alg
+#define crd_klen	CRD_INI.cri_klen
+#define crd_mlen	CRD_INI.cri_mlen
+
+	struct cryptodesc *crd_next;
+};
+
+/* Structure describing complete operation */
+struct cryptop {
+	struct list_head crp_next;
+	wait_queue_head_t crp_waitq;
+
+	u_int64_t	crp_sid;	/* Session ID */
+	int		crp_ilen;	/* Input data total length */
+	int		crp_olen;	/* Result total length */
+
+	int		crp_etype;	/*
+					 * Error type (zero means no error).
+					 * All error codes except EAGAIN
+					 * indicate possible data corruption (as in,
+					 * the data have been touched). On all
+					 * errors, the crp_sid may have changed
+					 * (reset to a new one), so the caller
+					 * should always check and use the new
+					 * value on future requests.
+					 */
+	int		crp_flags;
+
+#define CRYPTO_F_SKBUF		0x0001	/* Input/output are skbuf chains */
+#define CRYPTO_F_IOV		0x0002	/* Input/output are uio */
+#define CRYPTO_F_REL		0x0004	/* Must return data in same place */
+#define CRYPTO_F_BATCH		0x0008	/* Batch op if possible */
+#define CRYPTO_F_CBIMM		0x0010	/* Do callback immediately */
+#define CRYPTO_F_DONE		0x0020	/* Operation completed */
+#define CRYPTO_F_CBIFSYNC	0x0040	/* Do CBIMM if op is synchronous */
+
+	caddr_t		crp_buf;	/* Data to be processed */
+	caddr_t		crp_out_buf;	/* Crypto Result Buffer */
+	caddr_t		crp_opaque;	/* Opaque pointer, passed along */
+	struct cryptodesc *crp_desc;	/* Linked list of processing descriptors */
+
+	int (*crp_callback)(struct cryptop *); /* Callback function */
+};
+enum crypto_packet_return_code {
+		CRYPTO_OK=0,
+		CRYPTO_SOFT_TTL = 2,
+ 		CRYPTO_HARD_TTL,
+ 		CRYPTO_SA_INACTIVE,
+ 		CRYPTO_REPLAY,
+ 		CRYPTO_ICV_FAIL,
+ 		CRYPTO_SEQ_ROLL,
+ 		CRYPTO_MEM_ERROR,
+ 		CRYPTO_VERS_ERROR,
+ 		CRYPTO_PROT_ERROR,
+ 		CRYPTO_PYLD_ERROR,
+ 		CRYPTO_PAD_ERROR 
+};
+
+enum crypto_accel_type {
+                  CRYPTO_PACKET  =0x2,    /* OR together desired bits */
+                  CRYPTO_HARDWARE=0x1,
+                  CRYPTO_SOFTWARE=0x0
+};
+
+enum crypto_flags {
+                  CRYPTO_ENCRYPT=0x1, 	// same for encap (OCF l2)
+                  CRYPTO_DECRYPT=0x2,		// same for decap (OCF l2)
+                  CRYPTO_MAC_GEN=0x4,
+                  CRYPTO_MAC_CHECK=0x08,
+                  CRYPTO_COMPRESS_SMALLER=0x10,
+                  CRYPTO_COMPRESS_BIGGER=0x20
+};
+
+#define CRYPTO_BUF_CONTIG	0x0
+#define CRYPTO_BUF_IOV		0x1
+#define CRYPTO_BUF_SKBUF		0x2
+
+#define CRYPTO_OP_DECRYPT	0x0
+#define CRYPTO_OP_ENCRYPT	0x1
+
+/*
+ * Hints passed to process methods.
+ */
+#define CRYPTO_HINT_MORE	0x1	/* more ops coming shortly */
+
+struct cryptkop {
+	struct list_head krp_next;
+	wait_queue_head_t krp_waitq;
+
+	int		krp_flags;
+#define CRYPTO_KF_DONE		0x0001	/* Operation completed */
+#define CRYPTO_KF_CBIMM		0x0002	/* Do callback immediately */
+
+	u_int		krp_op;		/* ie. CRK_MOD_EXP or other */
+	u_int		krp_status;	/* return status */
+	u_short		krp_iparams;	/* # of input parameters */
+	u_short		krp_oparams;	/* # of output parameters */
+	u_int		krp_crid;	/* desired device, etc. */
+	u_int32_t	krp_hid;
+	struct crparam	krp_param[CRK_MAXPARAM];	/* kvm */
+	int		(*krp_callback)(struct cryptkop *);
+};
+
+#include <linux/ocf-compat.h>
+
+/*
+ * Session ids are 64 bits.  The lower 32 bits contain a "local id" which
+ * is a driver-private session identifier.  The upper 32 bits contain a
+ * "hardware id" used by the core crypto code to identify the driver and
+ * a copy of the driver's capabilities that can be used by client code to
+ * optimize operation.
+ */
+#define CRYPTO_SESID2HID(_sid)	(((_sid) >> 32) & 0x00ffffff)
+#define CRYPTO_SESID2CAPS(_sid)	(((_sid) >> 32) & 0xff000000)
+#define CRYPTO_SESID2LID(_sid)	(((u_int32_t) (_sid)) & 0xffffffff)
+
+extern	int crypto_newsession(u_int64_t *sid, struct cryptoini *cri, int hard);
+extern	int crypto_freesession(u_int64_t sid);
+#define CRYPTOCAP_F_HARDWARE	CRYPTO_FLAG_HARDWARE
+#define CRYPTOCAP_F_SOFTWARE	CRYPTO_FLAG_SOFTWARE
+#define CRYPTOCAP_F_SYNC	0x04000000	/* operates synchronously */
+extern	int32_t crypto_get_driverid(device_t dev, int flags);
+extern	int crypto_find_driver(const char *);
+extern	device_t crypto_find_device_byhid(int hid);
+extern	int crypto_getcaps(int hid);
+extern	int crypto_register(u_int32_t driverid, int alg, u_int16_t maxoplen,
+	    u_int32_t flags);
+extern	int crypto_kregister(u_int32_t, int, u_int32_t);
+extern	int crypto_unregister(u_int32_t driverid, int alg);
+extern	int crypto_unregister_all(u_int32_t driverid);
+extern	int crypto_dispatch(struct cryptop *crp);
+extern	int crypto_kdispatch(struct cryptkop *);
+#define CRYPTO_SYMQ	0x1
+#define CRYPTO_ASYMQ	0x2
+extern	int crypto_unblock(u_int32_t, int);
+extern	void crypto_done(struct cryptop *crp);
+extern	void crypto_kdone(struct cryptkop *);
+extern	int crypto_getfeat(int *);
+
+extern	void crypto_freereq(struct cryptop *crp);
+extern	struct cryptop *crypto_getreq(int num);
+
+extern  int crypto_usercrypto;      /* userland may do crypto requests */
+extern  int crypto_userasymcrypto;  /* userland may do asym crypto reqs */
+extern  int crypto_devallowsoft;    /* only use hardware crypto */
+
+/*
+ * random number support,  crypto_unregister_all will unregister
+ */
+extern int crypto_rregister(u_int32_t driverid,
+		int (*read_random)(void *arg, u_int32_t *buf, int len), void *arg);
+extern int crypto_runregister_all(u_int32_t driverid);
+
+/*
+ * Crypto-related utility routines used mainly by drivers.
+ *
+ * XXX these don't really belong here; but for now they're
+ *     kept apart from the rest of the system.
+ */
+struct uio;
+extern	void cuio_copydata(struct uio* uio, int off, int len, caddr_t cp);
+extern	void cuio_copyback(struct uio* uio, int off, int len, caddr_t cp);
+extern	struct iovec *cuio_getptr(struct uio *uio, int loc, int *off);
+
+extern	void crypto_copyback(int flags, caddr_t buf, int off, int size,
+	    caddr_t in);
+extern	void crypto_copydata(int flags, caddr_t buf, int off, int size,
+	    caddr_t out);
+extern	int crypto_apply(int flags, caddr_t buf, int off, int len,
+	    int (*f)(void *, void *, u_int), void *arg);
+
+#endif /* __KERNEL__ */
+#endif /* _CRYPTO_CRYPTO_H_ */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 29b6353..2573b1e 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -410,6 +410,9 @@
 struct vm_area_struct;
 struct vfsmount;
 struct cred;
+#if defined(CONFIG_COMCERTO_IMPROVED_SPLICE)
+struct socket;
+#endif
 
 extern void __init inode_init(void);
 extern void __init inode_init_early(void);
@@ -1615,6 +1618,10 @@
 	int (*flock) (struct file *, int, struct file_lock *);
 	ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
 	ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
+#if defined(CONFIG_COMCERTO_IMPROVED_SPLICE)
+	ssize_t (*splice_from_socket)(struct file *file, struct socket *sock,
+				     loff_t __user *ppos, size_t count);
+#endif
 	int (*setlease)(struct file *, long, struct file_lock **);
 	long (*fallocate)(struct file *file, int mode, loff_t offset,
 			  loff_t len);
@@ -2434,6 +2441,10 @@
 		struct pipe_inode_info *, size_t, unsigned int);
 extern ssize_t generic_file_splice_write(struct pipe_inode_info *,
 		struct file *, loff_t *, size_t, unsigned int);
+#if defined(CONFIG_COMCERTO_IMPROVED_SPLICE)
+extern ssize_t comcerto_file_splice_write(struct pipe_inode_info *,
+		struct file *, loff_t *, size_t, unsigned int);
+#endif
 extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe,
 		struct file *out, loff_t *, size_t len, unsigned int flags);
 extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 3a76faf..e371b05 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -141,7 +141,12 @@
 /* Flag - indicates that the buffer will be suitable for DMA.  Ignored on some
    platforms, used as appropriate on others */
 
+#if defined(CONFIG_COMCERTO_ZONE_DMA_NCNB)
+#define GFP_DMA		__GFP_DMA32
+#define GFP_DMA_NCNB	__GFP_DMA
+#else
 #define GFP_DMA		__GFP_DMA
+#endif
 
 /* 4GB DMA on some platforms */
 #define GFP_DMA32	__GFP_DMA32
diff --git a/include/linux/if.h b/include/linux/if.h
index db20bd4..d8498f6 100644
--- a/include/linux/if.h
+++ b/include/linux/if.h
@@ -52,6 +52,9 @@
 #define IFF_DORMANT	0x20000		/* driver signals dormant	*/
 
 #define IFF_ECHO	0x40000		/* echo sent packets		*/
+#if defined(CONFIG_ARCH_COMCERTO)
+#define IFF_WIFI_OFLD 	0x80000		/* Offload interface		*/
+#endif
 
 #define IFF_VOLATILE	(IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ECHO|\
 		IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT)
diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h
index 6d722f4..5e77aad 100644
--- a/include/linux/if_arp.h
+++ b/include/linux/if_arp.h
@@ -92,6 +92,8 @@
 #define ARPHRD_PHONET_PIPE 821		/* PhoNet pipe header		*/
 #define ARPHRD_CAIF	822		/* CAIF media type		*/
 
+#define ARPHRD_IPV6_IPV6_TUNNEL   ARPHRD_ETHER 
+
 #define ARPHRD_VOID	  0xFFFF	/* Void type, nothing is known */
 #define ARPHRD_NONE	  0xFFFE	/* zero header length */
 
diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index dd3f201..7a8bb26 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -106,6 +106,22 @@
 typedef int br_should_route_hook_t(struct sk_buff *skb);
 extern br_should_route_hook_t __rcu *br_should_route_hook;
 
+#if defined(CONFIG_ARCH_COMCERTO)
+struct brevent_fdb_update{
+	char * mac_addr;
+	struct net_device * dev;
+};
+
+enum brevent_notif_type {
+	BREVENT_PORT_DOWN = 1,	/* arg is struct net_device ptr */
+	BREVENT_FDB_UPDATE	/* arg is struct brevent_fdb_update ptr */
+};
+
+int register_brevent_notifier(struct notifier_block *nb);
+int unregister_brevent_notifier(struct notifier_block *nb);
+int call_brevent_notifiers(unsigned long val, void *v);
+#endif
+
 #endif
 
 #endif
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index e473003..e85de7c 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -34,6 +34,7 @@
 #define ETH_DATA_LEN	1500		/* Max. octets in payload	 */
 #define ETH_FRAME_LEN	1514		/* Max. octets in frame sans FCS */
 #define ETH_FCS_LEN	4		/* Octets in the FCS		 */
+#define ETH_IPHLEN      2               /* EtherIP header length         */
 
 /*
  *	These are the defined Ethernet Protocol ID's.
diff --git a/include/linux/if_ppp.h b/include/linux/if_ppp.h
index c9ad383..38f0d79 100644
--- a/include/linux/if_ppp.h
+++ b/include/linux/if_ppp.h
@@ -161,6 +161,9 @@
 #define PPPIOCATTCHAN	_IOW('t', 56, int)	/* attach to ppp channel */
 #define PPPIOCGCHAN	_IOR('t', 55, int)	/* get ppp channel number */
 #define PPPIOCGL2TPSTATS _IOR('t', 54, struct pppol2tp_ioc_stats)
+#if defined(CONFIG_COMCERTO_FP)
+#define PPPIOCSFPPIDLE	_IOW('t', 53, struct ppp_idle)	/* Set the FPP stats */
+#endif
 
 #define SIOCGPPPSTATS   (SIOCDEVPRIVATE + 0)
 #define SIOCGPPPVER     (SIOCDEVPRIVATE + 1)	/* NEVER change this!! */
diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h
index 16b92d0..9453ec2 100644
--- a/include/linux/if_tunnel.h
+++ b/include/linux/if_tunnel.h
@@ -21,6 +21,10 @@
 #define SIOCADD6RD      (SIOCDEVPRIVATE + 9)
 #define SIOCDEL6RD      (SIOCDEVPRIVATE + 10)
 #define SIOCCHG6RD      (SIOCDEVPRIVATE + 11)
+#define SIOCGET4RD      (SIOCDEVPRIVATE + 12)  
+#define SIOCADD4RD      (SIOCDEVPRIVATE + 13) 
+#define SIOCDEL4RD      (SIOCDEVPRIVATE + 14)
+#define SIOCCHG4RD      (SIOCDEVPRIVATE + 15)
 
 #define GRE_CSUM	__cpu_to_be16(0x8000)
 #define GRE_ROUTING	__cpu_to_be16(0x4000)
@@ -63,6 +67,20 @@
 	__u16			relay_prefixlen;
 };
 
+/* ip6 tnl 4rd parm -start  */ 
+struct ip6_tnl_4rd {
+       __be32                  prefix;
+       struct in6_addr         relay_prefix;
+       struct in6_addr         relay_suffix;
+       __u16                   prefixlen;
+       __u16                   relay_prefixlen;
+       __u16                   relay_suffixlen;
+       __u16                   psid_offsetlen;
+       __u16                   eabit_len;
+       __u16                   entry_num;
+};
+/* ip6 tnl 4rd parm -end  */ 
+
 enum {
 	IFLA_GRE_UNSPEC,
 	IFLA_GRE_LINK,
diff --git a/include/linux/in.h b/include/linux/in.h
index 01129c0..3422759 100644
--- a/include/linux/in.h
+++ b/include/linux/in.h
@@ -41,6 +41,7 @@
   IPPROTO_ESP = 50,            /* Encapsulation Security Payload protocol */
   IPPROTO_AH = 51,             /* Authentication Header protocol       */
   IPPROTO_BEETPH = 94,	       /* IP option pseudo header for BEET */
+  IPPROTO_ETHERIP = 97,        /* IP option for EtherIP tunnel (rfc 3378) */
   IPPROTO_PIM    = 103,		/* Protocol Independent Multicast	*/
 
   IPPROTO_COMP   = 108,                /* Compression Header protocol */
diff --git a/include/linux/ip6_tunnel.h b/include/linux/ip6_tunnel.h
index bf22b03..554e24e 100644
--- a/include/linux/ip6_tunnel.h
+++ b/include/linux/ip6_tunnel.h
@@ -31,4 +31,51 @@
 	struct in6_addr raddr;	/* remote tunnel end-point address */
 };
 
+
+struct ip6_4rd_map_msg {
+       __u32 reset;
+       __u32 ifindex;
+       __be32 prefix;
+       __u16 prefixlen;
+       struct in6_addr relay_prefix;
+       struct in6_addr relay_suffix;
+       __u16 relay_prefixlen;
+       __u16 relay_suffixlen;
+       __u16 psid_offsetlen;
+       __u16 eabit_len;
+       __u16 entry_num;
+};
+
+struct ip6_tnl_4rd_map_rule {
+       __be32 prefix;
+       __u16 prefixlen;
+       struct in6_addr relay_prefix;
+       struct in6_addr relay_suffix;
+       __u16 relay_prefixlen;
+       __u16 relay_suffixlen;
+       __u16 psid_offsetlen;
+       __u16 eabit_len;
+       __u16 entry_num;
+       struct list_head mr_list;
+};
+
+#ifdef __KERNEL__
+struct ip6_tnl_4rd_parm {
+       __be32 prefix;
+       struct in6_addr relay_prefix;
+       struct in6_addr relay_suffix;
+       __u16 prefixlen;
+       __u16 relay_prefixlen;
+       __u16 relay_suffixlen;
+       __be32 laddr4;
+       __u16 port_set_id;
+       __u16 port_set_id_len;
+       __u16 psid_offsetlen;
+       __u16 eabit_len;
+
+       struct list_head map_list;
+       rwlock_t map_lock;
+};
+#endif
+
 #endif
diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h
index c41d727..24b73c0 100644
--- a/include/linux/miscdevice.h
+++ b/include/linux/miscdevice.h
@@ -19,6 +19,7 @@
 #define APOLLO_MOUSE_MINOR	7
 #define PC110PAD_MINOR		9
 /*#define ADB_MOUSE_MINOR	10	FIXME OBSOLETE */
+#define CRYPTODEV_MINOR		70	/* /dev/crypto */
 #define WATCHDOG_MINOR		130	/* Watchdog timer     */
 #define TEMP_MINOR		131	/* Temperature Sensor */
 #define RTC_MINOR		135
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index ae451f8..b11401d 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1005,6 +1005,11 @@
 	/* mask of features inheritable by VLAN devices */
 	u32			vlan_features;
 
+#if defined(CONFIG_ARCH_COMCERTO)
+	/* This is pointing to network device that offload WiFi data to PFE */
+	struct net_device 	*wifi_offload_dev;
+#endif
+
 	/* Net device feature bits; if you change something,
 	 * also update netdev_features_strings[] in ethtool.c */
 
@@ -1620,6 +1625,9 @@
 extern int		dev_close(struct net_device *dev);
 extern void		dev_disable_lro(struct net_device *dev);
 extern int		dev_queue_xmit(struct sk_buff *skb);
+#if defined(CONFIG_ARCH_COMCERTO)
+extern int 		original_dev_queue_xmit(struct sk_buff *skb);
+#endif
 extern int		register_netdevice(struct net_device *dev);
 extern void		unregister_netdevice_queue(struct net_device *dev,
 						   struct list_head *head);
@@ -2048,6 +2056,9 @@
 extern int		netif_rx(struct sk_buff *skb);
 extern int		netif_rx_ni(struct sk_buff *skb);
 extern int		netif_receive_skb(struct sk_buff *skb);
+#if defined(CONFIG_ARCH_COMCERTO)
+extern int              capture_receive_skb(struct sk_buff *skb);
+#endif
 extern gro_result_t	dev_gro_receive(struct napi_struct *napi,
 					struct sk_buff *skb);
 extern gro_result_t	napi_skb_finish(gro_result_t ret, struct sk_buff *skb);
diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild
index a1b410c..e91c119 100644
--- a/include/linux/netfilter/Kbuild
+++ b/include/linux/netfilter/Kbuild
@@ -45,6 +45,7 @@
 header-y += xt_helper.h
 header-y += xt_iprange.h
 header-y += xt_ipvs.h
+header-y += xt_layer7.h
 header-y += xt_length.h
 header-y += xt_limit.h
 header-y += xt_mac.h
diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h
index 0d3dd66..3ca1f46 100644
--- a/include/linux/netfilter/nf_conntrack_common.h
+++ b/include/linux/netfilter/nf_conntrack_common.h
@@ -83,6 +83,16 @@
 	/* Conntrack is a fake untracked entry */
 	IPS_UNTRACKED_BIT = 12,
 	IPS_UNTRACKED = (1 << IPS_UNTRACKED_BIT),
+
+	/* Connection  cannot expire */
+	IPS_PERMANENT_BIT = 13,
+	IPS_PERMANENT = (1 << IPS_PERMANENT_BIT),
+
+#ifdef CONFIG_COMCERTO_FP
+	/* Connection is assured by DPI application */
+	IPS_DPI_ALLOWED_BIT = 14,
+	IPS_DPI_ALLOWED = (1 << IPS_DPI_ALLOWED_BIT),
+#endif
 };
 
 /* Connection tracking event types */
diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h
index debf1ae..fb0dd93 100644
--- a/include/linux/netfilter/nfnetlink_conntrack.h
+++ b/include/linux/netfilter/nfnetlink_conntrack.h
@@ -43,6 +43,8 @@
 	CTA_ZONE,
 	CTA_SECCTX,
 	CTA_TIMESTAMP,
+	CTA_COMCERTO_FP_ORIG,
+	CTA_COMCERTO_FP_REPLY,
 	__CTA_MAX
 };
 #define CTA_MAX (__CTA_MAX - 1)
@@ -190,4 +192,13 @@
 };
 #define CTA_SECCTX_MAX (__CTA_SECCTX_MAX - 1)
 
+enum ctattr_comcerto_fp {
+	CTA_COMCERTO_FP_UNSPEC,
+	CTA_COMCERTO_FP_MARK,
+	CTA_COMCERTO_FP_IFINDEX,
+	CTA_COMCERTO_FP_IIF,
+	__CTA_COMCERTO_FP_MAX
+};
+#define CTA_COMCERTO_FP_MAX (__CTA_COMCERTO_FP_MAX - 1)
+
 #endif /* _IPCONNTRACK_NETLINK_H */
diff --git a/include/linux/netfilter_ipv4/nf_nat.h b/include/linux/netfilter_ipv4/nf_nat.h
index 7a861d0..a7275b3 100644
--- a/include/linux/netfilter_ipv4/nf_nat.h
+++ b/include/linux/netfilter_ipv4/nf_nat.h
@@ -7,6 +7,7 @@
 #define IP_NAT_RANGE_PROTO_SPECIFIED 2
 #define IP_NAT_RANGE_PROTO_RANDOM 4
 #define IP_NAT_RANGE_PERSISTENT 8
+#define IP_NAT_RANGE_4RD_NAPT 16
 
 /* The protocol-specific manipulable parts of the tuple. */
 union nf_conntrack_man_proto {
diff --git a/include/linux/netfilter_ipv6/Kbuild b/include/linux/netfilter_ipv6/Kbuild
index bd095bc..b88c005 100644
--- a/include/linux/netfilter_ipv6/Kbuild
+++ b/include/linux/netfilter_ipv6/Kbuild
@@ -1,6 +1,7 @@
 header-y += ip6_tables.h
 header-y += ip6t_HL.h
 header-y += ip6t_LOG.h
+header-y += ip6t_NPT.h
 header-y += ip6t_REJECT.h
 header-y += ip6t_ah.h
 header-y += ip6t_frag.h
diff --git a/include/linux/netfilter_ipv6/ip6t_NPT.h b/include/linux/netfilter_ipv6/ip6t_NPT.h
new file mode 100644
index 0000000..f763355
--- /dev/null
+++ b/include/linux/netfilter_ipv6/ip6t_NPT.h
@@ -0,0 +1,16 @@
+#ifndef __NETFILTER_IP6T_NPT
+#define __NETFILTER_IP6T_NPT
+
+#include <linux/types.h>
+#include <linux/netfilter.h>
+
+struct ip6t_npt_tginfo {
+	union nf_inet_addr	src_pfx;
+	union nf_inet_addr	dst_pfx;
+	__u8			src_pfx_len;
+	__u8			dst_pfx_len;
+	/* Used internally by the kernel */
+	__sum16			adjustment;
+};
+
+#endif /* __NETFILTER_IP6T_NPT */
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index 8374d29..6f65e12 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -26,8 +26,23 @@
 #define NETLINK_ECRYPTFS	19
 #define NETLINK_RDMA		20
 #define NETLINK_CRYPTO		21	/* Crypto layer */
+#define NETLINK_FF              30
+#define NETLINK_VOP             31
+#define NETLINK_KEY             32
+#define NETLINK_L2FLOW          33
 
-#define MAX_LINKS 32		
+#define NETLINK_VOIP		34
+#define NETLINK_DTAM		35
+#define NETLINK_MCH		36
+#define NETLINK_CONFIG		37
+#define NETLINK_GENPLAY		38
+#define NETLINK_COMADEBUG	39
+#define NETLINK_EEPROM		40
+#define NETLINK_SS7		41
+#define NETLINK_DSR		42
+#define NETLINK_MMI		43
+
+#define MAX_LINKS 44
 
 struct sockaddr_nl {
 	__kernel_sa_family_t	nl_family;	/* AF_NETLINK	*/
diff --git a/include/linux/ocf-compat.h b/include/linux/ocf-compat.h
new file mode 100644
index 0000000..4ad1223
--- /dev/null
+++ b/include/linux/ocf-compat.h
@@ -0,0 +1,372 @@
+#ifndef _BSD_COMPAT_H_
+#define _BSD_COMPAT_H_ 1
+/****************************************************************************/
+/*
+ * Provide compat routines for older linux kernels and BSD kernels
+ *
+ * Written by David McCullough <david_mccullough@mcafee.com>
+ * Copyright (C) 2010 David McCullough <david_mccullough@mcafee.com>
+ *
+ * LICENSE TERMS
+ *
+ * The free distribution and use of this software in both source and binary
+ * form is allowed (with or without changes) provided that:
+ *
+ *   1. distributions of this source code include the above copyright
+ *      notice, this list of conditions and the following disclaimer;
+ *
+ *   2. distributions in binary form include the above copyright
+ *      notice, this list of conditions and the following disclaimer
+ *      in the documentation and/or other associated materials;
+ *
+ *   3. the copyright holder's name is not used to endorse products
+ *      built using this software without specific written permission.
+ *
+ * ALTERNATIVELY, provided that this notice is retained in full, this file
+ * may be distributed under the terms of the GNU General Public License (GPL),
+ * in which case the provisions of the GPL apply INSTEAD OF those given above.
+ *
+ * DISCLAIMER
+ *
+ * This software is provided 'as is' with no explicit or implied warranties
+ * in respect of its properties, including, but not limited to, correctness
+ * and/or fitness for purpose.
+ */
+/****************************************************************************/
+#ifdef __KERNEL__
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED)
+#include <linux/config.h>
+#endif
+
+/*
+ * fake some BSD driver interface stuff specifically for OCF use
+ */
+
+typedef struct ocf_device *device_t;
+
+typedef struct {
+	int (*cryptodev_newsession)(device_t dev, u_int32_t *sidp, struct cryptoini *cri);
+	int (*cryptodev_freesession)(device_t dev, u_int64_t tid);
+	int (*cryptodev_process)(device_t dev, struct cryptop *crp, int hint);
+	int (*cryptodev_kprocess)(device_t dev, struct cryptkop *krp, int hint);
+} device_method_t;
+#define DEVMETHOD(id, func)	id: func
+
+struct ocf_device {
+	char name[32];		/* the driver name */
+	char nameunit[32];	/* the driver name + HW instance */
+	int  unit;
+	device_method_t	methods;
+	void *softc;
+};
+
+#define CRYPTODEV_NEWSESSION(dev, sid, cri) \
+	((*(dev)->methods.cryptodev_newsession)(dev,sid,cri))
+#define CRYPTODEV_FREESESSION(dev, sid) \
+	((*(dev)->methods.cryptodev_freesession)(dev, sid))
+#define CRYPTODEV_PROCESS(dev, crp, hint) \
+	((*(dev)->methods.cryptodev_process)(dev, crp, hint))
+#define CRYPTODEV_KPROCESS(dev, krp, hint) \
+	((*(dev)->methods.cryptodev_kprocess)(dev, krp, hint))
+
+#define device_get_name(dev)	((dev)->name)
+#define device_get_nameunit(dev)	((dev)->nameunit)
+#define device_get_unit(dev)	((dev)->unit)
+#define device_get_softc(dev)	((dev)->softc)
+
+#define	softc_device_decl \
+		struct ocf_device _device; \
+		device_t
+
+#define	softc_device_init(_sc, _name, _unit, _methods) \
+	if (1) {\
+	strncpy((_sc)->_device.name, _name, sizeof((_sc)->_device.name) - 1); \
+	snprintf((_sc)->_device.nameunit, sizeof((_sc)->_device.name), "%s%d", _name, _unit); \
+	(_sc)->_device.unit = _unit; \
+	(_sc)->_device.methods = _methods; \
+	(_sc)->_device.softc = (void *) _sc; \
+	*(device_t *)((softc_get_device(_sc))+1) = &(_sc)->_device; \
+	} else
+
+#define	softc_get_device(_sc)	(&(_sc)->_device)
+
+/*
+ * iomem support for 2.4 and 2.6 kernels
+ */
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+#define ocf_iomem_t	unsigned long
+
+/*
+ * implement simple workqueue like support for older kernels
+ */
+
+#include <linux/tqueue.h>
+
+#define work_struct tq_struct
+
+#define INIT_WORK(wp, fp, ap) \
+	do { \
+		(wp)->sync = 0; \
+		(wp)->routine = (fp); \
+		(wp)->data = (ap); \
+	} while (0)
+
+#define schedule_work(wp) \
+	do { \
+		queue_task((wp), &tq_immediate); \
+		mark_bh(IMMEDIATE_BH); \
+	} while (0)
+
+#define flush_scheduled_work()	run_task_queue(&tq_immediate)
+
+#else
+#define ocf_iomem_t	void __iomem *
+
+#include <linux/workqueue.h>
+
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+#include <linux/fdtable.h>
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
+#define files_fdtable(files)	(files)
+#endif
+
+#ifdef MODULE_PARM
+#undef module_param	/* just in case */
+#define	module_param(a,b,c)		MODULE_PARM(a,"i")
+#endif
+
+#define bzero(s,l)		memset(s,0,l)
+#define bcopy(s,d,l)	memcpy(d,s,l)
+#define bcmp(x, y, l)	memcmp(x,y,l)
+
+#define MIN(x,y)	((x) < (y) ? (x) : (y))
+
+#define device_printf(dev, a...) ({ \
+				printk("%s: ", device_get_nameunit(dev)); printk(a); \
+			})
+
+#undef printf
+#define printf(fmt...)	printk(fmt)
+
+#define KASSERT(c,p)	if (!(c)) { printk p ; } else
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+#define ocf_daemonize(str) \
+	daemonize(); \
+	spin_lock_irq(&current->sigmask_lock); \
+	sigemptyset(&current->blocked); \
+	recalc_sigpending(current); \
+	spin_unlock_irq(&current->sigmask_lock); \
+	sprintf(current->comm, str);
+#else
+#define ocf_daemonize(str) daemonize(str);
+#endif
+
+#define	TAILQ_INSERT_TAIL(q,d,m) list_add_tail(&(d)->m, (q))
+#define	TAILQ_EMPTY(q)	list_empty(q)
+#define	TAILQ_FOREACH(v, q, m) list_for_each_entry(v, q, m)
+
+#define read_random(p,l) get_random_bytes(p,l)
+
+#define DELAY(x)	((x) > 2000 ? mdelay((x)/1000) : udelay(x))
+#define strtoul simple_strtoul
+
+#define pci_get_vendor(dev)	((dev)->vendor)
+#define pci_get_device(dev)	((dev)->device)
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+#define pci_set_consistent_dma_mask(dev, mask) (0)
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
+#define pci_dma_sync_single_for_cpu pci_dma_sync_single
+#endif
+
+#ifndef DMA_32BIT_MASK
+#define DMA_32BIT_MASK  0x00000000ffffffffULL
+#endif
+
+#ifndef htole32
+#define htole32(x)	cpu_to_le32(x)
+#endif
+#ifndef htobe32
+#define htobe32(x)	cpu_to_be32(x)
+#endif
+#ifndef htole16
+#define htole16(x)	cpu_to_le16(x)
+#endif
+#ifndef htobe16
+#define htobe16(x)	cpu_to_be16(x)
+#endif
+
+/* older kernels don't have these */
+
+#include <asm/irq.h>
+#if !defined(IRQ_NONE) && !defined(IRQ_RETVAL)
+#define IRQ_NONE
+#define IRQ_HANDLED
+#define IRQ_WAKE_THREAD
+#define IRQ_RETVAL
+#define irqreturn_t void
+typedef irqreturn_t (*irq_handler_t)(int irq, void *arg, struct pt_regs *regs);
+#endif
+#ifndef IRQF_SHARED
+#define IRQF_SHARED	SA_SHIRQ
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+# define strlcpy(dest,src,len) \
+		({strncpy(dest,src,(len)-1); ((char *)dest)[(len)-1] = '\0'; })
+#endif
+
+#ifndef MAX_ERRNO
+#define MAX_ERRNO	4095
+#endif
+#ifndef IS_ERR_VALUE
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,5)
+#include <linux/err.h>
+#endif
+#ifndef IS_ERR_VALUE
+#define IS_ERR_VALUE(x) ((unsigned long)(x) >= (unsigned long)-MAX_ERRNO)
+#endif
+#endif
+
+/*
+ * common debug for all
+ */
+#if 1
+#define dprintk(a...)	do { if (debug) printk(a); } while(0)
+#else
+#define dprintk(a...)
+#endif
+
+#ifndef SLAB_ATOMIC
+/* Changed in 2.6.20, must use GFP_ATOMIC now */
+#define	SLAB_ATOMIC	GFP_ATOMIC
+#endif
+
+/*
+ * need some additional support for older kernels */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,2)
+#define pci_register_driver_compat(driver, rc) \
+	do { \
+		if ((rc) > 0) { \
+			(rc) = 0; \
+		} else if (rc == 0) { \
+			(rc) = -ENODEV; \
+		} else { \
+			pci_unregister_driver(driver); \
+		} \
+	} while (0)
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
+#define pci_register_driver_compat(driver,rc) ((rc) = (rc) < 0 ? (rc) : 0)
+#else
+#define pci_register_driver_compat(driver,rc)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+
+#include <linux/mm.h>
+#include <asm/scatterlist.h>
+
+static inline void sg_set_page(struct scatterlist *sg,  struct page *page,
+			       unsigned int len, unsigned int offset)
+{
+	sg->page = page;
+	sg->offset = offset;
+	sg->length = len;
+}
+
+static inline void *sg_virt(struct scatterlist *sg)
+{
+	return page_address(sg->page) + sg->offset;
+}
+
+#define sg_init_table(sg, n)
+
+#define sg_mark_end(sg)
+
+#endif
+
+#ifndef late_initcall
+#define late_initcall(init) module_init(init)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4) || !defined(CONFIG_SMP)
+#define ocf_for_each_cpu(cpu) for ((cpu) = 0; (cpu) == 0; (cpu)++)
+#else
+#define ocf_for_each_cpu(cpu) for_each_present_cpu(cpu)
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+#include <linux/sched.h>
+#define	kill_proc(p,s,v)	send_sig(s,find_task_by_vpid(p),0)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4)
+
+struct ocf_thread {
+	struct task_struct	*task;
+	int					(*func)(void *arg);
+	void				*arg;
+};
+
+/* thread startup helper func */
+static inline int ocf_run_thread(void *arg)
+{
+	struct ocf_thread *t = (struct ocf_thread *) arg;
+	if (!t)
+		return -1; /* very bad */
+	t->task = current;
+	daemonize();
+	spin_lock_irq(&current->sigmask_lock);
+	sigemptyset(&current->blocked);
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+	return (*t->func)(t->arg);
+}
+
+#define kthread_create(f,a,fmt...) \
+	({ \
+		struct ocf_thread t; \
+		pid_t p; \
+		t.task = NULL; \
+		t.func = (f); \
+		t.arg = (a); \
+		p = kernel_thread(ocf_run_thread, &t, CLONE_FS|CLONE_FILES); \
+		while (p != (pid_t) -1 && t.task == NULL) \
+			schedule(); \
+		if (t.task) \
+			snprintf(t.task->comm, sizeof(t.task->comm), fmt); \
+		(t.task); \
+	})
+
+#define kthread_bind(t,cpu)	/**/
+
+#define kthread_should_stop()	(strcmp(current->comm, "stopping") == 0)
+
+#define kthread_stop(t) \
+	({ \
+		strcpy((t)->comm, "stopping"); \
+		kill_proc((t)->pid, SIGTERM, 1); \
+		do { \
+			schedule(); \
+		} while (kill_proc((t)->pid, SIGTERM, 1) == 0); \
+	})
+
+#else
+#include <linux/kthread.h>
+#endif
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0)
+#define	skb_frag_page(x)	((x)->page)
+#endif
+
+#endif /* __KERNEL__ */
+
+/****************************************************************************/
+#endif /* _BSD_COMPAT_H_ */
diff --git a/include/linux/of.h b/include/linux/of.h
index 4948552..7b3ed80 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -336,6 +336,22 @@
 #define of_match_node(_matches, _node)	NULL
 #endif /* CONFIG_OF */
 
+/**
+* of_property_read_bool - Findfrom a property
+* @np:         device node from which the property value is to be read.
+* @propname:   name of the property to be searched.
+*
+* Search for a property in a device node.
+* Returns true if the property exist false otherwise.
+*/
+static inline bool of_property_read_bool(const struct device_node *np,
+										const char *propname)
+{
+	struct property *prop = of_find_property(np, propname, NULL);
+
+	return prop ? true : false;
+}
+
 static inline int of_property_read_u32(const struct device_node *np,
 				       const char *propname,
 				       u32 *out_value)
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index e90a673..35ff525 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -104,6 +104,9 @@
 #ifdef CONFIG_MEMORY_FAILURE
 	PG_hwpoison,		/* hardware poisoned page. Don't touch */
 #endif
+#ifdef CONFIG_RAID_ZERO_COPY
+        PG_constant,            /* const page not modified during raid5 io */
+#endif
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 	PG_compound_lock,
 #endif
@@ -193,6 +196,16 @@
 
 struct page;	/* forward declaration */
 
+#ifdef CONFIG_RAID_ZERO_COPY
+#define PageConstant(page) test_bit(PG_constant, &(page)->flags)
+#define SetPageConstant(page) set_bit(PG_constant, &(page)->flags)
+#define ClearPageConstant(page) clear_bit(PG_constant, &(page->flags))
+#define TestSetPageConstant(page) test_and_set_bit(PG_constant, &(page)->flags)
+extern void clear_page_constant(struct page *page);
+#endif
+
+
+
 TESTPAGEFLAG(Locked, locked)
 PAGEFLAG(Error, error) TESTCLEARFLAG(Error, error)
 PAGEFLAG(Referenced, referenced) TESTCLEARFLAG(Referenced, referenced)
diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h
index 0b80c80..0456669 100644
--- a/include/linux/pfkeyv2.h
+++ b/include/linux/pfkeyv2.h
@@ -268,6 +268,7 @@
 #define SADB_SAFLAGS_NOPMTUDISC	0x20000000
 #define SADB_SAFLAGS_DECAP_DSCP	0x40000000
 #define SADB_SAFLAGS_NOECN	0x80000000
+#define SADB_SAFLAGS_ESN	0x01000000
 
 /* Security Association states */
 #define SADB_SASTATE_LARVAL	0
diff --git a/include/linux/random.h b/include/linux/random.h
index 8f74538..0ff31a9 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -34,6 +34,30 @@
 /* Clear the entropy pool and associated counters.  (Superuser only.) */
 #define RNDCLEARPOOL	_IO( 'R', 0x06 )
 
+#ifdef CONFIG_FIPS_RNG
+
+/* Size of seed value - equal to AES blocksize */
+#define AES_BLOCK_SIZE_BYTES	16
+#define SEED_SIZE_BYTES			AES_BLOCK_SIZE_BYTES
+/* Size of AES key */
+#define KEY_SIZE_BYTES		16
+
+/* ioctl() structure used by FIPS 140-2 Tests */
+struct rand_fips_test {
+	unsigned char key[KEY_SIZE_BYTES];			/* Input */
+	unsigned char datetime[SEED_SIZE_BYTES];	/* Input */
+	unsigned char seed[SEED_SIZE_BYTES];		/* Input */
+	unsigned char result[SEED_SIZE_BYTES];		/* Output */
+};
+
+/* FIPS 140-2 RNG Variable Seed Test. (Superuser only.) */
+#define RNDFIPSVST	_IOWR('R', 0x10, struct rand_fips_test)
+
+/* FIPS 140-2 RNG Monte Carlo Test. (Superuser only.) */
+#define RNDFIPSMCT	_IOWR('R', 0x11, struct rand_fips_test)
+
+#endif /* #ifdef CONFIG_FIPS_RNG */
+
 struct rand_pool_info {
 	int	entropy_count;
 	int	buf_size;
@@ -54,6 +78,10 @@
 				 unsigned int value);
 extern void add_interrupt_randomness(int irq);
 
+extern void random_input_words(__u32 *buf, size_t wordcount, int ent_count);
+extern int random_input_wait(void);
+#define HAS_RANDOM_INPUT_WAIT 1
+
 extern void get_random_bytes(void *buf, int nbytes);
 void generate_random_uuid(unsigned char uuid_out[16]);
 
diff --git a/include/linux/rtc/rtc-c2k.h b/include/linux/rtc/rtc-c2k.h
new file mode 100644
index 0000000..e4d7af9
--- /dev/null
+++ b/include/linux/rtc/rtc-c2k.h
@@ -0,0 +1,24 @@
+
+/*
+	REGISTER OFFSET_ADDRESS R/W DESCRIPTION RESET VALUE
+*/
+
+#define	C2K_RTC_RTCCON 0X00 /* R/W RTC CONTROL REGISTER 0X00 */
+#define	C2K_RTC_RTCALM 0X04 /* R/W RTC ALARM CONTROL REGISTER 0X00 */
+#define	C2K_RTC_ALMSEC 0X08 /* R/W ALARM SECOND DATA REGISTER 0X00 */
+#define	C2K_RTC_ALMMIN 0X0C /* R/W ALARM MINUTE DATA REGISTER 0X00 */
+#define	C2K_RTC_ALMHOUR 0X10 /* R/W ALARM HOUR DATA REGISTER 0X00 */
+#define	C2K_RTC_ALMDATE 0X14 /* R/W ALARM DATE DATA REGISTER 0X00 */
+#define	C2K_RTC_ALMDAY 0X18 /* R/W ALARM DAY OF WEEK DATA REGISTER 0X00 */
+#define	C2K_RTC_ALMMON 0X1C /* R/W ALARM MONTH DATA REGISTER 0X00 */
+#define	C2K_RTC_ALMYEAR 0X20 /* R/W ALARM YEAR DATA REGISTER 0X00 */
+#define	C2K_RTC_BCDSEC 0X24 /* R/W BCD SECOND REGISTER */
+#define	C2K_RTC_BCDMIN 0X28 /* R/W BCD MINUTE REGISTER */
+#define	C2K_RTC_BCDHOUR 0X2C /* R/W BCD HOUR REGISTER */
+#define	C2K_RTC_BCDDATE 0X30 /* R/W BCD DATE REGISTER */
+#define	C2K_RTC_BCDDAY 0X34 /* R/W BCD DAY OF WEEK REGISTER */
+#define	C2K_RTC_BCDMON 0X38 /* R/W BCD MONTH REGISTER */
+#define	C2K_RTC_BCDYEAR 0X3C /* R/W BCD YEAR REGISTER */
+#define	C2K_RTC_RTCIM 0X40 /* R/W RTC INTERRUPT MODE REGISTER 0X00 */
+#define	C2K_RTC_RTCPEND 0X44 /* R/W RTC INTERRUPT PENDING REGISTER 0X00 */
+
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 8e872ea..6c2fb2f 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -119,7 +119,12 @@
 #define RTM_GETDCB RTM_GETDCB
 	RTM_SETDCB,
 #define RTM_SETDCB RTM_SETDCB
-
+       RTM_NEW4RD = 80,
+#define RTM_NEW4RD      RTM_NEW4RD
+       RTM_DEL4RD,
+#define RTM_DEL4RD      RTM_DEL4RD
+       RTM_GET4RD,
+#define RTM_GET4RD      RTM_GET4RD
 	__RTM_MAX,
 #define RTM_MAX		(((__RTM_MAX + 3) & ~3) - 1)
 };
@@ -621,6 +626,9 @@
 			u32 group, struct nlmsghdr *nlh, gfp_t flags);
 extern void rtnl_set_sk_err(struct net *net, u32 group, int error);
 extern int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics);
+#ifdef CONFIG_ARCH_COMCERTO
+extern int rtnetlink_put_metrics_2(struct sk_buff *skb, u32 *metrics, struct dst_entry *dst);
+#endif
 extern int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst,
 			      u32 id, u32 ts, u32 tsage, long expires,
 			      u32 error);
@@ -742,6 +750,7 @@
    	__rta_reserve(skb, attrtype, attrlen); })
 
 extern void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change);
+extern void __rtmsg_ifinfo(int type, struct net_device *dev, unsigned change, gfp_t flags);
 
 /* RTNL is used as a global lock for all changes to network configuration  */
 extern void rtnl_lock(void);
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 53dc7e7..4b42eb7 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -414,6 +414,9 @@
 	kmemcheck_bitfield_end(flags1);
 	__be16			protocol;
 
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+	__u32			ipsec_offload;
+#endif
 	void			(*destructor)(struct sk_buff *skb);
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 	struct nf_conntrack	*nfct;
@@ -468,6 +471,11 @@
 	sk_buff_data_t		end;
 	unsigned char		*head,
 				*data;
+#if defined(CONFIG_COMCERTO_CUSTOM_SKB_LAYOUT)
+	unsigned char 		*mspd_data;
+	__u32 			mspd_len;
+	__u32 			mspd_ofst;
+#endif
 	unsigned int		truesize;
 	atomic_t		users;
 };
@@ -550,6 +558,17 @@
 	return __alloc_skb(size, priority, 1, NUMA_NO_NODE);
 }
 
+#if defined(CONFIG_ARCH_COMCERTO)
+extern struct sk_buff *__alloc_skb_header(unsigned int size, void* data, gfp_t gfp_mask,
+			    int fclone, int node);
+static inline struct sk_buff *alloc_skb_header(unsigned int size, 
+					void* data,
+					gfp_t priority)
+{
+	return __alloc_skb_header(size, data, priority, 0, NUMA_NO_NODE);
+}
+#endif
+
 extern void skb_recycle(struct sk_buff *skb);
 extern bool skb_recycle_check(struct sk_buff *skb, int skb_size);
 
@@ -2085,6 +2104,11 @@
 extern int	       skb_copy_datagram_iovec(const struct sk_buff *from,
 					       int offset, struct iovec *to,
 					       int size);
+#if defined(CONFIG_COMCERTO_IMPROVED_SPLICE)
+extern int	       skb_copy_datagram_to_kernel_iovec(const struct sk_buff *from,
+					       int offset, struct iovec *to,
+					       int size);
+#endif
 extern int	       skb_copy_and_csum_datagram_iovec(struct sk_buff *skb,
 							int hlen,
 							struct iovec *iov);
diff --git a/include/linux/slab_def.h b/include/linux/slab_def.h
index d00e0ba..334f381 100644
--- a/include/linux/slab_def.h
+++ b/include/linux/slab_def.h
@@ -148,7 +148,7 @@
 		return NULL;
 found:
 #ifdef CONFIG_ZONE_DMA
-		if (flags & GFP_DMA)
+		if (flags & __GFP_DMA)
 			cachep = malloc_sizes[i].cs_dmacachep;
 		else
 #endif
diff --git a/include/linux/socket.h b/include/linux/socket.h
index ad919e0..ce12aa5 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -195,7 +195,10 @@
 #define AF_CAIF		37	/* CAIF sockets			*/
 #define AF_ALG		38	/* Algorithm sockets		*/
 #define AF_NFC		39	/* NFC sockets			*/
-#define AF_MAX		40	/* For now.. */
+#define AF_COMA		40	/* COMA sockets			*/
+#define AF_MAX		41	/* For now.. */
+
+
 
 /* Protocol families, same as address families. */
 #define PF_UNSPEC	AF_UNSPEC
@@ -238,8 +241,10 @@
 #define PF_CAIF		AF_CAIF
 #define PF_ALG		AF_ALG
 #define PF_NFC		AF_NFC
+#define PF_COMA		AF_COMA
 #define PF_MAX		AF_MAX
 
+
 /* Maximum queue length specifiable by listen.  */
 #define SOMAXCONN	128
 
@@ -266,6 +271,10 @@
 #define MSG_MORE	0x8000	/* Sender will send more */
 #define MSG_WAITFORONE	0x10000	/* recvmmsg(): block until 1+ packets avail */
 #define MSG_SENDPAGE_NOTLAST 0x20000 /* sendpage() internal : not the last page */
+#if defined(CONFIG_COMCERTO_IMPROVED_SPLICE)
+#define MSG_KERNSPACE   0x40000
+#define MSG_NOCATCHSIG	0x80000
+#endif
 #define MSG_EOF         MSG_FIN
 
 #define MSG_CMSG_CLOEXEC 0x40000000	/* Set close_on_exit for file
@@ -332,6 +341,9 @@
 			     int offset, int len);
 extern int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr *kaddr);
 extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data);
+#if defined(CONFIG_COMCERTO_IMPROVED_SPLICE)
+extern void memcpy_tokerneliovec(struct iovec *iov, unsigned char *kdata, int len);
+#endif
 
 struct timespec;
 
diff --git a/include/linux/spi/comcerto_spi.h b/include/linux/spi/comcerto_spi.h
new file mode 100644
index 0000000..f5b5da6
--- /dev/null
+++ b/include/linux/spi/comcerto_spi.h
@@ -0,0 +1,211 @@
+/*
+ *  linux/drivers/spi/busses/comcerto_spi.h
+ *
+ *  Copyright (C) Mindspeed Technologies
+ *
+ * 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.
+ *
+ */
+#ifndef _COMCERTO_SPI_H
+#define _COMCERTO_SPI_H
+
+#include <linux/list.h>
+#include <linux/spi/spi.h>
+//#include <asm-arm/types.h>
+#include <linux/types.h>
+
+#define comcerto_SPI_NAME "comcerto_spi"
+
+#define CFG_HZ_CLOCK            165000000       /* 165 MHz */
+#define SPI_BASEADDR            COMCERTO_APB_SPI_BASE
+
+#define SPI_BAUDR_MIN           2
+#define SPI_BAUDR_MAX           0xFFFE
+#define SPI_SPEED_MAX           (4*1000*1000)
+#define SPI_SPEED_MIN           0 /*need to be calculated using c2k pll bus clock*/
+#define SPI_FRAME_SIZE_MIN      4
+#define SPI_FRAME_SIZE_MAX      16
+#define SPI_CHIP_SELECT_MAX     15
+
+struct comcerto_spi_platform {
+    int     *chipselect;
+    int   num_chipselect;
+    u8  bits_per_word;
+    u8 num_devices;
+    unsigned long min_sc_rate;      /* maximum supported serial clock rate (in MHz) */
+    unsigned long max_sc_rate;      /* minimum supported serial clock rate (in MHz) */
+
+    u8 max_fs;                      /* maximum supported frame size (in bits) */
+    u8 min_fs;                      /* minimum supported frame size (in bits) */
+
+    u16 max_nframe;                 /* maximum supported transfer frame number */
+    u16 min_nframe;                 /* minimum supported transfer frame number */
+
+    u16 cs_msk;
+    unsigned long clock_rate;
+
+    struct spi_board_info *devices;
+};
+
+struct comcerto_transfer
+{
+    u8 *wbuf;
+    unsigned int wlen;
+
+    u8 *rbuf;
+    unsigned int rlen;
+
+    u8 mode;
+
+    u32 ctrlr0;
+
+    u8 bits_per_word;
+    u32 baudr;
+    u32 ser;
+
+    u8 fs;                          /* transfer frame size (in bits) */
+};
+
+struct spi_client_conf
+{
+    u16 cs_msk;                     /* chip select mask for this client */
+    u8 sc_polarity;                 /* serial clock polarity */
+    u8 sc_phase;                    /* serial clock phase */
+    unsigned long sc_rate;          /* serial clock rate (in MHz)*/
+    u8 cs_delay;                    /* chip select deassert time (in serial clock cycles) */
+};
+
+#define COMCERTO_SPI_CTRLR0               0x00
+#define COMCERTO_SPI_CTRLR1               0x04
+#define COMCERTO_SPI_SSIENR               0x08
+#define COMCERTO_SPI_MWCR                 0x0C
+#define COMCERTO_SPI_SER                  0x10
+#define COMCERTO_SPI_BAUDR                0x14
+#define COMCERTO_SPI_TXFTLR               0x18
+#define COMCERTO_SPI_RXFTLR               0x1C
+#define COMCERTO_SPI_TXFLR                0x20
+#define COMCERTO_SPI_RXFLR                0x24
+#define COMCERTO_SPI_SR                   0x28
+#define COMCERTO_SPI_IMR                  0x2C
+#define COMCERTO_SPI_ISR                  0x30
+#define COMCERTO_SPI_RISR                 0x34
+#define COMCERTO_SPI_TXOICR               0x38
+#define COMCERTO_SPI_RXOICR               0x3C
+#define COMCERTO_SPI_RXUICR               0x40
+#define COMCERTO_SPI_MSTICR               0x44
+#define COMCERTO_SPI_ICR                  0x48
+#define COMCERTO_SPI_IDR                  0x58
+#define COMCERTO_SPI_DR                   0x60
+
+
+/* SR - status register bits */
+#define BUSY		(1<<0)	/* SSI busy flag, serial transfer in progress */
+#define TFNF		(1<<1)	/* Transmit FIFO not full */
+#define TFE		(1<<2)	/* Transmit FIFO empty */
+#define RFNE		(1<<3)	/* Receive FIFO not empty */
+#define RFF		(1<<4)	/* Receive FIFO full */
+#define TXE		(1<<5)	/* Transmission error */
+#define DCOL		(1<<6)	/* Data collision error */
+
+/* Interrupt status after being masked */
+#define TXEIS		(1<<0)	/* Transmit FIFO empty interrupt status */
+#define TXOIS		(1<<1)	/* Transmit FIFO overflow interrupt status */
+#define RXUIS		(1<<2)	/* Receive FIFO underflow interrupt status */
+#define RXOIS		(1<<3)	/* Receive FIFO overflow interrupt status */
+#define RXFIS		(1<<4)	/* Receive FIFO full interrupt status */
+#define MSTIS		(1<<5)	/* Multi-Master contention interrupt status */
+
+/* Interrupt status before being masked */
+#define TXEIR		(1<<0)	/* Transmit FIFO empty interrupt status */
+#define TXOIR		(1<<1)	/* Transmit FIFO overflow interrupt status */
+#define RXUIR		(1<<2)	/* Receive FIFO underflow interrupt status */
+#define RXOIR		(1<<3)	/* Receive FIFO overflow interrupt status */
+#define RXFIR		(1<<4)	/* Receive FIFO full interrupt status */
+#define MSTIR		(1<<5)	/* Multi-Master contention interrupt status */
+
+
+/* Interrupt mask register */
+#define TXEIM		(1<<0)	/* Transmit FIFO empty interrupt status */
+#define TXOIM		(1<<1)	/* Transmit FIFO overflow interrupt status */
+#define RXUIM		(1<<2)	/* Receive FIFO underflow interrupt status */
+#define RXOIM		(1<<3)	/* Receive FIFO overflow interrupt status */
+#define RXFIM		(1<<4)	/* Receive FIFO full interrupt status */
+#define MSTIM		(1<<5)	/* Multi-Master contention interrupt status */
+
+
+#define SPI_TRANSFER_MODE_WRITE_ONLY	0x01
+#define SPI_TRANSFER_MODE_READ_ONLY	0x02
+#define SPI_TRANSFER_MODE_WRITE_READ	0x03
+
+typedef u8	u4;
+
+struct spi_local_transfer
+{
+	u8 *wbuf;
+	unsigned int wlen;
+
+	u8 *rbuf;
+	unsigned int rlen;
+
+	u8 mode;
+
+	u8 fs;				/* transfer frame size (in bits) */
+};
+
+struct spi_adapter_caps
+{
+	unsigned long min_sc_rate;	/* maximum supported serial clock rate (in MHz) */
+	unsigned long max_sc_rate;	/* minimum supported serial clock rate (in MHz) */
+
+	u8 max_fs;			/* maximum supported frame size (in bits) */
+	u8 min_fs;			/* minimum supported frame size (in bits) */
+
+	u16 cs_msk;			/* mask of supported chip selects */
+
+	u16 max_nframe;			/* maximum supported transfer frame number */
+	u16 min_nframe;			/* minimum supported transfer frame number */
+};
+
+struct spi_client_config
+{
+	u16 cs_msk;			/* chip select mask for this client */
+	u8 sc_polarity;			/* serial clock polarity */
+	u8 sc_phase;			/* serial clock phase */
+	unsigned long sc_rate;		/* serial clock rate (in MHz)*/
+	u8 cs_delay;			/* chip select deassert time (in serial clock cycles) */
+};
+
+/* A SPI bus adapter instance */
+struct spi_adapter
+{
+	char *name;
+
+	int (*do_transfer)(struct spi_adapter *adapter, struct spi_local_transfer *transfer, struct spi_client_config *config);
+
+	void *data;
+	unsigned long membase;
+	unsigned long clock_rate;	
+
+	struct list_head clients;
+
+	struct spi_adapter_caps caps;
+
+	struct spi_master       master;
+};
+
+/* A SPI device instance */
+struct spi_client
+{
+	struct spi_client_config config;
+	struct spi_adapter *adapter;
+	void *data;
+	struct list_head list;
+};
+
+//int spi_writeread_mem(struct spi_client *client, u8 fs, u8 *rbuffer, int rlen, u8 *wbuffer, int wlen);
+int spi_writeread_mem(struct spi_adapter *adapter, u8 fs, u8 *rbuffer, int rlen, u8 *wbuffer, int wlen);
+
+
+#endif /* _COMCERTO_SPI_H */
diff --git a/include/linux/spi/designware.h b/include/linux/spi/designware.h
new file mode 100644
index 0000000..cc0335b
--- /dev/null
+++ b/include/linux/spi/designware.h
@@ -0,0 +1,15 @@
+/*
+ * designware.h - platform glue for the Synopsys DesignWare SPI controller
+ */
+
+#define        CLK_NAME       10
+#define        TX_FIFO_DEPTH  8
+#define        RX_FIFO_DEPTH  8
+
+struct spi_controller_pdata {
+	int use_dma;
+	int num_chipselects;
+	int bus_num;
+	u32 max_freq;
+	char clk_name[CLK_NAME];
+};
diff --git a/include/linux/spi2/spi.h b/include/linux/spi2/spi.h
new file mode 100644
index 0000000..9cba316
--- /dev/null
+++ b/include/linux/spi2/spi.h
@@ -0,0 +1,167 @@
+/*
+ *  linux/include/linux/spi.h
+ *
+ *  Copyright (C) Mindspeed Technologies
+ *
+ * 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.
+ *
+ */
+#ifndef _SPI_H
+#define _SPI_H
+
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#include <linux/device.h>
+#endif
+
+#define SPI_TRANSFER_MODE_WRITE_ONLY	0x01
+#define SPI_TRANSFER_MODE_READ_ONLY	0x02
+#define SPI_TRANSFER_MODE_WRITE_READ	0x03
+
+typedef u8	u4;
+
+struct spi_transfer
+{
+	u8 *wbuf;
+	unsigned int wlen;
+
+	u8 *rbuf;
+	unsigned int rlen;
+
+	u8 mode;
+
+	u8 fs;				/* transfer frame size (in bits) */
+};
+
+struct spi_adapter_caps
+{
+	unsigned long min_sc_rate;	/* maximum supported serial clock rate (in MHz) */
+	unsigned long max_sc_rate;	/* minimum supported serial clock rate (in MHz) */
+
+	u8 max_fs;			/* maximum supported frame size (in bits) */
+	u8 min_fs;			/* minimum supported frame size (in bits) */
+
+	u16 cs_msk;			/* mask of supported chip selects */
+
+	u16 max_nframe;			/* maximum supported transfer frame number */
+	u16 min_nframe;			/* minimum supported transfer frame number */
+};
+
+struct spi_client_config
+{
+	u16 cs_msk;			/* chip select mask for this client */
+	u8 sc_polarity;			/* serial clock polarity */
+	u8 sc_phase;			/* serial clock phase */
+	unsigned long sc_rate;		/* serial clock rate (in MHz)*/
+	u8 cs_delay;			/* chip select deassert time (in serial clock cycles) */
+	unsigned long ba_delay; 	/* bus access delay, in us */
+};
+
+/* A SPI bus adapter instance */
+struct spi_adapter
+{
+	char *name;
+
+	int (*do_transfer)(struct spi_adapter *adapter, struct spi_transfer *transfer, struct spi_client_config *config);
+
+	void *data;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+	struct device dev;
+#endif
+	struct list_head list;
+	struct list_head clients;
+
+	struct spi_adapter_caps caps;
+
+	int bus_num;
+
+	spinlock_t lock;
+};
+
+/* A SPI device instance */
+struct spi_client
+{
+	struct spi_client_config config;
+
+	struct spi_driver *driver;
+
+	struct spi_adapter *adapter;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+	struct device dev;
+#else
+	void *data;
+#endif
+	struct list_head list;
+};
+
+/* A SPI device driver */
+struct spi_driver {
+	char *name;
+
+	int (*attach_adapter)(struct spi_adapter *adapter);
+	int (*detach_client)(struct spi_client *client);
+#ifdef CONFIG_PM
+	int (*suspend)(struct spi_client *client, pm_message_t state);
+	int (*resume)(struct spi_client *client);
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+	struct device_driver driver;
+#endif
+	struct list_head list;
+	short bus_id;
+};
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+static inline void *spi_get_clientdata (struct spi_client *dev)
+{
+	return dev_get_drvdata (&dev->dev);
+}
+
+static inline void spi_set_clientdata (struct spi_client *dev, void *data)
+{
+	dev_set_drvdata (&dev->dev, data); 
+}
+#else
+static inline void *spi_get_clientdata (struct spi_client *dev)
+{
+	return (void *) dev->data;
+}
+
+static inline void spi_set_clientdata (struct spi_client *dev, void *data)
+{
+	dev->data = data;
+}
+#endif
+
+int spi_add_adapter(struct spi_adapter *adapter);
+int spi_del_adapter(struct spi_adapter *adapter);
+
+int spi_add_driver(struct spi_driver *driver);
+int spi_del_driver(struct spi_driver *driver);
+
+int spi_attach_client(struct spi_client *client);
+int spi_detach_client(struct spi_client *client);
+
+int spi_write_mem(struct spi_client *client, u8 fs, u8 *buffer, int len);
+int spi_write_single(struct spi_client *client, u8 fs, u16 value);
+
+int spi_writen(struct spi_client *client, u4 value);
+int spi_writeb(struct spi_client *client, u8 value);
+int spi_writew(struct spi_client *client, u16 value);
+
+int spi_read_mem(struct spi_client *client, u8 fs, u8 *buffer, int len);
+int spi_read_single(struct spi_client *client, u8 fs, u16 *value);
+int spi_writeread_mem(struct spi_client *client, u8 fs, u8 *rbuffer, int rlen, u8 *wbuffer, int wlen);
+
+int spi_readn(struct spi_client *client, u4 *value);
+int spi_readb(struct spi_client *client, u8 *value);
+int spi_readw(struct spi_client *client, u16 *value);
+
+#endif /* _SPI_H */
diff --git a/include/net/flow.h b/include/net/flow.h
index 2a7eefd..2b4adb6 100644
--- a/include/net/flow.h
+++ b/include/net/flow.h
@@ -212,9 +212,17 @@
 		struct net *net, const struct flowi *key, u16 family,
 		u8 dir, struct flow_cache_object *oldobj, void *ctx);
 
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+extern struct flow_cache_object *flow_cache_lookup(
+		struct net *net, const struct flowi *key, u16 family,
+		u8 dir, u8 *new_flow, flow_resolve_t resolver, void *ctx);
+extern void flow_cache_remove(
+				const struct flowi *fl, unsigned short family, unsigned short dir);
+#else
 extern struct flow_cache_object *flow_cache_lookup(
 		struct net *net, const struct flowi *key, u16 family,
 		u8 dir, flow_resolve_t resolver, void *ctx);
+#endif
 
 extern void flow_cache_flush(void);
 extern void flow_cache_flush_deferred(void);
diff --git a/include/net/ip.h b/include/net/ip.h
index eca0ef7..6616ba5 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -408,6 +408,7 @@
 	IP_DEFRAG_VS_FWD,
 	IP_DEFRAG_AF_PACKET,
 	IP_DEFRAG_MACVLAN,
+	IP_DEFRAG_IP6_TNL_4RD /* Used to support Post Fragmentation for 4o6 tunnels */
 };
 
 int ip_defrag(struct sk_buff *skb, u32 user);
diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h
index fc73e66..68205dd 100644
--- a/include/net/ip6_tunnel.h
+++ b/include/net/ip6_tunnel.h
@@ -19,6 +19,10 @@
 	struct flowi fl;	/* flowi template for xmit */
 	struct dst_entry *dst_cache;    /* cached dst */
 	u32 dst_cookie;
+#if defined(CONFIG_INET6_IPSEC_OFFLOAD)
+	u32 genid;
+#endif
+       struct ip6_tnl_4rd_parm ip4rd; /* 4rd parameters for the tunnel */ 
 };
 
 /* Tunnel encapsulation limit destination sub-option */
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index 0b6a3e8..2a39687 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -100,6 +100,14 @@
 #include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
 #include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
 
+#if defined(CONFIG_COMCERTO_FP)
+struct comcerto_fp_info {
+	int ifindex;
+	int iif;
+	u32 mark;
+};
+#endif
+
 struct nf_conn {
 	/* Usage count in here is 1 for hash table/destruct timer, 1 per skb,
            plus 1 for any connection(s) we are `master' for */
@@ -128,6 +136,10 @@
 	u_int32_t secmark;
 #endif
 
+#if defined(CONFIG_COMCERTO_FP)
+	struct comcerto_fp_info fp_info[IP_CT_DIR_MAX];
+#endif
+
 	/* Extensions */
 	struct nf_ct_ext *ext;
 #ifdef CONFIG_NET_NS
@@ -331,6 +343,9 @@
 
 struct kernel_param;
 
+extern int nf_conntrack_set_dpi_allow_report(struct sk_buff *skb);
+extern int nf_conntrack_set_dpi_allow_and_mark(struct sk_buff *skb, int mark);
+
 extern int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp);
 extern unsigned int nf_conntrack_htable_size;
 extern unsigned int nf_conntrack_max;
diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h
index aced085..f8fb25f 100644
--- a/include/net/netfilter/nf_conntrack_core.h
+++ b/include/net/netfilter/nf_conntrack_core.h
@@ -76,4 +76,8 @@
 
 extern spinlock_t nf_conntrack_lock ;
 
+#ifdef CONFIG_COMCERTO_FP
+#define COMCERTO_PERMANENT_TIMEOUT	1000
+#endif
+
 #endif /* _NF_CONNTRACK_CORE_H */
diff --git a/include/net/netfilter/nf_conntrack_ecache.h b/include/net/netfilter/nf_conntrack_ecache.h
index a88fb69..ea6f8a4 100644
--- a/include/net/netfilter/nf_conntrack_ecache.h
+++ b/include/net/netfilter/nf_conntrack_ecache.h
@@ -18,6 +18,7 @@
 	u16 ctmask;		/* bitmask of ct events to be delivered */
 	u16 expmask;		/* bitmask of expect events to be delivered */
 	u32 pid;		/* netlink pid of destroyer */
+	struct timer_list timeout;
 };
 
 static inline struct nf_conntrack_ecache *
diff --git a/include/net/netns/xfrm.h b/include/net/netns/xfrm.h
index 748f91f..19295e5 100644
--- a/include/net/netns/xfrm.h
+++ b/include/net/netns/xfrm.h
@@ -27,6 +27,9 @@
 	struct hlist_head	*state_bydst;
 	struct hlist_head	*state_bysrc;
 	struct hlist_head	*state_byspi;
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+	struct hlist_head	*state_byh;
+#endif
 	unsigned int		state_hmask;
 	unsigned int		state_num;
 	struct work_struct	state_hash_work;
diff --git a/include/net/udp.h b/include/net/udp.h
index 3b285f4..009c6b0 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -191,6 +191,9 @@
 extern int udp_lib_setsockopt(struct sock *sk, int level, int optname,
 			      char __user *optval, unsigned int optlen,
 			      int (*push_pending_frames)(struct sock *));
+extern int 	udp6_lib_setsockopt(struct sock *sk, int level, int optname,
+				   char __user *optval, unsigned int optlen,
+				   int (*push_pending_frames)(struct sock *));
 extern struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport,
 				    __be32 daddr, __be16 dport,
 				    int dif);
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index b203e14..add91c3 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -137,7 +137,10 @@
 	};
 	struct hlist_node	bysrc;
 	struct hlist_node	byspi;
-
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+	struct hlist_node 	byh;
+	u16			handle;
+#endif
 	atomic_t		refcnt;
 	spinlock_t		lock;
 
@@ -229,6 +232,11 @@
 	/* Private data of this transformer, format is opaque,
 	 * interpreted by xfrm_type methods. */
 	void			*data;
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+	 /* Intended direction of this state, used for offloading */
+	int	dir;
+	int	offloaded;	
+#endif
 };
 
 static inline struct net *xs_net(struct xfrm_state *x)
@@ -247,6 +255,13 @@
 	XFRM_STATE_EXPIRED,
 	XFRM_STATE_DEAD
 };
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+enum {
+	 XFRM_STATE_DIR_UNKNOWN,
+	 XFRM_STATE_DIR_IN,
+	 XFRM_STATE_DIR_OUT,
+};
+#endif
 
 /* callback structure passed from either netlink or pfkey */
 struct km_event {
@@ -299,6 +314,9 @@
 
 extern int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo);
 extern int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo);
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+extern struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family);
+#endif
 extern void km_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c);
 extern void km_state_notify(struct xfrm_state *x, const struct km_event *c);
 
@@ -958,6 +976,35 @@
 	struct xfrm_state	*xvec[XFRM_MAX_DEPTH];
 };
 
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+struct xfrm_input_shared
+{
+	struct sk_buff 		*skb;
+	int 			xfrm_nr, first, xfrm_encap;
+	struct xfrm_state 	*xfrm_vec[XFRM_MAX_DEPTH];
+	__u16 			encap_type;
+	int 			decaps;
+	u32			seq, spi;
+	unsigned int   nhoff;
+	int 			nexthdr;
+	int 			(*callback)(struct xfrm_input_shared *sh);
+	atomic_t		refcnt;
+};
+
+
+static inline void xfrm_shared_get(struct xfrm_input_shared *sh)
+{
+	atomic_inc(&sh->refcnt);
+}
+
+static inline void xfrm_shared_put(struct xfrm_input_shared *sh)
+{
+	if (atomic_dec_and_test(&sh->refcnt)) {
+		kfree(sh);
+	}
+}
+#endif
+
 static inline int secpath_exists(struct sk_buff *skb)
 {
 #ifdef CONFIG_XFRM
@@ -1469,6 +1516,10 @@
 extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family);
 extern int xfrm6_extract_header(struct sk_buff *skb);
 extern int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb);
+/* NAT-T changes Start */
+extern int xfrm6_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
+			   int encap_type);
+/* NAT-T changes End */
 extern int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi);
 extern int xfrm6_transport_finish(struct sk_buff *skb, int async);
 extern int xfrm6_rcv(struct sk_buff *skb);
@@ -1487,12 +1538,21 @@
 
 #ifdef CONFIG_XFRM
 extern int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb);
+extern int xfrm6_udp_encap_rcv(struct sock *sk, struct sk_buff *skb);
 extern int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen);
 #else
 static inline int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
 {
  	return -ENOPROTOOPT;
 } 
+/* NAT-T changes Start */
+static inline int xfrm6_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
+{
+	/* should not happen */
+	kfree_skb(skb);
+	return 0;
+}
+/* NAT-T changes End */
 
 static inline int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
 {
diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c
index 4e316e1..22b499b 100644
--- a/kernel/ksysfs.c
+++ b/kernel/ksysfs.c
@@ -141,6 +141,484 @@
 }
 KERNEL_ATTR_RO(fscaps);
 
+#if defined(CONFIG_COMCERTO_MDMA_PROF)
+extern unsigned int mdma_time_counter[256]; // 16 -> 4000 us
+extern unsigned int mdma_reqtime_counter[256]; // 16 -> 4000 us
+extern unsigned int mdma_data_counter[256];
+extern unsigned int init_mdma_prof;
+extern unsigned int enable_mdma_prof;
+
+static ssize_t comcerto_mdma_prof_enable_show(struct kobject *kobj,
+				  struct kobj_attribute *attr, char *buf)
+{
+	int n;
+	buf[0] = '\0';
+	n = 0;
+	if (enable_mdma_prof)
+		n += sprintf(buf, "MDMA profiling is enabled\n");
+	else
+		n += sprintf(buf, "MDMA profiling is disabled\n");
+
+	return (n + 1);
+}
+
+static ssize_t comcerto_mdma_prof_enable_store(struct kobject *kobj,
+				  struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	unsigned int enable;
+
+	if (kstrtouint(buf, 0, &enable))
+		return -EINVAL;
+
+	if (enable > 0)
+		enable_mdma_prof = 1;
+	else
+		enable_mdma_prof = 0;
+
+	return count;
+}
+KERNEL_ATTR_RW(comcerto_mdma_prof_enable);
+
+static ssize_t comcerto_mdma_reqtiming_show(struct kobject *kobj,
+				  struct kobj_attribute *attr, char *buf)
+{
+	int i;
+	int n;
+
+	buf[0] = '\0';
+	n = 0;
+	n += sprintf(buf, "Histogram of mdma request time\n");
+
+	for (i = 0; i < 255; i++)
+	{
+		if (mdma_reqtime_counter[i]) {
+			n += sprintf(buf + n, "%d in [%d-%d] us\n", mdma_reqtime_counter[i], i << 4, (i + 1) << 4);
+			mdma_reqtime_counter[i] = 0;
+		}
+	}
+	if (mdma_reqtime_counter[255]) {
+		n += sprintf(buf + n, "%d >= %d us\n", mdma_reqtime_counter[255], 255 << 4);
+		mdma_reqtime_counter[255] = 0;
+	}
+	return (n + 1);
+}
+KERNEL_ATTR_RO(comcerto_mdma_reqtiming);
+
+static ssize_t comcerto_mdma_timing_show(struct kobject *kobj,
+				  struct kobj_attribute *attr, char *buf)
+{
+	int i;
+	int n;
+
+	init_mdma_prof = 0;
+	buf[0] = '\0';
+	n = 0;
+	n += sprintf(buf, "Histogram of inter mdma request time\n");
+
+	for (i = 0; i < 255; i++)
+	{
+		if (mdma_time_counter[i]) {
+			n += sprintf(buf + n, "%d in [%d-%d] us\n", mdma_time_counter[i], i << 4, (i + 1) << 4);
+			mdma_time_counter[i] = 0;
+		}
+	}
+	if (mdma_time_counter[255]) {
+		n += sprintf(buf + n, "%d >= %d us\n", mdma_time_counter[255], 255 << 4);
+		mdma_time_counter[255] = 0;
+	}
+	return (n + 1);
+}
+KERNEL_ATTR_RO(comcerto_mdma_timing);
+
+static ssize_t comcerto_mdma_data_show(struct kobject *kobj,
+				  struct kobj_attribute *attr, char *buf)
+{
+	int i;
+	int n;
+
+	buf[0] = '\0';
+	n = 0;
+	n += sprintf(buf, "Histogram of mdma data length (up to 1M)\n");
+	for (i = 0; i < 256; i++)
+	{
+		if (mdma_data_counter[i]) {
+			n += sprintf(buf + n, "%d in [%d-%d] KB\n", mdma_data_counter[i], i << (13 - 10), (i + 1) << (13 - 10));
+			mdma_data_counter[i] = 0;
+		}
+	}
+	return (n + 1);
+}
+KERNEL_ATTR_RO(comcerto_mdma_data);
+#endif
+
+#if defined(CONFIG_COMCERTO_SPLICE_PROF)
+extern unsigned int splicew_time_counter[256]; // 4 ms -> 1S
+extern unsigned int splicew_reqtime_counter[256]; // 4 ms -> 1S
+extern unsigned int splicew_data_counter[256]; 
+extern unsigned int init_splicew_prof; 
+extern unsigned int enable_splice_prof;
+static ssize_t comcerto_splice_prof_enable_show(struct kobject *kobj,
+				  struct kobj_attribute *attr, char *buf)
+{
+	int n;
+	buf[0] = '\0';
+	n = 0;
+	if (enable_splice_prof)
+		n += sprintf(buf, "Splice profiling is enabled\n");
+	else
+		n += sprintf(buf, "Splice profiling is disabled\n");
+
+	return (n + 1);
+}
+static ssize_t comcerto_splice_prof_enable_store(struct kobject *kobj,
+				  struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	unsigned int enable;
+
+	if (kstrtouint(buf, 0, &enable))
+		return -EINVAL;
+
+	if (enable > 0)
+		enable_splice_prof = 1;
+	else
+		enable_splice_prof = 0;
+
+	return count;
+}
+KERNEL_ATTR_RW(comcerto_splice_prof_enable);
+static ssize_t comcerto_splicew_reqtiming_show(struct kobject *kobj,
+				  struct kobj_attribute *attr, char *buf)
+{
+	int i;
+	int n;
+
+	buf[0] = '\0';
+	n = 0;
+	n += sprintf(buf, "Histogram of splice write time (up to 1 sec otherwise date is discarded)\n");
+
+	for (i = 0; i < 255; i++)
+	{
+		if (splicew_reqtime_counter[i]) {
+			n += sprintf(buf + n, "%d in [%d-%d] ms\n", splicew_reqtime_counter[i], (i * 8), (i * 8) + 8);
+			splicew_reqtime_counter[i] = 0;
+		}
+	}
+	if (splicew_reqtime_counter[255]) {
+		n += sprintf(buf + n, "%d > 1 second\n", splicew_reqtime_counter[255]);
+		splicew_reqtime_counter[255] = 0;
+	}
+	return (n + 1);
+}
+KERNEL_ATTR_RO(comcerto_splicew_reqtiming);
+static ssize_t comcerto_splicew_timing_show(struct kobject *kobj,
+				  struct kobj_attribute *attr, char *buf)
+{
+	int i;
+	int n;
+
+	init_splicew_prof = 0;
+	buf[0] = '\0';
+	n = 0;
+	n += sprintf(buf, "Histogram of inter splice write time (up to 1 sec otherwise date is discarded)\n");
+
+	for (i = 0; i < 255; i++)
+	{
+		if (splicew_time_counter[i]) {
+			n += sprintf(buf + n, "%d in [%d-%d] ms\n", splicew_time_counter[i], (i * 8), (i * 8) + 8);
+			splicew_time_counter[i] = 0;
+		}
+	}
+	if (splicew_time_counter[255]) {
+ 		n += sprintf(buf + n, "%d > 1 second\n", splicew_time_counter[255]);
+		splicew_time_counter[255] = 0;
+	}
+	return (n + 1);
+}
+KERNEL_ATTR_RO(comcerto_splicew_timing);
+static ssize_t comcerto_splicew_data_show(struct kobject *kobj,
+				  struct kobj_attribute *attr, char *buf)
+{
+	int i;
+	int n;
+
+	buf[0] = '\0';
+	n = 0;
+	n += sprintf(buf, "Histogram of splice write data length (up to 1M)\n");
+	for (i = 0; i < 256; i++)
+	{
+		if (splicew_data_counter[i]) {
+			n += sprintf(buf + n, "%d in [%d-%d] KB\n", splicew_data_counter[i], (i * 8), (i * 8) + 8);
+			splicew_data_counter[i] = 0;
+		}
+	}
+	return (n + 1);
+}
+KERNEL_ATTR_RO(comcerto_splicew_data);
+
+
+extern unsigned int splicer_time_counter[256]; // 4 ms -> 1S
+extern unsigned int splicer_reqtime_counter[256]; // 4 ms -> 1S
+extern unsigned int splicer_data_counter[256]; 
+extern unsigned int splicer_tcp_rsock_counter[64];
+extern unsigned int init_splicer_prof; 
+static ssize_t comcerto_splicer_reqtiming_show(struct kobject *kobj,
+				  struct kobj_attribute *attr, char *buf)
+{
+	int i;
+	int n;
+
+	buf[0] = '\0';
+	n = 0;
+	n += sprintf(buf, "Histogram of splice read time\n");
+
+	for (i = 0; i < 255; i++)
+	{
+		if (splicer_reqtime_counter[i]) {
+			n += sprintf(buf + n, "%d in [%d-%d] ms\n", splicer_reqtime_counter[i], (i * 8), (i * 8) + 8);
+			splicer_reqtime_counter[i] = 0;
+		}
+	}
+	if (splicer_reqtime_counter[255]) {
+	 	n += sprintf(buf + n, "%d > 1 second\n", splicer_reqtime_counter[255]);
+		splicer_reqtime_counter[255] = 0;
+	}
+	return (n + 1);
+}
+KERNEL_ATTR_RO(comcerto_splicer_reqtiming);
+static ssize_t comcerto_splicer_timing_show(struct kobject *kobj,
+				  struct kobj_attribute *attr, char *buf)
+{
+	int i;
+	int n;
+
+	init_splicer_prof = 0;
+	buf[0] = '\0';
+	n = 0;
+	n += sprintf(buf, "Histogram of inter splice read time\n");
+
+	for (i = 0; i < 255; i++)
+	{
+		if (splicer_time_counter[i]) {
+			n += sprintf(buf + n, "%d in [%d-%d] ms\n", splicer_time_counter[i], (i * 8), (i * 8) + 8);
+			splicer_time_counter[i] = 0;
+		}
+	}
+	if (splicer_time_counter[255]) {
+ 		n += sprintf(buf + n, "%d > 1 second\n", splicer_time_counter[255]);
+		splicer_time_counter[255] = 0;
+	}
+	return (n + 1);
+}
+KERNEL_ATTR_RO(comcerto_splicer_timing);
+static ssize_t comcerto_splicer_data_show(struct kobject *kobj,
+				  struct kobj_attribute *attr, char *buf)
+{
+	int i;
+	int n;
+
+	buf[0] = '\0';
+	n = 0;
+	n += sprintf(buf, "Histogram of splice read data length (up to 1M)\n");
+	for (i = 0; i < 256; i++)
+	{
+		if (splicer_data_counter[i]) {
+			n += sprintf(buf + n, "%d in [%d-%d] KB\n", splicer_data_counter[i], (i * 8), (i * 8) + 8);
+			splicer_data_counter[i] = 0;
+		}
+	}
+	return (n + 1);
+}
+KERNEL_ATTR_RO(comcerto_splicer_data);
+static ssize_t comcerto_splicer_tcp_rsock_show(struct kobject *kobj,
+				  struct kobj_attribute *attr, char *buf)
+{
+	int i;
+	int n;
+
+	buf[0] = '\0';
+	n = 0;
+	n += sprintf(buf, "Histogram of TCP receive queue size when splice read is performed\n");
+	for (i = 0; i < 63; i++)
+	{
+		if (splicer_tcp_rsock_counter[i]) {
+			n += sprintf(buf + n, "%d in [%d-%d] KB\n", splicer_tcp_rsock_counter[i], (i * 64), (i * 64) + 64);
+			splicer_tcp_rsock_counter[i] = 0;
+		}
+	}
+	if (splicer_tcp_rsock_counter[i]) {
+			n += sprintf(buf + n, "%d >= %d KB\n", splicer_tcp_rsock_counter[i], (i * 64));
+			splicer_tcp_rsock_counter[i] = 0;
+	}
+	return (n + 1);
+}
+KERNEL_ATTR_RO(comcerto_splicer_tcp_rsock);
+#endif
+
+#if defined(CONFIG_COMCERTO_AHCI_PROF)
+
+#include "../drivers/ata/ahci.h"
+
+static ssize_t comcerto_ahci_prof_enable_show(struct kobject *kobj,
+				  struct kobj_attribute *attr, char *buf)
+{
+	int n;
+	buf[0] = '\0';
+	n = 0;
+	if (enable_ahci_prof)
+		n += sprintf(buf, "AHCI profiling is enabled\n");
+	else
+		n += sprintf(buf, "AHCI profiling is disabled\n");
+
+	return (n + 1);
+}
+static ssize_t comcerto_ahci_prof_enable_store(struct kobject *kobj,
+				  struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	unsigned int enable;
+
+	if (kstrtouint(buf, 0, &enable))
+		return -EINVAL;
+
+	if (enable > 0)
+		enable_ahci_prof = 1;
+	else
+		enable_ahci_prof = 0;
+
+	return count;
+}
+KERNEL_ATTR_RW(comcerto_ahci_prof_enable);
+static ssize_t comcerto_ahci_timing_show(struct kobject *kobj,
+				  struct kobj_attribute *attr, char *buf)
+{
+	int i, n, p;
+
+	buf[0] = '\0';
+	n = 0;
+	n += sprintf(buf, "Histogram of ahci inter request time (us)\n");
+
+	for (p = 0; p < MAX_AHCI_PORTS; p++) {
+		struct ahci_port_stats *stats = &ahci_port_stats[p];
+
+		n += sprintf(buf + n, "AHCI Port %d\n", p);
+
+		stats->init_prof = 0;
+
+		for (i = 0; i < MAX_BINS - 1; i++)
+		{
+			if (stats->time_counter[i]) {
+				n += sprintf(buf + n, "%8d in [%5d-%5d]\n", stats->time_counter[i], i << US_SHIFT, (i + 1) << US_SHIFT);
+				stats->time_counter[i] = 0;
+			}
+		}
+
+		if (stats->time_counter[MAX_BINS - 1]) {
+		 	n += sprintf(buf + n, "%d > %d us\n", stats->time_counter[MAX_BINS - 1], (MAX_BINS - 1) << US_SHIFT);
+			stats->time_counter[MAX_BINS - 1] = 0;
+		}
+	}
+
+	return (n + 1);
+}
+KERNEL_ATTR_RO(comcerto_ahci_timing);
+static ssize_t comcerto_ahci_data_show(struct kobject *kobj,
+				  struct kobj_attribute *attr, char *buf)
+{
+	int i, n, p;
+
+	buf[0] = '\0';
+	n = 0;
+	n += sprintf(buf, "Histogram of ahci requests data length (KiB)\n");
+
+	for (p = 0; p < MAX_AHCI_PORTS; p++) {
+		struct ahci_port_stats *stats = &ahci_port_stats[p];
+
+		n += sprintf(buf + n, "AHCI Port %d\n", p);
+
+		for (i = 0; i < MAX_BINS; i++)
+		{
+			if (stats->data_counter[i]) {
+				n += sprintf(buf + n, "%8d in [%3d-%3d]\n", stats->data_counter[i], (i << BYTE_SHIFT) / 1024, ((i + 1) << BYTE_SHIFT) / 1024);
+				stats->data_counter[i] = 0;
+			}
+		}
+	}
+
+	return (n + 1);
+}
+KERNEL_ATTR_RO(comcerto_ahci_data);
+
+
+extern struct ahci_port_stats ahci_port_stats[MAX_AHCI_PORTS];
+static ssize_t comcerto_ahci_qc_rate_show(struct kobject *kobj,
+				  struct kobj_attribute *attr, char *buf)
+{
+	int i, n, p;
+	unsigned int mean_rate, total_kb;
+
+	buf[0] = '\0';
+	n = 0;
+	n += sprintf(buf, "Histogram of AHCI requests rate completion (MiB MiB/s):\n");
+
+	for (p = 0; p < MAX_AHCI_PORTS; p++) {
+		struct ahci_port_stats *stats = &ahci_port_stats[p];
+
+		n += sprintf(buf + n, "AHCI Port %d\n", p);
+		total_kb = 0;
+		mean_rate = 0;
+
+		for (i = 0; i < MAX_BINS; i++)
+		{
+			if (stats->rate_counter[i]) {
+				n += sprintf(buf + n, "%8d in [%3d-%3d]\n", stats->rate_counter[i] / 1024, i << RATE_SHIFT, (i + 1) << RATE_SHIFT);
+				mean_rate += stats->rate_counter[i] * (((2 * i + 1) << RATE_SHIFT) / 2);
+				total_kb += stats->rate_counter[i];
+				stats->rate_counter[i] = 0;
+			}
+		}
+		n += sprintf(buf + n, "\n");
+
+		for (i = 0; i < MAX_AHCI_SLOTS; i++) {
+			if (stats->pending_counter[i]) {
+				n += sprintf(buf + n, "%8d in [%2d]\n", stats->pending_counter[i], i);
+				stats->pending_counter[i] = 0;
+			}
+		}
+
+		if (total_kb) {
+			n += sprintf(buf + n, "Mean: %d MiB/s for %d MiB\n", mean_rate / total_kb, total_kb / 1024);
+			n += sprintf(buf + n, "Max issues in a row : %d \n\n", stats->nb_pending_max);
+		}
+
+		stats->nb_pending_max = 0;
+	}
+
+	return (n + 1);
+}
+KERNEL_ATTR_RO(comcerto_ahci_qc_rate);
+
+
+extern unsigned int ahci_qc_no_free_slot;
+static ssize_t comcerto_ahci_qc_no_free_slot_show(struct kobject *kobj,
+				  struct kobj_attribute *attr, char *buf)
+{
+	int n, p;
+
+	buf[0] = '\0';
+	n = 0;
+
+	for (p = 0; p < MAX_AHCI_PORTS; p++) {
+		struct ahci_port_stats *stats = &ahci_port_stats[p];
+
+		n += sprintf(buf + n, "AHCI Port %d no_free_slot count: %d\n", p, stats->no_free_slot);
+
+		stats->no_free_slot = 0;
+	}
+
+	return (n + 1);
+}
+KERNEL_ATTR_RO(comcerto_ahci_qc_no_free_slot);
+#endif
+
 /*
  * Make /sys/kernel/notes give the raw contents of our kernel .notes section.
  */
@@ -182,6 +660,29 @@
 	&kexec_crash_size_attr.attr,
 	&vmcoreinfo_attr.attr,
 #endif
+#if defined(CONFIG_COMCERTO_MDMA_PROF)
+	&comcerto_mdma_prof_enable_attr.attr,
+	&comcerto_mdma_timing_attr.attr,
+	&comcerto_mdma_reqtiming_attr.attr,
+	&comcerto_mdma_data_attr.attr,
+#endif
+#if defined(CONFIG_COMCERTO_SPLICE_PROF)
+	&comcerto_splice_prof_enable_attr.attr,
+	&comcerto_splicew_timing_attr.attr,
+	&comcerto_splicew_reqtiming_attr.attr,
+	&comcerto_splicew_data_attr.attr,
+	&comcerto_splicer_timing_attr.attr,
+	&comcerto_splicer_reqtiming_attr.attr,
+	&comcerto_splicer_data_attr.attr,
+	&comcerto_splicer_tcp_rsock_attr.attr,
+#endif
+#if defined(CONFIG_COMCERTO_AHCI_PROF)
+	&comcerto_ahci_prof_enable_attr.attr,
+	&comcerto_ahci_timing_attr.attr,
+	&comcerto_ahci_data_attr.attr,
+	&comcerto_ahci_qc_rate_attr.attr,
+	&comcerto_ahci_qc_no_free_slot_attr.attr,
+#endif
 	NULL
 };
 
diff --git a/kernel/pid.c b/kernel/pid.c
index fa5f722..2bf49fd 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -428,6 +428,7 @@
 {
 	return find_task_by_pid_ns(vnr, current->nsproxy->pid_ns);
 }
+EXPORT_SYMBOL(find_task_by_vpid);
 
 struct pid *get_task_pid(struct task_struct *task, enum pid_type type)
 {
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index deb5461..d4c5692 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -148,6 +148,15 @@
 	You probably want to have your system's RTC driver statically
 	linked, ensuring that it's available when this test runs.
 
+config PM_SYSFS_MANUAL
+	bool "Driver model /sys/devices/.../power/state files"
+	depends on PM 
+	default n
+	---help---
+	The driver model started out with a sysfs file intended to provide
+	a userspace hook for device power management. By this hook Non CPU 
+	devices can be put in power off state. 
+
 config CAN_PM_TRACE
 	def_bool y
 	depends on PM_DEBUG && PM_SLEEP
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 36e0f09..bb998cc 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -15,6 +15,7 @@
 #include <linux/workqueue.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
+#include <mach/comcerto-2000/pm.h>
 
 #include "power.h"
 
@@ -306,6 +307,28 @@
 
 power_attr(state);
 
+#ifdef CONFIG_ARCH_M86XXX
+static ssize_t bitmask_show(struct kobject *kobj, struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned int value=c2k_pm_bitmask_show();
+	return sprintf(buf,"%02x\n",value);
+
+}
+
+static ssize_t bitmask_store(struct kobject *kobj, struct kobj_attribute *attr,
+			   const char *buf, size_t n)
+{
+	unsigned long value;
+	value=simple_strtoul(buf,NULL,16);
+	/* Store the Bitmask value in the Global Variable */
+	c2k_pm_bitmask_store(value);
+	return n;
+
+}
+power_attr(bitmask);
+#endif
+
 #ifdef CONFIG_PM_SLEEP
 /*
  * The 'wakeup_count' attribute, along with the functions defined in
@@ -404,6 +427,9 @@
 
 static struct attribute * g[] = {
 	&state_attr.attr,
+#ifdef CONFIG_ARCH_M86XXX
+	&bitmask_attr.attr,
+#endif
 #ifdef CONFIG_PM_TRACE
 	&pm_trace_attr.attr,
 	&pm_trace_dev_match_attr.attr,
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index af48faa..f31d659 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -171,15 +171,16 @@
 
 	arch_suspend_disable_irqs();
 	BUG_ON(!irqs_disabled());
-
-	error = syscore_suspend();
+	/* FIXME syscore suspend/resume is not working for HGW build */
+	//error = syscore_suspend();
+	error = 0;
 	if (!error) {
 		*wakeup = pm_wakeup_pending();
 		if (!(suspend_test(TEST_CORE) || *wakeup)) {
 			error = suspend_ops->enter(state);
 			events_check_enabled = false;
 		}
-		syscore_resume();
+		//syscore_resume();
 	}
 
 	arch_suspend_enable_irqs();
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 2c71d91..e34cc37 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -202,7 +202,11 @@
  * we want to handle softirqs as soon as possible, but they
  * should not be able to lock up the box.
  */
+#if defined(CONFIG_ARCH_COMCERTO)
+#define MAX_SOFTIRQ_RESTART 2
+#else
 #define MAX_SOFTIRQ_RESTART 10
+#endif
 
 asmlinkage void __do_softirq(void)
 {
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index 2b49dd2..0462891 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -225,12 +225,40 @@
 }
 BDI_SHOW(max_ratio, bdi->max_ratio)
 
+#ifdef CONFIG_ARCH_M86XXX
+static ssize_t cpu0_bind_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct backing_dev_info *bdi = dev_get_drvdata(dev);
+	unsigned int flag;
+
+	flag = simple_strtoul(buf, NULL, 10);
+	if (flag)
+		bdi->cpu0_bind = 1;
+	else
+		bdi->cpu0_bind = 0;
+
+	return count;
+}
+
+static ssize_t cpu0_bind_show(struct device *dev,
+			   struct device_attribute *attr, char *page)
+{
+	struct backing_dev_info *bdi = dev_get_drvdata(dev);
+
+	return snprintf(page, PAGE_SIZE-1, "%d\n", bdi->cpu0_bind);
+}
+#endif /* CONFIG_ARCH_M86XXX */
+
 #define __ATTR_RW(attr) __ATTR(attr, 0644, attr##_show, attr##_store)
 
 static struct device_attribute bdi_dev_attrs[] = {
 	__ATTR_RW(read_ahead_kb),
 	__ATTR_RW(min_ratio),
 	__ATTR_RW(max_ratio),
+#ifdef CONFIG_ARCH_M86XXX
+	__ATTR_RW(cpu0_bind),
+#endif
 	__ATTR_NULL,
 };
 
@@ -478,6 +506,10 @@
 				writeback_inodes_wb(&bdi->wb, 1024,
 						    WB_REASON_FORKER_THREAD);
 			} else {
+#ifdef CONFIG_ARCH_M86XXX
+				if (bdi->cpu0_bind)
+					kthread_bind(task, 0);
+#endif
 				/*
 				 * The spinlock makes sure we do not lose
 				 * wake-ups when racing with 'bdi_queue_work()'.
diff --git a/mm/filemap.c b/mm/filemap.c
index 556858c..e310263 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -28,6 +28,9 @@
 #include <linux/backing-dev.h>
 #include <linux/pagevec.h>
 #include <linux/blkdev.h>
+#ifdef CONFIG_RAID_ZERO_COPY
+#include <linux/rmap.h>
+#endif
 #include <linux/security.h>
 #include <linux/syscalls.h>
 #include <linux/cpuset.h>
@@ -609,10 +612,27 @@
 		BUG();
 
 	smp_mb__after_clear_bit();
+
+#ifdef CONFIG_RAID_ZERO_COPY
+	clear_page_constant(page);
+#endif
+
 	wake_up_page(page, PG_writeback);
 }
 EXPORT_SYMBOL(end_page_writeback);
 
+#ifdef CONFIG_RAID_ZERO_COPY
+void clear_page_constant(struct page *page)
+{
+       if (PageConstant(page)) {
+               ClearPageConstant(page);
+               SetPageUptodate(page);
+       }
+}
+EXPORT_SYMBOL(clear_page_constant);
+#endif
+
+
 /**
  * __lock_page - get a lock on the page, assuming we need to sleep to get it
  * @page: the page to lock
diff --git a/mm/mmap.c b/mm/mmap.c
index eae90af..6e12c5f 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1886,7 +1886,7 @@
 	unmap_vmas(&tlb, vma, start, end, &nr_accounted, NULL);
 	vm_unacct_memory(nr_accounted);
 	free_pgtables(&tlb, vma, prev ? prev->vm_end : FIRST_USER_ADDRESS,
-				 next ? next->vm_start : 0);
+				 next ? next->vm_start : mm->task_size);
 	tlb_finish_mmu(&tlb, start, end);
 }
 
@@ -2261,7 +2261,7 @@
 	end = unmap_vmas(&tlb, vma, 0, -1, &nr_accounted, NULL);
 	vm_unacct_memory(nr_accounted);
 
-	free_pgtables(&tlb, vma, FIRST_USER_ADDRESS, 0);
+	free_pgtables(&tlb, vma, FIRST_USER_ADDRESS, mm->task_size);
 	tlb_finish_mmu(&tlb, 0, end);
 
 	/*
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 065dbe8..b7b898d 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1668,6 +1668,11 @@
 			!cpuset_zone_allowed_softwall(zone, gfp_mask))
 				continue;
 
+#ifdef CONFIG_COMCERTO_ZONE_DMA_NCNB
+		if (!(gfp_mask & __GFP_DMA) && (zone_idx(zone) == ZONE_DMA))
+			continue;
+#endif
+
 		BUILD_BUG_ON(ALLOC_NO_WATERMARKS < NR_WMARK);
 		if (!(alloc_flags & ALLOC_NO_WATERMARKS)) {
 			unsigned long mark;
diff --git a/mm/slab.c b/mm/slab.c
index cd3ab93..8bffa97 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -749,7 +749,7 @@
 	 * for large kmalloc calls required.
 	 */
 #ifdef CONFIG_ZONE_DMA
-	if (unlikely(gfpflags & GFP_DMA))
+	if (unlikely(gfpflags & __GFP_DMA))
 		return csizep->cs_dmacachep;
 #endif
 	return csizep->cs_cachep;
@@ -2445,7 +2445,8 @@
 	cachep->flags = flags;
 	cachep->gfpflags = 0;
 	if (CONFIG_ZONE_DMA_FLAG && (flags & SLAB_CACHE_DMA))
-		cachep->gfpflags |= GFP_DMA;
+		cachep->gfpflags |= __GFP_DMA;
+
 	cachep->buffer_size = size;
 	cachep->reciprocal_buffer_size = reciprocal_value(size);
 
@@ -2791,10 +2792,10 @@
 static void kmem_flagcheck(struct kmem_cache *cachep, gfp_t flags)
 {
 	if (CONFIG_ZONE_DMA_FLAG) {
-		if (flags & GFP_DMA)
-			BUG_ON(!(cachep->gfpflags & GFP_DMA));
+		if (flags & __GFP_DMA)
+			BUG_ON(!(cachep->gfpflags & __GFP_DMA));
 		else
-			BUG_ON(cachep->gfpflags & GFP_DMA);
+			BUG_ON(cachep->gfpflags & __GFP_DMA);
 	}
 }
 
diff --git a/net/bridge/br.c b/net/bridge/br.c
index f20c4fd..e92aa84 100644
--- a/net/bridge/br.c
+++ b/net/bridge/br.c
@@ -100,6 +100,60 @@
 	br_fdb_fini();
 }
 
+#if defined(CONFIG_ARCH_COMCERTO)
+static ATOMIC_NOTIFIER_HEAD(brevent_notif_chain);
+
+/**
+ *	register_brevent_notifier - register a netevent notifier block
+ *	@nb: notifier
+ *
+ *	Register a notifier to be called when a bridge event occurs.
+ *	The notifier passed is linked into the kernel structures and must
+ *	not be reused until it has been unregistered. A negative errno code
+ *	is returned on a failure.
+ */
+int register_brevent_notifier(struct notifier_block *nb)
+{
+	int err;
+
+	err = atomic_notifier_chain_register(&brevent_notif_chain, nb);
+	return err;
+}
+
+/**
+ *	unregister_brevent_notifier - unregister a netevent notifier block
+ *	@nb: notifier
+ *
+ *	Unregister a notifier previously registered by
+ *	register_neigh_notifier(). The notifier is unlinked into the
+ *	kernel structures and may then be reused. A negative errno code
+ *	is returned on a failure.
+ */
+
+int unregister_brevent_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&brevent_notif_chain, nb);
+}
+
+/**
+ *	call_brevent_notifiers - call all netevent notifier blocks
+ *      @val: value passed unmodified to notifier function
+ *      @v:   pointer passed unmodified to notifier function
+ *
+ *	Call all neighbour notifier blocks.  Parameters and return value
+ *	are as for notifier_call_chain().
+ */
+
+int call_brevent_notifiers(unsigned long val, void *v)
+{
+	return atomic_notifier_call_chain(&brevent_notif_chain, val, v);
+}
+
+EXPORT_SYMBOL_GPL(register_brevent_notifier);
+EXPORT_SYMBOL_GPL(unregister_brevent_notifier);
+EXPORT_SYMBOL_GPL(call_brevent_notifiers);
+#endif
+
 module_init(br_init)
 module_exit(br_deinit)
 MODULE_LICENSE("GPL");
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index c8e7861..3ae122f 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -18,6 +18,10 @@
 #include <linux/times.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#if defined(CONFIG_ARCH_COMCERTO)
+#include <linux/rtnetlink.h>
+#include <linux/module.h>
+#endif
 #include <linux/jhash.h>
 #include <linux/random.h>
 #include <linux/slab.h>
@@ -32,6 +36,11 @@
 
 static u32 fdb_salt __read_mostly;
 
+#if defined(CONFIG_ARCH_COMCERTO)
+	int(*br_fdb_can_expire)(unsigned char *mac_addr, struct net_device *dev) = NULL;
+	DEFINE_SPINLOCK(br_fdb_cb_lock);
+#endif
+
 int __init br_fdb_init(void)
 {
 	br_fdb_cache = kmem_cache_create("bridge_fdb_cache",
@@ -42,6 +51,9 @@
 		return -ENOMEM;
 
 	get_random_bytes(&fdb_salt, sizeof(fdb_salt));
+#if defined(CONFIG_ARCH_COMCERTO)
+	spin_lock_init(&br_fdb_cb_lock);
+#endif
 	return 0;
 }
 
@@ -142,6 +154,15 @@
 			unsigned long this_timer;
 			if (f->is_static)
 				continue;
+#if defined(CONFIG_ARCH_COMCERTO)
+				spin_lock(&br_fdb_cb_lock);
+				if(br_fdb_can_expire && !(*br_fdb_can_expire)(f->addr.addr, f->dst->dev)){
+					f->updated = jiffies;
+					spin_unlock(&br_fdb_cb_lock);
+					continue;
+				}
+				spin_unlock(&br_fdb_cb_lock);
+#endif
 			this_timer = f->updated + delay;
 			if (time_before_eq(this_timer, jiffies))
 				fdb_delete(f);
@@ -418,7 +439,19 @@
 					"own address as source address\n",
 					source->dev->name);
 		} else {
-			/* fastpath: update of existing entry */
+				/* fastpath: update of existing entry */
+#if defined(CONFIG_ARCH_COMCERTO)
+				if (fdb->dst != source) {
+					struct brevent_fdb_update fdb_update;
+
+					fdb_update.dev = source->dev;
+					fdb_update.mac_addr = fdb->addr.addr;
+					//FIXME
+					//__rtmsg_ifinfo(RTM_NEWLINK, br->dev, 0, GFP_ATOMIC);
+					//FIXME
+					call_brevent_notifiers(BREVENT_FDB_UPDATE, &fdb_update);
+				}
+#endif
 			fdb->dst = source;
 			fdb->updated = jiffies;
 		}
@@ -434,6 +467,24 @@
 	}
 }
 
+#if defined(CONFIG_ARCH_COMCERTO)
+void br_fdb_register_can_expire_cb(int(*cb)(unsigned char *mac_addr, struct net_device *dev))
+{
+        spin_lock_bh(&br_fdb_cb_lock);
+        br_fdb_can_expire = cb;
+        spin_unlock_bh(&br_fdb_cb_lock);
+}
+EXPORT_SYMBOL(br_fdb_register_can_expire_cb);
+
+void br_fdb_deregister_can_expire_cb()
+{
+        spin_lock_bh(&br_fdb_cb_lock);
+        br_fdb_can_expire = NULL;
+        spin_unlock_bh(&br_fdb_cb_lock);
+}
+EXPORT_SYMBOL(br_fdb_deregister_can_expire_cb);
+#endif
+
 static int fdb_to_nud(const struct net_bridge_fdb_entry *fdb)
 {
 	if (fdb->is_local)
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index 69e0c8f..eb602b9 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -43,7 +43,11 @@
 {
 	/* ip_fragment doesn't copy the MAC header */
 	if (nf_bridge_maybe_copy_header(skb) ||
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+	    (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb) && (!skb->ipsec_offload))) {
+#else
 	    (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb))) {
+#endif
 		kfree_skb(skb);
 	} else {
 		skb_push(skb, ETH_HLEN);
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 988c300..b457fd7 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -70,6 +70,10 @@
 
 	BR_INPUT_SKB_CB(skb)->brdev = br->dev;
 
+#if defined(CONFIG_ARCH_COMCERTO)
+	skb->cb[4] = 0;
+#endif
+
 	/* The packet skb2 goes to the local host (NULL to skip). */
 	skb2 = NULL;
 
@@ -108,6 +112,10 @@
 	if (skb) {
 		if (dst) {
 			dst->used = jiffies;
+#if defined(CONFIG_ARCH_COMCERTO)
+			/* Used by ABM module */
+			skb->cb[4] = 1;
+#endif
 			br_forward(dst->dst, skb, skb2);
 		} else
 			br_flood_forward(br, skb, skb2);
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 4d6fb62..4c6dbbd 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -359,6 +359,10 @@
 extern void br_fdb_update(struct net_bridge *br,
 			  struct net_bridge_port *source,
 			  const unsigned char *addr);
+#if defined(CONFIG_ARCH_COMCERTO)
+	extern void br_fdb_register_can_expire_cb(int(*cb)(unsigned char *mac_addr, struct net_device *dev)); 
+	extern void br_fdb_deregister_can_expire_cb(void);
+#endif 
 extern int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb);
 extern int br_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
 extern int br_fdb_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index 19308e3..43d67aa 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -121,6 +121,10 @@
 
 	if (br_is_root_bridge(br) && !wasroot)
 		br_become_root_bridge(br);
+
+#if defined(CONFIG_ARCH_COMCERTO)
+	call_brevent_notifiers(BREVENT_PORT_DOWN, p->dev);
+#endif
 }
 
 static void br_stp_start(struct net_bridge *br)
diff --git a/net/core/datagram.c b/net/core/datagram.c
index 68bbf9f..624b6b8 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -128,6 +128,188 @@
 	goto out;
 }
 
+#if defined(CONFIG_COMCERTO_IMPROVED_SPLICE)
+/*
+ *	skb_copy_datagram_to_kernel_iovec - Copy a datagram to a kernel iovec structure.
+ *	@skb: buffer to copy
+ *	@offset: offset in the buffer to start copying from
+ *	@to: io vector to copy to
+ *	@len: amount of data to copy from buffer to iovec
+ *
+ *	Note: the iovec is modified during the copy.
+ */
+
+#if defined(CONFIG_COMCERTO_SPLICE_USE_MDMA)
+int skb_copy_datagram_to_kernel_iovec_soft(const struct sk_buff *skb, int offset,
+				      struct iovec *to, int len)
+#else
+int skb_copy_datagram_to_kernel_iovec(const struct sk_buff *skb, int offset,
+				      struct iovec *to, int len)
+#endif
+{
+	int i, fraglen, end = 0;
+	struct sk_buff *next = skb_shinfo(skb)->frag_list;
+
+	if (!len)
+		return 0;
+
+next_skb:
+	fraglen = skb_headlen(skb);
+	i = -1;
+
+	while (1) {
+		int start = end;
+
+		if ((end += fraglen) > offset) {
+			int copy = end - offset;
+			int o = offset - start;
+
+			if (copy > len)
+				copy = len;
+			if (i == -1)
+				memcpy_tokerneliovec(to, skb->data + o, copy);
+			else {
+				skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+				struct page *page = skb_frag_page(frag);
+				void *p = kmap(page) + frag->page_offset + o;
+				memcpy_tokerneliovec(to, p, copy);
+				kunmap(page);
+			}
+
+			if (!(len -= copy))
+				return 0;
+			offset += copy;
+		}
+		if (++i >= skb_shinfo(skb)->nr_frags)
+			break;
+		fraglen = skb_shinfo(skb)->frags[i].size;
+	}
+	if (next) {
+		skb = next;
+		BUG_ON(skb_shinfo(skb)->frag_list);
+		next = skb->next;
+		goto next_skb;
+	}
+
+	return -EFAULT;
+}
+
+#if defined(CONFIG_COMCERTO_SPLICE_USE_MDMA)
+#include <mach/hardware.h>
+#include <mach/dma.h>
+int skb_copy_datagram_to_kernel_iovec(const struct sk_buff *skb, int offset,
+				      struct iovec *to, int len)
+{
+	int i, ret, fraglen, copy, o, end = 0;
+	struct sk_buff *next = skb_shinfo(skb)->frag_list;
+
+	struct comcerto_dma_sg *sg;
+	unsigned int size;
+	int total_len, input_len;
+	if (!len)
+		return 0;
+
+	total_len = len;
+	
+	size = sizeof(struct comcerto_dma_sg);
+	sg = kmalloc(size, GFP_ATOMIC);
+	if (!sg)
+		return skb_copy_datagram_to_kernel_iovec_soft (skb, offset, to, len);
+
+	comcerto_dma_sg_init(sg);
+
+next_skb:
+	fraglen = skb_headlen(skb);
+	i = -1;
+
+	while (1) {
+		int start = end;
+
+		if ((end += fraglen) > offset) {
+current_frag:
+			copy = end - offset;
+			o = offset - start;
+
+			if (copy > len)
+				copy = len;
+			
+			// preparing input
+			if (i == -1) {
+				ret = comcerto_dma_sg_add_input(sg, skb->data + o, copy, 0);
+			} else {
+				skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+				struct page *page = skb_frag_page(frag);
+				void *p = page_address(page) + frag->page_offset + o;
+				ret = comcerto_dma_sg_add_input(sg, p, copy, 0);
+			}
+			if (likely(ret == 0)) {
+				len -= copy;
+				offset += copy;
+			}
+
+			if ((len == 0) || unlikely(ret))
+			{
+				input_len = total_len - len;
+				len = input_len;
+				//preparing output
+				while (len > 0) {
+					if (to->iov_len) {
+						int copy = min_t(unsigned int, to->iov_len, len);
+
+						ret = comcerto_dma_sg_add_output(sg, to->iov_base, copy, 1);
+						if (unlikely(ret)) {
+							/* no clean way out, but this should never happen the way
+							 * skb_copy_datagram_to_kernel_iovec is called currently.
+							 */
+							comcerto_dma_sg_cleanup(sg, input_len);
+							kfree(sg);
+							return -EFAULT;
+						}
+						len -= copy;
+						to->iov_base += copy;
+						to->iov_len -= copy;
+					}
+					if (to->iov_len == 0)
+						to++;
+				}
+
+				//let's run the dma operation
+				comcerto_dma_get();
+				comcerto_dma_sg_setup(sg, input_len);
+				comcerto_dma_start();
+				comcerto_dma_wait();
+				comcerto_dma_put();
+				comcerto_dma_sg_cleanup(sg, input_len);
+
+				total_len = total_len - input_len;
+				if (total_len) {// Yes => last input fragment failed, add it again
+					comcerto_dma_sg_init(sg);
+					goto current_frag;
+				} else { //Everything copied, exit successfully
+					kfree(sg);
+					return 0;
+				}
+
+			}
+		}
+		if (++i >= skb_shinfo(skb)->nr_frags)
+			break;
+		fraglen = skb_shinfo(skb)->frags[i].size;
+	}
+	if (next) {
+		skb = next;
+		BUG_ON(skb_shinfo(skb)->frag_list);
+		next = skb->next;
+		goto next_skb;
+	}
+
+	comcerto_dma_sg_cleanup(sg, total_len - len);
+	kfree(sg);
+	return -EFAULT;
+}
+#endif
+#endif
+
 /**
  *	__skb_recv_datagram - Receive a datagram skbuff
  *	@sk: socket
diff --git a/net/core/dev.c b/net/core/dev.c
index 5738654..35ac2f6 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2460,6 +2460,16 @@
  */
 int dev_queue_xmit(struct sk_buff *skb)
 {
+#if defined(CONFIG_ARCH_COMCERTO)
+	if (skb->dev->flags & IFF_WIFI_OFLD)
+		skb->dev = skb->dev->wifi_offload_dev;
+
+	return original_dev_queue_xmit(skb);
+}
+
+int original_dev_queue_xmit(struct sk_buff *skb)
+{
+#endif
 	struct net_device *dev = skb->dev;
 	struct netdev_queue *txq;
 	struct Qdisc *q;
@@ -2539,6 +2549,10 @@
 }
 EXPORT_SYMBOL(dev_queue_xmit);
 
+#if defined(CONFIG_ARCH_COMCERTO)
+EXPORT_SYMBOL(original_dev_queue_xmit);
+#endif
+
 
 /*=======================================================================
 			Receiver routines
@@ -3367,6 +3381,52 @@
 }
 EXPORT_SYMBOL(netif_receive_skb);
 
+#if defined(CONFIG_ARCH_COMCERTO)
+int capture_receive_skb(struct sk_buff *skb)
+{
+        struct net_device *null_or_orig = NULL;
+        struct packet_type *ptype, *pt_prev;
+        struct net_device *orig_dev;
+        int ret = NET_RX_DROP;
+
+	if (!netdev_tstamp_prequeue)
+		net_timestamp_check(skb);
+
+        if (!skb->skb_iif)
+                skb->skb_iif = skb->dev->ifindex;
+
+        skb_reset_network_header(skb);
+        skb_reset_transport_header(skb);
+	skb_reset_mac_len(skb);
+
+        pt_prev = NULL;
+        orig_dev = skb->dev;
+
+        rcu_read_lock();
+        list_for_each_entry_rcu(ptype, &ptype_all, list) {
+                if (!ptype->dev || ptype->dev == skb->dev) {
+                        if (pt_prev)
+                                ret = deliver_skb(skb, pt_prev, orig_dev);
+                        pt_prev = ptype;
+                }
+        }
+
+        if (pt_prev) {
+                ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
+        } else {
+                kfree_skb(skb);
+                /* Jamal, now you will not able to escape explaining
+                 * me how you were going to use this. :-)
+                 */
+                ret = NET_RX_DROP;
+        }
+        rcu_read_unlock();
+        return ret;
+}
+
+EXPORT_SYMBOL(capture_receive_skb);
+#endif
+
 /* Network device is going away, flush any packets still pending
  * Called with irqs disabled.
  */
diff --git a/net/core/flow.c b/net/core/flow.c
index e318c7e..a0e9eaa 100644
--- a/net/core/flow.c
+++ b/net/core/flow.c
@@ -22,6 +22,9 @@
 #include <linux/cpumask.h>
 #include <linux/mutex.h>
 #include <net/flow.h>
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+#include <net/xfrm.h>
+#endif
 #include <linux/atomic.h>
 #include <linux/security.h>
 
@@ -36,6 +39,10 @@
 	u32				genid;
 	struct flowi			key;
 	struct flow_cache_object	*object;
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+	u8				flags;
+	#define FLOW_CACHE_FLAG_IPSEC_OFFLOAD 0x01
+#endif
 };
 
 struct flow_cache_percpu {
@@ -44,6 +51,9 @@
 	u32				hash_rnd;
 	int				hash_rnd_recalc;
 	struct tasklet_struct		flush_tasklet;
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+	struct tasklet_struct		flowcache_rem_tasklet;
+#endif
 };
 
 struct flow_flush_info {
@@ -61,6 +71,16 @@
 	struct timer_list		rnd_timer;
 };
 
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+struct flow_remove_info {
+	struct flow_cache		*cache;
+	struct flowi			*key;
+	unsigned short			family;
+	unsigned short			dir;
+	atomic_t			cpuleft;
+	struct completion		completion;
+};
+#endif
 atomic_t flow_cache_genid = ATOMIC_INIT(0);
 EXPORT_SYMBOL(flow_cache_genid);
 static struct flow_cache flow_cache_global;
@@ -72,6 +92,10 @@
 #define flow_cache_hash_size(cache)	(1 << (cache)->hash_shift)
 #define FLOW_HASH_RND_PERIOD		(10 * 60 * HZ)
 
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+extern int ipsec_nlkey_flow_remove(struct flowi *fl, u16 family, u16 dir);
+#endif
+
 static void flow_cache_new_hashrnd(unsigned long arg)
 {
 	struct flow_cache *fc = (void *) arg;
@@ -110,8 +134,14 @@
 	list_splice_tail_init(&flow_cache_gc_list, &gc_list);
 	spin_unlock_bh(&flow_cache_gc_lock);
 
-	list_for_each_entry_safe(fce, n, &gc_list, u.gc_list)
+	list_for_each_entry_safe(fce, n, &gc_list, u.gc_list) {
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+		/*call nl_key_flow_remove*/
+		if (fce->flags & FLOW_CACHE_FLAG_IPSEC_OFFLOAD)
+			ipsec_nlkey_flow_remove(&fce->key, fce->family, fce->dir);
+#endif
 		flow_entry_kill(fce);
+	}
 }
 static DECLARE_WORK(flow_cache_gc_work, flow_cache_gc_task);
 
@@ -204,9 +234,15 @@
 	return 0;
 }
 
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+struct flow_cache_object *
+flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir,
+			u8 *new_flow, flow_resolve_t resolver, void *ctx)
+#else
 struct flow_cache_object *
 flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir,
 		  flow_resolve_t resolver, void *ctx)
+#endif
 {
 	struct flow_cache *fc = &flow_cache_global;
 	struct flow_cache_percpu *fcp;
@@ -216,6 +252,11 @@
 	size_t keysize;
 	unsigned int hash;
 
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+	if (new_flow)
+		*new_flow = 0;
+#endif
+
 	local_bh_disable();
 	fcp = this_cpu_ptr(fc->percpu);
 
@@ -281,8 +322,15 @@
 	flo = resolver(net, key, family, dir, flo, ctx);
 	if (fle) {
 		fle->genid = atomic_read(&flow_cache_genid);
-		if (!IS_ERR(flo))
+		if (!IS_ERR(flo)) {
 			fle->object = flo;
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+			if (new_flow) {
+				*new_flow = 1;
+				fle->flags |= FLOW_CACHE_FLAG_IPSEC_OFFLOAD;
+			}
+#endif
+		}
 		else
 			fle->genid--;
 	} else {
@@ -358,6 +406,83 @@
 	put_online_cpus();
 }
 
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+static void flow_cache_remove_per_cpu(void *data)
+{
+	struct flow_remove_info* info = data;
+	int cpu;
+	struct tasklet_struct *tasklet;
+
+	cpu = smp_processor_id();
+	tasklet = &per_cpu_ptr(info->cache->percpu, cpu)->flowcache_rem_tasklet;
+	tasklet->data = (unsigned long)info;
+	tasklet_schedule(tasklet);
+}
+
+void flow_cache_remove_tasklet(unsigned long data) 
+{
+	struct flow_remove_info* info = (struct flow_remove_info*) data;
+	struct flow_cache *fc = &flow_cache_global;
+	struct flow_cache_percpu *fcp;
+	struct flow_cache_entry *fle;
+	struct hlist_node *entry;
+	size_t keysize;
+	unsigned int hash;
+	struct flowi *key = info->key;
+	unsigned short family = info->family;
+	unsigned short dir = info->dir;
+
+	fcp = this_cpu_ptr(fc->percpu);
+	
+	keysize = flow_key_size(family);
+	if (!keysize)
+		goto nocache;
+
+	hash = flow_hash_code(fc, fcp, key, keysize);
+	
+	hlist_for_each_entry(fle, entry, &fcp->hash_table[hash], u.hlist) {
+		if((fle->family == family) && (fle->dir == dir) && (flow_key_compare(&fle->key, key, keysize) == 0)) {
+			hlist_del(&fle->u.hlist);
+			flow_entry_kill(fle);
+			break;
+		}
+	}
+		
+nocache:	
+	if (atomic_dec_and_test(&info->cpuleft))
+		complete(&info->completion);
+	return;
+}
+
+void flow_cache_remove(const struct flowi *key,
+			unsigned short family, unsigned short dir)
+{
+	struct flow_remove_info info;
+	static DEFINE_MUTEX(flow_rem_sem);
+
+	/* Don't want cpus going down or up during this. */
+	get_online_cpus();
+	mutex_lock(&flow_rem_sem);
+	info.cache = &flow_cache_global;
+	info.key = (struct flowi*)key;
+	//memcpy(&info.key, key, sizeof(struct flowi));
+	info.family = family;
+	info.dir = dir;
+        atomic_set(&info.cpuleft, num_online_cpus());
+        init_completion(&info.completion);
+
+        local_bh_disable();
+	smp_call_function(flow_cache_remove_per_cpu, &info, 1);
+	flow_cache_remove_tasklet((unsigned long)&info);
+        local_bh_enable();
+
+        wait_for_completion(&info.completion);
+        mutex_unlock(&flow_rem_sem);
+        put_online_cpus();
+}
+
+#endif
+
 static void flow_cache_flush_task(struct work_struct *work)
 {
 	flow_cache_flush();
@@ -384,6 +509,9 @@
 		fcp->hash_rnd_recalc = 1;
 		fcp->hash_count = 0;
 		tasklet_init(&fcp->flush_tasklet, flow_cache_flush_tasklet, 0);
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+		tasklet_init(&fcp->flowcache_rem_tasklet, flow_cache_remove_tasklet, 0);
+#endif
 	}
 	return 0;
 }
diff --git a/net/core/iovec.c b/net/core/iovec.c
index c40f27e..6665c0c 100644
--- a/net/core/iovec.c
+++ b/net/core/iovec.c
@@ -124,6 +124,28 @@
 }
 EXPORT_SYMBOL(memcpy_toiovecend);
 
+#if defined(CONFIG_COMCERTO_IMPROVED_SPLICE)
+/*
+ *	In kernel copy to iovec. Returns -EFAULT on error.
+ *
+ *	Note: this modifies the original iovec.
+ */
+void memcpy_tokerneliovec(struct iovec *iov, unsigned char *kdata, int len)
+{
+	while (len > 0) {
+		if (iov->iov_len) {
+			int copy = min_t(unsigned int, iov->iov_len, len);
+			memcpy(iov->iov_base, kdata, copy);
+			len -= copy;
+			kdata += copy;
+			iov->iov_base += copy;
+			iov->iov_len -= copy;
+		}
+		iov++;
+	}
+}
+#endif
+
 /*
  *	Copy iovec to kernel. Returns -EFAULT on error.
  *
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 7aafaed..fba58b8 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1138,6 +1138,10 @@
 						 neigh->parms->reachable_time :
 						 0)));
 		neigh->nud_state = new;
+#ifdef CONFIG_COMCERTO_FP
+		if ((old & (NUD_STALE | NUD_DELAY | NUD_PROBE)) && (new & NUD_REACHABLE))
+			notify = 1;
+#endif
 	}
 
 	if (lladdr != neigh->ha) {
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 2ef859a..403a253 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -622,7 +622,40 @@
 	return -EMSGSIZE;
 }
 EXPORT_SYMBOL(rtnetlink_put_metrics);
+#ifdef CONFIG_ARCH_COMCERTO
+int rtnetlink_put_metrics_2(struct sk_buff *skb, u32 *metrics, struct dst_entry *dst)
+{
+	struct nlattr *mx;
+	int i, valid = 0;
 
+	mx = nla_nest_start(skb, RTA_METRICS);
+	if (mx == NULL)
+		return -ENOBUFS;
+
+	for (i = 0; i < RTAX_MAX; i++) {
+		if (metrics[i]) {
+			valid++;
+			NLA_PUT_U32(skb, i+1, metrics[i]);
+		}
+		else if ((i + 1) == RTAX_MTU){
+			valid++;
+			NLA_PUT_U32(skb, i+1, dst_mtu(dst));
+		}
+	}
+
+	if (!valid) {
+		nla_nest_cancel(skb, mx);
+		return 0;
+	}
+
+	return nla_nest_end(skb, mx);
+
+nla_put_failure:
+	nla_nest_cancel(skb, mx);
+	return -EMSGSIZE;
+}
+EXPORT_SYMBOL(rtnetlink_put_metrics_2);
+#endif
 int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst, u32 id,
 		       u32 ts, u32 tsage, long expires, u32 error)
 {
@@ -1902,14 +1935,14 @@
 	return skb->len;
 }
 
-void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
+void __rtmsg_ifinfo(int type, struct net_device *dev, unsigned change, gfp_t flags)
 {
 	struct net *net = dev_net(dev);
 	struct sk_buff *skb;
 	int err = -ENOBUFS;
 	size_t if_info_size;
 
-	skb = nlmsg_new((if_info_size = if_nlmsg_size(dev)), GFP_KERNEL);
+	skb = nlmsg_new((if_info_size = if_nlmsg_size(dev)), flags);
 	if (skb == NULL)
 		goto errout;
 
@@ -1922,12 +1955,24 @@
 		kfree_skb(skb);
 		goto errout;
 	}
-	rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
+	rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, flags);
 	return;
 errout:
 	if (err < 0)
 		rtnl_set_sk_err(net, RTNLGRP_LINK, err);
 }
+#if defined(CONFIG_ARCH_COMCERTO)
+EXPORT_SYMBOL(__rtmsg_ifinfo);
+#endif
+
+void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
+{
+	__rtmsg_ifinfo(type, dev, change, GFP_KERNEL);
+}
+#if defined(CONFIG_COMCERTO_FP)
+EXPORT_SYMBOL(rtmsg_ifinfo);
+#endif
+
 
 /* Protected by RTNL sempahore.  */
 static struct rtattr **rta_buf;
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index af9c3c6..d325941 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -218,6 +218,10 @@
 	skb->mac_header = ~0U;
 #endif
 
+#if defined(CONFIG_COMCERTO_CUSTOM_SKB_LAYOUT)
+	skb->mspd_data = NULL;
+	skb->mspd_len = 0;
+#endif
 	/* make sure we initialize shinfo sequentially */
 	shinfo = skb_shinfo(skb);
 	memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
@@ -244,6 +248,93 @@
 }
 EXPORT_SYMBOL(__alloc_skb);
 
+#if defined(CONFIG_ARCH_COMCERTO)
+/**
+ *	__alloc_skb_header	-	allocate a network buffer
+ *	@size: size to allocate
+ *	@gfp_mask: allocation mask
+ *	@fclone: allocate from fclone cache instead of head cache
+ *		and allocate a cloned (child) skb
+ *
+ *	Allocate a new &sk_buff. The returned buffer has no headroom and a
+ *	tail room of size bytes. The object has a reference count of one.
+ *	The return is the buffer. On a failure the return is %NULL.
+ *
+ *	Buffers may only be allocated from interrupts using a @gfp_mask of
+ *	%GFP_ATOMIC.
+ */
+struct sk_buff *__alloc_skb_header(unsigned int size, void *data, gfp_t gfp_mask,
+			    int fclone, int node)
+{
+	struct kmem_cache *cache;
+	struct skb_shared_info *shinfo;
+	struct sk_buff *skb;
+
+	cache = fclone ? skbuff_fclone_cache : skbuff_head_cache;
+
+	if (size <= SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) {
+		skb = NULL;
+		goto out;
+	}
+
+	/* Get the HEAD */
+	skb = kmem_cache_alloc_node(cache, gfp_mask & ~__GFP_DMA, node);
+	if (!skb)
+		goto out;
+	prefetchw(skb);
+
+	/* kmalloc might give us more room than requested.
+	 * Put skb_shared_info exactly at the end of allocated zone,
+	 * to allow max possible filling before reallocation.
+	 */
+	size = SKB_WITH_OVERHEAD(ksize(data));
+	prefetchw(data + size);
+
+	/*
+	 * Only clear those fields we need to clear, not those that we will
+	 * actually initialise below. Hence, don't put any more fields after
+	 * the tail pointer in struct sk_buff!
+	 */
+	memset(skb, 0, offsetof(struct sk_buff, tail));
+	/* Account for allocated memory : skb + skb->head */
+	skb->truesize = SKB_TRUESIZE(size);
+	atomic_set(&skb->users, 1);
+	skb->head = data;
+	skb->data = data;
+	skb_reset_tail_pointer(skb);
+	skb->end = skb->tail + size;
+#ifdef NET_SKBUFF_DATA_USES_OFFSET
+	skb->mac_header = ~0U;
+#endif
+
+#if defined(CONFIG_COMCERTO_CUSTOM_SKB_LAYOUT)
+	skb->mspd_data = NULL;
+	skb->mspd_len = 0;
+#endif
+
+	/* make sure we initialize shinfo sequentially */
+	shinfo = skb_shinfo(skb);
+	memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
+	atomic_set(&shinfo->dataref, 1);
+	kmemcheck_annotate_variable(shinfo->destructor_arg);
+
+	if (fclone) {
+		struct sk_buff *child = skb + 1;
+		atomic_t *fclone_ref = (atomic_t *) (child + 1);
+
+		kmemcheck_annotate_bitfield(child, flags1);
+		kmemcheck_annotate_bitfield(child, flags2);
+		skb->fclone = SKB_FCLONE_ORIG;
+		atomic_set(fclone_ref, 1);
+
+		child->fclone = SKB_FCLONE_UNAVAILABLE;
+	}
+out:
+	return skb;
+}
+EXPORT_SYMBOL(__alloc_skb_header);
+#endif
+
 /**
  *	__netdev_alloc_skb - allocate an skbuff for rx on a specific device
  *	@dev: network device to receive on
@@ -356,6 +447,13 @@
 			skb_drop_fraglist(skb);
 
 		kfree(skb->head);
+
+#if defined(CONFIG_COMCERTO_CUSTOM_SKB_LAYOUT)
+		if (skb->mspd_data) {
+			kfree(skb->mspd_data);
+			skb->mspd_data = NULL;
+		}
+#endif
 	}
 }
 
@@ -497,6 +595,9 @@
 {
 	struct skb_shared_info *shinfo;
 
+#if defined(CONFIG_COMCERTO_CUSTOM_SKB_LAYOUT)
+	WARN_ON(skb->mspd_len);
+#endif
 	skb_release_head_state(skb);
 
 	shinfo = skb_shinfo(skb);
@@ -546,6 +647,9 @@
 #ifdef CONFIG_XFRM
 	new->sp			= secpath_get(old->sp);
 #endif
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+        new->ipsec_offload      = old->ipsec_offload;
+#endif
 	memcpy(new->cb, old->cb, sizeof(old->cb));
 	new->csum		= old->csum;
 	new->local_df		= old->local_df;
@@ -583,6 +687,24 @@
 {
 #define C(x) n->x = skb->x
 
+#if defined(CONFIG_COMCERTO_CUSTOM_SKB_LAYOUT)
+	if (skb->mspd_data) {
+		if (skb->mspd_len) {
+			int ofst = skb->len - skb->mspd_len;
+
+			memcpy(skb->data + ofst, skb->mspd_data + skb->mspd_ofst, skb->mspd_len);
+			skb->mspd_len = 0;
+		}
+
+		WARN_ON(skb_shared(skb));
+
+		if (!skb_shared(skb)) {
+			kfree(skb->mspd_data);
+			skb->mspd_data = NULL;
+		}
+	}
+#endif
+
 	n->next = n->prev = NULL;
 	n->sk = NULL;
 	__copy_skb_header(n, skb);
@@ -601,6 +723,13 @@
 	C(truesize);
 	atomic_set(&n->users, 1);
 
+#if defined(CONFIG_COMCERTO_CUSTOM_SKB_LAYOUT)
+	WARN_ON(skb->mspd_data);
+	C(mspd_data);
+	C(mspd_len);
+	C(mspd_ofst);
+#endif
+
 	atomic_inc(&(skb_shinfo(skb)->dataref));
 	skb->cloned = 1;
 
@@ -777,6 +906,24 @@
 	if (!n)
 		return NULL;
 
+#if defined(CONFIG_COMCERTO_CUSTOM_SKB_LAYOUT)
+	if (skb->mspd_data) {
+		if (skb->mspd_len) {
+			int ofst = skb->len - skb->mspd_len;
+
+			memcpy(skb->data + ofst, skb->mspd_data + skb->mspd_ofst, skb->mspd_len);
+			((struct sk_buff *)skb)->mspd_len = 0;
+		}
+
+		WARN_ON(skb_shared(skb));
+
+		if (!skb_shared(skb)) {
+			kfree(skb->mspd_data);
+			((struct sk_buff *)skb)->mspd_data = NULL;
+		}
+	}
+#endif
+
 	/* Set the data pointer */
 	skb_reserve(n, headerlen);
 	/* Set the tail pointer and length */
@@ -808,6 +955,10 @@
 	unsigned int size = skb_end_pointer(skb) - skb->head;
 	struct sk_buff *n = alloc_skb(size, gfp_mask);
 
+#if defined(CONFIG_COMCERTO_CUSTOM_SKB_LAYOUT)
+	WARN_ON(skb->mspd_len);
+#endif
+
 	if (!n)
 		goto out;
 
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index cbb505b..b787148 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -339,6 +339,12 @@
 
 	  If unsure, say Y.
 
+config INET_IPSEC_OFFLOAD
+	bool "IPsec Fast Path Processing offload"
+	depends on (INET_ESP || INET_AH) && COMCERTO_FP
+		---help---
+	  Support for IPsec Fast Path offload.
+
 config INET_IPCOMP
 	tristate "IP: IPComp transformation"
 	select INET_XFRM_TUNNEL
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index f2dc69c..3ad63e6 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -22,7 +22,8 @@
 obj-$(CONFIG_NET_IPGRE) += ip_gre.o
 obj-$(CONFIG_SYN_COOKIES) += syncookies.o
 obj-$(CONFIG_INET_AH) += ah4.o
-obj-$(CONFIG_INET_ESP) += esp4.o
+#obj-$(CONFIG_INET_ESP) += esp4.o
+obj-$(CONFIG_INET_IPSEC_OFFLOAD) += esp4.o
 obj-$(CONFIG_INET_IPCOMP) += ipcomp.o
 obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o
 obj-$(CONFIG_INET_XFRM_MODE_BEET) += xfrm4_mode_beet.o
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 0bc95f3..fedf053 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -238,7 +238,13 @@
 		return dst_output(skb);
 	}
 #endif
+
+#if defined(CONFIG_INET_IPSEC_OFFLOAD)
+	if ((skb->ipsec_offload == 0) &&
+		skb->len > ip_skb_dst_mtu(skb) && !skb_is_gso(skb))
+#else
 	if (skb->len > ip_skb_dst_mtu(skb) && !skb_is_gso(skb))
+#endif
 		return ip_fragment(skb, ip_finish_output2);
 	else
 		return ip_finish_output2(skb);
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index 4f47e06..0ab609d 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -81,6 +81,16 @@
 
 	if (IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED)
 		return 0;
+
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+	/* Mindspeed added WA: required to support 4o6 ipsec offload */
+	if(skb->ipsec_offload)
+	{
+		if (IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED)
+			return 0;
+	}
+#endif
+
 	if (xfrm_decode_session(skb, &fl, AF_INET) < 0)
 		return -1;
 
diff --git a/net/ipv4/netfilter/nf_nat_proto_common.c b/net/ipv4/netfilter/nf_nat_proto_common.c
index a3d9976..986a298 100644
--- a/net/ipv4/netfilter/nf_nat_proto_common.c
+++ b/net/ipv4/netfilter/nf_nat_proto_common.c
@@ -83,14 +83,123 @@
 	else
 		off = *rover;
 
-	for (i = 0; ; ++off) {
-		*portptr = htons(min + off % range_size);
-		if (++i != range_size && nf_nat_used_tuple(tuple, ct))
-			continue;
-		if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM))
-			*rover = off;
-		return;
-	}
+       /* 4rd specific range NAPT - start */
+       if ((range->flags & IP_NAT_RANGE_4RD_NAPT) && (maniptype == IP_NAT_MANIP_SRC)){
+               __be16 fix_port;
+               __be16 port_min, port_max;
+               u_int16_t port_set_id;
+               u_int16_t mbitlen   = 0 ;
+               u_int16_t offsetlen = 0 ;
+               u_int16_t psidlen   = 0 ;
+               u_int16_t range_total_size = 0 ;
+               u_int16_t offset_4rd;
+               u_int16_t o_state;
+               u_int16_t m_state;
+
+               u_int16_t offset_min;
+               u_int16_t offset_max;
+               u_int16_t offset_cnt;
+               u_int16_t mbit_cnt;
+
+               # define MAXBITLEN 16
+               port_min = ntohs(range->min.all);
+               port_max = ntohs(range->max.all);
+
+               for(i = 0; i < MAXBITLEN; i++){
+                       if( ((port_min >> i) & 0x0001) == ((port_max >> i) & 0x0001) ){
+                               psidlen++;
+                               i++;
+                               break;
+                       }
+                       else{
+                               mbitlen++;
+                       }
+               }
+
+               for( ; i < MAXBITLEN; i++){
+                       if( ((port_min >> i) & 0x0001) == ((port_max >> i) & 0x0001) ){
+                               psidlen++;
+                       }
+                       else{
+                               break;
+                       }
+               }
+
+               offsetlen = MAXBITLEN - psidlen - mbitlen;
+
+               if((psidlen == 0) || (mbitlen == 0)){
+                       /* ERROR */
+                       printk(KERN_INFO "4rd parameter INVALID");
+               }
+
+               port_set_id = (port_min & port_max) >> mbitlen;
+
+               if( offsetlen ){
+                       if(port_min < 4096){
+                               if(offsetlen > 4){
+
+
+                                       offset_min = 0x1000 >> (psidlen + mbitlen);
+                                       offset_max = (1 << offsetlen) - 1;
+                                       offset_cnt = offset_max - offset_min + 1;
+                                       mbit_cnt = 1 << mbitlen;
+                                       range_total_size = offset_cnt * mbit_cnt;
+                               }
+                               else{
+                                       offset_min = 0x0001;
+                                       offset_cnt = (1 << offsetlen) - 1;
+                                       mbit_cnt = 1 << mbitlen;
+                                       range_total_size = offset_cnt * mbit_cnt;
+                               }
+                       }
+                       else{
+                               offset_min = 0x0000;
+                               offset_cnt = 1 << offsetlen;
+                               mbit_cnt = 1 << mbitlen;
+                               range_total_size = offset_cnt * mbit_cnt;
+                       }
+               }
+               else{
+                       offset_min = 0;
+                       range_total_size = ( 1 << mbitlen ) ;
+               }
+
+               for (i = 0; ; ++off) {
+
+                       offset_4rd = off % range_total_size ;
+
+                       if ( mbitlen != 0 ){
+                               o_state = offset_4rd / ( 1 << mbitlen ) ;
+                               m_state = offset_4rd % ( 1 << mbitlen ) ;
+                       }else{
+                               o_state = offset_4rd / ( 1 << mbitlen ) ;
+                               m_state = 0 ;
+                       }
+
+                       fix_port = (( offset_min + o_state ) << ( mbitlen + psidlen ));
+                       fix_port |= ( port_set_id << mbitlen );
+                       fix_port |= m_state;
+
+                       *portptr = htons(fix_port);
+
+                       if ((++i != range_total_size) && nf_nat_used_tuple(tuple, ct))
+                               continue;
+
+                       //printk(KERN_INFO "fix_port = %d ",fix_port);
+                       return ;
+               }
+       } /* 4rd specific range NAPT - end */
+       else{
+
+	       for (i = 0; ; ++off) {
+		       *portptr = htons(min + off % range_size);
+		       if (++i != range_size && nf_nat_used_tuple(tuple, ct))
+			       continue;
+		       if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM))
+			       *rover = off;
+		       return;
+	       }
+       }
 	return;
 }
 EXPORT_SYMBOL_GPL(nf_nat_proto_unique_tuple);
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 94cdbc5..3427f9d 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -3013,7 +3013,11 @@
 	if (rt->rt_dst != rt->rt_gateway)
 		NLA_PUT_BE32(skb, RTA_GATEWAY, rt->rt_gateway);
 
+#ifdef CONFIG_ARCH_COMCERTO
+	if (rtnetlink_put_metrics_2(skb, dst_metrics_ptr(&rt->dst), &rt->dst) < 0)
+#else
 	if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
+#endif
 		goto nla_put_failure;
 
 	if (rt->rt_mark)
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 11ba922..132e9fd 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -594,7 +594,15 @@
 
 	return tcp_read_sock(sk, &rd_desc, tcp_splice_data_recv);
 }
-
+#if defined(CONFIG_COMCERTO_SPLICE_PROF)
+unsigned int splicer_time_counter[256];
+unsigned int splicer_reqtime_counter[256];
+unsigned int splicer_data_counter[256];
+unsigned int splicer_tcp_rsock_counter[64];
+static struct timeval last_splicer;
+unsigned int init_splicer_prof = 0;
+extern unsigned int enable_splice_prof;
+#endif
 /**
  *  tcp_splice_read - splice data from TCP socket to a pipe
  * @sock:	socket to splice from
@@ -620,7 +628,28 @@
 	long timeo;
 	ssize_t spliced;
 	int ret;
+#if defined(CONFIG_COMCERTO_SPLICE_PROF)
+	struct timeval now;
+	int diff_time_ms;
 
+	if (enable_splice_prof) {
+		do_gettimeofday(&now);
+		if (init_splicer_prof) {
+			diff_time_ms = ((now.tv_sec - last_splicer.tv_sec) * 1000) + ((now.tv_usec - last_splicer.tv_usec) / 1000);
+			if (diff_time_ms < 1000) {
+				splicer_time_counter[diff_time_ms >> 3]++;
+			}
+			else {
+				splicer_time_counter[255]++;
+			}
+		}
+		if (len < (1 <<21))
+			splicer_data_counter[(len >> 13) & 0xFF]++;
+		else
+			splicer_data_counter[255]++;
+		last_splicer = now;
+	}
+#endif
 	sock_rps_record_flow(sk);
 	/*
 	 * We can't seek on a socket input
@@ -631,7 +660,18 @@
 	ret = spliced = 0;
 
 	lock_sock(sk);
+#if defined(CONFIG_COMCERTO_SPLICE_PROF)
+	/* Need locked socket*/
+	if (enable_splice_prof) {
+		const struct tcp_sock *tp = tcp_sk(sk);
+		int rsock_qsize = tp->rcv_nxt - tp->copied_seq;
 
+		if (rsock_qsize < (4 * 1024 * 1024))
+			splicer_tcp_rsock_counter[(rsock_qsize >> 16) & 0x3F]++;
+		else
+			splicer_tcp_rsock_counter[63]++;
+	}
+#endif
 	timeo = sock_rcvtimeo(sk, sock->file->f_flags & O_NONBLOCK);
 	while (tss.len) {
 		ret = __tcp_splice_read(sk, &tss);
@@ -684,6 +724,23 @@
 
 	release_sock(sk);
 
+#if defined(CONFIG_COMCERTO_SPLICE_PROF)
+	if (enable_splice_prof) {
+		do_gettimeofday(&now);
+
+		diff_time_ms = ((now.tv_sec - last_splicer.tv_sec) * 1000) + ((now.tv_usec - last_splicer.tv_usec) / 1000);
+		if (diff_time_ms < 1000) {//Don't record useless data
+			splicer_reqtime_counter[diff_time_ms >> 3]++;
+		}
+		else
+			splicer_reqtime_counter[255]++;
+
+		if(!init_splicer_prof)
+			init_splicer_prof = 1;
+
+		last_splicer = now;
+	}
+#endif
 	if (spliced)
 		return spliced;
 
@@ -1459,6 +1516,23 @@
 	do {
 		u32 offset;
 
+#if defined(CONFIG_COMCERTO_IMPROVED_SPLICE)
+		if (flags & MSG_NOCATCHSIG) {
+			if (signal_pending(current)) {
+				if (sigismember(&current->pending.signal, SIGQUIT) ||
+				    sigismember(&current->pending.signal, SIGABRT) ||
+				    sigismember(&current->pending.signal, SIGKILL) ||
+				    sigismember(&current->pending.signal, SIGTERM) ||
+				    sigismember(&current->pending.signal, SIGSTOP)) {
+
+					if (copied)
+						break;
+					copied = timeo ? sock_intr_errno(timeo) : -EAGAIN;
+					break;
+				}
+			}
+		} else
+#endif
 		/* Are we at urgent data? Stop if we have read anything or have SIGURG pending. */
 		if (tp->urg_data && tp->urg_seq == *seq) {
 			if (copied)
@@ -1687,8 +1761,16 @@
 			} else
 #endif
 			{
-				err = skb_copy_datagram_iovec(skb, offset,
-						msg->msg_iov, used);
+#if defined(CONFIG_COMCERTO_IMPROVED_SPLICE)
+				if (msg->msg_flags & MSG_KERNSPACE)
+				{
+					err = skb_copy_datagram_to_kernel_iovec(skb,
+							offset, msg->msg_iov, used);
+				}				
+				else
+#endif
+					err = skb_copy_datagram_iovec(skb, offset,
+							msg->msg_iov, used);
 				if (err) {
 					/* Exception. Bailout! */
 					if (!copied)
diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c
index 8280645..2b89f0d 100644
--- a/net/ipv4/xfrm4_tunnel.c
+++ b/net/ipv4/xfrm4_tunnel.c
@@ -3,6 +3,7 @@
  * Copyright (C) 2003 David S. Miller (davem@redhat.com)
  */
 
+
 #include <linux/skbuff.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index 36d7437..a348cf9 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -94,6 +94,12 @@
 
 	  If unsure, say Y.
 
+config INET6_IPSEC_OFFLOAD
+	bool "IPsec IPv6 Fast Path Processing offload"
+	depends on (INET6_ESP && COMCERTO_FP)
+		---help---
+	  Support for IPsec IPv6 Fast Path offload.
+
 config INET6_IPCOMP
 	tristate "IPv6: IPComp transformation"
 	select INET6_XFRM_TUNNEL
@@ -222,6 +228,15 @@
 
 	  If unsure, say N.
 
+config IPV6_ETHERIP
+	tristate "EtherIP over IPv6: EtherIP-in-IPv6 tunnel"
+	depends on IPV6
+	select INET6_TUNNEL
+	---help---
+	  Support for EtherIP-in-IPv6 tunnels described in RFC 3378.
+
+	  If unsure, say N.
+
 config IPV6_MROUTE
 	bool "IPv6: multicast routing (EXPERIMENTAL)"
 	depends on IPV6 && EXPERIMENTAL
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index 049f35e..08de35a 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -23,7 +23,8 @@
 ipv6-objs += $(ipv6-y)
 
 obj-$(CONFIG_INET6_AH) += ah6.o
-obj-$(CONFIG_INET6_ESP) += esp6.o
+#obj-$(CONFIG_INET6_ESP) += esp6.o
+obj-$(CONFIG_INET6_IPSEC_OFFLOAD) += esp6.o
 obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o
 obj-$(CONFIG_INET6_XFRM_TUNNEL) += xfrm6_tunnel.o
 obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o
@@ -36,6 +37,7 @@
 
 obj-$(CONFIG_IPV6_SIT) += sit.o
 obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
+obj-$(CONFIG_IPV6_ETHERIP) += ethipip6.o
 
 obj-y += addrconf_core.o exthdrs_core.o
 
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index 65dd543..0b9e148 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -138,11 +138,26 @@
 	kfree(ESP_SKB_CB(skb)->tmp);
 	xfrm_output_resume(skb, err);
 }
+static void udp_v6_send_check(struct sk_buff *skb)
+{
+	struct ipv6hdr *ipv6h=ipv6_hdr(skb);
+	struct udphdr *uh=udp_hdr(skb);
+	uh->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len,
+			IPPROTO_UDP, 0);
+	skb->csum_start = skb_transport_header(skb) - skb->head;
+	skb->csum_offset = offsetof(struct udphdr, check);
+	skb->ip_summed = CHECKSUM_PARTIAL;
+
+	if (uh->check == 0)
+		uh->check = CSUM_MANGLED_0;
+
+}
 
 static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
 {
 	int err;
 	struct ip_esp_hdr *esph;
+	struct udphdr *uh=NULL;
 	struct crypto_aead *aead;
 	struct aead_givcrypt_request *req;
 	struct scatterlist *sg;
@@ -228,13 +243,46 @@
 	esph = ip_esp_hdr(skb);
 	*skb_mac_header(skb) = IPPROTO_ESP;
 
+	/* NAT-T changes Start */
+	/* this is non-NULL only with UDP Encapsulation */
+	if (x->encap) {
+		struct xfrm_encap_tmpl *encap = x->encap;
+		__be32 *udpdata32;
+		__be16 sport, dport;
+		int encap_type;
+		spin_lock_bh(&x->lock);
+		sport = encap->encap_sport;
+		dport = encap->encap_dport;
+		encap_type = encap->encap_type;
+		spin_unlock_bh(&x->lock);
+		uh = (struct udphdr *)esph;
+		uh->source = sport;
+		uh->dest = dport;
+		uh->len = htons(skb->len - skb_transport_offset(skb));
+		uh->check = 0;
+
+		switch (encap_type) {
+			default:
+			case UDP_ENCAP_ESPINUDP:
+				esph = (struct ip_esp_hdr *)(uh + 1);
+				break;
+			case UDP_ENCAP_ESPINUDP_NON_IKE:
+				udpdata32 = (__be32 *)(uh + 1);
+				udpdata32[0] = udpdata32[1] = 0;
+				esph = (struct ip_esp_hdr *)(udpdata32 + 2);
+				break;
+		}
+		*skb_mac_header(skb) = IPPROTO_UDP;
+	}
+
+
 	esph->spi = x->id.spi;
 	esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low);
 
 	sg_init_table(sg, nfrags);
 	skb_to_sgvec(skb, sg,
-		     esph->enc_data + crypto_aead_ivsize(aead) - skb->data,
-		     clen + alen);
+			esph->enc_data + crypto_aead_ivsize(aead) - skb->data,
+			clen + alen);
 
 	if ((x->props.flags & XFRM_STATE_ESN)) {
 		sg_init_table(asg, 3);
@@ -249,7 +297,7 @@
 	aead_givcrypt_set_crypt(req, sg, sg, clen, iv);
 	aead_givcrypt_set_assoc(req, asg, assoclen);
 	aead_givcrypt_set_giv(req, esph->enc_data,
-			      XFRM_SKB_CB(skb)->seq.output.low);
+			XFRM_SKB_CB(skb)->seq.output.low);
 
 	ESP_SKB_CB(skb)->tmp = tmp;
 	err = crypto_aead_givencrypt(req);
@@ -259,6 +307,13 @@
 	if (err == -EBUSY)
 		err = NET_XMIT_DROP;
 
+
+	/* NAT-T changes Start */
+	if (x->encap) {
+		udp_v6_send_check(skb);
+	}
+	/* NAT-T changes End */
+
 	kfree(tmp);
 
 error:
@@ -267,6 +322,7 @@
 
 static int esp_input_done2(struct sk_buff *skb, int err)
 {
+	struct ipv6hdr *ipv6h;
 	struct xfrm_state *x = xfrm_input_state(skb);
 	struct esp_data *esp = x->data;
 	struct crypto_aead *aead = esp->aead;
@@ -289,11 +345,48 @@
 	padlen = nexthdr[0];
 	if (padlen + 2 + alen >= elen) {
 		LIMIT_NETDEBUG(KERN_WARNING "ipsec esp packet is garbage "
-			       "padlen=%d, elen=%d\n", padlen + 2, elen - alen);
+				"padlen=%d, elen=%d\n", padlen + 2, elen - alen);
 		goto out;
 	}
 
 	/* ... check padding bits here. Silly. :-) */
+	/* NAT-T changes Start */
+	ipv6h = ipv6_hdr(skb);
+	if (x->encap) {
+		struct xfrm_encap_tmpl *encap = x->encap;
+		struct udphdr *uh = (void *)(skb_network_header(skb) + hdr_len);
+
+		/* 1) if the NAT-T peer's IP or port changed then
+		 *    advertize the change to the keying daemon.
+		 *    This is an inbound SA, so just compare
+		 *    SRC ports.
+		 */
+		if (memcmp(&ipv6h->saddr, x->props.saddr.a6 ,sizeof(ipv6h->saddr)) ||
+				uh->source != encap->encap_sport) {
+			xfrm_address_t ipaddr;
+			memcpy(ipaddr.a6, &ipv6h->saddr, sizeof(ipaddr.a6));
+			km_new_mapping(x, &ipaddr, uh->source);
+			/* XXX: perhaps add an extra
+			 * policy check here, to see
+			 * if we should allow or
+			 * reject a packet from a
+			 * different source
+			 * address/port.
+			 */
+		}
+
+		/*
+		 * 2) ignore UDP/TCP checksums in case
+		 *    of NAT-T in Transport Mode, or
+		 *    perform other post-processing fixes
+		 *    as per draft-ietf-ipsec-udp-encaps-06,
+		 *    section 3.1.2
+		 */
+		if (x->props.mode == XFRM_MODE_TRANSPORT || x->props.mode == XFRM_MODE_BEET) 
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+	}
+	/*NAT-T changes End*/
 
 	pskb_trim(skb, skb->len - alen - padlen - 2);
 	__skb_pull(skb, hlen);
@@ -577,8 +670,8 @@
 	u32 align;
 	int err;
 
-	if (x->encap)
-		return -EINVAL;
+	//if (x->encap)
+	//	return -EINVAL;
 
 	esp = kzalloc(sizeof(*esp), GFP_KERNEL);
 	if (esp == NULL)
@@ -615,6 +708,22 @@
 		goto error;
 	}
 
+	/* NAT-T  changes Start */
+	if (x->encap) {
+		struct xfrm_encap_tmpl *encap = x->encap;
+		switch (encap->encap_type) {
+		default:
+			goto error;
+		case UDP_ENCAP_ESPINUDP:
+			x->props.header_len += sizeof(struct udphdr);
+			break;
+		case UDP_ENCAP_ESPINUDP_NON_IKE:
+			x->props.header_len += sizeof(struct udphdr) + 2 * sizeof(u32) * 4;
+			break;
+		}
+	}
+	/* NAT-T changes End */
+
 	align = ALIGN(crypto_aead_blocksize(aead), 4);
 	if (esp->padlen)
 		align = max_t(u32, align, esp->padlen);
diff --git a/net/ipv6/ethipip6.c b/net/ipv6/ethipip6.c
new file mode 100644
index 0000000..c1765c7
--- /dev/null
+++ b/net/ipv6/ethipip6.c
@@ -0,0 +1,1594 @@
+/*
+ * 	EtherIP tunnel over IPv6 link
+ *	IPv6 tunneling device
+ *	Linux INET6 implementation
+ *
+ *	Authors:
+ *	Ville Nuorvala		<vnuorval@tcs.hut.fi>
+ *	Yasuyuki Kozakai	<kozakai@linux-ipv6.org>
+ *
+ *      Based on:
+ *      linux/net/ipv6/ip6_tunnel.c, linux/net/ipv6/sit.c and linux/net/ipv4/ipip.c
+ *
+ *      RFC 3378
+ *
+ *	This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/capability.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/sockios.h>
+#include <linux/icmp.h>
+#include <linux/if.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/if_tunnel.h>
+#include <linux/net.h>
+#include <linux/in6.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/icmpv6.h>
+#include <linux/init.h>
+#include <linux/route.h>
+#include <linux/rtnetlink.h>
+#include <linux/netfilter_ipv6.h>
+#include <linux/etherdevice.h>
+
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+
+#include <net/icmp.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
+#include <net/ip6_tunnel.h>
+#include <net/xfrm.h>
+#include <net/dsfield.h>
+#include <net/inet_ecn.h>
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
+#include <net/protocol.h>
+
+MODULE_AUTHOR("Ville Nuorvala");
+MODULE_DESCRIPTION("EtherIP-in-IPv6 tunneling device");
+MODULE_LICENSE("GPL");
+
+#define ETHERIP_VERSION       0x3000
+
+#define IPV6_TNL_F_TOS_TO_TC  128
+#define IPV6_TLV_TEL_DST_SIZE 8
+
+#ifdef ETHIPIP6_TNL_DEBUG
+#define ETHIPIP6_TNL_TRACE(x...) printk(KERN_DEBUG "%s:" x "\n", __func__)
+#else
+#define ETHIPIP6_TNL_TRACE(x...) do {;} while(0)
+#endif
+
+#define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK)
+#define IPV6_TCLASS_SHIFT 20
+
+#define HASH_SIZE  32
+
+#define HASH(addr) ((__force u32)((addr)->s6_addr32[0] ^ (addr)->s6_addr32[1] ^ \
+		     (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \
+		    (HASH_SIZE - 1))
+
+static void ethipip6_fb_tnl_dev_init(struct net_device *dev);
+static int ethipip6_tnl_dev_init(struct net_device *dev);
+static void ethipip6_tnl_dev_setup(struct net_device *dev);
+
+static int ethipip6_tnl_net_id __read_mostly;
+struct ip6_tnl_net {
+	/* the IPv6 tunnel fallback device */
+	struct net_device *fb_tnl_dev;
+	/* lists for storing tunnels in use */
+	struct ip6_tnl *tnls_r_l[HASH_SIZE];
+	struct ip6_tnl *tnls_wc[1];
+	struct ip6_tnl **tnls[2];
+};
+
+/*
+ * Locking : hash tables are protected by RCU and a spinlock
+ */
+static DEFINE_SPINLOCK(ethipip6_tnl_lock);
+
+static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t)
+{
+	struct dst_entry *dst = t->dst_cache;
+
+	if (dst && dst->obsolete &&
+	    dst->ops->check(dst, t->dst_cookie) == NULL) {
+		t->dst_cache = NULL;
+		dst_release(dst);
+		return NULL;
+	}
+
+	return dst;
+}
+
+static inline void ip6_tnl_dst_reset(struct ip6_tnl *t)
+{
+	dst_release(t->dst_cache);
+	t->dst_cache = NULL;
+}
+
+static inline void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst)
+{
+	struct rt6_info *rt = (struct rt6_info *) dst;
+	t->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
+	dst_release(t->dst_cache);
+	t->dst_cache = dst;
+}
+
+/**
+ * ethipip6_tnl_lookup - fetch tunnel matching the end-point addresses
+ *   @remote: the address of the tunnel exit-point
+ *   @local: the address of the tunnel entry-point
+ *
+ * Return:
+ *   tunnel matching given end-points if found,
+ *   else fallback tunnel if its device is up,
+ *   else %NULL
+ **/
+
+#define for_each_ethip6_tunnel_rcu(start) \
+	for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
+
+static struct ip6_tnl *
+ethipip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local)
+{
+	unsigned h0 = HASH(remote);
+	unsigned h1 = HASH(local);
+	struct ip6_tnl *t;
+	struct ip6_tnl_net *ip6n = net_generic(net, ethipip6_tnl_net_id);
+
+	for_each_ethip6_tunnel_rcu(ip6n->tnls_r_l[h0 ^ h1]) {
+		if (ipv6_addr_equal(local, &t->parms.laddr) &&
+		    ipv6_addr_equal(remote, &t->parms.raddr) &&
+		    (t->dev->flags & IFF_UP))
+			return t;
+	}
+	t = rcu_dereference(ip6n->tnls_wc[0]);
+	if (t && (t->dev->flags & IFF_UP))
+		return t;
+
+	return NULL;
+}
+
+/**
+ * ethipip6_tnl_bucket - get head of list matching given tunnel parameters
+ *   @p: parameters containing tunnel end-points
+ *
+ * Description:
+ *   ethipip6_tnl_bucket() returns the head of the list matching the
+ *   &struct in6_addr entries laddr and raddr in @p.
+ *
+ * Return: head of IPv6 tunnel list
+ **/
+
+static struct ip6_tnl **
+ethipip6_tnl_bucket(struct ip6_tnl_net *ip6n, struct ip6_tnl_parm *p)
+{
+	struct in6_addr *remote = &p->raddr;
+	struct in6_addr *local = &p->laddr;
+	unsigned h = 0;
+	int prio = 0;
+
+	if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) {
+		prio = 1;
+		h = HASH(remote) ^ HASH(local);
+	}
+	return &ip6n->tnls[prio][h];
+}
+
+/**
+ * ethipip6_tnl_link - add tunnel to hash table
+ *   @t: tunnel to be added
+ **/
+
+static void
+ethipip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t)
+{
+	struct ip6_tnl **tp = ethipip6_tnl_bucket(ip6n, &t->parms);
+
+	spin_lock_bh(&ethipip6_tnl_lock);
+	t->next = *tp;
+	rcu_assign_pointer(*tp, t);
+	spin_unlock_bh(&ethipip6_tnl_lock);
+}
+
+/**
+ * ethipip6_tnl_unlink - remove tunnel from hash table
+ *   @t: tunnel to be removed
+ **/
+
+static void
+ethipip6_tnl_unlink(struct ip6_tnl_net *ip6n, struct ip6_tnl *t)
+{
+	struct ip6_tnl **tp;
+
+	for (tp = ethipip6_tnl_bucket(ip6n, &t->parms); *tp; tp = &(*tp)->next) {
+		if (t == *tp) {
+			spin_lock_bh(&ethipip6_tnl_lock);
+			*tp = t->next;
+			spin_unlock_bh(&ethipip6_tnl_lock);
+			break;
+		}
+	}
+}
+
+/**
+ * ip6_tnl_create() - create a new tunnel
+ *   @p: tunnel parameters
+ *   @pt: pointer to new tunnel
+ *
+ * Description:
+ *   Create tunnel matching given parameters.
+ *
+ * Return:
+ *   created tunnel or NULL
+ **/
+
+static struct ip6_tnl *ip6_tnl_create(struct net *net, struct ip6_tnl_parm *p)
+{
+	struct net_device *dev;
+	struct ip6_tnl *t;
+	char name[IFNAMSIZ];
+	int err;
+	struct ip6_tnl_net *ip6n = net_generic(net, ethipip6_tnl_net_id);
+
+	if (p->name[0])
+		strlcpy(name, p->name, IFNAMSIZ);
+	else
+		sprintf(name, "ethipip6tnl%%d");
+
+	dev = alloc_netdev(sizeof (*t), name, ethipip6_tnl_dev_setup);
+	if (dev == NULL)
+		goto failed;
+
+	dev_net_set(dev, net);
+
+	if (strchr(name, '%')) {
+		if (dev_alloc_name(dev, name) < 0)
+			goto failed_free;
+	}
+
+	t = netdev_priv(dev);
+	t->parms = *p;
+
+	if ((err = register_netdevice(dev)) < 0)
+		goto failed_free;
+
+	dev_hold(dev);
+	ethipip6_tnl_link(ip6n, t);
+	return t;
+
+failed_free:
+	free_netdev(dev);
+failed:
+	return NULL;
+}
+
+/**
+ * ethipip6_tnl_locate - find or create tunnel matching given parameters
+ *   @p: tunnel parameters
+ *   @create: != 0 if allowed to create new tunnel if no match found
+ *
+ * Description:
+ *   ethipip6_tnl_locate() first tries to locate an existing tunnel
+ *   based on @parms. If this is unsuccessful, but @create is set a new
+ *   tunnel device is created and registered for use.
+ *
+ * Return:
+ *   matching tunnel or NULL
+ **/
+
+static struct ip6_tnl *ethipip6_tnl_locate(struct net *net,
+		struct ip6_tnl_parm *p, int create)
+{
+	struct in6_addr *remote = &p->raddr;
+	struct in6_addr *local = &p->laddr;
+	struct ip6_tnl *t;
+	struct ip6_tnl_net *ip6n = net_generic(net, ethipip6_tnl_net_id);
+
+	for (t = *ethipip6_tnl_bucket(ip6n, p); t; t = t->next) {
+		if (ipv6_addr_equal(local, &t->parms.laddr) &&
+		    ipv6_addr_equal(remote, &t->parms.raddr))
+			return t;
+	}
+	if (!create)
+		return NULL;
+	return ip6_tnl_create(net, p);
+}
+
+/**
+ * ethipip6_tnl_dev_uninit - tunnel device uninitializer
+ *   @dev: the device to be destroyed
+ *
+ * Description:
+ *   ethipip6_tnl_dev_uninit() removes tunnel from its list
+ **/
+
+static void
+ethipip6_tnl_dev_uninit(struct net_device *dev)
+{
+	struct ip6_tnl *t = netdev_priv(dev);
+	struct net *net = dev_net(dev);
+	struct ip6_tnl_net *ip6n = net_generic(net, ethipip6_tnl_net_id);
+
+	if (dev == ip6n->fb_tnl_dev) {
+		spin_lock_bh(&ethipip6_tnl_lock);
+		ip6n->tnls_wc[0] = NULL;
+		spin_unlock_bh(&ethipip6_tnl_lock);
+	} else {
+		ethipip6_tnl_unlink(ip6n, t);
+	}
+	ip6_tnl_dst_reset(t);
+	dev_put(dev);
+}
+
+/**
+ * parse_tvl_tnl_enc_lim - handle encapsulation limit option
+ *   @skb: received socket buffer
+ *
+ * Return:
+ *   0 if none was found,
+ *   else index to encapsulation limit
+ **/
+
+static __u16
+parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw)
+{
+	struct ipv6hdr *ipv6h = (struct ipv6hdr *) raw;
+	__u8 nexthdr = ipv6h->nexthdr;
+	__u16 off = sizeof (*ipv6h);
+
+	while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) {
+		__u16 optlen = 0;
+		struct ipv6_opt_hdr *hdr;
+		if (raw + off + sizeof (*hdr) > skb->data &&
+		    !pskb_may_pull(skb, raw - skb->data + off + sizeof (*hdr)))
+			break;
+
+		hdr = (struct ipv6_opt_hdr *) (raw + off);
+		if (nexthdr == NEXTHDR_FRAGMENT) {
+			struct frag_hdr *frag_hdr = (struct frag_hdr *) hdr;
+			if (frag_hdr->frag_off)
+				break;
+			optlen = 8;
+		} else if (nexthdr == NEXTHDR_AUTH) {
+			optlen = (hdr->hdrlen + 2) << 2;
+		} else {
+			optlen = ipv6_optlen(hdr);
+		}
+		if (nexthdr == NEXTHDR_DEST) {
+			__u16 i = off + 2;
+			while (1) {
+				struct ipv6_tlv_tnl_enc_lim *tel;
+
+				/* No more room for encapsulation limit */
+				if (i + sizeof (*tel) > off + optlen)
+					break;
+
+				tel = (struct ipv6_tlv_tnl_enc_lim *) &raw[i];
+				/* return index of option if found and valid */
+				if (tel->type == IPV6_TLV_TNL_ENCAP_LIMIT &&
+				    tel->length == 1)
+					return i;
+				/* else jump to next option */
+				if (tel->type)
+					i += tel->length + 2;
+				else
+					i++;
+			}
+		}
+		nexthdr = hdr->nexthdr;
+		off += optlen;
+	}
+	return 0;
+}
+
+/**
+ * ethipip6_tnl_err - tunnel error handler
+ *
+ * Description:
+ *   ethipip6_tnl_err() should handle errors in the tunnel according
+ *   to the specifications in RFC 2473.
+ **/
+
+static int
+ethipip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
+	    u8 *type, u8 *code, int *msg, __u32 *info, int offset)
+{
+	struct ipv6hdr *ipv6h = (struct ipv6hdr *) skb->data;
+	struct ip6_tnl *t;
+	int rel_msg = 0;
+	u8 rel_type = ICMPV6_DEST_UNREACH;
+	u8 rel_code = ICMPV6_ADDR_UNREACH;
+	__u32 rel_info = 0;
+	__u16 len;
+	int err = -ENOENT;
+
+	/* If the packet doesn't contain the original IPv6 header we are
+	   in trouble since we might need the source address for further
+	   processing of the error. */
+
+	rcu_read_lock();
+	if ((t = ethipip6_tnl_lookup(dev_net(skb->dev), &ipv6h->daddr,
+					&ipv6h->saddr)) == NULL)
+		goto out;
+
+	if (t->parms.proto != ipproto && t->parms.proto != 0)
+		goto out;
+
+	err = 0;
+
+	switch (*type) {
+		__u32 teli;
+		struct ipv6_tlv_tnl_enc_lim *tel;
+		__u32 mtu;
+	case ICMPV6_DEST_UNREACH:
+		if (net_ratelimit())
+			printk(KERN_WARNING
+			       "%s: Path to destination invalid "
+			       "or inactive!\n", t->parms.name);
+		rel_msg = 1;
+		break;
+	case ICMPV6_TIME_EXCEED:
+		if ((*code) == ICMPV6_EXC_HOPLIMIT) {
+			if (net_ratelimit())
+				printk(KERN_WARNING
+				       "%s: Too small hop limit or "
+				       "routing loop in tunnel!\n",
+				       t->parms.name);
+			rel_msg = 1;
+		}
+		break;
+	case ICMPV6_PARAMPROB:
+		teli = 0;
+		if ((*code) == ICMPV6_HDR_FIELD)
+			teli = parse_tlv_tnl_enc_lim(skb, skb->data);
+
+		if (teli && teli == *info - 2) {
+			tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli];
+			if (tel->encap_limit == 0) {
+				if (net_ratelimit())
+					printk(KERN_WARNING
+					       "%s: Too small encapsulation "
+					       "limit or routing loop in "
+					       "tunnel!\n", t->parms.name);
+				rel_msg = 1;
+			}
+		} else if (net_ratelimit()) {
+			printk(KERN_WARNING
+			       "%s: Recipient unable to parse tunneled "
+			       "packet!\n ", t->parms.name);
+		}
+		break;
+	case ICMPV6_PKT_TOOBIG:
+		mtu = *info - offset;
+		if (mtu < IPV6_MIN_MTU)
+			mtu = IPV6_MIN_MTU;
+		t->dev->mtu = mtu;
+
+		if ((len = sizeof (*ipv6h) + ntohs(ipv6h->payload_len)) > mtu) {
+			rel_type = ICMPV6_PKT_TOOBIG;
+			rel_code = 0;
+			rel_info = mtu;
+			rel_msg = 1;
+		}
+		break;
+	}
+
+	*type = rel_type;
+	*code = rel_code;
+	*info = rel_info;
+	*msg = rel_msg;
+
+out:
+	rcu_read_unlock();
+	return err;
+}
+
+static int
+ip4ethipip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+	   u8 type, u8 code, int offset, __be32 info)
+{
+	int rel_msg = 0;
+	u8 rel_type = type;
+	u8 rel_code = code;
+	__u32 rel_info = ntohl(info);
+	int err;
+	struct sk_buff *skb2;
+	struct iphdr *eiph;
+	struct flowi fl;
+	struct rtable *rt;
+
+	err = ethipip6_tnl_err(skb, IPPROTO_IPIP, opt, &rel_type, &rel_code,
+			  &rel_msg, &rel_info, offset);
+	if (err < 0)
+		return err;
+
+	if (rel_msg == 0)
+		return 0;
+
+	switch (rel_type) {
+	case ICMPV6_DEST_UNREACH:
+		if (rel_code != ICMPV6_ADDR_UNREACH)
+			return 0;
+		rel_type = ICMP_DEST_UNREACH;
+		rel_code = ICMP_HOST_UNREACH;
+		break;
+	case ICMPV6_PKT_TOOBIG:
+		if (rel_code != 0)
+			return 0;
+		rel_type = ICMP_DEST_UNREACH;
+		rel_code = ICMP_FRAG_NEEDED;
+		break;
+	default:
+		return 0;
+	}
+
+	if (!pskb_may_pull(skb, offset + sizeof(struct iphdr)))
+		return 0;
+
+	skb2 = skb_clone(skb, GFP_ATOMIC);
+	if (!skb2)
+		return 0;
+
+	skb_dst_drop(skb2);
+
+	skb_pull(skb2, offset);
+	skb_reset_network_header(skb2);
+	eiph = ip_hdr(skb2);
+
+	/* Try to guess incoming interface */
+	memset(&fl, 0, sizeof(fl));
+	fl.u.ip4.daddr = eiph->saddr;
+	fl.flowi_tos = RT_TOS(eiph->tos);
+	fl.flowi_proto = IPPROTO_IPIP;
+	rt = ip_route_output_key(dev_net(skb->dev), &fl.u.ip4);
+	if (IS_ERR(rt))
+		goto out;
+
+	skb2->dev = rt->dst.dev;
+
+	/* route "incoming" packet */
+	if (rt->rt_flags & RTCF_LOCAL) {
+		ip_rt_put(rt);
+		fl.u.ip4.daddr = eiph->daddr;
+		fl.u.ip4.saddr = eiph->saddr;
+		fl.flowi_tos = eiph->tos;
+		rt = ip_route_output_key(dev_net(skb->dev), &fl.u.ip4);
+		if (IS_ERR(rt))
+			goto out;
+		if (rt->dst.dev->type != ARPHRD_TUNNEL) {
+			ip_rt_put(rt);
+			goto out;
+		}
+		skb_dst_set(skb2, (struct dst_entry *)rt);
+	} else {
+		ip_rt_put(rt);
+		if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos,
+				   skb2->dev) ||
+		    skb_dst(skb2)->dev->type != ARPHRD_TUNNEL)
+			goto out;
+	}
+
+	/* change mtu on this route */
+	if (rel_type == ICMP_DEST_UNREACH && rel_code == ICMP_FRAG_NEEDED) {
+		if (rel_info > dst_mtu(skb_dst(skb2)))
+			goto out;
+
+		skb_dst(skb2)->ops->update_pmtu(skb_dst(skb2), rel_info);
+	}
+
+	icmp_send(skb2, rel_type, rel_code, htonl(rel_info));
+
+out:
+	kfree_skb(skb2);
+	return 0;
+}
+
+static int
+ip6ethipip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+	   u8 type, u8 code, int offset, __be32 info)
+{
+	int rel_msg = 0;
+	u8 rel_type = type;
+	u8 rel_code = code;
+	__u32 rel_info = ntohl(info);
+	int err;
+
+	err = ethipip6_tnl_err(skb, IPPROTO_IPV6, opt, &rel_type, &rel_code,
+			  &rel_msg, &rel_info, offset);
+	if (err < 0)
+		return err;
+
+	if (rel_msg && pskb_may_pull(skb, offset + sizeof(struct ipv6hdr))) {
+		struct rt6_info *rt;
+		struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
+
+		if (!skb2)
+			return 0;
+
+		skb_dst_drop(skb2);
+		skb_pull(skb2, offset);
+		skb_reset_network_header(skb2);
+
+		/* Try to guess incoming interface */
+		rt = rt6_lookup(dev_net(skb->dev), &ipv6_hdr(skb2)->saddr,
+				NULL, 0, 0);
+
+		if (rt && rt->rt6i_dev)
+			skb2->dev = rt->rt6i_dev;
+
+		icmpv6_send(skb2, rel_type, rel_code, rel_info);
+
+		if (rt)
+			dst_release(&rt->dst);
+
+		kfree_skb(skb2);
+	}
+
+	return 0;
+}
+
+static void ip4ethipip6_dscp_ecn_decapsulate(struct ip6_tnl *t,
+					struct ipv6hdr *ipv6h,
+					struct sk_buff *skb)
+{
+	__u8 dsfield = ipv6_get_dsfield(ipv6h) & ~INET_ECN_MASK;
+
+	if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY)
+		ipv4_change_dsfield(ip_hdr(skb), INET_ECN_MASK, dsfield);
+
+	if (INET_ECN_is_ce(dsfield))
+		IP_ECN_set_ce(ip_hdr(skb));
+}
+
+static void ip6ethipip6_dscp_ecn_decapsulate(struct ip6_tnl *t,
+					struct ipv6hdr *ipv6h,
+					struct sk_buff *skb)
+{
+	if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY)
+		ipv6_copy_dscp(ipv6_get_dsfield(ipv6h), ipv6_hdr(skb));
+
+	if (INET_ECN_is_ce(ipv6_get_dsfield(ipv6h)))
+		IP6_ECN_set_ce(ipv6_hdr(skb));
+}
+
+/* called with rcu_read_lock() */
+static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t)
+{
+	struct ip6_tnl_parm *p = &t->parms;
+	int ret = 0;
+	struct net *net = dev_net(t->dev);
+
+	if (p->flags & IP6_TNL_F_CAP_RCV) {
+		struct net_device *ldev = NULL;
+
+		if (p->link)
+			ldev = dev_get_by_index_rcu(net, p->link);
+
+		if ((ipv6_addr_is_multicast(&p->laddr) ||
+		     likely(ipv6_chk_addr(net, &p->laddr, ldev, 0))) &&
+		    likely(!ipv6_chk_addr(net, &p->raddr, NULL, 0)))
+			ret = 1;
+
+	}
+	return ret;
+}
+
+/**
+ * ethipip6_tnl_rcv - decapsulate IPv6 packet and retransmit it locally
+ *   @skb: received socket buffer
+ *   @protocol: ethernet protocol ID
+ *   @dscp_ecn_decapsulate: the function to decapsulate DSCP code and ECN
+ *
+ * Return: 0
+ **/
+static int ethipip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
+		       __u8 ipproto,
+		       void (*dscp_ecn_decapsulate)(struct ip6_tnl *t,
+						    struct ipv6hdr *ipv6h,
+						    struct sk_buff *skb))
+{
+	struct ip6_tnl *t;
+	struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+
+	__u16 *etherip_ver;
+
+	if (!pskb_may_pull(skb, ETH_IPHLEN+ETH_HLEN))
+		goto discard;
+	
+	etherip_ver = (__u16 *)skb->data;
+	if (*etherip_ver != htons(ETHERIP_VERSION)) 
+		goto discard;
+	
+	rcu_read_lock();
+
+	if ((t = ethipip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr,
+					&ipv6h->daddr)) != NULL) {
+		if (t->parms.proto != ipproto && t->parms.proto != 0) {
+			rcu_read_unlock();
+			goto discard;
+		}
+
+		/* Check the xfrm policy for decrypted packets */
+		if (skb->sp && !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
+			rcu_read_unlock();
+			goto discard;
+		}
+
+		if (!ip6_tnl_rcv_ctl(t)) {
+			t->dev->stats.rx_dropped++;
+			rcu_read_unlock();
+			goto discard;
+		}
+		secpath_reset(skb);
+		skb_pull(skb, ETH_IPHLEN);
+		skb->pkt_type = PACKET_HOST;
+		skb->protocol = eth_type_trans(skb, skb->dev);
+		skb_reset_network_header(skb);
+
+
+		memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
+		skb->dev = t->dev;
+		skb_dst_drop(skb);
+		nf_reset(skb);
+
+		dscp_ecn_decapsulate(t, ipv6h, skb);
+
+		t->dev->stats.rx_packets++;
+		t->dev->stats.rx_bytes += skb->len;
+		netif_rx(skb);
+		rcu_read_unlock();
+		return 0;
+	}
+	rcu_read_unlock();
+
+discard:
+	kfree_skb(skb);
+	return 0;
+}
+
+static int ip4ethipip6_rcv(struct sk_buff *skb)
+{
+	return ethipip6_tnl_rcv(skb, ETH_P_IP, IPPROTO_ETHERIP,
+			   ip4ethipip6_dscp_ecn_decapsulate);
+}
+
+static int ip6ethipip6_rcv(struct sk_buff *skb)
+{
+	return ethipip6_tnl_rcv(skb, ETH_P_IPV6, IPPROTO_ETHERIP,
+			   ip6ethipip6_dscp_ecn_decapsulate);
+}
+
+struct ipv6_tel_txoption {
+	struct ipv6_txoptions ops;
+	__u8 dst_opt[8];
+};
+
+static void init_tel_txopt(struct ipv6_tel_txoption *opt, __u8 encap_limit)
+{
+	memset(opt, 0, sizeof(struct ipv6_tel_txoption));
+
+	opt->dst_opt[2] = IPV6_TLV_TNL_ENCAP_LIMIT;
+	opt->dst_opt[3] = 1;
+	opt->dst_opt[4] = encap_limit;
+	opt->dst_opt[5] = IPV6_TLV_PADN;
+	opt->dst_opt[6] = 1;
+
+	opt->ops.dst0opt = (struct ipv6_opt_hdr *) opt->dst_opt;
+	opt->ops.opt_nflen = 8;
+}
+
+/**
+ * ethipip6_tnl_addr_conflict - compare packet addresses to tunnel's own
+ *   @t: the outgoing tunnel device
+ *   @hdr: IPv6 header from the incoming packet
+ *
+ * Description:
+ *   Avoid trivial tunneling loop by checking that tunnel exit-point
+ *   doesn't match source of incoming packet.
+ *
+ * Return:
+ *   1 if conflict,
+ *   0 else
+ **/
+
+static inline int
+ethipip6_tnl_addr_conflict(struct ip6_tnl *t, struct ipv6hdr *hdr)
+{
+	return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr);
+}
+
+static inline int ethipip6_tnl_xmit_ctl(struct ip6_tnl *t)
+{
+	struct ip6_tnl_parm *p = &t->parms;
+	int ret = 0;
+	struct net *net = dev_net(t->dev);
+
+	if (p->flags & IP6_TNL_F_CAP_XMIT) {
+		struct net_device *ldev = NULL;
+
+		rcu_read_lock();
+		if (p->link)
+			ldev = dev_get_by_index_rcu(net, p->link);
+
+		if (unlikely(!ipv6_chk_addr(net, &p->laddr, ldev, 0)))
+			printk(KERN_WARNING
+			       "%s xmit: Local address not yet configured!\n",
+			       p->name);
+		else if (!ipv6_addr_is_multicast(&p->raddr) &&
+			 unlikely(ipv6_chk_addr(net, &p->raddr, NULL, 0)))
+			printk(KERN_WARNING
+			       "%s xmit: Routing loop! "
+			       "Remote address found on this node!\n",
+			       p->name);
+		else
+			ret = 1;
+		rcu_read_unlock();
+	}
+	return ret;
+}
+/**
+ * ethipip6_tnl_xmit2 - encapsulate packet and send
+ *   @skb: the outgoing socket buffer
+ *   @dev: the outgoing tunnel device
+ *   @dsfield: dscp code for outer header
+ *   @fl: flow of tunneled packet
+ *   @encap_limit: encapsulation limit
+ *   @pmtu: Path MTU is stored if packet is too big
+ *
+ * Description:
+ *   Build new header and do some sanity checks on the packet before sending
+ *   it.
+ *
+ * Return:
+ *   0 on success
+ *   -1 fail
+ *   %-EMSGSIZE message too big. return mtu in this case.
+ **/
+
+static int ethipip6_tnl_xmit2(struct sk_buff *skb,
+			 struct net_device *dev,
+			 __u8 dsfield,
+			 struct flowi *fl,
+			 int encap_limit,
+			 __u32 *pmtu)
+{
+	struct net *net = dev_net(dev);
+	struct ip6_tnl *t = netdev_priv(dev);
+	struct net_device_stats *stats = &t->dev->stats;
+	struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+	struct ipv6_tel_txoption opt;
+	struct dst_entry *dst;
+	struct net_device *tdev;
+	int mtu;
+	unsigned int max_headroom = sizeof(struct ipv6hdr);
+	u8 proto;
+	int err = -1;
+	int pkt_len;
+	__u16 *etherip_ver;
+
+	if (((dst = ip6_tnl_dst_check(t)) != NULL) 
+#if defined(CONFIG_INET6_IPSEC_OFFLOAD)            
+                && (t->genid == atomic_read(&flow_cache_genid))
+#endif
+            ) {
+		dst_hold(dst);
+        } else {
+		dst = ip6_route_output(net, NULL, &fl->u.ip6);
+
+		if(dst->error)
+			goto tx_err_link_failure;
+		dst = xfrm_lookup(net, dst, fl, NULL, 0);
+		if(IS_ERR(dst))
+		{
+			err = PTR_ERR(dst);
+			dst = NULL;
+			goto tx_err_link_failure;
+		}
+#if defined(CONFIG_INET6_IPSEC_OFFLOAD)
+		t->genid = atomic_read(&flow_cache_genid);
+#endif
+        }
+
+	/* donot allow wifi specific pkts to be bridged,
+         * is there any better why to identify this condition!!! 
+         * if (skb->len < 42) some thing like this... 
+         * For regular ethernet pkts, iphdr is always aligned to 4bytes,
+         * so one way is to check the address alignment */
+	if (!((unsigned int)skb->data & 0x3)) {
+		stats->rx_length_errors++;
+	 	goto tx_err_dst_release;
+	}
+
+	tdev = dst->dev;
+
+	if (tdev == dev) {
+		stats->collisions++;
+		if (net_ratelimit())
+			printk(KERN_WARNING
+			       "%s: Local routing loop detected!\n",
+			       t->parms.name);
+		goto tx_err_dst_release;
+	}
+	mtu = dst_mtu(dst) - (sizeof (*ipv6h) + ETH_IPHLEN + ETH_HLEN);
+	if (encap_limit >= 0) {
+		max_headroom += 8;
+		mtu -= 8;
+	}
+	if (mtu < IPV6_MIN_MTU)
+		mtu = IPV6_MIN_MTU;
+	if (skb_dst(skb))
+		skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
+
+	/*
+	 * Okay, now see if we can stuff it in the buffer as-is.
+	 */
+	max_headroom += LL_RESERVED_SPACE(tdev);
+
+	if (skb_headroom(skb) < max_headroom || skb_shared(skb) ||
+	    (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
+		struct sk_buff *new_skb;
+
+		if (!(new_skb = skb_realloc_headroom(skb, max_headroom)))
+			goto tx_err_dst_release;
+
+		if (skb->sk)
+			skb_set_owner_w(new_skb, skb->sk);
+		kfree_skb(skb);
+		skb = new_skb;
+	}
+	skb_dst_drop(skb);
+	skb_dst_set(skb, dst_clone(dst));
+
+	skb->transport_header = skb->network_header;
+	IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
+
+	etherip_ver  = (__u16 *)skb_push(skb, ETH_IPHLEN);
+	*etherip_ver = htons(ETHERIP_VERSION);
+
+	proto = fl->flowi_proto;
+	if (encap_limit >= 0) {
+		init_tel_txopt(&opt, encap_limit);
+		ipv6_push_nfrag_opts(skb, &opt.ops, &proto, NULL);
+	}
+	skb_push(skb, sizeof(struct ipv6hdr));
+	skb_reset_network_header(skb);
+	ipv6h = ipv6_hdr(skb);
+	*(__be32*)ipv6h = fl->u.ip6.flowlabel | htonl(0x60000000);
+	//dsfield = INET_ECN_encapsulate(0, dsfield);
+	//ipv6_change_dsfield(ipv6h, ~INET_ECN_MASK, dsfield);
+	ipv6h->hop_limit = t->parms.hop_limit;
+	ipv6h->nexthdr = proto;
+	ipv6_addr_copy(&ipv6h->saddr, &fl->u.ip6.saddr);
+	ipv6_addr_copy(&ipv6h->daddr, &fl->u.ip6.daddr);
+	nf_reset(skb);
+	pkt_len = skb->len;
+	skb->local_df = 1;
+	err = ip6_local_out(skb);
+
+	if (net_xmit_eval(err) == 0) {
+		stats->tx_bytes += pkt_len;
+		stats->tx_packets++;
+	} else {
+		stats->tx_errors++;
+		stats->tx_aborted_errors++;
+	}
+	ip6_tnl_dst_store(t, dst);
+	return 0;
+tx_err_link_failure:
+	stats->tx_carrier_errors++;
+	dst_link_failure(skb);
+tx_err_dst_release:
+	dst_release(dst);
+	return err;
+}
+
+static inline int
+__ethipip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ip6_tnl *t = netdev_priv(dev);
+	struct flowi fl;
+	__u32 mtu = 0;
+	int err;
+
+	memcpy(&fl, &t->fl, sizeof (fl));
+	fl.flowi_proto = IPPROTO_ETHERIP;
+
+	err = ethipip6_tnl_xmit2(skb, dev, 0, &fl, -1, &mtu);
+	if (err != 0) {
+		/* XXX: send ICMP error even if DF is not set. */
+		if (err == -EMSGSIZE) {
+			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
+		}
+		return -1;
+	}
+
+	return 0;
+}
+
+static inline int
+ip4ethipip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ip6_tnl *t = netdev_priv(dev);
+	struct iphdr  *iph = ip_hdr(skb);
+	int encap_limit = -1;
+	struct flowi fl;
+	__u8 dsfield;
+	__u32 mtu = 0;
+	int err;
+
+
+	memcpy(&fl, &t->fl, sizeof (fl));
+	fl.flowi_proto = IPPROTO_ETHERIP;
+
+	dsfield = ipv4_get_dsfield(iph);
+
+
+	err = ethipip6_tnl_xmit2(skb, dev, dsfield, &fl, encap_limit, &mtu);
+	if (err != 0) {
+		/* XXX: send ICMP error even if DF is not set. */
+		if (err == -EMSGSIZE)
+			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, 
+				htonl(mtu));
+		return -1;
+	}
+
+	return 0;
+}
+
+static inline int
+ip6ethipip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ip6_tnl *t = netdev_priv(dev);
+	struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+	int encap_limit = -1;
+	//__u16 offset;
+	struct flowi fl;
+	__u8 dsfield;
+	__u32 mtu = 0;
+	int err;
+
+	memcpy(&fl, &t->fl, sizeof (fl));
+	fl.flowi_proto = IPPROTO_ETHERIP;
+
+	dsfield = ipv6_get_dsfield(ipv6h);
+
+	err = ethipip6_tnl_xmit2(skb, dev, dsfield, &fl, encap_limit, &mtu);
+	if (err != 0) {
+		if (err == -EMSGSIZE)
+			icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+		return -1;
+	}
+
+	return 0;
+}
+
+static netdev_tx_t
+ethipip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ip6_tnl *t = netdev_priv(dev);
+	struct net_device_stats *stats = &t->dev->stats;
+	int ret;
+
+	switch (skb->protocol) {
+	case htons(ETH_P_IP):
+		ret = ip4ethipip6_tnl_xmit(skb, dev);
+		break;
+	case htons(ETH_P_IPV6):
+		ret = ip6ethipip6_tnl_xmit(skb, dev);
+		break;
+	default:
+		ret = __ethipip6_tnl_xmit(skb, dev);
+		break;
+	}
+
+	if (ret < 0)
+		goto tx_err;
+
+	return NETDEV_TX_OK;
+
+tx_err:
+	stats->tx_errors++;
+	stats->tx_dropped++;
+	kfree_skb(skb);
+	return NETDEV_TX_OK;
+}
+
+static void ip6_tnl_set_cap(struct ip6_tnl *t)
+{
+	struct ip6_tnl_parm *p = &t->parms;
+	int ltype = ipv6_addr_type(&p->laddr);
+	int rtype = ipv6_addr_type(&p->raddr);
+
+	p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV);
+
+	if (ltype & (IPV6_ADDR_UNICAST|IPV6_ADDR_MULTICAST) &&
+	    rtype & (IPV6_ADDR_UNICAST|IPV6_ADDR_MULTICAST) &&
+	    !((ltype|rtype) & IPV6_ADDR_LOOPBACK) &&
+	    (!((ltype|rtype) & IPV6_ADDR_LINKLOCAL) || p->link)) {
+		if (ltype&IPV6_ADDR_UNICAST)
+			p->flags |= IP6_TNL_F_CAP_XMIT;
+		if (rtype&IPV6_ADDR_UNICAST)
+			p->flags |= IP6_TNL_F_CAP_RCV;
+	}
+}
+
+static void ethipip6_tnl_link_config(struct ip6_tnl *t)
+{
+	struct net_device *dev = t->dev;
+	struct ip6_tnl_parm *p = &t->parms;
+	struct flowi *fl = &t->fl;
+	struct net_device *ldev = NULL;
+	struct net *net = dev_net(t->dev);
+
+	memcpy(dev->dev_addr, &p->laddr, dev->addr_len);
+	/* Make sure that dev_addr is nither mcast nor all zeros */
+	dev->dev_addr[0] &= 0xfe;
+	dev->dev_addr[0] |= 0x2;
+
+	memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr));
+
+	/* Set up flowi template */
+	ipv6_addr_copy(&fl->u.ip6.saddr, &p->laddr);
+	ipv6_addr_copy(&fl->u.ip6.daddr, &p->raddr);
+	fl->flowi_oif = p->link;
+	//fl->u.ip6.flowlabel = 0; 
+
+	if (!(p->flags&IP6_TNL_F_USE_ORIG_TCLASS))
+		fl->u.ip6.flowlabel |= IPV6_TCLASS_MASK & p->flowinfo;
+	if (!(p->flags&IP6_TNL_F_USE_ORIG_FLOWLABEL))
+		fl->u.ip6.flowlabel |= IPV6_FLOWLABEL_MASK & p->flowinfo;
+
+	ip6_tnl_set_cap(t);
+
+	if (p->flags&IP6_TNL_F_CAP_XMIT && p->flags&IP6_TNL_F_CAP_RCV)
+		dev->flags |= IFF_POINTOPOINT;
+	else
+		dev->flags &= ~IFF_POINTOPOINT;
+
+	dev->iflink = p->link;
+
+	/* Initialize the default mtu  of tunnel with it's parent interface
+	mtu */
+	rcu_read_lock();
+	if (p->link)
+	{
+		ldev = dev_get_by_index_rcu(net, p->link);
+		if (ldev)
+			dev->mtu = ldev->mtu;
+	}
+	rcu_read_unlock();
+
+	if (p->flags & IP6_TNL_F_CAP_XMIT) {
+		int strict = (ipv6_addr_type(&p->raddr) &
+			      (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL));
+
+		struct rt6_info *rt = rt6_lookup(dev_net(dev),
+						 &p->raddr, &p->laddr,
+						 p->link, strict);
+
+		if (rt == NULL)
+			return;
+
+		if (rt->rt6i_dev) {
+			dev->hard_header_len = rt->rt6i_dev->hard_header_len +
+				sizeof (struct ipv6hdr);
+
+			dev->mtu = rt->rt6i_dev->mtu; //To make bridge happy
+
+			if (dev->mtu < IPV6_MIN_MTU)
+				dev->mtu = IPV6_MIN_MTU;
+		}
+		dst_release(&rt->dst);
+	}
+}
+
+/**
+ * ethipip6_tnl_change - update the tunnel parameters
+ *   @t: tunnel to be changed
+ *   @p: tunnel configuration parameters
+ *
+ * Description:
+ *   ethipip6_tnl_change() updates the tunnel parameters
+ **/
+
+static int
+ethipip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p)
+{
+	ipv6_addr_copy(&t->parms.laddr, &p->laddr);
+	ipv6_addr_copy(&t->parms.raddr, &p->raddr);
+	t->parms.flags = p->flags;
+	t->parms.hop_limit = p->hop_limit;
+	t->parms.encap_limit = p->encap_limit;
+	t->parms.flowinfo = p->flowinfo;
+	t->parms.link = p->link;
+	t->parms.proto = p->proto;
+	ip6_tnl_dst_reset(t);
+	ethipip6_tnl_link_config(t);
+	return 0;
+}
+
+/**
+ * ehtipip6_tnl_ioctl - configure ipv6 tunnels from userspace
+ *   @dev: virtual device associated with tunnel
+ *   @ifr: parameters passed from userspace
+ *   @cmd: command to be performed
+ *
+ * Description:
+ *   ethipip6_tnl_ioctl() is used for managing IPv6 tunnels
+ *   from userspace.
+ *
+ *   The possible commands are the following:
+ *     %SIOCGETTUNNEL: get tunnel parameters for device
+ *     %SIOCADDTUNNEL: add tunnel matching given tunnel parameters
+ *     %SIOCCHGTUNNEL: change tunnel parameters to those given
+ *     %SIOCDELTUNNEL: delete tunnel
+ *
+ *   The fallback device "ethipip6tnl0", created during module
+ *   initialization, can be used for creating other tunnel devices.
+ *
+ * Return:
+ *   0 on success,
+ *   %-EFAULT if unable to copy data to or from userspace,
+ *   %-EPERM if current process hasn't %CAP_NET_ADMIN set
+ *   %-EINVAL if passed tunnel parameters are invalid,
+ *   %-EEXIST if changing a tunnel's parameters would cause a conflict
+ *   %-ENODEV if attempting to change or delete a nonexisting device
+ **/
+
+static int
+ethipip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	int err = 0;
+	struct ip6_tnl_parm p;
+	struct ip6_tnl *t = NULL;
+	struct net *net = dev_net(dev);
+	struct ip6_tnl_net *ip6n = net_generic(net, ethipip6_tnl_net_id);
+
+	switch (cmd) {
+	case SIOCGETTUNNEL:
+		if (dev == ip6n->fb_tnl_dev) {
+			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) {
+				err = -EFAULT;
+				break;
+			}
+			t = ethipip6_tnl_locate(net, &p, 0);
+		}
+		if (t == NULL)
+			t = netdev_priv(dev);
+		memcpy(&p, &t->parms, sizeof (p));
+		if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof (p))) {
+			err = -EFAULT;
+		}
+		break;
+	case SIOCADDTUNNEL:
+	case SIOCCHGTUNNEL:
+		err = -EPERM;
+		if (!capable(CAP_NET_ADMIN))
+			break;
+		err = -EFAULT;
+		if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p)))
+			break;
+		err = -EINVAL;
+		if (p.proto != IPPROTO_ETHERIP && p.proto != 0)
+			break;
+		t = ethipip6_tnl_locate(net, &p, cmd == SIOCADDTUNNEL);
+		if (dev != ip6n->fb_tnl_dev && cmd == SIOCCHGTUNNEL) {
+			if (t != NULL) {
+				if (t->dev != dev) {
+					err = -EEXIST;
+					break;
+				}
+			} else
+				t = netdev_priv(dev);
+
+			ethipip6_tnl_unlink(ip6n, t);
+			err = ethipip6_tnl_change(t, &p);
+			ethipip6_tnl_link(ip6n, t);
+			netdev_state_change(dev);
+		}
+		if (t) {
+			err = 0;
+			if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof (p)))
+				err = -EFAULT;
+
+		} else
+			err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
+		break;
+	case SIOCDELTUNNEL:
+		err = -EPERM;
+		if (!capable(CAP_NET_ADMIN))
+			break;
+
+		if (dev == ip6n->fb_tnl_dev) {
+			err = -EFAULT;
+			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p)))
+				break;
+			err = -ENOENT;
+			if ((t = ethipip6_tnl_locate(net, &p, 0)) == NULL)
+				break;
+			err = -EPERM;
+			if (t->dev == ip6n->fb_tnl_dev)
+				break;
+			dev = t->dev;
+		}
+		err = 0;
+		unregister_netdevice(dev);
+		break;
+	default:
+		err = -EINVAL;
+	}
+	return err;
+}
+
+/**
+ * ethipip6_tnl_change_mtu - change mtu manually for tunnel device
+ *   @dev: virtual device associated with tunnel
+ *   @new_mtu: the new mtu
+ *
+ * Return:
+ *   0 on success,
+ *   %-EINVAL if mtu too small
+ **/
+
+static int
+ethipip6_tnl_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if (new_mtu < IPV6_MIN_MTU) {
+		return -EINVAL;
+	}
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+static int ethipip6_open(struct net_device *dev)
+{
+	return 0;
+}
+
+static int ethipip6_stop(struct net_device *dev)
+{
+	return 0;
+}
+
+static const struct net_device_ops ip6_tnl_netdev_ops = {
+	.ndo_init = ethipip6_tnl_dev_init,
+	.ndo_uninit = ethipip6_tnl_dev_uninit,
+	.ndo_start_xmit = ethipip6_tnl_xmit,
+	.ndo_do_ioctl = ethipip6_tnl_ioctl,
+	.ndo_change_mtu = ethipip6_tnl_change_mtu,
+	.ndo_open = ethipip6_open,
+	.ndo_stop = ethipip6_stop, 
+};
+
+/**
+ * ethipip6_tnl_dev_setup - setup virtual tunnel device
+ *   @dev: virtual device associated with tunnel
+ *
+ * Description:
+ *   Initialize function pointers and device parameters
+ **/
+
+static void ethipip6_tnl_dev_setup(struct net_device *dev)
+{
+	struct ip6_tnl *t = netdev_priv(dev);
+
+	dev->netdev_ops = &ip6_tnl_netdev_ops;
+	dev->destructor = free_netdev;
+
+	dev->type = ARPHRD_IPV6_IPV6_TUNNEL;
+	dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr);
+	dev->mtu = ETH_DATA_LEN - sizeof (struct ipv6hdr) - ETH_IPHLEN - ETH_HLEN;
+	dev->flags |= IFF_NOARP;
+
+	if (ipv6_addr_type(&t->parms.raddr) & IPV6_ADDR_UNICAST)
+		dev->flags |= IFF_POINTOPOINT;
+	dev->iflink = 0; 
+
+	dev->addr_len = ETH_ALEN; //To make bridge happy while adding etherip iface to bridge
+	dev->features |= NETIF_F_NETNS_LOCAL;
+}
+
+
+/**
+ * ethipip6_tnl_dev_init_gen - general initializer for all tunnel devices
+ *   @dev: virtual device associated with tunnel
+ **/
+
+static inline void
+ethipip6_tnl_dev_init_gen(struct net_device *dev)
+{
+	struct ip6_tnl *t = netdev_priv(dev);
+	t->dev = dev;
+	strcpy(t->parms.name, dev->name);
+}
+
+/**
+ * ethipip6_tnl_dev_init - initializer for all non fallback tunnel devices
+ *   @dev: virtual device associated with tunnel
+ **/
+
+static int ethipip6_tnl_dev_init(struct net_device *dev)
+{
+	struct ip6_tnl *t = netdev_priv(dev);
+	ethipip6_tnl_dev_init_gen(dev);
+	ethipip6_tnl_link_config(t);
+
+	return 0;
+}
+
+/**
+ * ethipip6_fb_tnl_dev_init - initializer for fallback tunnel device
+ *   @dev: fallback device
+ *
+ * Return: 0
+ **/
+
+static void ethipip6_fb_tnl_dev_init(struct net_device *dev)
+{
+	struct ip6_tnl *t = netdev_priv(dev);
+	struct net *net = dev_net(dev);
+	struct ip6_tnl_net *ip6n = net_generic(net, ethipip6_tnl_net_id);
+
+	ethipip6_tnl_dev_init_gen(dev);
+	t->parms.proto = IPPROTO_ETHERIP;
+	dev_hold(dev);
+	ip6n->tnls_wc[0] = t;
+}
+
+static struct xfrm6_tunnel ip4ethipip6_handler = {
+	.handler	= ip4ethipip6_rcv,
+	.err_handler	= ip4ethipip6_err,
+	.priority	=	3,
+};
+
+static struct xfrm6_tunnel ip6ethipip6_handler = {
+	.handler	= ip6ethipip6_rcv,
+	.err_handler	= ip6ethipip6_err,
+	.priority	=	3,
+};
+
+static void ethipip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n)
+{
+	int h;
+	struct ip6_tnl *t;
+	LIST_HEAD(list);
+
+	for (h = 0; h < HASH_SIZE; h++) {
+		t = ip6n->tnls_r_l[h];
+		while (t != NULL) {
+			unregister_netdevice_queue(t->dev, &list);
+			t = t->next;
+		}
+	}
+
+	t = ip6n->tnls_wc[0];
+	unregister_netdevice_queue(t->dev, &list);
+	unregister_netdevice_many(&list);
+}
+
+static int ethipip6_tnl_init_net(struct net *net)
+{
+	struct ip6_tnl_net *ip6n = net_generic(net, ethipip6_tnl_net_id);
+	int err;
+
+	ip6n->tnls[0] = ip6n->tnls_wc;
+	ip6n->tnls[1] = ip6n->tnls_r_l;
+
+	err = -ENOMEM;
+	ip6n->fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ethipip6tnl0",
+				      ethipip6_tnl_dev_setup);
+
+	if (!ip6n->fb_tnl_dev)
+		goto err_alloc_dev;
+	dev_net_set(ip6n->fb_tnl_dev, net);
+
+	ethipip6_fb_tnl_dev_init(ip6n->fb_tnl_dev);
+
+	err = register_netdev(ip6n->fb_tnl_dev);
+	if (err < 0)
+		goto err_register;
+	return 0;
+
+err_register:
+	free_netdev(ip6n->fb_tnl_dev);
+err_alloc_dev:
+	return err;
+}
+
+static void ethipip6_tnl_exit_net(struct net *net)
+{
+	struct ip6_tnl_net *ip6n = net_generic(net, ethipip6_tnl_net_id);
+
+	rtnl_lock();
+	ethipip6_tnl_destroy_tunnels(ip6n);
+	rtnl_unlock();
+}
+
+static struct pernet_operations ethipip6_tnl_net_ops = {
+	.init = ethipip6_tnl_init_net,
+	.exit = ethipip6_tnl_exit_net,
+	.id   = &ethipip6_tnl_net_id,
+	.size = sizeof(struct ip6_tnl_net),
+};
+
+static const struct inet6_protocol ethipip6_protocol = {
+ 	.handler        =       ip4ethipip6_rcv,
+        .err_handler    =       ip4ethipip6_err,
+	.flags		= 	IPPROTO_ETHERIP,
+};
+
+/**
+ * ethipip6_tunnel_init - register protocol and reserve needed resources
+ *
+ * Return: 0 on success
+ **/
+
+static int __init ethipip6_tunnel_init(void)
+{
+	int  err;
+
+	if (xfrm6_tunnel_register(&ip4ethipip6_handler, AF_INET)) {
+		printk(KERN_ERR "ip6_tunnel init: can't register ip4ethipip6\n");
+		err = -EAGAIN;
+		goto out;
+	}
+
+	if (xfrm6_tunnel_register(&ip6ethipip6_handler, AF_INET6)) {
+		printk(KERN_ERR "ip6_tunnel init: can't register ip6ethipip6\n");
+		err = -EAGAIN;
+		goto unreg_ip4ip6;
+	}
+
+	err = register_pernet_device(&ethipip6_tnl_net_ops);
+	if (err < 0)
+		goto err_pernet;
+
+	if (inet6_add_protocol(&ethipip6_protocol, IPPROTO_ETHERIP)) { 
+                return -EAGAIN;
+	}
+	return 0;
+
+err_pernet:
+	xfrm6_tunnel_deregister(&ip6ethipip6_handler, AF_INET6);
+unreg_ip4ip6:
+	xfrm6_tunnel_deregister(&ip4ethipip6_handler, AF_INET);
+out:
+	return err;
+}
+
+/**
+ * ethipip6_tunnel_cleanup - free resources and unregister protocol
+ **/
+
+static void __exit ethipip6_tunnel_cleanup(void)
+{
+
+	if (inet6_del_protocol(&ethipip6_protocol, IPPROTO_ETHERIP)) { 
+                printk(KERN_ERR "ethipip6: can't del protocol IPPROTO_ETHERIP\n");
+        }
+
+	if (xfrm6_tunnel_deregister(&ip4ethipip6_handler, AF_INET))
+		printk(KERN_INFO "ip6_tunnel close: can't deregister ip4ethipip6\n");
+
+	if (xfrm6_tunnel_deregister(&ip6ethipip6_handler, AF_INET6))
+		printk(KERN_INFO "ip6_tunnel close: can't deregister ip6ethipip6\n");
+
+	unregister_pernet_device(&ethipip6_tnl_net_ops);
+}
+
+module_init(ethipip6_tunnel_init);
+module_exit(ethipip6_tunnel_cleanup);
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index ae98e09..5d1eec4 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -152,8 +152,15 @@
 
 static int ip6_finish_output(struct sk_buff *skb)
 {
+
+#if defined(CONFIG_INET6_IPSEC_OFFLOAD)
+	if ((skb->ipsec_offload == 0) &&
+		(skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
+		dst_allfrag(skb_dst(skb)))
+#else
 	if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
-	    dst_allfrag(skb_dst(skb)))
+		dst_allfrag(skb_dst(skb)))
+#endif
 		return ip6_fragment(skb, ip6_finish_output2);
 	else
 		return ip6_finish_output2(skb);
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index d19f499..d0cf5b5 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -37,6 +37,7 @@
 #include <linux/route.h>
 #include <linux/rtnetlink.h>
 #include <linux/netfilter_ipv6.h>
+#include <linux/netfilter/nf_conntrack_proto_gre.h>
 #include <linux/slab.h>
 
 #include <asm/uaccess.h>
@@ -74,6 +75,10 @@
 		     (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \
 		    (HASH_SIZE - 1))
 
+
+#define for_each_ip6_tunnel_rcu(start) \
+	for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
+
 static int ip6_tnl_dev_init(struct net_device *dev);
 static void ip6_tnl_dev_setup(struct net_device *dev);
 
@@ -119,6 +124,550 @@
  * Locking : hash tables are protected by RCU and RTNL
  */
 
+static struct kmem_cache *mr_kmem __read_mostly;
+int mr_kmem_alloced = 0;
+
+static inline size_t  ip6_4rd_nlmsg_size(void)
+{
+	return NLMSG_ALIGN(sizeof(struct ip6_4rd_map_msg));
+}
+
+static int ip6_4rd_fill_node( struct sk_buff *skb, struct ip6_tnl_4rd_map_rule *mr,
+			u32 pid, u32 seq,int type, unsigned int flags, int reset, unsigned int ifindex)
+{
+	struct ip6_4rd_map_msg *mr_msg;
+	struct nlmsghdr *nlh;
+
+	nlh = nlmsg_put(skb, pid , seq, type, sizeof(*mr_msg), flags);
+	if (nlh == NULL)
+		return -EMSGSIZE;
+
+	mr_msg = nlmsg_data(nlh);
+	if(reset)
+	{
+		memset(mr_msg,0,sizeof(*mr_msg));
+		mr_msg->reset = 1;
+		mr_msg->ifindex = ifindex;
+		
+	}
+	else
+	{
+		//	memcpy(mr_msg,mr, sizeof(*mr_msg));
+		memset(mr_msg,0,sizeof(*mr_msg));
+		mr_msg->prefix = mr->prefix;
+		mr_msg->prefixlen = mr->prefixlen ;
+		ipv6_addr_copy(&mr_msg->relay_prefix, &mr->relay_prefix);
+		ipv6_addr_copy(&mr_msg->relay_suffix, &mr->relay_suffix);
+		mr_msg->relay_prefixlen = mr->relay_prefixlen ;
+		mr_msg->relay_suffixlen = mr->relay_suffixlen ;
+		mr_msg->psid_offsetlen = mr->psid_offsetlen ;
+		mr_msg->eabit_len = mr->eabit_len ;
+		mr_msg->entry_num = mr->entry_num ;
+		mr_msg->ifindex = ifindex;
+	}
+	return nlmsg_end(skb, nlh);
+
+}
+
+
+static int inet6_dump4rd_mrule(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	struct net *net = sock_net(skb->sk);
+	unsigned int h, s_h;
+	int s_idx, s_ip_idx;
+	int idx, ip_idx;
+	struct ip6_tnl_4rd_map_rule *mr ;
+	int err = 0;
+
+
+	struct ip6_tnl *t;
+	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
+
+	s_h = cb->args[0];
+	s_idx = idx = cb->args[1];
+	s_ip_idx = ip_idx = cb->args[2];
+
+	for (h = s_h; h < HASH_SIZE ; h++, s_idx = 0) {
+		idx = 0;
+		for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[h])
+		{
+			if (idx < s_idx)
+				goto cont_tunnel;
+			if (idx > s_idx)
+				s_ip_idx = 0;
+			ip_idx = 0;
+			read_lock(&t->ip4rd.map_lock);
+			list_for_each_entry (mr, &t->ip4rd.map_list, mr_list){
+				if (ip_idx < s_ip_idx)
+					goto cont_mr;
+				err = ip6_4rd_fill_node(skb, mr,NETLINK_CB(cb->skb).pid,
+						cb->nlh->nlmsg_seq,RTM_NEW4RD, NLM_F_MULTI , 0, t->dev->ifindex);
+				if (err < 0) {
+					WARN_ON(err == -EMSGSIZE);
+					kfree_skb(skb);
+					read_unlock(&t->ip4rd.map_lock);
+					goto out;
+				}
+cont_mr:
+				ip_idx++;
+			}
+			read_unlock(&t->ip4rd.map_lock);
+cont_tunnel:
+			idx++;	
+		}
+	}
+out:
+	cb->args[0] = h;
+	cb->args[1] = idx;
+	cb->args[2] = ip_idx;
+	
+	return skb->len;
+}
+
+
+void ip6_4rd_notify(int event, struct ip6_tnl_4rd_map_rule *mr ,struct net_device *dev, int reset)
+{
+	struct sk_buff *skb;
+	struct net *net = dev_net(dev);
+	int err;
+
+	err = -ENOBUFS;
+
+	skb = nlmsg_new(ip6_4rd_nlmsg_size(), gfp_any());
+	if (skb == NULL)
+		goto errout;
+
+	err = ip6_4rd_fill_node(skb, mr,0,0,event,  0, reset, dev->ifindex);
+	if (err < 0) {
+		/* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
+		WARN_ON(err == -EMSGSIZE);
+		kfree_skb(skb);
+		goto errout;
+	}
+	rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR,
+		    NULL, gfp_any());
+	return;
+errout:
+	if (err < 0)
+		rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err);
+}
+
+static inline void
+ip6_tnl_4rd_mr_destroy(char *f, struct ip6_tnl_4rd_map_rule *mr)
+{
+	list_del(&mr->mr_list);
+	kmem_cache_free(mr_kmem, mr);
+	--mr_kmem_alloced;
+}
+
+static int
+ip6_tnl_4rd_mr_create(struct ip6_tnl_4rd *ip4rd, struct ip6_tnl_4rd_parm *parm, struct net_device *dev)
+{
+	struct ip6_tnl_4rd_map_rule *mr ;
+	int err = 0;
+
+       write_lock_bh(&parm->map_lock);
+       list_for_each_entry (mr, &parm->map_list, mr_list){
+               if( mr->entry_num == ip4rd->entry_num ){
+                       printk(KERN_DEBUG "ip6_tnl_4rd_mr_create: map rule found update");
+                       mr->prefix = ip4rd->prefix ;
+                       ipv6_addr_copy(&mr->relay_prefix, &ip4rd->relay_prefix);
+                       ipv6_addr_copy(&mr->relay_suffix, &ip4rd->relay_suffix);
+                       mr->prefixlen = ip4rd->prefixlen ;
+                       mr->relay_prefixlen = ip4rd->relay_prefixlen ;
+                       mr->relay_suffixlen = ip4rd->relay_suffixlen ;
+                       mr->psid_offsetlen = ip4rd->psid_offsetlen ;
+                       mr->eabit_len = ip4rd->eabit_len ;
+                       mr->entry_num = ip4rd->entry_num ;
+                       goto out;
+               }
+       }
+
+       mr = kmem_cache_alloc(mr_kmem, GFP_KERNEL);
+
+       if (!mr) {
+               printk(KERN_INFO "ip6_tnl_4rd_mr_create: kmem_cache_alloc fail");
+               err = -1 ;
+               goto out;
+       }
+
+       mr->prefix = ip4rd->prefix ;
+       ipv6_addr_copy(&mr->relay_prefix, &ip4rd->relay_prefix);
+       ipv6_addr_copy(&mr->relay_suffix, &ip4rd->relay_suffix);
+       mr->prefixlen = ip4rd->prefixlen ;
+       mr->relay_prefixlen = ip4rd->relay_prefixlen ;
+       mr->relay_suffixlen = ip4rd->relay_suffixlen ;
+       mr->psid_offsetlen = ip4rd->psid_offsetlen ;
+       mr->eabit_len = ip4rd->eabit_len ;
+       mr->entry_num = ip4rd->entry_num ;
+
+       ++mr_kmem_alloced;
+       list_add_tail(&mr->mr_list, &parm->map_list);
+
+out:
+	ip6_4rd_notify(RTM_NEW4RD,mr, dev,0); /* modified by MSPD */
+	write_unlock_bh(&parm->map_lock);
+	return err;
+}
+
+static void
+ip6_tnl_4rd_mr_delete_all(struct ip6_tnl_4rd_parm *parm, struct net_device *dev)
+{
+	struct ip6_tnl_4rd_map_rule *mr, *mr_rule;
+
+	write_lock_bh(&parm->map_lock);
+	list_for_each_entry_safe (mr, mr_rule, &parm->map_list, mr_list){
+		ip6_tnl_4rd_mr_destroy("all", mr);
+	}
+	ip6_4rd_notify(RTM_DEL4RD,mr, dev ,1);
+	write_unlock_bh(&parm->map_lock);
+
+}
+
+static int
+ip6_tnl_4rd_mr_delete(__u16 entry_num , struct ip6_tnl_4rd_parm *parm, struct net_device *dev)
+{
+	struct ip6_tnl_4rd_map_rule *mr, *mr_rule;
+	int err = -1 ;
+
+	write_lock_bh(&parm->map_lock);
+	list_for_each_entry_safe (mr, mr_rule, &parm->map_list, mr_list){
+		if( mr->entry_num == entry_num ){
+			printk(KERN_DEBUG "ip6_tnl_4rd_mr_delete: map rule found delete");
+			ip6_tnl_4rd_mr_destroy("one", mr);
+			err = 0 ;
+			break;
+		}
+	}
+	ip6_4rd_notify(RTM_DEL4RD,mr,dev,0);
+	write_unlock_bh(&parm->map_lock);
+	return err ;
+}
+
+static void
+ip6_tnl_4rd_mr_show(struct ip6_tnl_4rd_parm *parm)
+{
+	struct ip6_tnl_4rd_map_rule *mr;
+
+       printk(KERN_DEBUG "-- 4rd mapping rule list\n");
+       printk(KERN_DEBUG "-- entry num = %d \n",mr_kmem_alloced);
+
+	read_lock(&parm->map_lock);
+	list_for_each_entry(mr, &parm->map_list, mr_list){
+		printk(KERN_DEBUG "%03d : %03d.%03d.%03d.%03d/%02d %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x/%03d %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x/%03d eabit:%03d offset:%03d \n",
+			mr->entry_num,
+			(ntohl(mr->prefix) >> 24) & 0xff,
+			(ntohl(mr->prefix) >> 16) & 0xff,
+			(ntohl(mr->prefix) >>  8) & 0xff,
+			ntohl(mr->prefix) & 0xff,
+			mr->prefixlen,
+			mr->relay_prefix.s6_addr[0],
+			mr->relay_prefix.s6_addr[1],
+			mr->relay_prefix.s6_addr[2],
+			mr->relay_prefix.s6_addr[3],
+			mr->relay_prefix.s6_addr[4],
+			mr->relay_prefix.s6_addr[5],
+			mr->relay_prefix.s6_addr[6],
+			mr->relay_prefix.s6_addr[7],
+			mr->relay_prefix.s6_addr[8],
+			mr->relay_prefix.s6_addr[9],
+			mr->relay_prefix.s6_addr[10],
+			mr->relay_prefix.s6_addr[11],
+			mr->relay_prefix.s6_addr[12],
+			mr->relay_prefix.s6_addr[13],
+			mr->relay_prefix.s6_addr[14],
+			mr->relay_prefix.s6_addr[15],
+			mr->relay_prefixlen,
+			mr->relay_suffix.s6_addr[0],
+			mr->relay_suffix.s6_addr[1],
+			mr->relay_suffix.s6_addr[2],
+			mr->relay_suffix.s6_addr[3],
+			mr->relay_suffix.s6_addr[4],
+			mr->relay_suffix.s6_addr[5],
+			mr->relay_suffix.s6_addr[6],
+			mr->relay_suffix.s6_addr[7],
+			mr->relay_suffix.s6_addr[8],
+			mr->relay_suffix.s6_addr[9],
+			mr->relay_suffix.s6_addr[10],
+			mr->relay_suffix.s6_addr[11],
+			mr->relay_suffix.s6_addr[12],
+			mr->relay_suffix.s6_addr[13],
+			mr->relay_suffix.s6_addr[14],
+			mr->relay_suffix.s6_addr[15],
+			mr->relay_suffixlen,
+			mr->eabit_len,
+			mr->psid_offsetlen );
+	}
+	read_unlock(&parm->map_lock);
+}
+
+static int
+ip6_tnl_4rd_modify_daddr(struct in6_addr *daddr6, __be32 daddr4, __be16 dport4,
+		struct ip6_tnl_4rd_map_rule *mr)
+{
+       int i, pbw0, pbi0, pbi1;
+       __u32 daddr[4];
+       __u32 port_set_id = 0;
+       __u32 mask;
+       __u32 da = ntohl(daddr4);
+       __u16 dp = ntohs(dport4);
+       __u32 diaddr[4];
+       int port_set_id_len = ( mr->eabit_len ) - ( 32 - mr->prefixlen ) ;
+
+       if ( port_set_id_len < 0) {
+               printk(KERN_DEBUG "ip6_tnl_4rd_modify_daddr: PSID length ERROR %d\n", port_set_id_len);
+               return -1;
+       }
+
+       if ( port_set_id_len > 0) {
+               mask = 0xffffffff >> (32 - port_set_id_len);
+               port_set_id = ( dp >> (16 - mr->psid_offsetlen - port_set_id_len ) & mask ) ;
+       }
+
+       for (i = 0; i < 4; ++i)
+               daddr[i] = ntohl(mr->relay_prefix.s6_addr32[i])
+                       | ntohl(mr->relay_suffix.s6_addr32[i]);
+
+       if( mr->prefixlen < 32 ) {
+               pbw0 = mr->relay_prefixlen >> 5;
+               pbi0 = mr->relay_prefixlen & 0x1f;
+               daddr[pbw0] |= (da << mr->prefixlen) >> pbi0;
+               pbi1 = pbi0 - mr->prefixlen;
+               if (pbi1 > 0)
+                       daddr[pbw0+1] |= da << (32 - pbi1);
+	}
+       if ( port_set_id_len > 0) {
+	       pbw0 = (mr->relay_prefixlen + 32 - mr->prefixlen) >> 5;
+	       pbi0 = (mr->relay_prefixlen + 32 - mr->prefixlen) & 0x1f;
+	       daddr[pbw0] |= (port_set_id << (32 - port_set_id_len)) >> pbi0;
+	       pbi1 = pbi0 - (32 - port_set_id_len);
+	       if (pbi1 > 0)
+		       daddr[pbw0+1] |= port_set_id << (32 - pbi1);
+       }
+
+       memset(diaddr, 0, sizeof(diaddr));
+
+       diaddr[2] = ( da >> 8 ) ;
+       diaddr[3] = ( da << 24 ) ;
+       diaddr[3] |= ( port_set_id << 8 ) ;
+
+       for (i = 0; i < 4; ++i)
+               daddr[i] = daddr[i] | diaddr[i] ;
+
+       for (i = 0; i < 4; ++i)
+               daddr6->s6_addr32[i] = htonl(daddr[i]);
+
+       /* DBG */
+       printk(KERN_DEBUG "ip6_tnl_4rd_modify_daddr: %08x %08x %08x %08x  PSID:%04x\n",
+               daddr[0], daddr[1], daddr[2], daddr[3], port_set_id);
+
+       return 0;
+}
+
+/**
+ * ip6_tnl_4rd_rcv_helper - 
+ *   @skb: received socket buffer
+ *   @t: tunnel device
+ **/
+
+static int
+ip6_tnl_4rd_rcv_helper(struct sk_buff *skb, struct ip6_tnl *t)
+{
+       int err = 0;
+       struct iphdr *iph;
+
+       iph = ip_hdr(skb);
+
+       switch (iph->protocol) {
+       case IPPROTO_TCP:
+       case IPPROTO_UDP:
+       case IPPROTO_ICMP:
+       case IPPROTO_GRE:
+               break;
+       default:
+               err = -1;
+               break;
+       }
+
+       return err;
+}
+
+static int
+ip6_tnl_4rd_xmit_helper(struct sk_buff *skb, struct flowi6 *fl6,
+		struct ip6_tnl *t)
+{
+       int err = 0;
+       struct iphdr *iph, *icmpiph;
+       __be16  *idp;
+       struct tcphdr *tcph, *icmptcph;
+       struct udphdr *udph, *icmpudph;
+       struct icmphdr *icmph;
+       struct gre_hdr *greh;
+       __u32 mask;
+       __be16 *sportp = NULL;
+       __be32 daddr;
+       __be16 dport;
+       u8 *ptr;
+       int no_dst_chg = 0;
+       struct ip6_tnl_4rd_map_rule *mr,*mr_tmp;
+       int mr_prefixlen ;
+       int count ;
+
+       iph = ip_hdr(skb);
+
+       daddr = iph->daddr;
+       idp = &iph->id;
+
+       ptr = (u8 *)iph;
+       ptr += iph->ihl * 4;
+       switch (iph->protocol) {
+       case IPPROTO_TCP:
+               tcph = (struct tcphdr *)ptr;
+               sportp = &tcph->source;
+               dport = tcph->dest;
+               break;
+       case IPPROTO_UDP:
+               udph = (struct udphdr *)ptr;
+               sportp = &udph->source;
+               dport = udph->dest;
+               break;
+       case IPPROTO_ICMP:
+               icmph = (struct icmphdr *)ptr;
+               switch (icmph->type) {
+               case ICMP_DEST_UNREACH:
+               case ICMP_SOURCE_QUENCH:
+               case ICMP_REDIRECT:
+               case ICMP_TIME_EXCEEDED:
+               case ICMP_PARAMETERPROB:
+                       ptr = (u8 *)icmph;
+                       ptr += sizeof(struct icmphdr);
+                       icmpiph = (struct iphdr*)ptr;
+                       if (ntohs(iph->tot_len) < icmpiph->ihl * 4 + 12) {
+                               err = -1;
+                               goto out;
+                       }
+                       daddr = icmpiph->saddr;
+                       ptr += icmpiph->ihl * 4;
+                       switch (icmpiph->protocol) {
+                       case IPPROTO_TCP:
+                               icmptcph = (struct tcphdr *)ptr;
+                               sportp = &icmptcph->dest;
+                               dport = icmptcph->source;
+                               break;
+                       case IPPROTO_UDP:
+                               icmpudph = (struct udphdr *)ptr;
+                               sportp = &icmpudph->dest;
+                               dport = icmpudph->source;
+                               break;
+                       default:
+                               err = -1;
+                               goto out;
+                       }
+                       break;
+               default:
+                       no_dst_chg = 1;
+                       break;
+               }
+               break;
+       case IPPROTO_GRE:
+               greh = (struct gre_hdr *)ptr;
+               if(greh->protocol != GRE_PROTOCOL_PPTP){
+                       err = -1;
+                       goto out;
+               }
+               no_dst_chg = 1;
+               break;
+       default:
+               err = -1;
+               goto out;
+       }
+
+       if ( no_dst_chg == 0 ){
+
+               count = 0;
+               mr_prefixlen = 0;
+
+               read_lock(&t->ip4rd.map_lock);
+               list_for_each_entry (mr, &t->ip4rd.map_list, mr_list){
+                       mask = 0xffffffff << (32 - mr->prefixlen) ;
+                       if( (htonl(daddr) & mask ) == htonl( mr->prefix) ) {
+                               if ( mr->prefixlen >= mr_prefixlen ){
+                                       mr_prefixlen = mr->prefixlen ;
+                                       mr_tmp = mr;
+                                       count++;
+                               }
+                       }
+               }
+
+               if (count){
+                       err = ip6_tnl_4rd_modify_daddr(&fl6->daddr, daddr, dport, mr_tmp );
+                       if (err){
+                                       read_unlock(&t->ip4rd.map_lock);
+                                       goto out;
+                       }
+               }
+               read_unlock(&t->ip4rd.map_lock);
+
+               if(sportp && idp){
+                       *idp=*sportp;
+               }
+       }
+
+       iph->check = 0;
+       iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+
+       /* XXX: */
+       skb->local_df = 1;
+
+out:
+	return err;
+}
+
+/**
+ * ip6_tnl_4rd_update_parms - update 4rd parameters
+ *   @t: tunnel to be updated
+ *
+ * Description:
+ *   ip6_tnl_4rd_update_parms() updates 4rd parameters
+ **/
+static void
+ip6_tnl_4rd_update_parms(struct ip6_tnl *t)
+{
+	int pbw0, pbi0, pbi1;
+	__u32 d;
+
+	t->ip4rd.port_set_id_len = t->ip4rd.relay_suffixlen
+				- t->ip4rd.relay_prefixlen
+				- (32 - t->ip4rd.prefixlen);
+	pbw0 = (t->ip4rd.relay_suffixlen - t->ip4rd.port_set_id_len) >> 5;
+	pbi0 = (t->ip4rd.relay_suffixlen - t->ip4rd.port_set_id_len) & 0x1f;
+	d = (ntohl(t->parms.laddr.s6_addr32[pbw0]) << pbi0)
+		>> (32 - t->ip4rd.port_set_id_len);
+	pbi1 = pbi0 - (32 - t->ip4rd.port_set_id_len);
+
+	if (pbi1 > 0)
+		d |= ntohl(t->parms.laddr.s6_addr32[pbw0+1]) >> (32 - pbi1);
+	t->ip4rd.port_set_id = d;
+
+	/* local v4 address */
+	t->ip4rd.laddr4 = t->ip4rd.prefix;
+	pbw0 = t->ip4rd.relay_prefixlen >> 5;
+	pbi0 = t->ip4rd.relay_prefixlen & 0x1f;
+	d = (ntohl(t->parms.laddr.s6_addr32[pbw0]) << pbi0)
+		>> t->ip4rd.prefixlen;
+	pbi1 = pbi0 - t->ip4rd.prefixlen;
+	if (pbi1 > 0)
+		d |= ntohl(t->parms.laddr.s6_addr32[pbw0+1]) >> (32 - pbi1);
+	t->ip4rd.laddr4 |= htonl(d);
+	if (t->ip4rd.port_set_id_len < 0) {
+		d = ntohl(t->ip4rd.laddr4);
+		d &= 0xffffffff << -t->ip4rd.port_set_id_len;
+		t->ip4rd.laddr4 = htonl(d);
+	}
+
+}
+
+
 static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t)
 {
 	struct dst_entry *dst = t->dst_cache;
@@ -158,22 +707,26 @@
  *   else %NULL
  **/
 
-#define for_each_ip6_tunnel_rcu(start) \
-	for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
 
 static struct ip6_tnl *
 ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_addr *local)
 {
-	unsigned int h0 = HASH(remote);
-	unsigned int h1 = HASH(local);
+//	unsigned int h0 = HASH(remote); /* 4rd support, remote could be any, so hashing to be done only based on local address */
+	unsigned int h1 = HASH(local); 
 	struct ip6_tnl *t;
 	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
 
-	for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[h0 ^ h1]) {
+	for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[h1]) {
 		if (ipv6_addr_equal(local, &t->parms.laddr) &&
 		    ipv6_addr_equal(remote, &t->parms.raddr) &&
 		    (t->dev->flags & IFF_UP))
 			return t;
+                if (t->ip4rd.prefix &&
+                   ipv6_addr_equal(local, &t->parms.laddr) &&
+                /* ipv6_prefix_equal(remote, &t->ip4rd.relay_prefix,
+                       t->ip4rd.relay_prefixlen) && 4RD D  */
+                   (t->dev->flags & IFF_UP))
+                       return t;
 	}
 	t = rcu_dereference(ip6n->tnls_wc[0]);
 	if (t && (t->dev->flags & IFF_UP))
@@ -196,14 +749,14 @@
 static struct ip6_tnl __rcu **
 ip6_tnl_bucket(struct ip6_tnl_net *ip6n, const struct ip6_tnl_parm *p)
 {
-	const struct in6_addr *remote = &p->raddr;
+//	const struct in6_addr *remote = &p->raddr;
 	const struct in6_addr *local = &p->laddr;
 	unsigned h = 0;
 	int prio = 0;
 
-	if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) {
+	if (!ipv6_addr_any(local)) {      /* 4rd support, since remote address could be any address, refrain from checking based on remote */ 
 		prio = 1;
-		h = HASH(remote) ^ HASH(local);
+		h = HASH(local);	
 	}
 	return &ip6n->tnls[prio][h];
 }
@@ -291,6 +844,9 @@
 
 	strcpy(t->parms.name, dev->name);
 
+	rwlock_init(&t->ip4rd.map_lock);
+	INIT_LIST_HEAD(&t->ip4rd.map_list); 
+
 	dev_hold(dev);
 	ip6_tnl_link(ip6n, t);
 	return t;
@@ -766,6 +1322,10 @@
 		__skb_tunnel_rx(skb, t->dev);
 
 		dscp_ecn_decapsulate(t, ipv6h, skb);
+                if (ip6_tnl_4rd_rcv_helper(skb, t)) {
+                        rcu_read_unlock();
+                        goto discard;
+                }
 
 		netif_rx(skb);
 
@@ -898,6 +1458,7 @@
 	u8 proto;
 	int err = -1;
 	int pkt_len;
+	__u8 hop_limit;    
 
 	if (!fl6->flowi6_mark)
 		dst = ip6_tnl_dst_check(t);
@@ -934,10 +1495,21 @@
 		mtu = IPV6_MIN_MTU;
 	if (skb_dst(skb))
 		skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
-	if (skb->len > mtu) {
-		*pmtu = mtu;
-		err = -EMSGSIZE;
-		goto tx_err_dst_release;
+        if (!t->ip4rd.prefix) {   /* 4rd support requires Post Fragmentation, so skb->len could be greater than MTU */ 
+                if (skb->len > mtu) {
+                        *pmtu = mtu;
+                        err = -EMSGSIZE;
+                        goto tx_err_dst_release;
+                }
+        }                         
+
+	if (t->ip4rd.prefix) {
+		struct iphdr *iph;
+		iph = ip_hdr(skb);
+		hop_limit = iph->ttl;
+	}
+	else {
+		hop_limit = t->parms.hop_limit;
 	}
 
 	/*
@@ -977,7 +1549,7 @@
 	*(__be32*)ipv6h = fl6->flowlabel | htonl(0x60000000);
 	dsfield = INET_ECN_encapsulate(0, dsfield);
 	ipv6_change_dsfield(ipv6h, ~INET_ECN_MASK, dsfield);
-	ipv6h->hop_limit = t->parms.hop_limit;
+	ipv6h->hop_limit = hop_limit;    
 	ipv6h->nexthdr = proto;
 	ipv6_addr_copy(&ipv6h->saddr, &fl6->saddr);
 	ipv6_addr_copy(&ipv6h->daddr, &fl6->daddr);
@@ -1034,6 +1606,10 @@
 	if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
 		fl6.flowi6_mark = skb->mark;
 
+
+        if (t->ip4rd.prefix && ip6_tnl_4rd_xmit_helper(skb, &fl6, t))
+                return -1;
+
 	err = ip6_tnl_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu);
 	if (err != 0) {
 		/* XXX: send ICMP error even if DF is not set. */
@@ -1105,6 +1681,8 @@
 
 	switch (skb->protocol) {
 	case htons(ETH_P_IP):
+                if (t->ip4rd.prefix && ip_defrag(skb, IP_DEFRAG_IP6_TNL_4RD))
+                        return NETDEV_TX_OK;
 		ret = ip4ip6_tnl_xmit(skb, dev);
 		break;
 	case htons(ETH_P_IPV6):
@@ -1143,6 +1721,11 @@
 		if (rtype&IPV6_ADDR_UNICAST)
 			p->flags |= IP6_TNL_F_CAP_RCV;
 	}
+
+        if (t->ip4rd.prefix) {
+                p->flags |= IP6_TNL_F_CAP_XMIT;
+                p->flags |= IP6_TNL_F_CAP_RCV;
+        }
 }
 
 static void ip6_tnl_link_config(struct ip6_tnl *t)
@@ -1220,6 +1803,7 @@
 	t->parms.flowinfo = p->flowinfo;
 	t->parms.link = p->link;
 	t->parms.proto = p->proto;
+        ip6_tnl_4rd_update_parms(t);        
 	ip6_tnl_dst_reset(t);
 	ip6_tnl_link_config(t);
 	return 0;
@@ -1261,6 +1845,8 @@
 	struct ip6_tnl *t = NULL;
 	struct net *net = dev_net(dev);
 	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
+        struct ip6_tnl_4rd ip4rd, *ip4rdp;  
+        struct ip6_tnl_4rd_map_rule *mr;   
 
 	switch (cmd) {
 	case SIOCGETTUNNEL:
@@ -1334,9 +1920,115 @@
 		err = 0;
 		unregister_netdevice(dev);
 		break;
+	case SIOCADD4RD:
+	case SIOCDEL4RD:
+		err = -EPERM;
+		if (!capable(CAP_NET_ADMIN))
+			goto done;
+
+		err = -EFAULT;
+		if (copy_from_user(&ip4rd, ifr->ifr_ifru.ifru_data, sizeof(ip4rd)))
+			goto done;
+
+		t = netdev_priv(dev);
+
+		if (cmd == SIOCADD4RD) {
+
+			__be32 prefix;
+			struct in6_addr relay_prefix, relay_suffix;
+
+			err = -EINVAL;
+
+			if (ip4rd.relay_suffixlen > 64)
+				goto done;
+
+			if (ip4rd.relay_suffixlen <= ip4rd.relay_prefixlen)
+				goto done;
+
+			prefix = ip4rd.prefix & htonl(0xffffffffUL << (32 - ip4rd.prefixlen));
+			if (prefix != ip4rd.prefix)
+				goto done;
+
+			ipv6_addr_prefix(&relay_prefix, &ip4rd.relay_prefix, ip4rd.relay_prefixlen);
+			if (!ipv6_addr_equal(&relay_prefix, &ip4rd.relay_prefix))
+				goto done;
+
+			ipv6_addr_prefix(&relay_suffix, &ip4rd.relay_suffix, ip4rd.relay_suffixlen);
+			if (!ipv6_addr_equal(&relay_suffix, &ip4rd.relay_suffix))
+				goto done;
+
+
+			err = ip6_tnl_4rd_mr_create(&ip4rd, &t->ip4rd, t->dev); /* modified by MSPD */
+
+			if ( ip4rd.entry_num == 0 ){
+
+				t->ip4rd.prefix = prefix;
+				ipv6_addr_copy(&t->ip4rd.relay_prefix, &relay_prefix);
+				ipv6_addr_copy(&t->ip4rd.relay_suffix, &relay_suffix);
+				t->ip4rd.prefixlen = ip4rd.prefixlen;
+				t->ip4rd.relay_prefixlen = ip4rd.relay_prefixlen;
+				t->ip4rd.relay_suffixlen = ip4rd.relay_suffixlen;
+				t->ip4rd.psid_offsetlen = ip4rd.psid_offsetlen;
+
+				ip6_tnl_4rd_update_parms(t);
+				ip6_tnl_dst_reset(t);
+				ip6_tnl_link_config(t);
+			}
+			/* DBG */
+			ip6_tnl_4rd_mr_show(&t->ip4rd);
+		}else if(cmd == SIOCDEL4RD){
+			if ( ip4rd.entry_num == 0 ){
+				ip6_tnl_4rd_mr_delete_all(&t->ip4rd, t->dev);
+				t->ip4rd.prefix = 0;
+				memset(&t->ip4rd.relay_prefix, 0, sizeof(t->ip4rd.relay_prefix));
+				memset(&t->ip4rd.relay_suffix, 0, sizeof(t->ip4rd.relay_suffix));
+				t->ip4rd.prefixlen = 0;
+				t->ip4rd.relay_prefixlen = 0;
+				t->ip4rd.relay_suffixlen = 0;
+				t->ip4rd.psid_offsetlen = 0;
+				t->ip4rd.laddr4 = 0;
+				t->ip4rd.port_set_id = t->ip4rd.port_set_id_len = 0;
+
+				ip6_tnl_dst_reset(t);
+				ip6_tnl_link_config(t);
+			}else{
+				err = ip6_tnl_4rd_mr_delete( ip4rd.entry_num , &t->ip4rd, t->dev);  /* modified by MSPD */
+			}
+			/* DBG */
+			ip6_tnl_4rd_mr_show(&t->ip4rd);
+		}else{
+			printk(KERN_ERR "=== ioctl_cmd 0x%x \n",cmd );
+		}
+		err = 0;
+		break;
+        case SIOCGET4RD:
+                t = netdev_priv(dev);
+                ip4rdp = (struct ip6_tnl_4r *)ifr->ifr_ifru.ifru_data;
+ 
+                read_lock(&t->ip4rd.map_lock);
+                list_for_each_entry (mr, &t->ip4rd.map_list, mr_list){
+                        ipv6_addr_copy(&ip4rd.relay_prefix, &mr->relay_prefix);
+                        ipv6_addr_copy(&ip4rd.relay_suffix, &mr->relay_suffix);
+                        ip4rd.prefix = mr->prefix;
+                        ip4rd.relay_prefixlen = mr->relay_prefixlen;
+                        ip4rd.relay_suffixlen = mr->relay_suffixlen;
+                        ip4rd.prefixlen = mr->prefixlen;
+                        ip4rd.eabit_len = mr->eabit_len;
+                        ip4rd.psid_offsetlen = mr->psid_offsetlen;
+                        ip4rd.entry_num = mr->entry_num;
+ 
+                        if (copy_to_user(ip4rdp, &ip4rd, sizeof(ip4rd))) {
+                                read_unlock(&t->ip4rd.map_lock);
+                                err = -EFAULT;
+                        }
+                        ip4rdp++;
+                }
+                read_unlock(&t->ip4rd.map_lock);
+                break;
 	default:
 		err = -EINVAL;
 	}
+done:
 	return err;
 }
 
@@ -1545,12 +2237,22 @@
 
 static int __init ip6_tunnel_init(void)
 {
-	int  err;
+        int err = 0;                
+ 
+        mr_kmem = kmem_cache_create("ip6_tnl_4rd_map_rule",
+                sizeof(struct ip6_tnl_4rd_map_rule), 0, SLAB_HWCACHE_ALIGN,
+                NULL);
+        if (!mr_kmem)
+	{
+		err= -ENOMEM; 
+                goto out_pernet;
+	}
 
 	err = register_pernet_device(&ip6_tnl_net_ops);
 	if (err < 0)
-		goto out_pernet;
+		goto out_kmem;
 
+	
 	err = xfrm6_tunnel_register(&ip4ip6_handler, AF_INET);
 	if (err < 0) {
 		printk(KERN_ERR "ip6_tunnel init: can't register ip4ip6\n");
@@ -1563,12 +2265,18 @@
 		goto out_ip6ip6;
 	}
 
+        err =__rtnl_register(PF_UNSPEC, RTM_GET4RD, NULL , inet6_dump4rd_mrule, NULL);
+        if(err < 0)
+                goto out_ip6ip6;
+
 	return 0;
 
 out_ip6ip6:
 	xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET);
 out_ip4ip6:
 	unregister_pernet_device(&ip6_tnl_net_ops);
+out_kmem:
+	kmem_cache_destroy(mr_kmem);
 out_pernet:
 	return err;
 }
@@ -1585,7 +2293,12 @@
 	if (xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6))
 		printk(KERN_INFO "ip6_tunnel close: can't deregister ip6ip6\n");
 
+        kmem_cache_destroy(mr_kmem);     
+ 
 	unregister_pernet_device(&ip6_tnl_net_ops);
+
+        rtnl_unregister(PF_UNSPEC, RTM_GET4RD);
+ 
 }
 
 module_init(ip6_tunnel_init);
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index f792b34..95d651c 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -205,6 +205,14 @@
         
          If unsure, say N.
 
+config IP6_NF_TARGET_NPT
+	tristate "NPT (Network Prefix translation) target support"
+	help
+	  This option adds the `SNPT' and `DNPT' target, which perform
+	  stateless IPv6-to-IPv6 Network Prefix Translation per RFC 6296.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 endif # IP6_NF_IPTABLES
 
 endmenu
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index abfee91..91b0806 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -31,4 +31,5 @@
 
 # targets
 obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
+obj-$(CONFIG_IP6_NF_TARGET_NPT) += ip6t_NPT.o
 obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
diff --git a/net/ipv6/netfilter/ip6t_NPT.c b/net/ipv6/netfilter/ip6t_NPT.c
new file mode 100644
index 0000000..2698150
--- /dev/null
+++ b/net/ipv6/netfilter/ip6t_NPT.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2011, 2012 Patrick McHardy <kaber@trash.net>
+ *
+ * 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/module.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <net/ipv6.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv6.h>
+#include <linux/netfilter_ipv6/ip6t_NPT.h>
+#include <linux/netfilter/x_tables.h>
+#include <net/netfilter/nf_conntrack.h>
+
+static int ip6t_npt_checkentry(const struct xt_tgchk_param *par)
+{
+	struct ip6t_npt_tginfo *npt = par->targinfo;
+	__wsum src_sum = 0, dst_sum = 0;
+	struct in6_addr pfx;
+	unsigned int i;
+
+	if (npt->src_pfx_len > 64 || npt->dst_pfx_len > 64)
+		return -EINVAL;
+
+	/* Ensure that LSB of prefix is zero */
+	ipv6_addr_prefix(&pfx, &npt->src_pfx.in6, npt->src_pfx_len);
+	if (!ipv6_addr_equal(&pfx, &npt->src_pfx.in6))
+		return -EINVAL;
+	ipv6_addr_prefix(&pfx, &npt->dst_pfx.in6, npt->dst_pfx_len);
+	if (!ipv6_addr_equal(&pfx, &npt->dst_pfx.in6))
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(npt->src_pfx.in6.s6_addr16); i++) {
+		src_sum = csum_add(src_sum,
+				(__force __wsum)npt->src_pfx.in6.s6_addr16[i]);
+		dst_sum = csum_add(dst_sum,
+				(__force __wsum)npt->dst_pfx.in6.s6_addr16[i]);
+	}
+
+	npt->adjustment = ~csum_fold(csum_sub(src_sum, dst_sum));
+	return 0;
+}
+
+static bool ip6t_npt_map_pfx(const struct ip6t_npt_tginfo *npt,
+			     struct in6_addr *addr)
+{
+	unsigned int pfx_len;
+	unsigned int i, idx;
+	__be32 mask;
+	__sum16 sum;
+
+	pfx_len = max(npt->src_pfx_len, npt->dst_pfx_len);
+	for (i = 0; i < pfx_len; i += 32) {
+		if (pfx_len - i >= 32)
+			mask = 0;
+		else
+			mask = htonl((1 << (i - pfx_len + 32)) - 1);
+
+		idx = i / 32;
+		addr->s6_addr32[idx] &= mask;
+		addr->s6_addr32[idx] |= ~mask & npt->dst_pfx.in6.s6_addr32[idx];
+	}
+
+	if (pfx_len <= 48)
+		idx = 3;
+	else {
+		for (idx = 4; idx < ARRAY_SIZE(addr->s6_addr16); idx++) {
+			if ((__force __sum16)addr->s6_addr16[idx] !=
+			    CSUM_MANGLED_0)
+				break;
+		}
+		if (idx == ARRAY_SIZE(addr->s6_addr16))
+			return false;
+	}
+
+	sum = ~csum_fold(csum_add(csum_unfold((__force __sum16)addr->s6_addr16[idx]),
+				  csum_unfold(npt->adjustment)));
+	if (sum == CSUM_MANGLED_0)
+		sum = 0;
+	*(__force __sum16 *)&addr->s6_addr16[idx] = sum;
+
+	return true;
+}
+
+static unsigned int
+ip6t_snpt_tg(struct sk_buff *skb, const struct xt_action_param *par)
+{
+	const struct ip6t_npt_tginfo *npt = par->targinfo;
+	struct nf_conn *ct;
+	enum ip_conntrack_info ctinfo;
+
+	if (!ip6t_npt_map_pfx(npt, &ipv6_hdr(skb)->saddr)) {
+		icmpv6_send(skb, ICMPV6_PARAMPROB, ICMPV6_HDR_FIELD,
+			    offsetof(struct ipv6hdr, saddr));
+		return NF_DROP;
+	}
+#ifdef CONFIG_COMCERTO_FP
+	ct = nf_ct_get(skb, &ctinfo);
+	if (ct && ((ctinfo == IP_CT_NEW) || (ctinfo == IP_CT_RELATED))) {
+		rcu_read_lock();
+		memcpy(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.in6, &ipv6_hdr(skb)->saddr, sizeof(struct in6_addr));
+		rcu_read_unlock();
+	}
+#endif
+	return XT_CONTINUE;
+}
+
+static unsigned int
+ip6t_dnpt_tg(struct sk_buff *skb, const struct xt_action_param *par)
+{
+	const struct ip6t_npt_tginfo *npt = par->targinfo;
+	struct nf_conn *ct;
+	enum ip_conntrack_info ctinfo;
+
+	if (!ip6t_npt_map_pfx(npt, &ipv6_hdr(skb)->daddr)) {
+		icmpv6_send(skb, ICMPV6_PARAMPROB, ICMPV6_HDR_FIELD,
+			    offsetof(struct ipv6hdr, daddr));
+		return NF_DROP;
+	}
+#ifdef CONFIG_COMCERTO_FP
+	ct = nf_ct_get(skb, &ctinfo);
+	if (ct && ((ctinfo == IP_CT_NEW) || (ctinfo == IP_CT_RELATED))) {
+		rcu_read_lock();
+		memcpy(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.in6, &ipv6_hdr(skb)->daddr, sizeof(struct in6_addr));
+		rcu_read_unlock();
+	}
+#endif
+	return XT_CONTINUE;
+}
+
+static struct xt_target ip6t_npt_target_reg[] __read_mostly = {
+	{
+		.name		= "SNPT",
+		.target		= ip6t_snpt_tg,
+		.targetsize	= sizeof(struct ip6t_npt_tginfo),
+		.checkentry	= ip6t_npt_checkentry,
+		.family		= NFPROTO_IPV6,
+		.hooks		= (1 << NF_INET_LOCAL_IN) |
+				  (1 << NF_INET_POST_ROUTING),
+		.me		= THIS_MODULE,
+	},
+	{
+		.name		= "DNPT",
+		.target		= ip6t_dnpt_tg,
+		.targetsize	= sizeof(struct ip6t_npt_tginfo),
+		.checkentry	= ip6t_npt_checkentry,
+		.family		= NFPROTO_IPV6,
+		.hooks		= (1 << NF_INET_PRE_ROUTING) |
+				  (1 << NF_INET_LOCAL_OUT),
+		.me		= THIS_MODULE,
+	},
+};
+
+static int __init ip6t_npt_init(void)
+{
+	return xt_register_targets(ip6t_npt_target_reg,
+				   ARRAY_SIZE(ip6t_npt_target_reg));
+}
+
+static void __exit ip6t_npt_exit(void)
+{
+	xt_unregister_targets(ip6t_npt_target_reg,
+			      ARRAY_SIZE(ip6t_npt_target_reg));
+}
+
+module_init(ip6t_npt_init);
+module_exit(ip6t_npt_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("IPv6-to-IPv6 Network Prefix Translation (RFC 6296)");
+MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+MODULE_ALIAS("ip6t_SNPT");
+MODULE_ALIAS("ip6t_DNPT");
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 2e21751..eb608ef 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -2440,8 +2440,11 @@
 		ipv6_addr_copy(&saddr_buf, &rt->rt6i_prefsrc.addr);
 		NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
 	}
-
+#ifdef CONFIG_ARCH_COMCERTO
+	if (rtnetlink_put_metrics_2(skb, dst_metrics_ptr(&rt->dst), &rt->dst) < 0)
+#else
 	if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
+#endif
 		goto nla_put_failure;
 
 	rcu_read_lock();
@@ -2503,6 +2506,7 @@
 	struct rtmsg *rtm;
 	struct flowi6 fl6;
 	int err, iif = 0;
+	int flags = 0;
 
 	err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
 	if (err < 0)
@@ -2531,6 +2535,9 @@
 	if (tb[RTA_OIF])
 		fl6.flowi6_oif = nla_get_u32(tb[RTA_OIF]);
 
+	if (tb[RTA_MARK])
+		fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]);
+
 	if (iif) {
 		struct net_device *dev;
 		dev = __dev_get_by_index(net, iif);
@@ -2538,6 +2545,14 @@
 			err = -ENODEV;
 			goto errout;
 		}
+
+		fl6.flowi6_iif = iif;
+
+		if (!ipv6_addr_any(&fl6.saddr))
+			flags |= RT6_LOOKUP_F_HAS_SADDR;
+
+		if (rt6_need_strict(&fl6.daddr) && dev->type != ARPHRD_PIMREG)
+			flags |= RT6_LOOKUP_F_IFACE;
 	}
 
 	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
@@ -2552,7 +2567,11 @@
 	skb_reset_mac_header(skb);
 	skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
 
-	rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl6);
+	if (iif)
+		rt = (struct rt6_info*) fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_input);
+	else
+		rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl6);
+
 	skb_dst_set(skb, &rt->dst);
 
 	err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 8c25419..2be1dee 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -515,6 +515,36 @@
 	if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
 		goto drop;
 
+
+	/* NAT-T changes Start */
+	if ( up->encap_type ) {
+		/*
+		 * This is an encapsulation socket, so pass the skb to
+		 * the socket's udp6_encap_rcv() hook.Otherwise, just
+		 * fall through and pass this up the UDP socket.
+		 * up->encap_rcv() returns the following value:
+		 * =0 if skb was successfully passed to the encap
+		 * handler or was discarded by it.
+		 * >0 if skb should be passed on to UDP.
+		 * <0 if skb should be resubmitted as proto -N
+		 */
+
+		/* if we're overly short, let UDP handle it */
+		if (skb->len > sizeof(struct udphdr) &&
+		    up->encap_rcv != NULL) {
+			int ret;
+
+			ret = (*up->encap_rcv)(sk, skb);
+			if (ret <= 0) {
+				UDP_INC_STATS_BH(sock_net(sk),
+						UDP_MIB_INDATAGRAMS,
+						is_udplite);
+				return -ret;
+			}
+			 /* FALLTHROUGH -- it's a UDP Packet */
+		}
+	}
+
 	/*
 	 * UDP-Lite specific tests, ignored on UDP sockets (see net/ipv4/udp.c).
 	 */
@@ -1240,24 +1270,111 @@
 }
 
 /*
+*	Socket option code for UDP for IPV6
+*/
+int udp6_lib_setsockopt(struct sock *sk, int level, int optname,
+		       char __user *optval, unsigned int optlen,
+		       int (*push_pending_frames)(struct sock *))
+{
+	struct udp_sock *up = udp_sk(sk);
+	int val;
+	int err = 0;
+	int is_udplite = IS_UDPLITE(sk);
+
+	if (optlen < sizeof(int))
+		return -EINVAL;
+
+	if (get_user(val, (int __user *)optval))
+		return -EFAULT;
+
+	switch (optname) {
+		case UDP_CORK:
+			if (val != 0) {
+				up->corkflag = 1;
+			} else {
+				up->corkflag = 0;
+				lock_sock(sk);
+				(*push_pending_frames)(sk);
+				release_sock(sk);
+			}
+			break;
+
+		case UDP_ENCAP:
+			switch (val) {
+				case 0:
+				case UDP_ENCAP_ESPINUDP:
+				case UDP_ENCAP_ESPINUDP_NON_IKE:
+					up->encap_rcv = xfrm6_udp_encap_rcv;
+					/* FALLTHROUGH */
+				case UDP_ENCAP_L2TPINUDP:
+					up->encap_type = val;
+					break;
+				default:
+					err = -ENOPROTOOPT;
+					break;
+			}
+			break;
+
+			/*
+			 * 	UDP-Lite's partial checksum coverage (RFC 3828).
+			 */
+			/* The sender sets actual checksum coverage length via this option.
+			 * The case coverage > packet length is handled by send module. */
+		case UDPLITE_SEND_CSCOV:
+			if (!is_udplite)         /* Disable the option on UDP sockets */
+				return -ENOPROTOOPT;
+			if (val != 0 && val < 8) /* Illegal coverage: use default (8) */
+				val = 8;
+			else if (val > USHRT_MAX)
+				val = USHRT_MAX;
+			up->pcslen = val;
+			up->pcflag |= UDPLITE_SEND_CC;
+			break;
+
+			/* The receiver specifies a minimum checksum coverage value. To make
+			 * sense, this should be set to at least 8 (as done below). If zero is
+			 * used, this again means full checksum coverage.                     */
+		case UDPLITE_RECV_CSCOV:
+			if (!is_udplite)         /* Disable the option on UDP sockets */
+				return -ENOPROTOOPT;
+			if (val != 0 && val < 8) /* Avoid silly minimal values.       */
+				val = 8;
+			else if (val > USHRT_MAX)
+				val = USHRT_MAX;
+			up->pcrlen = val;
+			up->pcflag |= UDPLITE_RECV_CC;
+			break;
+
+		default:
+			err = -ENOPROTOOPT;
+			break;
+	}
+
+	return err;
+}
+
+EXPORT_SYMBOL(udp6_lib_setsockopt);
+
+
+/*
  *	Socket option code for UDP
  */
 int udpv6_setsockopt(struct sock *sk, int level, int optname,
-		     char __user *optval, unsigned int optlen)
+		char __user *optval, unsigned int optlen)
 {
 	if (level == SOL_UDP  ||  level == SOL_UDPLITE)
-		return udp_lib_setsockopt(sk, level, optname, optval, optlen,
-					  udp_v6_push_pending_frames);
+		return udp6_lib_setsockopt(sk, level, optname, optval, optlen,
+				udp_v6_push_pending_frames);
 	return ipv6_setsockopt(sk, level, optname, optval, optlen);
 }
 
 #ifdef CONFIG_COMPAT
 int compat_udpv6_setsockopt(struct sock *sk, int level, int optname,
-			    char __user *optval, unsigned int optlen)
+		char __user *optval, unsigned int optlen)
 {
 	if (level == SOL_UDP  ||  level == SOL_UDPLITE)
-		return udp_lib_setsockopt(sk, level, optname, optval, optlen,
-					  udp_v6_push_pending_frames);
+		return udp6_lib_setsockopt(sk, level, optname, optval, optlen,
+				udp_v6_push_pending_frames);
 	return compat_ipv6_setsockopt(sk, level, optname, optval, optlen);
 }
 #endif
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
index f8c3cf8..e23b7ef 100644
--- a/net/ipv6/xfrm6_input.c
+++ b/net/ipv6/xfrm6_input.c
@@ -21,6 +21,15 @@
 	return xfrm6_extract_header(skb);
 }
 
+int xfrm6_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
+		    int encap_type)
+{
+	XFRM_SPI_SKB_CB(skb)->family = AF_INET6;
+	XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr);
+	return xfrm_input(skb, nexthdr, spi, encap_type);
+}
+EXPORT_SYMBOL(xfrm6_rcv_encap);
+
 int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi)
 {
 	XFRM_SPI_SKB_CB(skb)->family = AF_INET6;
@@ -46,6 +55,106 @@
 		ip6_rcv_finish);
 	return -1;
 }
+/* If it's a keepalive packet, then just eat it.
+ * If it's an encapsulated packet, then pass it to the
+ * IPsec xfrm input.
+ * Returns 0 if skb passed to xfrm or was dropped.
+ * Returns >0 if skb should be passed to UDP.
+ * Returns <0 if skb should be resubmitted (-ret is protocol)
+ */
+int xfrm6_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
+{
+
+#ifndef CONFIG_XFRM
+	return 1;
+#else
+	struct udp_sock *up = udp_sk(sk);
+	struct udphdr *uh;
+	struct ipv6hdr *iph;
+	int iphlen, len;
+
+	__u8 *udpdata;
+	__be32 *udpdata32;
+	__u16 encap_type = up->encap_type;
+
+
+
+	/* if this is not encapsulated socket, then just return now */
+	if (!encap_type)
+		return 1;
+
+	/* If this is a paged skb, make sure we pull up
+	 * whatever data we need to look at. */
+	len = skb->len - sizeof(struct udphdr);
+	if (!pskb_may_pull(skb, sizeof(struct udphdr) + min(len, 8)))
+		return 1;
+
+	/* Now we can get the pointers */
+	uh = udp_hdr(skb);
+	udpdata = (__u8 *)uh + sizeof(struct udphdr);
+	udpdata32 = (__be32 *)udpdata;
+
+	switch (encap_type) {
+	default:
+	case UDP_ENCAP_ESPINUDP:
+		/* Check if this is a keepalive packet.  If so, eat it. */
+		if (len == 1 && udpdata[0] == 0xff) {
+			goto drop;
+		} else if (len > sizeof(struct ip_esp_hdr) && udpdata32[0] != 0) {
+			/* ESP Packet without Non-ESP header */
+			len = sizeof(struct udphdr);
+		} else
+			/* Must be an IKE packet.. pass it through */
+			return 1;
+		break;
+	case UDP_ENCAP_ESPINUDP_NON_IKE:
+		/* Check if this is a keepalive packet.  If so, eat it. */
+		if (len == 1 && udpdata[0] == 0xff) {
+			goto drop;
+		} else if (len > 2 * sizeof(u32) + sizeof(struct ip_esp_hdr) &&
+			   udpdata32[0] == 0 && udpdata32[1] == 0) {
+
+			/* ESP Packet with Non-IKE marker */
+			len = sizeof(struct udphdr) + 2 * (sizeof(u32) * 4);
+		} else
+			/* Must be an IKE packet.. pass it through */
+			return 1;
+		break;
+	}
+
+	/* At this point we are sure that this is an ESPinUDP packet,
+	 * so we need to remove 'len' bytes from the packet (the UDP
+	 * header and optional ESP marker bytes) and then modify the
+	 * protocol to ESP, and then call into the transform receiver.
+	 */
+	if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC)){
+		goto drop;
+	}
+
+	/* Now we can update and verify the packet length... */
+	iph = ipv6_hdr(skb);
+	iphlen = ntohs(iph->payload_len);
+	if (skb->len < iphlen) {
+		/* packet is too small!?! */
+		goto drop;
+	}
+
+	/* pull the data buffer up to the ESP header and set the
+	 * transport header to point to ESP.  Keep UDP on the stack
+	 * for later.
+	 */
+	__skb_pull(skb, len);
+	skb_reset_transport_header(skb);
+
+	/* process ESP */
+	return xfrm6_rcv_encap(skb, IPPROTO_ESP, 0, encap_type);
+
+drop:
+	kfree_skb(skb);
+	return 0;
+#endif
+}
+
 
 int xfrm6_rcv(struct sk_buff *skb)
 {
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index d879f7e..aa83e48 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -123,11 +123,17 @@
 {
 	struct flowi6 *fl6 = &fl->u.ip6;
 	int onlyproto = 0;
-	u16 offset = skb_network_header_len(skb);
-	const struct ipv6hdr *hdr = ipv6_hdr(skb);
+	/* use the reassembled packet if conntrack has done the reassembly */
+#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
+	struct sk_buff *whole_skb = (skb->nfct_reasm) ? skb->nfct_reasm : skb;
+#else
+	struct sk_buff *whole_skb = skb;
+#endif
+	u16 offset = skb_network_header_len(whole_skb);
+	const struct ipv6hdr *hdr = ipv6_hdr(whole_skb);
 	struct ipv6_opt_hdr *exthdr;
-	const unsigned char *nh = skb_network_header(skb);
-	u8 nexthdr = nh[IP6CB(skb)->nhoff];
+	const unsigned char *nh = skb_network_header(whole_skb);
+	u8 nexthdr = nh[IP6CB(whole_skb)->nhoff];
 
 	memset(fl6, 0, sizeof(struct flowi6));
 	fl6->flowi6_mark = skb->mark;
@@ -135,9 +141,9 @@
 	ipv6_addr_copy(&fl6->daddr, reverse ? &hdr->saddr : &hdr->daddr);
 	ipv6_addr_copy(&fl6->saddr, reverse ? &hdr->daddr : &hdr->saddr);
 
-	while (nh + offset + 1 < skb->data ||
-	       pskb_may_pull(skb, nh + offset + 1 - skb->data)) {
-		nh = skb_network_header(skb);
+	while (nh + offset + 1 < whole_skb->data ||
+		pskb_may_pull(whole_skb, nh + offset + 1 - whole_skb->data)) {
+		nh = skb_network_header(whole_skb);
 		exthdr = (struct ipv6_opt_hdr *)(nh + offset);
 
 		switch (nexthdr) {
@@ -156,8 +162,8 @@
 		case IPPROTO_TCP:
 		case IPPROTO_SCTP:
 		case IPPROTO_DCCP:
-			if (!onlyproto && (nh + offset + 4 < skb->data ||
-			     pskb_may_pull(skb, nh + offset + 4 - skb->data))) {
+			if (!onlyproto && (nh + offset + 4 < whole_skb->data ||
+			pskb_may_pull(whole_skb, nh + offset + 4 - whole_skb->data))) {
 				__be16 *ports = (__be16 *)exthdr;
 
 				fl6->fl6_sport = ports[!!reverse];
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 1e733e9..1a72eb2 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -30,8 +30,184 @@
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
 #include <net/xfrm.h>
+#include <net/netlink.h>
 
 #include <net/sock.h>
+#include <net/ip6_route.h>
+
+#if defined(CONFIG_INET_IPSEC_OFFLOAD)|| defined(CONFIG_INET6_IPSEC_OFFLOAD)
+#define NLKEY_SUPPORT 1
+#else 
+#undef NLKEY_SUPPORT
+#endif 
+
+#ifdef NLKEY_SUPPORT
+#include <net/dsfield.h>
+#include <net/inet_ecn.h>
+#include <net/ipv6.h>
+
+
+extern struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos,
+						xfrm_address_t *prev_saddr,
+						xfrm_address_t *prev_daddr,
+						int family);
+extern int xfrm_get_tos(struct flowi *fl, int family);
+extern int ipsec_nlkey_flow(u16 xfrm_nr, u16 *xfrm_handle, 
+		const struct flowi *fl, u16 family, u16 dir);
+
+
+#define	NLKEY_SA_CREATE		0x0A01
+#define NLKEY_SA_DELETE		0x0A02
+#define NLKEY_SA_FLUSH 		0x0A03
+#define NLKEY_SA_SET_KEYS	0x0A04
+#define NLKEY_SA_SET_TUNNEL	0x0A05
+#define NLKEY_SA_SET_NATT	0x0A06
+#define	NLKEY_SA_SET_STATE	0x0A07
+#define	NLKEY_SA_SET_LIFETIME	0x0A08
+#define	NLKEY_SA_NOTIFY		0x0A09
+#define NLKEY_SA_INFO_UPDATE	0x0A0C
+#define	NLKEY_FLOW_ADD		0x0A11
+#define NLKEY_FLOW_REMOVE	0x0A12
+#define NLKEY_FLOW_NOTIFY	0x0A13
+#define NLKEY_NULL_MSG		0x0000
+
+#define NLKEY_HDR_LEN		4
+#define NLKEY_MSG_LEN 		256
+
+#define NLKEY_MAX_NUM_KEYS	2
+#define NLKEY_MAX_KEY_LEN	(256 / 8)
+
+struct nlkey_msg {
+	/* message data */
+	unsigned short fcode;
+	unsigned short length;
+	unsigned short payload[(NLKEY_MSG_LEN /sizeof(unsigned short))];
+};
+/* sizeof(nlkey_msg) = 4 + 256 */
+
+struct nlkey_sa_id {
+	unsigned int spi;
+	unsigned char sa_type;
+	unsigned char proto_family;
+	unsigned char replay_window;
+#define NLKEY_SAFLAGS_ESN	0x1
+	unsigned char flags;
+	unsigned int dst_ip[4];
+	unsigned int src_ip[4];
+	unsigned short mtu;
+	unsigned short dev_mtu;
+
+};
+/* sizeof(nlkey_sa_id) = 24 */
+
+struct nlkey_sa_create {
+	unsigned short sagd;
+	unsigned short rsvd;
+	struct nlkey_sa_id said;
+};
+/* sizeof(nlkey_sa_delete) = 28 */
+
+struct nlkey_sa_delete {
+	unsigned short sagd;
+	unsigned short rsvd;
+};
+/* sizeof(nlkey_sa_delete) = 4 */
+
+struct nlkey_sa_set_tunnel {
+	unsigned short sagd;
+	unsigned char rsvd;
+	unsigned char proto_family;
+	union {
+		struct iphdr 	 ipv4h;
+		struct ipv6hdr ipv6h;
+	} h;
+};
+/* sizeof(nlkey_sa_set_tunnel) = 36 */
+
+struct nlkey_sa_set_natt {
+	unsigned short sagd;
+	unsigned short sport;
+	unsigned short dport;
+	unsigned short rsvd;
+};
+/* sizeof(nlkey_sa_set_natt) = 4 */
+
+struct nlkey_sa_set_state {
+	unsigned short sagd;
+	unsigned short rsvd;
+	unsigned short state;
+	unsigned short rsvd2;
+};
+/* sizeof(nlkey_sa_set_natt) = 8 */
+
+struct nlkey_key_desc {
+	unsigned short key_bits;
+	unsigned char key_alg;
+	unsigned char  key_type;
+	unsigned char key[NLKEY_MAX_KEY_LEN]; 
+};
+/* sizeof(nlkey_key_desc) =  36 */
+
+struct nlkey_sa_set_keys {
+	unsigned short sagd;
+	unsigned short rsvd;	
+	unsigned short num_keys;
+	unsigned short rsvd2;
+	struct nlkey_key_desc keys[NLKEY_MAX_NUM_KEYS];
+};
+/* sizeof(nlkey_sa_set_keys) =  80 */
+
+struct nlkey_lifetime_desc {
+	unsigned int allocations;
+	unsigned int bytes[2];
+};
+/* sizeof(nlkey_sa_set_lifetime) =  12 */
+
+struct nlkey_sa_set_lifetime {
+	unsigned short sagd;
+	unsigned short rsvd;
+	struct nlkey_lifetime_desc hard_time;
+	struct nlkey_lifetime_desc soft_time;
+	struct nlkey_lifetime_desc current_time;
+};
+/* sizeof(nlkey_sa_set_lifetime) =  40 */
+
+/* SA notifications */
+#define IPSEC_SOFT_EXPIRE 0
+#define IPSEC_HARD_EXPIRE 1
+
+struct nlkey_sa_notify {
+	unsigned short sagd;
+	unsigned short rsvd;
+	unsigned int  action;
+};
+/* sizeof(nlkey_sa_notify) = 8 */
+
+/* SA Info update */
+
+struct nlkey_sa_info {
+        unsigned short sagd;
+        unsigned short rsvd;
+        unsigned long long bytes;
+        unsigned long long packets;
+};
+/* sizeof(nlkey_sa_info) =  */
+
+
+static int ipsec_nlkey_send(struct net *net, struct xfrm_state *x, const struct km_event *c);
+static void ipsec_nlkey_rcv(struct sk_buff *skb);
+static void ipsec_nlkey_init(void);
+static unsigned short ipsec_sacode_to_nlkeycode(unsigned short sa_code);
+static struct sk_buff * ipsec_xfrm2nlkey (struct net *net, struct xfrm_state *x, 
+					const struct km_event *c, unsigned short *msg_id);
+static int ipsec_nlkey_set_said(struct net *net, struct xfrm_state *x, const struct km_event *c, struct nlkey_sa_id *said);
+
+/* netlink NETLINK_KEY socket */
+struct sock *nlkey_socket = NULL;
+
+#endif
+/************************************************************************************/
+
 
 #define _X2KEY(x) ((x) == XFRM_INF ? 0 : (x))
 #define _KEY2X(x) ((x) == 0 ? XFRM_INF : (x))
@@ -837,6 +1013,8 @@
 		sa->sadb_sa_flags |= SADB_SAFLAGS_DECAP_DSCP;
 	if (x->props.flags & XFRM_STATE_NOPMTUDISC)
 		sa->sadb_sa_flags |= SADB_SAFLAGS_NOPMTUDISC;
+	if (x->props.flags & XFRM_STATE_ESN)
+		sa->sadb_sa_flags |= SADB_SAFLAGS_ESN;
 
 	/* hard time */
 	if (hsc & 2) {
@@ -1104,6 +1282,8 @@
 		x->props.flags |= XFRM_STATE_DECAP_DSCP;
 	if (sa->sadb_sa_flags & SADB_SAFLAGS_NOPMTUDISC)
 		x->props.flags |= XFRM_STATE_NOPMTUDISC;
+	if (sa->sadb_sa_flags & SADB_SAFLAGS_ESN)
+		x->props.flags |= XFRM_STATE_ESN;
 
 	lifetime = ext_hdrs[SADB_EXT_LIFETIME_HARD - 1];
 	if (lifetime != NULL) {
@@ -2959,6 +3139,7 @@
 	out_hdr->sadb_msg_pid = 0;
 
 	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL, xs_net(x));
+
 	return 0;
 }
 
@@ -2967,6 +3148,12 @@
 	struct net *net = x ? xs_net(x) : c->net;
 	struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
 
+
+#ifdef NLKEY_SUPPORT
+	/* send message to the user space through NETLINK_KEY socket*/
+	ipsec_nlkey_send(net, x, c);
+#endif
+
 	if (atomic_read(&net_pfkey->socks_nr) == 0)
 		return 0;
 
@@ -3748,6 +3935,593 @@
 	.migrate	= pfkey_send_migrate,
 };
 
+
+#ifdef NLKEY_SUPPORT
+extern struct xfrm_state *xfrm_state_lookup_byhandle(struct net *net, u16 handle);
+
+static unsigned short ipsec_sacode_to_nlkeycode(unsigned short sa_code)
+{
+	unsigned nlkey_code;
+
+	switch (sa_code) 
+	{
+		case XFRM_MSG_DELSA:
+			nlkey_code = NLKEY_SA_DELETE;
+			break;
+		case XFRM_MSG_NEWSA:
+		case XFRM_MSG_UPDSA:
+			nlkey_code = NLKEY_SA_CREATE;
+			break;
+		case XFRM_MSG_FLUSHSA:
+			nlkey_code = NLKEY_SA_FLUSH;
+			break;
+		case XFRM_MSG_EXPIRE:
+			nlkey_code = NLKEY_SA_SET_STATE;
+			break;
+		default:
+			nlkey_code = NLKEY_NULL_MSG;
+			break;
+	}
+
+	return nlkey_code;
+}
+
+static void ipsec_nlkey_rcv(struct sk_buff *skb)
+{
+	struct nlmsghdr *nlh = NULL;
+	struct nlkey_msg *msg = NULL;
+	struct flowi flow;
+	unsigned short *p;
+	unsigned short family, dir;
+	struct xfrm_state *x;
+	struct nlkey_sa_notify sa_notify_msg;
+	struct nlkey_sa_info sa_info_msg;
+
+	/* extract message from skb */
+	nlh = (struct nlmsghdr *)skb->data;
+
+	msg = (struct nlkey_msg *)NLMSG_DATA(nlh);
+
+	//printk(KERN_INFO "ipsec_nlkey_rcv fcode: 0x%x length: %d bytes\n",msg->fcode,msg->length);
+
+	/* process command received from user space */
+	switch(msg->fcode)
+	{
+		case NLKEY_FLOW_REMOVE:
+			//printk(KERN_INFO "ipsec_nlkey_rcv NLKEY_FLOW_REMOVE\n");
+			p = msg->payload;
+			memcpy(&flow, p, sizeof(struct flowi)); p += sizeof(struct flowi)/2;
+			family = *p; p++;
+			dir = *p; p++;
+			flow_cache_remove(&flow, family, dir);
+			break;
+
+		case NLKEY_SA_NOTIFY:
+			//printk(KERN_INFO "ipsec_nlkey_rcv NLKEY_SA_NOTIFY\n");
+			memcpy(&sa_notify_msg, msg->payload, sizeof(struct nlkey_sa_notify));
+			x = xfrm_state_lookup_byhandle(&init_net, sa_notify_msg.sagd);
+			if (x) {
+				spin_lock(&x->lock);
+
+				if (sa_notify_msg.action) { 
+					// hard expired
+					x->km.state = XFRM_STATE_EXPIRED;
+					tasklet_hrtimer_start(&x->mtimer, ktime_set(0,0), HRTIMER_MODE_REL);
+				}
+				else if (!x->km.dying) {
+					 x->km.dying = 1;
+					 km_state_expired(x, 0, 0);
+				}
+
+				spin_unlock(&x->lock);
+				xfrm_state_put(x);
+			}
+			break;
+
+		case NLKEY_SA_INFO_UPDATE:
+			memcpy(&sa_info_msg, msg->payload, sizeof(struct nlkey_sa_info));
+
+			x = xfrm_state_lookup_byhandle(&init_net,sa_info_msg.sagd);
+			if (x) {
+				spin_lock(&x->lock);
+
+				x->curlft.bytes = sa_info_msg.bytes;
+				x->curlft.packets = sa_info_msg.packets;
+
+				spin_unlock(&x->lock);
+				xfrm_state_put(x);
+			}
+			break;
+		default:
+			//printk(KERN_INFO "ipsec_nlkey_rcv fcode 0x%x not supported\n", msg->fcode);
+			break;
+	}
+
+}
+
+extern struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos,
+						  xfrm_address_t *saddr,
+						  xfrm_address_t *daddr,
+						  int family);
+static int ipsec_nlkey_set_said(struct net *net, struct xfrm_state *x, 
+				const struct km_event *c, struct nlkey_sa_id *said)
+{
+
+	struct flowi fl;
+	int tos;
+	xfrm_address_t saddr, daddr;
+	struct dst_entry *dst;
+	int rc = 0;
+
+	memset(&fl, 0, sizeof(struct flowi));
+
+	/* SPI */
+	said->spi = x->id.spi;
+	/* SA Type (AH or ESP) */
+	said->sa_type = x->id.proto;
+	/* Protocol Family (IPv4 or IPv6) */
+	said->proto_family = x->props.family;
+	/* Replay window */
+	said->replay_window = x->props.replay_window;
+	/* Destination IP Address */
+	if(x->props.family == AF_INET6) {
+		memcpy(&said->dst_ip, x->id.daddr.a6, sizeof(struct in6_addr));
+		ipv6_addr_copy(&fl.u.ip6.daddr, (struct in6_addr *)x->id.daddr.a6);
+		memcpy(&said->src_ip, x->props.saddr.a6, sizeof(struct in6_addr));
+	}
+	else {
+		said->dst_ip[0] = x->id.daddr.a4;
+		fl.u.ip4.daddr = x->id.daddr.a4;
+		said->src_ip[0] = x->props.saddr.a4;
+	}
+	said->mtu = 0;
+
+	if(x->props.flags & XFRM_STATE_ESN)
+		said->flags = NLKEY_SAFLAGS_ESN;
+	xfrm_flowi_addr_get(&fl, &saddr, &daddr, x->props.family);
+
+	tos = xfrm_get_tos(&fl, x->props.family);
+	if (tos < 0) {
+		printk(KERN_ERR "%s:%d: FIXME\n",__FUNCTION__,__LINE__);	
+		rc = -1;
+		goto error;
+	}
+	
+	dst = __xfrm_dst_lookup(net, tos, NULL, &daddr, x->props.family);
+	if (IS_ERR(dst)) {
+		printk(KERN_ERR "%s:%d: FIXME\n",__FUNCTION__,__LINE__);
+		rc = -1;
+		goto error;
+	}
+	said->dev_mtu = dst_mtu(dst);
+	said->mtu = xfrm_state_mtu(x,dst_mtu(dst));	
+
+	dst_release(dst);
+error:
+	return rc;
+}
+
+static struct sk_buff * ipsec_xfrm2nlkey (struct net *net, struct xfrm_state *x, 
+					const struct km_event *c, unsigned short *msg_id)
+{
+	struct nlkey_sa_id sa_id_msg;
+	struct nlkey_sa_create sa_create_msg;
+	struct nlkey_sa_delete sa_delete_msg;
+	struct nlkey_sa_set_keys sa_set_keys_msg;
+	struct nlkey_sa_set_tunnel sa_set_tunnel_msg;
+	struct nlkey_sa_set_natt sa_set_natt_msg;
+	struct nlkey_sa_set_state sa_set_state_msg;
+	struct nlkey_sa_set_lifetime sa_set_lifetime_msg;
+	struct nlkey_msg msg;
+	struct sk_buff *skb = NULL;
+	struct nlmsghdr *nlh = NULL;
+	gfp_t allocation = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
+	unsigned char tunnel, keys, natt, state, lifetime;
+
+	/* supported SA informations */
+	keys = 1; state = 1; tunnel = 1; lifetime = 1; natt = 1; 
+
+	/* next message to build */
+	memset(&msg, 0, sizeof(struct nlkey_msg));
+	msg.fcode = *msg_id;
+	
+	//printk(KERN_INFO "\n\nipsec_xfrm2nlkey: processing event 0x%x\n", msg.fcode);
+
+	switch (msg.fcode)
+	{
+		case NLKEY_SA_CREATE:
+			//printk(KERN_INFO "ipsec_xfrm2nlkey: NLKEY_SA_CREATE\n");
+			if(x) {
+				/* some check before builing message */
+				if((x->id.proto != IPPROTO_ESP) && (x->id.proto != IPPROTO_AH)) {
+					printk(KERN_ERR "ipsec_xfrm2nlkey: protocol %d not supported\n", x->id.proto);
+					*msg_id = NLKEY_NULL_MSG;
+					goto exit;
+				}	
+				memset(&sa_create_msg, 0, sizeof(struct nlkey_sa_create));	
+
+				/* SA global handler */
+				sa_create_msg.sagd = x->handle;
+
+				/* SA identifier */
+				if(ipsec_nlkey_set_said(net, x, c, &sa_create_msg.said) < 0)
+				{
+					printk(KERN_ERR "%s: set sa ID failed\n", __func__);
+					*msg_id = NLKEY_NULL_MSG; /* next message */
+					goto exit;
+				}
+				memcpy(msg.payload, &sa_create_msg, sizeof(struct nlkey_sa_create));
+				msg.length = sizeof(struct nlkey_sa_create);
+				*msg_id = NLKEY_SA_SET_KEYS; /* next message */
+			} else {
+				*msg_id = NLKEY_NULL_MSG; /* next message */
+				goto exit;
+			}
+			
+			break;
+
+		case NLKEY_SA_SET_KEYS:
+			//printk(KERN_INFO "ipsec_xfrm2nlkey: NLKEY_SA_SET_KEYS\n");
+			if(keys) {
+				memset(&sa_set_keys_msg, 0, sizeof(struct nlkey_sa_set_keys));
+
+				/* SA global handler */
+				sa_set_keys_msg.sagd = x->handle; 
+				
+				/* auth key */
+				if(x->aalg) {
+					if (x->aalg->alg_key_len) {
+						sa_set_keys_msg.keys[sa_set_keys_msg.num_keys].key_bits = x->aalg->alg_key_len;
+						sa_set_keys_msg.keys[sa_set_keys_msg.num_keys].key_alg = x->props.aalgo;
+						sa_set_keys_msg.keys[sa_set_keys_msg.num_keys].key_type = 0;
+						memcpy(sa_set_keys_msg.keys[sa_set_keys_msg.num_keys].key, x->aalg->alg_key,(sa_set_keys_msg.keys[sa_set_keys_msg.num_keys].key_bits / 8));
+						//printk(KERN_INFO "ipsec_xfrm2nlkey: AUTH - algo %d key %d bits\n", sa_set_keys_msg.keys[sa_set_keys_msg.num_keys].key_alg, sa_set_keys_msg.keys[sa_set_keys_msg.num_keys].key_bits);
+						sa_set_keys_msg.num_keys++;
+					}
+				}
+				/* encrypt key */
+				if(x->ealg) {
+					if (x->ealg->alg_key_len) {
+
+						sa_set_keys_msg.keys[sa_set_keys_msg.num_keys].key_bits = x->ealg->alg_key_len;
+						sa_set_keys_msg.keys[sa_set_keys_msg.num_keys].key_alg = x->props.ealgo;
+						sa_set_keys_msg.keys[sa_set_keys_msg.num_keys].key_type = 1;
+						memcpy(sa_set_keys_msg.keys[sa_set_keys_msg.num_keys].key, x->ealg->alg_key,(sa_set_keys_msg.keys[sa_set_keys_msg.num_keys].key_bits / 8));
+						//printk(KERN_INFO "ipsec_xfrm2nlkey: ENCRYPT - algo %d key %d bits\n", sa_set_keys_msg.keys[sa_set_keys_msg.num_keys].key_alg, sa_set_keys_msg.keys[sa_set_keys_msg.num_keys].key_bits);
+						sa_set_keys_msg.num_keys++;
+					}
+				}
+				memcpy(msg.payload, &sa_set_keys_msg, sizeof(struct nlkey_sa_set_keys));
+				msg.length = sizeof(struct nlkey_sa_set_keys);
+				*msg_id = NLKEY_SA_SET_TUNNEL; /* next message */
+			} else {
+				*msg_id = NLKEY_SA_SET_TUNNEL; /* next message */
+				goto exit;
+			}
+			break;
+
+		case NLKEY_SA_SET_TUNNEL:
+			//printk(KERN_INFO "ipsec_xfrm2nlkey: NLKEY_SA_SET_TUNNEL\n");
+			if(tunnel && (x->props.mode == XFRM_MODE_TUNNEL)) {
+				memset(&sa_set_tunnel_msg, 0, sizeof(struct nlkey_sa_set_tunnel));
+
+				/* SA global handler */
+				sa_set_tunnel_msg.sagd = x->handle; 
+
+				/* Tunnel */
+				sa_set_tunnel_msg.proto_family = x->props.family;
+				if(x->props.family == AF_INET6) {
+					struct ipv6hdr *top_iph = &sa_set_tunnel_msg.h.ipv6h;
+					int dsfield;
+					top_iph->version = 6;
+					top_iph->priority = 0;
+					top_iph->flow_lbl[0] = 0;
+					top_iph->flow_lbl[1] = 0;
+					top_iph->flow_lbl[2] = 0;
+					top_iph->nexthdr = IPPROTO_IPIP;	
+					dsfield = ipv6_get_dsfield(top_iph);
+					dsfield = INET_ECN_encapsulate(dsfield, dsfield);
+					if (x->props.flags & XFRM_STATE_NOECN)
+						dsfield &= ~INET_ECN_MASK;
+					ipv6_change_dsfield(top_iph, 0, dsfield);
+					top_iph->hop_limit = 64;
+					memcpy(&top_iph->daddr, x->id.daddr.a6, sizeof(struct in6_addr));
+					memcpy(&top_iph->saddr, x->props.saddr.a6, sizeof(struct in6_addr));
+					//printk(KERN_INFO "ipsec_xfrm2nlkey: IPv6 tunnel\n");
+					//printk(KERN_INFO "dst: %x %x %x %x\n", x->id.daddr.a6[0], x->id.daddr.a6[1], x->id.daddr.a6[2], x->id.daddr.a6[3]);
+					//(KERN_INFO "src: %x %x %x %x\n", x->props.saddr.a6[0], x->props.saddr.a6[1], x->props.saddr.a6[2], x->props.saddr.a6[3]);
+				}
+				else {
+					struct iphdr *top_iph = &sa_set_tunnel_msg.h.ipv4h;
+					top_iph->ihl = 5;
+					top_iph->version = 4;
+					top_iph->tos = 0;
+					top_iph->frag_off = 0; 
+					top_iph->ttl = 64;
+					top_iph->saddr = x->props.saddr.a4;
+					top_iph->daddr = x->id.daddr.a4;
+					//printk(KERN_INFO "ipsec_xfrm2nlkey: IPv4 tunnel dst:%x - src:%x \n", x->id.daddr.a4, x->props.saddr.a4);
+				}
+				memcpy(msg.payload, &sa_set_tunnel_msg, sizeof(struct nlkey_sa_set_tunnel));
+				msg.length = sizeof(struct nlkey_sa_set_tunnel);
+				*msg_id = NLKEY_SA_SET_NATT; /* next message */
+			} else {
+				*msg_id = NLKEY_SA_SET_NATT; /* next message */
+				goto exit;	
+			} 
+			break;
+
+		case NLKEY_SA_SET_NATT:
+			//printk(KERN_INFO "ipsec_xfrm2nlkey: NLKEY_SA_SET_NATT\n");
+			if((natt) && (x->encap)){
+				memset(&sa_set_natt_msg, 0, sizeof(struct nlkey_sa_set_natt));
+
+				/* SA global handler */
+				sa_set_natt_msg.sagd = x->handle; 
+				sa_set_natt_msg.sport = x->encap->encap_sport;
+				sa_set_natt_msg.dport = x->encap->encap_dport;
+				//printk(KERN_INFO "src port: %d  dst port: %d \n", ntohs(sa_set_natt_msg.sport), ntohs( sa_set_natt_msg.dport));
+				memcpy(msg.payload, &sa_set_natt_msg, sizeof(struct nlkey_sa_set_natt));
+				msg.length = sizeof(struct nlkey_sa_set_natt);
+				*msg_id = NLKEY_SA_SET_LIFETIME; /* next message */
+			} else {
+				*msg_id = NLKEY_SA_SET_LIFETIME; /* next message */
+				goto exit;	
+			}
+			break;
+
+		case NLKEY_SA_SET_LIFETIME:
+			//printk(KERN_INFO "ipsec_xfrm2nlkey: NLKEY_SA_SET_LIFETIME\n");
+			if(lifetime) {
+				memset(&sa_set_lifetime_msg, 0, sizeof(struct nlkey_sa_set_lifetime));
+
+				/* SA global handler */
+				sa_set_lifetime_msg.sagd = x->handle;
+
+				/* hard time */
+				sa_set_lifetime_msg.hard_time.allocations =  _X2KEY(x->lft.hard_packet_limit);
+				if(_X2KEY(x->lft.hard_byte_limit))
+					memcpy(sa_set_lifetime_msg.hard_time.bytes, &x->lft.hard_byte_limit, sizeof(uint64_t));
+
+				/* soft time */
+				sa_set_lifetime_msg.soft_time.allocations =  _X2KEY(x->lft.soft_packet_limit);
+				if(_X2KEY(x->lft.soft_byte_limit))
+					memcpy(sa_set_lifetime_msg.soft_time.bytes, &x->lft.soft_byte_limit, sizeof(uint64_t));
+
+				/* current time */
+				sa_set_lifetime_msg.current_time.allocations = x->curlft.packets;
+				memcpy(sa_set_lifetime_msg.current_time.bytes, &x->curlft.bytes, sizeof(uint64_t));
+
+				memcpy(msg.payload, &sa_set_lifetime_msg, sizeof(struct nlkey_sa_set_lifetime));
+				msg.length = sizeof(struct nlkey_sa_set_lifetime);
+				*msg_id = NLKEY_SA_SET_STATE; /* next message */
+			} else {
+				*msg_id = NLKEY_SA_SET_STATE; /* next message */
+				goto exit;	
+			}
+			break;
+
+		case NLKEY_SA_SET_STATE:
+			//printk(KERN_INFO "ipsec_xfrm2nlkey: NLKEY_SET_STATE\n");
+			if(state) {
+				memset(&sa_set_state_msg, 0, sizeof(struct nlkey_sa_set_state));
+				memset(&sa_id_msg, 0, sizeof(struct nlkey_sa_id));
+
+				/* SA global handler */
+				sa_set_state_msg.sagd = x->handle; 
+				/* State */
+				sa_set_state_msg.state = x->km.state;
+				// TODO: set the offloaded state once ack received !
+				x->offloaded = 1;
+				atomic_inc(&flow_cache_genid);
+
+				memcpy(msg.payload, &sa_set_state_msg, sizeof(struct nlkey_sa_set_state));
+				msg.length = sizeof(struct nlkey_sa_set_state);
+				*msg_id = NLKEY_NULL_MSG; /* next message */
+			} else {
+				*msg_id = NLKEY_NULL_MSG; /* next message */
+				goto exit;
+			}
+			break;
+		
+		case NLKEY_SA_DELETE:
+			//printk(KERN_INFO "ipsec_xfrm2nlkey: NLKEY_SA_DELETE\n");
+			memset(&sa_delete_msg, 0, sizeof(struct nlkey_sa_delete));
+			
+			/* SA global handler */
+			sa_delete_msg.sagd = x->handle;
+			memcpy(msg.payload, &sa_delete_msg, sizeof(struct nlkey_sa_delete));
+			msg.length = sizeof(struct nlkey_sa_delete);
+			atomic_inc(&flow_cache_genid);
+
+
+			*msg_id = NLKEY_NULL_MSG; /* next message */
+			break;
+
+		case NLKEY_SA_FLUSH:
+			//printk(KERN_INFO "ipsec_xfrm2nlkey: NLKEY_SA_FLUSH\n");
+			/* No data required for flush SA command */
+			atomic_inc(&flow_cache_genid);
+
+			*msg_id = NLKEY_NULL_MSG; /* next message */
+			break;
+
+		default:
+			printk(KERN_ERR "ipsec_xfrm2nlkey: event 0x%x not supported\n", c->event);
+			*msg_id = NLKEY_NULL_MSG; /* next message */
+			break;
+	}
+
+	/* prepare netlink message for kernel to user space direction */
+	if(msg.length > NLKEY_MSG_LEN)
+	{
+		printk(KERN_ERR "ipsec_xfrm2nlkey: maximum message size reached (%d bytes)\n", msg.length);
+		goto exit;
+	}
+
+	skb = alloc_skb(NLMSG_SPACE(NLKEY_MSG_LEN + NLKEY_HDR_LEN), allocation);
+	if (skb == NULL)
+		goto exit;
+		
+	nlh = (struct nlmsghdr *)skb_put(skb, NLMSG_SPACE(NLKEY_HDR_LEN + msg.length));
+	memcpy(NLMSG_DATA(nlh), (unsigned char *)&msg, (NLKEY_HDR_LEN + msg.length));
+	
+	/* whole length of the message i.e. header + payload */
+	nlh->nlmsg_len = NLMSG_SPACE(NLKEY_HDR_LEN + msg.length);
+
+	/* from kernel */
+	nlh->nlmsg_pid = 0;
+	nlh->nlmsg_flags = 0;
+        nlh->nlmsg_type = 0;
+	NETLINK_CB(skb).pid = 0;
+	NETLINK_CB(skb).dst_group = 1;
+exit:
+	return skb;
+}
+
+static int ipsec_nlkey_send(struct net *net, struct xfrm_state *x, const struct km_event *c)
+{
+	struct sk_buff *skb;
+	unsigned short msg_type;
+	int rc = 0;
+
+	/* We may generate more than one message when adding new SA (sa_create + sa_set_state + sa_set_tunnel...) */
+	msg_type = ipsec_sacode_to_nlkeycode((unsigned short)c->event);
+
+	while(msg_type != NLKEY_NULL_MSG)
+	{
+		/* build nlkey message */
+		skb = ipsec_xfrm2nlkey(net, x, c, &msg_type);
+
+		if(skb != NULL)
+			if((rc = netlink_broadcast(nlkey_socket, skb, 0, 1, GFP_ATOMIC)) < 0)
+				return rc;
+	}
+
+	return rc;
+}
+
+
+int ipsec_nlkey_flow(u16 xfrm_nr, u16 *xfrm_handle, const struct flowi *fl, u16 family, u16 dir)
+{
+	struct sk_buff *skb;
+	struct nlkey_msg msg;
+	struct nlmsghdr *nlh = NULL;
+	unsigned short *p;
+	gfp_t allocation = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
+
+	//printk(KERN_INFO "ipsec_nlkey_flow \n");
+
+	/* next message to build */
+	memset(&msg, 0, sizeof(struct nlkey_msg));
+	msg.fcode = NLKEY_FLOW_ADD;
+
+	// Number of SA for this flow
+	p = msg.payload;
+	*p++ = xfrm_nr;
+	msg.length += sizeof(unsigned short);
+	// SA handles list
+	memcpy(p, xfrm_handle, xfrm_nr*sizeof(unsigned short));
+	msg.length += xfrm_nr*sizeof(unsigned short);
+	p+=xfrm_nr;
+	// flow family
+	*p++ = family;
+	msg.length += sizeof(unsigned short);
+	// flow family
+	*p++ = dir;
+	msg.length += sizeof(unsigned short);
+	// flow descriptor
+	memcpy(p, fl, sizeof(struct flowi));
+	msg.length +=sizeof(struct flowi);
+	p+=sizeof(struct flowi) / sizeof(u16);
+
+	skb = alloc_skb(NLMSG_SPACE(NLKEY_MSG_LEN + NLKEY_HDR_LEN), allocation);
+	if (skb == NULL)
+		return -ENOMEM;
+
+	/* prepare netlink message for kernel to user space direction */
+	nlh = (struct nlmsghdr *)skb_put(skb, NLMSG_SPACE(NLKEY_HDR_LEN + msg.length));
+	memcpy(NLMSG_DATA(nlh), (unsigned char *)&msg, (NLKEY_HDR_LEN + msg.length));
+
+	/* whole length of the message i.e. header + payload */
+	nlh->nlmsg_len = NLMSG_SPACE(NLKEY_HDR_LEN + msg.length);
+
+	/* from kernel */
+	nlh->nlmsg_pid = 0; 
+	nlh->nlmsg_flags = 0;
+        nlh->nlmsg_type = 0;
+	NETLINK_CB(skb).pid = 0;
+	NETLINK_CB(skb).dst_group = 1;
+
+	return(netlink_broadcast(nlkey_socket, skb, 0, 1, allocation));
+}
+EXPORT_SYMBOL(ipsec_nlkey_flow);
+
+
+int ipsec_nlkey_flow_remove(struct flowi *fl, u16 family, u16 dir)
+{
+	struct sk_buff *skb;
+	struct nlkey_msg msg;
+	struct nlmsghdr *nlh = NULL;
+	unsigned short *p;
+	gfp_t allocation = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
+
+	
+	//printk(KERN_INFO "ipsec_nlkey_flow_remove\n");
+
+	/* next message to build */
+	memset(&msg, 0, sizeof(struct nlkey_msg));
+	msg.fcode = NLKEY_FLOW_REMOVE;
+
+	p = msg.payload;
+	// flow family
+	*p++ = family;
+	msg.length += sizeof(unsigned short);
+	// flow family
+	*p++ = dir;
+	msg.length += sizeof(unsigned short);
+	// flow descriptor
+	memcpy(p, fl, sizeof(struct flowi));
+	msg.length +=sizeof(struct flowi);
+	p+=sizeof(struct flowi) / sizeof(u16);
+
+	skb = alloc_skb(NLMSG_SPACE(NLKEY_MSG_LEN + NLKEY_HDR_LEN), allocation);
+	if (skb == NULL)
+		return -ENOMEM;
+
+	/* prepare netlink message for kernel to user space direction */
+	nlh = (struct nlmsghdr *)skb_put(skb, NLMSG_SPACE(NLKEY_HDR_LEN + msg.length));
+	memcpy(NLMSG_DATA(nlh), (unsigned char *)&msg, (NLKEY_HDR_LEN + msg.length));
+	
+	/* whole length of the message i.e. header + payload */
+	nlh->nlmsg_len = NLMSG_SPACE(NLKEY_HDR_LEN + msg.length);
+
+	/* from kernel */
+	nlh->nlmsg_pid = 0; 
+	nlh->nlmsg_flags = 0;
+        nlh->nlmsg_type = 0;
+	NETLINK_CB(skb).pid = 0;
+	NETLINK_CB(skb).dst_group = 1;	
+
+		
+        return(netlink_broadcast(nlkey_socket, skb, 0, 1, allocation));
+
+	
+}
+EXPORT_SYMBOL(ipsec_nlkey_flow_remove);
+
+
+
+static void ipsec_nlkey_init(void)
+{
+	printk(KERN_INFO "Initializing NETLINK_KEY socket\n");
+
+	nlkey_socket = netlink_kernel_create(&init_net, NETLINK_KEY, 1,
+				     ipsec_nlkey_rcv, NULL, THIS_MODULE);
+}
+#endif
+
+
 static int __net_init pfkey_net_init(struct net *net)
 {
 	struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
@@ -3782,6 +4556,11 @@
 	sock_unregister(PF_KEY);
 	unregister_pernet_subsys(&pfkey_net_ops);
 	proto_unregister(&key_proto);
+
+#ifdef NLKEY_SUPPORT
+	/* release NETLINK_KEY socket */
+	sock_release(nlkey_socket->sk_socket);
+#endif
 }
 
 static int __init ipsec_pfkey_init(void)
@@ -3800,6 +4579,12 @@
 	err = xfrm_register_km(&pfkeyv2_mgr);
 	if (err != 0)
 		goto out_sock_unregister;
+
+#ifdef NLKEY_SUPPORT
+	/* create NETLINK_KEY socket for IPSec offload on Comcerto */
+	ipsec_nlkey_init();
+#endif
+
 out:
 	return err;
 
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index 89ff8c6..7501b22 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -1253,11 +1253,10 @@
 	/* Remove from tunnel list */
 	spin_lock_bh(&pn->l2tp_tunnel_list_lock);
 	list_del_rcu(&tunnel->list);
+	kfree_rcu(tunnel, rcu);
 	spin_unlock_bh(&pn->l2tp_tunnel_list_lock);
-	synchronize_rcu();
 
 	atomic_dec(&l2tp_tunnel_count);
-	kfree(tunnel);
 }
 
 /* Create a socket for the tunnel, if one isn't set up by
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h
index a16a48e..4393794 100644
--- a/net/l2tp/l2tp_core.h
+++ b/net/l2tp/l2tp_core.h
@@ -157,6 +157,7 @@
 
 struct l2tp_tunnel {
 	int			magic;		/* Should be L2TP_TUNNEL_MAGIC */
+	struct rcu_head rcu;
 	rwlock_t		hlist_lock;	/* protect session_hlist */
 	struct hlist_head	session_hlist[L2TP_HASH_SIZE];
 						/* hashed list of sessions,
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 0427cbd..e1e1ced 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -6,6 +6,8 @@
 
 obj-$(CONFIG_NETFILTER) = netfilter.o
 
+obj-$(CONFIG_COMCERTO_FP) += comcerto_fp_netfilter.o
+
 obj-$(CONFIG_NETFILTER_NETLINK) += nfnetlink.o
 obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o
 obj-$(CONFIG_NETFILTER_NETLINK_LOG) += nfnetlink_log.o
diff --git a/net/netfilter/comcerto_fp_netfilter.c b/net/netfilter/comcerto_fp_netfilter.c
new file mode 100644
index 0000000..bc6ef68
--- /dev/null
+++ b/net/netfilter/comcerto_fp_netfilter.c
@@ -0,0 +1,137 @@
+/*
+ *  linux/drivers/net/comcerto/fp_netfilter.c
+ *
+ *  Copyright (C) 2010 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter.h>
+#include <net/netfilter/nf_conntrack.h>
+
+static unsigned int fp_netfilter_pre_routing(int family, unsigned int hooknum, struct sk_buff *skb)
+{
+	struct nf_conn *ct;
+	u_int8_t protonum;
+	enum ip_conntrack_info ctinfo;
+	struct comcerto_fp_info *fp_info;
+	int dir;
+
+	ct = nf_ct_get(skb, &ctinfo);
+	if (!ct)
+		goto done;
+
+	protonum = nf_ct_protonum(ct);
+	if ((protonum != IPPROTO_TCP) && (protonum != IPPROTO_UDP) && (protonum != IPPROTO_IPIP))
+		goto done;
+
+	dir = CTINFO2DIR(ctinfo);
+
+//	if (printk_ratelimit())
+//		printk(KERN_INFO "ct: %lx, dir: %x, mark: %x, ifindex: %d iif: %d\n", (unsigned long)ct, dir, skb->mark, skb->dev->ifindex, skb->skb_iif);
+
+	/* We could also check for changes and notify userspace (or print message) */
+	if (dir == IP_CT_DIR_ORIGINAL) {
+		fp_info = &ct->fp_info[IP_CT_DIR_ORIGINAL];
+	} else {
+		fp_info = &ct->fp_info[IP_CT_DIR_REPLY];
+	}
+
+	if (fp_info->mark && (fp_info->mark != skb->mark))
+		if (printk_ratelimit())
+			printk(KERN_INFO "ct: mark changed %x, %x\n", fp_info->mark, skb->mark);
+
+	if (fp_info->ifindex && (fp_info->ifindex != skb->dev->ifindex))
+		if (printk_ratelimit())
+			printk(KERN_INFO "ct: ifindex changed %d, %d\n", fp_info->ifindex, skb->dev->ifindex);
+
+	if (fp_info->iif && (fp_info->iif != skb->skb_iif))
+		if (printk_ratelimit())
+			printk(KERN_INFO "ct: iif changed %d, %d\n", fp_info->iif, skb->skb_iif);
+
+	fp_info->mark = skb->mark;
+	fp_info->ifindex = skb->dev->ifindex;
+	fp_info->iif = skb->skb_iif;
+
+done:
+	return NF_ACCEPT;
+}
+
+static unsigned int fp_ipv4_netfilter_pre_routing(unsigned int hooknum,
+                                      struct sk_buff *skb,
+                                      const struct net_device *in,
+                                      const struct net_device *out,
+                                      int (*okfn)(struct sk_buff *))
+{
+
+	return fp_netfilter_pre_routing(PF_INET, hooknum, skb);
+}
+
+static unsigned int fp_ipv6_netfilter_pre_routing(unsigned int hooknum,
+                                      struct sk_buff *skb,
+                                      const struct net_device *in,
+                                      const struct net_device *out,
+                                      int (*okfn)(struct sk_buff *))
+{
+
+	return fp_netfilter_pre_routing(PF_INET6, hooknum, skb);
+}
+
+
+static struct nf_hook_ops fp_netfilter_ops[] __read_mostly = {
+	{
+		.hook		= fp_ipv4_netfilter_pre_routing,
+		.owner		= THIS_MODULE,
+		.pf		= NFPROTO_IPV4,
+		.hooknum	= NF_INET_PRE_ROUTING,
+		.priority	= NF_IP_PRI_LAST,
+	},
+	{
+		.hook		= fp_ipv6_netfilter_pre_routing,
+		.owner		= THIS_MODULE,
+		.pf		= NFPROTO_IPV6,
+		.hooknum	= NF_INET_PRE_ROUTING,
+		.priority	= NF_IP_PRI_LAST,
+	},
+};
+
+static int __init fp_netfilter_init(void)
+{
+	int rc;
+
+	rc = nf_register_hooks(fp_netfilter_ops, ARRAY_SIZE(fp_netfilter_ops));
+	if (rc < 0) {
+		printk(KERN_ERR "fp_netfilter_ops: can't register hooks.\n");
+		goto err0;
+	}
+
+	return 0;
+
+err0:
+	return rc;
+}
+
+
+static void __exit fp_netfilter_exit(void)
+{
+	nf_unregister_hooks(fp_netfilter_ops, ARRAY_SIZE(fp_netfilter_ops));
+}
+
+module_init(fp_netfilter_init);
+module_exit(fp_netfilter_exit);
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 884e227..3d3622ac 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -255,12 +255,15 @@
 {
 	struct nf_conn *ct = (void *)ul_conntrack;
 	struct net *net = nf_ct_net(ct);
+	struct nf_conntrack_ecache *ecache = nf_ct_ecache_find(ct);
+
+	BUG_ON(ecache == NULL);
 
 	if (nf_conntrack_event(IPCT_DESTROY, ct) < 0) {
 		/* bad luck, let's retry again */
-		ct->timeout.expires = jiffies +
+		ecache->timeout.expires = jiffies +
 			(random32() % net->ct.sysctl_events_retry_timeout);
-		add_timer(&ct->timeout);
+		add_timer(&ecache->timeout);
 		return;
 	}
 	/* we've got the event delivered, now it's dying */
@@ -274,6 +277,9 @@
 void nf_ct_insert_dying_list(struct nf_conn *ct)
 {
 	struct net *net = nf_ct_net(ct);
+	struct nf_conntrack_ecache *ecache = nf_ct_ecache_find(ct);
+
+	BUG_ON(ecache == NULL);
 
 	/* add this conntrack to the dying list */
 	spin_lock_bh(&nf_conntrack_lock);
@@ -281,10 +287,10 @@
 			     &net->ct.dying);
 	spin_unlock_bh(&nf_conntrack_lock);
 	/* set a new timer to retry event delivery */
-	setup_timer(&ct->timeout, death_by_event, (unsigned long)ct);
-	ct->timeout.expires = jiffies +
+	setup_timer(&ecache->timeout, death_by_event, (unsigned long)ct);
+	ecache->timeout.expires = jiffies +
 		(random32() % net->ct.sysctl_events_retry_timeout);
-	add_timer(&ct->timeout);
+	add_timer(&ecache->timeout);
 }
 EXPORT_SYMBOL_GPL(nf_ct_insert_dying_list);
 
@@ -292,11 +298,36 @@
 {
 	struct nf_conn *ct = (void *)ul_conntrack;
 	struct nf_conn_tstamp *tstamp;
+#ifdef CONFIG_COMCERTO_FP
+	struct nf_conntrack_l4proto *l4proto;
+#endif
 
 	tstamp = nf_conn_tstamp_find(ct);
 	if (tstamp && tstamp->stop == 0)
 		tstamp->stop = ktime_to_ns(ktime_get_real());
 
+#ifdef CONFIG_COMCERTO_FP
+	l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
+
+	if (test_bit(IPS_DYING_BIT, &ct->status) ||
+	   (!test_bit(IPS_PERMANENT_BIT, &ct->status)) ||
+	   ((l4proto->l4proto == IPPROTO_TCP) && (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED))) {
+		if (!test_bit(IPS_DYING_BIT, &ct->status) &&
+		    unlikely(nf_conntrack_event(IPCT_DESTROY, ct) < 0)) {
+			/* destroy event was not delivered */
+			nf_ct_delete_from_lists(ct);
+			nf_ct_insert_dying_list(ct);
+			return;
+		}
+		set_bit(IPS_DYING_BIT, &ct->status);
+		nf_ct_delete_from_lists(ct);
+		nf_ct_put(ct);
+	} else {
+		ct->timeout.expires = jiffies + COMCERTO_PERMANENT_TIMEOUT * HZ;
+		add_timer(&ct->timeout);
+	}
+#else
+
 	if (!test_bit(IPS_DYING_BIT, &ct->status) &&
 	    unlikely(nf_conntrack_event(IPCT_DESTROY, ct) < 0)) {
 		/* destroy event was not delivered */
@@ -307,6 +338,7 @@
 	set_bit(IPS_DYING_BIT, &ct->status);
 	nf_ct_delete_from_lists(ct);
 	nf_ct_put(ct);
+#endif
 }
 
 /*
@@ -610,10 +642,20 @@
 	if (!ct)
 		return dropped;
 
+#ifdef CONFIG_COMCERTO_FP
+	clear_bit(IPS_PERMANENT_BIT, &ct->status);
+	/* Avoid race with timer expiration */
+	if (del_timer_sync(&ct->timeout)) {
+#else
 	if (del_timer(&ct->timeout)) {
+#endif
 		death_by_timeout((unsigned long)ct);
-		dropped = 1;
-		NF_CT_STAT_INC_ATOMIC(net, early_drop);
+		/* Check if we indeed killed this entry. Reliable event
+		   delivery may have inserted it into the dying list. */
+		if (test_bit(IPS_DYING_BIT, &ct->status)) {
+			dropped = 1;
+			NF_CT_STAT_INC_ATOMIC(net, early_drop);
+		}
 	}
 	nf_ct_put(ct);
 	return dropped;
@@ -1079,7 +1121,13 @@
 		}
 	}
 
+#ifdef CONFIG_COMCERTO_FP
+	clear_bit(IPS_PERMANENT_BIT, &ct->status);
+	/* Avoid race with timer expiration */
+	if (del_timer_sync(&ct->timeout)) {
+#else
 	if (del_timer(&ct->timeout)) {
+#endif
 		ct->timeout.function((unsigned long)ct);
 		return true;
 	}
@@ -1200,7 +1248,14 @@
 
 	while ((ct = get_next_corpse(net, iter, data, &bucket)) != NULL) {
 		/* Time to push up daises... */
+
+#ifdef CONFIG_COMCERTO_FP
+		clear_bit(IPS_PERMANENT_BIT, &ct->status);
+		/* Avoid race with timer expiration */
+		if (del_timer_sync(&ct->timeout))
+#else
 		if (del_timer(&ct->timeout))
+#endif
 			death_by_timeout((unsigned long)ct);
 		/* ... else the timer will get him soon. */
 
@@ -1362,6 +1417,46 @@
 }
 EXPORT_SYMBOL_GPL(nf_ct_alloc_hashtable);
 
+#ifdef CONFIG_COMCERTO_FP
+int nf_conntrack_set_dpi_allow_report(struct sk_buff *skb)
+{
+	int err = 0;
+	struct nf_conn *ct = (struct nf_conn *)skb->nfct;
+
+	nf_conntrack_get(skb->nfct);
+
+	set_bit(IPS_DPI_ALLOWED_BIT, &ct->status);
+
+	nf_conntrack_event_cache(IPCT_PROTOINFO, ct);
+
+	nf_conntrack_put(skb->nfct);
+
+	return err;
+}
+EXPORT_SYMBOL(nf_conntrack_set_dpi_allow_report);
+
+int nf_conntrack_set_dpi_allow_and_mark(struct sk_buff *skb, int mark)
+{
+	int err = 0;
+	struct nf_conn *ct = (struct nf_conn *)skb->nfct;
+
+	nf_conntrack_get(skb->nfct);
+
+	set_bit(IPS_DPI_ALLOWED_BIT, &ct->status);
+
+#ifdef CONFIG_NF_CONNTRACK_MARK
+	ct->mark = mark;
+#endif
+
+	nf_conntrack_event_cache(IPCT_PROTOINFO, ct);
+
+	nf_conntrack_put(skb->nfct);
+
+	return err;
+}
+EXPORT_SYMBOL(nf_conntrack_set_dpi_allow_and_mark);
+#endif
+
 int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
 {
 	int i, bucket;
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 782cdcd..0683213 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -301,6 +301,41 @@
 #define ctnetlink_dump_secctx(a, b) (0)
 #endif
 
+#if defined(CONFIG_COMCERTO_FP)
+static int
+ctnetlink_dump_comcerto_fp(struct sk_buff *skb, const struct nf_conn *ct)
+{
+	struct nlattr *nest_count;
+
+	nest_count = nla_nest_start(skb, CTA_COMCERTO_FP_ORIG | NLA_F_NESTED);
+	if (!nest_count)
+		goto nla_put_failure;
+
+	NLA_PUT_U32(skb, CTA_COMCERTO_FP_MARK, ct->fp_info[IP_CT_DIR_ORIGINAL].mark);
+	NLA_PUT_U32(skb, CTA_COMCERTO_FP_IFINDEX, ct->fp_info[IP_CT_DIR_ORIGINAL].ifindex);
+	NLA_PUT_U32(skb, CTA_COMCERTO_FP_IIF, ct->fp_info[IP_CT_DIR_ORIGINAL].iif);
+
+	nla_nest_end(skb, nest_count);
+
+	nest_count = nla_nest_start(skb, CTA_COMCERTO_FP_REPLY | NLA_F_NESTED);
+	if (!nest_count)
+		goto nla_put_failure;
+
+	NLA_PUT_U32(skb, CTA_COMCERTO_FP_MARK, ct->fp_info[IP_CT_DIR_REPLY].mark);
+	NLA_PUT_U32(skb, CTA_COMCERTO_FP_IFINDEX, ct->fp_info[IP_CT_DIR_REPLY].ifindex);
+	NLA_PUT_U32(skb, CTA_COMCERTO_FP_IIF, ct->fp_info[IP_CT_DIR_REPLY].iif);
+
+	nla_nest_end(skb, nest_count);
+
+	return 0;
+
+nla_put_failure:
+	return -1;
+}
+#else
+#define ctnetlink_dump_comcerto_fp(a, b) (0)
+#endif
+
 #define master_tuple(ct) &(ct->master->tuplehash[IP_CT_DIR_ORIGINAL].tuple)
 
 static inline int
@@ -437,6 +472,7 @@
 	    ctnetlink_dump_helpinfo(skb, ct) < 0 ||
 	    ctnetlink_dump_mark(skb, ct) < 0 ||
 	    ctnetlink_dump_secctx(skb, ct) < 0 ||
+	    ctnetlink_dump_comcerto_fp(skb, ct) < 0 ||
 	    ctnetlink_dump_id(skb, ct) < 0 ||
 	    ctnetlink_dump_use(skb, ct) < 0 ||
 	    ctnetlink_dump_master(skb, ct) < 0 ||
@@ -528,6 +564,12 @@
 	       + nla_total_size(0) /* CTA_HELP */
 	       + nla_total_size(NF_CT_HELPER_NAME_LEN) /* CTA_HELP_NAME */
 	       + ctnetlink_secctx_size(ct)
+#ifdef CONFIG_COMCERTO_FP
+	       + 2 * nla_total_size(0) /* CTA_COMCERTO_FP_ORIG|REPL */
+	       + 2 * nla_total_size(sizeof(uint32_t)) /* CTA_COMCERTO_FP_MARK */
+	       + 2 * nla_total_size(sizeof(uint32_t)) /* CTA_COMCERTO_FP_IFINDEX */
+	       + 2 * nla_total_size(sizeof(uint32_t)) /* CTA_COMCERTO_FP_IIF */
+#endif
 #ifdef CONFIG_NF_NAT_NEEDED
 	       + 2 * nla_total_size(0) /* CTA_NAT_SEQ_ADJ_ORIG|REPL */
 	       + 6 * nla_total_size(sizeof(u_int32_t)) /* CTA_NAT_SEQ_OFFSET */
@@ -605,6 +647,9 @@
 	if (nf_ct_zone(ct))
 		NLA_PUT_BE16(skb, CTA_ZONE, htons(nf_ct_zone(ct)));
 
+	if (ctnetlink_dump_comcerto_fp(skb, ct) < 0)
+		goto nla_put_failure;
+
 	if (ctnetlink_dump_id(skb, ct) < 0)
 		goto nla_put_failure;
 
@@ -1078,7 +1123,36 @@
 	ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK);
 	return 0;
 }
+#if defined(CONFIG_COMCERTO_FP)
+/*
+ * This function detects ctnetlink messages that require
+ * to set the conntrack status to IPS_PERMANENT.
+ * It updates only this bit regardless of other possible
+ * changes.
+ * Return 0 if succesfull
+ */
+static int
+ctnetlink_change_permanent(struct nf_conn *ct, const struct nlattr * const cda[])
+{
+	unsigned int status;
+	u_int32_t id;
 
+	if (cda[CTA_STATUS] && cda[CTA_ID]) {
+		status = ntohl(nla_get_be32(cda[CTA_STATUS]));
+		id = ntohl(nla_get_be32(cda[CTA_ID]));
+
+		if (status & IPS_PERMANENT) {
+			if ((u32)(unsigned long)ct == id) {
+				ct->status |= IPS_PERMANENT;
+				return 0;
+			}
+			else
+				return -ENOENT;
+		}
+	}
+	return -1;
+}
+#endif
 static int
 ctnetlink_change_nat(struct nf_conn *ct, const struct nlattr * const cda[])
 {
@@ -1549,6 +1623,13 @@
 	if (!(nlh->nlmsg_flags & NLM_F_EXCL)) {
 		struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
 
+#if defined(CONFIG_COMCERTO_FP)
+		/* If the permanent status has been set, this is a specific
+		 * message. Don't broadcast the event and don't update the ct */
+		err = ctnetlink_change_permanent(ct, cda);
+		if ((err == 0) || (err == -ENOENT))
+			goto out_unlock;
+#endif
 		err = ctnetlink_change_conntrack(ct, cda);
 		if (err == 0) {
 			nf_conntrack_get(&ct->ct_general);
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index 621e2da..0758b88 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -223,6 +223,12 @@
 		if (seq_printf(s, "[ASSURED] "))
 			goto release;
 
+#ifdef CONFIG_COMCERTO_FP
+	if (test_bit(IPS_PERMANENT_BIT, &ct->status))
+		if (seq_printf(s, "[PERMANENT] "))
+			goto release;
+#endif
+
 #if defined(CONFIG_NF_CONNTRACK_MARK)
 	if (seq_printf(s, "mark=%u ", ct->mark))
 		goto release;
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index 47bacd8..bd1c628 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -43,11 +43,32 @@
 	struct dst_entry *dst = skb_dst(skb);
 	struct xfrm_state *x = dst->xfrm;
 	struct net *net = xs_net(x);
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+	struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH];
+	int xfrm_nr = 0;
+	int i;
+#endif
 
 	if (err <= 0)
 		goto resume;
 
 	do {
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+		if (x->offloaded)  {
+
+			if (xfrm_nr == XFRM_MAX_DEPTH) {
+				err = -ENOBUFS;
+				goto out_exit;
+			}
+
+			if (!x->curlft.use_time) 
+				x->curlft.use_time = get_seconds();
+
+			xfrm_vec[xfrm_nr++] = x;
+			skb->ipsec_offload = 1;
+			goto next_dst;
+		}
+#endif
 		err = xfrm_state_check_space(x, skb);
 		if (err) {
 			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
@@ -90,6 +111,9 @@
 			goto error_nolock;
 		}
 
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+next_dst:
+#endif
 		dst = skb_dst_pop(skb);
 		if (!dst) {
 			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
@@ -101,6 +125,26 @@
 	} while (x && !(x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL));
 
 	err = 0;
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+	if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
+		struct sec_path *sp;
+
+		sp = secpath_dup(skb->sp);
+		if (!sp)
+			goto error_nolock;
+		if (skb->sp)
+			secpath_put(skb->sp);
+		skb->sp = sp;
+	}
+	if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH)
+		goto error_nolock;
+
+	memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec,
+	       xfrm_nr * sizeof(xfrm_vec[0]));
+	skb->sp->len += xfrm_nr;
+	for (i = 0; i < skb->sp->len; i++)
+		xfrm_state_hold(skb->sp->xvec[i]);
+#endif
 
 out_exit:
 	return err;
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 0174034..12b1cf5 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -46,7 +46,15 @@
 
 static struct kmem_cache *xfrm_dst_cache __read_mostly;
 
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+extern int ipsec_nlkey_flow(u16 xfrm_nr, u16 *xfrm_handle,
+                const struct flowi *fl, u16 family, u16 dir);
+#endif
+
+#if !defined(CONFIG_INET_IPSEC_OFFLOAD) && !defined(CONFIG_INET6_IPSEC_OFFLOAD)
 static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family);
+#endif
+
 static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo);
 static void xfrm_init_pmtu(struct dst_entry *dst);
 static int stale_bundle(struct dst_entry *dst);
@@ -94,7 +102,10 @@
 	return 0;
 }
 
-static inline struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos,
+#if !defined(CONFIG_INET_IPSEC_OFFLOAD) && !defined(CONFIG_INET6_IPSEC_OFFLOAD) 
+static inline 
+#endif
+struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos,
 						  const xfrm_address_t *saddr,
 						  const xfrm_address_t *daddr,
 						  int family)
@@ -112,8 +123,14 @@
 
 	return dst;
 }
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+EXPORT_SYMBOL(__xfrm_dst_lookup);
+#endif
 
-static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos,
+#if !defined(CONFIG_INET_IPSEC_OFFLOAD) && !defined(CONFIG_INET6_IPSEC_OFFLOAD) 
+static inline 
+#endif
+struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos,
 						xfrm_address_t *prev_saddr,
 						xfrm_address_t *prev_daddr,
 						int family)
@@ -143,6 +160,9 @@
 
 	return dst;
 }
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+EXPORT_SYMBOL(xfrm_dst_lookup);
+#endif
 
 static inline unsigned long make_jiffies(long secs)
 {
@@ -1264,7 +1284,10 @@
  * still valid.
  */
 
-static inline int xfrm_get_tos(const struct flowi *fl, int family)
+#if !defined(CONFIG_INET_IPSEC_OFFLOAD) && !defined(CONFIG_INET6_IPSEC_OFFLOAD)
+static inline 
+#endif
+int xfrm_get_tos(const struct flowi *fl, int family)
 {
 	struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
 	int tos;
@@ -1278,6 +1301,9 @@
 
 	return tos;
 }
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+EXPORT_SYMBOL(xfrm_get_tos);
+#endif
 
 static struct flow_cache_object *xfrm_bundle_flo_get(struct flow_cache_object *flo)
 {
@@ -1461,7 +1487,12 @@
 		xdst->route = dst;
 		dst_copy_metrics(dst1, dst);
 
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+		if ((xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) &&
+			(!xfrm[i]->offloaded)) {
+#else
 		if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
+#endif
 			family = xfrm[i]->props.family;
 			dst = xfrm_dst_lookup(xfrm[i], tos, &saddr, &daddr,
 					      family);
@@ -1786,6 +1817,9 @@
 	u16 family = dst_orig->ops->family;
 	u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT);
 	int i, err, num_pols, num_xfrms = 0, drop_pols = 0;
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+	u8 new_flow = 0;
+#endif
 
 restart:
 	dst = NULL;
@@ -1836,8 +1870,13 @@
 		    !net->xfrm.policy_count[XFRM_POLICY_OUT])
 			goto nopol;
 
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+		flo = flow_cache_lookup(net, fl, family, dir, &new_flow,
+					xfrm_bundle_lookup, dst_orig);
+#else
 		flo = flow_cache_lookup(net, fl, family, dir,
 					xfrm_bundle_lookup, dst_orig);
+#endif
 		if (flo == NULL)
 			goto nopol;
 		if (IS_ERR(flo)) {
@@ -1917,6 +1956,30 @@
 		dst_release(dst);
 		dst = dst_orig;
 	}
+
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+	if (new_flow) {
+		struct dst_entry *dst1 = dst;
+		struct xfrm_state *x; 
+		u16	xfrm_handle[XFRM_POLICY_TYPE_MAX];
+
+		num_xfrms = 0;
+		memset(xfrm_handle, 0, XFRM_POLICY_TYPE_MAX*sizeof(u16));
+		while((x = dst1->xfrm) != NULL) {
+			if (!x->offloaded)
+				goto ok;
+			xfrm_handle[num_xfrms++] = x->handle;
+			dst1 = dst1->child;
+			if (dst1 == NULL) {
+				err = -EHOSTUNREACH;
+				goto error;
+			}
+		}
+		// sent flow notification to cmm with sa_handle
+		ipsec_nlkey_flow(num_xfrms, xfrm_handle, fl, family, (unsigned short)dir);
+	}
+#endif
+
 ok:
 	xfrm_pols_put(pols, drop_pols);
 	if (dst && dst->xfrm &&
@@ -2042,9 +2105,14 @@
 	int xfrm_nr;
 	int pi;
 	int reverse;
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+	u8 new_flow = 0;
+#endif
 	struct flowi fl;
 	u8 fl_dir;
 	int xerr_idx = -1;
+	
+	//printk(KERN_INFO "%s\n", __func__);
 
 	reverse = dir & ~XFRM_POLICY_MASK;
 	dir &= XFRM_POLICY_MASK;
@@ -2081,9 +2149,13 @@
 
 	if (!pol) {
 		struct flow_cache_object *flo;
-
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+		flo = flow_cache_lookup(net, &fl, family, fl_dir, &new_flow,
+					xfrm_policy_lookup, NULL);
+#else
 		flo = flow_cache_lookup(net, &fl, family, fl_dir,
 					xfrm_policy_lookup, NULL);
+#endif
 		if (IS_ERR_OR_NULL(flo))
 			pol = ERR_CAST(flo);
 		else
@@ -2177,6 +2249,28 @@
 			goto reject;
 		}
 
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+		if (new_flow) {
+			struct xfrm_state *x;
+			u16	xfrm_handle[XFRM_POLICY_TYPE_MAX];
+
+			xfrm_nr = 0;
+			memset(xfrm_handle, 0, XFRM_POLICY_TYPE_MAX*sizeof(u16));
+			for (i=skb->sp->len-1; i>=0; i--) 
+			{
+				x = skb->sp->xvec[i];
+				
+				if (!x->offloaded)
+					goto std_path;
+				
+				xfrm_handle[xfrm_nr++] = x->handle;
+			}
+			// sent flow notification to cmm with sa_handle
+			ipsec_nlkey_flow(xfrm_nr, xfrm_handle, (const struct flowi *)&fl, family, fl_dir);
+		}
+
+std_path:
+#endif
 		xfrm_pols_put(pols, npols);
 		return 1;
 	}
@@ -2506,7 +2600,10 @@
 	read_unlock_bh(&xfrm_policy_afinfo_lock);
 }
 
-static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family)
+#if !defined(CONFIG_INET_IPSEC_OFFLOAD) && !defined(CONFIG_INET6_IPSEC_OFFLOAD)
+static 
+#endif
+struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family)
 {
 	struct xfrm_policy_afinfo *afinfo;
 	if (unlikely(family >= NPROTO))
@@ -2517,6 +2614,9 @@
 		read_unlock(&xfrm_policy_afinfo_lock);
 	return afinfo;
 }
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+EXPORT_SYMBOL(xfrm_policy_get_afinfo);
+#endif
 
 static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo)
 {
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 9414b9c..520035a 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -39,6 +39,10 @@
 
 static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
 
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+static unsigned short xfrm_state_handle;
+#endif
+
 static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
 static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
 
@@ -66,11 +70,20 @@
 	return __xfrm_spi_hash(daddr, spi, proto, family, net->xfrm.state_hmask);
 }
 
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+static void xfrm_hash_transfer(struct hlist_head *list,
+			       struct hlist_head *ndsttable,
+			       struct hlist_head *nsrctable,
+			       struct hlist_head *nspitable,
+			       struct hlist_head *nhtable,
+			       unsigned int nhashmask)
+#else
 static void xfrm_hash_transfer(struct hlist_head *list,
 			       struct hlist_head *ndsttable,
 			       struct hlist_head *nsrctable,
 			       struct hlist_head *nspitable,
 			       unsigned int nhashmask)
+#endif
 {
 	struct hlist_node *entry, *tmp;
 	struct xfrm_state *x;
@@ -94,6 +107,11 @@
 					    nhashmask);
 			hlist_add_head(&x->byspi, nspitable+h);
 		}
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+		if (x->handle) {
+			hlist_add_head(&x->byh, nhtable+(x->handle & nhashmask));
+		}
+#endif
 	}
 }
 
@@ -108,6 +126,9 @@
 {
 	struct net *net = container_of(work, struct net, xfrm.state_hash_work);
 	struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi;
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+	struct hlist_head *nh, *oh;
+#endif
 	unsigned long nsize, osize;
 	unsigned int nhashmask, ohashmask;
 	int i;
@@ -129,22 +150,41 @@
 		xfrm_hash_free(nsrc, nsize);
 		goto out_unlock;
 	}
-
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+	nh = xfrm_hash_alloc(nsize);
+	if (!nh) {
+		xfrm_hash_free(ndst, nsize);
+		xfrm_hash_free(nsrc, nsize);
+		xfrm_hash_free(nspi, nsize);
+		goto out_unlock;
+	}
+#endif
 	spin_lock_bh(&xfrm_state_lock);
 
 	nhashmask = (nsize / sizeof(struct hlist_head)) - 1U;
 	for (i = net->xfrm.state_hmask; i >= 0; i--)
-		xfrm_hash_transfer(net->xfrm.state_bydst+i, ndst, nsrc, nspi,
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)		
+		xfrm_hash_transfer(net->xfrm.state_bydst+i, ndst, nsrc, nspi, nh,
 				   nhashmask);
+#else
+		xfrm_hash_transfer(net->xfrm.state_bydst+i, ndst, nsrc, nspi,
+				   nhashmask);	
+#endif
 
 	odst = net->xfrm.state_bydst;
 	osrc = net->xfrm.state_bysrc;
 	ospi = net->xfrm.state_byspi;
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+	oh   = net->xfrm.state_byh;
+#endif
 	ohashmask = net->xfrm.state_hmask;
 
 	net->xfrm.state_bydst = ndst;
 	net->xfrm.state_bysrc = nsrc;
 	net->xfrm.state_byspi = nspi;
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+	net->xfrm.state_byh   = nh;
+#endif
 	net->xfrm.state_hmask = nhashmask;
 
 	spin_unlock_bh(&xfrm_state_lock);
@@ -153,6 +193,9 @@
 	xfrm_hash_free(odst, osize);
 	xfrm_hash_free(osrc, osize);
 	xfrm_hash_free(ospi, osize);
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+	xfrm_hash_free(oh,   osize);
+#endif
 
 out_unlock:
 	mutex_unlock(&hash_resize_mutex);
@@ -494,6 +537,9 @@
 		INIT_HLIST_NODE(&x->bydst);
 		INIT_HLIST_NODE(&x->bysrc);
 		INIT_HLIST_NODE(&x->byspi);
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+		INIT_HLIST_NODE(&x->byh);
+#endif
 		tasklet_hrtimer_init(&x->mtimer, xfrm_timer_handler, CLOCK_REALTIME, HRTIMER_MODE_ABS);
 		setup_timer(&x->rtimer, xfrm_replay_timer_handler,
 				(unsigned long)x);
@@ -504,6 +550,12 @@
 		x->lft.hard_packet_limit = XFRM_INF;
 		x->replay_maxage = 0;
 		x->replay_maxdiff = 0;
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+		x->handle = xfrm_state_handle++;
+		if (x->handle == 0)
+			x->handle = xfrm_state_handle++;
+		hlist_add_head(&x->byh, net->xfrm.state_byh+(x->handle & net->xfrm.state_hmask));
+#endif
 		x->inner_mode = NULL;
 		x->inner_mode_iaf = NULL;
 		spin_lock_init(&x->lock);
@@ -538,6 +590,10 @@
 		hlist_del(&x->bysrc);
 		if (x->id.spi)
 			hlist_del(&x->byspi);
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+		if (x->handle)
+			hlist_del(&x->byh);
+#endif
 		net->xfrm.state_num--;
 		spin_unlock(&xfrm_state_lock);
 
@@ -1408,6 +1464,37 @@
 }
 EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
 
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+struct xfrm_state *__xfrm_state_lookup_byhandle(struct net *net, u16 handle)
+{
+	unsigned int h = (handle & net->xfrm.state_hmask);
+	struct xfrm_state *x;
+	struct hlist_node *entry;
+
+	hlist_for_each_entry(x, entry, net->xfrm.state_byh+h, byh) {
+		if (x->handle != handle)
+			continue;
+	
+		xfrm_state_hold(x);
+		return x;
+	}
+
+	return NULL;
+}
+
+struct xfrm_state *
+xfrm_state_lookup_byhandle(struct net *net, u16 handle)
+{
+	struct xfrm_state *x;
+
+	spin_lock_bh(&xfrm_state_lock);
+	x = __xfrm_state_lookup_byhandle(net, handle);
+	spin_unlock_bh(&xfrm_state_lock);
+	return x;
+}
+EXPORT_SYMBOL(xfrm_state_lookup_byhandle);
+#endif
+
 struct xfrm_state *
 xfrm_find_acq(struct net *net, struct xfrm_mark *mark, u8 mode, u32 reqid, u8 proto,
 	      const xfrm_address_t *daddr, const xfrm_address_t *saddr,
@@ -2026,6 +2113,12 @@
 	net->xfrm.state_byspi = xfrm_hash_alloc(sz);
 	if (!net->xfrm.state_byspi)
 		goto out_byspi;
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+	net->xfrm.state_byh = xfrm_hash_alloc(sz);
+	if (!net->xfrm.state_byh)
+		goto out_byh;
+	get_random_bytes(&xfrm_state_handle, sizeof(xfrm_state_handle));
+#endif
 	net->xfrm.state_hmask = ((sz / sizeof(struct hlist_head)) - 1);
 
 	net->xfrm.state_num = 0;
@@ -2035,6 +2128,10 @@
 	init_waitqueue_head(&net->xfrm.km_waitq);
 	return 0;
 
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
+out_byh:
+	xfrm_hash_free(net->xfrm.state_byspi, sz);
+#endif
 out_byspi:
 	xfrm_hash_free(net->xfrm.state_bysrc, sz);
 out_bysrc: