From c20c257448b56296f9cc1c8e9f778f8dc4e0c4cf Mon Sep 17 00:00:00 2001
From: Gabor Juhos <juhosg@openwrt.org>
Date: Tue, 20 Nov 2012 21:37:53 +0000
Subject: cns21xx: add support for 3.6

Signed-off-by: Gabor Juhos <juhosg@openwrt.org>

git-svn-id: svn://svn.openwrt.org/openwrt/trunk@34285 3c298f89-4303-0410-b956-a3cf2f4a3e73
---
 target/linux/cns21xx/config-3.6                    |  135 ++
 .../patches-3.6/002-arm-debugll-printk.patch       |   24 +
 .../003-arm-introduce-fa-platform.patch            |   56 +
 .../cns21xx/patches-3.6/004-arm-add-fa-time.patch  |  143 ++
 .../patches-3.6/005-arm-add-fa-gpio-driver.patch   |  343 +++
 .../006-arm-add-fa-watchdog-driver.patch           |  458 ++++
 .../cns21xx/patches-3.6/100-cns21xx-core.patch     | 2050 ++++++++++++++++
 .../patches-3.6/101-cns21xx-serial-support.patch   |  103 +
 .../patches-3.6/102-cns21xx-gpiolib-support.patch  |   85 +
 .../patches-3.6/103-cns21xx-usb-ohci-support.patch |  230 ++
 .../patches-3.6/104-cns21xx-usb-ehci-support.patch |  213 ++
 .../patches-3.6/105-cns21xx-spi-driver.patch       |  578 +++++
 .../patches-3.6/106-cns21xx-gec-driver.patch       | 2507 ++++++++++++++++++++
 .../patches-3.6/201-cns21xx-add-usb-devices.patch  |  104 +
 .../202-cns21xx-add-watchdog-device.patch          |   63 +
 .../203-cns21xx-add-spi-master-device.patch        |  117 +
 .../patches-3.6/204-cns21xx-add-gec-device.patch   |  178 ++
 .../patches-3.6/301-cns21xx-mach-ns-k330.patch     |  234 ++
 .../patches-3.6/302-cns21xx-mach-nsb3ast.patch     |  201 ++
 19 files changed, 7822 insertions(+)
 create mode 100644 target/linux/cns21xx/config-3.6
 create mode 100644 target/linux/cns21xx/patches-3.6/002-arm-debugll-printk.patch
 create mode 100644 target/linux/cns21xx/patches-3.6/003-arm-introduce-fa-platform.patch
 create mode 100644 target/linux/cns21xx/patches-3.6/004-arm-add-fa-time.patch
 create mode 100644 target/linux/cns21xx/patches-3.6/005-arm-add-fa-gpio-driver.patch
 create mode 100644 target/linux/cns21xx/patches-3.6/006-arm-add-fa-watchdog-driver.patch
 create mode 100644 target/linux/cns21xx/patches-3.6/100-cns21xx-core.patch
 create mode 100644 target/linux/cns21xx/patches-3.6/101-cns21xx-serial-support.patch
 create mode 100644 target/linux/cns21xx/patches-3.6/102-cns21xx-gpiolib-support.patch
 create mode 100644 target/linux/cns21xx/patches-3.6/103-cns21xx-usb-ohci-support.patch
 create mode 100644 target/linux/cns21xx/patches-3.6/104-cns21xx-usb-ehci-support.patch
 create mode 100644 target/linux/cns21xx/patches-3.6/105-cns21xx-spi-driver.patch
 create mode 100644 target/linux/cns21xx/patches-3.6/106-cns21xx-gec-driver.patch
 create mode 100644 target/linux/cns21xx/patches-3.6/201-cns21xx-add-usb-devices.patch
 create mode 100644 target/linux/cns21xx/patches-3.6/202-cns21xx-add-watchdog-device.patch
 create mode 100644 target/linux/cns21xx/patches-3.6/203-cns21xx-add-spi-master-device.patch
 create mode 100644 target/linux/cns21xx/patches-3.6/204-cns21xx-add-gec-device.patch
 create mode 100644 target/linux/cns21xx/patches-3.6/301-cns21xx-mach-ns-k330.patch
 create mode 100644 target/linux/cns21xx/patches-3.6/302-cns21xx-mach-nsb3ast.patch

(limited to 'target')

diff --git a/target/linux/cns21xx/config-3.6 b/target/linux/cns21xx/config-3.6
new file mode 100644
index 0000000000..5e39860209
--- /dev/null
+++ b/target/linux/cns21xx/config-3.6
@@ -0,0 +1,135 @@
+CONFIG_ALIGNMENT_TRAP=y
+CONFIG_ARCH_CNS21XX=y
+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
+CONFIG_ARM=y
+# CONFIG_ARM_CPU_SUSPEND is not set
+CONFIG_ARM_L1_CACHE_SHIFT=4
+CONFIG_ARM_L1_CACHE_SHIFT_4=y
+# CONFIG_ARPD is not set
+CONFIG_ATA=m
+CONFIG_BCMA_POSSIBLE=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_CMDLINE="console=ttyS0,38400 rootfstype=squashfs,jffs2 noinitrd"
+CONFIG_CMDLINE_FROM_BOOTLOADER=y
+CONFIG_CNS21XX_DEV_GEC=y
+CONFIG_CNS21XX_DEV_SPI_MASTER=y
+CONFIG_CNS21XX_DEV_USB=y
+CONFIG_CNS21XX_GEC=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4=y
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_CPU_CACHE_FA=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_FA=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+CONFIG_CPU_FA526=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+CONFIG_CPU_PABRT_LEGACY=y
+CONFIG_CPU_TLB_FA=y
+CONFIG_CPU_USE_DOMAINS=y
+# CONFIG_DEBUG_USER is not set
+CONFIG_DECOMPRESS_LZMA=y
+CONFIG_DLCI=m
+CONFIG_DLCI_MAX=8
+CONFIG_DMADEVICES=y
+CONFIG_DNOTIFY=y
+CONFIG_EEPROM_AT25=y
+CONFIG_ELF_CORE=y
+CONFIG_FA_WATCHDOG=y
+CONFIG_FRAME_POINTER=y
+CONFIG_GENERIC_ATOMIC64=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+# CONFIG_HAMRADIO is not set
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAVE_AOUT=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_HAVE_ARCH_PFN_VALID=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+CONFIG_HAVE_IRQ_WORK=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_SPARSE_IRQ=y
+CONFIG_HDLC=m
+CONFIG_HDLC_CISCO=m
+CONFIG_HDLC_FR=m
+CONFIG_HDLC_PPP=m
+CONFIG_HDLC_RAW=m
+CONFIG_HWMON=y
+CONFIG_HW_RANDOM=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_KTIME_SCALAR=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+CONFIG_M25PXX_USE_FAST_READ=y
+CONFIG_MACH_NSB3AST=y
+CONFIG_MACH_NS_K330=y
+CONFIG_MDIO_BOARDINFO=y
+# CONFIG_MTD_CFI is not set
+CONFIG_MTD_M25P80=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_PER_CPU_KM=y
+CONFIG_NLS=m
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PCI_SYSCALL is not set
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PHYLIB=y
+CONFIG_PHYS_OFFSET=0x00000000
+CONFIG_PLAT_FA=y
+CONFIG_PLAT_FA_GPIO=y
+CONFIG_PLAT_FA_TIME=y
+# CONFIG_PREEMPT_RCU is not set
+CONFIG_SCSI=m
+CONFIG_SCSI_MOD=m
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SERIO=y
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SPI=y
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_CNS21XX=y
+CONFIG_SPI_DEBUG=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPLIT_PTLOCK_CPUS=999999
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_UID16=y
+# CONFIG_USB_ARCH_HAS_XHCI is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_WAN=y
+CONFIG_XZ_DEC=y
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZONE_DMA_FLAG=0
diff --git a/target/linux/cns21xx/patches-3.6/002-arm-debugll-printk.patch b/target/linux/cns21xx/patches-3.6/002-arm-debugll-printk.patch
new file mode 100644
index 0000000000..e14509ef3c
--- /dev/null
+++ b/target/linux/cns21xx/patches-3.6/002-arm-debugll-printk.patch
@@ -0,0 +1,24 @@
+--- a/kernel/printk.c
++++ b/kernel/printk.c
+@@ -48,6 +48,10 @@
+ #define CREATE_TRACE_POINTS
+ #include <trace/events/printk.h>
+ 
++#ifdef CONFIG_DEBUG_LL
++extern void printascii(char *);
++#endif /* CONFIG_DEBUG_LL */
++
+ /*
+  * Architectures can override it:
+  */
+@@ -473,6 +477,10 @@ static ssize_t devkmsg_read(struct file
+ 	ts_usec = msg->ts_nsec;
+ 	do_div(ts_usec, 1000);
+ 
++#ifdef CONFIG_DEBUG_LL
++	printascii(printk_buf);
++#endif
++
+ 	/*
+ 	 * If we couldn't merge continuation line fragments during the print,
+ 	 * export the stored flags to allow an optional external merge of the
diff --git a/target/linux/cns21xx/patches-3.6/003-arm-introduce-fa-platform.patch b/target/linux/cns21xx/patches-3.6/003-arm-introduce-fa-platform.patch
new file mode 100644
index 0000000000..018734e29f
--- /dev/null
+++ b/target/linux/cns21xx/patches-3.6/003-arm-introduce-fa-platform.patch
@@ -0,0 +1,56 @@
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -1133,10 +1133,15 @@ source "arch/arm/mach-vt8500/Kconfig"
+ 
+ source "arch/arm/mach-w90x900/Kconfig"
+ 
++source "arch/arm/plat-fa/Kconfig"
++
+ # Definitions to make life easier
+ config ARCH_ACORN
+ 	bool
+ 
++config PLAT_FA
++	bool
++
+ config PLAT_IOP
+ 	bool
+ 	select GENERIC_CLOCKEVENTS
+--- a/arch/arm/Makefile
++++ b/arch/arm/Makefile
+@@ -205,6 +205,7 @@ plat-$(CONFIG_ARCH_MXC)		:= mxc
+ plat-$(CONFIG_ARCH_OMAP)	:= omap
+ plat-$(CONFIG_ARCH_S3C64XX)	:= samsung
+ plat-$(CONFIG_ARCH_ZYNQ)	:= versatile
++plat-$(CONFIG_PLAT_FA)		:= fa
+ plat-$(CONFIG_PLAT_IOP)		:= iop
+ plat-$(CONFIG_PLAT_NOMADIK)	:= nomadik
+ plat-$(CONFIG_PLAT_ORION)	:= orion
+@@ -304,7 +305,7 @@ define archhelp
+   echo  '  Image         - Uncompressed kernel image (arch/$(ARCH)/boot/Image)'
+   echo  '* xipImage      - XIP kernel image, if configured (arch/$(ARCH)/boot/xipImage)'
+   echo  '  uImage        - U-Boot wrapped zImage'
+-  echo  '  bootpImage    - Combined zImage and initial RAM disk' 
++  echo  '  bootpImage    - Combined zImage and initial RAM disk'
+   echo  '                  (supply initrd image via make variable INITRD=<path>)'
+   echo  '  dtbs          - Build device tree blobs for enabled boards'
+   echo  '  install       - Install uncompressed kernel'
+--- /dev/null
++++ b/arch/arm/plat-fa/Makefile
+@@ -0,0 +1,10 @@
++#
++# Makefile for the linux kernel.
++#
++
++obj-y :=
++
++obj-m :=
++obj-n :=
++obj-  :=
++
+--- /dev/null
++++ b/arch/arm/plat-fa/Kconfig
+@@ -0,0 +1,3 @@
++if PLAT_FA
++
++endif
diff --git a/target/linux/cns21xx/patches-3.6/004-arm-add-fa-time.patch b/target/linux/cns21xx/patches-3.6/004-arm-add-fa-time.patch
new file mode 100644
index 0000000000..460e7cb69d
--- /dev/null
+++ b/target/linux/cns21xx/patches-3.6/004-arm-add-fa-time.patch
@@ -0,0 +1,143 @@
+--- /dev/null
++++ b/arch/arm/plat-fa/include/plat/time.h
+@@ -0,0 +1,20 @@
++/*
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * 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.
++ */
++
++#ifndef _FA_TIME_H
++#define _FA_TIME_H
++
++#define FA_TIMER1	0
++#define FA_TIMER2	1
++#define FA_TIMER3	2
++
++int __init fa_timer_init(unsigned int mapbase, unsigned int irq,
++			 unsigned int timer, unsigned int freq);
++
++#endif /* _FA_TIME_H */
+--- /dev/null
++++ b/arch/arm/plat-fa/time.c
+@@ -0,0 +1,97 @@
++/*
++ *  Copyright (C) 2001-2006 Storlink, Corp.
++ *  Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * 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/init.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/io.h>
++
++#include <asm/mach/time.h>
++#include <plat/time.h>
++
++/*
++ * Register definitions for the timers
++ */
++#define TIMER_COUNT(_base, _tmr)	((_base) + 0x00 + (_tmr) * 0x10)
++#define TIMER_LOAD(_base, _tmr)		((_base) + 0x04 + (_tmr) * 0x10)
++#define TIMER_MATCH1(_base, _tmr)	((_base) + 0x08 + (_tmr) * 0x10)
++#define TIMER_MATCH2(_base, _tmr)	((_base) + 0x0c + (_tmr) * 0x10)
++
++#define TIMER_CR(_base)			((_base) + 0x30)
++#define TIMER_STATUS(_base)		((_base) + 0x34)
++#define TIMER_MASK(_base)		((_base) + 0x38)
++
++#define TIMER_SIZE		0x3c
++
++#define TIMER_CR_ENABLE(x)	(1 << ((x) * 3))
++#define TIMER_CR_CLOCK(x)	(1 << ((x) * 3 + 1))
++#define TIMER_CR_INT(x)		(1 << ((x) * 3 + 2))
++#define TIMER_CR_DOWN(x)	(1 << ((x) * 3 + 9))
++
++#define TIMER_MASK_MATCH1(x)	(1 << ((x) * 3))
++#define TIMER_MASK_MATCH2(x)	(1 << ((x) * 3 + 1))
++#define TIMER_MASK_OF(x)	(1 << ((x) * 3 + 2))
++
++#define TIMER_MASK_ALL		0x7ff
++
++/*
++ * IRQ handler for the timer
++ */
++static irqreturn_t fa_timer_interrupt(int irq, void *dev_id)
++{
++	timer_tick();
++	return IRQ_HANDLED;
++}
++
++static struct irqaction fa_timer_irq = {
++	.name		= "Timer Tick",
++	.flags		= IRQF_DISABLED | IRQF_TIMER,
++	.handler	= fa_timer_interrupt,
++};
++
++int __init fa_timer_init(unsigned int mapbase, unsigned int irq,
++			 unsigned int timer, unsigned int freq)
++{
++	void __iomem *base;
++
++	base = ioremap(mapbase, TIMER_SIZE);
++	if (!base)
++		return -ENOMEM;
++
++	/* disable timers, clear status and mask all interrupts */
++	__raw_writel(0, TIMER_CR(base));
++	__raw_writel(0, TIMER_STATUS(base));
++	__raw_writel(TIMER_MASK_ALL, TIMER_MASK(base));
++
++	/*
++	 * Make irqs happen for the system timer
++	 */
++	setup_irq(irq, &fa_timer_irq);
++
++	/* Setup the timer */
++	__raw_writel(freq / HZ, TIMER_COUNT(base, timer));
++	__raw_writel(freq / HZ, TIMER_LOAD(base, timer));
++	__raw_writel(0, TIMER_MATCH1(base, timer));
++	__raw_writel(0, TIMER_MATCH2(base, timer));
++
++	/* Enable interrupt and start the timer */
++	__raw_writel(TIMER_MASK_ALL & ~TIMER_MASK_OF(timer),
++		     TIMER_MASK(base));
++
++	__raw_writel(TIMER_CR_ENABLE(timer) |
++		     TIMER_CR_INT(timer) |
++		     TIMER_CR_DOWN(timer),
++		     TIMER_CR(base));
++
++	iounmap(base);
++
++	return 0;
++}
+--- a/arch/arm/plat-fa/Kconfig
++++ b/arch/arm/plat-fa/Kconfig
+@@ -1,3 +1,6 @@
+ if PLAT_FA
+ 
++config PLAT_FA_TIME
++	def_bool n
++
+ endif
+--- a/arch/arm/plat-fa/Makefile
++++ b/arch/arm/plat-fa/Makefile
+@@ -4,6 +4,8 @@
+ 
+ obj-y :=
+ 
++obj-$(CONFIG_PLAT_FA_TIME)	+= time.o
++
+ obj-m :=
+ obj-n :=
+ obj-  :=
diff --git a/target/linux/cns21xx/patches-3.6/005-arm-add-fa-gpio-driver.patch b/target/linux/cns21xx/patches-3.6/005-arm-add-fa-gpio-driver.patch
new file mode 100644
index 0000000000..d7e8e88cc9
--- /dev/null
+++ b/target/linux/cns21xx/patches-3.6/005-arm-add-fa-gpio-driver.patch
@@ -0,0 +1,343 @@
+--- /dev/null
++++ b/arch/arm/plat-fa/gpio.c
+@@ -0,0 +1,283 @@
++/*
++ * Gpiochip and interrupt routines for Faraday FA526 based SoCs
++ *
++ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
++ * Copyright (C) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * Based on plat-mxc/gpio.c:
++ *  MXC GPIO supchip. (c) 2008 Daniel Mack <daniel@caiaq.de>
++ *  Copyright 2008 Juergen Beisert, kernel@pengutronix.de
++ *
++ * 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/spinlock.h>
++
++#include <plat/gpio.h>
++
++#define GPIO_DATA_OUT		0x0
++#define GPIO_DATA_IN		0x4
++#define GPIO_DIR		0x8
++#define GPIO_DATA_SET		0x10
++#define GPIO_DATA_CLR		0x14
++#define GPIO_PULL_EN		0x18
++#define GPIO_PULL_TYPE		0x1C
++#define GPIO_INT_EN		0x20
++#define GPIO_INT_STAT		0x24
++#define GPIO_INT_MASK		0x2C
++#define GPIO_INT_CLR		0x30
++#define GPIO_INT_TYPE		0x34
++#define GPIO_INT_BOTH_EDGE	0x38
++#define GPIO_INT_LEVEL		0x3C
++#define GPIO_DEBOUNCE_EN	0x40
++#define GPIO_DEBOUNCE_PRESCALE	0x44
++
++#define GPIO_REGS_SIZE		0x48
++
++static DEFINE_SPINLOCK(fa_gpio_lock);
++
++static inline struct fa_gpio_chip *to_fgc(struct gpio_chip *chip)
++{
++	return container_of(chip, struct fa_gpio_chip, gpio_chip);
++}
++
++static void _fa_gpio_irq_setenable(struct irq_data *d, int enable)
++{
++	struct fa_gpio_chip *fgc = irq_get_chip_data(d->irq);
++	void __iomem *base = fgc->mem_base;
++	unsigned int gpio = d->irq - fgc->irq_base;
++	unsigned int reg;
++
++	reg = __raw_readl(base + GPIO_INT_EN);
++	reg = (reg & (~(1 << gpio))) | (!!enable << gpio);
++	__raw_writel(reg, base + GPIO_INT_EN);
++}
++
++static void fa_gpio_irq_ack(struct irq_data *d)
++{
++	struct fa_gpio_chip *fgc = irq_get_chip_data(d->irq);
++	unsigned int gpio = d->irq - fgc->irq_base;
++
++	__raw_writel(1 << gpio, fgc->mem_base + GPIO_INT_CLR);
++}
++
++static void fa_gpio_irq_mask(struct irq_data *d)
++{
++	_fa_gpio_irq_setenable(d, 0);
++}
++
++static void fa_gpio_irq_unmask(struct irq_data *d)
++{
++	_fa_gpio_irq_setenable(d, 1);
++}
++
++static int fa_gpio_irq_set_type(struct irq_data *d, unsigned int type)
++{
++	struct fa_gpio_chip *fgc = irq_get_chip_data(d->irq);
++	void __iomem *base = fgc->mem_base;
++	unsigned int gpio = d->irq - fgc->irq_base;
++	unsigned int gpio_mask = 1 << gpio;
++	unsigned int reg_both, reg_level, reg_type;
++
++	reg_type = __raw_readl(base + GPIO_INT_TYPE);
++	reg_level = __raw_readl(base + GPIO_INT_LEVEL);
++	reg_both = __raw_readl(base + GPIO_INT_BOTH_EDGE);
++
++	switch (type) {
++	case IRQ_TYPE_EDGE_BOTH:
++		reg_type &= ~gpio_mask;
++		reg_both |= gpio_mask;
++		break;
++	case IRQ_TYPE_EDGE_RISING:
++		reg_type &= ~gpio_mask;
++		reg_both &= ~gpio_mask;
++		reg_level &= ~gpio_mask;
++		break;
++	case IRQ_TYPE_EDGE_FALLING:
++		reg_type &= ~gpio_mask;
++		reg_both &= ~gpio_mask;
++		reg_level |= gpio_mask;
++		break;
++	case IRQ_TYPE_LEVEL_HIGH:
++		reg_type |= gpio_mask;
++		reg_level &= ~gpio_mask;
++		break;
++	case IRQ_TYPE_LEVEL_LOW:
++		reg_type |= gpio_mask;
++		reg_level |= gpio_mask;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	__raw_writel(reg_type, base + GPIO_INT_TYPE);
++	__raw_writel(reg_level, base + GPIO_INT_LEVEL);
++	__raw_writel(reg_both, base + GPIO_INT_BOTH_EDGE);
++
++	fa_gpio_irq_ack(d);
++
++	return 0;
++}
++
++static void fa_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
++{
++	struct fa_gpio_data *data = irq_get_handler_data(irq);
++	unsigned int chip;
++
++	for (chip = 0; chip < data->nchips; chip++) {
++		struct fa_gpio_chip *fgc = &data->chips[chip];
++		unsigned int status;
++		unsigned int i;
++
++		status = __raw_readl(fgc->mem_base + GPIO_INT_STAT);
++		for (i = fgc->irq_base; status != 0; status >>= 1, i++) {
++			if ((status & 1) == 0)
++				continue;
++
++			BUG_ON(!(irq_desc[i].handle_irq));
++			irq_desc[i].handle_irq(i, &irq_desc[i]);
++		}
++	}
++}
++
++static struct irq_chip fa_gpio_irq_chip = {
++	.name		= "GPIO",
++	.irq_ack	= fa_gpio_irq_ack,
++	.irq_mask	= fa_gpio_irq_mask,
++	.irq_unmask	= fa_gpio_irq_unmask,
++	.irq_set_type	= fa_gpio_irq_set_type,
++};
++
++static void _fa_gpio_set_direction(struct fa_gpio_chip *fgc, unsigned offset,
++				   int is_output)
++{
++	unsigned int reg;
++
++	reg = __raw_readl(fgc->mem_base + GPIO_DIR);
++	if (is_output)
++		reg |= 1 << offset;
++	else
++		reg &= ~(1 << offset);
++	__raw_writel(reg, fgc->mem_base + GPIO_DIR);
++}
++
++static void _fa_gpio_set(struct fa_gpio_chip *fgc, unsigned offset, int value)
++{
++	if (value)
++		__raw_writel(1 << offset, fgc->mem_base + GPIO_DATA_SET);
++	else
++		__raw_writel(1 << offset, fgc->mem_base + GPIO_DATA_CLR);
++}
++
++static void fa_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
++{
++	struct fa_gpio_chip *fgc = to_fgc(chip);
++
++	_fa_gpio_set(fgc, offset, value);
++}
++
++static int fa_gpio_get(struct gpio_chip *chip, unsigned offset)
++{
++	struct fa_gpio_chip *fgc = to_fgc(chip);
++
++	return (__raw_readl(fgc->mem_base + GPIO_DATA_IN) >> offset) & 1;
++}
++
++static int fa_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
++{
++	struct fa_gpio_chip *fgc = to_fgc(chip);
++
++	return fgc->irq_base + offset;
++}
++
++static int fa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
++{
++	struct fa_gpio_chip *fgc = to_fgc(chip);
++	unsigned long flags;
++
++	spin_lock_irqsave(&fa_gpio_lock, flags);
++
++	_fa_gpio_set_direction(fgc, offset, 0);
++
++	spin_unlock_irqrestore(&fa_gpio_lock, flags);
++
++	return 0;
++}
++
++static int fa_gpio_direction_output(struct gpio_chip *chip,
++				    unsigned offset,
++				    int value)
++{
++	struct fa_gpio_chip *fgc = to_fgc(chip);
++	unsigned long flags;
++
++	spin_lock_irqsave(&fa_gpio_lock, flags);
++
++	_fa_gpio_set(fgc, offset, value);
++	_fa_gpio_set_direction(fgc, offset, 1);
++
++	spin_unlock_irqrestore(&fa_gpio_lock, flags);
++
++	return 0;
++}
++
++static int fa_gpio_init_chip(struct fa_gpio_chip *fgc)
++{
++	void __iomem *mem_base;
++	unsigned int i;
++	int err;
++
++	mem_base = ioremap(fgc->map_base, GPIO_REGS_SIZE);
++	if (!mem_base)
++		return -ENXIO;
++
++	fgc->mem_base = mem_base;
++
++	fgc->gpio_chip.direction_input = fa_gpio_direction_input;
++	fgc->gpio_chip.direction_output = fa_gpio_direction_output;
++	fgc->gpio_chip.get = fa_gpio_get;
++	fgc->gpio_chip.set = fa_gpio_set;
++	fgc->gpio_chip.to_irq = fa_gpio_to_irq;
++
++	/* disable, unmask and clear all interrupts */
++	__raw_writel(0x0, mem_base + GPIO_INT_EN);
++	__raw_writel(0x0, mem_base + GPIO_INT_MASK);
++	__raw_writel(~0x0, mem_base + GPIO_INT_CLR);
++
++	for (i = fgc->irq_base;
++	     i < fgc->irq_base + fgc->gpio_chip.ngpio; i++) {
++		irq_set_chip(i, &fa_gpio_irq_chip);
++		irq_set_chip_data(i, fgc);
++		irq_set_handler(i, handle_edge_irq);
++		set_irq_flags(i, IRQF_VALID);
++	}
++
++	err = gpiochip_add(&fgc->gpio_chip);
++	if (err)
++		goto unmap;
++
++	return 0;
++
++ unmap:
++	iounmap(fgc->mem_base);
++	return err;
++}
++
++void __init fa_gpio_init(struct fa_gpio_data *data)
++{
++	unsigned int i;
++
++	for (i = 0; i < data->nchips; i++) {
++		int err;
++
++		err = fa_gpio_init_chip(&data->chips[i]);
++		if (WARN(err, "GPIO init failed\n"))
++			return;
++	}
++
++	irq_set_chained_handler(data->irq, fa_gpio_irq_handler);
++	irq_set_handler_data(data->irq, data);
++}
+--- /dev/null
++++ b/arch/arm/plat-fa/include/plat/gpio.h
+@@ -0,0 +1,33 @@
++/*
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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 _FA_GPIO_H
++#define _FA_GPIO_H
++
++#include <linux/init.h>
++#include <linux/gpio.h>
++#include <linux/irq.h>
++#include <linux/io.h>
++
++struct fa_gpio_chip {
++	struct gpio_chip	gpio_chip;
++	unsigned int		map_base;
++	unsigned int		irq_base;
++
++	void __iomem		*mem_base;
++};
++
++struct fa_gpio_data {
++	struct fa_gpio_chip	*chips;
++	unsigned int		nchips;
++	unsigned int		irq;
++};
++
++void __init fa_gpio_init(struct fa_gpio_data *data);
++
++#endif /* _FA_GPIO_H */
+--- a/arch/arm/plat-fa/Kconfig
++++ b/arch/arm/plat-fa/Kconfig
+@@ -1,5 +1,8 @@
+ if PLAT_FA
+ 
++config PLAT_FA_GPIO
++	def_bool n
++
+ config PLAT_FA_TIME
+ 	def_bool n
+ 
+--- a/arch/arm/plat-fa/Makefile
++++ b/arch/arm/plat-fa/Makefile
+@@ -4,6 +4,7 @@
+ 
+ obj-y :=
+ 
++obj-$(CONFIG_PLAT_FA_GPIO)	+= gpio.o
+ obj-$(CONFIG_PLAT_FA_TIME)	+= time.o
+ 
+ obj-m :=
diff --git a/target/linux/cns21xx/patches-3.6/006-arm-add-fa-watchdog-driver.patch b/target/linux/cns21xx/patches-3.6/006-arm-add-fa-watchdog-driver.patch
new file mode 100644
index 0000000000..948734f749
--- /dev/null
+++ b/target/linux/cns21xx/patches-3.6/006-arm-add-fa-watchdog-driver.patch
@@ -0,0 +1,458 @@
+--- a/drivers/watchdog/Kconfig
++++ b/drivers/watchdog/Kconfig
+@@ -352,6 +352,13 @@ config IMX2_WDT
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called imx2_wdt.
+ 
++config FA_WATCHDOG
++	tristate "Faraday watchdog"
++	depends on ARCH_GEMINI
++	help
++	  Say Y here if you want support for the built-in watchdog timer
++	  found in some Faraday FA526 based SoCs.
++
+ # AVR32 Architecture
+ 
+ config AT32AP700X_WDT
+--- a/drivers/watchdog/Makefile
++++ b/drivers/watchdog/Makefile
+@@ -52,6 +52,7 @@ obj-$(CONFIG_STMP3XXX_WATCHDOG) += stmp3
+ obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o
+ obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
+ obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
++obj-$(CONFIG_FA_WATCHDOG) += fa_wdt.o
+ 
+ # AVR32 Architecture
+ obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
+--- /dev/null
++++ b/drivers/watchdog/fa_wdt.c
+@@ -0,0 +1,413 @@
++/*
++ *  Watchdog driver for SoCs based on the Faraday FA526 core
++ *
++ *  Copyright (C) 2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
++ *  Copyright (C) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * 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/module.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/fs.h>
++#include <linux/notifier.h>
++#include <linux/reboot.h>
++#include <linux/uaccess.h>
++#include <linux/miscdevice.h>
++#include <linux/platform_device.h>
++#include <linux/watchdog.h>
++#include <linux/slab.h>
++#include <linux/fa_wdt.h>
++
++#define FA_WDCOUNTER		0x0
++#define FA_WDLOAD		0x4
++#define FA_WDRESTART		0x8
++
++#define WDRESTART_MAGIC		0x5AB9
++
++#define FA_WDCR			0xC
++
++#define WDCR_CLOCK_5MHZ		(1 << 4)
++#define WDCR_SYS_RST		(1 << 1)
++#define WDCR_ENABLE		(1 << 0)
++
++#define WDT_DEFAULT_TIMEOUT	13
++
++/* status bits */
++#define WDT_ACTIVE		0
++#define WDT_OK_TO_CLOSE		1
++
++static unsigned int timeout = WDT_DEFAULT_TIMEOUT;
++static int nowayout = WATCHDOG_NOWAYOUT;
++
++static DEFINE_SPINLOCK(fa_wdt_lock);
++
++static struct platform_device *fa_wdt_dev;
++
++struct fa_wdt_struct {
++	struct resource		*res;
++	struct device		*dev;
++	void __iomem		*base;
++	unsigned long		status;
++	unsigned int		clock;
++	unsigned int		max_timeout;
++};
++
++static const struct watchdog_info fa_wdt_info = {
++	.identity	= "Faraday watchdog",
++	.options	= WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING |
++			  WDIOF_SETTIMEOUT,
++};
++
++/* Disable the watchdog. */
++static void fa_wdt_stop(struct fa_wdt_struct *fa_wdt)
++{
++	spin_lock(&fa_wdt_lock);
++
++	__raw_writel(0, fa_wdt->base + FA_WDCR);
++
++	clear_bit(WDT_ACTIVE, &fa_wdt->status);
++
++	spin_unlock(&fa_wdt_lock);
++}
++
++/* Service the watchdog */
++static void fa_wdt_service(struct fa_wdt_struct *fa_wdt)
++{
++	__raw_writel(WDRESTART_MAGIC, fa_wdt->base + FA_WDRESTART);
++}
++
++/* Enable and reset the watchdog. */
++static void fa_wdt_start(struct fa_wdt_struct *fa_wdt)
++{
++	spin_lock(&fa_wdt_lock);
++
++	__raw_writel(timeout * fa_wdt->clock,
++		     fa_wdt->base + FA_WDLOAD);
++
++	fa_wdt_service(fa_wdt);
++
++	/* set clock before enabling */
++	__raw_writel(WDCR_CLOCK_5MHZ | WDCR_SYS_RST,
++			fa_wdt->base + FA_WDCR);
++
++	__raw_writel(WDCR_CLOCK_5MHZ | WDCR_SYS_RST | WDCR_ENABLE,
++			fa_wdt->base + FA_WDCR);
++
++	set_bit(WDT_ACTIVE, &fa_wdt->status);
++
++	spin_unlock(&fa_wdt_lock);
++}
++
++/* Watchdog device is opened, and watchdog starts running. */
++static int fa_wdt_open(struct inode *inode, struct file *file)
++{
++	struct fa_wdt_struct *fa_wdt = platform_get_drvdata(fa_wdt_dev);
++
++	if (test_bit(WDT_ACTIVE, &fa_wdt->status))
++		return -EBUSY;
++
++	file->private_data = fa_wdt;
++
++	fa_wdt_start(fa_wdt);
++
++	return nonseekable_open(inode, file);
++}
++
++/* Close the watchdog device. */
++static int fa_wdt_close(struct inode *inode, struct file *file)
++{
++	struct fa_wdt_struct *fa_wdt = file->private_data;
++
++	/* Disable the watchdog if possible */
++	if (test_bit(WDT_OK_TO_CLOSE, &fa_wdt->status))
++		fa_wdt_stop(fa_wdt);
++	else
++		dev_warn(fa_wdt->dev, "Device closed unexpectedly - timer will not stop\n");
++
++	return 0;
++}
++
++/* Handle commands from user-space. */
++static long fa_wdt_ioctl(struct file *file, unsigned int cmd,
++			 unsigned long arg)
++{
++	struct fa_wdt_struct *fa_wdt = file->private_data;
++
++	int value;
++
++	switch (cmd) {
++	case WDIOC_KEEPALIVE:
++		fa_wdt_service(fa_wdt);
++		return 0;
++
++	case WDIOC_GETSUPPORT:
++		return copy_to_user((struct watchdog_info *)arg, &fa_wdt_info,
++			sizeof(fa_wdt_info)) ? -EFAULT : 0;
++
++	case WDIOC_SETTIMEOUT:
++		if (get_user(value, (int *)arg))
++			return -EFAULT;
++
++		if ((value < 1) || (value > fa_wdt->max_timeout))
++			return -EINVAL;
++
++		timeout = value;
++
++		/* restart wdt to use new timeout */
++		fa_wdt_stop(fa_wdt);
++		fa_wdt_start(fa_wdt);
++
++		/* Fall through */
++	case WDIOC_GETTIMEOUT:
++		return put_user(timeout, (int *)arg);
++
++	case WDIOC_GETTIMELEFT:
++		value = __raw_readl(fa_wdt->base + FA_WDCOUNTER);
++		return put_user(value / fa_wdt->clock, (int *)arg);
++
++	default:
++		return -ENOTTY;
++	}
++}
++
++/* Refresh the watchdog whenever device is written to. */
++static ssize_t fa_wdt_write(struct file *file, const char *data,
++			    size_t len, loff_t *ppos)
++{
++	struct fa_wdt_struct *fa_wdt = file->private_data;
++
++	if (len) {
++		if (!nowayout) {
++			size_t i;
++
++			clear_bit(WDT_OK_TO_CLOSE, &fa_wdt->status);
++			for (i = 0; i != len; i++) {
++				char c;
++
++				if (get_user(c, data + i))
++					return -EFAULT;
++				if (c == 'V')
++					set_bit(WDT_OK_TO_CLOSE,
++						&fa_wdt->status);
++			}
++		}
++		fa_wdt_service(fa_wdt);
++	}
++
++	return len;
++}
++
++static int fa_wdt_notify_sys(struct notifier_block *this,
++			     unsigned long code, void *unused)
++{
++	struct fa_wdt_struct *fa_wdt = platform_get_drvdata(fa_wdt_dev);
++
++	if (code == SYS_DOWN || code == SYS_HALT)
++		fa_wdt_stop(fa_wdt);
++
++	return NOTIFY_DONE;
++}
++
++static struct notifier_block fa_wdt_notifier = {
++	.notifier_call = fa_wdt_notify_sys,
++};
++
++static const struct file_operations fa_wdt_fops = {
++	.owner		= THIS_MODULE,
++	.llseek		= no_llseek,
++	.unlocked_ioctl	= fa_wdt_ioctl,
++	.open		= fa_wdt_open,
++	.release	= fa_wdt_close,
++	.write		= fa_wdt_write,
++};
++
++static struct miscdevice fa_wdt_miscdev = {
++	.minor		= WATCHDOG_MINOR,
++	.name		= "watchdog",
++	.fops		= &fa_wdt_fops,
++};
++
++static void fa_wdt_shutdown(struct platform_device *pdev)
++{
++	struct fa_wdt_struct *fa_wdt = platform_get_drvdata(pdev);
++
++	fa_wdt_stop(fa_wdt);
++}
++
++static int __devinit fa_wdt_probe(struct platform_device *pdev)
++{
++	int ret;
++	int res_size;
++	struct resource *res;
++	void __iomem *base;
++	struct fa_wdt_struct *fa_wdt;
++	struct fa_wdt_platform_data *pdata;
++
++	pdata = pdev->dev.platform_data;
++	if (!pdata) {
++		dev_err(&pdev->dev, "no platform data specified\n");
++		return -EINVAL;
++	}
++
++	if (!pdata->clock) {
++		dev_err(&pdev->dev, "invalid clock value\n");
++		return -EINVAL;
++	}
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		dev_err(&pdev->dev, "can't get device resources\n");
++		return -ENODEV;
++	}
++
++	res_size = resource_size(res);
++	if (!request_mem_region(res->start, res_size, res->name)) {
++		dev_err(&pdev->dev, "can't allocate %d bytes at %d address\n",
++			res_size, res->start);
++		return -ENOMEM;
++	}
++
++	base = ioremap(res->start, res_size);
++	if (!base) {
++		dev_err(&pdev->dev, "ioremap failed\n");
++		ret = -EIO;
++		goto fail0;
++	}
++
++	fa_wdt = kzalloc(sizeof(struct fa_wdt_struct), GFP_KERNEL);
++	if (!fa_wdt) {
++		dev_err(&pdev->dev, "can't allocate interface\n");
++		ret = -ENOMEM;
++		goto fail1;
++	}
++
++	/* Setup fa_wdt driver structure */
++	fa_wdt->base = base;
++	fa_wdt->res = res;
++	fa_wdt->dev = &pdev->dev;
++	fa_wdt->clock = pdata->clock;
++	fa_wdt->max_timeout = 0xffffffffU / pdata->clock;
++
++	/* Set up platform driver data */
++	platform_set_drvdata(pdev, fa_wdt);
++	fa_wdt_dev = pdev;
++
++	if (fa_wdt_miscdev.parent) {
++		ret = -EBUSY;
++		goto fail2;
++	}
++
++	ret = register_reboot_notifier(&fa_wdt_notifier);
++	if (ret)
++		goto fail2;
++
++	fa_wdt_miscdev.parent = &pdev->dev;
++
++	ret = misc_register(&fa_wdt_miscdev);
++	if (ret)
++		goto fail3;
++
++	return 0;
++
++fail3:
++	unregister_reboot_notifier(&fa_wdt_notifier);
++fail2:
++	platform_set_drvdata(pdev, NULL);
++	kfree(fa_wdt);
++fail1:
++	iounmap(base);
++fail0:
++	release_mem_region(res->start, res_size);
++
++	return ret;
++}
++
++static int __devexit fa_wdt_remove(struct platform_device *pdev)
++{
++	struct fa_wdt_struct *fa_wdt = platform_get_drvdata(pdev);
++
++	platform_set_drvdata(pdev, NULL);
++	misc_deregister(&fa_wdt_miscdev);
++	unregister_reboot_notifier(&fa_wdt_notifier);
++	fa_wdt_dev = NULL;
++	iounmap(fa_wdt->base);
++	release_mem_region(fa_wdt->res->start, resource_size(fa_wdt->res));
++
++	kfree(fa_wdt);
++
++	return 0;
++}
++
++#ifdef CONFIG_PM
++static int fa_wdt_suspend(struct platform_device *pdev, pm_message_t message)
++{
++	struct fa_wdt_struct *fa_wdt = platform_get_drvdata(pdev);
++	unsigned int reg;
++
++	reg = __raw_readw(fa_wdt->base + FA_WDCR);
++	reg &= ~(WDCR_WDENABLE);
++	__raw_writel(reg, fa_wdt->base + FA_WDCR);
++
++	return 0;
++}
++
++static int fa_wdt_resume(struct platform_device *pdev)
++{
++	struct fa_wdt_struct *fa_wdt = platform_get_drvdata(pdev);
++	unsigned int reg;
++
++	if (fa_wdt->status) {
++		reg = __raw_readw(fa_wdt->base + FA_WDCR);
++		reg |= WDCR_WDENABLE;
++		__raw_writel(reg, fa_wdt->base + FA_WDCR);
++	}
++
++	return 0;
++}
++#else
++#define fa_wdt_suspend	NULL
++#define fa_wdt_resume	NULL
++#endif
++
++static struct platform_driver fa_wdt_driver = {
++	.probe		= fa_wdt_probe,
++	.remove		= __devexit_p(fa_wdt_remove),
++	.shutdown	= fa_wdt_shutdown,
++	.suspend	= fa_wdt_suspend,
++	.resume		= fa_wdt_resume,
++	.driver		= {
++		.name	= "fa-wdt",
++		.owner	= THIS_MODULE,
++	},
++};
++
++static int __init fa_wdt_init(void)
++{
++	return platform_driver_probe(&fa_wdt_driver, fa_wdt_probe);
++}
++
++static void __exit fa_wdt_exit(void)
++{
++	platform_driver_unregister(&fa_wdt_driver);
++}
++
++module_init(fa_wdt_init);
++module_exit(fa_wdt_exit);
++
++module_param(timeout, uint, 0);
++MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds");
++
++module_param(nowayout, int, 0);
++MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
++
++MODULE_AUTHOR("Paulius Zaleckas");
++MODULE_AUTHOR("Gabor Juhos");
++MODULE_DESCRIPTION("Watchdog driver for Faraday FA526 based SoCs");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
++MODULE_ALIAS("platform:fa-wdt");
+--- /dev/null
++++ b/include/linux/fa_wdt.h
+@@ -0,0 +1,13 @@
++/*
++ * Platform data definition for the Faraday watchdog driver
++ */
++
++#ifndef _FA_WDT_H
++#define _FA_WDT_H
++
++struct fa_wdt_platform_data {
++	unsigned int	clock;
++};
++
++#endif /* _FA_WDT_H */
++
diff --git a/target/linux/cns21xx/patches-3.6/100-cns21xx-core.patch b/target/linux/cns21xx/patches-3.6/100-cns21xx-core.patch
new file mode 100644
index 0000000000..b386045faa
--- /dev/null
+++ b/target/linux/cns21xx/patches-3.6/100-cns21xx-core.patch
@@ -0,0 +1,2050 @@
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -177,6 +177,11 @@ config NEED_RET_TO_USER
+ config ARCH_MTD_XIP
+ 	bool
+ 
++config ARM_L1_CACHE_SHIFT_4
++	bool
++	help
++	  Setting ARM L1 cache line size to 16 bytes.
++
+ config VECTORS_BASE
+ 	hex
+ 	default 0xffff0000 if MMU || CPU_HIGH_VECTOR
+@@ -380,6 +385,15 @@ config ARCH_HIGHBANK
+ 	help
+ 	  Support for the Calxeda Highbank SoC based boards.
+ 
++config ARCH_CNS21XX
++	bool "Cavium Networks CNS21xx family"
++	select CPU_FA526
++	select PLAT_FA
++	select PLAT_FA_TIME
++	select ARM_L1_CACHE_SHIFT_4
++	help
++	  Support for Cavium Networks CNS21xx family.
++
+ config ARCH_CLPS711X
+ 	bool "Cirrus Logic CLPS711x/EP721x/EP731x-based"
+ 	select CPU_ARM720T
+@@ -1041,6 +1055,8 @@ source "arch/arm/mach-davinci/Kconfig"
+ 
+ source "arch/arm/mach-dove/Kconfig"
+ 
++source "arch/arm/mach-cns21xx/Kconfig"
++
+ source "arch/arm/mach-ep93xx/Kconfig"
+ 
+ source "arch/arm/mach-footbridge/Kconfig"
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/Kconfig
+@@ -0,0 +1,6 @@
++if ARCH_CNS21XX
++
++menu "Cavium Networks CNS21xx based machines"
++endmenu
++
++endif
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/Makefile
+@@ -0,0 +1,10 @@
++#
++# Makefile for the linux kernel.
++#
++
++# Object file lists.
++
++obj-y		:= core.o irq.o mm.o time.o
++
++# machine specific files
++
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/Makefile.boot
+@@ -0,0 +1,3 @@
++   zreladdr-y	+= 0x00008000
++params_phys-y	:= 0x00000100
++initrd_phys-y	:= 0x00C00000
+--- a/arch/arm/Makefile
++++ b/arch/arm/Makefile
+@@ -137,6 +137,7 @@ textofs-$(CONFIG_ARCH_MSM8960) := 0x0020
+ # by CONFIG_* macro name.
+ machine-$(CONFIG_ARCH_AT91)		:= at91
+ machine-$(CONFIG_ARCH_BCMRING)		:= bcmring
++machine-$(CONFIG_ARCH_CNS21XX)		:= cns21xx
+ machine-$(CONFIG_ARCH_CLPS711X)		:= clps711x
+ machine-$(CONFIG_ARCH_CNS3XXX)		:= cns3xxx
+ machine-$(CONFIG_ARCH_DAVINCI)		:= davinci
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/common.h
+@@ -0,0 +1,19 @@
++/*
++ *  Copyright (c) 2008 Cavium Networks
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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 _MACH_CNS21XX_COMMON_H
++#define _MACH_CNS21XX_COMMON_H
++
++void cns21xx_restart(char mode, const char *cmd);
++void cns21xx_map_io(void);
++void cns21xx_init_irq(void);
++
++extern struct sys_timer cns21xx_timer;
++
++#endif /* _MACH_CNS21XX_COMMON_H */
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/mm.c
+@@ -0,0 +1,170 @@
++/*
++ *  Copyright (c) 2008 Cavium Networks
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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/mm.h>
++#include <linux/init.h>
++
++#include <asm/mach/map.h>
++
++#include <mach/hardware.h>
++#include <mach/cns21xx.h>
++
++#include "common.h"
++
++/*
++ * Standard IO mapping
++ */
++static struct map_desc cns21xx_io_desc[] __initdata = {
++	{
++		.virtual	= CNS21XX_FLASH_BANK0_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_FLASH_BANK0_BASE),
++		.length		= SZ_256M,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_IDE_DEVICE_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_IDE_DEVICE_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_GDMAC_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_GDMAC_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_NIC_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_NIC_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_SPI_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_SPI_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_PCM_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_PCM_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_I2C_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_I2C_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_I2S_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_I2S_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_DDRC_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_DDRC_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_SMC_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_SMC_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_IDE_CTRL_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_IDE_CTRL_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_MISC_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_MISC_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_CPM_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_CPM_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_UART0_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_UART0_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_UART1_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_UART1_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_TIMER_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_TIMER_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_WDT_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_WDT_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_RTC_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_RTC_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_GPIOA_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_GPIOA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_GPIOB_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_GPIOB_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_PCI_CFGDATA_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_PCI_CFGDATA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_PCI_CFGADDR_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_PCI_CFGADDR_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_OHCI_CONFIG_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_OHCI_CONFIG_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_OHCI_CTRL_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_OHCI_CTRL_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_EHCI_CONFIG_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_EHCI_CONFIG_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_EHCI_CTRL_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_EHCI_CTRL_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_USB_DEVICE_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_USB_DEVICE_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}, {
++		.virtual	= CNS21XX_INTC_BASE_VIRT,
++		.pfn		= __phys_to_pfn(CNS21XX_INTC_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE
++	}
++};
++
++void __init cns21xx_map_io(void)
++{
++	iotable_init(cns21xx_io_desc, ARRAY_SIZE(cns21xx_io_desc));
++}
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/include/mach/hardware.h
+@@ -0,0 +1,20 @@
++/*
++ *  Copyright (c) 2008 Cavium Networks
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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 _CNS21XX_HARDWARE_H
++#define _CNS21XX_HARDWARE_H
++
++#ifndef __ASSEMBLY__
++extern unsigned long cns21xx_get_pll_freq(void);
++extern unsigned long cns21xx_get_cpu_freq(void);
++extern unsigned long cns21xx_get_ahb_freq(void);
++extern unsigned long cns21xx_get_apb_freq(void);
++#endif
++
++#endif /* _CNS21XX_HARDWARE_H */
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/include/mach/debug-macro.S
+@@ -0,0 +1,25 @@
++/*
++ *  Copyright (c) 2008 Cavium Networks
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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 <mach/cns21xx.h>
++
++/* TODO: make it configurable */
++#define CNS21XX_DEBUG_UART_BASE		CNS21XX_UART0_BASE
++#define CNS21XX_DEBUG_UART_BASE_VIRT	CNS21XX_UART0_BASE_VIRT
++
++	.macro	addruart, rp, rv
++	mov	\rp, #(CNS21XX_DEBUG_UART_BASE)				@ physical
++	mov	\rv, #(CNS21XX_DEBUG_UART_BASE_VIRT & 0xff000000)	@virtual
++	orr	\rv, \rv, #(CNS21XX_DEBUG_UART_BASE_VIRT & 0x00ff0000)
++	orr	\rv, \rv, #(CNS21XX_DEBUG_UART_BASE_VIRT & 0x0000ff00)
++	orr	\rv, \rv, #(CNS21XX_DEBUG_UART_BASE_VIRT & 0x000000ff)
++	.endm
++
++#define UART_SHIFT 2
++#include <asm/hardware/debug-8250.S>
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/include/mach/entry-macro.S
+@@ -0,0 +1,39 @@
++/*
++ *  Copyright (c) 2008 Cavium Networks
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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 <mach/cns21xx.h>
++#include <mach/irqs.h>
++
++#define INTC_IRQ_STATUS	0x1c
++
++	.macro	disable_fiq
++	.endm
++
++	.macro  get_irqnr_preamble, base, tmp
++	.endm
++
++	.macro  arch_ret_to_user, tmp1, tmp2
++	.endm
++
++	.macro get_irqnr_and_base, irqnr, irqstat, base, tmp
++	ldr		\base, =(CNS21XX_INTC_BASE_VIRT + INTC_IRQ_STATUS)
++	ldr		\irqstat, [\base]
++	mov		\irqnr, #0
++9001:
++	tst		\irqstat, #1
++	bne		9002f
++	add		\irqnr, \irqnr, #1
++	mov		\irqstat, \irqstat, lsr #1
++	cmp		\irqnr, #CNS21XX_NR_INTC_IRQS
++	bcc		9001b
++9002:
++	.endm
++
++	.macro irq_prio_table
++	.endm
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/include/mach/io.h
+@@ -0,0 +1,18 @@
++/*
++ *  Copyright (c) 2008 Cavium Networks
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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 _CNS21XX_IO_H
++#define _CNS21XX_IO_H
++
++#define IO_SPACE_LIMIT	0xffffffff
++
++#define __io(p)		__typesafe_io(p)
++#define __mem_pci(a)	(a)
++
++#endif /* _CNS21XX_IO_H */
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/include/mach/irqs.h
+@@ -0,0 +1,53 @@
++/*
++ *  Copyright (c) 2008 Cavium Networks
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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 _CNS21XX_IRQS_H
++#define _CNS21XX_IRQS_H
++
++#define CNS21XX_IRQ_TIMER1	0
++#define CNS21XX_IRQ_TIMER2	1
++#define CNS21XX_IRQ_CPM		2
++#define CNS21XX_IRQ_WDT		3
++#define CNS21XX_IRQ_GPIO	4
++#define CNS21XX_IRQ_PCI_INTA	5
++#define CNS21XX_IRQ_PCI_INTB	6
++#define CNS21XX_IRQ_PCI_BROKEN	7
++#define CNS21XX_IRQ_AHB2PCI	8
++#define CNS21XX_IRQ_UART0	9
++#define CNS21XX_IRQ_UART1	10
++#define CNS21XX_IRQ_GDMAC_TC	11
++#define CNS21XX_IRQ_GDMAC_ERR	12
++#define CNS21XX_IRQ_PCMCIA	13
++#define CNS21XX_IRQ_RTC		14
++#define CNS21XX_IRQ_PCM		15
++#define CNS21XX_IRQ_USB_DEVICE	16
++#define CNS21XX_IRQ_IDE		17
++#define CNS21XX_IRQ_NIC_STATUS	18
++#define CNS21XX_IRQ_NIC_TXTC	19
++#define CNS21XX_IRQ_NIC_RXRC	20
++#define CNS21XX_IRQ_NIC_TXQE	21
++#define CNS21XX_IRQ_NIC_RXQF	22
++#define CNS21XX_IRQ_OHCI	23
++#define CNS21XX_IRQ_EHCI	24
++#define CNS21XX_IRQ_I2S		25
++#define CNS21XX_IRQ_SPI		26
++#define CNS21XX_IRQ_I2C		27
++#define CNS21XX_IRQ_USB_VBUS	28
++#define CNS21XX_IRQ_EXT_29	29
++#define CNS21XX_IRQ_EXT_30	30
++#define CNS21XX_IRQ_HSDMAC	31
++
++#define CNS21XX_GPIO_IRQ_BASE	32
++
++#define CNS21XX_NR_INTC_IRQS	32
++#define CNS21XX_NR_GPIO_IRQS	64
++
++#define NR_IRQS			96
++
++#endif /* _CNS21XX_IRQS_H */
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/include/mach/timex.h
+@@ -0,0 +1,15 @@
++/*
++ *  Copyright (c) 2008 Cavium Networks
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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 _CNS21XX_TIMEX_H
++#define _CNS21XX_TIMEX_H
++
++#define CLOCK_TICK_RATE		43750000
++
++#endif /* _CNS21XX_TIMEX_H */
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/include/mach/uncompress.h
+@@ -0,0 +1,40 @@
++/*
++ *  Copyright (c) 2008 Cavium Networks
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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 _CNS21XX_UNCOMPRESS_H
++#define _CNS21XX_UNCOMPRESS_H
++
++#define UART_BASE	0x78000000
++
++#define UART_REG(offs)	(*((volatile unsigned int *)(UART_BASE + offs)))
++
++#define UART_THR	UART_REG(0x00)
++#define UART_LSR	UART_REG(0x14)
++#define THR_EMPTY	(1 << 5)
++
++#define UART_THR_EMPTY()     (((UART_LSR) & THR_EMPTY) == (THR_EMPTY))
++
++static void putc(int c)
++{
++	if (c != 0) {
++		while (!UART_THR_EMPTY())
++			barrier();
++
++		UART_THR = (int)(c & 0xFF);
++	}
++}
++
++static inline void flush(void)
++{
++}
++
++#define arch_decomp_setup()
++#define arch_decomp_wdog()
++
++#endif /* _CNS21XX_UNCOMPRESS_H */
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/include/mach/system.h
+@@ -0,0 +1,30 @@
++/*
++ *  Copyright (c) 2008 Cavium Networks
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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 _CNS21XX_SYSTEM_H
++#define _CNS21XX_SYSTEM_H
++
++#include <mach/cns21xx.h>
++#include <mach/cns21xx_powermgmt.h>
++
++static inline void arch_idle(void)
++{
++	/*
++	 * Because of broken hardware we have to enable interrupts or the CPU
++	 * will never wakeup... Acctualy it is not very good to enable
++	 * interrupts here since scheduler can miss a tick, but there is
++	 * no other way around this. Platforms that needs it for power saving
++	 * should call enable_hlt() in init code, since by default it is
++	 * disabled.
++	 */
++	local_irq_enable();
++	cpu_do_idle();
++}
++
++#endif /*  _CNS21XX_SYSTEM_H */
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/irq.c
+@@ -0,0 +1,176 @@
++/*
++ *  Copyright (c) 2008 Cavium Networks
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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/init.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++
++#include <asm/system_misc.h>
++
++#include <mach/cns21xx.h>
++
++#define	INTC_INTERRUPT_RAW_STATUS_REG		0x000
++#define	INTC_EDGE_INTERRUPT_SOURCE_CLEAR_REG	0x004
++#define	INTC_INTERRUPT_MASK_REG			0x008
++#define	INTC_INTERRUPT_MASK_CLEAR_REG		0x00c
++#define	INTC_INTERRUPT_TRIGGER_MODE_REG		0x010
++#define	INTC_INTERRUPT_TRIGGER_LEVEL_REG	0x014
++#define	INTC_FIQ_SELECT_REG			0x018
++#define	INTC_IRQ_STATUS_REG			0x01c
++#define	INTC_FIQ_STATUS_REG			0x020
++#define	INTC_SOFTWARE_INTERRUPT_REG		0x024
++#define	INTC_SOFTWARE_INTERRUPT_CLEAR_REG	0x028
++#define	INTC_SOFTWARE_PRIORITY_MASK_REG		0x02c
++#define	INTC_POWER_MANAGEMENT_INTERRUPT_REG	0x034
++
++#define	INTC_VECTOR_ADDRESS_REG(_x)		((_x) + 0x040)
++#define	INTC_PRIORITY_REG(_x)			((_x) + 0x0c0)
++#define	INTC_IRQ_VECTOR_ADDRESS_REG		0x140
++#define	INTC_VECTOR_INTERRUPT_ENABLE_REG	0x144
++
++#define INTC_SIZE				0x148
++
++static unsigned int cns21xx_irq_types[CNS21XX_NR_INTC_IRQS] = {
++	[CNS21XX_IRQ_TIMER1]	= IRQ_TYPE_EDGE_RISING,
++	[CNS21XX_IRQ_TIMER2]	= IRQ_TYPE_EDGE_RISING,
++	[CNS21XX_IRQ_CPM]	= IRQ_TYPE_EDGE_FALLING,
++	[CNS21XX_IRQ_WDT]	= IRQ_TYPE_EDGE_RISING,
++	[CNS21XX_IRQ_GPIO]	= IRQ_TYPE_NONE,
++	[CNS21XX_IRQ_PCI_INTA]	= IRQ_TYPE_LEVEL_LOW,
++	[CNS21XX_IRQ_PCI_INTB]	= IRQ_TYPE_LEVEL_LOW,
++	[CNS21XX_IRQ_PCI_BROKEN] = IRQ_TYPE_LEVEL_HIGH,
++	[CNS21XX_IRQ_AHB2PCI]	= IRQ_TYPE_LEVEL_HIGH,
++	[CNS21XX_IRQ_UART0]	= IRQ_TYPE_LEVEL_HIGH,
++	[CNS21XX_IRQ_UART1]	= IRQ_TYPE_LEVEL_HIGH,
++	[CNS21XX_IRQ_GDMAC_TC]	= IRQ_TYPE_LEVEL_HIGH,
++	[CNS21XX_IRQ_GDMAC_ERR]	= IRQ_TYPE_LEVEL_HIGH,
++	[CNS21XX_IRQ_PCMCIA]	= IRQ_TYPE_NONE,
++	[CNS21XX_IRQ_RTC]	= IRQ_TYPE_LEVEL_HIGH,
++	[CNS21XX_IRQ_PCM]	= IRQ_TYPE_LEVEL_LOW,
++	[CNS21XX_IRQ_USB_DEVICE] = IRQ_TYPE_LEVEL_LOW,
++	[CNS21XX_IRQ_IDE]	= IRQ_TYPE_LEVEL_HIGH,
++	[CNS21XX_IRQ_NIC_STATUS] = IRQ_TYPE_LEVEL_HIGH,
++	[CNS21XX_IRQ_NIC_TXTC]	= IRQ_TYPE_EDGE_RISING,
++	[CNS21XX_IRQ_NIC_RXRC]	= IRQ_TYPE_EDGE_RISING,
++	[CNS21XX_IRQ_NIC_TXQE]	= IRQ_TYPE_EDGE_RISING,
++	[CNS21XX_IRQ_NIC_RXQF]	= IRQ_TYPE_EDGE_RISING,
++	[CNS21XX_IRQ_OHCI]	= IRQ_TYPE_LEVEL_LOW,
++	[CNS21XX_IRQ_EHCI]	= IRQ_TYPE_LEVEL_LOW,
++	[CNS21XX_IRQ_I2S]	= IRQ_TYPE_LEVEL_LOW,
++	[CNS21XX_IRQ_SPI]	= IRQ_TYPE_LEVEL_LOW,
++	[CNS21XX_IRQ_I2C]	= IRQ_TYPE_LEVEL_LOW,
++	[CNS21XX_IRQ_USB_VBUS]	= IRQ_TYPE_EDGE_RISING,
++	[CNS21XX_IRQ_EXT_29]	= IRQ_TYPE_NONE,
++	[CNS21XX_IRQ_EXT_30]	= IRQ_TYPE_NONE,
++	[CNS21XX_IRQ_HSDMAC]	= IRQ_TYPE_EDGE_RISING,
++};
++
++static void __iomem *cns21xx_intc_base;
++
++static inline void cns21xx_intc_writel(u32 val, unsigned int reg)
++{
++	__raw_writel(val, cns21xx_intc_base + reg);
++}
++
++static inline u32 cns21xx_intc_readl(unsigned int reg)
++{
++	return __raw_readl(cns21xx_intc_base + reg);
++}
++
++static void cns21xx_irq_ack(struct irq_data *d)
++{
++	cns21xx_intc_writel(1 << d->irq, INTC_EDGE_INTERRUPT_SOURCE_CLEAR_REG);
++}
++
++static void cns21xx_irq_mask(struct irq_data *d)
++{
++	cns21xx_intc_writel(1 << d->irq, INTC_INTERRUPT_MASK_REG);
++}
++
++static void cns21xx_irq_unmask(struct irq_data *d)
++{
++	cns21xx_intc_writel(1 << d->irq, INTC_INTERRUPT_MASK_CLEAR_REG);
++}
++
++static struct irq_chip cns21xx_irq_chip = {
++	.name	= "INTC",
++	.irq_ack = cns21xx_irq_ack,
++	.irq_mask = cns21xx_irq_mask,
++	.irq_unmask = cns21xx_irq_unmask,
++};
++
++static struct resource cns21xx_intc_resource = {
++	.name	= "INTC",
++	.flags	= IORESOURCE_MEM,
++	.start	= CNS21XX_INTC_BASE,
++	.end	= CNS21XX_INTC_BASE + INTC_SIZE - 1,
++};
++
++void __init cns21xx_init_irq(void)
++{
++	unsigned int mode = 0;
++	unsigned int level = 0;
++	int i;
++
++	/*
++	 * Disable arch_idle() by default since it is buggy
++	 * For more info see arch/arm/mach-cns21xx/include/mach/system.h
++	 */
++	disable_hlt();
++
++	request_resource(&iomem_resource, &cns21xx_intc_resource);
++	cns21xx_intc_base = ioremap(cns21xx_intc_resource.start, INTC_SIZE);
++
++	cns21xx_intc_writel(0xffffffff, INTC_INTERRUPT_MASK_REG);
++	cns21xx_intc_writel(0xffffffff, INTC_EDGE_INTERRUPT_SOURCE_CLEAR_REG);
++	cns21xx_intc_writel(0xffffffff, INTC_SOFTWARE_INTERRUPT_CLEAR_REG);
++	cns21xx_intc_writel(0, INTC_SOFTWARE_PRIORITY_MASK_REG);
++	cns21xx_intc_writel(0, INTC_FIQ_SELECT_REG);
++	cns21xx_intc_writel(0, INTC_VECTOR_INTERRUPT_ENABLE_REG);
++
++	for (i = 0; i < ARRAY_SIZE(cns21xx_irq_types);  i++) {
++		irq_flow_handler_t handler;
++
++		switch (cns21xx_irq_types[i]) {
++		case IRQ_TYPE_EDGE_RISING:
++			handler = handle_edge_irq;
++			mode |= (1 << i);
++			break;
++
++		case IRQ_TYPE_EDGE_FALLING:
++			handler = handle_edge_irq;
++			mode |= (1 << i);
++			level |= (1 << i);
++			break;
++
++		case IRQ_TYPE_LEVEL_LOW:
++			handler = handle_level_irq;
++			level |= (1 << i);
++			break;
++
++		case IRQ_TYPE_LEVEL_HIGH:
++		case IRQ_TYPE_NONE:
++			handler = handle_level_irq;
++			break;
++
++		default:
++			BUG();
++			break;
++		}
++
++		irq_set_chip(i, &cns21xx_irq_chip);
++		irq_set_handler(i, handler);
++		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
++	}
++
++	cns21xx_intc_writel(mode, INTC_INTERRUPT_TRIGGER_MODE_REG);
++	cns21xx_intc_writel(level, INTC_INTERRUPT_TRIGGER_LEVEL_REG);
++}
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/time.c
+@@ -0,0 +1,28 @@
++/*
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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/init.h>
++#include <linux/irq.h>
++
++#include <asm/mach/time.h>
++
++#include <plat/time.h>
++#include <mach/hardware.h>
++#include <mach/cns21xx.h>
++
++#include "common.h"
++
++static void __init cns21xx_timer_init(void)
++{
++	fa_timer_init(CNS21XX_TIMER_BASE, CNS21XX_IRQ_TIMER1, FA_TIMER1,
++		      cns21xx_get_apb_freq());
++}
++
++struct sys_timer cns21xx_timer = {
++	.init		= cns21xx_timer_init,
++};
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/include/mach/cns21xx_powermgmt.h
+@@ -0,0 +1,591 @@
++/*
++ *  Copyright (c) 2008 Cavium Networks
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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 _CNS21XX_POWERMGMT_H
++#define _CNS21XX_POWERMGMT_H
++
++#define PWRMGT_MEM_MAP_VALUE(reg_offset) \
++	(*((u32 volatile *)(CNS21XX_CPM_BASE_VIRT + reg_offset)))
++
++/*
++ * define access macros
++ */
++#define PWRMGT_CLOCK_GATE_CONTROL0_REG		PWRMGT_MEM_MAP_VALUE(0x00)
++#define PWRMGT_CLOCK_GATE_CONTROL1_REG		PWRMGT_MEM_MAP_VALUE(0x04)
++#define PWRMGT_SOFTWARE_RESET_CONTROL_REG	PWRMGT_MEM_MAP_VALUE(0x08)
++#define PWRMGT_SYSTEM_CLOCK_CONTROL_REG		PWRMGT_MEM_MAP_VALUE(0x0C)
++#define PWRMGT_PLL_POWER_DOWN_CONTROL_REG	PWRMGT_MEM_MAP_VALUE(0x10)
++#define PWRMGT_CPU_INITIALIZATION_REG		PWRMGT_MEM_MAP_VALUE(0x14)
++#define PWRMGT_PAD_DRIVE_STRENGTH_CONTROL_REG	PWRMGT_MEM_MAP_VALUE(0x1C)
++#define PWRMGT_USB_DEVICE_POWERMGT_REG		PWRMGT_MEM_MAP_VALUE(0x20)
++#define PWRMGT_REGULATOR_CONTROL_REG		PWRMGT_MEM_MAP_VALUE(0x24)
++#define PWRMGT_RTC_XTAL_CONTROL_REG		PWRMGT_MEM_MAP_VALUE(0x28)
++#define PWRMGT_PLL250_CONTROL_REG		PWRMGT_MEM_MAP_VALUE(0x2C)
++
++
++/*
++ * define constants macros
++ */
++#define PWRMGT_GLOBAL_SOFTWARE_RESET_MASK_BIT_INDEX		0
++#define PWRMGT_PCMCIA_SOFTWARE_RESET_BIT_INDEX			1
++#define PWRMGT_IDE_SOFTWARE_RESET_BIT_INDEX			2
++#define PWRMGT_VIC_SOFTWARE_RESET_BIT_INDEX			3
++#define PWRMGT_DMA_SOFTWARE_RESET_BIT_INDEX			4
++#define PWRMGT_NIC_SOFTWARE_RESET_BIT_INDEX			5
++#define PWRMGT_USB_HOST_SOFTWARE_RESET_BIT_INDEX		6
++#define PWRMGT_PCI_BRIDGE_SOFTWARE_RESET_BIT_INDEX		7
++#define PWRMGT_P2S_SOFTWARE_RESET_BIT_INDEX			8
++#define PWRMGT_UART0_SOFTWARE_RESET_BIT_INDEX			9
++#define PWRMGT_UART1_SOFTWARE_RESET_BIT_INDEX			10
++#define PWRMGT_TIMER_SOFTWARE_RESET_BIT_INDEX			11
++#define PWRMGT_WDTIMER_SOFTWARE_RESET_BIT_INDEX			12
++#define PWRMGT_GPIO_SOFTWARE_RESET_BIT_INDEX			13
++#define PWRMGT_USB_DEVICE_SOFTWARE_RESET_BIT_INDEX		14
++#define PWRMGT_FAST_ETHERNET_PHY_SOFTWARE_RESET_BIT_INDEX	15
++#define PWRMGT_HSDMA_SOFTWARE_RESET_BIT_INDEX			16
++
++#define PWRMGT_PLL_FREQUENCY_175MHZ		(0 << 0)
++#define PWRMGT_PLL_FREQUENCY_200MHZ		(1 << 0)
++#define PWRMGT_PLL_FREQUENCY_225MHZ		(2 << 0)
++#define PWRMGT_PLL_FREQUENCY_250MHZ		(3 << 0)
++
++#define PWRMGT_CPUCLK_DIVIDER_BY_1		(0 << 2)
++#define PWRMGT_CPUCLK_DIVIDER_BY_2		(1 << 2)
++#define PWRMGT_CPUCLK_DIVIDER_BY_3		(2 << 2)
++#define PWRMGT_CPUCLK_DIVIDER_BY_4		(3 << 2)
++
++#define PWRMGT_HCLK_DIVIDER_BY_1		(0 << 4)
++#define PWRMGT_HCLK_DIVIDER_BY_2		(1 << 4)
++#define PWRMGT_HCLK_DIVIDER_BY_3		(2 << 4)
++#define PWRMGT_HCLK_DIVIDER_BY_4		(3 << 4)
++
++#define PWRMGT_HCLK_SOURCE_FCLK			(0 << 6)
++#define PWRMGT_HCLK_SOURCE_125MHZ		(1 << 6)
++
++#define PWRMGT_PCLK_DIVIDER_BY_1		(0 << 8)
++#define PWRMGT_PCLK_DIVIDER_BY_2		(1 << 8)
++#define PWRMGT_PCLK_DIVIDER_BY_3		(2 << 8)
++#define PWRMGT_PCLK_DIVIDER_BY_4		(3 << 8)
++
++#define PWRMGT_PCICLK_DIVIDER_BY_1		(0 << 10)
++#define PWRMGT_PCICLK_DIVIDER_BY_2		(1 << 10)
++#define PWRMGT_PCICLK_DIVIDER_BY_3		(2 << 10)
++#define PWRMGT_PCICLK_DIVIDER_BY_4		(3 << 10)
++
++
++#define PWRMGT_PLLCLK_TO_CPUCLK_RATIO_BY_1	1
++#define PWRMGT_PLLCLK_TO_CPUCLK_RATIO_BY_2	2
++#define PWRMGT_PLLCLK_TO_CPUCLK_RATIO_BY_3	3
++#define PWRMGT_PLLCLK_TO_CPUCLK_RATIO_BY_4	4
++
++#define PWRMGT_CPUCLK_TO_HCLK_RATIO_BY_1	1
++#define PWRMGT_CPUCLK_TO_HCLK_RATIO_BY_2	2
++#define PWRMGT_CPUCLK_TO_HCLK_RATIO_BY_3	3
++#define PWRMGT_CPUCLK_TO_HCLK_RATIO_BY_4	4
++
++#define PWRMGT_HCLK_TO_PCLK_RATIO_BY_1		1
++#define PWRMGT_HCLK_TO_PCLK_RATIO_BY_2		2
++#define PWRMGT_HCLK_TO_PCLK_RATIO_BY_3		3
++#define PWRMGT_HCLK_TO_PCLK_RATIO_BY_4		4
++
++/*
++ * Macro defines for Clock Gate	Control
++ */
++#define HAL_PWRMGT_DISABLE_DRAMC_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL0_REG &= ~(0x1); \
++}
++
++
++#define HAL_PWRMGT_ENABLE_NIC_CLOCK() \
++{ \
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0x1 << 0); \
++    PWRMGT_CLOCK_GATE_CONTROL0_REG |= (0x0F << 20); \
++    PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 5); \
++}
++
++#define HAL_PWRMGT_DISABLE_NIC_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL0_REG &= ~(0x0F << 20); \
++}
++
++
++#define HAL_PWRMGT_ENABLE_PCI_BRIDGE_33M_CLOCK() \
++{ \
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0x1 << 1); \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~(0x3 << 10); \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= (0x1 << 10); \
++    PWRMGT_CLOCK_GATE_CONTROL0_REG |= (0x1 << 28) | (0x1 << 30); \
++    PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 7); \
++}
++
++#define HAL_PWRMGT_ENABLE_PCI_BRIDGE_66M_CLOCK() \
++{ \
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0x1 << 1); \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~(0x3 << 10); \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= (0x0 << 10); \
++    PWRMGT_CLOCK_GATE_CONTROL0_REG |= (0x1 << 28) | (0x1 << 30); \
++    PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 7); \
++}
++
++#define HAL_PWRMGT_DISABLE_PCI_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL0_REG &= ~((0x1 << 28) | (0x1 << 30)); \
++}
++
++
++#define HAL_PWRMGT_ENABLE_USB_CLOCK() \
++{ \
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0xF << 1); \
++    PWRMGT_CLOCK_GATE_CONTROL0_REG |= (0x1 << 24); \
++    PWRMGT_CLOCK_GATE_CONTROL1_REG |= (0x1 << 28); \
++    PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 6) | (0x1 << 14); \
++}
++
++#define HAL_PWRMGT_DISABLE_USB_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL0_REG &= ~(0x1 << 24); \
++    PWRMGT_CLOCK_GATE_CONTROL1_REG &= ~(0x1 << 28); \
++}
++
++
++#define HAL_PWRMGT_ENABLE_DMA_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL0_REG |= (0x1 << 16); \
++    PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 4); \
++}
++
++#define HAL_PWRMGT_DISABLE_DMA_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL0_REG &= ~(0x1 << 16); \
++}
++
++
++#define HAL_PWRMGT_ENABLE_IDE_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL0_REG |= (0x1 << 8) | (0x1 << 9); \
++    PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 2); \
++}
++
++#define HAL_PWRMGT_DISABLE_IDE_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL0_REG &= ~((0x1 << 8) | (0x1 << 9)); \
++}
++
++
++#define HAL_PWRMGT_ENABLE_UART0_CLOCK()	\
++{ \
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~((0x1 << 1) |	(0x1 << 2) | (0x1 << 5)); \
++    PWRMGT_CLOCK_GATE_CONTROL1_REG |= (0x1 << 12); \
++    PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 9); \
++}
++
++#define HAL_PWRMGT_DISABLE_UART0_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL1_REG &= ~(0x1 << 12); \
++}
++
++
++#define HAL_PWRMGT_ENABLE_UART1_CLOCK()	\
++{ \
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~((0x1 << 1) |	(0x1 << 2) | (0x1 << 5)); \
++    PWRMGT_CLOCK_GATE_CONTROL1_REG |= (0x1 << 13); \
++    PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 10); \
++}
++
++#define HAL_PWRMGT_DISABLE_UART1_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL1_REG &= ~(0x1 << 13); \
++}
++
++
++#define HAL_PWRMGT_ENABLE_PCMCIA_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL0_REG |= (0x1 << 4) | (0x1 << 5); \
++}
++
++#define HAL_PWRMGT_DISABLE_PCMCIA_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL0_REG &= ~((0x1 << 4) | (0x1 << 5)); \
++}
++
++
++#define HAL_PWRMGT_ENABLE_GPIO_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL1_REG |= (0x1 << 25); \
++}
++
++#define HAL_PWRMGT_DISABLE_GPIO_CLOCK()	\
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL1_REG &= ~(0x1 << 25); \
++}
++
++
++#define HAL_PWRMGT_ENABLE_WDTIMER_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL1_REG |= (0x1 << 21) | (0x1 << 22); \
++}
++
++#define HAL_PWRMGT_DISABLE_WDTIMER_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL1_REG &= ~((0x1 << 21) | (0x1 << 22)); \
++}
++
++
++#define HAL_PWRMGT_ENABLE_RTC_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL1_REG |= (0x1 << 23); \
++}
++
++#define HAL_PWRMGT_DISABLE_RTC_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL1_REG &= ~(0x1 << 23); \
++}
++
++
++#define HAL_PWRMGT_ENABLE_TIMER_CLOCK()	\
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL1_REG |= (0x1 << 17) | (0x1 << 18)	| (0x1 << 19); \
++}
++
++#define HAL_PWRMGT_DISABLE_TIMER_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL1_REG &= ~((0x1 << 17) | (0x1 << 18) | (0x1 << 19)); \
++}
++
++
++#define HAL_PWRMGT_ENABLE_I2C_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL1_REG |= (0x1 << 1); \
++}
++
++#define HAL_PWRMGT_DISABLE_I2C_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL1_REG &= ~(0x1 << 1); \
++}
++
++
++#define HAL_PWRMGT_ENABLE_I2S_CLOCK() \
++{ \
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~((0x1 << 5) |	(0x1 << 6)); \
++    PWRMGT_CLOCK_GATE_CONTROL1_REG |= (0x1 << 1) | (0x1 << 10);	\
++    PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 8); \
++}
++
++#define HAL_PWRMGT_DISABLE_I2S_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL1_REG &= ~((0x1 << 1) | (0x1 << 10)); \
++}
++
++
++#define HAL_PWRMGT_ENABLE_PCM_CLOCK() \
++{ \
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0x1 << 5); \
++    PWRMGT_CLOCK_GATE_CONTROL1_REG |= (0x1 << 1) | (0x1 << 6); \
++    PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 8); \
++}
++
++#define HAL_PWRMGT_DISABLE_PCM_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL1_REG &= ~((0x1 << 1) | (0x1 << 6)); \
++}
++
++
++#define HAL_PWRMGT_ENABLE_SPI_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL1_REG |= (0x1 << 0) | (0x1 << 1); \
++}
++
++#define HAL_PWRMGT_DISABLE_SPI_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL1_REG &= ~((0x1 << 0) | (0x1 << 1)); \
++}
++
++
++#define HAL_PWRMGT_ENABLE_VIC_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL0_REG |= (0x1 << 12); \
++}
++
++#define HAL_PWRMGT_DISABLE_VIC_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL0_REG &= ~(0x1 << 12); \
++}
++
++
++#define HAL_PWRMGT_ENABLE_SMC_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL0_REG |= (0x1 << 4) | (0x1 << 5); \
++}
++
++#define HAL_PWRMGT_DISABLE_SMC_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL0_REG &= ~((0x1 << 4) | (0x1 << 5)); \
++}
++
++
++#define HAL_PWRMGT_ENABLE_HSDMA_CLOCK()	\
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL1_REG |= (0x1 << 29); \
++    PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 16); \
++}
++
++#define HAL_PWRMGT_DISABLE_HSDMA_CLOCK() \
++{ \
++    PWRMGT_CLOCK_GATE_CONTROL1_REG &= ~(0x1 << 29); \
++}
++
++
++
++/*
++ * Macro defines for Reset Control
++ */
++#define HAL_PWRMGT_GLOBAL_SOFTWARE_RESET() \
++{ \
++    PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1);	\
++    PWRMGT_SOFTWARE_RESET_CONTROL_REG &= ~(0x1); \
++}
++
++
++/*
++ * Macro defines for System Clock Control
++ */
++#define HAL_PWRMGT_SET_PLL_FREQUENCY_175MHZ() \
++{ \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~0x3; \
++}
++
++
++#define HAL_PWRMGT_SET_PLL_FREQUENCY_200MHZ() \
++{ \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~0x3; \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= 0x1; \
++}
++
++
++#define HAL_PWRMGT_SET_PLL_FREQUENCY_225MHZ() \
++{ \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~0x3; \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= 0x2; \
++}
++
++
++#define HAL_PWRMGT_SET_PLL_FREQUENCY_250MHZ() \
++{ \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~0x3; \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= 0x3; \
++}
++
++
++#define HAL_PWRMGT_CONFIG_PLLCLK_TO_CPUCLK_RATIO(ratio)	\
++{ \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~(0x3 << 2); \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= (((ratio	- 1) & 0x3) << 2); \
++}
++
++
++#define HAL_PWRMGT_CONFIG_CPUCLK_TO_HCLK_RATIO(ratio) \
++{ \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~(0x3 << 4); \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= (((ratio	- 1) & 0x3) << 4); \
++}
++
++
++#define HAL_PWRMGT_HCLK_SOURCE_FCLK() \
++{ \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~(0x1 << 6); \
++}
++
++
++#define HAL_PWRMGT_HCLK_SOURCE_125MHZ()	\
++{ \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= (0x1 << 6); \
++}
++
++
++#define HAL_PWRMGT_GIGA_NIC_CLOCK_SOURCE_HCLK()	\
++{ \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~(0x1 << 7); \
++}
++
++
++#define HAL_PWRMGT_GIGA_NIC_CLOCK_SOURCE_62_5MHZ() \
++{ \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= (0x1 << 7); \
++}
++
++
++#define HAL_PWRMGT_CONFIG_HCLK_TO_PCLK_RATIO(ratio) \
++{ \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~(0x3 << 8); \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= (((ratio	- 1) & 0x3) << 8); \
++}
++
++
++#define HAL_PWRMGT_I2S_CLOCK_SOURCE_8192000HZ()	\
++{ \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~(0x3 << 12); \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= (0x0 << 12); \
++}
++
++
++#define HAL_PWRMGT_I2S_CLOCK_SOURCE_11289600HZ() \
++{ \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~(0x3 << 12); \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= (0x1 << 12); \
++}
++
++
++#define HAL_PWRMGT_I2S_CLOCK_SOURCE_12288000HZ() \
++{ \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~(0x3 << 12); \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= (0x2 << 12); \
++}
++
++
++#define HAL_PWRMGT_CONFIGURE_MDC_CLOCK_DIVIDER(divided_value) \
++{ \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~(0x3 << 14); \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= ((divided_value & 0x3) << 14); \
++}
++
++
++#define HAL_PWRMGT_CONFIGURE_CLOCK_OUT_PIN(pin_source_select, divided_value) \
++{ \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~(0x3F << 16); \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= ((pin_source_select & 0xF) << 16); \
++    PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= ((divided_value & 0x3) << 20); \
++}
++
++
++/*
++ * Macro defines for PLL Power Down Control
++ */
++#define HAL_PWRMGT_POWER_DOWN_SYSTEM_XTAL_PAD()	\
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG |= (0x1 << 7)
++
++#define HAL_PWRMGT_POWER_ON_SYSTEM_XTAL_PAD() \
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0x1 << 7)
++
++
++#define HAL_PWRMGT_POWER_DOWN_PLL_X5() \
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG |= (0x1 << 0)
++
++#define HAL_PWRMGT_POWER_ON_PLL_X5() \
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0x1 << 0)
++
++
++#define HAL_PWRMGT_POWER_DOWN_PLL_X8() \
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG |= (0x1 << 1)
++
++#define HAL_PWRMGT_POWER_ON_PLL_X8() \
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0x1 << 1)
++
++
++#define HAL_PWRMGT_POWER_DOWN_PLL_X3() \
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG |= (0x1 << 2)
++
++#define HAL_PWRMGT_POWER_ON_PLL_X3() \
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0x1 << 2)
++
++
++#define HAL_PWRMGT_POWER_DOWN_USBH_PHY_PLL() \
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG |= (0x1 << 3)
++
++#define HAL_PWRMGT_POWER_ON_USBH_PHY_PLL() \
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0x1 << 3)
++
++
++#define HAL_PWRMGT_POWER_DOWN_USBD_PHY_PLL() \
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG |= (0x1 << 4)
++
++#define HAL_PWRMGT_POWER_ON_USBD_PHY_PLL() \
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0x1 << 4)
++
++
++#define HAL_PWRMGT_POWER_DOWN_PLL_X2250() \
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG |= (0x1 << 5)
++
++#define HAL_PWRMGT_POWER_ON_PLL_X2250()	\
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0x1 << 5)
++
++
++#define HAL_PWRMGT_POWER_DOWN_PLL_X7() \
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG |= (0x1 << 6)
++
++#define HAL_PWRMGT_POWER_ON_PLL_X7() \
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0x1 << 6)
++
++
++#define HAL_PWRMGT_POWER_DOWN_ALL_PLL()	\
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG =	0x7F;
++
++#define HAL_PWRMGT_POWER_ON_ALL_PLL() \
++    PWRMGT_PLL_POWER_DOWN_CONTROL_REG =	0;
++
++
++/*
++ * Macro defines for Pad Drive Strength	Control
++ */
++#define HAL_PWRMGT_SELECT_PAD_DRIVE_STRENGTH_PCMCIA_CARDBUS_MODE() \
++{ \
++    PWRMGT_PAD_DRIVE_STRENGTH_CONTROL_REG &= ~(0x3 << 0); \
++}
++
++#define HAL_PWRMGT_SELECT_PAD_DRIVE_STRENGTH_PCI_MODE()	\
++{ \
++    PWRMGT_PAD_DRIVE_STRENGTH_CONTROL_REG &= ~(0x3 << 0); \
++    PWRMGT_PAD_DRIVE_STRENGTH_CONTROL_REG |= (0x1 << 0); \
++}
++
++#define HAL_PWRMGT_SELECT_PAD_DRIVE_STRENGTH_MII_MODE()	\
++{ \
++    PWRMGT_PAD_DRIVE_STRENGTH_CONTROL_REG |= (0x1 << 2); \
++}
++
++#define HAL_PWRMGT_SELECT_PAD_DRIVE_STRENGTH_RGMII_MODE() \
++{ \
++    PWRMGT_PAD_DRIVE_STRENGTH_CONTROL_REG &= ~(0x1 << 2); \
++}
++
++#define HAL_PWRMGT_ENABLE_MII_PAD_SIGNAL_NOT_BOUNDED() \
++{ \
++    PWRMGT_PAD_DRIVE_STRENGTH_CONTROL_REG |= (0x1 << 3); \
++}
++
++#define HAL_PWRMGT_DISABLE_MII_PAD_SIGNAL_NOT_BOUNDED()	\
++{ \
++    PWRMGT_PAD_DRIVE_STRENGTH_CONTROL_REG &= ~(0x1 << 3); \
++}
++
++
++/*
++ * Macro defines for USB Device	Power Management
++ */
++#define HAL_PWRMGT_REMOTE_WAKEUP_USB_HOST() \
++{ \
++    PWRMGT_USB_DEVICE_POWERMGT_REG |= (0x1 << 4); \
++}
++
++#define HAL_PWRMGT_USB_DEVICE_PHY_CLOCK_SOURCE_EXTERNAL_12MHZ()	\
++{ \
++    PWRMGT_USB_DEVICE_POWERMGT_REG &= ~(0x1 << 5); \
++}
++
++#define HAL_PWRMGT_USB_DEVICE_PHY_CLOCK_SOURCE_INTERNAL_12MHZ()	\
++{ \
++    PWRMGT_USB_DEVICE_POWERMGT_REG |= (0x1 << 5); \
++}
++
++
++/*
++ * Macro defines for Regulator Control
++ */
++
++#endif /* _CNS21XX_POWERMGMT_H */
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/include/mach/cns21xx.h
+@@ -0,0 +1,88 @@
++/*
++ *  Copyright (c) 2008 Cavium Networks
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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 _CNS21XX_H
++#define _CNS21XX_H
++
++#define CNS21XX_FLASH_BANK0_BASE	0x10000000
++#define CNS21XX_FLASH_BANK1_BASE	0x11000000
++#define CNS21XX_FLASH_BANK2_BASE	0x12000000
++#define CNS21XX_FLASH_BANK3_BASE	0x13000000
++#define CNS21XX_PCMCIA_ATTR_BASE	0x14000000
++#define CNS21XX_PCMCIA_MEM_BASE		0x15000000
++#define CNS21XX_PCMCIA_IO_BASE		0x16000000
++#define CNS21XX_IDE_DEVICE_BASE		0x18000000
++#define CNS21XX_SDRAM_MEMORY_BASE	0x20000000
++#define CNS21XX_GDMAC_BASE		0x60000000
++#define CNS21XX_NIC_BASE		0x70000000
++#define CNS21XX_SPI_BASE		0x71000000
++#define CNS21XX_PCM_BASE		0x71000000
++#define CNS21XX_I2C_BASE		0x71000000
++#define CNS21XX_I2S_BASE		0x71000000
++#define CNS21XX_DDRC_BASE		0x72000000
++#define CNS21XX_SMC_BASE		0x73000000
++#define CNS21XX_PCMCIA_CTRL_BASE	0x73000000
++#define CNS21XX_IDE_CTRL_BASE		0x74000000
++#define CNS21XX_MISC_BASE		0x76000000
++#define CNS21XX_CPM_BASE		0x77000000
++#define CNS21XX_UART0_BASE		0x78000000
++#define CNS21XX_UART1_BASE		0x78800000
++#define CNS21XX_TIMER_BASE		0x79000000
++#define CNS21XX_WDT_BASE		0x7a000000
++#define CNS21XX_RTC_BASE		0x7b000000
++#define CNS21XX_GPIOA_BASE		0x7c000000
++#define CNS21XX_GPIOB_BASE		0x7c800000
++#define CNS21XX_PCI_CFGDATA_BASE	0xa0000000
++#define CNS21XX_PCI_CFGADDR_BASE	0xa4000000
++#define CNS21XX_PCI_IO_BASE		0xa8000000
++#define CNS21XX_PCI_MEMORY_BASE		0xb0000000
++#define CNS21XX_OHCI_CONFIG_BASE	0xc0000000
++#define CNS21XX_OHCI_CTRL_BASE		0xc4000000
++#define CNS21XX_EHCI_CONFIG_BASE	0xc8000000
++#define CNS21XX_EHCI_CTRL_BASE		0xcc000000
++#define CNS21XX_USB_DEVICE_BASE		0xd0000000
++#define CNS21XX_INTC_BASE		0xfffff000
++
++#define CNS21XX_FLASH_BANK0_BASE_VIRT	0xe0000000
++#define CNS21XX_FLASH_BANK1_BASE_VIRT	0xe2000000
++#define CNS21XX_FLASH_BANK2_BASE_VIRT	0xe4000000
++#define CNS21XX_FLASH_BANK3_BASE_VIRT	0xe8000000
++#define CNS21XX_IDE_DEVICE_BASE_VIRT	0xfef00000
++#define CNS21XX_GDMAC_BASE_VIRT		0xfef01000
++#define CNS21XX_NIC_BASE_VIRT		0xfef02000
++#define CNS21XX_SPI_BASE_VIRT		0xfef03000
++#define CNS21XX_PCM_BASE_VIRT		0xfef04000
++#define CNS21XX_I2C_BASE_VIRT		0xfef05000
++#define CNS21XX_I2S_BASE_VIRT		0xfef06000
++#define CNS21XX_DDRC_BASE_VIRT		0xfef07000
++#define CNS21XX_SMC_BASE_VIRT		0xfef08000
++#define CNS21XX_PCMCIA_CTRL_BASE_VIRT	0xfef09000
++#define CNS21XX_IDE_CTRL_BASE_VIRT	0xfef0A000
++#define CNS21XX_MISC_BASE_VIRT		0xfef0B000
++#define CNS21XX_CPM_BASE_VIRT		0xfef0C000
++#define CNS21XX_UART0_BASE_VIRT		0xfef0D000
++#define CNS21XX_UART1_BASE_VIRT		0xfef0E000
++#define CNS21XX_TIMER_BASE_VIRT		0xfef0F000
++#define CNS21XX_WDT_BASE_VIRT		0xfef10000
++#define CNS21XX_RTC_BASE_VIRT		0xfef11000
++#define CNS21XX_GPIOA_BASE_VIRT		0xfef12000
++#define CNS21XX_GPIOB_BASE_VIRT		0xfef13000
++#define CNS21XX_PCI_CFGDATA_BASE_VIRT	0xfef14000
++#define CNS21XX_PCI_CFGADDR_BASE_VIRT	0xfef15000
++#define CNS21XX_OHCI_CONFIG_BASE_VIRT	0xfef16000
++#define CNS21XX_OHCI_CTRL_BASE_VIRT	0xfef17000
++#define CNS21XX_EHCI_CONFIG_BASE_VIRT	0xfef18000
++#define CNS21XX_EHCI_CTRL_BASE_VIRT	0xfef19000
++#define CNS21XX_USB_DEVICE_BASE_VIRT	0xfef1a000
++#define CNS21XX_INTC_BASE_VIRT		0xfef1b000
++
++#define CNS21XX_PHYS_IO		CNS21XX_UART0_BASE
++#define CNS21XX_IO_PAGE_OFFSET	((CNS21XX_UART0_BASE_VIRT) >> 18) & 0xfffc
++
++#endif /* _CNS21XX_H */
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/core.c
+@@ -0,0 +1,85 @@
++/*
++ *  Copyright (c) 2008 Cavium Networks
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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 <mach/hardware.h>
++#include <mach/cns21xx.h>
++#include <mach/cns21xx_powermgmt.h>
++
++static unsigned long cns21xx_pll_freq;
++static unsigned long cns21xx_cpu_freq;
++static unsigned long cns21xx_ahb_freq;
++static unsigned long cns21xx_apb_freq;
++
++static void cns21xx_init_freq(void)
++{
++	static int freq_init_done;
++	unsigned int t;
++
++	if (freq_init_done)
++		return;
++
++	t = PWRMGT_SYSTEM_CLOCK_CONTROL_REG;
++	switch (t & 0x3) {
++	case 0x00:
++		cns21xx_pll_freq = 175000000;
++		break;
++
++	case 0x01:
++		cns21xx_pll_freq = 200000000;
++		break;
++
++	case 0x02:
++		cns21xx_pll_freq = 225000000;
++		break;
++
++	case 0x03:
++		cns21xx_pll_freq = 250000000;
++		break;
++	}
++
++	cns21xx_cpu_freq = cns21xx_pll_freq / (((t >> 2) & 0x3) + 1);
++	cns21xx_ahb_freq = cns21xx_cpu_freq / (((t >> 4) & 0x3) + 1);
++	cns21xx_apb_freq = cns21xx_ahb_freq / (((t >> 8) & 0x3) + 1);
++
++	freq_init_done = 1;
++}
++
++unsigned long cns21xx_get_pll_freq(void)
++{
++	cns21xx_init_freq();
++	return cns21xx_pll_freq;
++}
++
++unsigned long cns21xx_get_cpu_freq(void)
++{
++	cns21xx_init_freq();
++	return cns21xx_cpu_freq;
++}
++
++unsigned long cns21xx_get_ahb_freq(void)
++{
++	cns21xx_init_freq();
++	return cns21xx_ahb_freq;
++}
++
++unsigned long cns21xx_get_apb_freq(void)
++{
++	cns21xx_init_freq();
++	return cns21xx_apb_freq;
++}
++
++void cns21xx_restart(char mode, const char *cmd)
++{
++	PWRMGT_SOFTWARE_RESET_CONTROL_REG |=
++		(1UL << PWRMGT_GLOBAL_SOFTWARE_RESET_MASK_BIT_INDEX);
++	PWRMGT_SOFTWARE_RESET_CONTROL_REG &=
++		~(1UL << PWRMGT_GLOBAL_SOFTWARE_RESET_MASK_BIT_INDEX);
++}
+--- a/arch/arm/mm/Kconfig
++++ b/arch/arm/mm/Kconfig
+@@ -846,6 +846,7 @@ config ARM_L1_CACHE_SHIFT_6
+ config ARM_L1_CACHE_SHIFT
+ 	int
+ 	default 6 if ARM_L1_CACHE_SHIFT_6
++	default 4 if ARM_L1_CACHE_SHIFT_4
+ 	default 5
+ 
+ config ARM_DMA_MEM_BUFFERABLE
+--- a/arch/arm/mm/cache-fa.S
++++ b/arch/arm/mm/cache-fa.S
+@@ -28,7 +28,7 @@
+ /*
+  * The total size of the data cache.
+  */
+-#ifdef CONFIG_ARCH_GEMINI
++#if (defined(CONFIG_ARCH_GEMINI) || defined(CONFIG_ARCH_CNS21XX))
+ #define CACHE_DSIZE	8192
+ #else
+ #define CACHE_DSIZE	16384 
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/include/mach/cns21xx_misc.h
+@@ -0,0 +1,507 @@
++/*******************************************************************************
++ *
++ *  Copyright (c) 2008 Cavium Networks
++ *
++ *  This file 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.
++ *
++ *  This file is distributed in the hope that it will be useful,
++ *  but AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
++ *  NONINFRINGEMENT.  See the GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this file; if not, write to the Free Software
++ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA or
++ *  visit http://www.gnu.org/licenses/.
++ *
++ *  This file may also be available under a different license from Cavium.
++ *  Contact Cavium Networks for more information
++ *
++ ******************************************************************************/
++
++#ifndef	_STAR_MISC_H_
++#define _STAR_MISC_H_
++
++#include <mach/cns21xx.h>
++
++#define MISC_MEM_MAP_VALUE(reg_offset) \
++	(*((u32 volatile *)(CNS21XX_MISC_BASE_VIRT + reg_offset)))
++
++/*
++ * define access macros
++ */
++#define MISC_MEMORY_REMAP_REG			MISC_MEM_MAP_VALUE(0x00)
++#define MISC_CHIP_CONFIG_REG			MISC_MEM_MAP_VALUE(0x04)
++#define MISC_DEBUG_PROBE_DATA_REG		MISC_MEM_MAP_VALUE(0x08)
++#define MISC_DEBUG_PROBE_SELECTION_REG		MISC_MEM_MAP_VALUE(0x0C)
++#define MISC_PCI_CONTROL_BROKEN_MASK_REG	MISC_MEM_MAP_VALUE(0x10)
++#define MISC_PCI_BROKEN_STATUS_REG		MISC_MEM_MAP_VALUE(0x14)
++#define MISC_PCI_DEVICE_VENDOR_ID_REG		MISC_MEM_MAP_VALUE(0x18)
++#define MISC_USB_HOST_PHY_CONTROL_TEST_REG	MISC_MEM_MAP_VALUE(0x1C)
++#define MISC_GPIOA_PIN_ENABLE_REG		MISC_MEM_MAP_VALUE(0x20)
++#define MISC_GPIOB_PIN_ENABLE_REG		MISC_MEM_MAP_VALUE(0x24)
++#define MISC_GPIOA_RESISTOR_CONFIG_REG		MISC_MEM_MAP_VALUE(0x28)
++#define MISC_GPIOA_DRIVE_STRENGTH_CONFIG_REG	MISC_MEM_MAP_VALUE(0x2C)
++#define MISC_FAST_ETHERNET_PHY_CONFIG_REG	MISC_MEM_MAP_VALUE(0x30)
++#define MISC_SOFTWARE_TEST_1_REG		MISC_MEM_MAP_VALUE(0x38)
++#define MISC_SOFTWARE_TEST_2_REG		MISC_MEM_MAP_VALUE(0x3C)
++
++#define MISC_E_FUSE_0_REG			MISC_MEM_MAP_VALUE(0x60)
++#define MISC_E_FUSE_1_REG			MISC_MEM_MAP_VALUE(0x64)
++
++
++/*
++ * define constants macros
++ */
++#define MISC_PARALLEL_FLASH_BOOT		0
++#define MISC_SPI_SERIAL_FLASH_BOOT		1
++
++#define MISC_LITTLE_ENDIAN			0
++#define MISC_BIG_ENDIAN				1
++
++#define MISC_FARADAY_ICE			0
++#define MISC_ARM_ICE				1
++
++#define MISC_EXT_INT29_PINS			((0x1 << 0))
++#define MISC_EXT_INT30_PINS			((0x1 << 1))
++#define MISC_EXT_INT31_PINS			((0x1 << 2))
++#define MISC_I2C_PINS				((0x1 << 13) | (0x1 << 14))
++#define MISC_I2S_PINS				((0x1 << 15) | (0x1 << 16) | (0x1 << 17))
++#define MISC_I2SSD_PINS				(1 << 15)
++#define MISC_I2SWS_PINS				(1 << 16)
++#define MISC_I2SCLK_PINS			(1 << 17)
++#define MISC_PCM_PINS				((0x1 << 18) | (0x1 << 19) | (0x1 << 20) | (0x1 << 21))
++#define MISC_PCMDR_PINS				(1 << 18)
++#define MISC_PCMDT_PINS				(1 << 19)
++#define MISC_PCMFS_PINS				(1 << 20)
++#define MISC_PCMCLK_PINS			(1 << 21)
++#define MISC_LED0_PINS				((0x1 << 22))
++#define MISC_LED1_PINS				((0x1 << 23))
++#define MISC_LED2_PINS				((0x1 << 24))
++#define MISC_LED012_PINS			((0x1 << 22) | (0x1 << 23) | (0x1 << 24))
++#define MISC_WDTIMER_RESET_PINS			((0x1 << 25))
++#define MISC_SPIDR_PINS				(0x1 << 26)
++#define MISC_SPICLK_PINS			(0x1 << 27)
++#define MISC_SPICSN0_PINS			(0x1 << 28)
++#define MISC_SPICSN1_PINS			(0x1 << 29)
++#define MISC_SPICSN2_PINS			(0x1 << 30)
++#define MISC_SPICSN3_PINS			(0x1 << 31)
++#define MISC_SPI_PINS				((0x1 << 26) | (0x1 << 27) | (0x1 << 28) | (0x1 << 29) | (0x1 << 30) | (0x1 << 31))
++#define MISC_MDC_MDIO_PINS			((0x1 << 0) | (0x1 << 1))
++#define MISC_NIC_COL_PINS			((0x1 << 2))
++#define MISC_IDE_PINS				((0xFF << 3))
++#define MISC_SRAM_BANK1_PINS			((0x1 << 11) | (0x1 << 14))
++#define MISC_SRAM_BANK2_PINS			((0x1 << 12) | (0x1 << 15))
++#define MISC_SRAM_BANK3_PINS			((0x1 << 13) | (0x1 << 16))
++#define MISC_PCMCIA_PINS			((0x1 << 17) | (0x1 << 18) | (0x1 << 19) | (0x1 << 20))
++#define MISC_UART1_PINS				((0x1 << 21) | (0x1 << 22))
++#define MISC_PCI_PINS				(((u32)0x1FF << 23))
++
++#define MISC_UART0_ACT0_Pin			(0x1 << 2)
++#define MISC_UART1_ACT1_Pin			(0x1 << 3)
++
++#define MISC_GPIOA_PIN_0			0
++#define MISC_GPIOA_PIN_1			1
++#define MISC_GPIOA_PIN_2			2
++#define MISC_GPIOA_PIN_3			3
++#define MISC_GPIOA_PIN_4			4
++#define MISC_GPIOA_PIN_5			5
++#define MISC_GPIOA_PIN_6			6
++#define MISC_GPIOA_PIN_7			7
++#define MISC_GPIOA_PIN_8			8
++#define MISC_GPIOA_PIN_9			9
++#define MISC_GPIOA_PIN_10			10
++
++#define MISC_GPIOA_75K_RESISTOR_PULL_DOWN	1
++#define MISC_GPIOA_75K_RESISTOR_PULL_UP		2
++#define MISC_GPIOA_75K_RESISTOR_PULL_KEEPER	3
++
++#define MISC_GPIOA_DRIVE_STRENGTH_4MA		0
++#define MISC_GPIOA_DRIVE_STRENGTH_8MA		1
++
++
++/*
++ * macro declarations
++ */
++#define HAL_MISC_ENABLE_SPI_SERIAL_FLASH_BANK_ACCESS() \
++{ \
++    (MISC_CHIP_CONFIG_REG) |= (0x1 << 4); \
++}
++
++#define HAL_MISC_DISABLE_SPI_SERIAL_FLASH_BANK_ACCESS()	\
++{ \
++    (MISC_CHIP_CONFIG_REG) &= ~(0x1 << 4); \
++}
++
++
++/*
++ * Macro defines for GPIOA and GPIOB Pin Enable	Register
++ */
++#define HAL_MISC_ENABLE_EXT_INT29_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	|= (MISC_EXT_INT29_PINS); \
++}
++
++#define HAL_MISC_DISABLE_EXT_INT29_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_EXT_INT29_PINS); \
++}
++
++#define HAL_MISC_ENABLE_EXT_INT30_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	|= (MISC_EXT_INT30_PINS); \
++}
++
++#define HAL_MISC_DISABLE_EXT_INT30_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_EXT_INT30_PINS); \
++}
++
++#define HAL_MISC_ENABLE_I2C_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	|= (MISC_I2C_PINS); \
++}
++
++#define HAL_MISC_DISABLE_I2C_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_I2C_PINS); \
++}
++
++#define HAL_MISC_ENABLE_I2S_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	|= (MISC_I2S_PINS); \
++}
++
++#define HAL_MISC_DISABLE_I2S_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_I2S_PINS); \
++}
++
++#define HAL_MISC_DISABLE_I2SSD_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_I2SSD_PINS); \
++}
++
++#define HAL_MISC_DISABLE_I2SWS_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_I2SWS_PINS); \
++}
++
++#define HAL_MISC_DISABLE_I2SCLK_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_I2SCLK_PINS); \
++}
++
++#define HAL_MISC_ENABLE_PCM_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	|= (MISC_PCM_PINS); \
++}
++
++#define HAL_MISC_DISABLE_PCM_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_PCM_PINS); \
++}
++
++#define HAL_MISC_DISABLE_PCMDR_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_PCMDR_PINS); \
++}
++
++#define HAL_MISC_DISABLE_PCMDT_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_PCMDT_PINS); \
++}
++
++#define HAL_MISC_DISABLE_PCMFS_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_PCMFS_PINS); \
++}
++
++#define HAL_MISC_DISABLE_PCMCLK_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_PCMCLK_PINS); \
++}
++
++#define HAL_MISC_ENABLE_LED0_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	|= (MISC_LED0_PINS); \
++}
++
++#define HAL_MISC_DISABLE_LED0_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_LED0_PINS); \
++}
++
++#define HAL_MISC_ENABLE_LED1_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	|= (MISC_LED1_PINS); \
++}
++
++#define HAL_MISC_DISABLE_LED1_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_LED1_PINS); \
++}
++
++#define HAL_MISC_ENABLE_LED2_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	|= (MISC_LED2_PINS); \
++}
++
++#define HAL_MISC_DISABLE_LED2_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_LED2_PINS); \
++}
++
++#define HAL_MISC_ENABLE_LED012_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	|= (MISC_LED012_PINS); \
++}
++
++#define HAL_MISC_DISABLE_LED012_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_LED012_PINS);	\
++}
++
++#define HAL_MISC_ENABLE_WDTIMER_RESET_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	|= (MISC_WDTIMER_RESET_PINS); \
++}
++
++#define HAL_MISC_DISABLE_WDTIMER_RESET_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_WDTIMER_RESET_PINS); \
++}
++
++#define HAL_MISC_ENABLE_SPI_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	|= (MISC_SPI_PINS); \
++}
++
++#define HAL_MISC_ENABLE_SPIDR_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	|= (MISC_SPIDR_PINS); \
++}
++
++#define HAL_MISC_ENABLE_SPICLK_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	|= (MISC_SPICLK_PINS); \
++}
++
++#define HAL_MISC_ENABLE_SPICSN0_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	|= (MISC_SPICSN0_PINS); \
++}
++
++#define HAL_MISC_ENABLE_SPICSN0_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	|= (MISC_SPICSN0_PINS); \
++}
++
++#define HAL_MISC_ENABLE_SPICSN1_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	|= (MISC_SPICSN1_PINS); \
++}
++
++#define HAL_MISC_ENABLE_SPICSN2_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	|= (MISC_SPICSN2_PINS); \
++}
++
++#define HAL_MISC_ENABLE_SPICSN3_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	|= (MISC_SPICSN3_PINS); \
++}
++
++#define HAL_MISC_DISABLE_SPI_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_SPI_PINS); \
++}
++
++#define HAL_MISC_DISABLE_SPIDR_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_SPIDR_PINS); \
++}
++
++#define HAL_MISC_DISABLE_SPICLK_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_SPICLK_PINS); \
++}
++
++#define HAL_MISC_DISABLE_SPICSN0_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_SPICSN0_PINS); \
++}
++
++#define HAL_MISC_DISABLE_SPICSN1_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_SPICSN1_PINS); \
++}
++
++#define HAL_MISC_DISABLE_SPICSN2_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_SPICSN2_PINS); \
++}
++
++#define HAL_MISC_DISABLE_SPICSN3_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_SPICSN3_PINS); \
++}
++
++#define HAL_MISC_ENABLE_UART0_ACT0_PIN() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	|= (MISC_UART0_ACT0_Pin); \
++}
++
++#define HAL_MISC_DISABLE_UART0_ACT0_PIN() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_UART0_ACT0_Pin); \
++}
++
++#define HAL_MISC_ENABLE_UART1_ACT1_PIN() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	|= (MISC_UART1_ACT1_Pin); \
++}
++
++#define HAL_MISC_DISABLE_UART1_ACT1_PIN() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	&= ~(MISC_UART1_ACT1_Pin); \
++}
++
++#define HAL_MISC_ENABLE_MDC_MDIO_PINS()	\
++{ \
++    (MISC_GPIOB_PIN_ENABLE_REG)	|= (MISC_MDC_MDIO_PINS); \
++}
++
++#define HAL_MISC_DISABLE_MDC_MDIO_PINS() \
++{ \
++    (MISC_GPIOB_PIN_ENABLE_REG)	&= ~(MISC_MDC_MDIO_PINS); \
++}
++
++#define HAL_MISC_ENABLE_NIC_COL_PINS() \
++{ \
++    (MISC_GPIOB_PIN_ENABLE_REG)	|= (MISC_NIC_COL_PINS);	\
++}
++
++#define HAL_MISC_DISABLE_NIC_COL_PINS()	\
++{ \
++    (MISC_GPIOB_PIN_ENABLE_REG)	&= ~(MISC_NIC_COL_PINS); \
++}
++
++#define HAL_MISC_ENABLE_IDE_PINS() \
++{ \
++    (MISC_GPIOB_PIN_ENABLE_REG)	|= (MISC_IDE_PINS); \
++}
++
++#define HAL_MISC_DISABLE_IDE_PINS() \
++{ \
++    (MISC_GPIOB_PIN_ENABLE_REG)	&= ~(MISC_IDE_PINS); \
++}
++
++#define HAL_MISC_ENABLE_SRAM_BANK1_PINS() \
++{ \
++    (MISC_GPIOB_PIN_ENABLE_REG)	|= (MISC_SRAM_BANK1_PINS); \
++}
++
++#define HAL_MISC_DISABLE_SRAM_BANK1_PINS() \
++{ \
++    (MISC_GPIOB_PIN_ENABLE_REG)	&= ~(MISC_SRAM_BANK1_PINS); \
++}
++
++#define HAL_MISC_ENABLE_SRAM_BANK2_PINS() \
++{ \
++    (MISC_GPIOB_PIN_ENABLE_REG)	|= (MISC_SRAM_BANK2_PINS); \
++}
++
++#define HAL_MISC_DISABLE_SRAM_BANK2_PINS() \
++{ \
++    (MISC_GPIOB_PIN_ENABLE_REG)	&= ~(MISC_SRAM_BANK2_PINS); \
++}
++
++#define HAL_MISC_ENABLE_SRAM_BANK3_PINS() \
++{ \
++    (MISC_GPIOB_PIN_ENABLE_REG)	|= (MISC_SRAM_BANK3_PINS); \
++}
++
++#define HAL_MISC_DISABLE_SRAM_BANK3_PINS() \
++{ \
++    (MISC_GPIOB_PIN_ENABLE_REG)	&= ~(MISC_SRAM_BANK3_PINS); \
++}
++
++#define HAL_MISC_ENABLE_PCMCIA_PINS() \
++{ \
++    (MISC_GPIOB_PIN_ENABLE_REG)	|= (MISC_PCMCIA_PINS); \
++}
++
++#define HAL_MISC_DISABLE_PCMCIA_PINS() \
++{ \
++    (MISC_GPIOB_PIN_ENABLE_REG)	&= ~(MISC_PCMCIA_PINS);	\
++}
++
++#define HAL_MISC_ENABLE_UART1_PINS() \
++{ \
++    (MISC_GPIOB_PIN_ENABLE_REG)	|= (MISC_UART1_PINS); \
++}
++
++#define HAL_MISC_DISABLE_UART1_PINS() \
++{ \
++    (MISC_GPIOB_PIN_ENABLE_REG)	&= ~(MISC_UART1_PINS); \
++}
++
++#define HAL_MISC_ENABLE_PCI_PINS() \
++{ \
++    (MISC_GPIOB_PIN_ENABLE_REG)	|= (MISC_PCI_PINS); \
++}
++
++#define HAL_MISC_DISABLE_PCI_PINS() \
++{ \
++    (MISC_GPIOB_PIN_ENABLE_REG)	&= ~(MISC_PCI_PINS); \
++}
++
++#define HAL_MISC_ENABLE_ALL_SHARED_GPIO_PINS() \
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	= (0x0); \
++    (MISC_GPIOB_PIN_ENABLE_REG)	= (0x0); \
++}
++
++#define HAL_MISC_DISABLE_ALL_SHARED_GPIO_PINS()	\
++{ \
++    (MISC_GPIOA_PIN_ENABLE_REG)	= (0xFFFFFFFF);	\
++    (MISC_GPIOB_PIN_ENABLE_REG)	= (0xFFFFFFFF);	\
++}
++
++#define HAL_MISC_CONFIGURE_GPIOA_RESISTOR(pin_index, value) \
++{ \
++    (MISC_GPIOA_RESISTOR_CONFIG_REG) &=	~(0x3 << (2 * pin_index)); \
++    (MISC_GPIOA_RESISTOR_CONFIG_REG) |=	((value	& 0x3) << (2 * pin_index)); \
++}
++
++#define HAL_MISC_CONFIGURE_GPIOA_DRIVE_STRENGTH(pin_index, value) \
++{ \
++    (MISC_GPIOA_DRIVE_STRENGTH_CONFIG_REG) &= ~(0x1 << pin_index); \
++    (MISC_GPIOA_DRIVE_STRENGTH_CONFIG_REG) |= (value <<	pin_index); \
++}
++
++#define HAL_MISC_SELECT_FAST_ETHERNET_PHY_LED_MODE0() \
++{ \
++    (MISC_FAST_ETHERNET_PHY_CONFIG_REG)	= (0x0); \
++}
++
++#define HAL_MISC_SELECT_FAST_ETHERNET_PHY_LED_MODE1() \
++{ \
++    (MISC_FAST_ETHERNET_PHY_CONFIG_REG)	= (0x1); \
++}
++
++#define HAL_MISC_SELECT_FAST_ETHERNET_PHY_LED_MODE2() \
++{ \
++    (MISC_FAST_ETHERNET_PHY_CONFIG_REG)	= (0x2); \
++}
++
++#define HAL_MISC_SELECT_FAST_ETHERNET_PHY_LED_MODE3() \
++{ \
++    (MISC_FAST_ETHERNET_PHY_CONFIG_REG)	= (0x3); \
++}
++
++
++#endif	// end of #ifndef _STAR_MISC_H_
diff --git a/target/linux/cns21xx/patches-3.6/101-cns21xx-serial-support.patch b/target/linux/cns21xx/patches-3.6/101-cns21xx-serial-support.patch
new file mode 100644
index 0000000000..05ad3e4682
--- /dev/null
+++ b/target/linux/cns21xx/patches-3.6/101-cns21xx-serial-support.patch
@@ -0,0 +1,103 @@
+--- a/arch/arm/mach-cns21xx/common.h
++++ b/arch/arm/mach-cns21xx/common.h
+@@ -16,4 +16,7 @@ void cns21xx_init_irq(void);
+ 
+ extern struct sys_timer cns21xx_timer;
+ 
++int cns21xx_register_uart0(void);
++int cns21xx_register_uart1(void);
++
+ #endif /* _MACH_CNS21XX_COMMON_H */
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/devices.c
+@@ -0,0 +1,79 @@
++/*
++ *  Copyright (c) 2008 Cavium Networks
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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/init.h>
++#include <linux/platform_device.h>
++#include <linux/serial_8250.h>
++
++#include <mach/irqs.h>
++#include <mach/hardware.h>
++#include <mach/cns21xx.h>
++#include <mach/cns21xx_misc.h>
++
++#define CNS21XX_UART_CLOCK	24000000
++
++#define CNS21XX_UART_FLAGS (UPF_SKIP_TEST | UPF_FIXED_TYPE | UPF_NO_TXEN_TEST)
++
++static struct plat_serial8250_port cns21xx_uart0_data[] = {
++	{
++		.mapbase	= CNS21XX_UART0_BASE,
++		.membase	= (void *) CNS21XX_UART0_BASE_VIRT,
++		.irq		= CNS21XX_IRQ_UART0,
++		.uartclk	= CNS21XX_UART_CLOCK,
++		.regshift	= 2,
++		.iotype		= UPIO_MEM,
++		.type		= PORT_16550A,
++		.flags		= CNS21XX_UART_FLAGS,
++	}, {
++		/* terminating entry */
++	},
++};
++
++static struct platform_device cns21xx_uart0_device = {
++	.name	= "serial8250",
++	.id	= PLAT8250_DEV_PLATFORM,
++	.dev	= {
++		.platform_data = cns21xx_uart0_data,
++	},
++};
++
++int __init cns21xx_register_uart0(void)
++{
++	return platform_device_register(&cns21xx_uart0_device);
++}
++
++static struct plat_serial8250_port cns21xx_uart1_data[] = {
++	{
++		.mapbase	= CNS21XX_UART1_BASE,
++		.membase	= (void *) CNS21XX_UART1_BASE_VIRT,
++		.irq		= CNS21XX_IRQ_UART1,
++		.uartclk	= CNS21XX_UART_CLOCK,
++		.regshift	= 2,
++		.iotype		= UPIO_MEM,
++		.type		= PORT_16550A,
++		.flags		= CNS21XX_UART_FLAGS,
++	}, {
++		/* terminating entry */
++	},
++};
++
++static struct platform_device cns21xx_uart1_device = {
++	.name	= "serial8250",
++	.id	= PLAT8250_DEV_PLATFORM1,
++	.dev	= {
++		.platform_data = cns21xx_uart1_data,
++	},
++};
++
++int __init cns21xx_register_uart1(void)
++{
++	HAL_MISC_ENABLE_UART1_PINS();
++	return platform_device_register(&cns21xx_uart1_device);
++}
+--- a/arch/arm/mach-cns21xx/Makefile
++++ b/arch/arm/mach-cns21xx/Makefile
+@@ -4,7 +4,7 @@
+ 
+ # Object file lists.
+ 
+-obj-y		:= core.o irq.o mm.o time.o
++obj-y		:= core.o devices.o irq.o mm.o time.o
+ 
+ # machine specific files
+ 
diff --git a/target/linux/cns21xx/patches-3.6/102-cns21xx-gpiolib-support.patch b/target/linux/cns21xx/patches-3.6/102-cns21xx-gpiolib-support.patch
new file mode 100644
index 0000000000..19c8e3ce97
--- /dev/null
+++ b/target/linux/cns21xx/patches-3.6/102-cns21xx-gpiolib-support.patch
@@ -0,0 +1,85 @@
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -390,6 +390,8 @@ config ARCH_CNS21XX
+ 	select CPU_FA526
+ 	select PLAT_FA
+ 	select PLAT_FA_TIME
++	select PLAT_FA_GPIO
++	select ARCH_REQUIRE_GPIOLIB
+ 	select ARM_L1_CACHE_SHIFT_4
+ 	help
+ 	  Support for Cavium Networks CNS21xx family.
+--- a/arch/arm/mach-cns21xx/common.h
++++ b/arch/arm/mach-cns21xx/common.h
+@@ -13,6 +13,7 @@
+ void cns21xx_restart(char mode, const char *cmd);
+ void cns21xx_map_io(void);
+ void cns21xx_init_irq(void);
++void cns21xx_gpio_init(void);
+ 
+ extern struct sys_timer cns21xx_timer;
+ 
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/gpio.c
+@@ -0,0 +1,45 @@
++/*
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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 <plat/gpio.h>
++
++#include <mach/cns21xx.h>
++#include <mach/irqs.h>
++
++static struct fa_gpio_chip cns21xx_gpio_chips[] = {
++	{
++		.gpio_chip = {
++			.label	= "GPIOA",
++			.base	= 0,
++			.ngpio	= 32,
++		},
++
++		.map_base	= CNS21XX_GPIOA_BASE,
++		.irq_base	= CNS21XX_GPIO_IRQ_BASE,
++	}, {
++		.gpio_chip = {
++			.label	= "GPIOB",
++			.base	= 32,
++			.ngpio	= 32,
++		},
++
++		.map_base	= CNS21XX_GPIOB_BASE,
++		.irq_base	= CNS21XX_GPIO_IRQ_BASE + 32,
++	}
++};
++
++static struct fa_gpio_data cns21xx_gpio_data = {
++	.chips	= cns21xx_gpio_chips,
++	.nchips = ARRAY_SIZE(cns21xx_gpio_chips),
++	.irq	= CNS21XX_IRQ_GPIO,
++};
++
++void __init cns21xx_gpio_init(void)
++{
++	fa_gpio_init(&cns21xx_gpio_data);
++}
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/include/mach/gpio.h
+@@ -0,0 +1,2 @@
++/* empty */
++
+--- a/arch/arm/mach-cns21xx/Makefile
++++ b/arch/arm/mach-cns21xx/Makefile
+@@ -4,7 +4,7 @@
+ 
+ # Object file lists.
+ 
+-obj-y		:= core.o devices.o irq.o mm.o time.o
++obj-y		:= core.o devices.o gpio.o irq.o mm.o time.o
+ 
+ # machine specific files
+ 
diff --git a/target/linux/cns21xx/patches-3.6/103-cns21xx-usb-ohci-support.patch b/target/linux/cns21xx/patches-3.6/103-cns21xx-usb-ohci-support.patch
new file mode 100644
index 0000000000..5770c212dd
--- /dev/null
+++ b/target/linux/cns21xx/patches-3.6/103-cns21xx-usb-ohci-support.patch
@@ -0,0 +1,230 @@
+--- a/drivers/usb/host/ohci-hcd.c
++++ b/drivers/usb/host/ohci-hcd.c
+@@ -579,7 +579,6 @@ static int ohci_run (struct ohci_hcd *oh
+ 
+ 	/* boot firmware should have set this up (5.1.1.3.1) */
+ 	if (first) {
+-
+ 		val = ohci_readl (ohci, &ohci->regs->fminterval);
+ 		ohci->fminterval = val & 0x3fff;
+ 		if (ohci->fminterval != FI)
+@@ -663,6 +662,9 @@ retry:
+ 
+ 	periodic_reinit (ohci);
+ 
++	if (ohci->flags & OHCI_QUIRK_INIT_FMINTERVAL)
++		ohci_writel (ohci, ohci->fminterval, &ohci->regs->fminterval);
++
+ 	/* some OHCI implementations are finicky about how they init.
+ 	 * bogus values here mean not even enumeration could work.
+ 	 */
+@@ -1105,6 +1107,11 @@ MODULE_LICENSE ("GPL");
+ #define PLATFORM_DRIVER		ohci_hcd_tilegx_driver
+ #endif
+ 
++#ifdef CONFIG_ARCH_CNS21XX
++#include "ohci-cns21xx.c"
++#define PLATFORM_DRIVER		ohci_cns21xx_driver
++#endif
++
+ #ifdef CONFIG_USB_CNS3XXX_OHCI
+ #include "ohci-cns3xxx.c"
+ #define PLATFORM_DRIVER		ohci_hcd_cns3xxx_driver
+--- /dev/null
++++ b/drivers/usb/host/ohci-cns21xx.c
+@@ -0,0 +1,175 @@
++/*
++ *  Copyright (c) 2008 Cavium Networks
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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 <mach/cns21xx.h>
++
++#define DRIVER_NAME	"cns21xx-ohci"
++
++static int __devinit cns21xx_ohci_start(struct usb_hcd *hcd)
++{
++	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
++	int ret;
++
++	ret = ohci_init(ohci);
++	if (ret)
++		return ret;
++
++	ret = ohci_run(ohci);
++	if (ret) {
++		err("can't start %s", ohci_to_hcd(ohci)->self.bus_name);
++		goto err;
++	}
++
++	return 0;
++
++err:
++	ohci_stop(hcd);
++	return ret;
++}
++
++static const struct hc_driver ohci_cns21xx_hc_driver = {
++	.description		= hcd_name,
++	.product_desc		= "cns21xx-ohci",
++	.hcd_priv_size		= sizeof(struct ohci_hcd),
++
++	/*
++	 * generic hardware linkage
++	 */
++	.irq			= ohci_irq,
++	.flags			= HCD_USB11 | HCD_MEMORY,
++
++	/*
++	 * basic lifecycle operations
++	 */
++	.start			= cns21xx_ohci_start,
++	.stop			= ohci_stop,
++	.shutdown		= ohci_shutdown,
++
++	/*
++	 * managing i/o requests and associated device resources
++	 */
++	.urb_enqueue		= ohci_urb_enqueue,
++	.urb_dequeue		= ohci_urb_dequeue,
++	.endpoint_disable	= ohci_endpoint_disable,
++
++	/*
++	 * scheduling support
++	 */
++	.get_frame_number	= ohci_get_frame,
++
++	/*
++	 * root hub support
++	 */
++	.hub_status_data	= ohci_hub_status_data,
++	.hub_control		= ohci_hub_control,
++	.start_port_reset	= ohci_start_port_reset,
++};
++
++static void cns21xx_ohci_init_hc(void)
++{
++	__raw_writel(0x146, CNS21XX_OHCI_CONFIG_BASE_VIRT + 0x04);
++	__raw_writel(0x200, CNS21XX_OHCI_CONFIG_BASE_VIRT + 0x44);
++	msleep(100);
++}
++
++static int ohci_cns21xx_probe(struct platform_device *pdev)
++{
++	struct usb_hcd *hcd;
++	struct resource *res;
++	struct ohci_hcd *ohci;
++	int irq;
++	int ret;
++
++	if (usb_disabled())
++		return -ENODEV;
++
++	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++	if (!res) {
++		dev_dbg(&pdev->dev, "no IRQ specified for %s\n",
++			dev_name(&pdev->dev));
++		return -ENODEV;
++	}
++	irq = res->start;
++
++	hcd = usb_create_hcd(&ohci_cns21xx_hc_driver, &pdev->dev,
++			     dev_name(&pdev->dev));
++	if (!hcd)
++		return -ENOMEM;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		dev_dbg(&pdev->dev, "no base address specified for %s\n",
++			dev_name(&pdev->dev));
++		ret = -ENODEV;
++		goto err_put_hcd;
++	}
++	hcd->rsrc_start	= res->start;
++	hcd->rsrc_len	= res->end - res->start + 1;
++
++	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
++		dev_dbg(&pdev->dev, "controller already in use\n");
++		ret = -EBUSY;
++		goto err_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 err_release_region;
++	}
++
++	cns21xx_ohci_init_hc();
++
++	ohci = hcd_to_ohci(hcd);
++	ohci->flags |= OHCI_QUIRK_INIT_FMINTERVAL;
++	ohci_hcd_init(ohci);
++
++	ret = usb_add_hcd(hcd, irq,  IRQF_DISABLED);
++	if (ret)
++		goto err_unmap;
++
++	platform_set_drvdata(pdev, hcd);
++	return 0;
++
++err_unmap:
++	iounmap(hcd->regs);
++err_release_region:
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++err_put_hcd:
++	usb_put_hcd(hcd);
++	return ret;
++}
++
++static int ohci_cns21xx_remove(struct platform_device *pdev)
++{
++	struct usb_hcd *hcd = platform_get_drvdata(pdev);
++
++	usb_remove_hcd(hcd);
++	iounmap(hcd->regs);
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++	usb_put_hcd(hcd);
++	platform_set_drvdata(pdev, NULL);
++
++	return 0;
++}
++
++static struct platform_driver ohci_cns21xx_driver = {
++	.probe		= ohci_cns21xx_probe,
++	.remove		= ohci_cns21xx_remove,
++	.shutdown	= usb_hcd_platform_shutdown,
++	.driver		= {
++		.owner	= THIS_MODULE,
++		.name	= DRIVER_NAME,
++	},
++};
++
++MODULE_ALIAS("platform:" DRIVER_NAME);
+--- a/drivers/usb/host/ohci.h
++++ b/drivers/usb/host/ohci.h
+@@ -405,6 +405,7 @@ struct ohci_hcd {
+ #define	OHCI_QUIRK_HUB_POWER	0x100			/* distrust firmware power/oc setup */
+ #define	OHCI_QUIRK_AMD_PLL	0x200			/* AMD PLL quirk*/
+ #define	OHCI_QUIRK_AMD_PREFETCH	0x400			/* pre-fetch for ISO transfer */
++#define OHCI_QUIRK_INIT_FMINTERVAL 0x1000		/* fminterval must be initialized */
+ 	// there are also chip quirks/bugs in init logic
+ 
+ 	struct work_struct	nec_work;	/* Worker for NEC quirk */
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -393,6 +393,7 @@ config ARCH_CNS21XX
+ 	select PLAT_FA_GPIO
+ 	select ARCH_REQUIRE_GPIOLIB
+ 	select ARM_L1_CACHE_SHIFT_4
++	select USB_ARCH_HAS_OHCI
+ 	help
+ 	  Support for Cavium Networks CNS21xx family.
+ 
diff --git a/target/linux/cns21xx/patches-3.6/104-cns21xx-usb-ehci-support.patch b/target/linux/cns21xx/patches-3.6/104-cns21xx-usb-ehci-support.patch
new file mode 100644
index 0000000000..3936d10f08
--- /dev/null
+++ b/target/linux/cns21xx/patches-3.6/104-cns21xx-usb-ehci-support.patch
@@ -0,0 +1,213 @@
+--- /dev/null
++++ b/drivers/usb/host/ehci-cns21xx.c
+@@ -0,0 +1,186 @@
++/*
++ *  Copyright (c) 2008 Cavium Networks
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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/irq.h>
++
++#include <mach/cns21xx.h>
++
++#define DRIVER_NAME	"cns21xx-ehci"
++
++static int cns21xx_ehci_reset(struct usb_hcd *hcd)
++{
++	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++	int ret;
++
++	ret = ehci_halt(ehci);
++	if (ret)
++		return ret;
++
++	ret = ehci_init(hcd);
++	if (ret)
++		return ret;
++
++	ehci_reset(ehci);
++	ehci_port_power(ehci, 0);
++
++	return 0;
++}
++
++static const struct hc_driver ehci_cns21xx_hc_driver = {
++	.description		= hcd_name,
++        .product_desc		= DRIVER_NAME,
++        .hcd_priv_size		= sizeof(struct ehci_hcd),
++
++	/*
++	 * generic hardware linkage
++	 */
++	.irq			= ehci_irq,
++	.flags			= HCD_MEMORY | HCD_USB2,
++
++	/*
++	 * basic lifecycle operations
++	 */
++	.reset			= cns21xx_ehci_reset,
++	.start			= ehci_run,
++	.stop			= ehci_stop,
++	.shutdown		= ehci_shutdown,
++
++	/*
++	 * managing i/o requests and associated device resources
++	 */
++	.urb_enqueue		= ehci_urb_enqueue,
++	.urb_dequeue		= ehci_urb_dequeue,
++	.endpoint_disable	= ehci_endpoint_disable,
++	.endpoint_reset		= ehci_endpoint_reset,
++
++	/*
++	 * scheduling support
++	 */
++	.get_frame_number	= ehci_get_frame,
++
++	/*
++	 * root hub support
++	 */
++	.hub_status_data	= ehci_hub_status_data,
++	.hub_control		= ehci_hub_control,
++	.relinquish_port	= ehci_relinquish_port,
++	.port_handed_over	= ehci_port_handed_over,
++
++	.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
++};
++
++static void cns21xx_ehci_init_hc(void)
++{
++	__raw_writel(0x106, CNS21XX_EHCI_CONFIG_BASE_VIRT + 0x04);
++	__raw_writel((3 << 5) | 0x2000, CNS21XX_EHCI_CONFIG_BASE_VIRT + 0x40);
++	msleep(100);
++}
++
++static int ehci_cns21xx_probe(struct platform_device *pdev)
++{
++	struct usb_hcd *hcd;
++	struct ehci_hcd *ehci;
++	struct resource *res;
++	int irq;
++	int ret;
++
++	if (usb_disabled())
++		return -ENODEV;
++
++	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++	if (!res) {
++		dev_dbg(&pdev->dev, "no IRQ specified for %s\n",
++			dev_name(&pdev->dev));
++		return -ENODEV;
++	}
++	irq = res->start;
++
++	hcd = usb_create_hcd(&ehci_cns21xx_hc_driver, &pdev->dev,
++			     dev_name(&pdev->dev));
++	if (!hcd)
++		return -ENOMEM;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		dev_dbg(&pdev->dev, "no base address specified for %s\n",
++			dev_name(&pdev->dev));
++		ret = -ENODEV;
++		goto err_put_hcd;
++	}
++	hcd->rsrc_start	= res->start;
++	hcd->rsrc_len	= res->end - res->start + 1;
++
++	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
++		dev_dbg(&pdev->dev, "controller already in use\n");
++		ret = -EBUSY;
++		goto err_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 err_release_region;
++	}
++
++	cns21xx_ehci_init_hc();
++
++	ehci = hcd_to_ehci(hcd);
++
++	ehci->caps = hcd->regs;
++	ehci->regs = hcd->regs +
++		     HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
++	dbg_hcs_params(ehci, "reset");
++	dbg_hcc_params(ehci, "reset");
++
++	/* cache this readonly data; minimize chip reads */
++	ehci->hcs_params = readl(&ehci->caps->hcs_params);
++	ehci->sbrn = 0x20;
++
++	ret = usb_add_hcd(hcd, CNS21XX_IRQ_EHCI, IRQF_DISABLED);
++	if (ret)
++		goto err_unmap;
++
++	platform_set_drvdata(pdev, hcd);
++	return 0;
++
++err_unmap:
++	iounmap(hcd->regs);
++err_release_region:
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++err_put_hcd:
++	usb_put_hcd(hcd);
++	return ret;
++}
++
++static int ehci_cns21xx_remove(struct platform_device *pdev)
++{
++	struct usb_hcd *hcd = platform_get_drvdata(pdev);
++
++	usb_remove_hcd(hcd);
++	iounmap(hcd->regs);
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++	usb_put_hcd(hcd);
++	platform_set_drvdata(pdev, NULL);
++
++	return 0;
++}
++
++static struct platform_driver ehci_cns21xx_driver = {
++	.probe		= ehci_cns21xx_probe,
++	.remove		= ehci_cns21xx_remove,
++	.shutdown       = usb_hcd_platform_shutdown,
++	.driver		= {
++		.owner	= THIS_MODULE,
++		.name	= DRIVER_NAME,
++	},
++};
++
++MODULE_ALIAS("platform:" DRIVER_NAME);
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -1339,6 +1339,11 @@ MODULE_LICENSE ("GPL");
+ #define PLATFORM_DRIVER		ehci_platform_driver
+ #endif
+ 
++#ifdef CONFIG_ARCH_CNS21XX
++#include "ehci-cns21xx.c"
++#define PLATFORM_DRIVER		ehci_cns21xx_driver
++#endif
++
+ #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
+     !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
+     !defined(XILINX_OF_PLATFORM_DRIVER)
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -394,6 +394,7 @@ config ARCH_CNS21XX
+ 	select ARCH_REQUIRE_GPIOLIB
+ 	select ARM_L1_CACHE_SHIFT_4
+ 	select USB_ARCH_HAS_OHCI
++	select USB_ARCH_HAS_EHCI
+ 	help
+ 	  Support for Cavium Networks CNS21xx family.
+ 
diff --git a/target/linux/cns21xx/patches-3.6/105-cns21xx-spi-driver.patch b/target/linux/cns21xx/patches-3.6/105-cns21xx-spi-driver.patch
new file mode 100644
index 0000000000..363a3b5343
--- /dev/null
+++ b/target/linux/cns21xx/patches-3.6/105-cns21xx-spi-driver.patch
@@ -0,0 +1,578 @@
+--- a/include/linux/spi/spi.h
++++ b/include/linux/spi/spi.h
+@@ -507,6 +507,8 @@ struct spi_transfer {
+ 	u16		delay_usecs;
+ 	u32		speed_hz;
+ 
++	unsigned	last_in_message_list;
++
+ 	struct list_head transfer_list;
+ };
+ 
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -178,6 +178,14 @@ config SPI_GPIO_OLD
+ 
+ 	  If unsure, say N.
+ 
++config SPI_CNS21XX
++	tristate "Cavium Netowrks CNS21xx SPI master"
++	depends on ARCH_CNS21XX && EXPERIMENTAL
++	select SPI_BITBANG
++	help
++	  This driver supports the buil-in SPI controller of the Cavium Networks
++	  CNS21xx SoCs.
++
+ config SPI_IMX
+ 	tristate "Freescale i.MX SPI controllers"
+ 	depends on ARCH_MXC
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -19,6 +19,7 @@ obj-$(CONFIG_SPI_BFIN5XX)		+= spi-bfin5x
+ obj-$(CONFIG_SPI_BFIN_SPORT)		+= spi-bfin-sport.o
+ obj-$(CONFIG_SPI_BITBANG)		+= spi-bitbang.o
+ obj-$(CONFIG_SPI_BUTTERFLY)		+= spi-butterfly.o
++obj-$(CONFIG_SPI_CNS21XX)		+= spi-cns21xx.o
+ obj-$(CONFIG_SPI_COLDFIRE_QSPI)		+= spi-coldfire-qspi.o
+ obj-$(CONFIG_SPI_DAVINCI)		+= spi-davinci.o
+ obj-$(CONFIG_SPI_DESIGNWARE)		+= spi-dw.o
+--- a/drivers/spi/spi-bitbang.c
++++ b/drivers/spi/spi-bitbang.c
+@@ -330,6 +330,13 @@ static void bitbang_work(struct work_str
+ 				 */
+ 				if (!m->is_dma_mapped)
+ 					t->rx_dma = t->tx_dma = 0;
++
++				if (t->transfer_list.next == &m->transfers) {
++					t->last_in_message_list = 1;
++				} else {
++					t->last_in_message_list = 0;
++				}
++
+ 				status = bitbang->txrx_bufs(spi, t);
+ 			}
+ 			if (status > 0)
+--- /dev/null
++++ b/drivers/spi/spi-cns21xx.c
+@@ -0,0 +1,521 @@
++/*
++ *  Copyright (c) 2008 Cavium Networks
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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/init.h>
++#include <linux/module.h>
++#include <linux/spinlock.h>
++#include <linux/workqueue.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/errno.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spi_bitbang.h>
++
++#include <mach/hardware.h>
++#include <mach/cns21xx.h>
++
++#define DRIVER_NAME	"cns21xx-spi"
++
++#ifdef CONFIG_CNS21XX_SPI_DEBUG
++#define DBG(fmt, args...)	pr_info("[CNS21XX_SPI_DEBUG]" fmt, ## args)
++#else
++#define DBG(fmt, args...)	do {} while (0)
++#endif /*  CNS21XX_SPI_DEBUG */
++
++#define SPI_REG_CFG			0x40
++#define SPI_REG_STAT			0x44
++#define SPI_REG_BIT_RATE		0x48
++#define SPI_REG_TX_CTRL			0x4c
++#define SPI_REG_TX_DATA			0x50
++#define SPI_REG_RX_CTRL			0x54
++#define SPI_REG_RX_DATA			0x58
++#define SPI_REG_FIFO_TX_CFG		0x5c
++#define SPI_REG_FIFO_TX_CTRL		0x60
++#define SPI_REG_FIFO_RX_CFG		0x64
++#define SPI_REG_INTR_STAT		0x68
++#define SPI_REG_INTR_ENA		0x6c
++
++#define CFG_SPI_EN			BIT(31)
++#define CFG_SPI_CLKPOL			BIT(14)
++#define CFG_SPI_CLKPHA			BIT(13)
++#define CFG_SPI_MASTER_EN		BIT(11)
++#define CFG_SPI_CHAR_LEN_M		0x3
++#define CFG_SPI_CHAR_LEN_8BITS		0
++#define CFG_SPI_CHAR_LEN_16BITS		1
++#define CFG_SPI_CHAR_LEN_24BITS		2
++#define CFG_SPI_CHAR_LEN_32BITS		3
++
++#define STAT_SPI_BUSY_STA		BIT(1)
++
++#define BIT_RATE_DIV_1			0
++#define BIT_RATE_DIV_2			1
++#define BIT_RATE_DIV_4			2
++#define BIT_RATE_DIV_8			3
++#define BIT_RATE_DIV_16			4
++#define BIT_RATE_DIV_32			5
++#define BIT_RATE_DIV_64			6
++#define BIT_RATE_DIV_128		7
++
++#define TX_CTRL_SPI_TXDAT_EOF		BIT(2)
++#define TX_CTRL_SPI_TXCH_NUM_M		0x3
++#define TX_CTRL_CLEAR_MASK		(TX_CTRL_SPI_TXDAT_EOF | \
++					 TX_CTRL_SPI_TXCH_NUM_M)
++
++#define RX_CTRL_SPI_RXDAT_EOF		BIT(2)
++#define RX_CTRL_SPI_RXCH_NUM_M		0x3
++
++#define INTR_STAT_SPI_TXBF_UNRN_FG	BIT(7)
++#define INTR_STAT_SPI_RXBF_OVRN_FG	BIT(6)
++#define INTR_STAT_SPI_TXFF_UNRN_FG	BIT(5)
++#define INTR_STAT_SPI_RXFF_OVRN_FG	BIT(4)
++#define INTR_STAT_SPI_TXBUF_FG		BIT(3)
++#define INTR_STAT_SPI_RXBUF_FG		BIT(2)
++#define INTR_STAT_SPI_TXFF_FG		BIT(1)
++#define INTR_STAT_SPI_RXFF_FG		BIT(0)
++
++#define INTR_STAT_CLEAR_MASK		(INTR_STAT_SPI_TXBF_UNRN_FG | \
++					 INTR_STAT_SPI_RXBF_OVRN_FG | \
++					 INTR_STAT_SPI_TXFF_UNRN_FG | \
++					 INTR_STAT_SPI_RXFF_OVRN_FG)
++
++#define FIFO_TX_CFG_SPI_TXFF_THRED_M	0x3
++#define FIFO_TX_CFG_SPI_TXFF_THRED_S	4
++#define FIFO_TX_CFG_SPI_TXFF_THRED_2	0
++#define FIFO_TX_CFG_SPI_TXFF_THRED_4	1
++#define FIFO_TX_CFG_SPI_TXFF_THRED_6	0
++#define FIFO_TX_CFG_SPI_TXFF_STATUS_M	0xf
++
++#define FIFO_RX_CFG_SPI_RXFF_THRED_M	0x3
++#define FIFO_RX_CFG_SPI_RXFF_THRED_S	4
++#define FIFO_RX_CFG_SPI_RXFF_THRED_2	0
++#define FIFO_RX_CFG_SPI_RXFF_THRED_4	1
++#define FIFO_RX_CFG_SPI_RXFF_THRED_6	0
++#define FIFO_RX_CFG_SPI_RXFF_STATUS_M	0xf
++
++#define CNS21XX_SPI_NUM_BIT_RATES	8
++
++struct cns21xx_spi {
++	struct spi_bitbang	bitbang;
++
++	struct spi_master	*master;
++	struct device		*dev;
++	void __iomem		*base;
++	struct resource		*region;
++
++	unsigned		freq_max;
++	unsigned		freq_min;
++
++};
++
++static inline struct cns21xx_spi *to_hw(struct spi_device *spi)
++{
++	return spi_master_get_devdata(spi->master);
++}
++
++static inline u32 cns21xx_spi_rr(struct cns21xx_spi *hw, unsigned int reg)
++{
++	return __raw_readl(hw->base + reg);
++}
++
++static inline void cns21xx_spi_wr(struct cns21xx_spi *hw, u32 val,
++				  unsigned int reg)
++{
++	__raw_writel(val, hw->base + reg);
++}
++
++#define CNS21XX_SPI_RETRY_COUNT		100
++static inline int cns21xx_spi_wait(struct cns21xx_spi *hw, unsigned int reg,
++				   u32 mask, u32 val)
++{
++	int retry_cnt = 0;
++
++	do {
++		if ((cns21xx_spi_rr(hw, reg) & mask) == val)
++			break;
++
++		if (++retry_cnt > CNS21XX_SPI_RETRY_COUNT) {
++			dev_err(hw->dev, "timeout waiting on register %02x\n",
++				reg);
++			return -EIO;
++		}
++	} while (1);
++
++	return 0;
++}
++
++static int cns21xx_spi_txrx_word(struct cns21xx_spi *hw, u8 tx_channel,
++				 u8 tx_eof_flag, u32 tx_data, u32 *rx_data)
++{
++	unsigned int tx_ctrl;
++	u8 rx_channel;
++	u8 rx_eof_flag;
++	int err = 0;
++
++	err = cns21xx_spi_wait(hw, SPI_REG_STAT, STAT_SPI_BUSY_STA, 0);
++	if (err)
++		return err;
++
++	err = cns21xx_spi_wait(hw, SPI_REG_INTR_STAT, INTR_STAT_SPI_TXBUF_FG,
++			       INTR_STAT_SPI_TXBUF_FG);
++	if (err)
++		return err;
++
++	tx_ctrl = cns21xx_spi_rr(hw, SPI_REG_TX_CTRL);
++	tx_ctrl &= ~(TX_CTRL_CLEAR_MASK);
++	tx_ctrl |= (tx_channel & TX_CTRL_SPI_TXCH_NUM_M);
++	tx_ctrl |= (tx_eof_flag) ? TX_CTRL_SPI_TXDAT_EOF : 0;
++	cns21xx_spi_wr(hw, tx_ctrl, SPI_REG_TX_CTRL);
++
++	cns21xx_spi_wr(hw, tx_data, SPI_REG_TX_DATA);
++
++	err = cns21xx_spi_wait(hw, SPI_REG_INTR_STAT, INTR_STAT_SPI_RXBUF_FG,
++			       INTR_STAT_SPI_RXBUF_FG);
++	if (err)
++		return err;
++
++	rx_channel = cns21xx_spi_rr(hw, SPI_REG_RX_CTRL) &
++					RX_CTRL_SPI_RXCH_NUM_M;
++
++	rx_eof_flag = (cns21xx_spi_rr(hw, SPI_REG_RX_CTRL) &
++					RX_CTRL_SPI_RXDAT_EOF) ? 1 : 0;
++
++	*rx_data = cns21xx_spi_rr(hw, SPI_REG_RX_DATA);
++
++	if ((tx_channel != rx_channel) || (tx_eof_flag != rx_eof_flag))
++		return -EPROTO;
++
++	return 0;
++}
++
++static void cns21xx_spi_chipselect(struct spi_device *spi, int value)
++{
++	struct cns21xx_spi *hw = to_hw(spi);
++	unsigned int spi_config;
++	unsigned int tx_ctrl;
++
++	switch (value) {
++	case BITBANG_CS_INACTIVE:
++		break;
++
++	case BITBANG_CS_ACTIVE:
++		spi_config = cns21xx_spi_rr(hw, SPI_REG_CFG);
++
++		if (spi->mode & SPI_CPHA)
++			spi_config |= CFG_SPI_CLKPHA;
++		else
++			spi_config &= ~CFG_SPI_CLKPHA;
++
++		if (spi->mode & SPI_CPOL)
++			spi_config |= CFG_SPI_CLKPOL;
++		else
++			spi_config &= ~CFG_SPI_CLKPOL;
++
++		cns21xx_spi_wr(hw, spi_config, SPI_REG_CFG);
++
++		tx_ctrl = cns21xx_spi_rr(hw, SPI_REG_TX_CTRL);
++		tx_ctrl &= ~(TX_CTRL_CLEAR_MASK);
++		tx_ctrl |= (spi->chip_select & TX_CTRL_SPI_TXCH_NUM_M);
++		cns21xx_spi_wr(hw, tx_ctrl, SPI_REG_TX_CTRL);
++
++		break;
++	}
++}
++
++static int cns21xx_spi_setup(struct spi_device *spi)
++{
++	struct cns21xx_spi *hw = to_hw(spi);
++
++	if (spi->bits_per_word != 8) {
++		dev_err(&spi->dev, "%s: invalid bits_per_word=%u\n",
++			__func__, spi->bits_per_word);
++		return -EINVAL;
++	}
++
++	if (spi->max_speed_hz == 0)
++		spi->max_speed_hz = hw->freq_max;
++
++	if (spi->max_speed_hz > hw->freq_max ||
++	    spi->max_speed_hz < hw->freq_min) {
++		dev_err(&spi->dev, "%s: max_speed_hz=%u out of range\n",
++			__func__, spi->max_speed_hz);
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++static int cns21xx_spi_setup_transfer(struct spi_device *spi,
++				      struct spi_transfer *t)
++{
++	struct cns21xx_spi *hw = to_hw(spi);
++	u8	bits_per_word;
++	u32	hz;
++	int	i;
++
++	bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
++	hz = t ? t->speed_hz : spi->max_speed_hz;
++
++	if (!bits_per_word)
++		bits_per_word = spi->bits_per_word;
++
++	if (!hz)
++		hz = spi->max_speed_hz;
++
++	if (bits_per_word != 8) {
++		dev_err(&spi->dev, "%s: invalid bits_per_word=%u\n",
++			__func__, bits_per_word);
++		return -EINVAL;
++	}
++
++	if (hz > spi->max_speed_hz || hz > hw->freq_max || hz < hw->freq_min) {
++		dev_err(&spi->dev, "%s: max_speed_hz=%u out of range\n",
++			__func__, hz);
++		return -EINVAL;
++	}
++
++	for (i = 0; i < CNS21XX_SPI_NUM_BIT_RATES; i++)
++		if (spi->max_speed_hz > (cns21xx_get_apb_freq() >> i))
++			break;
++
++	DBG("max_speed:%uHz, curr_speed:%luHz, rate_index=%d\n",
++	    spi->max_speed_hz, cns21xx_get_apb_freq() / (1 << i), i);
++
++	cns21xx_spi_wr(hw, i, SPI_REG_BIT_RATE);
++
++	return 0;
++}
++
++static int cns21xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
++{
++	struct cns21xx_spi *hw = to_hw(spi);
++	const unsigned char *tx_buf;
++	unsigned char *rx_buf;
++	u32 rx_data;
++	int tx_eof;
++	int err = 0;
++	int i;
++
++	tx_buf = t->tx_buf;
++	rx_buf = t->rx_buf;
++	tx_eof = t->last_in_message_list;
++
++	DBG("txrx: tx %p, rx %p, len %d\n", tx_buf, rx_buf, t->len);
++
++	if (tx_buf) {
++		for (i = 0; i < t->len; i++)
++			DBG("tx_buf[%02d]: 0x%02x\n", i, tx_buf[i]);
++
++		for (i = 0; i < (t->len - 1); i++) {
++			err = cns21xx_spi_txrx_word(hw, spi->chip_select, 0,
++						    tx_buf[i], &rx_data);
++			if (err)
++				goto done;
++
++			if (rx_buf) {
++				rx_buf[i] = rx_data;
++				DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]);
++			}
++		}
++
++		err = cns21xx_spi_txrx_word(hw, spi->chip_select, tx_eof,
++					    tx_buf[i], &rx_data);
++		if (err)
++			goto done;
++
++		if ((tx_eof) && rx_buf) {
++			rx_buf[i] = rx_data;
++			DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]);
++		}
++	} else if (rx_buf) {
++		for (i = 0; i < (t->len - 1); i++) {
++			err = cns21xx_spi_txrx_word(hw, spi->chip_select, 0,
++						    0xff, &rx_data);
++			if (err)
++				goto done;
++
++			rx_buf[i] = rx_data;
++			DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]);
++		}
++
++		err = cns21xx_spi_txrx_word(hw, spi->chip_select, tx_eof,
++					    0xff, &rx_data);
++		if (err)
++			goto done;
++
++		rx_buf[i] = rx_data;
++		DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]);
++	}
++
++ done:
++	return (err) ? err : t->len;
++}
++
++static void __init cns21xx_spi_hw_init(struct cns21xx_spi *hw)
++{
++	u32 t;
++	u32 pclk;
++
++	/* Setup configuration register */
++	cns21xx_spi_wr(hw, CFG_SPI_MASTER_EN, SPI_REG_CFG);
++
++	/* Set default clock to PCLK/2 */
++	cns21xx_spi_wr(hw, BIT_RATE_DIV_2, SPI_REG_BIT_RATE);
++
++	/* Configure SPI's Tx channel */
++	cns21xx_spi_wr(hw, 0, SPI_REG_TX_CTRL);
++
++	/* Configure Tx FIFO Threshold */
++	t = cns21xx_spi_rr(hw, SPI_REG_FIFO_TX_CFG);
++	t &= ~(FIFO_TX_CFG_SPI_TXFF_THRED_M << FIFO_TX_CFG_SPI_TXFF_THRED_S);
++	t |= (FIFO_TX_CFG_SPI_TXFF_THRED_2 << FIFO_TX_CFG_SPI_TXFF_THRED_S);
++	cns21xx_spi_wr(hw, t, SPI_REG_FIFO_TX_CFG);
++
++	/* Configure Rx FIFO Threshold */
++	t = cns21xx_spi_rr(hw, SPI_REG_FIFO_RX_CFG);
++	t &= ~(FIFO_RX_CFG_SPI_RXFF_THRED_M << FIFO_RX_CFG_SPI_RXFF_THRED_S);
++	t |= (FIFO_RX_CFG_SPI_RXFF_THRED_2 << FIFO_RX_CFG_SPI_RXFF_THRED_S);
++	cns21xx_spi_wr(hw, t, SPI_REG_FIFO_RX_CFG);
++
++	/* Disable interrupts, and clear interrupt status */
++	cns21xx_spi_wr(hw, 0, SPI_REG_INTR_ENA);
++	cns21xx_spi_wr(hw, INTR_STAT_CLEAR_MASK, SPI_REG_INTR_STAT);
++
++	(void) cns21xx_spi_rr(hw, SPI_REG_RX_DATA);
++
++	/* Enable SPI */
++	t = cns21xx_spi_rr(hw, SPI_REG_CFG);
++	t |= CFG_SPI_EN;
++	cns21xx_spi_wr(hw, t, SPI_REG_CFG);
++
++	pclk = cns21xx_get_apb_freq();
++	hw->freq_max = pclk;
++	hw->freq_min = pclk / (1 << BIT_RATE_DIV_128);
++}
++
++static int __init cns21xx_spi_probe(struct platform_device *pdev)
++{
++	struct cns21xx_spi *hw;
++	struct spi_master *master;
++	struct resource *res;
++	int err = 0;
++
++	master = spi_alloc_master(&pdev->dev, sizeof(struct cns21xx_spi));
++	if (!master) {
++		dev_err(&pdev->dev, "No memory for spi_master\n");
++		return -ENOMEM;
++	}
++
++	hw = spi_master_get_devdata(master);
++
++	platform_set_drvdata(pdev, hw);
++	hw->master = spi_master_get(master);
++	hw->dev = &pdev->dev;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		dev_dbg(&pdev->dev, "no MEM resource found\n");
++		err = -ENOENT;
++		goto err_put_master;
++	}
++
++	hw->region = request_mem_region(res->start, resource_size(res),
++					dev_name(&pdev->dev));
++	if (!hw->region) {
++		dev_err(&pdev->dev, "unable to reserve iomem region\n");
++		err = -ENXIO;
++		goto err_put_master;
++	}
++
++	hw->base = ioremap(res->start, resource_size(res));
++	if (!hw->base) {
++		dev_err(&pdev->dev, "ioremap failed\n");
++		err = -ENOENT;
++		goto err_release_region;
++	}
++
++	cns21xx_spi_hw_init(hw);
++
++	master->bus_num = pdev->id;
++	if (master->bus_num == -1)
++		master->bus_num = 0;
++
++	master->num_chipselect = 4;
++	master->setup = cns21xx_spi_setup;
++
++	hw->bitbang.master = hw->master;
++	hw->bitbang.chipselect = cns21xx_spi_chipselect;
++	hw->bitbang.txrx_bufs = cns21xx_spi_txrx;
++	hw->bitbang.setup_transfer = cns21xx_spi_setup_transfer;
++
++	err = spi_bitbang_start(&hw->bitbang);
++	if (err) {
++		dev_err(hw->dev, "unable to register SPI master\n");
++		goto err_unmap;
++	}
++
++	dev_info(hw->dev, "iomem at %08x\n", res->start);
++
++	return 0;
++
++ err_unmap:
++	iounmap(hw->base);
++
++ err_release_region:
++	release_resource(hw->region);
++	kfree(hw->region);
++
++ err_put_master:
++	spi_master_put(hw->bitbang.master);
++	platform_set_drvdata(pdev, NULL);
++
++	return err;
++}
++
++static int __devexit cns21xx_spi_remove(struct platform_device *pdev)
++{
++	struct cns21xx_spi *hw = platform_get_drvdata(pdev);
++
++	spi_bitbang_stop(&hw->bitbang);
++	iounmap(hw->base);
++	release_resource(hw->region);
++	kfree(hw->region);
++	spi_master_put(hw->bitbang.master);
++	platform_set_drvdata(pdev, NULL);
++
++	return 0;
++}
++
++static struct platform_driver cns21xx_spi_driver = {
++	.remove		= __devexit_p(cns21xx_spi_remove),
++	.driver		= {
++		.name	= DRIVER_NAME,
++		.owner	= THIS_MODULE,
++	},
++};
++
++static int __init cns21xx_spi_init(void)
++{
++	return platform_driver_probe(&cns21xx_spi_driver, cns21xx_spi_probe);
++}
++
++static void __exit cns21xx_spi_exit(void)
++{
++	platform_driver_unregister(&cns21xx_spi_driver);
++}
++
++module_init(cns21xx_spi_init);
++module_exit(cns21xx_spi_exit);
++
++MODULE_DESCRIPTION("Cavium Networks CNS21xx SPI Controller driver");
++MODULE_AUTHOR("STAR Semi Corp.");
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/target/linux/cns21xx/patches-3.6/106-cns21xx-gec-driver.patch b/target/linux/cns21xx/patches-3.6/106-cns21xx-gec-driver.patch
new file mode 100644
index 0000000000..7688aa75b4
--- /dev/null
+++ b/target/linux/cns21xx/patches-3.6/106-cns21xx-gec-driver.patch
@@ -0,0 +1,2507 @@
+--- /dev/null
++++ b/drivers/net/ethernet/cns21xx/cns21xx_gec_main.c
+@@ -0,0 +1,2464 @@
++/*
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This driver has been derived from the ethernet driver of the
++ *  Star STR81xx SoC.
++ *	Copyright (c) 2008 Cavium Networks
++ *
++ *  This file 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/kernel.h>
++#include <linux/bootmem.h>
++#include <linux/sched.h>
++#include <linux/types.h>
++#include <linux/fcntl.h>
++#include <linux/interrupt.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/in.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/bitops.h>
++#include <linux/irq.h>
++#include <linux/io.h>
++#include <linux/pci.h>
++#include <linux/errno.h>
++#include <linux/delay.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/platform_device.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <linux/if_ether.h>
++#include <linux/icmp.h>
++#include <linux/udp.h>
++#include <linux/tcp.h>
++#include <linux/if_arp.h>
++#include <net/arp.h>
++
++#include <mach/hardware.h>
++#include <mach/cns21xx.h>
++#include <mach/cns21xx_misc.h>
++#include <mach/cns21xx_powermgmt.h>
++#include <mach/cns21xx_gec_platform.h>
++
++#define DRIVER_NAME	"cns21xx-gec"
++
++/* VSC8601 and WavePlus Phy are the same */
++#define CNS21XX_GEC_PHY_ADDR	0
++
++#define CNS21XX_GEC_TX_HW_CHECKSUM
++#define CNS21XX_GEC_RX_HW_CHECKSUM
++
++#define CNS21XX_PEND_INT_COUNT	16
++#define CNS21XX_PEND_INT_TIME	5	/* 5 x 20 usecs */
++
++#define	MAX_PACKET_LEN		1536
++
++#define CNS21XX_GEC_NUM_TXDS	48 /* FIXME: original 64 will cause UDP fail */
++#define CNS21XX_GEC_NUM_RXDS	64
++
++struct cns21xx_gec_mib_info {
++	u32	mib_rx_ok_pkt;
++	u64	mib_rx_ok_byte;
++	u32	mib_rx_runt;
++	u32	mib_rx_over_size;
++	u32	mib_rx_no_buffer_drop;
++	u32	mib_rx_crc_err;
++	u32	mib_rx_arl_drop;
++	u32	mib_rx_myvid_drop;
++	u32	mib_rx_csum_err;
++	u32	mib_rx_pause_frame;
++	u32	mib_tx_ok_pkt;
++	u64	mib_tx_ok_byte;
++	u32	mib_tx_pause_frame;
++};
++
++/*
++ * Network Driver, Receive/Send and Initial Buffer Function
++ */
++struct cns21xx_gec_txd {
++	/* 1st 32Bits */
++	u32 sdp;
++
++	/* 2nd 32Bits */
++	u32 length:16;
++	u32 reserved0:7;
++	u32 tco:1;
++	u32 uco:1;
++	u32 ico:1;
++	u32 insv:1;
++	u32 intr:1;
++	u32 ls:1;
++	u32 fs:1;
++	u32 eor:1;
++	u32 cown:1;
++
++	/* 3rd 32Bits */
++	u32 vid:12;
++	u32 cfi:1;
++	u32 pri:3;
++	u32 epid:16;
++
++	/* 4th 32Bits */
++	u32 reserved1;
++} __packed;
++
++struct cns21xx_gec_rxd {
++	/* 1st 32Bits */
++	u32 sdp;
++
++	/* 2nd  32Bits */
++	u32 length:16;
++	u32 l4f:1;
++	u32 ipf:1;
++	u32 prot:2;
++	u32 vted:1;
++	u32 mymac:1;
++	u32 hhit:1;
++	u32 rmc:1;
++	u32 crce:1;
++	u32 osize:1;
++	u32 reserved0:2;
++	u32 ls:1;
++	u32 fs:1;
++	u32 eor:1;
++	u32 cown:1;
++
++	/* 3rd 32Bits */
++	u32 vid:12;
++	u32 cfi:1;
++	u32 pri:3;
++	u32 epid:16;
++
++	/* 4th 32Bits */
++	u32 reserved1;
++} __packed;
++
++struct cns21xx_gec_ring {
++	u32		desc_dma;
++	void		*desc_cpu;
++	u32		curr;
++	u32		dirty;
++	u32		count;
++	struct sk_buff	**skbs;
++};
++
++#define CNS21XX_GEC_NUM_VLANS	4
++struct cns21xx_gec_vlan {
++	u32 vid;	/* 0~4095 */
++	u32 control;	/* ENABLE or DISABLE */
++};
++
++/* store this information for the driver.. */
++struct cns21xx_gec {
++	struct napi_struct      napi;
++	struct net_device       *netdev;
++	struct device		*parent;
++	struct cns21xx_gec_ring	txring;
++	struct cns21xx_gec_ring	rxring;
++
++	void __iomem		*base;
++	struct resource		*mem_res;
++	struct cns21xx_gec_plat_data *pdata;
++	spinlock_t		lock;
++	spinlock_t		tx_lock;
++
++	int			status_irq;
++	int			rxrc_irq;
++	int			rxqf_irq;
++	int			txtc_irq;
++	int			txqe_irq;
++	unsigned long		rx_queue_full;
++
++	struct cns21xx_gec_vlan	vlans[CNS21XX_GEC_NUM_VLANS];
++
++	struct timer_list	internal_phy_timer;
++	struct timer_list	nic_timer;
++	u8 phy_addr;
++	u16 phy_id;
++	struct cns21xx_gec_mib_info mib_info;
++};
++
++#define GEC_REG_PHY_CTRL0	0x000
++#define GEC_REG_PHY_CTRL1	0x004
++#define GEC_REG_MAC_CFG		0x008
++#define GEC_REG_FC_CFG		0x00c
++#define GEC_REG_ARL_CFG		0x010
++#define GEC_REG_MY_MAC_H	0x014
++#define GEC_REG_MY_MAC_L	0x018
++#define GEC_REG_HASH_CTRL	0x01c
++#define GEC_REG_VLAN_CTRL	0x020
++#define GEC_REG_VLAN_ID_0_1	0x024
++#define GEC_REG_VLAN_ID_2_3	0x028
++#define GEC_REG_DMA_CFG		0x030
++#define GEC_REG_TX_DMA_CTRL	0x034
++#define GEC_REG_RX_DMA_CTRL	0x038
++#define GEC_REG_TX_DPTR		0x03c
++#define GEC_REG_RX_DPTR		0x040
++#define GEC_REG_TX_BASE_ADDR	0x044
++#define GEC_REG_RX_BASE_ADDR	0x048
++#define GEC_REG_DLY_INT_CFG	0x04c
++#define GEC_REG_INT		0x050
++#define GEC_REG_INT_MASK	0x054
++#define GEC_REG_TEST0		0x058
++#define GEC_REG_TEST1		0x05c
++#define GEC_REG_EXTEND_CFG	0x060
++
++#define	GEC_REG_RX_OK_PKT_CNTR		0x100
++#define	GEC_REG_RX_OK_BYTE_CNTR		0x104
++#define	GEC_REG_RX_RUNT_BYTE_CNTR	0x108
++#define	GEC_REG_RX_OSIZE_DROP_PKT_CNTR	0x10c
++#define	GEC_REG_RX_NO_BUF_DROP_PKT_CNTR	0x110
++#define	GEC_REG_RX_CRC_ERR_PKT_CNTR	0x114
++#define	GEC_REG_RX_ARL_DROP_PKT_CNTR	0x118
++#define	GEC_REG_MYVLANID_MISMATCH_DROP_PKT_CNTR 0x11c
++#define	GEC_REG_RX_CHKSUM_ERR_PKT_CNTR	0x120
++#define	GEC_REG_RX_PAUSE_FRAME_PKT_CNTR	0x124
++#define	GEC_REG_TX_OK_PKT_CNTR		0x128
++#define	GEC_REG_TX_OK_BYTE_CNTR		0x12c
++#define	GEC_REG_TX_COLLISION_CNTR	0x130
++#define	GEC_REG_TX_PAUSE_FRAME_CNTR	0x130
++#define	GEC_REG_TX_FIFO_UNDERRUN_RETX_CNTR 0x134
++
++#define GEC_INT_MIB_COUNTER_TH	BIT(3)
++#define GEC_INT_PORT_STATUS_CHG	BIT(2)
++
++#define FE_PHY_LED_MODE (0x1 << 12)
++
++static void internal_phy_init_timer(struct cns21xx_gec *gec);
++static void internal_phy_start_timer(struct cns21xx_gec *gec);
++static void internal_phy_stop_timer(struct cns21xx_gec *gec);
++
++static void cns21xx_gec_phy_powerdown(struct cns21xx_gec *gec);
++static void cns21xx_gec_phy_powerup(struct cns21xx_gec *gec);
++
++static inline u32 cns21xx_gec_rr(struct cns21xx_gec *gec, unsigned int reg)
++{
++	return __raw_readl(gec->base + reg);
++}
++
++static inline void cns21xx_gec_wr(struct cns21xx_gec *gec, unsigned int reg,
++			       u32 val)
++{
++	__raw_writel(val, gec->base + reg);
++}
++
++static void cns21xx_gec_timer_func(unsigned long data)
++{
++	struct cns21xx_gec *gec = (struct cns21xx_gec *) data;
++	struct cns21xx_gec_ring *txring = &gec->txring;
++	int i;
++	int txsd_index;
++	int txsd_current;
++	int skb_free_count = 0;
++	struct cns21xx_gec_txd *txd;
++	unsigned long flags;
++
++	local_irq_save(flags);
++	txsd_current = cns21xx_gec_rr(gec, GEC_REG_TX_DPTR);
++	txsd_index = (txsd_current - (u32)txring->desc_dma) >> 4;
++	if (txsd_index > txring->dirty) {
++		skb_free_count = txsd_index - txring->dirty;
++	} else if (txsd_index <= txring->dirty) {
++		skb_free_count = txring->count + txsd_index -
++				 txring->dirty;
++	}
++	for (i = 0; i < skb_free_count; i++) {
++		txd = ((struct cns21xx_gec_txd *) txring->desc_cpu) +
++		      txring->dirty;
++
++		if (txd->cown == 0)
++			break;
++
++		if (txring->skbs[txring->dirty]) {
++			dev_kfree_skb_any(txring->skbs[txring->dirty]);
++			txring->skbs[txring->dirty] = NULL;
++
++			dma_unmap_single(gec->parent,
++					 txd->sdp,
++					 txd->length,
++					 DMA_TO_DEVICE);
++		}
++
++		txring->dirty++;
++		if (txring->dirty == txring->count)
++			txring->dirty = 0;
++	}
++	local_irq_restore(flags);
++}
++
++static void __init cns21xx_gec_timer_init(struct cns21xx_gec *gec)
++{
++	init_timer(&gec->nic_timer);
++	gec->nic_timer.function = &cns21xx_gec_timer_func;
++	gec->nic_timer.data = (unsigned long) gec;
++}
++
++static void cns21xx_gec_timer_modify(struct cns21xx_gec *gec, unsigned int t)
++{
++	mod_timer(&gec->nic_timer, jiffies + t);
++}
++
++static int cns21xx_gec_write_phy(struct cns21xx_gec *gec,
++			      u8 addr, u8 reg, u16 val)
++{
++	int i;
++
++	if (addr > 31 || reg > 31)
++		return -EINVAL;
++
++	/* clear previous rw_ok status */
++	cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL0, 0x1 << 15);
++
++	cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL0,
++		    addr | (reg  << 8) | (val << 16) | (0x1 << 13));
++
++	for (i = 0; i < 10000; i++) {
++		u32 status;
++
++		status = cns21xx_gec_rr(gec, GEC_REG_PHY_CTRL0);
++		if (status & (0x1 << 15)) {
++			/*
++			 * clear the rw_ok status,
++			 * and clear other bits value
++			 */
++			cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL0, (0x1 << 15));
++			return 0;
++		}
++		udelay(1000);
++	}
++
++	dev_err(&gec->netdev->dev,
++		"%s timed out, phy_addr:0x%x, phy_reg:0x%x, write_data:0x%x\n",
++	       __func__, addr, reg, val);
++
++	return -EIO;
++}
++
++static int cns21xx_gec_read_phy(struct cns21xx_gec *gec,
++			     u8 addr, u8 reg, u16 *val)
++{
++	int i;
++
++	if (addr > 31 || reg > 31)
++		return -EINVAL;
++
++	/* clear previous rw_ok status */
++	cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL0, 0x1 << 15);
++
++	cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL0,
++		    addr | (reg << 8) | (0x1 << 14));
++
++	for (i = 0; i < 10000; i++) {
++		u32 status;
++
++		status = cns21xx_gec_rr(gec, GEC_REG_PHY_CTRL0);
++		if (status & (0x1 << 15)) {
++			/*
++			 * clear the rw_ok status,
++			 * and clear other bits value
++			 */
++			cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL0, (0x1 << 15));
++			*val = (status >> 16) & 0xffff;
++			return 0;
++		}
++		udelay(1000);
++	}
++
++	dev_err(&gec->netdev->dev,
++		"%s timed out, phy_addr:0x%x, phy_reg:0x%x\n",
++	       __func__, addr, reg);
++
++	*val = 0xffff;
++	return -EIO;
++}
++
++static void cns21xx_gec_dma_config(struct cns21xx_gec *gec)
++{
++	u32 dma_config = 0;
++
++	dma_config = cns21xx_gec_rr(gec, GEC_REG_DMA_CFG);
++
++	/* Config TX DMA */
++	/* TX auto polling: 1 us */
++	dma_config &= ~(0x3 << 6);
++	/* TX auto polling :100us */
++	dma_config |= (0x2 << 6);
++	/* TX auto polling C-bit enable */
++	dma_config |= (0x1 << 5);
++	/* TX can transmit packets, No suspend */
++	dma_config &= ~(0x1 << 4);
++
++	/* Config RX DMA */
++	/* RX auto polling: 1 us */
++	dma_config &=  ~(0x3 << 2);
++	/* RX auto polling :100us */
++	dma_config |=  (0x2 << 2);
++	/* RX auto polling C-bit enable */
++	dma_config |=  (0x1 << 1);
++	/* RX can receive packets, No suspend */
++	dma_config &=  ~0x1;
++
++	/* 4N+2(for Linux) */
++	dma_config &= ~(0x1 << 16);
++
++	cns21xx_gec_wr(gec, GEC_REG_DMA_CFG, dma_config);
++}
++
++static void cns21xx_gec_mac_config(struct cns21xx_gec *gec)
++{
++	u32 mac_config;
++
++	mac_config = cns21xx_gec_rr(gec, GEC_REG_MAC_CFG);
++
++#ifdef CNS21XX_GEC_TX_HW_CHECKSUM
++	/* Tx ChkSum offload On: TCP/UDP/IP */
++	mac_config |= (0x1 << 26);
++#else
++	/* Tx ChkSum offload Off: TCP/UDP/IP */
++	mac_config &= ~(0x1 << 26);
++#endif
++
++#ifdef CNS21XX_GEC_RX_HW_CHECKSUM
++	/* Rx ChkSum offload On: TCP/UDP/IP */
++	mac_config |= (0x1 << 25);
++#else
++	/* Rx ChkSum offload Off: TCP/UDP/IP */
++	mac_config &= ~(0x1 << 25);
++#endif
++
++	/* Accept CSUM error pkt */
++	mac_config |= (0x1 << 24);
++	/* IST disable */
++	mac_config &= ~(0x1 << 23);
++	/* Strip vlan tag */
++	mac_config |= (0x1 << 22);
++	/* Accept CRC error pkt */
++	mac_config |= (0x1 << 21);
++	/* CRC strip */
++	mac_config |= (0x1 << 20);
++
++	/* Discard oversize pkt */
++	mac_config &= ~(0x1 << 18);
++
++	/* clear, set 1518 */
++	mac_config &= ~(0x3 << 16);
++
++	/* 1536 */
++	mac_config |= (0x2 << 16);
++
++	/* IPG */
++	mac_config |= (0x1f << 10);
++
++	/* Do not skip 16 consecutive collisions pkt */
++	/* allow to re-tx */
++	mac_config |= (0x1 << 9);
++	/* Fast retry */
++	mac_config |= (0x1 << 8);
++
++	cns21xx_gec_wr(gec, GEC_REG_MAC_CFG, mac_config);
++}
++
++static void cns21xx_gec_fc_config(struct cns21xx_gec *gec)
++{
++	u32 fc_config;
++
++	fc_config = cns21xx_gec_rr(gec, GEC_REG_FC_CFG);
++
++	/* Send pause on frame threshold */
++	/* Clear */
++	fc_config &= ~(0xfff << 16);
++	fc_config |= (0x360 << 16);
++	/* Disable UC_PAUSE */
++	fc_config &= ~(0x1 << 8);
++	/* Enable Half Duplex backpressure */
++	fc_config |= (0x1 << 7);
++	/* Collision-based BP */
++	fc_config &= ~(0x1 << 6);
++	/* Disable max BP collision */
++	fc_config &= ~(0x1 << 5);
++	/* Clear */
++	fc_config &= ~(0x1f);
++	/* Set */
++	fc_config |= (0xc);
++
++	cns21xx_gec_wr(gec, GEC_REG_FC_CFG, fc_config);
++}
++
++static void cns21xx_gec_internal_phy_config(struct cns21xx_gec *gec)
++{
++	u32 phy_ctrl1;
++	u32 phy_addr;
++
++	dev_info(&gec->netdev->dev, "Internal PHY\n");
++
++	phy_addr = CNS21XX_GEC_PHY_ADDR;
++	gec->phy_addr = phy_addr;
++
++	phy_ctrl1 = cns21xx_gec_rr(gec, GEC_REG_PHY_CTRL1);
++
++	/* set phy addr for auto-polling */
++	phy_ctrl1 |= (phy_addr & 0x1f) << 24;
++
++	/* set internal phy mode */
++	/* internel 10/100 phy */
++	phy_ctrl1 |= 0x1 << 18;
++
++	/* MII */
++	phy_ctrl1 &= ~(0x1 << 17);
++
++	/* MAC mode */
++	phy_ctrl1 &= ~(0x1 << 16);
++
++	/* config PHY LED bit[13:12] */
++	cns21xx_gec_read_phy(gec, phy_addr, 31, (u16 *)(&phy_ctrl1));
++	/* clear LED control */
++	phy_ctrl1 &= ~(0x3 << 12);
++	phy_ctrl1 |= FE_PHY_LED_MODE;
++	cns21xx_gec_write_phy(gec, phy_addr, 31, phy_ctrl1);
++
++	cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL1, phy_ctrl1);
++}
++
++static void cns21xx_gec_vsc8601_phy_config(struct cns21xx_gec *gec)
++{
++	u32 phy_ctrl1;
++	u32 phy_addr;
++	u16 phy_data;
++
++	phy_addr = CNS21XX_GEC_PHY_ADDR;
++	gec->phy_addr = phy_addr;
++
++	phy_ctrl1 = cns21xx_gec_rr(gec, GEC_REG_PHY_CTRL1);
++
++	/* phy addr for auto-polling */
++	phy_ctrl1 |= phy_addr << 24;
++
++	/* set external phy mode */
++	phy_ctrl1 &= ~(0x1 << 18);
++
++	/* set RGMII */
++	phy_ctrl1 |= (0x1 << 17);
++
++	/* set MII interface */
++	phy_ctrl1 &= ~(0x1 << 16);
++
++	cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL1, phy_ctrl1);
++
++	/* set phy addr for auto-polling */
++	phy_ctrl1 |= phy_addr << 24;
++
++	/* set external phy mode */
++	/* MII/RGMII interface */
++	phy_ctrl1 &= ~(0x1 << 18);
++
++	/* RGMII */
++	phy_ctrl1 |= (0x1 << 17);
++
++	/* MAC mode */
++	phy_ctrl1 &= ~(0x1 << 16);
++
++	cns21xx_gec_read_phy(gec, phy_addr, 3, &phy_data);
++	if ((phy_data & 0x000f) == 0x0000) {
++		/* type A chip */
++		u16 tmp16;
++
++		dev_info(&gec->netdev->dev, "VSC8601 Type A Chip\n");
++		cns21xx_gec_write_phy(gec, phy_addr, 31, 0x52B5);
++		cns21xx_gec_write_phy(gec, phy_addr, 16, 0xAF8A);
++
++		phy_data = 0x0;
++		cns21xx_gec_read_phy(gec, phy_addr, 18, &tmp16);
++		phy_data |= (tmp16 & ~0x0);
++		cns21xx_gec_write_phy(gec, phy_addr, 18, phy_data);
++
++		phy_data = 0x0008;
++		cns21xx_gec_read_phy(gec, phy_addr, 17, &tmp16);
++		phy_data |= (tmp16 & ~0x000C);
++		cns21xx_gec_write_phy(gec, phy_addr, 17, phy_data);
++
++		cns21xx_gec_write_phy(gec, phy_addr, 16, 0x8F8A);
++		cns21xx_gec_write_phy(gec, phy_addr, 16, 0xAF86);
++
++		phy_data = 0x0008;
++		cns21xx_gec_read_phy(gec, phy_addr, 18, &tmp16);
++		phy_data |= (tmp16 & ~0x000C);
++		cns21xx_gec_write_phy(gec, phy_addr, 18, phy_data);
++
++		phy_data = 0x0;
++		cns21xx_gec_read_phy(gec, phy_addr, 17, &tmp16);
++		phy_data |= (tmp16 & ~0x0);
++		cns21xx_gec_write_phy(gec, phy_addr, 17, phy_data);
++
++		cns21xx_gec_write_phy(gec, phy_addr, 16, 0x8F8A);
++
++		cns21xx_gec_write_phy(gec, phy_addr, 16, 0xAF82);
++
++		phy_data = 0x0;
++		cns21xx_gec_read_phy(gec, phy_addr, 18, &tmp16);
++		phy_data |= (tmp16 & ~0x0);
++		cns21xx_gec_write_phy(gec, phy_addr, 18, phy_data);
++
++		phy_data = 0x0100;
++		cns21xx_gec_read_phy(gec, phy_addr, 17, &tmp16);
++		phy_data |= (tmp16 & ~0x0180);
++		cns21xx_gec_write_phy(gec, phy_addr, 17, phy_data);
++
++		cns21xx_gec_write_phy(gec, phy_addr, 16, 0x8F82);
++
++		cns21xx_gec_write_phy(gec, phy_addr, 31, 0x0);
++
++		/* Set port type: single port */
++		cns21xx_gec_read_phy(gec, phy_addr, 9, &phy_data);
++		phy_data &= ~(0x1 << 10);
++		cns21xx_gec_write_phy(gec, phy_addr, 9, phy_data);
++	} else if ((phy_data & 0x000f) == 0x0001) {
++		/* type B chip */
++		dev_info(&gec->netdev->dev, "VSC8601 Type B Chip\n");
++
++		cns21xx_gec_read_phy(gec, phy_addr, 23, &phy_data);
++		phy_data |= (0x1 << 8); 	/* set RGMII timing skew */
++		cns21xx_gec_write_phy(gec, phy_addr, 23, phy_data);
++	}
++
++	/* change to extened registers */
++	cns21xx_gec_write_phy(gec, phy_addr, 31, 0x0001);
++
++	cns21xx_gec_read_phy(gec, phy_addr, 28, &phy_data);
++	phy_data &= ~(0x3 << 14); 		/* set RGMII TX timing skew */
++	phy_data |= (0x3 << 14); 		/* 2.0ns */
++	phy_data &= ~(0x3 << 12); 		/* set RGMII RX timing skew */
++	phy_data |= (0x3 << 12); 		/* 2.0ns */
++	cns21xx_gec_write_phy(gec, phy_addr, 28, phy_data);
++
++	/* change to normal registers */
++	cns21xx_gec_write_phy(gec, phy_addr, 31, 0x0000);
++
++#if 0
++	/* set TX and RX clock skew */
++	cns21xx_gec_wr(gec, GEC_REG_TEST0, (0x2 << 2) | (0x2 << 0));
++#endif
++
++	cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL1, phy_ctrl1);
++}
++
++static void cns21xx_gec_ip101a_phy_config(struct cns21xx_gec *gec)
++{
++	u32 phy_ctrl1;
++	u32 phy_addr;
++
++	dev_info(&gec->netdev->dev, "ICPlus IP101A\n");
++
++	phy_addr = 1;
++	gec->phy_addr = phy_addr;
++
++	phy_ctrl1 = cns21xx_gec_rr(gec, GEC_REG_PHY_CTRL1);
++
++	/* set phy addr for auto-polling */
++	phy_ctrl1 |= phy_addr << 24;
++
++	/* set external phy mode */
++	/* MII/RGMII interface */
++	phy_ctrl1 &= ~(0x1 << 18);
++
++	/* MII */
++	phy_ctrl1 &= ~(0x1 << 17);
++
++	/* MAC mode */
++	phy_ctrl1 &= ~(0x1 << 16);
++
++	cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL1, phy_ctrl1);
++}
++
++static void cns21xx_gec_ip1001_phy_config(struct cns21xx_gec *gec)
++{
++	u32 phy_ctrl1;
++	u32 phy_addr;
++	u16 phy_data;
++
++	dev_info(&gec->netdev->dev, "ICPlus IP1001\n");
++
++	phy_addr = 1;
++	gec->phy_addr = phy_addr;
++
++	phy_ctrl1 = cns21xx_gec_rr(gec, GEC_REG_PHY_CTRL1);
++
++	/* set phy addr for auto-polling */
++	phy_ctrl1 |= phy_addr << 24;
++
++	/* set external phy mode */
++	/* MII/RGMII interface */
++	phy_ctrl1 &= ~(0x1 << 18);
++
++	/* RGMII */
++	phy_ctrl1 |= (0x1 << 17);
++
++	/* MAC mode */
++	phy_ctrl1 &= ~(0x1 << 16);
++
++	cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL1, phy_ctrl1);
++	cns21xx_gec_read_phy(gec, phy_addr, 2, &phy_data);
++
++	/* set AN capability */
++	cns21xx_gec_read_phy(gec, phy_addr, 4, &phy_data);
++	/* clear existing values */
++	phy_data &= ~(0xf << 5);
++	/* 10Half */
++	phy_data |= (0x1 << 5);
++	/* 10Full */
++	phy_data |= (0x1 << 6);
++	/* 100Half */
++	phy_data |= (0x1 << 7);
++	/* 100Full */
++	phy_data |= (0x1 << 8);
++	/* FC on */
++	phy_data |= (0x1 << 10);
++	cns21xx_gec_write_phy(gec, phy_addr, 4, phy_data);
++
++	cns21xx_gec_read_phy(gec, phy_addr, 9, &phy_data);
++	/* 1000Full on */
++	phy_data |= (0x1 << 9);
++	phy_data &= ~(0x1 << 10);
++	phy_data |= (0x1 << 12);
++	cns21xx_gec_write_phy(gec, phy_addr, 9, phy_data);
++
++	cns21xx_gec_read_phy(gec, phy_addr, 16, &phy_data);
++	/* Smart function off */
++	phy_data &= ~(0x1 << 11);
++	/* TX delay */
++	phy_data |= (0x1 << 0);
++	/* RX delay */
++	phy_data |= (0x1 << 1);
++	cns21xx_gec_write_phy(gec, phy_addr, 16, phy_data);
++
++	cns21xx_gec_read_phy(gec, phy_addr, 16, &phy_data);
++
++#if 0
++	cns21xx_gec_read_phy(gec, phy_addr, 20, &phy_data);
++	phy_data &= ~(0x1<<2);
++
++	phy_data |=  (0x1<<9);
++	cns21xx_gec_write_phy(gec, phy_addr, 20, phy_data);
++#endif
++
++	cns21xx_gec_read_phy(gec, phy_addr, 0, &phy_data);
++	phy_data |= (0x1 << 9); 			/* re-AN */
++	cns21xx_gec_write_phy(gec, phy_addr, 0, phy_data);
++
++	cns21xx_gec_read_phy(gec, phy_addr, 9, &phy_data);
++
++	cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL1, phy_ctrl1);
++}
++
++static int cns21xx_gec_phy_config(struct cns21xx_gec *gec)
++{
++	u32 phy_ctrl1;
++
++	switch (gec->pdata->phy_type) {
++	case CNS21XX_GEC_PHY_TYPE_INTERNAL:
++		cns21xx_gec_internal_phy_config(gec);
++		break;
++
++	case CNS21XX_GEC_PHY_TYPE_VSC8601:
++		cns21xx_gec_vsc8601_phy_config(gec);
++		break;
++
++	case CNS21XX_GEC_PHY_TYPE_IP101A:
++		cns21xx_gec_ip101a_phy_config(gec);
++		break;
++
++	case CNS21XX_GEC_PHY_TYPE_IP1001:
++		cns21xx_gec_ip1001_phy_config(gec);
++		break;
++
++	default:
++		return -EINVAL;
++	}
++
++	phy_ctrl1 = cns21xx_gec_rr(gec, GEC_REG_PHY_CTRL1);
++
++	/* AN On */
++	phy_ctrl1 |= (0x1 << 8);
++	if (!((phy_ctrl1 >> 8) & 0x1)) { 	/* AN disable */
++		/* Force to FullDuplex mode */
++		phy_ctrl1 &= ~(0x1 << 11);	/* Half */
++
++		/* Force to 100Mbps mode */
++		phy_ctrl1 &= ~(0x3 << 9);	/* clear to 10M */
++		phy_ctrl1 |= (0x1 << 9);	/* set to 100M */
++	}
++
++	/* Force TX FlowCtrl On,in 1000M */
++	phy_ctrl1 |= (0x1 << 13);
++
++	/* Force TX FlowCtrl On, in 10/100M */
++	phy_ctrl1 |= (0x1 << 12);
++
++	/* Enable MII auto polling */
++	phy_ctrl1 &= ~(0x1 << 7);
++
++	cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL1, phy_ctrl1);
++	cns21xx_gec_phy_powerdown(gec);
++
++	return 0;
++}
++
++static void cns21xx_gec_vlan_config(struct cns21xx_gec *gec)
++{
++	/* setup VLAN entries */
++	gec->vlans[0].vid = 2;
++	gec->vlans[0].control = 0;
++	gec->vlans[1].vid = 2;
++	gec->vlans[1].control = 1;
++	gec->vlans[2].vid = 1;
++	gec->vlans[2].control = 1;
++	gec->vlans[3].vid = 1;
++	gec->vlans[3].control = 0;
++
++	cns21xx_gec_wr(gec, GEC_REG_VLAN_ID_0_1,
++		       (gec->vlans[0].vid & 0x0fff) |
++		       ((gec->vlans[1].vid & 0x0fff) << 16));
++
++	cns21xx_gec_wr(gec, GEC_REG_VLAN_ID_2_3,
++		       (gec->vlans[2].vid & 0x0fff) |
++		       ((gec->vlans[3].vid & 0x0fff) << 16));
++
++	cns21xx_gec_wr(gec, GEC_REG_VLAN_CTRL,
++		       (gec->vlans[0].control << 0) |
++		       (gec->vlans[1].control << 1) |
++		       (gec->vlans[2].control << 2) |
++		       (gec->vlans[3].control << 3));
++}
++
++static int cns21xx_gec_arl_config(struct cns21xx_gec *gec)
++{
++	u32 arl_config;
++
++	arl_config = cns21xx_gec_rr(gec, GEC_REG_ARL_CFG);
++
++	/* Misc Mode ON */
++	arl_config |= (0x1 << 4);
++
++	/* My MAC only enable */
++	arl_config |= (0x1 << 3);
++
++	/* Learn SA On */
++	arl_config &= ~(0x1 << 2);
++
++	/* Forward MC to CPU */
++	arl_config &= ~(0x1 << 1);
++
++	/* Hash direct mode */
++	arl_config &= ~(0x1);
++
++	cns21xx_gec_wr(gec, GEC_REG_ARL_CFG, arl_config);
++
++	return 0;
++}
++
++static void cns21xx_gec_phy_powerdown(struct cns21xx_gec *gec)
++{
++	u16 phy_data = 0;
++
++	cns21xx_gec_read_phy(gec, gec->phy_addr, 0, &phy_data);
++	phy_data |= (0x1 << 11);
++	cns21xx_gec_write_phy(gec, gec->phy_addr, 0, phy_data);
++
++	PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 15);
++	PWRMGT_SOFTWARE_RESET_CONTROL_REG &= ~(0x1 << 15);
++}
++
++static void cns21xx_gec_phy_powerup(struct cns21xx_gec *gec)
++{
++	u16 phy_data = 0;
++
++	cns21xx_gec_read_phy(gec, gec->phy_addr, 0, &phy_data);
++	phy_data &= ~(0x1 << 11);
++	cns21xx_gec_write_phy(gec, gec->phy_addr, 0, phy_data);
++
++	PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 15);
++}
++
++static void cns21xx_gec_enable(struct cns21xx_gec *gec)
++{
++	/* start Rx DMA */
++	cns21xx_gec_wr(gec, GEC_REG_RX_DMA_CTRL, 1);
++
++	cns21xx_gec_phy_powerup(gec);
++	internal_phy_start_timer(gec);
++}
++
++static void cns21xx_gec_shutdown(struct cns21xx_gec *gec)
++{
++	/* stop Rx and Tx DMA */
++	cns21xx_gec_wr(gec, GEC_REG_RX_DMA_CTRL, 0);
++	cns21xx_gec_wr(gec, GEC_REG_TX_DMA_CTRL, 0);
++
++	internal_phy_stop_timer(gec);
++}
++
++static irqreturn_t cns21xx_gec_receive_isr(int irq, void *dev_id)
++{
++	struct cns21xx_gec *gec = dev_id;
++
++	if (!test_bit(NAPI_STATE_SCHED, &gec->napi.state)) {
++		if (likely(napi_schedule_prep(&gec->napi)))
++			__napi_schedule(&gec->napi);
++	}
++
++	return IRQ_HANDLED;
++}
++
++static int cns21xx_gec_install_receive_isr(struct cns21xx_gec *gec)
++{
++	int err;
++
++	err = request_irq(gec->rxrc_irq, cns21xx_gec_receive_isr,
++			  IRQF_SHARED, dev_name(&gec->netdev->dev), gec);
++	if (err)
++		dev_err(&gec->netdev->dev,
++			"unable to get IRQ %d (err=%d)\n",
++			 gec->rxrc_irq, err);
++
++	return err;
++}
++
++static void cns21xx_gec_uninstall_receive_isr(struct cns21xx_gec *gec)
++{
++	free_irq(gec->rxrc_irq, gec);
++}
++
++static irqreturn_t cns21xx_gec_rxqf_isr(int irq, void *dev_id)
++{
++	struct cns21xx_gec *gec = dev_id;
++
++	/*
++	 * because in normal state, fsql only invoke once
++	 * and set_bit is atomic function, so don't mask it
++	 */
++	set_bit(0, &gec->rx_queue_full);
++	if (!test_bit(NAPI_STATE_SCHED, &gec->napi.state)) {
++		if (likely(napi_schedule_prep(&gec->napi)))
++			__napi_schedule(&gec->napi);
++	}
++
++	return IRQ_HANDLED;
++}
++
++static int cns21xx_gec_install_rxqf_isr(struct cns21xx_gec *gec)
++{
++	int err;
++
++	/*  QUEUE full interrupt handler */
++	err = request_irq(gec->rxqf_irq, cns21xx_gec_rxqf_isr,
++			  IRQF_SHARED, dev_name(&gec->netdev->dev), gec);
++	if (err)
++		dev_err(&gec->netdev->dev,
++			"unable to get IRQ %d (err=%d)\n",
++			 gec->rxqf_irq, err);
++
++	return err;
++}
++
++static void cns21xx_gec_uninstall_rxqf_isr(struct cns21xx_gec *gec)
++{
++	free_irq(gec->rxqf_irq, gec);
++}
++
++static void cns21xx_gec_mib_reset(struct cns21xx_gec *gec)
++{
++	unsigned long flags;
++
++	local_irq_save(flags);
++	(void) cns21xx_gec_rr(gec, GEC_REG_RX_OK_PKT_CNTR);
++	(void) cns21xx_gec_rr(gec, GEC_REG_RX_OK_BYTE_CNTR);
++	(void) cns21xx_gec_rr(gec, GEC_REG_RX_RUNT_BYTE_CNTR);
++	(void) cns21xx_gec_rr(gec, GEC_REG_RX_OSIZE_DROP_PKT_CNTR);
++	(void) cns21xx_gec_rr(gec, GEC_REG_RX_NO_BUF_DROP_PKT_CNTR);
++	(void) cns21xx_gec_rr(gec, GEC_REG_RX_CRC_ERR_PKT_CNTR);
++	(void) cns21xx_gec_rr(gec, GEC_REG_RX_ARL_DROP_PKT_CNTR);
++	(void) cns21xx_gec_rr(gec, GEC_REG_MYVLANID_MISMATCH_DROP_PKT_CNTR);
++	(void) cns21xx_gec_rr(gec, GEC_REG_RX_CHKSUM_ERR_PKT_CNTR);
++	(void) cns21xx_gec_rr(gec, GEC_REG_RX_PAUSE_FRAME_PKT_CNTR);
++	(void) cns21xx_gec_rr(gec, GEC_REG_TX_OK_PKT_CNTR);
++	(void) cns21xx_gec_rr(gec, GEC_REG_TX_OK_BYTE_CNTR);
++	(void) cns21xx_gec_rr(gec, GEC_REG_TX_PAUSE_FRAME_CNTR);
++	local_irq_restore(flags);
++}
++
++static void cns21xx_gec_mib_read(struct cns21xx_gec *gec)
++{
++	unsigned long flags;
++
++	local_irq_save(flags);
++	gec->mib_info.mib_rx_ok_pkt +=
++		cns21xx_gec_rr(gec, GEC_REG_RX_OK_PKT_CNTR);
++	gec->mib_info.mib_rx_ok_byte +=
++		cns21xx_gec_rr(gec, GEC_REG_RX_OK_BYTE_CNTR);
++	gec->mib_info.mib_rx_runt +=
++		cns21xx_gec_rr(gec, GEC_REG_RX_RUNT_BYTE_CNTR);
++	gec->mib_info.mib_rx_over_size +=
++		cns21xx_gec_rr(gec, GEC_REG_RX_OSIZE_DROP_PKT_CNTR);
++	gec->mib_info.mib_rx_no_buffer_drop +=
++		cns21xx_gec_rr(gec, GEC_REG_RX_NO_BUF_DROP_PKT_CNTR);
++	gec->mib_info.mib_rx_crc_err +=
++		cns21xx_gec_rr(gec, GEC_REG_RX_CRC_ERR_PKT_CNTR);
++	gec->mib_info.mib_rx_arl_drop +=
++		cns21xx_gec_rr(gec, GEC_REG_RX_ARL_DROP_PKT_CNTR);
++	gec->mib_info.mib_rx_myvid_drop +=
++		cns21xx_gec_rr(gec, GEC_REG_MYVLANID_MISMATCH_DROP_PKT_CNTR);
++	gec->mib_info.mib_rx_csum_err +=
++		cns21xx_gec_rr(gec, GEC_REG_RX_CHKSUM_ERR_PKT_CNTR);
++	gec->mib_info.mib_rx_pause_frame +=
++		cns21xx_gec_rr(gec, GEC_REG_RX_PAUSE_FRAME_PKT_CNTR);
++	gec->mib_info.mib_tx_ok_pkt +=
++		cns21xx_gec_rr(gec, GEC_REG_TX_OK_PKT_CNTR);
++	gec->mib_info.mib_tx_ok_byte +=
++		cns21xx_gec_rr(gec, GEC_REG_TX_OK_BYTE_CNTR);
++	gec->mib_info.mib_tx_pause_frame +=
++		cns21xx_gec_rr(gec, GEC_REG_TX_PAUSE_FRAME_CNTR);
++	local_irq_restore(flags);
++}
++
++static const char *cns21xx_gec_speed_str(u32 phy_ctrl1)
++{
++	switch ((phy_ctrl1 >> 2) & 3) {
++	case 0:
++		return "10";
++	case 1:
++		return "100";
++	case 2:
++		return "1000";
++	}
++
++	return "???";
++}
++
++static irqreturn_t cns21xx_gec_status_isr(int irq, void *dev_id)
++{
++	struct cns21xx_gec *gec = dev_id;
++	u32 int_status;
++
++	int_status = cns21xx_gec_rr(gec, GEC_REG_INT);
++	cns21xx_gec_wr(gec, GEC_REG_INT, int_status);
++
++	/* flush write */
++	(void) cns21xx_gec_rr(gec, GEC_REG_INT);
++
++	if (int_status & GEC_INT_MIB_COUNTER_TH)
++		cns21xx_gec_mib_read(gec);
++
++	if (int_status & GEC_INT_PORT_STATUS_CHG) {
++		u32 phy_ctrl1;
++
++		phy_ctrl1 = cns21xx_gec_rr(gec, GEC_REG_PHY_CTRL1);
++		if (phy_ctrl1 & BIT(0)) {
++			netif_carrier_on(gec->netdev);
++			dev_info(&gec->netdev->dev,
++				"link up (%sMbps/%s duplex)\n",
++				cns21xx_gec_speed_str(phy_ctrl1),
++				(phy_ctrl1 & BIT(4)) ? "Full" : "Half");
++		} else {
++			netif_carrier_off(gec->netdev);
++			dev_info(&gec->netdev->dev, "link down\n");
++		}
++	}
++
++	return IRQ_HANDLED;
++}
++
++static inline void cns21xx_gec_enable_interrupt(struct cns21xx_gec *gec,
++					     u32 mask)
++{
++	cns21xx_gec_wr(gec, GEC_REG_INT_MASK,
++		    cns21xx_gec_rr(gec, GEC_REG_INT_MASK) & ~mask);
++}
++
++static int cns21xx_gec_install_status_isr(struct cns21xx_gec *gec)
++{
++	int err;
++
++	err = request_irq(gec->status_irq, cns21xx_gec_status_isr,
++			  IRQF_DISABLED, dev_name(&gec->netdev->dev), gec);
++
++	if (err) {
++		dev_err(&gec->netdev->dev,
++			"unable to get IRQ %d (err=%d)\n",
++			 gec->status_irq, err);
++		return err;
++	}
++
++	cns21xx_gec_enable_interrupt(gec, GEC_INT_MIB_COUNTER_TH |
++					  GEC_INT_PORT_STATUS_CHG);
++
++	return 0;
++}
++
++static inline void cns21xx_gec_uninstall_status_isr(struct cns21xx_gec *gec)
++{
++	free_irq(gec->status_irq, gec);
++}
++
++static void cns21xx_gec_uninstall_isr(struct cns21xx_gec *gec)
++{
++	cns21xx_gec_uninstall_rxqf_isr(gec);
++	cns21xx_gec_uninstall_status_isr(gec);
++	cns21xx_gec_uninstall_receive_isr(gec);
++}
++
++static int cns21xx_gec_install_isr(struct cns21xx_gec *gec)
++{
++	int err;
++
++	/* setup delayed interrupts */
++	cns21xx_gec_wr(gec, GEC_REG_DLY_INT_CFG,
++		       (1 << 16) |
++		       ((CNS21XX_PEND_INT_COUNT & 0xFF) << 8) |
++		       (CNS21XX_PEND_INT_TIME & 0xFF));
++
++	err = cns21xx_gec_install_receive_isr(gec);
++	if (err)
++		goto err_out;
++
++	err = cns21xx_gec_install_rxqf_isr(gec);
++	if (err)
++		goto err_uninstall_receive;
++
++	err = cns21xx_gec_install_status_isr(gec);
++	if (err)
++		goto err_uninstall_rxqf;
++
++	return 0;
++
++ err_uninstall_rxqf:
++	cns21xx_gec_uninstall_rxqf_isr(gec);
++ err_uninstall_receive:
++	cns21xx_gec_uninstall_receive_isr(gec);
++ err_out:
++	return err;
++}
++
++static int cns21xx_gec_lan_open(struct net_device *dev)
++{
++	struct cns21xx_gec *gec = netdev_priv(dev);
++	int err;
++
++	dev_dbg(&gec->netdev->dev, "open\n");
++
++#ifdef MODULE
++	MOD_INC_USE_COUNT;
++#endif
++
++	napi_enable(&gec->napi);
++	netif_start_queue(dev);
++	err = cns21xx_gec_install_isr(gec);
++	if (err)
++		goto err;
++
++	cns21xx_gec_enable(gec);
++
++	return 0;
++
++ err:
++	netif_stop_queue(dev);
++	napi_disable(&gec->napi);
++	return err;
++}
++
++static void cns21xx_gec_timeout(struct net_device *dev)
++{
++	dev_dbg(&dev->dev, "timeout\n");
++	netif_wake_queue(dev);
++	dev->trans_start = jiffies;
++}
++
++static int cns21xx_gec_close(struct net_device *dev)
++{
++	struct cns21xx_gec *gec = netdev_priv(dev);
++
++	cns21xx_gec_phy_powerdown(gec);
++	cns21xx_gec_uninstall_isr(gec);
++	napi_disable(&gec->napi);
++	netif_stop_queue(dev);
++	cns21xx_gec_shutdown(gec);
++
++#ifdef MODULE
++	MOD_DEC_USE_COUNT;
++#endif
++
++	return 0;
++}
++
++static inline struct sk_buff *cns21xx_gec_alloc_skb(void)
++{
++	struct sk_buff *skb;
++
++	skb = dev_alloc_skb(MAX_PACKET_LEN + 2);
++
++	if (unlikely(!skb))
++		return NULL;
++
++	/* Make buffer alignment 2 beyond a 16 byte boundary
++	 * this will result in a 16 byte aligned IP header after
++	 * the 14 byte MAC header is removed
++	 */
++	skb_reserve(skb, 2);	/* 16 bit alignment */
++
++	return skb;
++}
++
++static inline int cns21xx_gec_tx_dma_size(struct cns21xx_gec *gec)
++{
++	return gec->txring.count * sizeof(struct cns21xx_gec_txd);
++}
++
++static inline int cns21xx_gec_rx_dma_size(struct cns21xx_gec *gec)
++{
++	return gec->rxring.count * sizeof(struct cns21xx_gec_rxd);
++}
++
++static void __init cns21xx_gec_buffer_free(struct cns21xx_gec *gec)
++{
++	struct cns21xx_gec_ring *txring = &gec->txring;
++	struct cns21xx_gec_ring *rxring = &gec->rxring;
++	int i;
++
++	if (rxring->desc_cpu) {
++		for (i = 0; i < rxring->count; i++) {
++			if (rxring->skbs[i])
++				dev_kfree_skb(rxring->skbs[i]);
++		}
++
++		dma_free_coherent(gec->parent, cns21xx_gec_rx_dma_size(gec),
++				  rxring->desc_cpu, rxring->desc_dma);
++		memset((void *)&rxring, 0, cns21xx_gec_rx_dma_size(gec));
++	}
++
++	if (txring->desc_cpu) {
++		dma_free_coherent(gec->parent, cns21xx_gec_tx_dma_size(gec),
++				  txring->desc_cpu, txring->desc_dma);
++		memset((void *)&txring, 0, cns21xx_gec_tx_dma_size(gec));
++	}
++
++	kfree(txring->skbs);
++	kfree(rxring->skbs);
++}
++
++static int __init cns21xx_gec_buffer_alloc(struct cns21xx_gec *gec)
++{
++	struct cns21xx_gec_ring *txring = &gec->txring;
++	struct cns21xx_gec_ring *rxring = &gec->rxring;
++	struct cns21xx_gec_rxd *rxd;
++	struct cns21xx_gec_txd *txd;
++	struct sk_buff	*skb;
++	int err = -ENOMEM;
++	int i;
++
++	rxring->skbs = kzalloc(rxring->count * sizeof(struct skb *),
++			       GFP_KERNEL);
++
++	if (rxring->skbs == NULL) {
++		dev_err(&gec->netdev->dev,
++			"%s allocation failed\n", "RX buffer");
++		goto err_out;
++	}
++
++	txring->skbs = kzalloc(txring->count * sizeof(struct skb *),
++			       GFP_KERNEL);
++
++	if (txring->skbs == NULL) {
++		dev_err(&gec->netdev->dev,
++			"%s allocation failed\n", "TX buffer");
++		goto err_out;
++	}
++
++	rxring->desc_cpu = dma_alloc_coherent(gec->parent,
++					      cns21xx_gec_rx_dma_size(gec),
++					      &rxring->desc_dma,
++					      GFP_KERNEL);
++	if (!rxring->desc_cpu) {
++		dev_err(&gec->netdev->dev,
++			"%s allocation failed\n", "RX ring");
++		goto err_out;
++	}
++
++	txring->desc_cpu = dma_alloc_coherent(gec->parent,
++					      cns21xx_gec_tx_dma_size(gec),
++					      &txring->desc_dma,
++					      GFP_KERNEL);
++	if (!txring->desc_cpu) {
++		dev_err(&gec->netdev->dev,
++			"%s allocation failed\n", "TX ring");
++		goto err_out;
++	}
++
++	/* Clean RX Memory */
++	memset((void *)rxring->desc_cpu, 0, cns21xx_gec_rx_dma_size(gec));
++	dev_dbg(&gec->netdev->dev,
++		"rxring->desc_cpu=0x%08X rxring->desc_dma=0x%08X\n",
++		(u32) rxring->desc_cpu,
++		(u32) rxring->desc_dma);
++
++	/* Set cur_index Point to Zero */
++	rxring->curr = 0;
++	rxd = rxring->desc_cpu;
++	for (i = 0; i < rxring->count; i++, rxd++) {
++		if (i == (rxring->count - 1)) {
++			/* End bit == 0; */
++			rxd->eor = 1;
++		}
++		skb = cns21xx_gec_alloc_skb();
++		if (!skb) {
++			dev_err(&gec->netdev->dev,
++				"%s allocation failed\n", "skb");
++			goto err_out;
++		}
++
++		/* Trans Packet from Virtual Memory to Physical Memory */
++		rxring->skbs[i]	= skb;
++		rxd->sdp = dma_map_single(gec->parent,
++						      skb->data,
++						      MAX_PACKET_LEN,
++						      DMA_TO_DEVICE);
++		rxd->length	= MAX_PACKET_LEN;
++	}
++
++	/* Clear TX Memory */
++	memset((void *)txring->desc_cpu, 0, cns21xx_gec_tx_dma_size(gec));
++	dev_dbg(&gec->netdev->dev,
++		"txring->desc_cpu=0x%08X txring->desc_dma=0x%08X\n",
++		(u32) txring->desc_cpu,
++		(u32) txring->desc_dma);
++
++	/* Set cur_index Point to Zero */
++	txring->curr = 0;
++	txd = txring->desc_cpu;
++	for (i = 0; i < txring->count; i++, txd++) {
++		if (i == (txring->count - 1)) {
++			/* End of Ring ==1 */
++			txd->eor = 1;
++		}
++		/* TX Ring , Cown == 1 */
++		txd->cown = 1;
++
++#ifdef CNS21XX_GEC_TX_HW_CHECKSUM
++		/* Enable Checksum */
++		txd->ico		= 1;
++		txd->uco		= 1;
++		txd->tco		= 1;
++#else
++		txd->ico		= 0;
++		txd->uco		= 0;
++		txd->tco		= 0;
++#endif
++		/* clear txring->skbs */
++		txring->skbs[i] 	= NULL;
++	}
++
++	return 0;
++
++err_out:
++	cns21xx_gec_buffer_free(gec);
++	return err;
++}
++
++static int cns21xx_gec_get_rfd_buff(struct cns21xx_gec *gec, int index)
++{
++	struct cns21xx_gec_ring *rxring = &gec->rxring;
++	struct cns21xx_gec_rxd *rxd;
++	struct sk_buff *skb;
++	unsigned char *data;
++	int len;
++
++	/* TODO: get rxdesc ptr */
++	rxd = ((struct cns21xx_gec_rxd *) rxring->desc_cpu) + index;
++	skb = rxring->skbs[index];
++
++	len = rxd->length;
++
++	dma_unmap_single(gec->parent, rxd->sdp, len,
++			 DMA_FROM_DEVICE);
++
++	data = skb_put(skb, len);
++
++	skb->dev = gec->netdev;
++
++#ifdef CNS21XX_GEC_RX_HW_CHECKSUM
++	if (rxd->ipf == 1 || rxd->l4f == 1) {
++		if (rxd->prot != 0x11) {
++			skb->ip_summed = CHECKSUM_NONE;
++		} else {
++			/* CheckSum Fail */
++			skb->dev->stats.rx_errors++;
++			goto freepacket;
++		}
++	} else {
++			skb->ip_summed = CHECKSUM_UNNECESSARY;
++	}
++#else
++	skb->ip_summed = CHECKSUM_NONE;
++#endif
++
++	/* this line must, if no, packet will not send to network layer */
++	skb->protocol = eth_type_trans(skb, skb->dev);
++
++	skb->dev->stats.rx_packets++;
++	skb->dev->stats.rx_bytes += len;
++	skb->dev->last_rx = jiffies;
++
++	/* if netif_rx any package, will let this driver core dump. */
++	netif_receive_skb(skb);
++
++	return 0;
++
++freepacket:
++	dev_kfree_skb_any(skb);
++	return 0;
++}
++
++static void cns21xx_gec_receive_packet(struct cns21xx_gec *gec,
++				    int mode, int *work_done, int work_to_do)
++{
++	struct cns21xx_gec_ring *rxring = &gec->rxring;
++	int rxsd_index;
++	u32 rxsd_current;
++	struct cns21xx_gec_rxd *rxd;
++	struct sk_buff *skb;
++	int i, rxcount = 0;
++
++	rxd = ((struct cns21xx_gec_rxd *) rxring->desc_cpu) + rxring->curr;
++	rxsd_current = cns21xx_gec_rr(gec, GEC_REG_RX_DPTR);
++	rxsd_index = (rxsd_current - (u32)rxring->desc_dma) >> 4;
++
++	if (rxsd_index > rxring->curr) {
++		rxcount = rxsd_index - rxring->curr;
++	} else if (rxsd_index < rxring->curr) {
++		rxcount = (rxring->count - rxring->curr) +
++			  rxsd_index;
++	} else {
++		if (rxd->cown == 0) {
++			goto receive_packet_exit;
++		} else {
++			/* Queue Full */
++			rxcount = rxring->count;
++		}
++	}
++
++	for (i = 0; i < rxcount; i++) {
++		if (*work_done >= work_to_do)
++			break;
++
++		++(*work_done);
++
++		if (rxd->cown != 0) {
++			/* Alloc New skb_buff */
++			skb = cns21xx_gec_alloc_skb();
++
++			/* Check skb_buff */
++			if (skb != NULL) {
++				cns21xx_gec_get_rfd_buff(gec, rxring->curr);
++				rxring->skbs[rxring->curr] = skb;
++				rxd->sdp =
++					dma_map_single(gec->parent,
++						       skb->data,
++						       MAX_PACKET_LEN,
++						       DMA_TO_DEVICE);
++				rxd->length = MAX_PACKET_LEN;
++
++				/* set cbit to 0 for CPU Transfer */
++				rxd->cown = 0;
++			} else {
++				/*
++				 * TODO: I will add dev->lp.stats->rx_dropped,
++				 * it will effect the performance
++				 */
++				dev_warn(&gec->netdev->dev,
++					 "skb allocation failed, reuse the buffer\n");
++
++				/* set cbit to 0 for CPU Transfer */
++				rxd->cown = 0;
++				return;
++			}
++		} else {
++#if 0
++			dev_err(&gec->netdev->dev, "encounter COWN == 0 BUG\n");
++#endif
++		}
++
++		if (rxring->curr == (rxring->count - 1)) {
++			rxring->curr = 0;
++			rxd = rxring->desc_cpu;
++		} else {
++			rxring->curr++;
++			rxd++;
++		}
++	}
++
++ receive_packet_exit:
++	return;
++}
++
++static int cns21xx_gec_poll(struct napi_struct *napi, int budget)
++{
++	struct cns21xx_gec *gec;
++	int work_done = 0;
++	int work_to_do = budget;
++
++	gec = container_of(napi, struct cns21xx_gec, napi);
++	cns21xx_gec_receive_packet(gec, 0, &work_done, work_to_do);
++
++	budget -= work_done;
++
++	/* if no Tx and not enough Rx work done, exit the polling mode */
++	if (work_done) {
++		if (test_bit(0, &gec->rx_queue_full) == 1) {
++			/* queue full */
++			clear_bit(0, &gec->rx_queue_full);
++			/* start Rx DMA */
++			cns21xx_gec_wr(gec, GEC_REG_RX_DMA_CTRL, 1);
++			return 1;
++		}
++	} else {
++		napi_complete(&gec->napi);
++#ifdef CONFIG_STAR_NIC_NAPI_MASK_IRQ
++		enable_irq(gec->rxrc_irq);
++#endif
++		return 0;
++	}
++
++	return work_done;
++}
++
++static int cns21xx_gec_send_packet(struct sk_buff *skb, struct net_device *dev)
++{
++	struct cns21xx_gec *gec = netdev_priv(dev);
++	struct cns21xx_gec_txd *txd;
++	struct cns21xx_gec_ring *txring = &gec->txring;
++	struct sk_buff *skb_free = NULL;
++	unsigned long flags;
++	unsigned int len;
++
++	if (skb_padto(skb, ETH_ZLEN))
++		return NETDEV_TX_OK;
++
++	len = max_t(unsigned int, skb->len, ETH_ZLEN);
++
++	spin_lock_irqsave(&gec->tx_lock, flags);
++
++	txd = ((struct cns21xx_gec_txd *) txring->desc_cpu) + txring->curr;
++	if (txd->cown == 0) {
++		/* This TFD is busy */
++		spin_unlock_irqrestore(&gec->tx_lock, flags);
++		/* re-queue the skb */
++		return NETDEV_TX_BUSY;
++	}
++
++	if (txd->sdp != 0) {
++		/* MUST TODO: Free skbuff */
++		skb_free = txring->skbs[txring->curr];
++
++		dma_unmap_single(gec->parent,
++				 txd->sdp,
++				 txd->length,
++				 DMA_TO_DEVICE);
++		txring->dirty = txring->curr + 1;
++		if (txring->dirty == txring->count)
++			txring->dirty = 0;
++	}
++
++#ifdef CNS21XX_GEC_TX_HW_CHECKSUM
++	if (skb->protocol == __constant_htons(ETH_P_IP)) {
++		if (ip_hdr(skb)->protocol == IPPROTO_UDP) {
++			txd->uco = 1;
++			txd->tco = 0;
++		} else if (ip_hdr(skb)->protocol == IPPROTO_TCP) {
++			txd->uco = 0;
++			txd->tco = 1;
++		} else {
++			txd->uco = 0;
++			txd->tco = 0;
++		}
++	} else {
++		txd->ico = 0;
++		txd->uco = 0;
++		txd->tco = 0;
++	}
++#endif /* CNS21XX_GEC_TX_HW_CHECKSUM */
++
++	txring->skbs[txring->curr] = skb;
++
++	txd->length = len;
++	txd->sdp = dma_map_single(gec->parent, skb->data, len,
++					      DMA_TO_DEVICE);
++
++	txd->fs = 1;
++	txd->ls = 1;
++
++	/* Wake interrupt */
++	txd->intr = 0;
++	txd->cown = 0;
++
++	mb();
++
++	/* Start Tx DMA */
++	cns21xx_gec_wr(gec, GEC_REG_TX_DMA_CTRL, 1);
++
++	dev->stats.tx_packets++;
++	dev->stats.tx_bytes += skb->len;
++	dev->trans_start = jiffies;
++
++	txring->curr++;
++	if (txring->curr == txring->count)
++		txring->curr = 0;
++
++	spin_unlock_irqrestore(&gec->tx_lock, flags);
++
++	if (skb_free)
++		dev_kfree_skb(skb_free);
++
++	cns21xx_gec_timer_modify(gec, 10);
++
++	return NETDEV_TX_OK;
++}
++
++static void cns21xx_gec_set_mac_addr(struct cns21xx_gec *gec,
++				  const char *mac_addr)
++{
++	cns21xx_gec_wr(gec, GEC_REG_MY_MAC_H,
++		    (mac_addr[0] << 8) | mac_addr[1]);
++
++	cns21xx_gec_wr(gec, GEC_REG_MY_MAC_L,
++		    (mac_addr[2] << 24) | (mac_addr[3] << 16) |
++		    (mac_addr[4] << 8) |  mac_addr[5]);
++
++	dev_dbg(&gec->netdev->dev, "MAC address: %pM", mac_addr);
++}
++
++static int cns21xx_gec_set_lan_mac_addr(struct net_device *dev, void *addr)
++{
++	struct sockaddr *sock_addr = addr;
++	struct cns21xx_gec *gec = netdev_priv(dev);
++
++	spin_lock_irq(&gec->lock);
++	memcpy(dev->dev_addr, sock_addr->sa_data, 6);
++	cns21xx_gec_set_mac_addr(gec, sock_addr->sa_data);
++	spin_unlock_irq(&gec->lock);
++
++	return 0;
++}
++
++static int __init cns21xx_gec_setup(struct cns21xx_gec *gec)
++{
++	int err;
++
++	/* set high */
++	PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 15);
++	/* set low */
++	PWRMGT_SOFTWARE_RESET_CONTROL_REG &= ~(0x1 << 15);
++	/* set high */
++	PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 15);
++	/* set NIC clock to 67.5MHz */
++	PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= (0x1 << 7);
++
++	/* enable NIC clock */
++	HAL_PWRMGT_ENABLE_NIC_CLOCK();
++#if 0
++	cns21xx_gec_wr(gec, GEC_REG_MAC_CFG, 0x00527C00);
++#endif
++	udelay(100);
++
++	/* Configure GPIO for NIC MDC/MDIO pins */
++	HAL_MISC_ENABLE_MDC_MDIO_PINS();
++	HAL_MISC_ENABLE_NIC_COL_PINS();
++
++#if 0
++	MISC_GPIOA_PIN_ENABLE_REG |= (0x7 << 22);
++	MISC_FAST_ETHERNET_PHY_CONFIG_REG |=  (FE_PHY_LED_MODE >> 12) & 0x3;
++
++	/* set high */
++	PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 15);
++	/* set low */
++	PWRMGT_SOFTWARE_RESET_CONTROL_REG &= ~(0x1 << 15);
++	/* set high */
++	PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 15);
++#endif
++
++	/* disable all interrupt status sources */
++	cns21xx_gec_wr(gec, GEC_REG_INT_MASK, ~(0));
++	/* clear pending interrupts */
++	cns21xx_gec_wr(gec, GEC_REG_INT, ~(0));
++
++	/* stop Rx and Tx DMA */
++	cns21xx_gec_wr(gec, GEC_REG_TX_DMA_CTRL, 0);
++	cns21xx_gec_wr(gec, GEC_REG_RX_DMA_CTRL, 0);
++
++	gec->txring.count = CNS21XX_GEC_NUM_TXDS;
++	gec->rxring.count = CNS21XX_GEC_NUM_RXDS;
++	err = cns21xx_gec_buffer_alloc(gec);
++	if (err)
++		return err;
++
++	cns21xx_gec_mac_config(gec);
++	cns21xx_gec_fc_config(gec);
++
++	err = cns21xx_gec_phy_config(gec);
++	if (err) {
++		cns21xx_gec_buffer_free(gec);
++		return err;
++	}
++
++	cns21xx_gec_vlan_config(gec);
++	cns21xx_gec_arl_config(gec);
++	cns21xx_gec_set_mac_addr(gec, gec->netdev->dev_addr);
++	cns21xx_gec_mib_reset(gec);
++
++	MISC_DEBUG_PROBE_SELECTION_REG = 0x00000125;    /* 0x00000105 pb0_nic */
++
++	cns21xx_gec_wr(gec, GEC_REG_TX_DPTR, gec->txring.desc_dma);
++	cns21xx_gec_wr(gec, GEC_REG_TX_BASE_ADDR, gec->txring.desc_dma);
++	cns21xx_gec_wr(gec, GEC_REG_RX_DPTR, gec->rxring.desc_dma);
++	cns21xx_gec_wr(gec, GEC_REG_RX_BASE_ADDR, gec->rxring.desc_dma);
++
++	cns21xx_gec_dma_config(gec);
++	internal_phy_init_timer(gec);
++	cns21xx_gec_timer_init(gec);
++
++	return 0;
++}
++
++static const struct net_device_ops cns21xx_gec_netdev_ops = {
++	.ndo_open		= cns21xx_gec_lan_open,
++	.ndo_stop		= cns21xx_gec_close,
++	.ndo_start_xmit		= cns21xx_gec_send_packet,
++	.ndo_set_mac_address	= cns21xx_gec_set_lan_mac_addr,
++	.ndo_tx_timeout		= cns21xx_gec_timeout,
++	.ndo_validate_addr	= eth_validate_addr,
++	.ndo_change_mtu		= eth_change_mtu,
++};
++
++static int __init cns21xx_gec_probe(struct platform_device *pdev)
++{
++	struct net_device *netdev;
++	struct cns21xx_gec *gec;
++	struct cns21xx_gec_plat_data *pdata;
++	int err;
++
++	pdata = pdev->dev.platform_data;
++	if (!pdata) {
++		dev_dbg(&pdev->dev, "no platform data\n");
++		err = -EINVAL;
++		goto err_out;
++	}
++
++	if (!pdata->mac_addr) {
++		dev_dbg(&pdev->dev, "no mac address\n");
++		err = -EINVAL;
++		goto err_out;
++	}
++
++	netdev = alloc_etherdev(sizeof(struct cns21xx_gec));
++	if (!netdev) {
++		err = -ENOMEM;
++		goto err_out;
++	}
++
++	SET_NETDEV_DEV(netdev, &pdev->dev);
++
++	gec = netdev_priv(netdev);
++	gec->pdata = pdata;
++	gec->parent = &pdev->dev;
++
++	gec->mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!gec->mem_res) {
++		dev_dbg(&pdev->dev, "no iomem resource\n");
++		err = -EINVAL;
++		goto err_free_netdev;
++	}
++
++	gec->status_irq = platform_get_irq_byname(pdev,
++						   CNS21XX_GEC_STATUS_IRQ_NAME);
++	if (gec->status_irq < 0) {
++		dev_dbg(&pdev->dev, "%s irq not specified\n",
++			CNS21XX_GEC_STATUS_IRQ_NAME);
++		err = -EINVAL;
++		goto err_free_netdev;
++	}
++
++	gec->rxrc_irq = platform_get_irq_byname(pdev,
++						CNS21XX_GEC_RXRC_IRQ_NAME);
++	if (gec->rxrc_irq < 0) {
++		dev_dbg(&pdev->dev, "%s irq not specified\n",
++			CNS21XX_GEC_RXRC_IRQ_NAME);
++		err = -EINVAL;
++		goto err_free_netdev;
++	}
++
++	gec->rxqf_irq = platform_get_irq_byname(pdev,
++						CNS21XX_GEC_RXQF_IRQ_NAME);
++	if (gec->rxqf_irq < 0) {
++		dev_dbg(&pdev->dev, "%s irq not specified\n",
++			CNS21XX_GEC_RXQF_IRQ_NAME);
++		err = -EINVAL;
++		goto err_free_netdev;
++	}
++
++	gec->txtc_irq = platform_get_irq_byname(pdev,
++						CNS21XX_GEC_TXTC_IRQ_NAME);
++	if (gec->txtc_irq < 0) {
++		dev_dbg(&pdev->dev, "%s irq not specified\n",
++			CNS21XX_GEC_TXTC_IRQ_NAME);
++		err = -EINVAL;
++		goto err_free_netdev;
++	}
++
++	gec->txqe_irq = platform_get_irq_byname(pdev,
++						CNS21XX_GEC_TXQE_IRQ_NAME);
++	if (gec->txqe_irq < 0) {
++		dev_dbg(&pdev->dev, "%s irq not specified\n",
++			CNS21XX_GEC_TXQE_IRQ_NAME);
++		err = -EINVAL;
++		goto err_free_netdev;
++	}
++
++	if (!request_mem_region(gec->mem_res->start,
++				resource_size(gec->mem_res), pdev->name)) {
++		dev_err(&pdev->dev, "unable to request mem region\n");
++		err = -EBUSY;
++		goto err_free_netdev;
++	}
++
++	gec->base = ioremap(gec->mem_res->start, resource_size(gec->mem_res));
++	if (!gec->base) {
++		dev_err(&pdev->dev, "ioremap failed \n");
++		err = -ENXIO;
++		goto err_release_mem;
++	}
++
++	platform_set_drvdata(pdev, netdev);
++
++	spin_lock_init(&gec->lock);
++	spin_lock_init(&gec->tx_lock);
++
++	netdev->base_addr = gec->mem_res->start;
++	netdev->netdev_ops = &cns21xx_gec_netdev_ops;
++#if defined(CNS21XX_GEC_TX_HW_CHECKSUM)
++	netdev->features = NETIF_F_IP_CSUM;
++#endif
++	memcpy(netdev->dev_addr, pdata->mac_addr, 6);
++	netif_napi_add(netdev, &gec->napi, cns21xx_gec_poll, 64);
++
++	gec->netdev = netdev;
++	err = register_netdev(netdev);
++	if (err)
++		goto err_unmap;
++
++	err = cns21xx_gec_setup(gec);
++	if (err)
++		goto err_unregister_netdev;
++
++	return 0;
++
++ err_unregister_netdev:
++	unregister_netdev(netdev);
++ err_unmap:
++	platform_set_drvdata(pdev, NULL);
++	iounmap(gec->base);
++ err_release_mem:
++	release_mem_region(gec->mem_res->start, resource_size(gec->mem_res));
++ err_free_netdev:
++	free_netdev(netdev);
++ err_out:
++	return err;
++}
++
++static int __devexit cns21xx_gec_remove(struct platform_device *pdev)
++{
++	struct net_device *netdev = platform_get_drvdata(pdev);
++	struct cns21xx_gec *gec = netdev_priv(netdev);
++
++	unregister_netdev(netdev);
++	platform_set_drvdata(pdev, NULL);
++	iounmap(gec->base);
++	release_mem_region(gec->mem_res->start, resource_size(gec->mem_res));
++	free_netdev(netdev);
++
++	return 0;
++}
++
++static struct platform_driver cns21xx_gec_driver = {
++	.remove	= __devexit_p(cns21xx_gec_remove),
++	.driver = {
++		.name	= "cns21xx-gec",
++		.owner	= THIS_MODULE,
++	}
++};
++
++static int __init cns21xx_gec_init(void)
++{
++	return platform_driver_probe(&cns21xx_gec_driver, cns21xx_gec_probe);
++}
++
++static void __exit cns21xx_gec_exit(void)
++{
++	platform_driver_unregister(&cns21xx_gec_driver);
++}
++
++module_init(cns21xx_gec_init);
++module_exit(cns21xx_gec_exit);
++
++#define INTERNAL_PHY_PATCH_CHECKCNT	16
++#define INTERNAL_PHY_PATCH_CHECK_PERIOD	1000 /* ms */
++
++static void (*phy_statemachine)(struct cns21xx_gec*, int, int, int);
++
++#define ETH3220_PHY_MON_PERIOD INTERNAL_PHY_PATCH_CHECK_PERIOD
++
++/*  phy monitor state  */
++#define NUM_PHY 1
++#define PHY_STATE_INIT				0
++#define LINK_DOWN_POSITIVE			1
++#define WAIT_LINK_UP_POSITIVE			2
++#define LINK_UP_POSITIVE			3
++#define WAIT_BYPASS_LINK_UP_POSITIVE		4
++#define BYPASS_AND_LINK_UP_POSITIVE		5
++#define LINK_UP_8101_POSITIVE			6
++#define WAIT_8101_LINK_UP_POSITIVE		7
++
++#define PHY_STATE_LAST				(WAIT_8101_LINK_UP_POSITIVE+1)
++
++/*  time setting  */
++#define WAIT_BYPASS_LINK_UP_POSITIVE_TIMEOUT	5000	/*  5000 ms  */
++#define WAIT_BYPASS_LINK_UP_NEGATIVE_TIMEOUT	5000	/*  5000 ms  */
++#define LINK_DOWN_ABILITY_DETECT_TIMEOUT	5000	/*  5000 ms  */
++#define DETECT_8101_PERIOD			7000	/*  7000 ms  */
++#define WAIT_8101_LINK_UP_TIMEOUT		3000	/*  3000 ms  */
++
++#define MAX_PHY_PORT				1
++#define DEFAULT_AGC_TRAIN			16
++#define MAX_AGC_TRAIN				16	/* train 16 times */
++static int agc_train_num = DEFAULT_AGC_TRAIN;
++u32 port_displaybuf[NUM_PHY][MAX_AGC_TRAIN + 1] = {
++	{0}
++};
++
++static int cuv[3][3] = {
++	{1, 1, 4},
++	{1, 1, 0},
++	{1, 1, -4}
++};
++
++static u32 link_status_old;
++
++struct eth3220_phy {
++	u16 state;
++	u16 linkdown_cnt;
++	u32 state_time;
++	u32 timer;
++};
++
++#define DEBUG_PHY_STATE_TRANSITION			1
++#if DEBUG_PHY_STATE_TRANSITION
++/*
++ * show state transition of debug phy port.
++ *  -1 for all ports
++ *  -2 for disable all ports
++ *  0 - 4 for each port
++ */
++static int debug_phy_port = -2;
++static char *phystate_name[] = {
++	"init",			/*  PHY_STATE_INIT  */
++	"ldp",			/*  LINK_DOWN_POSITIVE  */
++	"wait_lup",		/*  WAIT_LINK_UP_POSITIVE  */
++	"lup",			/*  LINK_UP_POSITIVE  */
++	"wait_bp_lup",		/*  WAIT_BYPASS_LINK_UP_POSITIVE  */
++	"bp_lup",		/*  BYPASS_AND_LINK_UP_POSITIVE  */
++	"8101_lup",		/*  LINK_UP_8101_POSITIVE  */
++	"wait_8101_lup",	/*  WAIT_8101_LINK_UP_POSITIVE  */
++	"err",
++};
++#endif  /*  DEBUG_PHY_STATE_TRANSITION  */
++
++static struct eth3220_phy phy[5] = {
++	{PHY_STATE_INIT, 0, 0, 0},
++	{PHY_STATE_INIT, 0, 0, 0},
++	{PHY_STATE_INIT, 0, 0, 0},
++	{PHY_STATE_INIT, 0, 0, 0},
++	{PHY_STATE_INIT, 0, 0, 0}
++};
++
++static u16 long_cable_global_reg[32] = {
++	0x0000, 0x19a0, 0x1d00, 0x0e80,
++	0x0f60, 0x07c0, 0x07e0, 0x03e0,
++	0x0000, 0x0000, 0x0000, 0x2000,
++	0x8250, 0x1700, 0x0000, 0x0000,
++	0x0000, 0x0000, 0x0000, 0x0000,
++	0x0000, 0x204b, 0x01c2, 0x0000,
++	0x0000, 0x0000, 0x0fff, 0x4100,
++	0x9319, 0x0021, 0x0034, 0x270a | FE_PHY_LED_MODE
++};
++
++static u16 long_cable_local_reg[32] = {
++	0x3100, 0x786d, 0x01c1, 0xca51,
++	0x05e1, 0x45e1, 0x0003, 0x001c,
++	0x2000, 0x9828, 0xf3c4, 0x400c,
++	0xf8ff, 0x6940, 0xb906, 0x503c,
++	0x8000, 0x297a, 0x1010, 0x5010,
++	0x6ae1, 0x7c73, 0x783c, 0xfbdf,
++	0x2080, 0x3244, 0x1301, 0x1a80,
++	0x8e8f, 0x8000, 0x9c29, 0xa70a | FE_PHY_LED_MODE
++};
++
++/*=============================================================*
++ *  eth3220ac_rt8101_phy_setting
++ *=============================================================*/
++static  void eth3220ac_rt8101_phy_setting(struct cns21xx_gec *gec, int port)
++{
++	cns21xx_gec_write_phy(gec, port, 12, 0x18ff);
++	cns21xx_gec_write_phy(gec, port, 18, 0x6400);
++}
++
++static void eth3220ac_release_bpf(struct cns21xx_gec *gec, int port)
++{
++	cns21xx_gec_write_phy(gec, port, 18, 0x6210);
++}
++
++static  void eth3220ac_def_bpf(struct cns21xx_gec *gec, int port)
++{
++	cns21xx_gec_write_phy(gec, port, 18, 0x6bff);
++}
++
++static  void eth3220ac_def_linkdown_setting(struct cns21xx_gec *gec, int port)
++{
++	cns21xx_gec_write_phy(gec, port, 13, 0xe901);
++	cns21xx_gec_write_phy(gec, port, 14, 0xa3c6);
++}
++
++static  void eth3220ac_def_linkup_setting(struct cns21xx_gec *gec, int port)
++{
++	cns21xx_gec_write_phy(gec, port, 13, 0x6901);
++	cns21xx_gec_write_phy(gec, port, 14, 0xa286);
++}
++
++/*=============================================================*
++ *  eth3220ac_link_agc:
++ *=============================================================*/
++static int eth3220ac_link_agc(struct cns21xx_gec *gec, int port, int speed)
++{
++	u16 reg;
++	u32 agc_data = 0;
++	u32 short_cable;
++	int i, jj;
++
++	/* if speed = 100MHz, then continue */
++	if (speed == 0)
++		return 0;
++
++	short_cable = 0;
++	jj = 0;
++	for (i = 0; i < agc_train_num; i++) {
++		cns21xx_gec_read_phy(gec, port, 15, &reg);
++		reg &= 0x7f;
++		if (reg <= 0x12) {
++			short_cable = 1;
++			jj++;
++			agc_data += (u32)reg;
++		}
++	}
++
++	if (short_cable)
++		agc_data = (agc_data / jj) + 4;
++	else
++		agc_data = (cuv[2][0] * agc_data) / cuv[2][1] /
++			   agc_train_num - 4;
++
++	/*  Fix AGC  */
++	agc_data = 0xd0 | (agc_data << 9);
++	cns21xx_gec_write_phy(gec, port, 15, agc_data);
++	udelay(1000);
++	cns21xx_gec_read_phy(gec, port, 15, &reg);
++	reg &= ~(0x1 << 7);
++	cns21xx_gec_write_phy(gec, port, 15, reg);
++
++	return 0;
++}
++
++/*=============================================================*
++ *  eth3220ac_unlink_agc:
++ *=============================================================*/
++static void eth3220ac_unlink_agc(struct cns21xx_gec *gec, int port)
++{
++	/* start AGC adaptive */
++	cns21xx_gec_write_phy(gec, port, 15, 0xa050);
++}
++
++/*=============================================================*
++ *  eth3220ac_rt8100_check
++ *=============================================================*/
++static int eth3220ac_rt8100_check(struct cns21xx_gec *gec, int port)
++{
++	u16 reg, reg2;
++
++	/* Read reg27 (error register) */
++	cns21xx_gec_read_phy(gec, port, 27, &reg);
++	/* if error exists, set Bypass Filter enable */
++	if ((reg & 0xfffc)) {
++		cns21xx_gec_read_phy(gec, port, 15, &reg);
++		cns21xx_gec_read_phy(gec, port, 27, &reg2);
++		if ((reg2 & 0xfffc) && (((reg >> 9) & 0xff) < 0x1c)) {
++			dev_err(&gec->netdev->dev, "8100 pos err\n");
++
++			/* Bypass agcgain disable */
++			cns21xx_gec_write_phy(gec, port, 15, (reg & (~(0x1 << 7))));
++
++			/* repeat counts when reaching threshold error */
++			cns21xx_gec_write_phy(gec, port, 13, 0x4940);
++
++			/*
++			 * Speed up AN speed and compensate threshold
++			 * phase error
++			 */
++			cns21xx_gec_write_phy(gec, port, 14, 0xa306);
++
++			/* Bypass Filter enable */
++			cns21xx_gec_read_phy(gec, port, 18, &reg2);
++
++			cns21xx_gec_write_phy(gec, port, 18, (reg | 0x400));
++
++			/* restart AN */
++			cns21xx_gec_write_phy(gec, port, 0, 0x3300);
++			return 1;
++		}
++	}
++	return 0;
++}
++
++
++/*=============================================================*
++ *  eth3220ac_rt8100_linkdown
++ *=============================================================*/
++static void eth3220ac_rt8100_linkdown(struct cns21xx_gec *gec, int port)
++{
++	u16 reg;
++
++	/* Bypass Filter disable */
++	cns21xx_gec_read_phy(gec, port, 18, &reg);
++	cns21xx_gec_write_phy(gec, port, 18, (reg & (~(0x1 << 10))));
++	eth3220ac_def_linkdown_setting(gec, port);
++}
++
++static void eth3220ac_normal_phy_setting(struct cns21xx_gec *gec, int port)
++{
++	cns21xx_gec_write_phy(gec, port, 12, 0xd8ff);
++	eth3220ac_def_bpf(gec, port);
++}
++
++/*=============================================================*
++ *  wp3220ac_phystate
++ *=============================================================*/
++static void wp3220ac_phystate(struct cns21xx_gec *gec, int port, int link, int speed)
++{
++	int next_state;
++	u16 reg, reg2;
++
++	phy[port].timer += ETH3220_PHY_MON_PERIOD;
++
++	if (link) {
++		/*  Link up state  */
++		switch (phy[port].state) {
++		case LINK_UP_POSITIVE:
++			next_state = eth3220ac_rt8100_check(gec, port) ?
++				WAIT_BYPASS_LINK_UP_POSITIVE :
++				LINK_UP_POSITIVE;
++			break;
++
++		case PHY_STATE_INIT:
++		case WAIT_LINK_UP_POSITIVE:
++		case LINK_DOWN_POSITIVE:
++			next_state = LINK_UP_POSITIVE;
++			eth3220ac_def_linkup_setting(gec, port);
++			eth3220ac_link_agc(gec, port, speed);
++			eth3220ac_release_bpf(gec, port);
++			break;
++
++		case WAIT_BYPASS_LINK_UP_POSITIVE:
++		case BYPASS_AND_LINK_UP_POSITIVE:
++			next_state = BYPASS_AND_LINK_UP_POSITIVE;
++			break;
++
++		case WAIT_8101_LINK_UP_POSITIVE:
++			next_state = LINK_UP_8101_POSITIVE;
++			eth3220ac_link_agc(gec, port, speed);
++			cns21xx_gec_write_phy(gec, port, 12, 0x98ff);
++			break;
++
++		case LINK_UP_8101_POSITIVE:
++			next_state = LINK_UP_8101_POSITIVE;
++			break;
++
++		default:
++			next_state = LINK_UP_POSITIVE;
++			eth3220ac_def_linkup_setting(gec, port);
++			eth3220ac_link_agc(gec, port, speed);
++		}
++	} else {
++		/*  Link down state  */
++		switch (phy[port].state) {
++		case LINK_DOWN_POSITIVE:
++			cns21xx_gec_read_phy(gec, port, 5, &reg);
++			cns21xx_gec_read_phy(gec, port, 28, &reg2);
++
++			/* AN Link Partner Ability Register or NLP */
++			if (reg || (reg2 & 0x100))
++				next_state = WAIT_LINK_UP_POSITIVE;
++			else
++				next_state = LINK_DOWN_POSITIVE;
++			break;
++
++		case WAIT_LINK_UP_POSITIVE:
++			if (phy[port].state_time >
++					LINK_DOWN_ABILITY_DETECT_TIMEOUT)
++				next_state = LINK_DOWN_POSITIVE;
++			else
++				next_state = WAIT_LINK_UP_POSITIVE;
++			break;
++
++		case WAIT_BYPASS_LINK_UP_POSITIVE:
++			/* set timeout = 5 sec */
++			if (phy[port].state_time >
++					WAIT_BYPASS_LINK_UP_POSITIVE_TIMEOUT) {
++				next_state = LINK_DOWN_POSITIVE;
++
++				/* Bypass Filter disable */
++				eth3220ac_rt8100_linkdown(gec, port);
++				eth3220ac_def_bpf(gec, port);
++			} else {
++				next_state = WAIT_BYPASS_LINK_UP_POSITIVE;
++			}
++			break;
++
++		case BYPASS_AND_LINK_UP_POSITIVE:
++			next_state = LINK_DOWN_POSITIVE;
++			eth3220ac_rt8100_linkdown(gec, port);
++			eth3220ac_def_bpf(gec, port);
++			break;
++
++		case WAIT_8101_LINK_UP_POSITIVE:
++			if (phy[port].state_time > WAIT_8101_LINK_UP_TIMEOUT) {
++				next_state = LINK_DOWN_POSITIVE;
++				eth3220ac_normal_phy_setting(gec, port);
++				eth3220ac_def_linkdown_setting(gec, port);
++			} else {
++				next_state = WAIT_8101_LINK_UP_POSITIVE;
++			}
++			break;
++
++		case LINK_UP_POSITIVE:
++			eth3220ac_unlink_agc(gec, port);
++			eth3220ac_def_linkdown_setting(gec, port);
++			eth3220ac_def_bpf(gec, port);
++			if (phy[port].timer > DETECT_8101_PERIOD) {
++				next_state = LINK_DOWN_POSITIVE;
++				phy[port].timer = 0;
++				phy[port].linkdown_cnt = 1;
++			} else {
++				if (++phy[port].linkdown_cnt > 2) {
++					next_state = WAIT_8101_LINK_UP_POSITIVE;
++					eth3220ac_rt8101_phy_setting(gec, port);
++				} else {
++					next_state = LINK_DOWN_POSITIVE;
++				}
++			}
++			break;
++
++		case LINK_UP_8101_POSITIVE:
++			eth3220ac_normal_phy_setting(gec, port);
++			/*  fall down to phy normal state  */
++		case PHY_STATE_INIT:
++			eth3220ac_def_linkdown_setting(gec, port);
++			eth3220ac_unlink_agc(gec, port);
++		default:
++			next_state = LINK_DOWN_POSITIVE;
++		}
++	}
++
++	if (phy[port].state != next_state) {
++		phy[port].state_time = 0;
++#if DEBUG_PHY_STATE_TRANSITION
++		if (debug_phy_port == -1 || port == debug_phy_port) {
++			if ((phy[port].state < PHY_STATE_LAST) &&
++			    (next_state < PHY_STATE_LAST))
++				dev_dbg(&gec->netdev->dev,
++					"p%d: %s->%s, %d, %d\n",
++					port, phystate_name[phy[port].state],
++					phystate_name[next_state],
++					phy[port].timer,
++					phy[port].linkdown_cnt);
++			else
++				dev_dbg(&gec->netdev->dev,
++					"p%d: %d->%d\n",
++					port, phy[port].state, next_state);
++		}
++#endif   /*  DEBUG_PHY_STATE_TRANSITION  */
++	} else {
++		phy[port].state_time += ETH3220_PHY_MON_PERIOD;
++	}
++	phy[port].state = next_state;
++}
++
++/*=============================================================*
++ *  eth3220_phyinit:
++ *=============================================================*/
++static void eth3220ac_10m_agc(struct cns21xx_gec *gec)
++{
++	/* Force 10M AGC = 2c globally */
++	cns21xx_gec_write_phy(gec, 0, 31, 0x2f1a);
++	cns21xx_gec_write_phy(gec, 0, 12, 0x112c);
++	cns21xx_gec_write_phy(gec, 0, 13, 0x2e21);
++	cns21xx_gec_write_phy(gec, 0, 31, 0xaf1a);
++}
++
++static void eth3220ac_dfe_init(struct cns21xx_gec *gec)
++{
++	int i;
++
++	cns21xx_gec_write_phy(gec, 0, 31, 0x2f1a);
++	for (i = 0; i <= 7; i++)
++		cns21xx_gec_write_phy(gec, 0, i, 0);
++	cns21xx_gec_write_phy(gec, 0, 11, 0x0b50);
++	cns21xx_gec_write_phy(gec, 0, 31, 0xaf1a);
++}
++
++static void eth3220ac_phy_cdr_training_init(struct cns21xx_gec *gec)
++{
++	int i;
++
++	/* Force all port in 10M FD mode */
++	for (i = 0; i < NUM_PHY; i++)
++		cns21xx_gec_write_phy(gec, i, 0, 0x100);
++
++	/* Global setting */
++	cns21xx_gec_write_phy(gec, 0, 31, 0x2f1a);
++	cns21xx_gec_write_phy(gec, 0, 29, 0x5021);
++	udelay(2000); 		/* 2ms, wait > 1 ms */
++	cns21xx_gec_write_phy(gec, 0, 29, 0x4021);
++	udelay(2000);		/* 2ms, wait > 1 ms */
++	cns21xx_gec_write_phy(gec, 0, 31, 0xaf1a);
++
++	/* Enable phy AN */
++	for (i = 0; i < NUM_PHY; i++)
++		cns21xx_gec_write_phy(gec, i, 0, 0x3100);
++}
++
++static void eth3220_phyinit(struct cns21xx_gec *gec)
++{
++	eth3220ac_10m_agc(gec);
++	eth3220ac_dfe_init(gec);
++	eth3220ac_phy_cdr_training_init(gec);
++}
++
++static void eth3220_phycfg(struct cns21xx_gec *gec, int phyaddr)
++{
++	eth3220ac_def_linkdown_setting(gec, phyaddr);
++	eth3220ac_normal_phy_setting(gec, phyaddr);
++	cns21xx_gec_write_phy(gec, phyaddr, 9, 0x7f);
++}
++
++static void internal_phy_patch_check(struct cns21xx_gec *gec, int init)
++{
++	u32 short_cable_agc_detect_count;
++	u32 link_status = 0, link_speed;
++	u32 phy_addr = gec->phy_addr;
++	u16 phy_data;
++	u16 phy_data2;
++	int i;
++
++	cns21xx_gec_read_phy(gec, phy_addr, 1, &phy_data);
++	udelay(100);
++	cns21xx_gec_read_phy(gec, phy_addr, 1, &phy_data2);
++	if (((phy_data & 0x0004) != 0x0004) &&
++	    ((phy_data2 & 0x0004) != 0x0004)) {
++		/* link down */
++		short_cable_agc_detect_count = 0;
++		for (i = 0; i < INTERNAL_PHY_PATCH_CHECKCNT; i++) {
++			cns21xx_gec_read_phy(gec, phy_addr, 15, &phy_data);
++			udelay(1000);
++			if ((phy_data & 0x7F) <= 0x12) {
++				/* short cable */
++				short_cable_agc_detect_count++;
++				break;
++			}
++		}
++		if (short_cable_agc_detect_count) {
++			u32 mac_cfg;
++
++			/* short cable */
++			phy_statemachine = wp3220ac_phystate;
++			eth3220_phyinit(gec);
++			cns21xx_gec_read_phy(gec, phy_addr, 1, &phy_data);
++			if (phy_data & 0x0040)
++				link_status = 1;
++
++			mac_cfg = cns21xx_gec_rr(gec, GEC_REG_MAC_CFG);
++			if ((mac_cfg & 0xC) == 0x4) /* 100Mbps */
++				link_speed = 1;
++			else
++				link_speed = 0;
++
++			link_status_old = link_status;
++			for (i = 0; i < MAX_PHY_PORT; link_status >>= 1, i++)
++				eth3220_phycfg(gec, i);
++		} else {
++			/* long cable */
++			/* set to global domain */
++			cns21xx_gec_write_phy(gec, phy_addr, 31,
++					      0x2f1a);
++			for (i = 0; i < 32; i++)
++				cns21xx_gec_write_phy(gec, phy_addr, i,
++						      long_cable_global_reg[i]);
++
++			/* set to local domain */
++			cns21xx_gec_write_phy(gec, phy_addr, 31,
++					      0xaf1a);
++			for (i = 0; i < 32; i++)
++				cns21xx_gec_write_phy(gec, phy_addr, i,
++						      long_cable_local_reg[i]);
++		}
++	}
++}
++
++static void internal_phy_timer_func(unsigned long data)
++{
++	struct cns21xx_gec *gec = (struct cns21xx_gec *) data;
++
++	internal_phy_patch_check(gec, 0);
++	mod_timer(&gec->internal_phy_timer,
++		  jiffies + INTERNAL_PHY_PATCH_CHECK_PERIOD / 10);
++}
++
++static void internal_phy_init_timer(struct cns21xx_gec *gec)
++{
++	init_timer(&gec->internal_phy_timer);
++	gec->internal_phy_timer.function = internal_phy_timer_func;
++	gec->internal_phy_timer.data = (unsigned long) gec;
++}
++
++static void internal_phy_start_timer(struct cns21xx_gec *gec)
++{
++	dev_dbg(&gec->netdev->dev, "starting patch check.\n");
++
++	internal_phy_patch_check(gec, 1);
++	mod_timer(&gec->internal_phy_timer,
++		  jiffies + INTERNAL_PHY_PATCH_CHECK_PERIOD / 10);
++}
++
++static void internal_phy_stop_timer(struct cns21xx_gec *gec)
++{
++	dev_dbg(&gec->netdev->dev, "stopping patch check.\n");
++
++	del_timer_sync(&gec->internal_phy_timer);
++}
+--- /dev/null
++++ b/drivers/net/ethernet/cns21xx/Kconfig
+@@ -0,0 +1,7 @@
++config CNS21XX_GEC
++	tristate  "CNS21XX Gigabit Ethernet Controller support"
++	depends on ARCH_CNS21XX
++	help
++	  If you wish to compile a kernel for Cavium Networks CNS21XX
++	  with ethernet support, then you should always answer Y to this.
++
+--- /dev/null
++++ b/drivers/net/ethernet/cns21xx/Makefile
+@@ -0,0 +1,7 @@
++#
++# Makefile for the Cavium Networks CNS21XX ethernet driver
++#
++
++cns21xx_gec-y	+= cns21xx_gec_main.o
++
++obj-$(CONFIG_CNS21XX_GEC) += cns21xx_gec.o
+--- a/drivers/net/ethernet/Kconfig
++++ b/drivers/net/ethernet/Kconfig
+@@ -32,6 +32,7 @@ source "drivers/net/ethernet/calxeda/Kco
+ source "drivers/net/ethernet/chelsio/Kconfig"
+ source "drivers/net/ethernet/cirrus/Kconfig"
+ source "drivers/net/ethernet/cisco/Kconfig"
++source "drivers/net/ethernet/cns21xx/Kconfig"
+ source "drivers/net/ethernet/davicom/Kconfig"
+ 
+ config DNET
+--- a/drivers/net/ethernet/Makefile
++++ b/drivers/net/ethernet/Makefile
+@@ -18,6 +18,7 @@ obj-$(CONFIG_NET_CALXEDA_XGMAC) += calxe
+ obj-$(CONFIG_NET_VENDOR_CHELSIO) += chelsio/
+ obj-$(CONFIG_NET_VENDOR_CIRRUS) += cirrus/
+ obj-$(CONFIG_NET_VENDOR_CISCO) += cisco/
++obj-$(CONFIG_CNS21XX_GEC) += cns21xx/
+ obj-$(CONFIG_DM9000) += davicom/
+ obj-$(CONFIG_DNET) += dnet.o
+ obj-$(CONFIG_NET_VENDOR_DEC) += dec/
diff --git a/target/linux/cns21xx/patches-3.6/201-cns21xx-add-usb-devices.patch b/target/linux/cns21xx/patches-3.6/201-cns21xx-add-usb-devices.patch
new file mode 100644
index 0000000000..c9299b6af3
--- /dev/null
+++ b/target/linux/cns21xx/patches-3.6/201-cns21xx-add-usb-devices.patch
@@ -0,0 +1,104 @@
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/dev-usb.c
+@@ -0,0 +1,71 @@
++/*
++ *  Copyright (c) 2008 Cavium Networks
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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/init.h>
++#include <linux/irq.h>
++#include <linux/dma-mapping.h>
++#include <linux/platform_device.h>
++
++#include <mach/cns21xx.h>
++
++static u64 cns21xx_usb_dmamask = DMA_BIT_MASK(32);
++
++static struct resource cns21xx_ohci_resources[] = {
++	[0] = {
++		.start	= CNS21XX_OHCI_CTRL_BASE,
++		.end	= CNS21XX_OHCI_CTRL_BASE + SZ_1M - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= CNS21XX_IRQ_OHCI,
++		.end	= CNS21XX_IRQ_OHCI,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device cns21xx_ohci_device = {
++	.name		= "cns21xx-ohci",
++	.id		= -1,
++	.dev = {
++		.dma_mask		= &cns21xx_usb_dmamask,
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.resource	= cns21xx_ohci_resources,
++	.num_resources	= ARRAY_SIZE(cns21xx_ohci_resources),
++};
++
++static struct resource cns21xx_ehci_resources[] = {
++	[0] = {
++		.start	= CNS21XX_EHCI_CTRL_BASE,
++		.end	= CNS21XX_EHCI_CTRL_BASE + SZ_1M - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= CNS21XX_IRQ_EHCI,
++		.end	= CNS21XX_IRQ_EHCI,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device cns21xx_ehci_device = {
++	.name		= "cns21xx-ehci",
++	.id		= -1,
++	.dev		= {
++		.dma_mask		= &cns21xx_usb_dmamask,
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.resource	= cns21xx_ehci_resources,
++	.num_resources	= ARRAY_SIZE(cns21xx_ehci_resources),
++};
++
++void __init cns21xx_register_usb(void)
++{
++	platform_device_register(&cns21xx_ehci_device);
++	platform_device_register(&cns21xx_ohci_device);
++}
+--- a/arch/arm/mach-cns21xx/Kconfig
++++ b/arch/arm/mach-cns21xx/Kconfig
+@@ -3,4 +3,7 @@ if ARCH_CNS21XX
+ menu "Cavium Networks CNS21xx based machines"
+ endmenu
+ 
++config CNS21XX_DEV_USB
++	def_bool n
++
+ endif
+--- a/arch/arm/mach-cns21xx/Makefile
++++ b/arch/arm/mach-cns21xx/Makefile
+@@ -6,5 +6,8 @@
+ 
+ obj-y		:= core.o devices.o gpio.o irq.o mm.o time.o
+ 
++# devices
++obj-$(CONFIG_CNS21XX_DEV_USB)		+= dev-usb.o
++
+ # machine specific files
+ 
+--- a/arch/arm/mach-cns21xx/common.h
++++ b/arch/arm/mach-cns21xx/common.h
+@@ -19,5 +19,6 @@ extern struct sys_timer cns21xx_timer;
+ 
+ int cns21xx_register_uart0(void);
+ int cns21xx_register_uart1(void);
++int cns21xx_register_usb(void);
+ 
+ #endif /* _MACH_CNS21XX_COMMON_H */
diff --git a/target/linux/cns21xx/patches-3.6/202-cns21xx-add-watchdog-device.patch b/target/linux/cns21xx/patches-3.6/202-cns21xx-add-watchdog-device.patch
new file mode 100644
index 0000000000..8542df4610
--- /dev/null
+++ b/target/linux/cns21xx/patches-3.6/202-cns21xx-add-watchdog-device.patch
@@ -0,0 +1,63 @@
+--- a/arch/arm/mach-cns21xx/common.h
++++ b/arch/arm/mach-cns21xx/common.h
+@@ -20,5 +20,6 @@ extern struct sys_timer cns21xx_timer;
+ int cns21xx_register_uart0(void);
+ int cns21xx_register_uart1(void);
+ int cns21xx_register_usb(void);
++int cns21xx_register_wdt(void);
+ 
+ #endif /* _MACH_CNS21XX_COMMON_H */
+--- a/arch/arm/mach-cns21xx/devices.c
++++ b/arch/arm/mach-cns21xx/devices.c
+@@ -11,6 +11,7 @@
+ #include <linux/init.h>
+ #include <linux/platform_device.h>
+ #include <linux/serial_8250.h>
++#include <linux/fa_wdt.h>
+ 
+ #include <mach/irqs.h>
+ #include <mach/hardware.h>
+@@ -77,3 +78,32 @@ int __init cns21xx_register_uart1(void)
+ 	HAL_MISC_ENABLE_UART1_PINS();
+ 	return platform_device_register(&cns21xx_uart1_device);
+ }
++
++static struct resource cns21xx_wdt_resources[] = {
++	{
++		.start	= CNS21XX_WDT_BASE,
++		.end	= CNS21XX_WDT_BASE + SZ_4K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++};
++
++#define CNS21XX_WDT_CLOCK	10	/* 10 Hz */
++
++static struct fa_wdt_platform_data cns21xx_wdt_data = {
++	.clock	= CNS21XX_WDT_CLOCK,
++};
++
++static struct platform_device cns21xx_wdt_device = {
++	.name			= "fa-wdt",
++	.id			= -1,
++	.resource 		= cns21xx_wdt_resources,
++	.num_resources		= ARRAY_SIZE(cns21xx_wdt_resources),
++	.dev = {
++		.platform_data	= &cns21xx_wdt_data,
++	},
++};
++
++int __init cns21xx_register_wdt(void)
++{
++	return platform_device_register(&cns21xx_wdt_device);
++}
+--- a/drivers/watchdog/Kconfig
++++ b/drivers/watchdog/Kconfig
+@@ -354,7 +354,7 @@ config IMX2_WDT
+ 
+ config FA_WATCHDOG
+ 	tristate "Faraday watchdog"
+-	depends on ARCH_GEMINI
++	depends on ARCH_GEMINI || ARCH_CNS21XX
+ 	help
+ 	  Say Y here if you want support for the built-in watchdog timer
+ 	  found in some Faraday FA526 based SoCs.
diff --git a/target/linux/cns21xx/patches-3.6/203-cns21xx-add-spi-master-device.patch b/target/linux/cns21xx/patches-3.6/203-cns21xx-add-spi-master-device.patch
new file mode 100644
index 0000000000..31d210b4fc
--- /dev/null
+++ b/target/linux/cns21xx/patches-3.6/203-cns21xx-add-spi-master-device.patch
@@ -0,0 +1,117 @@
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/dev-spi-master.c
+@@ -0,0 +1,83 @@
++/*
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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/init.h>
++#include <linux/spi/spi.h>
++#include <linux/dma-mapping.h>
++#include <linux/platform_device.h>
++
++#include <mach/hardware.h>
++#include <mach/cns21xx.h>
++#include <mach/cns21xx_misc.h>
++#include <mach/cns21xx_powermgmt.h>
++#include <mach/irqs.h>
++
++#include "common.h"
++
++static u64 spi_dmamask = DMA_BIT_MASK(32);
++static struct resource cns21xx_spi_resources[] = {
++	[0] = {
++		.start	= CNS21XX_SPI_BASE,
++		.end	= CNS21XX_SPI_BASE + SZ_4K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= CNS21XX_IRQ_SPI,
++		.end	= CNS21XX_IRQ_SPI,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device cns21xx_spi_master_device = {
++	.name		= "cns21xx-spi",
++	.id		= -1,
++	.dev		= {
++		.dma_mask		= &spi_dmamask,
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.resource	= cns21xx_spi_resources,
++	.num_resources	= ARRAY_SIZE(cns21xx_spi_resources),
++};
++
++void __init cns21xx_register_spi_master(int id, struct spi_board_info *info,
++					unsigned int n)
++{
++	unsigned int i;
++
++	/* Enable SPI pins */
++	HAL_MISC_ENABLE_SPIDR_PINS();
++	HAL_MISC_ENABLE_SPICLK_PINS();
++	for (i = 0; i < n; i++) {
++		switch (info[i].chip_select) {
++		case 0:
++			HAL_MISC_ENABLE_SPICSN0_PINS();
++			break;
++		case 1:
++			HAL_MISC_ENABLE_SPICSN1_PINS();
++			break;
++		case 2:
++			HAL_MISC_ENABLE_SPICSN2_PINS();
++			break;
++		case 3:
++			HAL_MISC_ENABLE_SPICSN3_PINS();
++			break;
++		}
++	}
++
++	/* Disable SPI serial flash access through 0x30000000 region */
++	HAL_MISC_DISABLE_SPI_SERIAL_FLASH_BANK_ACCESS();
++
++	/* Enable SPI clock */
++	HAL_PWRMGT_ENABLE_SPI_CLOCK();
++
++	cns21xx_spi_master_device.id = id;
++
++	spi_register_board_info(info, n);
++	platform_device_register(&cns21xx_spi_master_device);
++}
+--- a/arch/arm/mach-cns21xx/Kconfig
++++ b/arch/arm/mach-cns21xx/Kconfig
+@@ -6,4 +6,7 @@ endmenu
+ config CNS21XX_DEV_USB
+ 	def_bool n
+ 
++config CNS21XX_DEV_SPI_MASTER
++	def_bool n
++
+ endif
+--- a/arch/arm/mach-cns21xx/Makefile
++++ b/arch/arm/mach-cns21xx/Makefile
+@@ -8,6 +8,7 @@ obj-y		:= core.o devices.o gpio.o irq.o
+ 
+ # devices
+ obj-$(CONFIG_CNS21XX_DEV_USB)		+= dev-usb.o
++obj-$(CONFIG_CNS21XX_DEV_SPI_MASTER)	+= dev-spi-master.o
+ 
+ # machine specific files
+ 
+--- a/arch/arm/mach-cns21xx/common.h
++++ b/arch/arm/mach-cns21xx/common.h
+@@ -22,4 +22,8 @@ int cns21xx_register_uart1(void);
+ int cns21xx_register_usb(void);
+ int cns21xx_register_wdt(void);
+ 
++struct spi_board_info;
++void __init cns21xx_register_spi_master(int id, struct spi_board_info *info,
++					unsigned int n);
++
+ #endif /* _MACH_CNS21XX_COMMON_H */
diff --git a/target/linux/cns21xx/patches-3.6/204-cns21xx-add-gec-device.patch b/target/linux/cns21xx/patches-3.6/204-cns21xx-add-gec-device.patch
new file mode 100644
index 0000000000..910913bcc3
--- /dev/null
+++ b/target/linux/cns21xx/patches-3.6/204-cns21xx-add-gec-device.patch
@@ -0,0 +1,178 @@
+--- a/arch/arm/mach-cns21xx/Kconfig
++++ b/arch/arm/mach-cns21xx/Kconfig
+@@ -3,6 +3,9 @@ if ARCH_CNS21XX
+ menu "Cavium Networks CNS21xx based machines"
+ endmenu
+ 
++config CNS21XX_DEV_GEC
++	def_bool n
++
+ config CNS21XX_DEV_USB
+ 	def_bool n
+ 
+--- a/arch/arm/mach-cns21xx/Makefile
++++ b/arch/arm/mach-cns21xx/Makefile
+@@ -7,6 +7,7 @@
+ obj-y		:= core.o devices.o gpio.o irq.o mm.o time.o
+ 
+ # devices
++obj-$(CONFIG_CNS21XX_DEV_GEC)		+= dev-gec.o
+ obj-$(CONFIG_CNS21XX_DEV_USB)		+= dev-usb.o
+ obj-$(CONFIG_CNS21XX_DEV_SPI_MASTER)	+= dev-spi-master.o
+ 
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/dev-gec.c
+@@ -0,0 +1,98 @@
++/*
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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/init.h>
++#include <linux/dma-mapping.h>
++#include <linux/platform_device.h>
++#include <linux/etherdevice.h>
++
++#include <asm/sizes.h>
++#include <mach/cns21xx.h>
++#include <mach/irqs.h>
++
++#include "dev-gec.h"
++
++static u8 cns21xx_ethaddr[ETH_ALEN];
++struct cns21xx_gec_plat_data cns21xx_gec_data;
++
++static struct resource cns21xx_gec_resources[] = {
++	{
++		.start	= CNS21XX_NIC_BASE,
++		.end	= CNS21XX_NIC_BASE + SZ_4K - 1,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.name	= CNS21XX_GEC_STATUS_IRQ_NAME,
++		.start	= CNS21XX_IRQ_NIC_STATUS,
++		.end	= CNS21XX_IRQ_NIC_STATUS,
++		.flags	= IORESOURCE_IRQ,
++	}, {
++		.name	= CNS21XX_GEC_RXRC_IRQ_NAME,
++		.start	= CNS21XX_IRQ_NIC_RXRC,
++		.end	= CNS21XX_IRQ_NIC_RXRC,
++		.flags	= IORESOURCE_IRQ,
++	}, {
++		.name	= CNS21XX_GEC_RXQF_IRQ_NAME,
++		.start	= CNS21XX_IRQ_NIC_RXQF,
++		.end	= CNS21XX_IRQ_NIC_RXQF,
++		.flags	= IORESOURCE_IRQ,
++	}, {
++		.name	= CNS21XX_GEC_TXTC_IRQ_NAME,
++		.start	= CNS21XX_IRQ_NIC_TXTC,
++		.end	= CNS21XX_IRQ_NIC_TXTC,
++		.flags	= IORESOURCE_IRQ,
++	}, {
++		.name	= CNS21XX_GEC_TXQE_IRQ_NAME,
++		.start	= CNS21XX_IRQ_NIC_TXQE,
++		.end	= CNS21XX_IRQ_NIC_TXQE,
++		.flags	= IORESOURCE_IRQ,
++	}
++};
++
++static u64 cns21xx_gec_dmamask = DMA_BIT_MASK(32);
++static struct platform_device cns21xx_gec_device = {
++	.name			= "cns21xx-gec",
++	.id			= -1,
++	.resource		= cns21xx_gec_resources,
++	.num_resources		= ARRAY_SIZE(cns21xx_gec_resources),
++	.dev = {
++		.dma_mask		= &cns21xx_gec_dmamask,
++		.coherent_dma_mask 	= DMA_BIT_MASK(32),
++		.platform_data		= &cns21xx_gec_data,
++	},
++};
++
++static int __init cns21xx_ethaddr_setup(char *str)
++{
++	int t;
++
++	t = sscanf(str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
++		   &cns21xx_ethaddr[0], &cns21xx_ethaddr[1],
++		   &cns21xx_ethaddr[2], &cns21xx_ethaddr[3],
++		   &cns21xx_ethaddr[4], &cns21xx_ethaddr[5]);
++
++	if (t != ETH_ALEN)
++		pr_err("cns21xx: failed to parse mac address \"%s\"\n", str);
++
++	return 1;
++}
++
++__setup("ethaddr=", cns21xx_ethaddr_setup);
++
++__init int cns21xx_register_gec(void)
++{
++	if (cns21xx_gec_data.mac_addr == NULL)
++		cns21xx_gec_data.mac_addr = cns21xx_ethaddr;
++
++	if (!is_valid_ether_addr(cns21xx_gec_data.mac_addr)) {
++		random_ether_addr(cns21xx_gec_data.mac_addr);
++		pr_debug("cns21xx: using random MAC address \"%s\"\n",
++			cns21xx_gec_data.mac_addr);
++	}
++
++	return platform_device_register(&cns21xx_gec_device);
++}
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/dev-gec.h
+@@ -0,0 +1,18 @@
++/*
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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 _CNS21XX_DEV_GEC_H
++#define _CNS21XX_DEV_GEC_H
++
++#include <mach/cns21xx_gec_platform.h>
++
++extern struct cns21xx_gec_plat_data cns21xx_gec_data;
++
++__init int cns21xx_register_gec(void);
++
++#endif /* _CNS21XX_DEV_GEC_H */
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/include/mach/cns21xx_gec_platform.h
+@@ -0,0 +1,31 @@
++/*
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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 _CNS21XX_GEC_PLATFORM_H
++#define _CNS21XX_GEC_PLATFORM_H
++
++#define CNS21XX_GEC_STATUS_IRQ_NAME	"status"
++#define CNS21XX_GEC_RXRC_IRQ_NAME	"rxrc"
++#define CNS21XX_GEC_RXQF_IRQ_NAME	"rxqf"
++#define CNS21XX_GEC_TXTC_IRQ_NAME	"txtc"
++#define CNS21XX_GEC_TXQE_IRQ_NAME	"txqe"
++
++enum cns21xx_gec_phy_type {
++	CNS21XX_GEC_PHY_TYPE_INTERNAL = 0,
++	CNS21XX_GEC_PHY_TYPE_VSC8601,
++	CNS21XX_GEC_PHY_TYPE_IP101A,
++	CNS21XX_GEC_PHY_TYPE_IP1001,
++};
++
++struct cns21xx_gec_plat_data {
++	u8				*mac_addr;
++	enum cns21xx_gec_phy_type	phy_type;
++	u8				phy_addr;
++};
++
++#endif /* _CNS21XX_GEC_PLATFORM_H */
diff --git a/target/linux/cns21xx/patches-3.6/301-cns21xx-mach-ns-k330.patch b/target/linux/cns21xx/patches-3.6/301-cns21xx-mach-ns-k330.patch
new file mode 100644
index 0000000000..ca649cace3
--- /dev/null
+++ b/target/linux/cns21xx/patches-3.6/301-cns21xx-mach-ns-k330.patch
@@ -0,0 +1,234 @@
+--- a/arch/arm/mach-cns21xx/Kconfig
++++ b/arch/arm/mach-cns21xx/Kconfig
+@@ -1,6 +1,16 @@
+ if ARCH_CNS21XX
+ 
+ menu "Cavium Networks CNS21xx based machines"
++
++config MACH_NS_K330
++	bool "NS-K330 NAS"
++	select CNS21XX_DEV_GEC
++	select CNS21XX_DEV_SPI_MASTER
++	select CNS21XX_DEV_USB
++	help
++	  Say Y here if you intend to run this kernel on the
++	  NS-K330 NAS board.
++
+ endmenu
+ 
+ config CNS21XX_DEV_GEC
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/mach-ns-k330.c
+@@ -0,0 +1,204 @@
++/*
++ *  NS-K330 NAS board support
++ *
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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/init.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/flash.h>
++#include <linux/platform_device.h>
++#include <linux/gpio.h>
++#include <linux/leds.h>
++#include <linux/gpio_keys.h>
++#include <linux/input.h>
++
++#include <asm/setup.h>
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/time.h>
++#include <mach/hardware.h>
++#include <mach/cns21xx.h>
++#include <mach/cns21xx_misc.h>
++
++#include "common.h"
++#include "dev-gec.h"
++
++#define NS_K330_GPIO_LED_LINK		1
++#define NS_K330_GPIO_LED_USB1		16
++#define NS_K330_GPIO_LED_USB2		17
++#define NS_K330_GPIO_LED_ETH_GREEN	22
++#define NS_K330_GPIO_LED_ETH_ORANGE	23
++
++#define NS_K330_GPIO_BTN_RESET		13
++#define NS_K330_GPIO_BTN_USB1		14
++#define NS_K330_GPIO_BTN_USB2		15
++
++static struct mtd_partition ns_k330_partitions[] =  {
++	{
++		.name		= "boot",
++		.offset		= 0x0,
++		.size		= 0x040000,
++		.mask_flags	= MTD_WRITEABLE,
++	}, {
++		.name		= "config",
++		.offset		= 0x040000,
++		.size		= 0x020000,
++		.mask_flags	= MTD_WRITEABLE,
++	}, {
++		.name		= "kernel",
++		.offset		= 0x060000,
++		.size		= 0x100000,
++	}, {
++		.name		= "rootfs",
++		.offset		= 0x160000,
++		.size		= 0x290000,
++	}, {
++		.name		= "firmware",
++		.offset		= 0x060000,
++		.size		= 0x390000,
++	},
++};
++
++static struct flash_platform_data ns_k330_flash_data = {
++        .parts          = ns_k330_partitions,
++        .nr_parts       = ARRAY_SIZE(ns_k330_partitions),
++};
++
++static struct spi_board_info ns_k330_spi_board_info[] = {
++	{
++		.bus_num	= 0,
++		.chip_select	= 0,
++		.max_speed_hz	= 25000000,
++		.modalias	= "m25p80",
++		.platform_data	= &ns_k330_flash_data,
++	}
++};
++
++static struct gpio_led ns_k330_gpio_leds[] = {
++	{
++		.name		= "ns-k330:red:link",
++		.gpio		= NS_K330_GPIO_LED_LINK,
++		.active_low	= 1,
++	}, {
++		.name		= "ns-k330:green:usb1",
++		.gpio		= NS_K330_GPIO_LED_USB1,
++		.active_low	= 1,
++	}, {
++		.name		= "ns-k330:green:usb2",
++		.gpio		= NS_K330_GPIO_LED_USB2,
++		.active_low	= 1,
++	}, {
++		.name		= "ns-k330:green:eth",
++		.gpio		= NS_K330_GPIO_LED_ETH_GREEN,
++		.active_low	= 1,
++	}, {
++		.name		= "ns-k330:orange:eth",
++		.gpio		= NS_K330_GPIO_LED_ETH_ORANGE,
++		.active_low	= 1,
++	}
++};
++
++static struct gpio_led_platform_data ns_k330_gpio_leds_data = {
++	.num_leds		= ARRAY_SIZE(ns_k330_gpio_leds),
++	.leds			= ns_k330_gpio_leds,
++};
++
++static struct platform_device ns_k330_gpio_leds_device = {
++	.name			= "leds-gpio",
++	.id			= -1,
++	.dev.platform_data	= &ns_k330_gpio_leds_data,
++};
++
++static struct gpio_keys_button ns_k330_gpio_keys[] = {
++	{
++		.code		= KEY_RESTART,
++		.gpio		= NS_K330_GPIO_BTN_RESET,
++		.desc		= "Reset Button",
++		.active_low	= 1,
++	},
++	{
++		.code		= BTN_0,
++		.gpio		= NS_K330_GPIO_BTN_USB1,
++		.desc		= "USB1 Button",
++		.active_low	= 1,
++	},
++	{
++		.code		= BTN_1,
++		.gpio		= NS_K330_GPIO_BTN_USB2,
++		.desc		= "USB2 Button",
++		.active_low	= 0,
++	},
++};
++
++static struct gpio_keys_platform_data ns_k330_gpio_keys_data = {
++	.buttons	= ns_k330_gpio_keys,
++	.nbuttons	= ARRAY_SIZE(ns_k330_gpio_keys),
++};
++
++static struct platform_device ns_k330_gpio_keys_device = {
++	.name		= "gpio-keys",
++	.id		= -1,
++	.num_resources	= 0,
++	.dev		= {
++		.platform_data	= &ns_k330_gpio_keys_data,
++	},
++};
++
++static void __init ns_k330_fixup(struct tag *tags, char **cmdline,
++				 struct meminfo *mi)
++{
++	struct tag *t;
++
++	/* The board has 32MB of RAM mapped at 0. */
++	mi->nr_banks = 1;
++	mi->bank[0].start = 0;
++	mi->bank[0].size = SZ_32M;
++
++	for (t = tags; t->hdr.size; t = tag_next(t)) {
++		switch (t->hdr.tag) {
++		case ATAG_CORE:
++			if (t->u.core.rootdev == 255)
++				t->u.core.rootdev = 0;
++			break;
++		}
++	}
++}
++
++static void __init ns_k330_init(void)
++{
++	cns21xx_gpio_init();
++
++	HAL_MISC_DISABLE_LED012_PINS();
++	HAL_MISC_DISABLE_I2C_PINS();
++	HAL_MISC_DISABLE_I2S_PINS();
++
++	cns21xx_register_uart0();
++	cns21xx_register_wdt();
++	cns21xx_register_usb();
++	cns21xx_register_spi_master(-1, ns_k330_spi_board_info,
++				    ARRAY_SIZE(ns_k330_spi_board_info));
++
++	cns21xx_gec_data.phy_type = CNS21XX_GEC_PHY_TYPE_INTERNAL;
++	cns21xx_register_gec();
++
++	platform_device_register(&ns_k330_gpio_leds_device);
++	platform_device_register(&ns_k330_gpio_keys_device);
++}
++
++MACHINE_START(NS_K330, "NS-K330 NAS")
++	.fixup		= ns_k330_fixup,
++	.map_io		= cns21xx_map_io,
++	.init_irq	= cns21xx_init_irq,
++	.timer		= &cns21xx_timer,
++	.init_machine	= ns_k330_init,
++	.restart	= cns21xx_restart,
++MACHINE_END
+--- a/arch/arm/mach-cns21xx/Makefile
++++ b/arch/arm/mach-cns21xx/Makefile
+@@ -12,4 +12,4 @@ obj-$(CONFIG_CNS21XX_DEV_USB)		+= dev-us
+ obj-$(CONFIG_CNS21XX_DEV_SPI_MASTER)	+= dev-spi-master.o
+ 
+ # machine specific files
+-
++obj-$(CONFIG_MACH_NS_K330)		+= mach-ns-k330.o
diff --git a/target/linux/cns21xx/patches-3.6/302-cns21xx-mach-nsb3ast.patch b/target/linux/cns21xx/patches-3.6/302-cns21xx-mach-nsb3ast.patch
new file mode 100644
index 0000000000..503df1107d
--- /dev/null
+++ b/target/linux/cns21xx/patches-3.6/302-cns21xx-mach-nsb3ast.patch
@@ -0,0 +1,201 @@
+--- a/arch/arm/mach-cns21xx/Kconfig
++++ b/arch/arm/mach-cns21xx/Kconfig
+@@ -2,6 +2,15 @@ if ARCH_CNS21XX
+ 
+ menu "Cavium Networks CNS21xx based machines"
+ 
++config MACH_NSB3AST
++	bool "AGESTAR NSB3AST support"
++	select CNS21XX_DEV_GEC
++	select CNS21XX_DEV_SPI_MASTER
++	select CNS21XX_DEV_USB
++	help
++	  Say Y here if you intend to run this kernel on the
++	  AGESTAR NSB3AST board.
++
+ config MACH_NS_K330
+ 	bool "NS-K330 NAS"
+ 	select CNS21XX_DEV_GEC
+--- /dev/null
++++ b/arch/arm/mach-cns21xx/mach-nsb3ast.c
+@@ -0,0 +1,173 @@
++/*
++ *  AGESTAR NSB3AST board support
++ *
++ *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file 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/init.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/flash.h>
++#include <linux/platform_device.h>
++#include <linux/gpio.h>
++#include <linux/leds.h>
++#include <linux/gpio_keys.h>
++#include <linux/input.h>
++
++#include <asm/setup.h>
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/time.h>
++#include <mach/hardware.h>
++#include <mach/cns21xx.h>
++#include <mach/cns21xx_misc.h>
++
++#include "common.h"
++#include "dev-gec.h"
++
++static struct mtd_partition nsb3ast_partitions[] =  {
++	{
++		.name		= "armboot",
++		.offset		= 0x0,
++		.size		= 0x040000,
++		.mask_flags	= MTD_WRITEABLE,
++	}, {
++		.name		= "kernel",
++		.offset		= 0x040000,
++		.size		= 0x100000,
++	}, {
++		.name		= "rootfs",
++		.offset		= 0x140000,
++		.size		= 0x6c0000,
++	}, {
++		.name		= "firmware",
++		.offset		= 0x040000,
++		.size		= 0x7c0000,
++	}, {
++		.name		= "wholeflash",
++		.offset		= 0x0,
++		.size		= 0x800000,
++		.mask_flags	= MTD_WRITEABLE,
++	},
++};
++
++static struct flash_platform_data nsb3ast_flash_data = {
++        .parts          = nsb3ast_partitions,
++        .nr_parts       = ARRAY_SIZE(nsb3ast_partitions),
++};
++
++static struct spi_board_info nsb3ast_spi_board_info[] = {
++	{
++		.bus_num	= 0,
++		.chip_select	= 0,
++		.max_speed_hz	= 25000000,
++		.modalias	= "m25p80",
++		.platform_data	= &nsb3ast_flash_data,
++	}
++};
++
++static struct gpio_led nsb3ast_gpio_leds[] = {
++	{
++		.name		= "nsb3ast:red:d1",
++		.gpio		= 15,
++		.active_low	= 1,
++	}, {
++		.name		= "nsb3ast:amber:eth",
++		.gpio		= 22,
++		.active_low	= 1,
++	}
++};
++
++static struct gpio_led_platform_data nsb3ast_gpio_leds_data = {
++	.num_leds		= ARRAY_SIZE(nsb3ast_gpio_leds),
++	.leds			= nsb3ast_gpio_leds,
++};
++
++static struct platform_device nsb3ast_gpio_leds_device = {
++	.name			= "leds-gpio",
++	.id			= -1,
++	.dev.platform_data	= &nsb3ast_gpio_leds_data,
++};
++
++static struct gpio_keys_button nsb3ast_gpio_keys[] = {
++	{
++		.code		= KEY_RESTART,
++		.gpio		= 0,
++		.desc		= "Reset Button",
++		.active_low	= 1,
++	},
++	{
++		.code		= BTN_0,
++		.gpio		= 2,
++		.desc		= "USB Button",
++		.active_low	= 0,
++	},
++};
++
++static struct gpio_keys_platform_data nsb3ast_gpio_keys_data = {
++	.buttons	= nsb3ast_gpio_keys,
++	.nbuttons	= ARRAY_SIZE(nsb3ast_gpio_keys),
++};
++
++static struct platform_device nsb3ast_gpio_keys_device = {
++	.name		= "gpio-keys",
++	.id		= -1,
++	.num_resources	= 0,
++	.dev		= {
++		.platform_data	= &nsb3ast_gpio_keys_data,
++	},
++};
++
++static void __init nsb3ast_fixup(struct tag *tags, char **cmdline,
++			  	 struct meminfo *mi)
++{
++	struct tag *t;
++
++	/* The board has 32MB of RAM mapped at 0. */
++	mi->nr_banks = 1;
++	mi->bank[0].start = 0;
++	mi->bank[0].size = SZ_32M;
++
++	for (t = tags; t->hdr.size; t = tag_next(t)) {
++		switch (t->hdr.tag) {
++		case ATAG_CORE:
++			if (t->u.core.rootdev == 255)
++				t->u.core.rootdev = 0;
++			break;
++		}
++	}
++}
++
++static void __init nsb3ast_init(void)
++{
++	cns21xx_gpio_init();
++	cns21xx_register_uart0();
++	cns21xx_register_uart1();
++	cns21xx_register_wdt();
++	cns21xx_register_usb();
++	cns21xx_register_spi_master(-1, nsb3ast_spi_board_info,
++				    ARRAY_SIZE(nsb3ast_spi_board_info));
++
++	cns21xx_gec_data.phy_type = CNS21XX_GEC_PHY_TYPE_INTERNAL;
++	cns21xx_register_gec();
++
++	HAL_MISC_DISABLE_LED012_PINS();
++	platform_device_register(&nsb3ast_gpio_leds_device);
++	platform_device_register(&nsb3ast_gpio_keys_device);
++}
++
++MACHINE_START(NSB3AST, "AGESTAR NSB3AST")
++	.fixup		= nsb3ast_fixup,
++	.map_io		= cns21xx_map_io,
++	.init_irq	= cns21xx_init_irq,
++	.timer		= &cns21xx_timer,
++	.init_machine	= nsb3ast_init,
++	.restart	= cns21xx_restart,
++MACHINE_END
+--- a/arch/arm/mach-cns21xx/Makefile
++++ b/arch/arm/mach-cns21xx/Makefile
+@@ -13,3 +13,4 @@ obj-$(CONFIG_CNS21XX_DEV_SPI_MASTER)	+=
+ 
+ # machine specific files
+ obj-$(CONFIG_MACH_NS_K330)		+= mach-ns-k330.o
++obj-$(CONFIG_MACH_NSB3AST)		+= mach-nsb3ast.o
-- 
cgit v1.2.3