Browse Source

activate and refresh support for rb411/rb433

after n0-1 helped to find a way to fix my broken rb433
by using the primary bootloader via shortening a jumper
I got the motivation to get this target working again.
Summarize both targets to newly created rb4xx target.
Waldemar Brodkorb 15 years ago
parent
commit
896b6bb853

+ 1 - 6
TODO

@@ -1,9 +1,4 @@
-- php update
-- openssh update
+- add support for brcm 2.6
 - macos x build
 - macos x build
-- test on OpenSuSE
-- test on Fedora Core
 - help text for config/ needs adoption
 - help text for config/ needs adoption
 - fix watchdog for alix1c (mfgpt timers problem)
 - fix watchdog for alix1c (mfgpt timers problem)
-- implement rpm package backend 
-- implement dpkg package backend 

+ 6 - 1
mk/rootfs.mk

@@ -10,6 +10,11 @@ endef
 
 
 ifeq ($(ADK_LINUX_MIPS_RB532),y)
 ifeq ($(ADK_LINUX_MIPS_RB532),y)
 ROOTFS:=	root=/dev/sda2
 ROOTFS:=	root=/dev/sda2
+MTDDEV:=	root=/dev/mtdblock1
+endif
+
+ifeq ($(ADK_LINUX_MIPS_RB433),y)
+MTDDEV:=	root=/dev/mtdblock2
 endif
 endif
 
 
 ifeq ($(ADK_LINUX_ARM_FOXBOARD),y)
 ifeq ($(ADK_LINUX_ARM_FOXBOARD),y)
@@ -22,7 +27,7 @@ $(eval $(call rootfs_template,archive,ARCHIVE))
 $(eval $(call rootfs_template,initramfs,INITRAMFS))
 $(eval $(call rootfs_template,initramfs,INITRAMFS))
 $(eval $(call rootfs_template,initramfs-piggyback,INITRAMFS_PIGGYBACK))
 $(eval $(call rootfs_template,initramfs-piggyback,INITRAMFS_PIGGYBACK))
 $(eval $(call rootfs_template,squashfs,SQUASHFS))
 $(eval $(call rootfs_template,squashfs,SQUASHFS))
-$(eval $(call rootfs_template,yaffs,YAFFS,root=/dev/mtdblock1 panic=3))
+$(eval $(call rootfs_template,yaffs,YAFFS,$(MTDDEV) panic=3))
 $(eval $(call rootfs_template,nfsroot,NFSROOT,root=/dev/nfs ip=dhcp init=/init))
 $(eval $(call rootfs_template,nfsroot,NFSROOT,root=/dev/nfs ip=dhcp init=/init))
 $(eval $(call rootfs_template,encrypted,ENCRYPTED))
 $(eval $(call rootfs_template,encrypted,ENCRYPTED))
 
 

+ 7 - 1
package/adkinstall/Makefile

@@ -10,7 +10,7 @@ PKG_DESCR:=		installer for cf, mmc, sd or mtd devices
 PKG_SECTION:=		base
 PKG_SECTION:=		base
 PKG_DEPENDS:=		parted sfdisk e2fsprogs
 PKG_DEPENDS:=		parted sfdisk e2fsprogs
 
 
-PKG_TARGET_DEPENDS:=	alix wrap rb532 foxg20
+PKG_TARGET_DEPENDS:=	alix wrap rb532 foxg20 rb411 rb433
 
 
 WRKDIST=		${WRKDIR}/${PKG_NAME}-${PKG_VERSION}
 WRKDIST=		${WRKDIR}/${PKG_NAME}-${PKG_VERSION}
 NO_DISTFILES:=		1
 NO_DISTFILES:=		1
@@ -34,6 +34,12 @@ ifeq ($(ADK_LINUX_MIPS_RB532),y)
 else ifeq ($(ADK_LINUX_ARM_FOXBOARD),y)
 else ifeq ($(ADK_LINUX_ARM_FOXBOARD),y)
 	${INSTALL_BIN} ./src/adkinstall.foxg20 \
 	${INSTALL_BIN} ./src/adkinstall.foxg20 \
 		$(IDIR_ADKINSTALL)/sbin/adkinstall
 		$(IDIR_ADKINSTALL)/sbin/adkinstall
+else ifeq ($(ADK_LINUX_MIPS_RB433),y)
+	${INSTALL_BIN} ./src/adkinstall.rb4xx \
+		$(IDIR_ADKINSTALL)/sbin/adkinstall
+else ifeq ($(ADK_LINUX_MIPS_RB411),y)
+	${INSTALL_BIN} ./src/adkinstall.rb4xx \
+		$(IDIR_ADKINSTALL)/sbin/adkinstall
 else
 else
 	${INSTALL_BIN} ./src/adkinstall $(IDIR_ADKINSTALL)/sbin
 	${INSTALL_BIN} ./src/adkinstall $(IDIR_ADKINSTALL)/sbin
 endif
 endif

+ 4 - 0
package/base-files/src/sbin/adkupdate

@@ -34,6 +34,8 @@ prepare() {
 	mount -o remount,rw /
 	mount -o remount,rw /
 	if [ "$system" == "RB532" ];then
 	if [ "$system" == "RB532" ];then
 		mount -t yaffs2 /dev/mtdblock0 /boot
 		mount -t yaffs2 /dev/mtdblock0 /boot
+	elif [ "$system" == "AR7130" ];then
+		mount -t yaffs2 /dev/mtdblock1 /boot
 	elif [ "$system" == "FOXG20" ];then
 	elif [ "$system" == "FOXG20" ];then
 		mount -t vfat /dev/mmcblk0p1 /boot
 		mount -t vfat /dev/mmcblk0p1 /boot
 	fi
 	fi
@@ -89,6 +91,8 @@ if [ -x /sbin/cfgfs ];then
 fi
 fi
 if [ "$system" == "RB532" ];then
 if [ "$system" == "RB532" ];then
 	umount -f /boot
 	umount -f /boot
+elif [ "$system" == "AR7130" ];then
+	umount -f /boot
 elif [ "$system" == "FOXG20" ];then
 elif [ "$system" == "FOXG20" ];then
 	umount -f /boot
 	umount -f /boot
 fi
 fi

+ 1 - 1
package/cfgfs/Makefile

@@ -9,7 +9,7 @@ PKG_RELEASE:=		2
 PKG_DESCR:=		compressed config filesystem
 PKG_DESCR:=		compressed config filesystem
 PKG_SECTION:=		base
 PKG_SECTION:=		base
 
 
-PKG_TARGET_DEPENDS:=	alix wrap foxboard ag241 rb532 foxg20
+PKG_TARGET_DEPENDS:=	alix wrap foxboard ag241 rb532 foxg20 rb411 rb433
 
 
 WRKDIST=		${WRKDIR}/${PKG_NAME}-${PKG_VERSION}
 WRKDIST=		${WRKDIR}/${PKG_NAME}-${PKG_VERSION}
 NO_DISTFILES:=		1
 NO_DISTFILES:=		1

+ 1 - 1
package/nand/Makefile

@@ -9,7 +9,7 @@ PKG_RELEASE:=		3
 PKG_DESCR:=		NAND utility
 PKG_DESCR:=		NAND utility
 PKG_SECTION:=		base
 PKG_SECTION:=		base
 
 
-PKG_TARGET_DEPENDS:=	rb532
+PKG_TARGET_DEPENDS:=	rb532 rb411 rb433
 
 
 NO_DISTFILES:=		1
 NO_DISTFILES:=		1
 
 

+ 20 - 31
target/Config.in

@@ -116,10 +116,7 @@ config ADK_x86_64_qemu
 config ADK_rb532
 config ADK_rb532
 	tristate
 	tristate
 
 
-config ADK_rb411
-	tristate
-
-config ADK_rb433
+config ADK_rb4xx
 	tristate
 	tristate
 
 
 config ADK_zaurus
 config ADK_zaurus
@@ -182,8 +179,7 @@ config ADK_TARGET
 	default "foxg20"  if ADK_foxg20
 	default "foxg20"  if ADK_foxg20
 	default "native"  if ADK_NATIVE
 	default "native"  if ADK_NATIVE
 	default "rb532"  if ADK_rb532
 	default "rb532"  if ADK_rb532
-	default "rb411"  if ADK_rb411
-	default "rb433"  if ADK_rb433
+	default "rb4xx"  if ADK_rb4xx
 	default "zaurus"  if ADK_arm
 	default "zaurus"  if ADK_arm
 	default "lemote"  if ADK_lemote
 	default "lemote"  if ADK_lemote
 	default "ibmx40"  if ADK_ibmx40
 	default "ibmx40"  if ADK_ibmx40
@@ -696,35 +692,30 @@ prompt "Routerboard model"
 default ADK_LINUX_MIPS_RB532
 default ADK_LINUX_MIPS_RB532
 depends on ADK_LINUX_MIKROTIK
 depends on ADK_LINUX_MIKROTIK
 
 
-config ADK_LINUX_MIPS_RB411
-	bool "Mikrotik Routerboard 411"
-	select ADK_rb411
-	select ADK_KERNEL_NETDEVICES
-	select ADK_KERNEL_NET_PCI
-	select ADK_KERNEL_NETDEV_1000
-	select ADK_KERNEL_NET_ETHERNET
-	select ADK_TARGET_WITH_MINIPCI
-	depends on ADK_BROKEN
-	help
-	 Support for Mikrotik RB411.
-	 Status: development
-
-config ADK_LINUX_MIPS_RB433
-	bool "Mikrotik Routerboard 433"
-	select ADK_rb433
+config ADK_LINUX_MIPS_RB4XX
+	bool "Mikrotik Routerboard 411/433"
+	select ADK_rb4xx
+	select ADK_KERNEL_MISC_FILESYSTEMS
+	select ADK_KERNEL_YAFFS_FS
+	select ADK_KERNEL_YAFFS_YAFFS2
+	select ADK_KERNEL_YAFFS_AUTO_YAFFS2
 	select ADK_KERNEL_NETDEVICES
 	select ADK_KERNEL_NETDEVICES
 	select ADK_KERNEL_NET_PCI
 	select ADK_KERNEL_NET_PCI
 	select ADK_KERNEL_NETDEV_1000
 	select ADK_KERNEL_NETDEV_1000
 	select ADK_KERNEL_NET_ETHERNET
 	select ADK_KERNEL_NET_ETHERNET
 	select ADK_TARGET_WITH_MINIPCI
 	select ADK_TARGET_WITH_MINIPCI
-	depends on ADK_BROKEN
+	select ADK_TARGET_WITH_WATCHDOG
 	help
 	help
-	 Support for Mikrotik RB433.
-	 Status: development
+	 Support for Mikrotik RB411/RB433.
+	 Status: stable
 
 
 config ADK_LINUX_MIPS_RB532
 config ADK_LINUX_MIPS_RB532
 	bool "Mikrotik Routerboard 532"
 	bool "Mikrotik Routerboard 532"
 	select ADK_rb532
 	select ADK_rb532
+	select ADK_KERNEL_MISC_FILESYSTEMS
+	select ADK_KERNEL_YAFFS_FS
+	select ADK_KERNEL_YAFFS_YAFFS2
+	select ADK_KERNEL_YAFFS_AUTO_YAFFS2
 	select ADK_KERNEL_NETDEVICES
 	select ADK_KERNEL_NETDEVICES
 	select ADK_KERNEL_NET_PCI
 	select ADK_KERNEL_NET_PCI
 	select ADK_KERNEL_NET_ETHERNET
 	select ADK_KERNEL_NET_ETHERNET
@@ -782,8 +773,7 @@ config ADK_TARGET_LIB_EGLIBC
 		ADK_LINUX_X86_ALIX2D || \
 		ADK_LINUX_X86_ALIX2D || \
 		ADK_LINUX_X86_ALIX2D13 || \
 		ADK_LINUX_X86_ALIX2D13 || \
 		ADK_LINUX_X86_WRAP || \
 		ADK_LINUX_X86_WRAP || \
-		ADK_LINUX_MIPS_RB411 || \
-		ADK_LINUX_MIPS_RB433 || \
+		ADK_LINUX_MIPS_RB4XX || \
 		ADK_LINUX_MIPS_RB532 || \
 		ADK_LINUX_MIPS_RB532 || \
 		ADK_LINUX_X86_64_SHUTTLE || \
 		ADK_LINUX_X86_64_SHUTTLE || \
 		ADK_LINUX_MIPS64_LEMOTE || \
 		ADK_LINUX_MIPS64_LEMOTE || \
@@ -802,6 +792,7 @@ config ADK_TARGET_LIB_GLIBC
 		ADK_LINUX_X86_ALIX2D13 || \
 		ADK_LINUX_X86_ALIX2D13 || \
 		ADK_LINUX_X86_WRAP || \
 		ADK_LINUX_X86_WRAP || \
 		ADK_LINUX_MIPS_RB532 || \
 		ADK_LINUX_MIPS_RB532 || \
+		ADK_LINUX_MIPS_RB4XX || \
 		ADK_LINUX_X86_64_SHUTTLE || \
 		ADK_LINUX_X86_64_SHUTTLE || \
 		ADK_LINUX_RESCUE || \
 		ADK_LINUX_RESCUE || \
 		ADK_LINUX_MIPS64_LEMOTE || \
 		ADK_LINUX_MIPS64_LEMOTE || \
@@ -865,8 +856,7 @@ config ADK_TARGET_ROOTFS_YAFFS
 	select ADK_KERNEL_YAFFS_YAFFS2
 	select ADK_KERNEL_YAFFS_YAFFS2
 	depends on \
 	depends on \
 		ADK_LINUX_MIPS_RB532 || \
 		ADK_LINUX_MIPS_RB532 || \
-		ADK_LINUX_MIPS_RB433 || \
-		ADK_LINUX_MIPS_RB411
+		ADK_LINUX_MIPS_RB4XX
 	help
 	help
 	  Root filesystem on NAND.
 	  Root filesystem on NAND.
 
 
@@ -880,8 +870,7 @@ config ADK_TARGET_ROOTFS_NFSROOT
 		ADK_LINUX_X86_ALIX2D13 || \
 		ADK_LINUX_X86_ALIX2D13 || \
 		ADK_LINUX_X86_WRAP || \
 		ADK_LINUX_X86_WRAP || \
 		ADK_LINUX_MIPS_RB532 || \
 		ADK_LINUX_MIPS_RB532 || \
-		ADK_LINUX_MIPS_RB433 || \
-		ADK_LINUX_MIPS_RB411 || \
+		ADK_LINUX_MIPS_RB4XX || \
 		ADK_LINUX_MIPS_WAG54G || \
 		ADK_LINUX_MIPS_WAG54G || \
 		ADK_LINUX_MIPS_AG241 || \
 		ADK_LINUX_MIPS_AG241 || \
 		ADK_LINUX_MIPS64_LEMOTE
 		ADK_LINUX_MIPS64_LEMOTE

+ 7 - 6
target/bulk.lst

@@ -1,18 +1,15 @@
 ag241		uclibc		nfsroot
 ag241		uclibc		nfsroot
 foxboard	uclibc		nfsroot
 foxboard	uclibc		nfsroot
 foxg20		uclibc		nfsroot
 foxg20		uclibc		nfsroot
+rb4xx		uclibc		nfsroot
+rb4xx		eglibc		nfsroot
+rb4xx		glibc		nfsroot
 rb532		uclibc		nfsroot
 rb532		uclibc		nfsroot
 rb532		eglibc		nfsroot
 rb532		eglibc		nfsroot
 rb532		glibc		nfsroot
 rb532		glibc		nfsroot
 alix1c		uclibc		nfsroot
 alix1c		uclibc		nfsroot
 alix1c		eglibc		nfsroot
 alix1c		eglibc		nfsroot
 alix1c		glibc		nfsroot
 alix1c		glibc		nfsroot
-alix2d		uclibc		nfsroot
-alix2d		eglibc		nfsroot
-alix2d		glibc		nfsroot
-alix2d13	uclibc		nfsroot
-alix2d13	eglibc		nfsroot
-alix2d13	glibc		nfsroot
 wrap		uclibc		nfsroot
 wrap		uclibc		nfsroot
 wrap		eglibc		nfsroot
 wrap		eglibc		nfsroot
 wrap		glibc		nfsroot
 wrap		glibc		nfsroot
@@ -32,3 +29,7 @@ x86_64_qemu	uclibc		archive
 x86_64_qemu	eglibc		archive
 x86_64_qemu	eglibc		archive
 x86_64_qemu	glibc		archive
 x86_64_qemu	glibc		archive
 lemote		eglibc		archive
 lemote		eglibc		archive
+lemote		glibc		archive
+ibmx40		uclibc		archive
+ibmx40		eglibc		archive
+ibmx40		glibc		archive

+ 0 - 1075
target/linux/patches/2.6.33.3/swconfig.patch

@@ -1,1075 +0,0 @@
-diff -Nur linux-2.6.30.orig/drivers/net/phy/Kconfig linux-2.6.30/drivers/net/phy/Kconfig
---- linux-2.6.30.orig/drivers/net/phy/Kconfig	2009-06-10 05:05:27.000000000 +0200
-+++ linux-2.6.30/drivers/net/phy/Kconfig	2009-06-11 09:22:50.000000000 +0200
-@@ -13,6 +13,12 @@
- 
- if PHYLIB
- 
-+config SWCONFIG
-+	tristate "Switch configuration API"
-+	---help---
-+	  Switch configuration API using netlink. This allows
-+	  you to configure the VLAN features of certain switches.
-+
- comment "MII PHY device drivers"
- 
- config MARVELL_PHY
-diff -Nur linux-2.6.30.orig/drivers/net/phy/Makefile linux-2.6.30/drivers/net/phy/Makefile
---- linux-2.6.30.orig/drivers/net/phy/Makefile	2009-06-10 05:05:27.000000000 +0200
-+++ linux-2.6.30/drivers/net/phy/Makefile	2009-06-11 09:22:50.000000000 +0200
-@@ -3,6 +3,7 @@
- libphy-objs			:= phy.o phy_device.o mdio_bus.o
- 
- obj-$(CONFIG_PHYLIB)		+= libphy.o
-+obj-$(CONFIG_SWCONFIG)		+= swconfig.o
- obj-$(CONFIG_MARVELL_PHY)	+= marvell.o
- obj-$(CONFIG_DAVICOM_PHY)	+= davicom.o
- obj-$(CONFIG_CICADA_PHY)	+= cicada.o
-diff -Nur linux-2.6.30.orig/drivers/net/phy/swconfig.c linux-2.6.30/drivers/net/phy/swconfig.c
---- linux-2.6.30.orig/drivers/net/phy/swconfig.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.30/drivers/net/phy/swconfig.c	2009-06-11 09:22:50.000000000 +0200
-@@ -0,0 +1,872 @@
-+/*
-+ * swconfig.c: Switch configuration API
-+ *
-+ * Copyright (C) 2008 Felix Fietkau <nbd@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.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#include <linux/types.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/list.h>
-+#include <linux/if.h>
-+#include <linux/if_ether.h>
-+#include <linux/capability.h>
-+#include <linux/skbuff.h>
-+#include <linux/switch.h>
-+
-+//#define DEBUG 1
-+#ifdef DEBUG
-+#define DPRINTF(format, ...) printk("%s: " format, __func__, ##__VA_ARGS__)
-+#else
-+#define DPRINTF(...) do {} while(0)
-+#endif
-+
-+MODULE_AUTHOR("Felix Fietkau <nbd@openwrt.org>");
-+MODULE_LICENSE("GPL");
-+
-+static int swdev_id = 0;
-+static struct list_head swdevs;
-+static spinlock_t swdevs_lock = SPIN_LOCK_UNLOCKED;
-+struct swconfig_callback;
-+
-+struct swconfig_callback
-+{
-+	struct sk_buff *msg;
-+	struct genlmsghdr *hdr;
-+	struct genl_info *info;
-+	int cmd;
-+
-+	/* callback for filling in the message data */
-+	int (*fill)(struct swconfig_callback *cb, void *arg);
-+
-+	/* callback for closing the message before sending it */
-+	int (*close)(struct swconfig_callback *cb, void *arg);
-+
-+	struct nlattr *nest[4];
-+	int args[4];
-+};
-+
-+/* defaults */
-+
-+static int
-+swconfig_get_vlan_ports(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val)
-+{
-+	int ret;
-+	if (val->port_vlan >= dev->vlans)
-+		return -EINVAL;
-+
-+	if (!dev->get_vlan_ports)
-+		return -EOPNOTSUPP;
-+
-+	ret = dev->get_vlan_ports(dev, val);
-+	printk("SET PORTS %d\n", val->len);
-+	return ret;
-+}
-+
-+static int
-+swconfig_set_vlan_ports(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val)
-+{
-+	int i;
-+
-+	if (val->port_vlan >= dev->vlans)
-+		return -EINVAL;
-+
-+	/* validate ports */
-+	if (val->len > dev->ports)
-+		return -EINVAL;
-+
-+	for (i = 0; i < val->len; i++) {
-+		if (val->value.ports[i].id >= dev->ports)
-+			return -EINVAL;
-+	}
-+
-+	if (!dev->set_vlan_ports)
-+		return -EOPNOTSUPP;
-+
-+	printk("SET PORTS %d\n", val->len);
-+	return dev->set_vlan_ports(dev, val);
-+}
-+
-+static int
-+swconfig_apply_config(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val)
-+{
-+	/* don't complain if not supported by the switch driver */
-+	if (!dev->apply_config)
-+		return 0;
-+
-+	return dev->apply_config(dev);
-+}
-+
-+
-+enum global_defaults {
-+	GLOBAL_APPLY,
-+};
-+
-+enum vlan_defaults {
-+	VLAN_PORTS,
-+};
-+
-+enum port_defaults {
-+	PORT_LINK,
-+};
-+
-+static struct switch_attr default_global[] = {
-+	[GLOBAL_APPLY] = {
-+		.type = SWITCH_TYPE_NOVAL,
-+		.name = "apply",
-+		.description = "Activate changes in the hardware",
-+		.set = swconfig_apply_config,
-+	}
-+};
-+
-+static struct switch_attr default_port[] = {
-+	[PORT_LINK] = {
-+		.type = SWITCH_TYPE_INT,
-+		.name = "link",
-+		.description = "Current link speed",
-+	}
-+};
-+
-+static struct switch_attr default_vlan[] = {
-+	[VLAN_PORTS] = {
-+		.type = SWITCH_TYPE_PORTS,
-+		.name = "ports",
-+		.description = "VLAN port mapping",
-+		.set = swconfig_set_vlan_ports,
-+		.get = swconfig_get_vlan_ports,
-+	},
-+};
-+
-+
-+static void swconfig_defaults_init(struct switch_dev *dev)
-+{
-+	dev->def_global = 0;
-+	dev->def_vlan = 0;
-+	dev->def_port = 0;
-+
-+	if (dev->get_vlan_ports || dev->set_vlan_ports)
-+		set_bit(VLAN_PORTS, &dev->def_vlan);
-+
-+	/* always present, can be no-op */
-+	set_bit(GLOBAL_APPLY, &dev->def_global);
-+}
-+
-+
-+static struct genl_family switch_fam = {
-+	.id = GENL_ID_GENERATE,
-+	.name = "switch",
-+	.hdrsize = 0,
-+	.version = 1,
-+	.maxattr = SWITCH_ATTR_MAX,
-+};
-+
-+static const struct nla_policy switch_policy[SWITCH_ATTR_MAX+1] = {
-+	[SWITCH_ATTR_ID] = { .type = NLA_U32 },
-+	[SWITCH_ATTR_OP_ID] = { .type = NLA_U32 },
-+	[SWITCH_ATTR_OP_PORT] = { .type = NLA_U32 },
-+	[SWITCH_ATTR_OP_VLAN] = { .type = NLA_U32 },
-+	[SWITCH_ATTR_OP_VALUE_INT] = { .type = NLA_U32 },
-+	[SWITCH_ATTR_OP_VALUE_STR] = { .type = NLA_NUL_STRING },
-+	[SWITCH_ATTR_OP_VALUE_PORTS] = { .type = NLA_NESTED },
-+	[SWITCH_ATTR_TYPE] = { .type = NLA_U32 },
-+};
-+
-+static const struct nla_policy port_policy[SWITCH_PORT_ATTR_MAX+1] = {
-+	[SWITCH_PORT_ID] = { .type = NLA_U32 },
-+	[SWITCH_PORT_FLAG_TAGGED] = { .type = NLA_FLAG },
-+};
-+
-+static inline void
-+swconfig_lock(void)
-+{
-+	spin_lock(&swdevs_lock);
-+}
-+
-+static inline void
-+swconfig_unlock(void)
-+{
-+	spin_unlock(&swdevs_lock);
-+}
-+
-+static struct switch_dev *
-+swconfig_get_dev(struct genl_info *info)
-+{
-+	struct switch_dev *dev = NULL;
-+	struct switch_dev *p;
-+	int id;
-+
-+	if (!info->attrs[SWITCH_ATTR_ID])
-+		goto done;
-+
-+	id = nla_get_u32(info->attrs[SWITCH_ATTR_ID]);
-+	swconfig_lock();
-+	list_for_each_entry(p, &swdevs, dev_list) {
-+		if (id != p->id)
-+			continue;
-+
-+		dev = p;
-+		break;
-+	}
-+	if (dev)
-+		spin_lock(&dev->lock);
-+	else
-+		DPRINTF("device %d not found\n", id);
-+	swconfig_unlock();
-+done:
-+	return dev;
-+}
-+
-+static inline void
-+swconfig_put_dev(struct switch_dev *dev)
-+{
-+	spin_unlock(&dev->lock);
-+}
-+
-+static int
-+swconfig_dump_attr(struct swconfig_callback *cb, void *arg)
-+{
-+	struct switch_attr *op = arg;
-+	struct genl_info *info = cb->info;
-+	struct sk_buff *msg = cb->msg;
-+	int id = cb->args[0];
-+	void *hdr;
-+
-+	hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, &switch_fam,
-+			NLM_F_MULTI, SWITCH_CMD_NEW_ATTR);
-+	if (IS_ERR(hdr))
-+		return -1;
-+
-+	NLA_PUT_U32(msg, SWITCH_ATTR_OP_ID, id);
-+	NLA_PUT_U32(msg, SWITCH_ATTR_OP_TYPE, op->type);
-+	NLA_PUT_STRING(msg, SWITCH_ATTR_OP_NAME, op->name);
-+	if (op->description)
-+		NLA_PUT_STRING(msg, SWITCH_ATTR_OP_DESCRIPTION,
-+			op->description);
-+
-+	return genlmsg_end(msg, hdr);
-+nla_put_failure:
-+	genlmsg_cancel(msg, hdr);
-+	return -EMSGSIZE;
-+}
-+
-+/* spread multipart messages across multiple message buffers */
-+static int
-+swconfig_send_multipart(struct swconfig_callback *cb, void *arg)
-+{
-+	struct genl_info *info = cb->info;
-+	int restart = 0;
-+	int err;
-+
-+	do {
-+		if (!cb->msg) {
-+			cb->msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
-+			if (cb->msg == NULL)
-+				goto error;
-+		}
-+
-+		if (!(cb->fill(cb, arg) < 0))
-+			break;
-+
-+		/* fill failed, check if this was already the second attempt */
-+		if (restart)
-+			goto error;
-+
-+		/* try again in a new message, send the current one */
-+		restart = 1;
-+		if (cb->close) {
-+			if (cb->close(cb, arg) < 0)
-+				goto error;
-+		}
-+		err = genlmsg_unicast(cb->msg, info->snd_pid);
-+		cb->msg = NULL;
-+		if (err < 0)
-+			goto error;
-+
-+	} while (restart);
-+
-+	return 0;
-+
-+error:
-+	if (cb->msg)
-+		nlmsg_free(cb->msg);
-+	return -1;
-+}
-+
-+static int
-+swconfig_list_attrs(struct sk_buff *skb, struct genl_info *info)
-+{
-+	struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
-+	const struct switch_attrlist *alist;
-+	struct switch_dev *dev;
-+	struct swconfig_callback cb;
-+	int err = -EINVAL;
-+	int i;
-+
-+	/* defaults */
-+	struct switch_attr *def_list;
-+	unsigned long *def_active;
-+	int n_def;
-+
-+	dev = swconfig_get_dev(info);
-+	if (!dev)
-+		return -EINVAL;
-+
-+	switch(hdr->cmd) {
-+	case SWITCH_CMD_LIST_GLOBAL:
-+		alist = &dev->attr_global;
-+		def_list = default_global;
-+		def_active = &dev->def_global;
-+		n_def = ARRAY_SIZE(default_global);
-+		break;
-+	case SWITCH_CMD_LIST_VLAN:
-+		alist = &dev->attr_vlan;
-+		def_list = default_vlan;
-+		def_active = &dev->def_vlan;
-+		n_def = ARRAY_SIZE(default_vlan);
-+		break;
-+	case SWITCH_CMD_LIST_PORT:
-+		alist = &dev->attr_port;
-+		def_list = default_port;
-+		def_active = &dev->def_port;
-+		n_def = ARRAY_SIZE(default_port);
-+		break;
-+	default:
-+		WARN_ON(1);
-+		goto out;
-+	}
-+
-+	memset(&cb, 0, sizeof(cb));
-+	cb.info = info;
-+	cb.fill = swconfig_dump_attr;
-+	for (i = 0; i < alist->n_attr; i++) {
-+		if (alist->attr[i].disabled)
-+			continue;
-+		cb.args[0] = i;
-+		err = swconfig_send_multipart(&cb, &alist->attr[i]);
-+		if (err < 0)
-+			goto error;
-+	}
-+
-+	/* defaults */
-+	for (i = 0; i < n_def; i++) {
-+		if (!test_bit(i, def_active))
-+			continue;
-+		cb.args[0] = SWITCH_ATTR_DEFAULTS_OFFSET + i;
-+		err = swconfig_send_multipart(&cb, &def_list[i]);
-+		if (err < 0)
-+			goto error;
-+	}
-+	swconfig_put_dev(dev);
-+
-+	if (!cb.msg)
-+		return 0;
-+
-+	return genlmsg_unicast(cb.msg, info->snd_pid);
-+
-+error:
-+	if (cb.msg)
-+		nlmsg_free(cb.msg);
-+out:
-+	swconfig_put_dev(dev);
-+	return err;
-+}
-+
-+static struct switch_attr *
-+swconfig_lookup_attr(struct switch_dev *dev, struct genl_info *info,
-+		struct switch_val *val)
-+{
-+	struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
-+	const struct switch_attrlist *alist;
-+	struct switch_attr *attr = NULL;
-+	int attr_id;
-+
-+	/* defaults */
-+	struct switch_attr *def_list;
-+	unsigned long *def_active;
-+	int n_def;
-+
-+	if (!info->attrs[SWITCH_ATTR_OP_ID])
-+		goto done;
-+
-+	switch(hdr->cmd) {
-+	case SWITCH_CMD_SET_GLOBAL:
-+	case SWITCH_CMD_GET_GLOBAL:
-+		alist = &dev->attr_global;
-+		def_list = default_global;
-+		def_active = &dev->def_global;
-+		n_def = ARRAY_SIZE(default_global);
-+		break;
-+	case SWITCH_CMD_SET_VLAN:
-+	case SWITCH_CMD_GET_VLAN:
-+		alist = &dev->attr_vlan;
-+		def_list = default_vlan;
-+		def_active = &dev->def_vlan;
-+		n_def = ARRAY_SIZE(default_vlan);
-+		if (!info->attrs[SWITCH_ATTR_OP_VLAN])
-+			goto done;
-+		val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_VLAN]);
-+		break;
-+	case SWITCH_CMD_SET_PORT:
-+	case SWITCH_CMD_GET_PORT:
-+		alist = &dev->attr_port;
-+		def_list = default_port;
-+		def_active = &dev->def_port;
-+		n_def = ARRAY_SIZE(default_port);
-+		if (!info->attrs[SWITCH_ATTR_OP_PORT])
-+			goto done;
-+		val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_PORT]);
-+		break;
-+	default:
-+		WARN_ON(1);
-+		goto done;
-+	}
-+
-+	if (!alist)
-+		goto done;
-+
-+	attr_id = nla_get_u32(info->attrs[SWITCH_ATTR_OP_ID]);
-+	if (attr_id >= SWITCH_ATTR_DEFAULTS_OFFSET) {
-+		attr_id -= SWITCH_ATTR_DEFAULTS_OFFSET;
-+		if (attr_id >= n_def)
-+			goto done;
-+		if (!test_bit(attr_id, def_active))
-+			goto done;
-+		attr = &def_list[attr_id];
-+	} else {
-+		if (attr_id >= alist->n_attr)
-+			goto done;
-+		attr = &alist->attr[attr_id];
-+	}
-+
-+	if (attr->disabled)
-+		attr = NULL;
-+
-+done:
-+	if (!attr)
-+		DPRINTF("attribute lookup failed\n");
-+	val->attr = attr;
-+	return attr;
-+}
-+
-+static int
-+swconfig_parse_ports(struct sk_buff *msg, struct nlattr *head,
-+		struct switch_val *val, int max)
-+{
-+	struct nlattr *nla;
-+	int rem;
-+
-+	val->len = 0;
-+	nla_for_each_nested(nla, head, rem) {
-+		struct nlattr *tb[SWITCH_PORT_ATTR_MAX+1];
-+		struct switch_port *port = &val->value.ports[val->len];
-+
-+		if (val->len >= max)
-+			return -EINVAL;
-+
-+		if (nla_parse_nested(tb, SWITCH_PORT_ATTR_MAX, nla,
-+				port_policy))
-+			return -EINVAL;
-+
-+		if (!tb[SWITCH_PORT_ID])
-+			return -EINVAL;
-+
-+		port->id = nla_get_u32(tb[SWITCH_PORT_ID]);
-+		if (tb[SWITCH_PORT_FLAG_TAGGED])
-+			port->flags |= (1 << SWITCH_PORT_FLAG_TAGGED);
-+		val->len++;
-+	}
-+
-+	return 0;
-+}
-+
-+static int
-+swconfig_set_attr(struct sk_buff *skb, struct genl_info *info)
-+{
-+	struct switch_attr *attr;
-+	struct switch_dev *dev;
-+	struct switch_val val;
-+	int err = -EINVAL;
-+
-+	dev = swconfig_get_dev(info);
-+	if (!dev)
-+		return -EINVAL;
-+
-+	memset(&val, 0, sizeof(val));
-+	attr = swconfig_lookup_attr(dev, info, &val);
-+	if (!attr || !attr->set)
-+		goto error;
-+
-+	val.attr = attr;
-+	switch(attr->type) {
-+	case SWITCH_TYPE_NOVAL:
-+		break;
-+	case SWITCH_TYPE_INT:
-+		if (!info->attrs[SWITCH_ATTR_OP_VALUE_INT])
-+			goto error;
-+		val.value.i =
-+			nla_get_u32(info->attrs[SWITCH_ATTR_OP_VALUE_INT]);
-+		break;
-+	case SWITCH_TYPE_STRING:
-+		if (!info->attrs[SWITCH_ATTR_OP_VALUE_STR])
-+			goto error;
-+		val.value.s =
-+			nla_data(info->attrs[SWITCH_ATTR_OP_VALUE_STR]);
-+		break;
-+	case SWITCH_TYPE_PORTS:
-+		val.value.ports = dev->portbuf;
-+		memset(dev->portbuf, 0,
-+			sizeof(struct switch_port) * dev->ports);
-+
-+		/* TODO: implement multipart? */
-+		if (info->attrs[SWITCH_ATTR_OP_VALUE_PORTS]) {
-+			err = swconfig_parse_ports(skb,
-+				info->attrs[SWITCH_ATTR_OP_VALUE_PORTS], &val, dev->ports);
-+			if (err < 0)
-+				goto error;
-+		} else {
-+			val.len = 0;
-+			err = 0;
-+		}
-+		break;
-+	default:
-+		goto error;
-+	}
-+
-+	err = attr->set(dev, attr, &val);
-+error:
-+	swconfig_put_dev(dev);
-+	return err;
-+}
-+
-+static int
-+swconfig_close_portlist(struct swconfig_callback *cb, void *arg)
-+{
-+	if (cb->nest[0])
-+		nla_nest_end(cb->msg, cb->nest[0]);
-+	return 0;
-+}
-+
-+static int
-+swconfig_send_port(struct swconfig_callback *cb, void *arg)
-+{
-+	const struct switch_port *port = arg;
-+	struct nlattr *p = NULL;
-+
-+	if (!cb->nest[0]) {
-+		cb->nest[0] = nla_nest_start(cb->msg, cb->cmd);
-+		if (!cb->nest[0])
-+			return -1;
-+	}
-+
-+	p = nla_nest_start(cb->msg, SWITCH_ATTR_PORT);
-+	if (!p)
-+		goto error;
-+
-+	NLA_PUT_U32(cb->msg, SWITCH_PORT_ID, port->id);
-+	if (port->flags & (1 << SWITCH_PORT_FLAG_TAGGED))
-+		NLA_PUT_FLAG(cb->msg, SWITCH_PORT_FLAG_TAGGED);
-+
-+	nla_nest_end(cb->msg, p);
-+	return 0;
-+
-+nla_put_failure:
-+		nla_nest_cancel(cb->msg, p);
-+error:
-+	nla_nest_cancel(cb->msg, cb->nest[0]);
-+	return -1;
-+}
-+
-+static int
-+swconfig_send_ports(struct sk_buff **msg, struct genl_info *info, int attr,
-+		const struct switch_val *val)
-+{
-+	struct swconfig_callback cb;
-+	int err = 0;
-+	int i;
-+
-+	if (!val->value.ports)
-+		return -EINVAL;
-+
-+	memset(&cb, 0, sizeof(cb));
-+	cb.cmd = attr;
-+	cb.msg = *msg;
-+	cb.info = info;
-+	cb.fill = swconfig_send_port;
-+	cb.close = swconfig_close_portlist;
-+
-+	cb.nest[0] = nla_nest_start(cb.msg, cb.cmd);
-+	for (i = 0; i < val->len; i++) {
-+		err = swconfig_send_multipart(&cb, &val->value.ports[i]);
-+		if (err)
-+			goto done;
-+	}
-+	err = val->len;
-+	swconfig_close_portlist(&cb, NULL);
-+	*msg = cb.msg;
-+
-+done:
-+	return err;
-+}
-+
-+static int
-+swconfig_get_attr(struct sk_buff *skb, struct genl_info *info)
-+{
-+	struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
-+	struct switch_attr *attr;
-+	struct switch_dev *dev;
-+	struct sk_buff *msg = NULL;
-+	struct switch_val val;
-+	int err = -EINVAL;
-+	int cmd = hdr->cmd;
-+
-+	dev = swconfig_get_dev(info);
-+	if (!dev)
-+		return -EINVAL;
-+
-+	memset(&val, 0, sizeof(val));
-+	attr = swconfig_lookup_attr(dev, info, &val);
-+	if (!attr || !attr->get)
-+		goto error_dev;
-+
-+	if (attr->type == SWITCH_TYPE_PORTS) {
-+		val.value.ports = dev->portbuf;
-+		memset(dev->portbuf, 0,
-+			sizeof(struct switch_port) * dev->ports);
-+	}
-+
-+	err = attr->get(dev, attr, &val);
-+	if (err)
-+		goto error;
-+
-+	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
-+	if (!msg)
-+		goto error;
-+
-+	hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, &switch_fam,
-+			0, cmd);
-+	if (IS_ERR(hdr))
-+		goto nla_put_failure;
-+
-+	switch(attr->type) {
-+	case SWITCH_TYPE_INT:
-+		NLA_PUT_U32(msg, SWITCH_ATTR_OP_VALUE_INT, val.value.i);
-+		break;
-+	case SWITCH_TYPE_STRING:
-+		NLA_PUT_STRING(msg, SWITCH_ATTR_OP_VALUE_STR, val.value.s);
-+		break;
-+	case SWITCH_TYPE_PORTS:
-+		err = swconfig_send_ports(&msg, info,
-+				SWITCH_ATTR_OP_VALUE_PORTS, &val);
-+		if (err < 0)
-+			goto nla_put_failure;
-+		break;
-+	default:
-+		DPRINTF("invalid type in attribute\n");
-+		err = -EINVAL;
-+		goto error;
-+	}
-+	err = genlmsg_end(msg, hdr);
-+	if (err < 0)
-+		goto nla_put_failure;
-+
-+	swconfig_put_dev(dev);
-+	return genlmsg_unicast(msg, info->snd_pid);
-+
-+nla_put_failure:
-+	if (msg)
-+		nlmsg_free(msg);
-+error_dev:
-+	swconfig_put_dev(dev);
-+error:
-+	if (!err)
-+		err = -ENOMEM;
-+	return err;
-+}
-+
-+static int
-+swconfig_send_switch(struct sk_buff *msg, u32 pid, u32 seq, int flags,
-+		const struct switch_dev *dev)
-+{
-+	void *hdr;
-+
-+	hdr = genlmsg_put(msg, pid, seq, &switch_fam, flags,
-+			SWITCH_CMD_NEW_ATTR);
-+	if (IS_ERR(hdr))
-+		return -1;
-+
-+	NLA_PUT_U32(msg, SWITCH_ATTR_ID, dev->id);
-+	NLA_PUT_STRING(msg, SWITCH_ATTR_NAME, dev->name);
-+	NLA_PUT_STRING(msg, SWITCH_ATTR_DEV_NAME, dev->devname);
-+	NLA_PUT_U32(msg, SWITCH_ATTR_VLANS, dev->vlans);
-+	NLA_PUT_U32(msg, SWITCH_ATTR_PORTS, dev->ports);
-+
-+	return genlmsg_end(msg, hdr);
-+nla_put_failure:
-+	genlmsg_cancel(msg, hdr);
-+	return -EMSGSIZE;
-+}
-+
-+static int swconfig_dump_switches(struct sk_buff *skb,
-+		struct netlink_callback *cb)
-+{
-+	struct switch_dev *dev;
-+	int start = cb->args[0];
-+	int idx = 0;
-+
-+	swconfig_lock();
-+	list_for_each_entry(dev, &swdevs, dev_list) {
-+		if (++idx <= start)
-+			continue;
-+		if (swconfig_send_switch(skb, NETLINK_CB(cb->skb).pid,
-+				cb->nlh->nlmsg_seq, NLM_F_MULTI,
-+				dev) < 0)
-+			break;
-+	}
-+	swconfig_unlock();
-+	cb->args[0] = idx;
-+
-+	return skb->len;
-+}
-+
-+static int
-+swconfig_done(struct netlink_callback *cb)
-+{
-+	return 0;
-+}
-+
-+static struct genl_ops swconfig_ops[] = {
-+	{
-+		.cmd = SWITCH_CMD_LIST_GLOBAL,
-+		.doit = swconfig_list_attrs,
-+		.policy = switch_policy,
-+	},
-+	{
-+		.cmd = SWITCH_CMD_LIST_VLAN,
-+		.doit = swconfig_list_attrs,
-+		.policy = switch_policy,
-+	},
-+	{
-+		.cmd = SWITCH_CMD_LIST_PORT,
-+		.doit = swconfig_list_attrs,
-+		.policy = switch_policy,
-+	},
-+	{
-+		.cmd = SWITCH_CMD_GET_GLOBAL,
-+		.doit = swconfig_get_attr,
-+		.policy = switch_policy,
-+	},
-+	{
-+		.cmd = SWITCH_CMD_GET_VLAN,
-+		.doit = swconfig_get_attr,
-+		.policy = switch_policy,
-+	},
-+	{
-+		.cmd = SWITCH_CMD_GET_PORT,
-+		.doit = swconfig_get_attr,
-+		.policy = switch_policy,
-+	},
-+	{
-+		.cmd = SWITCH_CMD_SET_GLOBAL,
-+		.doit = swconfig_set_attr,
-+		.policy = switch_policy,
-+	},
-+	{
-+		.cmd = SWITCH_CMD_SET_VLAN,
-+		.doit = swconfig_set_attr,
-+		.policy = switch_policy,
-+	},
-+	{
-+		.cmd = SWITCH_CMD_SET_PORT,
-+		.doit = swconfig_set_attr,
-+		.policy = switch_policy,
-+	},
-+	{
-+		.cmd = SWITCH_CMD_GET_SWITCH,
-+		.dumpit = swconfig_dump_switches,
-+		.policy = switch_policy,
-+		.done = swconfig_done,
-+	}
-+};
-+
-+int
-+register_switch(struct switch_dev *dev, struct net_device *netdev)
-+{
-+	INIT_LIST_HEAD(&dev->dev_list);
-+	if (netdev) {
-+		dev->netdev = netdev;
-+		if (!dev->devname)
-+			dev->devname = netdev->name;
-+	}
-+	BUG_ON(!dev->devname);
-+
-+	if (dev->ports > 0) {
-+		dev->portbuf = kzalloc(sizeof(struct switch_port) * dev->ports,
-+				GFP_KERNEL);
-+		if (!dev->portbuf)
-+			return -ENOMEM;
-+	}
-+	dev->id = ++swdev_id;
-+	swconfig_defaults_init(dev);
-+	spin_lock_init(&dev->lock);
-+	swconfig_lock();
-+	list_add(&dev->dev_list, &swdevs);
-+	swconfig_unlock();
-+
-+	return 0;
-+}
-+EXPORT_SYMBOL_GPL(register_switch);
-+
-+void
-+unregister_switch(struct switch_dev *dev)
-+{
-+	kfree(dev->portbuf);
-+	spin_lock(&dev->lock);
-+	swconfig_lock();
-+	list_del(&dev->dev_list);
-+	swconfig_unlock();
-+}
-+EXPORT_SYMBOL_GPL(unregister_switch);
-+
-+
-+static int __init
-+swconfig_init(void)
-+{
-+	int i, err;
-+
-+	INIT_LIST_HEAD(&swdevs);
-+	err = genl_register_family(&switch_fam);
-+	if (err)
-+		return err;
-+
-+	for (i = 0; i < ARRAY_SIZE(swconfig_ops); i++) {
-+		err = genl_register_ops(&switch_fam, &swconfig_ops[i]);
-+		if (err)
-+			goto unregister;
-+	}
-+
-+	return 0;
-+
-+unregister:
-+	genl_unregister_family(&switch_fam);
-+	return err;
-+}
-+
-+static void __exit
-+swconfig_exit(void)
-+{
-+	genl_unregister_family(&switch_fam);
-+}
-+
-+module_init(swconfig_init);
-+module_exit(swconfig_exit);
-+
-diff -Nur linux-2.6.30.orig/include/linux/switch.h linux-2.6.30/include/linux/switch.h
---- linux-2.6.30.orig/include/linux/switch.h	1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.30/include/linux/switch.h	2009-06-11 09:22:50.000000000 +0200
-@@ -0,0 +1,168 @@
-+/*
-+ * switch.h: Switch configuration API
-+ *
-+ * Copyright (C) 2008 Felix Fietkau <nbd@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.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#ifndef __LINUX_SWITCH_H
-+#define __LINUX_SWITCH_H
-+
-+#include <linux/types.h>
-+#include <linux/netdevice.h>
-+#include <linux/netlink.h>
-+#include <linux/genetlink.h>
-+#ifndef __KERNEL__
-+#include <netlink/netlink.h>
-+#include <netlink/genl/genl.h>
-+#include <netlink/genl/ctrl.h>
-+#else
-+#include <net/genetlink.h>
-+#endif
-+
-+/* main attributes */
-+enum {
-+	SWITCH_ATTR_UNSPEC,
-+	/* global */
-+	SWITCH_ATTR_TYPE,
-+	/* device */
-+	SWITCH_ATTR_ID,
-+	SWITCH_ATTR_NAME,
-+	SWITCH_ATTR_DEV_NAME,
-+	SWITCH_ATTR_VLANS,
-+	SWITCH_ATTR_PORTS,
-+	/* attributes */
-+	SWITCH_ATTR_OP_ID,
-+	SWITCH_ATTR_OP_TYPE,
-+	SWITCH_ATTR_OP_NAME,
-+	SWITCH_ATTR_OP_PORT,
-+	SWITCH_ATTR_OP_VLAN,
-+	SWITCH_ATTR_OP_VALUE_INT,
-+	SWITCH_ATTR_OP_VALUE_STR,
-+	SWITCH_ATTR_OP_VALUE_PORTS,
-+	SWITCH_ATTR_OP_DESCRIPTION,
-+	/* port lists */
-+	SWITCH_ATTR_PORT,
-+	SWITCH_ATTR_MAX
-+};
-+
-+/* commands */
-+enum {
-+	SWITCH_CMD_UNSPEC,
-+	SWITCH_CMD_GET_SWITCH,
-+	SWITCH_CMD_NEW_ATTR,
-+	SWITCH_CMD_LIST_GLOBAL,
-+	SWITCH_CMD_GET_GLOBAL,
-+	SWITCH_CMD_SET_GLOBAL,
-+	SWITCH_CMD_LIST_PORT,
-+	SWITCH_CMD_GET_PORT,
-+	SWITCH_CMD_SET_PORT,
-+	SWITCH_CMD_LIST_VLAN,
-+	SWITCH_CMD_GET_VLAN,
-+	SWITCH_CMD_SET_VLAN
-+};
-+
-+/* data types */
-+enum switch_val_type {
-+	SWITCH_TYPE_UNSPEC,
-+	SWITCH_TYPE_INT,
-+	SWITCH_TYPE_STRING,
-+	SWITCH_TYPE_PORTS,
-+	SWITCH_TYPE_NOVAL,
-+};
-+
-+/* port nested attributes */
-+enum {
-+	SWITCH_PORT_UNSPEC,
-+	SWITCH_PORT_ID,
-+	SWITCH_PORT_FLAG_TAGGED,
-+	SWITCH_PORT_ATTR_MAX
-+};
-+
-+#define SWITCH_ATTR_DEFAULTS_OFFSET	0x1000
-+
-+#ifdef __KERNEL__
-+
-+struct switch_dev;
-+struct switch_op;
-+struct switch_val;
-+struct switch_attr;
-+struct switch_attrlist;
-+
-+int register_switch(struct switch_dev *dev, struct net_device *netdev);
-+void unregister_switch(struct switch_dev *dev);
-+
-+struct switch_attrlist {
-+	/* filled in by the driver */
-+	int n_attr;
-+	struct switch_attr *attr;
-+};
-+
-+
-+struct switch_dev {
-+	int id;
-+	void *priv;
-+	const char *name;
-+
-+	/* NB: either devname or netdev must be set */
-+	const char *devname;
-+	struct net_device *netdev;
-+
-+	int ports;
-+	int vlans;
-+	int cpu_port;
-+	struct switch_attrlist attr_global, attr_port, attr_vlan;
-+
-+	spinlock_t lock;
-+	struct switch_port *portbuf;
-+	struct list_head dev_list;
-+	unsigned long def_global, def_port, def_vlan;
-+
-+	int (*get_vlan_ports)(struct switch_dev *dev, struct switch_val *val);
-+	int (*set_vlan_ports)(struct switch_dev *dev, struct switch_val *val);
-+	int (*apply_config)(struct switch_dev *dev);
-+};
-+
-+struct switch_port {
-+	u32 id;
-+	u32 flags;
-+};
-+
-+struct switch_val {
-+	struct switch_attr *attr;
-+	int port_vlan;
-+	int len;
-+	union {
-+		const char *s;
-+		u32 i;
-+		struct switch_port *ports;
-+	} value;
-+};
-+
-+struct switch_attr {
-+	int disabled;
-+	int type;
-+	const char *name;
-+	const char *description;
-+
-+	int (*set)(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val);
-+	int (*get)(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val);
-+
-+	/* for driver internal use */
-+	int id;
-+	int ofs;
-+	int max;
-+};
-+
-+#endif
-+
-+#endif

+ 33 - 0
target/rb4xx/Makefile

@@ -0,0 +1,33 @@
+# This file is part of the OpenADK project. OpenADK is copyrighted
+# material, please see the LICENCE file in the top-level directory.
+
+include $(TOPDIR)/rules.mk
+include $(TOPDIR)/mk/kernel.mk
+include $(TOPDIR)/mk/modules.mk
+include $(TOPDIR)/mk/kernel-build.mk
+include $(TOPDIR)/mk/image.mk
+
+OSTRIP:=-R .reginfo -R .notes -R .note -R .comment -R .mdebug -R .note.gnu.build-id
+
+kernel-install:
+	$(TARGET_CROSS)objcopy $(OSTRIP) -S $(LINUX_DIR)/vmlinux \
+		$(TARGET_DIR)/boot/kernel 
+	@cp $(TARGET_DIR)/boot/kernel \
+		$(BUILD_DIR)/${ADK_TARGET}-${FS}-kernel
+
+ifeq ($(FS),nfsroot)
+imageinstall: $(BIN_DIR)/$(ROOTFSUSERTARBALL)
+	@cp $(BUILD_DIR)/${ADK_TARGET}-${FS}-kernel \
+		$(BIN_DIR)/${ADK_TARGET}-${FS}-kernel
+	@echo 'The kernel file is: ${BIN_DIR}/${ADK_TARGET}-${FS}-kernel'
+	@echo 'The nfs root tarball is: ${BIN_DIR}/${ROOTFSUSERTARBALL}'
+	@echo 'Login as user root with password linux123 via ssh or console'
+endif
+ifeq ($(FS),yaffs)
+imageinstall: $(BIN_DIR)/$(ROOTFSTARBALL)
+	@echo 'The root tarball is: ${BIN_DIR}/${ROOTFSTARBALL}'
+	@echo 'Format your NAND with Routerboot, boot via NFS and'
+	@echo 'then install kernel and filesystem:'
+	@echo 'adkinstall ${ROOTFSTARBALL}'
+	@echo 'Login as user root with password linux123 via ssh or console'
+endif

+ 1142 - 0
target/rb4xx/kernel.config

@@ -0,0 +1,1142 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.33.3
+# Thu May 20 13:15:45 2010
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_MACH_ALCHEMY is not set
+# CONFIG_AR7 is not set
+CONFIG_ATHEROS_AR71XX=y
+# CONFIG_BCM47XX is not set
+# CONFIG_BCM63XX is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_MACH_LOONGSON is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_NEC_MARKEINS is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_NXP_STB220 is not set
+# CONFIG_NXP_STB225 is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_POWERTV is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP28 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_MACH_TX39XX is not set
+# CONFIG_MACH_TX49XX is not set
+# CONFIG_MIKROTIK_RB532 is not set
+# CONFIG_WR_PPMC is not set
+# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set
+# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set
+# CONFIG_ALCHEMY_GPIO_INDIRECT is not set
+
+#
+# Atheros AR71xx machine selection
+#
+# CONFIG_AR71XX_MACH_AP81 is not set
+# CONFIG_AR71XX_MACH_AP83 is not set
+# CONFIG_AR71XX_MACH_DIR_600_A1 is not set
+# CONFIG_AR71XX_MACH_DIR_615_C1 is not set
+# CONFIG_AR71XX_MACH_DIR_825_B1 is not set
+# CONFIG_AR71XX_MACH_PB42 is not set
+# CONFIG_AR71XX_MACH_PB44 is not set
+# CONFIG_AR71XX_MACH_PB92 is not set
+# CONFIG_AR71XX_MACH_AW_NR580 is not set
+# CONFIG_AR71XX_MACH_WZR_HP_G300NH is not set
+# CONFIG_AR71XX_MACH_WP543 is not set
+# CONFIG_AR71XX_MACH_WRT160NL is not set
+# CONFIG_AR71XX_MACH_WRT400N is not set
+CONFIG_AR71XX_MACH_RB4XX=y
+# CONFIG_AR71XX_MACH_RB750 is not set
+# CONFIG_AR71XX_MACH_WNDR3700 is not set
+# CONFIG_AR71XX_MACH_WNR2000 is not set
+# CONFIG_AR71XX_MACH_MZK_W04NU is not set
+# CONFIG_AR71XX_MACH_MZK_W300NH is not set
+# CONFIG_AR71XX_MACH_NBG460N is not set
+# CONFIG_AR71XX_MACH_TL_WR741ND is not set
+# CONFIG_AR71XX_MACH_TL_WR841N_V1 is not set
+# CONFIG_AR71XX_MACH_TL_WR941ND is not set
+# CONFIG_AR71XX_MACH_TL_WR1043ND is not set
+# CONFIG_AR71XX_MACH_TEW_632BRP is not set
+# CONFIG_AR71XX_MACH_UBNT is not set
+# CONFIG_AR71XX_DEV_M25P80 is not set
+# CONFIG_AR71XX_DEV_AP91_PCI is not set
+# CONFIG_AR71XX_DEV_AP91_ETH is not set
+# CONFIG_AR71XX_DEV_AP94_PCI is not set
+# CONFIG_AR71XX_DEV_AR913X_WMAC is not set
+# CONFIG_AR71XX_DEV_DSA is not set
+CONFIG_AR71XX_DEV_GPIO_BUTTONS=y
+CONFIG_AR71XX_DEV_LEDS_GPIO=y
+# CONFIG_AR71XX_DEV_PB42_PCI is not set
+# CONFIG_AR71XX_DEV_PB9X_PCI is not set
+CONFIG_AR71XX_DEV_USB=y
+# CONFIG_AR71XX_NVRAM is not set
+CONFIG_LOONGSON_UART_BASE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_CEVT_R4K_LIB=y
+CONFIG_CEVT_R4K=y
+CONFIG_CSRC_R4K_LIB=y
+CONFIG_CSRC_R4K=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_MIPS_MACHINE=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_GPIO=y
+CONFIG_CPU_BIG_ENDIAN=y
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_IRQ_CPU=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+# CONFIG_CPU_LOONGSON2E is not set
+# CONFIG_CPU_LOONGSON2F is not set
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R5500 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+# CONFIG_CPU_CAVIUM_OCTEON is not set
+CONFIG_SYS_SUPPORTS_ZBOOT=y
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_SYS_HAS_CPU_MIPS32_R2=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_32KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_48 is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=100
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_KEXEC is not set
+# CONFIG_SECCOMP is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_TINY_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_PCSPKR_PLATFORM=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_PCI_QUIRKS=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
+# CONFIG_FREEZER is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCI_LEGACY is not set
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCI_IOV is not set
+CONFIG_MMU=y
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Power management options
+#
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_PM is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+# CONFIG_LIB80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_ROOTFS_ROOT_DEV=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_AR91XX_FLASH is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_CAFE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+CONFIG_MTD_NAND_RB4XX=y
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# The newer stack is recommended.
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_IP175C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_TC35815 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_R6040 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SMSC9420 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851_MLL is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_SC92031 is not set
+# CONFIG_ATL2 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+CONFIG_AG71XX=y
+# CONFIG_AG71XX_DEBUG is not set
+# CONFIG_AG71XX_AR8216_SUPPORT is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL1C is not set
+# CONFIG_JME is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+CONFIG_WLAN=y
+# CONFIG_ATMEL is not set
+# CONFIG_PRISM54 is not set
+# CONFIG_HOSTAP is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_VMXNET3 is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_DEVKMEM is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_GPIO_DEVICE is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+
+#
+# PCI GPIO expanders:
+#
+# CONFIG_GPIO_CS5535 is not set
+# CONFIG_GPIO_BT8XX is not set
+# CONFIG_GPIO_LANGWELL is not set
+
+#
+# SPI GPIO expanders:
+#
+
+#
+# AC97 GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_ALIM7101_WDT is not set
+CONFIG_AR71XX_WDT=y
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGA_ARB is not set
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_SOUND is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_USB is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_UWB is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+# CONFIG_AUFS_FS is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_FSNOTIFY is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
+# CONFIG_PROC_PAGE_MONITOR is not set
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_PRINTK_TIME=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=0
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,115200"
+# CONFIG_CMDLINE_OVERRIDE is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_DEFAULT_SECURITY_SELINUX is not set
+# CONFIG_DEFAULT_SECURITY_SMACK is not set
+# CONFIG_DEFAULT_SECURITY_TOMOYO is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+
+#
+# OCF Configuration
+#
+# CONFIG_OCF_OCF is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y

+ 18749 - 0
target/rb4xx/patches/ar71xx.patch

@@ -0,0 +1,18749 @@
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/ar71xx.c linux-2.6.33.3/arch/mips/ar71xx/ar71xx.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/ar71xx.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/ar71xx.c	2010-04-02 11:07:51.850954806 +0200
+@@ -0,0 +1,177 @@
++/*
++ *  AR71xx SoC routines
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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/types.h>
++#include <linux/mutex.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++static DEFINE_MUTEX(ar71xx_flash_mutex);
++
++void __iomem *ar71xx_ddr_base;
++EXPORT_SYMBOL_GPL(ar71xx_ddr_base);
++
++void __iomem *ar71xx_pll_base;
++EXPORT_SYMBOL_GPL(ar71xx_pll_base);
++
++void __iomem *ar71xx_reset_base;
++EXPORT_SYMBOL_GPL(ar71xx_reset_base);
++
++void __iomem *ar71xx_gpio_base;
++EXPORT_SYMBOL_GPL(ar71xx_gpio_base);
++
++void __iomem *ar71xx_usb_ctrl_base;
++EXPORT_SYMBOL_GPL(ar71xx_usb_ctrl_base);
++
++void ar71xx_device_stop(u32 mask)
++{
++	unsigned long flags;
++	u32 mask_inv;
++	u32 t;
++
++	switch (ar71xx_soc) {
++	case AR71XX_SOC_AR7130:
++	case AR71XX_SOC_AR7141:
++	case AR71XX_SOC_AR7161:
++		local_irq_save(flags);
++		t = ar71xx_reset_rr(AR71XX_RESET_REG_RESET_MODULE);
++		ar71xx_reset_wr(AR71XX_RESET_REG_RESET_MODULE, t | mask);
++		local_irq_restore(flags);
++		break;
++
++	case AR71XX_SOC_AR7240:
++	case AR71XX_SOC_AR7241:
++	case AR71XX_SOC_AR7242:
++		mask_inv = mask & RESET_MODULE_USB_OHCI_DLL_7240;
++		local_irq_save(flags);
++		t = ar71xx_reset_rr(AR724X_RESET_REG_RESET_MODULE);
++		t |= mask;
++		t &= ~mask_inv;
++		ar71xx_reset_wr(AR724X_RESET_REG_RESET_MODULE, t);
++		local_irq_restore(flags);
++		break;
++
++	case AR71XX_SOC_AR9130:
++	case AR71XX_SOC_AR9132:
++		local_irq_save(flags);
++		t = ar71xx_reset_rr(AR91XX_RESET_REG_RESET_MODULE);
++		ar71xx_reset_wr(AR91XX_RESET_REG_RESET_MODULE, t | mask);
++		local_irq_restore(flags);
++		break;
++
++	default:
++		BUG();
++	}
++}
++EXPORT_SYMBOL_GPL(ar71xx_device_stop);
++
++void ar71xx_device_start(u32 mask)
++{
++	unsigned long flags;
++	u32 mask_inv;
++	u32 t;
++
++	switch (ar71xx_soc) {
++	case AR71XX_SOC_AR7130:
++	case AR71XX_SOC_AR7141:
++	case AR71XX_SOC_AR7161:
++		local_irq_save(flags);
++		t = ar71xx_reset_rr(AR71XX_RESET_REG_RESET_MODULE);
++		ar71xx_reset_wr(AR71XX_RESET_REG_RESET_MODULE, t & ~mask);
++		local_irq_restore(flags);
++		break;
++
++	case AR71XX_SOC_AR7240:
++	case AR71XX_SOC_AR7241:
++	case AR71XX_SOC_AR7242:
++		mask_inv = mask & RESET_MODULE_USB_OHCI_DLL_7240;
++		local_irq_save(flags);
++		t = ar71xx_reset_rr(AR724X_RESET_REG_RESET_MODULE);
++		t &= ~mask;
++		t |= mask_inv;
++		ar71xx_reset_wr(AR724X_RESET_REG_RESET_MODULE, t);
++		local_irq_restore(flags);
++		break;
++
++	case AR71XX_SOC_AR9130:
++	case AR71XX_SOC_AR9132:
++		local_irq_save(flags);
++		t = ar71xx_reset_rr(AR91XX_RESET_REG_RESET_MODULE);
++		ar71xx_reset_wr(AR91XX_RESET_REG_RESET_MODULE, t & ~mask);
++		local_irq_restore(flags);
++		break;
++
++	default:
++		BUG();
++	}
++}
++EXPORT_SYMBOL_GPL(ar71xx_device_start);
++
++int ar71xx_device_stopped(u32 mask)
++{
++	unsigned long flags;
++	u32 t;
++
++	switch (ar71xx_soc) {
++	case AR71XX_SOC_AR7130:
++	case AR71XX_SOC_AR7141:
++	case AR71XX_SOC_AR7161:
++		local_irq_save(flags);
++		t = ar71xx_reset_rr(AR71XX_RESET_REG_RESET_MODULE);
++		local_irq_restore(flags);
++		break;
++
++	case AR71XX_SOC_AR7240:
++	case AR71XX_SOC_AR7241:
++	case AR71XX_SOC_AR7242:
++		local_irq_save(flags);
++		t = ar71xx_reset_rr(AR724X_RESET_REG_RESET_MODULE);
++		local_irq_restore(flags);
++		break;
++
++	case AR71XX_SOC_AR9130:
++	case AR71XX_SOC_AR9132:
++		local_irq_save(flags);
++		t = ar71xx_reset_rr(AR91XX_RESET_REG_RESET_MODULE);
++		local_irq_restore(flags);
++		break;
++
++	default:
++		BUG();
++	}
++
++	return ((t & mask) == mask);
++}
++EXPORT_SYMBOL_GPL(ar71xx_device_stopped);
++
++void ar71xx_ddr_flush(u32 reg)
++{
++	ar71xx_ddr_wr(reg, 1);
++	while ((ar71xx_ddr_rr(reg) & 0x1));
++
++	ar71xx_ddr_wr(reg, 1);
++	while ((ar71xx_ddr_rr(reg) & 0x1));
++}
++EXPORT_SYMBOL_GPL(ar71xx_ddr_flush);
++
++void ar71xx_flash_acquire(void)
++{
++	mutex_lock(&ar71xx_flash_mutex);
++}
++EXPORT_SYMBOL_GPL(ar71xx_flash_acquire);
++
++void ar71xx_flash_release(void)
++{
++	mutex_unlock(&ar71xx_flash_mutex);
++}
++EXPORT_SYMBOL_GPL(ar71xx_flash_release);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/dev-ap91-eth.c linux-2.6.33.3/arch/mips/ar71xx/dev-ap91-eth.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/dev-ap91-eth.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/dev-ap91-eth.c	2010-03-23 20:31:04.580708993 +0100
+@@ -0,0 +1,70 @@
++/*
++ *  Atheros AP91 reference board ethernet initialization
++ *
++ *  Copyright (C) 2010 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 "devices.h"
++#include "dev-dsa.h"
++#include "dev-ap91-eth.h"
++
++static struct dsa_chip_data ap91_dsa_chip = {
++	.port_names[0]  = "cpu",
++	.port_names[1]  = "lan1",
++	.port_names[2]  = "lan2",
++	.port_names[3]  = "lan3",
++	.port_names[4]  = "lan4",
++};
++
++static struct dsa_platform_data ap91_dsa_data = {
++	.nr_chips	= 1,
++	.chip		= &ap91_dsa_chip,
++};
++
++static void ap91_eth_set_port_name(unsigned port, const char *name)
++{
++	if (port < 1 || port > 5)
++		return;
++
++	if (name)
++		ap91_dsa_chip.port_names[port] = (char *) name;
++}
++
++void __init ap91_eth_init(u8 *mac_addr, const char *port_names[])
++{
++	if (mac_addr)
++		ar71xx_set_mac_base(mac_addr);
++
++	if (port_names) {
++		int i;
++
++		for (i = 0; i < AP91_ETH_NUM_PORT_NAMES; i++)
++			ap91_eth_set_port_name(i + 1, port_names[i]);
++	}
++
++	/* WAN port */
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth0_data.speed = SPEED_100;
++	ar71xx_eth0_data.duplex = DUPLEX_FULL;
++	ar71xx_eth0_data.fifo_cfg1 = 0x0fff0000;
++	ar71xx_eth0_data.fifo_cfg2 = 0x00001fff;
++	ar71xx_eth0_data.fifo_cfg3 = 0x008001ff;
++
++	/* LAN ports */
++	ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth1_data.speed = SPEED_1000;
++	ar71xx_eth1_data.duplex = DUPLEX_FULL;
++	ar71xx_eth1_data.fifo_cfg1 = 0x0fff0000;
++	ar71xx_eth1_data.fifo_cfg2 = 0x00001fff;
++	ar71xx_eth1_data.fifo_cfg3 = 0x008001ff;
++
++	ar71xx_add_device_mdio(0x0);
++	ar71xx_add_device_eth(1);
++	ar71xx_add_device_eth(0);
++
++	ar71xx_add_device_dsa(1, &ap91_dsa_data);
++}
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/dev-ap91-eth.h linux-2.6.33.3/arch/mips/ar71xx/dev-ap91-eth.h
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/dev-ap91-eth.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/dev-ap91-eth.h	2010-03-12 19:31:46.886045750 +0100
+@@ -0,0 +1,23 @@
++/*
++ *  Atheros AP91 reference board ethernet initialization
++ *
++ *  Copyright (C) 2010 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.
++ */
++
++#ifndef _AR71XX_DEV_AP91_ETH_H
++#define _AR71XX_DEV_AP91_ETH_H
++
++#define AP91_ETH_NUM_PORT_NAMES	4
++
++#if defined(CONFIG_AR71XX_DEV_AP91_ETH)
++void ap91_eth_init(u8 *mac_addr, const char *port_names[]) __init;
++#else
++static inline void ap91_eth_init(u8 *mac_addr) { }
++#endif
++
++#endif /* _AR71XX_DEV_AP91_ETH_H */
++
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/dev-ap91-pci.c linux-2.6.33.3/arch/mips/ar71xx/dev-ap91-pci.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/dev-ap91-pci.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/dev-ap91-pci.c	2009-12-25 12:10:59.596028998 +0100
+@@ -0,0 +1,114 @@
++/*
++ *  Atheros AP91 reference board PCI initialization
++ *
++ *  Copyright (C) 2009 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/pci.h>
++#include <linux/ath9k_platform.h>
++#include <linux/delay.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/pci.h>
++
++#include "dev-ap91-pci.h"
++
++static struct ath9k_platform_data ap91_wmac_data;
++static char ap91_wmac_mac[6];
++static int ap91_pci_fixup_enabled;
++
++static struct ar71xx_pci_irq ap91_pci_irqs[] __initdata = {
++	{
++		.slot	= 0,
++		.pin	= 1,
++		.irq	= AR71XX_PCI_IRQ_DEV0,
++	}
++};
++
++static int ap91_pci_plat_dev_init(struct pci_dev *dev)
++{
++	switch(PCI_SLOT(dev->devfn)) {
++	case 0:
++		dev->dev.platform_data = &ap91_wmac_data;
++		break;
++	}
++
++	return 0;
++}
++
++static void ap91_pci_fixup(struct pci_dev *dev)
++{
++	void __iomem *mem;
++	u16 *cal_data;
++	u16 cmd;
++	u32 val;
++
++	if (!ap91_pci_fixup_enabled)
++		return;
++
++	printk(KERN_INFO "PCI: fixup device %s\n", pci_name(dev));
++
++	cal_data = ap91_wmac_data.eeprom_data;
++	if (*cal_data != 0xa55a) {
++		printk(KERN_ERR "PCI: no calibration data found for %s\n",
++		       pci_name(dev));
++		return;
++	}
++
++	mem = ioremap(AR71XX_PCI_MEM_BASE, 0x10000);
++	if (!mem) {
++		printk(KERN_ERR "PCI: ioremap error for device %s\n",
++		       pci_name(dev));
++		return;
++	}
++
++	/* Setup the PCI device to allow access to the internal registers */
++	pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0xffff);
++	pci_read_config_word(dev, PCI_COMMAND, &cmd);
++	cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
++	pci_write_config_word(dev, PCI_COMMAND, cmd);
++
++        /* set pointer to first reg address */
++	cal_data += 3;
++	while (*cal_data != 0xffff) {
++		u32 reg;
++		reg = *cal_data++;
++		val = *cal_data++;
++		val |= (*cal_data++) << 16;
++
++		__raw_writel(val, mem + reg);
++		udelay(100);
++	}
++
++	pci_read_config_dword(dev, PCI_VENDOR_ID, &val);
++	dev->vendor = val & 0xffff;
++	dev->device = (val >> 16) & 0xffff;
++
++	pci_read_config_dword(dev, PCI_CLASS_REVISION, &val);
++	dev->revision = val & 0xff;
++	dev->class = val >> 8; /* upper 3 bytes */
++
++	iounmap(mem);
++}
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATHEROS, PCI_ANY_ID, ap91_pci_fixup);
++
++void __init ap91_pci_init(u8 *cal_data, u8 *mac_addr)
++{
++	if (cal_data)
++		memcpy(ap91_wmac_data.eeprom_data, cal_data,
++		       sizeof(ap91_wmac_data.eeprom_data));
++
++	if (mac_addr) {
++		memcpy(ap91_wmac_mac, mac_addr, sizeof(ap91_wmac_mac));
++		ap91_wmac_data.macaddr = ap91_wmac_mac;
++	}
++
++	ar71xx_pci_plat_dev_init = ap91_pci_plat_dev_init;
++	ar71xx_pci_init(ARRAY_SIZE(ap91_pci_irqs), ap91_pci_irqs);
++
++	ap91_pci_fixup_enabled = 1;
++}
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/dev-ap91-pci.h linux-2.6.33.3/arch/mips/ar71xx/dev-ap91-pci.h
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/dev-ap91-pci.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/dev-ap91-pci.h	2010-01-05 20:38:52.249392561 +0100
+@@ -0,0 +1,21 @@
++/*
++ *  Atheros AP91 reference board PCI initialization
++ *
++ *  Copyright (C) 2009 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.
++ */
++
++#ifndef _AR71XX_DEV_AP91_PCI_H
++#define _AR71XX_DEV_AP91_PCI_H
++
++#if defined(CONFIG_AR71XX_DEV_AP91_PCI)
++void ap91_pci_init(u8 *cal_data, u8 *mac_addr) __init;
++#else
++static inline void ap91_pci_init(u8 *cal_data, u8 *mac_addr) { }
++#endif
++
++#endif /* _AR71XX_DEV_AP91_PCI_H */
++
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/dev-ap94-pci.c linux-2.6.33.3/arch/mips/ar71xx/dev-ap94-pci.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/dev-ap94-pci.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/dev-ap94-pci.c	2010-02-13 16:30:07.244691791 +0100
+@@ -0,0 +1,159 @@
++/*
++ *  Atheros AP94 reference board PCI initialization
++ *
++ *  Copyright (C) 2009-2010 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/pci.h>
++#include <linux/ath9k_platform.h>
++#include <linux/delay.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/pci.h>
++
++#include "dev-ap94-pci.h"
++
++static struct ath9k_platform_data ap94_wmac0_data;
++static struct ath9k_platform_data ap94_wmac1_data;
++static char ap94_wmac0_mac[6];
++static char ap94_wmac1_mac[6];
++static int ap94_pci_fixup_enabled;
++
++static struct ar71xx_pci_irq ap94_pci_irqs[] __initdata = {
++        {
++                .slot   = 0,
++                .pin    = 1,
++                .irq    = AR71XX_PCI_IRQ_DEV0,
++        }, {
++                .slot   = 1,
++                .pin    = 1,
++                .irq    = AR71XX_PCI_IRQ_DEV1,
++        }
++};
++
++static int ap94_pci_plat_dev_init(struct pci_dev *dev)
++{
++	switch(PCI_SLOT(dev->devfn)) {
++	case 17:
++		dev->dev.platform_data = &ap94_wmac0_data;
++		break;
++
++	case 18:
++		dev->dev.platform_data = &ap94_wmac1_data;
++		break;
++	}
++
++	return 0;
++}
++
++static void ap94_pci_fixup(struct pci_dev *dev)
++{
++	void __iomem *mem;
++	u16 *cal_data;
++	u16 cmd;
++	u32 bar0;
++	u32 val;
++
++	if (!ap94_pci_fixup_enabled)
++		return;
++
++	switch (PCI_SLOT(dev->devfn)) {
++	case 17:
++		cal_data = ap94_wmac0_data.eeprom_data;
++		break;
++	case 18:
++		cal_data = ap94_wmac1_data.eeprom_data;
++		break;
++	default:
++		return;
++	}
++
++	if (*cal_data != 0xa55a) {
++		printk(KERN_ERR "PCI: no calibration data found for %s\n",
++		       pci_name(dev));
++		return;
++	}
++
++	mem = ioremap(AR71XX_PCI_MEM_BASE, 0x10000);
++	if (!mem) {
++		printk(KERN_ERR "PCI: ioremap error for device %s\n",
++		       pci_name(dev));
++		return;
++	}
++
++	printk(KERN_INFO "PCI: fixup device %s\n", pci_name(dev));
++
++	pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &bar0);
++
++	/* Setup the PCI device to allow access to the internal registers */
++	pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, AR71XX_PCI_MEM_BASE);
++	pci_read_config_word(dev, PCI_COMMAND, &cmd);
++	cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
++	pci_write_config_word(dev, PCI_COMMAND, cmd);
++
++	/* set pointer to first reg address */
++	cal_data += 3;
++	while (*cal_data != 0xffff) {
++		u32 reg;
++		reg = *cal_data++;
++		val = *cal_data++;
++		val |= (*cal_data++) << 16;
++
++		__raw_writel(val, mem + reg);
++		udelay(100);
++	}
++
++	pci_read_config_dword(dev, PCI_VENDOR_ID, &val);
++	dev->vendor = val & 0xffff;
++	dev->device = (val >> 16) & 0xffff;
++
++	pci_read_config_dword(dev, PCI_CLASS_REVISION, &val);
++	dev->revision = val & 0xff;
++	dev->class = val >> 8; /* upper 3 bytes */
++
++	pci_read_config_word(dev, PCI_COMMAND, &cmd);
++	cmd &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
++	pci_write_config_word(dev, PCI_COMMAND, cmd);
++
++	pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, bar0);
++
++	iounmap(mem);
++}
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATHEROS, PCI_ANY_ID, ap94_pci_fixup);
++
++void __init ap94_pci_enable_quirk_wndr3700(void)
++{
++	ap94_wmac0_data.quirk_wndr3700 = 1;
++	ap94_wmac1_data.quirk_wndr3700 = 1;
++}
++
++void __init ap94_pci_init(u8 *cal_data0, u8 *mac_addr0,
++			  u8 *cal_data1, u8 *mac_addr1)
++{
++	if (cal_data0)
++		memcpy(ap94_wmac0_data.eeprom_data, cal_data0,
++		       sizeof(ap94_wmac0_data.eeprom_data));
++
++	if (cal_data1)
++		memcpy(ap94_wmac1_data.eeprom_data, cal_data1,
++		       sizeof(ap94_wmac1_data.eeprom_data));
++
++	if (mac_addr0) {
++		memcpy(ap94_wmac0_mac, mac_addr0, sizeof(ap94_wmac0_mac));
++		ap94_wmac0_data.macaddr = ap94_wmac0_mac;
++	}
++
++	if (mac_addr1) {
++		memcpy(ap94_wmac1_mac, mac_addr1, sizeof(ap94_wmac1_mac));
++		ap94_wmac1_data.macaddr = ap94_wmac1_mac;
++	}
++
++	ar71xx_pci_plat_dev_init = ap94_pci_plat_dev_init;
++	ar71xx_pci_init(ARRAY_SIZE(ap94_pci_irqs), ap94_pci_irqs);
++
++	ap94_pci_fixup_enabled = 1;
++}
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/dev-ap94-pci.h linux-2.6.33.3/arch/mips/ar71xx/dev-ap94-pci.h
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/dev-ap94-pci.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/dev-ap94-pci.h	2010-02-13 16:30:07.244691791 +0100
+@@ -0,0 +1,28 @@
++/*
++ *  Atheros AP94 reference board PCI initialization
++ *
++ *  Copyright (C) 2009-2010 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.
++ */
++
++#ifndef _AR71XX_DEV_AP94_PCI_H
++#define _AR71XX_DEV_AP94_PCI_H
++
++#if defined(CONFIG_AR71XX_DEV_AP94_PCI)
++void ap94_pci_init(u8 *cal_data0, u8 *mac_addr0,
++		   u8 *cal_data1, u8 *mac_addr1) __init;
++
++void ap94_pci_enable_quirk_wndr3700(void) __init;
++
++#else
++static inline void ap94_pci_init(u8 *cal_data0, u8 *mac_addr0,
++				 u8 *cal_data1, u8 *mac_addr1) {}
++
++static inline void ap94_pci_enable_quirk_wndr3700(void) {}
++#endif
++
++#endif /* _AR71XX_DEV_AP94_PCI_H */
++
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/dev-ar913x-wmac.c linux-2.6.33.3/arch/mips/ar71xx/dev-ar913x-wmac.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/dev-ar913x-wmac.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/dev-ar913x-wmac.c	2010-03-23 20:31:04.941023040 +0100
+@@ -0,0 +1,68 @@
++/*
++ *  Atheros AR913x SoC built-in WMAC device support
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ *  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/init.h>
++#include <linux/delay.h>
++#include <linux/etherdevice.h>
++#include <linux/platform_device.h>
++#include <linux/ath9k_platform.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "dev-ar913x-wmac.h"
++
++static struct ath9k_platform_data ar913x_wmac_data;
++static char ar913x_wmac_mac[6];
++
++static struct resource ar913x_wmac_resources[] = {
++	{
++		.start	= AR91XX_WMAC_BASE,
++		.end	= AR91XX_WMAC_BASE + AR91XX_WMAC_SIZE - 1,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= AR71XX_CPU_IRQ_IP2,
++		.end	= AR71XX_CPU_IRQ_IP2,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ar913x_wmac_device = {
++	.name		= "ath9k",
++	.id		= -1,
++	.resource	= ar913x_wmac_resources,
++	.num_resources	= ARRAY_SIZE(ar913x_wmac_resources),
++	.dev = {
++		.platform_data = &ar913x_wmac_data,
++	},
++};
++
++void __init ar913x_add_device_wmac(u8 *cal_data, u8 *mac_addr)
++{
++	if (cal_data)
++		memcpy(ar913x_wmac_data.eeprom_data, cal_data,
++		       sizeof(ar913x_wmac_data.eeprom_data));
++
++	if (mac_addr) {
++		memcpy(ar913x_wmac_mac, mac_addr, sizeof(ar913x_wmac_mac));
++		ar913x_wmac_data.macaddr = ar913x_wmac_mac;
++	}
++
++	ar71xx_device_stop(RESET_MODULE_AMBA2WMAC);
++	mdelay(10);
++
++	ar71xx_device_start(RESET_MODULE_AMBA2WMAC);
++	mdelay(10);
++
++	platform_device_register(&ar913x_wmac_device);
++}
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/dev-ar913x-wmac.h linux-2.6.33.3/arch/mips/ar71xx/dev-ar913x-wmac.h
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/dev-ar913x-wmac.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/dev-ar913x-wmac.h	2010-01-05 20:38:52.185278525 +0100
+@@ -0,0 +1,19 @@
++/*
++ *  Atheros AR913x SoC built-in WMAC device support
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ *  This program is free software; you can redistribute it and/or modify it
++ *  under the terms of the GNU General Public License version 2 as published
++ *  by the Free Software Foundation.
++ */
++
++#ifndef _AR71XX_DEV_AR913X_WMAC_H
++#define _AR71XX_DEV_AR913X_WMAC_H
++
++void ar913x_add_device_wmac(u8 *cal_data, u8 *mac_addr) __init;
++
++#endif /* _AR71XX_DEV_AR913X_WMAC_H */
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/dev-dsa.c linux-2.6.33.3/arch/mips/ar71xx/dev-dsa.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/dev-dsa.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/dev-dsa.c	2010-01-05 20:38:52.058900684 +0100
+@@ -0,0 +1,50 @@
++/*
++ *  Atheros AR71xx DSA switch device support
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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/init.h>
++#include <linux/platform_device.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "devices.h"
++#include "dev-dsa.h"
++
++static struct platform_device ar71xx_dsa_switch_device = {
++	.name		= "dsa",
++	.id		= 0,
++};
++
++void __init ar71xx_add_device_dsa(unsigned int id,
++				  struct dsa_platform_data *d)
++{
++	int i;
++
++	switch (id) {
++	case 0:
++		d->netdev = &ar71xx_eth0_device.dev;
++		break;
++	case 1:
++		d->netdev = &ar71xx_eth1_device.dev;
++		break;
++	default:
++		printk(KERN_ERR
++			"ar71xx: invalid ethernet id %d for DSA switch\n",
++			id);
++		return;
++	}
++
++	for (i = 0; i < d->nr_chips; i++)
++		d->chip[i].mii_bus = &ar71xx_mdio_device.dev;
++
++	ar71xx_dsa_switch_device.dev.platform_data = d;
++
++	platform_device_register(&ar71xx_dsa_switch_device);
++}
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/dev-dsa.h linux-2.6.33.3/arch/mips/ar71xx/dev-dsa.h
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/dev-dsa.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/dev-dsa.h	2010-01-05 20:38:52.137278273 +0100
+@@ -0,0 +1,20 @@
++/*
++ *  Atheros AR71xx DSA switch device support
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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.
++ */
++
++#ifndef _AR71XX_DEV_DSA_H
++#define _AR71XX_DEV_DSA_H
++
++#include <net/dsa.h>
++
++void ar71xx_add_device_dsa(unsigned int id,
++			   struct dsa_platform_data *d) __init;
++
++#endif /* _AR71XX_DEV_DSA_H */
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/dev-gpio-buttons.c linux-2.6.33.3/arch/mips/ar71xx/dev-gpio-buttons.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/dev-gpio-buttons.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/dev-gpio-buttons.c	2010-01-05 20:38:52.310262885 +0100
+@@ -0,0 +1,58 @@
++/*
++ *  Atheros AR71xx GPIO button support
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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/init.h"
++#include <linux/platform_device.h>
++
++#include "dev-gpio-buttons.h"
++
++void __init ar71xx_add_device_gpio_buttons(int id,
++					   unsigned poll_interval,
++					   unsigned nbuttons,
++					   struct gpio_button *buttons)
++{
++	struct platform_device *pdev;
++	struct gpio_buttons_platform_data pdata;
++	struct gpio_button *p;
++	int err;
++
++	p = kmalloc(nbuttons * sizeof(*p), GFP_KERNEL);
++	if (!p)
++		return;
++
++	memcpy(p, buttons, nbuttons * sizeof(*p));
++
++	pdev = platform_device_alloc("gpio-buttons", id);
++	if (!pdev)
++		goto err_free_buttons;
++
++	memset(&pdata, 0, sizeof(pdata));
++	pdata.poll_interval = poll_interval;
++	pdata.nbuttons = nbuttons;
++	pdata.buttons = p;
++
++	err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
++	if (err)
++		goto err_put_pdev;
++
++
++	err = platform_device_add(pdev);
++	if (err)
++		goto err_put_pdev;
++
++	return;
++
++err_put_pdev:
++	platform_device_put(pdev);
++
++err_free_buttons:
++	kfree(p);
++}
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/dev-gpio-buttons.h linux-2.6.33.3/arch/mips/ar71xx/dev-gpio-buttons.h
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/dev-gpio-buttons.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/dev-gpio-buttons.h	2010-01-05 20:38:52.385278021 +0100
+@@ -0,0 +1,25 @@
++/*
++ *  Atheros AR71xx GPIO button support
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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.
++ */
++
++#ifndef _AR71XX_DEV_GPIO_BUTTONS_H
++#define _AR71XX_DEV_GPIO_BUTTONS_H
++
++#include <linux/input.h>
++#include <linux/gpio_buttons.h>
++
++#include <asm/mach-ar71xx/platform.h>
++
++void ar71xx_add_device_gpio_buttons(int id,
++				    unsigned poll_interval,
++				    unsigned nbuttons,
++				    struct gpio_button *buttons) __init;
++
++#endif /* _AR71XX_DEV_GPIO_BUTTONS_H */
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/devices.c linux-2.6.33.3/arch/mips/ar71xx/devices.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/devices.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/devices.c	2010-04-02 11:07:51.658955496 +0200
+@@ -0,0 +1,575 @@
++/*
++ *  Atheros AR71xx SoC platform devices
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ *  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/init.h>
++#include <linux/delay.h>
++#include <linux/etherdevice.h>
++#include <linux/platform_device.h>
++#include <linux/serial_8250.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "devices.h"
++
++static u8 ar71xx_mac_base[ETH_ALEN] __initdata;
++
++static struct resource ar71xx_uart_resources[] = {
++	{
++		.start	= AR71XX_UART_BASE,
++		.end	= AR71XX_UART_BASE + AR71XX_UART_SIZE - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++};
++
++#define AR71XX_UART_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP)
++static struct plat_serial8250_port ar71xx_uart_data[] = {
++	{
++		.mapbase	= AR71XX_UART_BASE,
++		.irq		= AR71XX_MISC_IRQ_UART,
++		.flags		= AR71XX_UART_FLAGS,
++		.iotype		= UPIO_MEM32,
++		.regshift	= 2,
++	}, {
++		/* terminating entry */
++	}
++};
++
++static struct platform_device ar71xx_uart_device = {
++	.name		= "serial8250",
++	.id		= PLAT8250_DEV_PLATFORM,
++	.resource	= ar71xx_uart_resources,
++	.num_resources	= ARRAY_SIZE(ar71xx_uart_resources),
++	.dev = {
++		.platform_data	= ar71xx_uart_data
++	},
++};
++
++void __init ar71xx_add_device_uart(void)
++{
++	ar71xx_uart_data[0].uartclk = ar71xx_ahb_freq;
++	platform_device_register(&ar71xx_uart_device);
++}
++
++static struct resource ar71xx_mdio_resources[] = {
++	{
++		.name	= "mdio_base",
++		.flags	= IORESOURCE_MEM,
++		.start	= AR71XX_GE0_BASE,
++		.end	= AR71XX_GE0_BASE + 0x200 - 1,
++	}
++};
++
++static struct ag71xx_mdio_platform_data ar71xx_mdio_data;
++
++struct platform_device ar71xx_mdio_device = {
++	.name		= "ag71xx-mdio",
++	.id		= -1,
++	.resource	= ar71xx_mdio_resources,
++	.num_resources	= ARRAY_SIZE(ar71xx_mdio_resources),
++	.dev = {
++		.platform_data = &ar71xx_mdio_data,
++	},
++};
++
++void __init ar71xx_add_device_mdio(u32 phy_mask)
++{
++	switch (ar71xx_soc) {
++	case AR71XX_SOC_AR7240:
++	case AR71XX_SOC_AR7241:
++	case AR71XX_SOC_AR7242:
++		ar71xx_mdio_data.is_ar7240 = 1;
++		break;
++	default:
++		break;
++	}
++
++	ar71xx_mdio_data.phy_mask = phy_mask;
++
++	platform_device_register(&ar71xx_mdio_device);
++}
++
++static void ar71xx_set_pll(u32 cfg_reg, u32 pll_reg, u32 pll_val, u32 shift)
++{
++	void __iomem *base;
++	u32 t;
++
++	base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
++
++	t = __raw_readl(base + cfg_reg);
++	t &= ~(3 << shift);
++	t |=  (2 << shift);
++	__raw_writel(t, base + cfg_reg);
++	udelay(100);
++
++	__raw_writel(pll_val, base + pll_reg);
++
++	t |= (3 << shift);
++	__raw_writel(t, base + cfg_reg);
++	udelay(100);
++
++	t &= ~(3 << shift);
++	__raw_writel(t, base + cfg_reg);
++	udelay(100);
++
++	printk(KERN_DEBUG "ar71xx: pll_reg %#x: %#x\n",
++		(unsigned int)(base + pll_reg), __raw_readl(base + pll_reg));
++
++	iounmap(base);
++}
++
++struct ar71xx_eth_pll_data ar71xx_eth0_pll_data;
++struct ar71xx_eth_pll_data ar71xx_eth1_pll_data;
++
++static u32 ar71xx_get_eth_pll(unsigned int mac, int speed)
++{
++	struct ar71xx_eth_pll_data *pll_data;
++	u32 pll_val;
++
++	switch (mac) {
++	case 0:
++		pll_data = &ar71xx_eth0_pll_data;
++		break;
++	case 1:
++		pll_data = &ar71xx_eth1_pll_data;
++		break;
++	default:
++		BUG();
++	}
++
++	switch (speed) {
++	case SPEED_10:
++		pll_val = pll_data->pll_10;
++		break;
++	case SPEED_100:
++		pll_val = pll_data->pll_100;
++		break;
++	case SPEED_1000:
++		pll_val = pll_data->pll_1000;
++		break;
++	default:
++		BUG();
++	}
++
++	return pll_val;
++}
++
++static void ar71xx_set_pll_ge0(int speed)
++{
++	u32 val = ar71xx_get_eth_pll(0, speed);
++
++	ar71xx_set_pll(AR71XX_PLL_REG_SEC_CONFIG, AR71XX_PLL_REG_ETH0_INT_CLOCK,
++			val, AR71XX_ETH0_PLL_SHIFT);
++}
++
++static void ar71xx_set_pll_ge1(int speed)
++{
++	u32 val = ar71xx_get_eth_pll(1, speed);
++
++	ar71xx_set_pll(AR71XX_PLL_REG_SEC_CONFIG, AR71XX_PLL_REG_ETH1_INT_CLOCK,
++			 val, AR71XX_ETH1_PLL_SHIFT);
++}
++
++static void ar724x_set_pll_ge0(int speed)
++{
++	/* TODO */
++}
++
++static void ar724x_set_pll_ge1(int speed)
++{
++	/* TODO */
++}
++
++static void ar91xx_set_pll_ge0(int speed)
++{
++	u32 val = ar71xx_get_eth_pll(0, speed);
++
++	ar71xx_set_pll(AR91XX_PLL_REG_ETH_CONFIG, AR91XX_PLL_REG_ETH0_INT_CLOCK,
++			 val, AR91XX_ETH0_PLL_SHIFT);
++}
++
++static void ar91xx_set_pll_ge1(int speed)
++{
++	u32 val = ar71xx_get_eth_pll(1, speed);
++
++	ar71xx_set_pll(AR91XX_PLL_REG_ETH_CONFIG, AR91XX_PLL_REG_ETH1_INT_CLOCK,
++			 val, AR91XX_ETH1_PLL_SHIFT);
++}
++
++static void ar71xx_ddr_flush_ge0(void)
++{
++	ar71xx_ddr_flush(AR71XX_DDR_REG_FLUSH_GE0);
++}
++
++static void ar71xx_ddr_flush_ge1(void)
++{
++	ar71xx_ddr_flush(AR71XX_DDR_REG_FLUSH_GE1);
++}
++
++static void ar724x_ddr_flush_ge0(void)
++{
++	ar71xx_ddr_flush(AR724X_DDR_REG_FLUSH_GE0);
++}
++
++static void ar724x_ddr_flush_ge1(void)
++{
++	ar71xx_ddr_flush(AR724X_DDR_REG_FLUSH_GE1);
++}
++
++static void ar91xx_ddr_flush_ge0(void)
++{
++	ar71xx_ddr_flush(AR91XX_DDR_REG_FLUSH_GE0);
++}
++
++static void ar91xx_ddr_flush_ge1(void)
++{
++	ar71xx_ddr_flush(AR91XX_DDR_REG_FLUSH_GE1);
++}
++
++static struct resource ar71xx_eth0_resources[] = {
++	{
++		.name	= "mac_base",
++		.flags	= IORESOURCE_MEM,
++		.start	= AR71XX_GE0_BASE,
++		.end	= AR71XX_GE0_BASE + 0x200 - 1,
++	}, {
++		.name	= "mii_ctrl",
++		.flags	= IORESOURCE_MEM,
++		.start	= AR71XX_MII_BASE + MII_REG_MII0_CTRL,
++		.end	= AR71XX_MII_BASE + MII_REG_MII0_CTRL + 3,
++	}, {
++		.name	= "mac_irq",
++		.flags	= IORESOURCE_IRQ,
++		.start	= AR71XX_CPU_IRQ_GE0,
++		.end	= AR71XX_CPU_IRQ_GE0,
++	},
++};
++
++struct ag71xx_platform_data ar71xx_eth0_data = {
++	.reset_bit	= RESET_MODULE_GE0_MAC,
++};
++
++struct platform_device ar71xx_eth0_device = {
++	.name		= "ag71xx",
++	.id		= 0,
++	.resource	= ar71xx_eth0_resources,
++	.num_resources	= ARRAY_SIZE(ar71xx_eth0_resources),
++	.dev = {
++		.platform_data = &ar71xx_eth0_data,
++	},
++};
++
++static struct resource ar71xx_eth1_resources[] = {
++	{
++		.name	= "mac_base",
++		.flags	= IORESOURCE_MEM,
++		.start	= AR71XX_GE1_BASE,
++		.end	= AR71XX_GE1_BASE + 0x200 - 1,
++	}, {
++		.name	= "mii_ctrl",
++		.flags	= IORESOURCE_MEM,
++		.start	= AR71XX_MII_BASE + MII_REG_MII1_CTRL,
++		.end	= AR71XX_MII_BASE + MII_REG_MII1_CTRL + 3,
++	}, {
++		.name	= "mac_irq",
++		.flags	= IORESOURCE_IRQ,
++		.start	= AR71XX_CPU_IRQ_GE1,
++		.end	= AR71XX_CPU_IRQ_GE1,
++	},
++};
++
++struct ag71xx_platform_data ar71xx_eth1_data = {
++	.reset_bit	= RESET_MODULE_GE1_MAC,
++};
++
++struct platform_device ar71xx_eth1_device = {
++	.name		= "ag71xx",
++	.id		= 1,
++	.resource	= ar71xx_eth1_resources,
++	.num_resources	= ARRAY_SIZE(ar71xx_eth1_resources),
++	.dev = {
++		.platform_data = &ar71xx_eth1_data,
++	},
++};
++
++#define AR71XX_PLL_VAL_1000	0x00110000
++#define AR71XX_PLL_VAL_100	0x00001099
++#define AR71XX_PLL_VAL_10	0x00991099
++
++#define AR724X_PLL_VAL_1000	0x00110000
++#define AR724X_PLL_VAL_100	0x00001099
++#define AR724X_PLL_VAL_10	0x00991099
++
++#define AR91XX_PLL_VAL_1000	0x1a000000
++#define AR91XX_PLL_VAL_100	0x13000a44
++#define AR91XX_PLL_VAL_10	0x00441099
++
++static void __init ar71xx_init_eth_pll_data(unsigned int id)
++{
++	struct ar71xx_eth_pll_data *pll_data;
++	u32 pll_10, pll_100, pll_1000;
++
++	switch (id) {
++	case 0:
++		pll_data = &ar71xx_eth0_pll_data;
++		break;
++	case 1:
++		pll_data = &ar71xx_eth1_pll_data;
++		break;
++	default:
++		BUG();
++	}
++
++	switch (ar71xx_soc) {
++	case AR71XX_SOC_AR7130:
++	case AR71XX_SOC_AR7141:
++	case AR71XX_SOC_AR7161:
++		pll_10 = AR71XX_PLL_VAL_10;
++		pll_100 = AR71XX_PLL_VAL_100;
++		pll_1000 = AR71XX_PLL_VAL_1000;
++		break;
++
++	case AR71XX_SOC_AR7240:
++	case AR71XX_SOC_AR7241:
++	case AR71XX_SOC_AR7242:
++		pll_10 = AR724X_PLL_VAL_10;
++		pll_100 = AR724X_PLL_VAL_100;
++		pll_1000 = AR724X_PLL_VAL_1000;
++		break;
++
++	case AR71XX_SOC_AR9130:
++	case AR71XX_SOC_AR9132:
++		pll_10 = AR91XX_PLL_VAL_10;
++		pll_100 = AR91XX_PLL_VAL_100;
++		pll_1000 = AR91XX_PLL_VAL_1000;
++		break;
++	default:
++		BUG();
++	}
++
++	if (!pll_data->pll_10)
++		pll_data->pll_10 = pll_10;
++
++	if (!pll_data->pll_100)
++		pll_data->pll_100 = pll_100;
++
++	if (!pll_data->pll_1000)
++		pll_data->pll_1000 = pll_1000;
++}
++
++static int ar71xx_eth_instance __initdata;
++void __init ar71xx_add_device_eth(unsigned int id)
++{
++	struct platform_device *pdev;
++	struct ag71xx_platform_data *pdata;
++
++	ar71xx_init_eth_pll_data(id);
++
++	switch (id) {
++	case 0:
++		switch (ar71xx_eth0_data.phy_if_mode) {
++		case PHY_INTERFACE_MODE_MII:
++			ar71xx_eth0_data.mii_if = MII0_CTRL_IF_MII;
++			break;
++		case PHY_INTERFACE_MODE_GMII:
++			ar71xx_eth0_data.mii_if = MII0_CTRL_IF_GMII;
++			break;
++		case PHY_INTERFACE_MODE_RGMII:
++			ar71xx_eth0_data.mii_if = MII0_CTRL_IF_RGMII;
++			break;
++		case PHY_INTERFACE_MODE_RMII:
++			ar71xx_eth0_data.mii_if = MII0_CTRL_IF_RMII;
++			break;
++		default:
++			printk(KERN_ERR "ar71xx: invalid PHY interface mode "
++					"for eth0\n");
++			return;
++		}
++		pdev = &ar71xx_eth0_device;
++		break;
++	case 1:
++		switch (ar71xx_eth1_data.phy_if_mode) {
++		case PHY_INTERFACE_MODE_RMII:
++			ar71xx_eth1_data.mii_if = MII1_CTRL_IF_RMII;
++			break;
++		case PHY_INTERFACE_MODE_RGMII:
++			ar71xx_eth1_data.mii_if = MII1_CTRL_IF_RGMII;
++			break;
++		default:
++			printk(KERN_ERR "ar71xx: invalid PHY interface mode "
++					"for eth1\n");
++			return;
++		}
++		pdev = &ar71xx_eth1_device;
++		break;
++	default:
++		printk(KERN_ERR "ar71xx: invalid ethernet id %d\n", id);
++		return;
++	}
++
++	pdata = pdev->dev.platform_data;
++
++	switch (ar71xx_soc) {
++	case AR71XX_SOC_AR7130:
++		pdata->ddr_flush = id ? ar71xx_ddr_flush_ge1
++				      : ar71xx_ddr_flush_ge0;
++		pdata->set_pll =  id ? ar71xx_set_pll_ge1
++				     : ar71xx_set_pll_ge0;
++		break;
++
++	case AR71XX_SOC_AR7141:
++	case AR71XX_SOC_AR7161:
++		pdata->ddr_flush = id ? ar71xx_ddr_flush_ge1
++				      : ar71xx_ddr_flush_ge0;
++		pdata->set_pll =  id ? ar71xx_set_pll_ge1
++				     : ar71xx_set_pll_ge0;
++		pdata->has_gbit = 1;
++		break;
++
++	case AR71XX_SOC_AR7241:
++	case AR71XX_SOC_AR7242:
++		ar71xx_eth0_data.reset_bit |= AR724X_RESET_GE0_MDIO;
++		ar71xx_eth1_data.reset_bit |= AR724X_RESET_GE1_MDIO;
++		/* fall through */
++	case AR71XX_SOC_AR7240:
++		pdata->ddr_flush = id ? ar724x_ddr_flush_ge1
++				      : ar724x_ddr_flush_ge0;
++		pdata->set_pll =  id ? ar724x_set_pll_ge1
++				     : ar724x_set_pll_ge0;
++		pdata->is_ar724x = 1;
++		break;
++
++	case AR71XX_SOC_AR9130:
++		pdata->ddr_flush = id ? ar91xx_ddr_flush_ge1
++				      : ar91xx_ddr_flush_ge0;
++		pdata->set_pll =  id ? ar91xx_set_pll_ge1
++				     : ar91xx_set_pll_ge0;
++		pdata->is_ar91xx = 1;
++		break;
++
++	case AR71XX_SOC_AR9132:
++		pdata->ddr_flush = id ? ar91xx_ddr_flush_ge1
++				      : ar91xx_ddr_flush_ge0;
++		pdata->set_pll =  id ? ar91xx_set_pll_ge1
++				      : ar91xx_set_pll_ge0;
++		pdata->is_ar91xx = 1;
++		pdata->has_gbit = 1;
++		break;
++
++	default:
++		BUG();
++	}
++
++	switch (pdata->phy_if_mode) {
++	case PHY_INTERFACE_MODE_GMII:
++	case PHY_INTERFACE_MODE_RGMII:
++		if (!pdata->has_gbit) {
++			printk(KERN_ERR "ar71xx: no gbit available on eth%d\n",
++					id);
++			return;
++		}
++		/* fallthrough */
++	default:
++		break;
++	}
++
++	if (is_valid_ether_addr(ar71xx_mac_base)) {
++		memcpy(pdata->mac_addr, ar71xx_mac_base, ETH_ALEN);
++		pdata->mac_addr[5] += ar71xx_eth_instance;
++	} else {
++		random_ether_addr(pdata->mac_addr);
++		printk(KERN_DEBUG
++			"ar71xx: using random MAC address for eth%d\n",
++			ar71xx_eth_instance);
++	}
++
++	if (pdata->mii_bus_dev == NULL)
++		pdata->mii_bus_dev = &ar71xx_mdio_device.dev;
++
++	/* Reset the device */
++	ar71xx_device_stop(pdata->reset_bit);
++	mdelay(100);
++
++	ar71xx_device_start(pdata->reset_bit);
++	mdelay(100);
++
++	platform_device_register(pdev);
++	ar71xx_eth_instance++;
++}
++
++static struct resource ar71xx_spi_resources[] = {
++	[0] = {
++		.start	= AR71XX_SPI_BASE,
++		.end	= AR71XX_SPI_BASE + AR71XX_SPI_SIZE - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++};
++
++static struct platform_device ar71xx_spi_device = {
++	.name		= "ar71xx-spi",
++	.id		= -1,
++	.resource	= ar71xx_spi_resources,
++	.num_resources	= ARRAY_SIZE(ar71xx_spi_resources),
++};
++
++void __init ar71xx_add_device_spi(struct ar71xx_spi_platform_data *pdata,
++				struct spi_board_info const *info,
++				unsigned n)
++{
++	spi_register_board_info(info, n);
++	ar71xx_spi_device.dev.platform_data = pdata;
++	platform_device_register(&ar71xx_spi_device);
++}
++
++void __init ar71xx_add_device_wdt(void)
++{
++	platform_device_register_simple("ar71xx-wdt", -1, NULL, 0);
++}
++
++void __init ar71xx_set_mac_base(unsigned char *mac)
++{
++	memcpy(ar71xx_mac_base, mac, ETH_ALEN);
++}
++
++void __init ar71xx_parse_mac_addr(char *mac_str)
++{
++	u8 tmp[ETH_ALEN];
++	int t;
++
++	t = sscanf(mac_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
++			&tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]);
++
++	if (t != ETH_ALEN)
++		t = sscanf(mac_str, "%02hhx.%02hhx.%02hhx.%02hhx.%02hhx.%02hhx",
++			&tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]);
++
++	if (t == ETH_ALEN)
++		ar71xx_set_mac_base(tmp);
++	else
++		printk(KERN_DEBUG "ar71xx: failed to parse mac address "
++				"\"%s\"\n", mac_str);
++}
++
++static int __init ar71xx_ethaddr_setup(char *str)
++{
++	ar71xx_parse_mac_addr(str);
++	return 1;
++}
++__setup("ethaddr=", ar71xx_ethaddr_setup);
++
++static int __init ar71xx_kmac_setup(char *str)
++{
++	ar71xx_parse_mac_addr(str);
++	return 1;
++}
++__setup("kmac=", ar71xx_kmac_setup);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/devices.h linux-2.6.33.3/arch/mips/ar71xx/devices.h
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/devices.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/devices.h	2010-01-05 20:38:52.093279648 +0100
+@@ -0,0 +1,48 @@
++/*
++ *  Atheros AR71xx SoC device definitions
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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.
++ */
++
++#ifndef __AR71XX_DEVICES_H
++#define __AR71XX_DEVICES_H
++
++#include <asm/mach-ar71xx/platform.h>
++
++struct platform_device;
++
++void ar71xx_add_device_spi(struct ar71xx_spi_platform_data *pdata,
++			   struct spi_board_info const *info,
++			   unsigned n) __init;
++
++void ar71xx_set_mac_base(unsigned char *mac) __init;
++void ar71xx_parse_mac_addr(char *mac_str) __init;
++
++struct ar71xx_eth_pll_data {
++	u32	pll_10;
++	u32	pll_100;
++	u32	pll_1000;
++};
++
++extern struct ar71xx_eth_pll_data ar71xx_eth0_pll_data;
++extern struct ar71xx_eth_pll_data ar71xx_eth1_pll_data;
++
++extern struct ag71xx_platform_data ar71xx_eth0_data;
++extern struct ag71xx_platform_data ar71xx_eth1_data;
++extern struct platform_device ar71xx_eth0_device;
++extern struct platform_device ar71xx_eth1_device;
++void ar71xx_add_device_eth(unsigned int id) __init;
++
++extern struct platform_device ar71xx_mdio_device;
++void ar71xx_add_device_mdio(u32 phy_mask) __init;
++
++void ar71xx_add_device_uart(void) __init;
++
++void ar71xx_add_device_wdt(void) __init;
++
++#endif /* __AR71XX_DEVICES_H */
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/dev-leds-gpio.c linux-2.6.33.3/arch/mips/ar71xx/dev-leds-gpio.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/dev-leds-gpio.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/dev-leds-gpio.c	2010-01-05 20:38:51.933280770 +0100
+@@ -0,0 +1,56 @@
++/*
++ *  Atheros AR71xx GPIO LED device support
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ *  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/init.h>
++#include <linux/platform_device.h>
++
++#include "dev-leds-gpio.h"
++
++void __init ar71xx_add_device_leds_gpio(int id, unsigned num_leds,
++					struct gpio_led *leds)
++{
++	struct platform_device *pdev;
++	struct gpio_led_platform_data pdata;
++	struct gpio_led *p;
++	int err;
++
++	p = kmalloc(num_leds * sizeof(*p), GFP_KERNEL);
++	if (!p)
++		return;
++
++	memcpy(p, leds, num_leds * sizeof(*p));
++
++	pdev = platform_device_alloc("leds-gpio", id);
++	if (!pdev)
++		goto err_free_leds;
++
++	memset(&pdata, 0, sizeof(pdata));
++	pdata.num_leds = num_leds;
++	pdata.leds = p;
++
++	err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
++	if (err)
++		goto err_put_pdev;
++
++	err = platform_device_add(pdev);
++	if (err)
++		goto err_put_pdev;
++
++	return;
++
++err_put_pdev:
++	platform_device_put(pdev);
++
++err_free_leds:
++	kfree(p);
++}
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/dev-leds-gpio.h linux-2.6.33.3/arch/mips/ar71xx/dev-leds-gpio.h
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/dev-leds-gpio.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/dev-leds-gpio.h	2010-01-05 20:38:51.937279883 +0100
+@@ -0,0 +1,21 @@
++/*
++ *  Atheros AR71xx GPIO LED device support
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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.
++ */
++
++#ifndef _AR71XX_DEV_LEDS_GPIO_H
++#define _AR71XX_DEV_LEDS_GPIO_H
++
++#include <linux/leds.h>
++
++void ar71xx_add_device_leds_gpio(int id,
++				 unsigned num_leds,
++				 struct gpio_led *leds) __init;
++
++#endif /* _AR71XX_DEV_LEDS_GPIO_H */
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/dev-m25p80.c linux-2.6.33.3/arch/mips/ar71xx/dev-m25p80.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/dev-m25p80.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/dev-m25p80.c	2009-12-25 12:10:59.660426865 +0100
+@@ -0,0 +1,30 @@
++/*
++ *  Copyright (C) 2009 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/init.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/flash.h>
++
++#include "devices.h"
++#include "dev-m25p80.h"
++
++static struct spi_board_info ar71xx_spi_info[] = {
++	{
++		.bus_num	= 0,
++		.chip_select	= 0,
++		.max_speed_hz	= 25000000,
++		.modalias	= "m25p80",
++	}
++};
++
++void __init ar71xx_add_device_m25p80(struct flash_platform_data *pdata)
++{
++	ar71xx_spi_info[0].platform_data = pdata;
++	ar71xx_add_device_spi(NULL, ar71xx_spi_info,
++			      ARRAY_SIZE(ar71xx_spi_info));
++}
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/dev-m25p80.h linux-2.6.33.3/arch/mips/ar71xx/dev-m25p80.h
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/dev-m25p80.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/dev-m25p80.h	2009-12-25 12:10:59.660426865 +0100
+@@ -0,0 +1,16 @@
++/*
++ *  Copyright (C) 2009 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.
++ */
++
++#ifndef _AR71XX_DEV_M25P80_H
++#define _AR71XX_DEV_M25P80_H
++
++#include <linux/spi/flash.h>
++
++void ar71xx_add_device_m25p80(struct flash_platform_data *pdata) __init;
++
++#endif /* _AR71XX_DEV_M25P80_H */
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/dev-pb42-pci.c linux-2.6.33.3/arch/mips/ar71xx/dev-pb42-pci.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/dev-pb42-pci.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/dev-pb42-pci.c	2010-01-05 20:38:52.185278525 +0100
+@@ -0,0 +1,40 @@
++/*
++ *  Atheros PB42 reference board PCI initialization
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ *  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/pci.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/pci.h>
++
++#include "dev-pb42-pci.h"
++
++static struct ar71xx_pci_irq pb42_pci_irqs[] __initdata = {
++	{
++		.slot	= 0,
++		.pin	= 1,
++		.irq	= AR71XX_PCI_IRQ_DEV0,
++	}, {
++		.slot	= 1,
++		.pin	= 1,
++		.irq	= AR71XX_PCI_IRQ_DEV1,
++	}, {
++		.slot	= 2,
++		.pin	= 1,
++		.irq	= AR71XX_PCI_IRQ_DEV2,
++	}
++};
++
++void __init pb42_pci_init(void)
++{
++	ar71xx_pci_init(ARRAY_SIZE(pb42_pci_irqs), pb42_pci_irqs);
++}
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/dev-pb42-pci.h linux-2.6.33.3/arch/mips/ar71xx/dev-pb42-pci.h
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/dev-pb42-pci.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/dev-pb42-pci.h	2010-01-05 20:38:52.217277854 +0100
+@@ -0,0 +1,21 @@
++/*
++ *  Atheros PB42 reference board PCI initialization
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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.
++ */
++
++#ifndef _AR71XX_DEV_PB42_PCI_H
++#define _AR71XX_DEV_PB42_PCI_H
++
++#if defined(CONFIG_AR71XX_DEV_PB42_PCI)
++void pb42_pci_init(void) __init;
++#else
++static inline void pb42_pci_init(void) { }
++#endif
++
++#endif /* _AR71XX_DEV_PB42_PCI_H */
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/dev-pb9x-pci.c linux-2.6.33.3/arch/mips/ar71xx/dev-pb9x-pci.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/dev-pb9x-pci.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/dev-pb9x-pci.c	2010-04-02 11:07:51.650955594 +0200
+@@ -0,0 +1,33 @@
++/*
++ *  Atheros PB9x reference board PCI initialization
++ *
++ *  Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ *  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/pci.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/pci.h>
++
++#include "dev-pb9x-pci.h"
++
++static struct ar71xx_pci_irq pb9x_pci_irqs[] __initdata = {
++	{
++		.slot	= 0,
++		.pin	= 1,
++		.irq	= AR71XX_PCI_IRQ_DEV0,
++	}
++};
++
++void __init pb9x_pci_init(void)
++{
++	ar71xx_pci_init(ARRAY_SIZE(pb9x_pci_irqs), pb9x_pci_irqs);
++}
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/dev-pb9x-pci.h linux-2.6.33.3/arch/mips/ar71xx/dev-pb9x-pci.h
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/dev-pb9x-pci.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/dev-pb9x-pci.h	2010-04-02 11:07:51.654953031 +0200
+@@ -0,0 +1,22 @@
++/*
++ *  Atheros PB9x reference board PCI initialization
++ *
++ *  Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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.
++ */
++
++#ifndef _AR71XX_DEV_PB9X_PCI_H
++#define _AR71XX_DEV_PB9X_PCI_H
++
++#if defined(CONFIG_AR71XX_DEV_PB9X_PCI)
++void pb9x_pci_init(void) __init;
++#else
++static inline void pb9x_pci_init(void) { }
++#endif
++
++#endif /* _AR71XX_DEV_PB9X_PCI_H */
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/dev-usb.c linux-2.6.33.3/arch/mips/ar71xx/dev-usb.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/dev-usb.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/dev-usb.c	2010-04-02 11:07:51.694953375 +0200
+@@ -0,0 +1,181 @@
++/*
++ *  Atheros AR71xx USB host device support
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ *  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/init.h>
++#include <linux/delay.h>
++#include <linux/dma-mapping.h>
++#include <linux/platform_device.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/platform.h>
++
++#include "dev-usb.h"
++
++/*
++ * OHCI (USB full speed host controller)
++ */
++static struct resource ar71xx_ohci_resources[] = {
++	[0] = {
++		.start	= AR71XX_OHCI_BASE,
++		.end	= AR71XX_OHCI_BASE + AR71XX_OHCI_SIZE - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AR71XX_MISC_IRQ_OHCI,
++		.end	= AR71XX_MISC_IRQ_OHCI,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct resource ar7240_ohci_resources[] = {
++	[0] = {
++		.start	= AR7240_OHCI_BASE,
++		.end	= AR7240_OHCI_BASE + AR7240_OHCI_SIZE - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AR71XX_CPU_IRQ_USB,
++		.end	= AR71XX_CPU_IRQ_USB,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static u64 ar71xx_ohci_dmamask = DMA_BIT_MASK(32);
++static struct platform_device ar71xx_ohci_device = {
++	.name		= "ar71xx-ohci",
++	.id		= -1,
++	.resource	= ar71xx_ohci_resources,
++	.num_resources	= ARRAY_SIZE(ar71xx_ohci_resources),
++	.dev = {
++		.dma_mask		= &ar71xx_ohci_dmamask,
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++};
++
++/*
++ * EHCI (USB full speed host controller)
++ */
++static struct resource ar71xx_ehci_resources[] = {
++	[0] = {
++		.start	= AR71XX_EHCI_BASE,
++		.end	= AR71XX_EHCI_BASE + AR71XX_EHCI_SIZE - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AR71XX_CPU_IRQ_USB,
++		.end	= AR71XX_CPU_IRQ_USB,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static u64 ar71xx_ehci_dmamask = DMA_BIT_MASK(32);
++static struct ar71xx_ehci_platform_data ar71xx_ehci_data;
++
++static struct platform_device ar71xx_ehci_device = {
++	.name		= "ar71xx-ehci",
++	.id		= -1,
++	.resource	= ar71xx_ehci_resources,
++	.num_resources	= ARRAY_SIZE(ar71xx_ehci_resources),
++	.dev = {
++		.dma_mask		= &ar71xx_ehci_dmamask,
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++		.platform_data		= &ar71xx_ehci_data,
++	},
++};
++
++#define AR71XX_USB_RESET_MASK \
++	(RESET_MODULE_USB_HOST | RESET_MODULE_USB_PHY \
++	| RESET_MODULE_USB_OHCI_DLL)
++
++#define AR7240_USB_RESET_MASK \
++	(RESET_MODULE_USB_HOST | RESET_MODULE_USB_OHCI_DLL_7240)
++
++static void __init ar71xx_usb_setup(void)
++{
++	ar71xx_device_stop(AR71XX_USB_RESET_MASK);
++	mdelay(1000);
++	ar71xx_device_start(AR71XX_USB_RESET_MASK);
++
++	/* Turning on the Buff and Desc swap bits */
++	ar71xx_usb_ctrl_wr(USB_CTRL_REG_CONFIG, 0xf0000);
++
++	/* WAR for HW bug. Here it adjusts the duration between two SOFS */
++	ar71xx_usb_ctrl_wr(USB_CTRL_REG_FLADJ, 0x20c00);
++
++	mdelay(900);
++
++	platform_device_register(&ar71xx_ohci_device);
++	platform_device_register(&ar71xx_ehci_device);
++}
++
++static void __init ar7240_usb_setup(void)
++{
++	ar71xx_device_stop(AR7240_USB_RESET_MASK);
++	mdelay(1000);
++	ar71xx_device_start(AR7240_USB_RESET_MASK);
++
++	/* WAR for HW bug. Here it adjusts the duration between two SOFS */
++	ar71xx_usb_ctrl_wr(USB_CTRL_REG_FLADJ, 0x3);
++
++	if (ar71xx_soc == AR71XX_SOC_AR7241 || ar71xx_soc == AR71XX_SOC_AR7242) {
++		ar71xx_ehci_data.is_ar91xx = 1;
++		ar71xx_ehci_device.resource = ar7240_ohci_resources;
++		ar71xx_ehci_device.num_resources = ARRAY_SIZE(ar7240_ohci_resources);
++		platform_device_register(&ar71xx_ehci_device);
++	} else {
++		ar71xx_ohci_device.resource = ar7240_ohci_resources;
++		ar71xx_ohci_device.num_resources = ARRAY_SIZE(ar7240_ohci_resources);
++		platform_device_register(&ar71xx_ohci_device);
++	}
++}
++
++static void __init ar91xx_usb_setup(void)
++{
++	ar71xx_device_stop(RESET_MODULE_USBSUS_OVERRIDE);
++	mdelay(10);
++
++	ar71xx_device_start(RESET_MODULE_USB_HOST);
++	mdelay(10);
++
++	ar71xx_device_start(RESET_MODULE_USB_PHY);
++	mdelay(10);
++
++	ar71xx_ehci_data.is_ar91xx = 1;
++	platform_device_register(&ar71xx_ehci_device);
++}
++
++void __init ar71xx_add_device_usb(void)
++{
++	switch (ar71xx_soc) {
++	case AR71XX_SOC_AR7240:
++	case AR71XX_SOC_AR7241:
++	case AR71XX_SOC_AR7242:
++		ar7240_usb_setup();
++		break;
++
++	case AR71XX_SOC_AR7130:
++	case AR71XX_SOC_AR7141:
++	case AR71XX_SOC_AR7161:
++		ar71xx_usb_setup();
++		break;
++
++	case AR71XX_SOC_AR9130:
++	case AR71XX_SOC_AR9132:
++		ar91xx_usb_setup();
++		break;
++
++	default:
++		BUG();
++	}
++}
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/dev-usb.h linux-2.6.33.3/arch/mips/ar71xx/dev-usb.h
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/dev-usb.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/dev-usb.h	2010-01-05 20:38:52.326200390 +0100
+@@ -0,0 +1,17 @@
++/*
++ *  Atheros AR71xx USB host device support
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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.
++ */
++
++#ifndef _AR71XX_DEV_USB_H
++#define _AR71XX_DEV_USB_H
++
++void ar71xx_add_device_usb(void) __init;
++
++#endif /* _AR71XX_DEV_USB_H */
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/early_printk.c linux-2.6.33.3/arch/mips/ar71xx/early_printk.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/early_printk.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/early_printk.c	2009-12-13 20:45:21.280039916 +0100
+@@ -0,0 +1,30 @@
++/*
++ *  Atheros AR71xx SoC early printk support
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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/io.h>
++#include <linux/serial_reg.h>
++#include <asm/addrspace.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#define UART_READ(r) \
++	__raw_readl((void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE) + 4 * (r)))
++
++#define UART_WRITE(r, v) \
++	__raw_writel((v), (void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE) + 4*(r)))
++
++void prom_putchar(unsigned char ch)
++{
++	while (((UART_READ(UART_LSR)) & UART_LSR_THRE) == 0);
++	UART_WRITE(UART_TX, ch);
++	while (((UART_READ(UART_LSR)) & UART_LSR_THRE) == 0);
++}
++
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/gpio.c linux-2.6.33.3/arch/mips/ar71xx/gpio.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/gpio.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/gpio.c	2010-04-02 11:07:51.646954247 +0200
+@@ -0,0 +1,182 @@
++/*
++ *  Atheros AR71xx SoC GPIO API support
++ *
++ *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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/init.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/spinlock.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/gpio.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++static DEFINE_SPINLOCK(ar71xx_gpio_lock);
++
++unsigned long ar71xx_gpio_count;
++EXPORT_SYMBOL(ar71xx_gpio_count);
++
++void __ar71xx_gpio_set_value(unsigned gpio, int value)
++{
++	void __iomem *base = ar71xx_gpio_base;
++
++	if (value)
++		__raw_writel(1 << gpio, base + GPIO_REG_SET);
++	else
++		__raw_writel(1 << gpio, base + GPIO_REG_CLEAR);
++}
++EXPORT_SYMBOL(__ar71xx_gpio_set_value);
++
++int __ar71xx_gpio_get_value(unsigned gpio)
++{
++	return (__raw_readl(ar71xx_gpio_base + GPIO_REG_IN) >> gpio) & 1;
++}
++EXPORT_SYMBOL(__ar71xx_gpio_get_value);
++
++static int ar71xx_gpio_get_value(struct gpio_chip *chip, unsigned offset)
++{
++	return __ar71xx_gpio_get_value(offset);
++}
++
++static void ar71xx_gpio_set_value(struct gpio_chip *chip,
++				  unsigned offset, int value)
++{
++	__ar71xx_gpio_set_value(offset, value);
++}
++
++static int ar71xx_gpio_direction_input(struct gpio_chip *chip,
++				       unsigned offset)
++{
++	void __iomem *base = ar71xx_gpio_base;
++	unsigned long flags;
++
++	spin_lock_irqsave(&ar71xx_gpio_lock, flags);
++
++	__raw_writel(__raw_readl(base + GPIO_REG_OE) & ~(1 << offset),
++		     base + GPIO_REG_OE);
++
++	spin_unlock_irqrestore(&ar71xx_gpio_lock, flags);
++
++	return 0;
++}
++
++static int ar71xx_gpio_direction_output(struct gpio_chip *chip,
++					unsigned offset, int value)
++{
++	void __iomem *base = ar71xx_gpio_base;
++	unsigned long flags;
++
++	spin_lock_irqsave(&ar71xx_gpio_lock, flags);
++
++	if (value)
++		__raw_writel(1 << offset, base + GPIO_REG_SET);
++	else
++		__raw_writel(1 << offset, base + GPIO_REG_CLEAR);
++
++	__raw_writel(__raw_readl(base + GPIO_REG_OE) | (1 << offset),
++		     base + GPIO_REG_OE);
++
++	spin_unlock_irqrestore(&ar71xx_gpio_lock, flags);
++
++	return 0;
++}
++
++static struct gpio_chip ar71xx_gpio_chip = {
++	.label			= "ar71xx",
++	.get			= ar71xx_gpio_get_value,
++	.set			= ar71xx_gpio_set_value,
++	.direction_input	= ar71xx_gpio_direction_input,
++	.direction_output	= ar71xx_gpio_direction_output,
++	.base			= 0,
++	.ngpio			= AR71XX_GPIO_COUNT,
++};
++
++void ar71xx_gpio_function_enable(u32 mask)
++{
++	void __iomem *base = ar71xx_gpio_base;
++	unsigned long flags;
++
++	spin_lock_irqsave(&ar71xx_gpio_lock, flags);
++
++	__raw_writel(__raw_readl(base + GPIO_REG_FUNC) | mask,
++		     base + GPIO_REG_FUNC);
++	/* flush write */
++	(void) __raw_readl(base + GPIO_REG_FUNC);
++
++	spin_unlock_irqrestore(&ar71xx_gpio_lock, flags);
++}
++
++void ar71xx_gpio_function_disable(u32 mask)
++{
++	void __iomem *base = ar71xx_gpio_base;
++	unsigned long flags;
++
++	spin_lock_irqsave(&ar71xx_gpio_lock, flags);
++
++	__raw_writel(__raw_readl(base + GPIO_REG_FUNC) & ~mask,
++		     base + GPIO_REG_FUNC);
++	/* flush write */
++	(void) __raw_readl(base + GPIO_REG_FUNC);
++
++	spin_unlock_irqrestore(&ar71xx_gpio_lock, flags);
++}
++
++void ar71xx_gpio_function_setup(u32 set, u32 clear)
++{
++	void __iomem *base = ar71xx_gpio_base;
++	unsigned long flags;
++
++	spin_lock_irqsave(&ar71xx_gpio_lock, flags);
++
++	__raw_writel((__raw_readl(base + GPIO_REG_FUNC) & ~clear) | set,
++		     base + GPIO_REG_FUNC);
++	/* flush write */
++	(void) __raw_readl(base + GPIO_REG_FUNC);
++
++	spin_unlock_irqrestore(&ar71xx_gpio_lock, flags);
++}
++EXPORT_SYMBOL(ar71xx_gpio_function_setup);
++
++void __init ar71xx_gpio_init(void)
++{
++	int err;
++
++	if (!request_mem_region(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE,
++				"AR71xx GPIO controller"))
++		panic("cannot allocate AR71xx GPIO registers page");
++
++	switch (ar71xx_soc) {
++	case AR71XX_SOC_AR7130:
++	case AR71XX_SOC_AR7141:
++	case AR71XX_SOC_AR7161:
++		ar71xx_gpio_chip.ngpio = AR71XX_GPIO_COUNT;
++		break;
++
++	case AR71XX_SOC_AR7240:
++	case AR71XX_SOC_AR7241:
++	case AR71XX_SOC_AR7242:
++		ar71xx_gpio_chip.ngpio = AR724X_GPIO_COUNT;
++		break;
++
++	case AR71XX_SOC_AR9130:
++	case AR71XX_SOC_AR9132:
++		ar71xx_gpio_chip.ngpio = AR91XX_GPIO_COUNT;
++		break;
++
++	default:
++		BUG();
++	}
++
++	err = gpiochip_add(&ar71xx_gpio_chip);
++	if (err)
++		panic("cannot add AR71xx GPIO chip, error=%d", err);
++}
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/irq.c linux-2.6.33.3/arch/mips/ar71xx/irq.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/irq.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/irq.c	2010-05-16 13:17:31.871599360 +0200
+@@ -0,0 +1,295 @@
++/*
++ *  Atheros AR71xx SoC specific interrupt handling
++ *
++ *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ *  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/init.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++
++#include <asm/irq_cpu.h>
++#include <asm/mipsregs.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++static int ip2_flush_reg;
++
++static void ar71xx_gpio_irq_dispatch(void)
++{
++	void __iomem *base = ar71xx_gpio_base;
++	u32 pending;
++
++	pending = __raw_readl(base + GPIO_REG_INT_PENDING) &
++		  __raw_readl(base + GPIO_REG_INT_ENABLE);
++
++	if (pending)
++		do_IRQ(AR71XX_GPIO_IRQ_BASE + fls(pending) - 1);
++	else
++		spurious_interrupt();
++}
++
++static void ar71xx_gpio_irq_unmask(unsigned int irq)
++{
++	void __iomem *base = ar71xx_gpio_base;
++	u32 t;
++
++	irq -= AR71XX_GPIO_IRQ_BASE;
++
++	t = __raw_readl(base + GPIO_REG_INT_ENABLE);
++	__raw_writel(t | (1 << irq), base + GPIO_REG_INT_ENABLE);
++
++	/* flush write */
++	(void) __raw_readl(base + GPIO_REG_INT_ENABLE);
++}
++
++static void ar71xx_gpio_irq_mask(unsigned int irq)
++{
++	void __iomem *base = ar71xx_gpio_base;
++	u32 t;
++
++	irq -= AR71XX_GPIO_IRQ_BASE;
++
++	t = __raw_readl(base + GPIO_REG_INT_ENABLE);
++	__raw_writel(t & ~(1 << irq), base + GPIO_REG_INT_ENABLE);
++
++	/* flush write */
++	(void) __raw_readl(base + GPIO_REG_INT_ENABLE);
++}
++
++#if 0
++static int ar71xx_gpio_irq_set_type(unsigned int irq, unsigned int flow_type)
++{
++	/* TODO: implement */
++	return 0;
++}
++#else
++#define ar71xx_gpio_irq_set_type	NULL
++#endif
++
++static struct irq_chip ar71xx_gpio_irq_chip = {
++	.name		= "AR71XX GPIO",
++	.unmask		= ar71xx_gpio_irq_unmask,
++	.mask		= ar71xx_gpio_irq_mask,
++	.mask_ack	= ar71xx_gpio_irq_mask,
++	.set_type	= ar71xx_gpio_irq_set_type,
++};
++
++static struct irqaction ar71xx_gpio_irqaction = {
++	.handler	= no_action,
++	.name		= "cascade [AR71XX GPIO]",
++};
++
++#define GPIO_IRQ_INIT_STATUS (IRQ_LEVEL | IRQ_TYPE_LEVEL_HIGH | IRQ_DISABLED)
++#define GPIO_INT_ALL	0xffff
++
++static void __init ar71xx_gpio_irq_init(void)
++{
++	void __iomem *base = ar71xx_gpio_base;
++	int i;
++
++	__raw_writel(0, base + GPIO_REG_INT_ENABLE);
++	__raw_writel(0, base + GPIO_REG_INT_PENDING);
++
++	/* setup type of all GPIO interrupts to level sensitive */
++	__raw_writel(GPIO_INT_ALL, base + GPIO_REG_INT_TYPE);
++
++	/* setup polarity of all GPIO interrupts to active high */
++	__raw_writel(GPIO_INT_ALL, base + GPIO_REG_INT_POLARITY);
++
++	for (i = AR71XX_GPIO_IRQ_BASE;
++	     i < AR71XX_GPIO_IRQ_BASE + AR71XX_GPIO_IRQ_COUNT; i++) {
++		irq_desc[i].status = GPIO_IRQ_INIT_STATUS;
++		set_irq_chip_and_handler(i, &ar71xx_gpio_irq_chip,
++					 handle_level_irq);
++	}
++
++	setup_irq(AR71XX_MISC_IRQ_GPIO, &ar71xx_gpio_irqaction);
++}
++
++static void ar71xx_misc_irq_dispatch(void)
++{
++	u32 pending;
++
++	pending = ar71xx_reset_rr(AR71XX_RESET_REG_MISC_INT_STATUS)
++	    & ar71xx_reset_rr(AR71XX_RESET_REG_MISC_INT_ENABLE);
++
++	if (pending & MISC_INT_UART)
++		do_IRQ(AR71XX_MISC_IRQ_UART);
++
++	else if (pending & MISC_INT_DMA)
++		do_IRQ(AR71XX_MISC_IRQ_DMA);
++
++	else if (pending & MISC_INT_PERFC)
++		do_IRQ(AR71XX_MISC_IRQ_PERFC);
++
++	else if (pending & MISC_INT_TIMER)
++		do_IRQ(AR71XX_MISC_IRQ_TIMER);
++
++	else if (pending & MISC_INT_OHCI)
++		do_IRQ(AR71XX_MISC_IRQ_OHCI);
++
++	else if (pending & MISC_INT_ERROR)
++		do_IRQ(AR71XX_MISC_IRQ_ERROR);
++
++	else if (pending & MISC_INT_GPIO)
++		ar71xx_gpio_irq_dispatch();
++
++	else if (pending & MISC_INT_WDOG)
++		do_IRQ(AR71XX_MISC_IRQ_WDOG);
++
++	else
++		spurious_interrupt();
++}
++
++static void ar71xx_misc_irq_unmask(unsigned int irq)
++{
++	void __iomem *base = ar71xx_reset_base;
++	u32 t;
++
++	irq -= AR71XX_MISC_IRQ_BASE;
++
++	t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
++	__raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
++
++	/* flush write */
++	(void) __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
++}
++
++static void ar71xx_misc_irq_mask(unsigned int irq)
++{
++	void __iomem *base = ar71xx_reset_base;
++	u32 t;
++
++	irq -= AR71XX_MISC_IRQ_BASE;
++
++	t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
++	__raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
++
++	/* flush write */
++	(void) __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
++}
++
++static void ar724x_misc_irq_ack(unsigned int irq)
++{
++	void __iomem *base = ar71xx_reset_base;
++	u32 t;
++
++	irq -= AR71XX_MISC_IRQ_BASE;
++
++	t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS);
++	__raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_STATUS);
++
++	/* flush write */
++	(void) __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS);
++}
++
++static struct irq_chip ar71xx_misc_irq_chip = {
++	.name		= "AR71XX MISC",
++	.unmask		= ar71xx_misc_irq_unmask,
++	.mask		= ar71xx_misc_irq_mask,
++};
++
++static struct irqaction ar71xx_misc_irqaction = {
++	.handler	= no_action,
++	.name		= "cascade [AR71XX MISC]",
++};
++
++static void __init ar71xx_misc_irq_init(void)
++{
++	void __iomem *base = ar71xx_reset_base;
++	int i;
++
++	__raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_ENABLE);
++	__raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_STATUS);
++
++	switch (ar71xx_soc) {
++	case AR71XX_SOC_AR7240:
++	case AR71XX_SOC_AR7241:
++	case AR71XX_SOC_AR7242:
++		ar71xx_misc_irq_chip.ack = ar724x_misc_irq_ack;
++		break;
++	default:
++		ar71xx_misc_irq_chip.mask_ack = ar71xx_misc_irq_mask;
++		break;
++	}
++
++	for (i = AR71XX_MISC_IRQ_BASE;
++	     i < AR71XX_MISC_IRQ_BASE + AR71XX_MISC_IRQ_COUNT; i++) {
++		irq_desc[i].status = IRQ_DISABLED;
++		set_irq_chip_and_handler(i, &ar71xx_misc_irq_chip,
++					 handle_level_irq);
++	}
++
++	setup_irq(AR71XX_CPU_IRQ_MISC, &ar71xx_misc_irqaction);
++}
++
++asmlinkage void plat_irq_dispatch(void)
++{
++	unsigned long pending;
++
++	pending = read_c0_status() & read_c0_cause() & ST0_IM;
++
++	if (pending & STATUSF_IP7)
++		do_IRQ(AR71XX_CPU_IRQ_TIMER);
++
++	else if (pending & STATUSF_IP2) {
++		/*
++		 * This IRQ is meant for a PCI device. Drivers for PCI devices
++		 * typically allocate coherent DMA memory for the descriptor
++		 * ring, however the DMA controller may still have some
++		 * unsynchronized data in the FIFO.
++		 * Issue a flush here to ensure that the driver sees the update.
++		 */
++		ar71xx_ddr_flush(ip2_flush_reg);
++		do_IRQ(AR71XX_CPU_IRQ_IP2);
++	}
++
++	else if (pending & STATUSF_IP4)
++		do_IRQ(AR71XX_CPU_IRQ_GE0);
++
++	else if (pending & STATUSF_IP5)
++		do_IRQ(AR71XX_CPU_IRQ_GE1);
++
++	else if (pending & STATUSF_IP3)
++		do_IRQ(AR71XX_CPU_IRQ_USB);
++
++	else if (pending & STATUSF_IP6)
++		ar71xx_misc_irq_dispatch();
++
++	else
++		spurious_interrupt();
++}
++
++void __init arch_init_irq(void)
++{
++	switch(ar71xx_soc) {
++	case AR71XX_SOC_AR7240:
++	case AR71XX_SOC_AR7241:
++	case AR71XX_SOC_AR7242:
++		ip2_flush_reg = AR724X_DDR_REG_FLUSH_PCIE;
++		break;
++	case AR71XX_SOC_AR9130:
++	case AR71XX_SOC_AR9132:
++		ip2_flush_reg = AR91XX_DDR_REG_FLUSH_WMAC;
++		break;
++	default:
++		ip2_flush_reg = AR71XX_DDR_REG_FLUSH_PCI;
++		break;
++	}
++	mips_cpu_irq_init();
++
++	ar71xx_misc_irq_init();
++
++	cp0_perfcount_irq = AR71XX_MISC_IRQ_PERFC;
++
++	ar71xx_gpio_irq_init();
++}
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/Kconfig linux-2.6.33.3/arch/mips/ar71xx/Kconfig
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/Kconfig	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/Kconfig	2010-05-16 13:17:31.779600220 +0200
+@@ -0,0 +1,264 @@
++if ATHEROS_AR71XX
++
++menu "Atheros AR71xx machine selection"
++
++config AR71XX_MACH_AP81
++	bool "Atheros AP81 board support"
++	select AR71XX_DEV_M25P80
++	select AR71XX_DEV_AR913X_WMAC
++	select AR71XX_DEV_GPIO_BUTTONS
++	select AR71XX_DEV_LEDS_GPIO
++	select AR71XX_DEV_USB
++	default n
++
++config AR71XX_MACH_AP83
++	bool "Atheros AP83 board support"
++	select AR71XX_DEV_AR913X_WMAC
++	select AR71XX_DEV_GPIO_BUTTONS
++	select AR71XX_DEV_LEDS_GPIO
++	select AR71XX_DEV_USB
++	default n
++
++config AR71XX_MACH_DIR_600_A1
++	bool "D-Link DIR-600 rev. A1 support"
++	select AR71XX_DEV_AP91_ETH
++	select AR71XX_DEV_AP91_PCI if PCI
++	select AR71XX_DEV_M25P80
++	select AR71XX_DEV_GPIO_BUTTONS
++	select AR71XX_DEV_LEDS_GPIO
++	select AR71XX_NVRAM
++	default n
++
++config AR71XX_MACH_DIR_615_C1
++	bool "D-Link DIR-615 rev. C1 support"
++	select AR71XX_DEV_M25P80
++	select AR71XX_DEV_AR913X_WMAC
++	select AR71XX_DEV_GPIO_BUTTONS
++	select AR71XX_DEV_LEDS_GPIO
++	select AR71XX_NVRAM
++	default n
++
++config AR71XX_MACH_DIR_825_B1
++	bool "D-Link DIR-825 rev. B1 board support"
++	select AR71XX_DEV_M25P80
++	select AR71XX_DEV_AP94_PCI if PCI
++	select AR71XX_DEV_GPIO_BUTTONS
++	select AR71XX_DEV_LEDS_GPIO
++	select AR71XX_DEV_USB
++	default n
++
++config AR71XX_MACH_PB42
++	bool "Atheros PB42 board support"
++	select AR71XX_DEV_M25P80
++	select AR71XX_DEV_GPIO_BUTTONS
++	select AR71XX_DEV_PB42_PCI if PCI
++	default n
++
++config AR71XX_MACH_PB44
++	bool "Atheros PB44 board support"
++	select AR71XX_DEV_GPIO_BUTTONS
++	select AR71XX_DEV_PB42_PCI if PCI
++	select AR71XX_DEV_LEDS_GPIO
++	select AR71XX_DEV_USB
++	default n
++
++config AR71XX_MACH_PB92
++	bool "Atheros PB92 board support"
++	select AR71XX_DEV_GPIO_BUTTONS
++	select AR71XX_DEV_PB9X_PCI if PCI
++	select AR71XX_DEV_LEDS_GPIO
++	select AR71XX_DEV_USB
++	default n
++
++config AR71XX_MACH_AW_NR580
++	bool "AzureWave AW-NR580 board support"
++	select AR71XX_DEV_M25P80
++	select AR71XX_DEV_GPIO_BUTTONS
++	select AR71XX_DEV_PB42_PCI if PCI
++	select AR71XX_DEV_LEDS_GPIO
++	default n
++
++config AR71XX_MACH_WZR_HP_G300NH
++	bool "Buffalo WZR-HP-G300NH board support"
++	select AR71XX_DEV_AR913X_WMAC
++	select AR71XX_DEV_GPIO_BUTTONS
++	select AR71XX_DEV_LEDS_GPIO
++	select AR71XX_DEV_USB
++	default y
++
++config AR71XX_MACH_WP543
++	bool "Compex WP543/WPJ543 board support"
++	select MYLOADER
++	select AR71XX_DEV_M25P80
++	select AR71XX_DEV_GPIO_BUTTONS
++	select AR71XX_DEV_PB42_PCI if PCI
++	select AR71XX_DEV_LEDS_GPIO
++	select AR71XX_DEV_USB
++	default n
++
++config AR71XX_MACH_WRT160NL
++	bool "Linksys WRT160NL board support"
++	select AR71XX_DEV_M25P80
++	select AR71XX_DEV_AR913X_WMAC
++	select AR71XX_DEV_GPIO_BUTTONS
++	select AR71XX_DEV_LEDS_GPIO
++	select AR71XX_DEV_USB
++	select AR71XX_NVRAM
++	default n
++
++config AR71XX_MACH_WRT400N
++	bool "Linksys WRT400N board support"
++	select AR71XX_DEV_AP94_PCI if PCI
++	select AR71XX_DEV_M25P80
++	select AR71XX_DEV_GPIO_BUTTONS
++	select AR71XX_DEV_LEDS_GPIO
++	default n
++
++config AR71XX_MACH_RB4XX
++	bool "MikroTik RouterBOARD 4xx series support"
++	select AR71XX_DEV_GPIO_BUTTONS
++	select AR71XX_DEV_LEDS_GPIO
++	select AR71XX_DEV_USB
++	default n
++
++config AR71XX_MACH_RB750
++	bool "MikroTik RouterBOARD 750 support"
++	select AR71XX_DEV_AP91_ETH
++	default n
++
++config AR71XX_MACH_WNDR3700
++	bool "NETGEAR WNDR3700 board support"
++	select AR71XX_DEV_M25P80
++	select AR71XX_DEV_AP94_PCI if PCI
++	select AR71XX_DEV_GPIO_BUTTONS
++	select AR71XX_DEV_LEDS_GPIO
++	select AR71XX_DEV_USB
++	default n
++
++config AR71XX_MACH_WNR2000
++	bool "NETGEAR WNR2000 board support"
++	select AR71XX_DEV_M25P80
++	select AR71XX_DEV_AR913X_WMAC
++	select AR71XX_DEV_GPIO_BUTTONS
++	select AR71XX_DEV_LEDS_GPIO
++	default n
++
++config AR71XX_MACH_MZK_W04NU
++	bool "Planex MZK-W04NU board support"
++	select AR71XX_DEV_M25P80
++	select AR71XX_DEV_AR913X_WMAC
++	select AR71XX_DEV_GPIO_BUTTONS
++	select AR71XX_DEV_LEDS_GPIO
++	select AR71XX_DEV_USB
++	default n
++
++config AR71XX_MACH_MZK_W300NH
++	bool "Planex MZK-W300NH board support"
++	select AR71XX_DEV_M25P80
++	select AR71XX_DEV_AR913X_WMAC
++	select AR71XX_DEV_GPIO_BUTTONS
++	select AR71XX_DEV_LEDS_GPIO
++	default n
++
++config AR71XX_MACH_NBG460N
++	bool "Zyxel NBG460N/550N/550NH board support"
++	select AR71XX_DEV_M25P80
++	select AR71XX_DEV_AR913X_WMAC
++	select AR71XX_DEV_GPIO_BUTTONS
++	select AR71XX_DEV_LEDS_GPIO
++	default n
++	
++config AR71XX_MACH_TL_WR741ND
++	bool "TP-LINK TL-WR741ND support"
++	select AR71XX_DEV_M25P80
++	select AR71XX_DEV_AP91_ETH
++	select AR71XX_DEV_AP91_PCI if PCI
++	select AR71XX_DEV_GPIO_BUTTONS
++	select AR71XX_DEV_LEDS_GPIO
++	default n
++
++config AR71XX_MACH_TL_WR841N_V1
++	bool "TP-LINK TL-WR841N v1 support"
++	select AR71XX_DEV_M25P80
++	select AR71XX_DEV_PB42_PCI if PCI
++	select AR71XX_DEV_DSA
++	select AR71XX_DEV_GPIO_BUTTONS
++	select AR71XX_DEV_LEDS_GPIO
++	default n
++
++config AR71XX_MACH_TL_WR941ND
++	bool "TP-LINK TL-WR941ND support"
++	select AR71XX_DEV_M25P80
++	select AR71XX_DEV_AR913X_WMAC
++	select AR71XX_DEV_DSA
++	select AR71XX_DEV_GPIO_BUTTONS
++	select AR71XX_DEV_LEDS_GPIO
++	default n
++
++config AR71XX_MACH_TL_WR1043ND
++	bool "TP-LINK TL-WR1043ND support"
++	select AR71XX_DEV_M25P80
++	select AR71XX_DEV_AR913X_WMAC
++	select AR71XX_DEV_GPIO_BUTTONS
++	select AR71XX_DEV_LEDS_GPIO
++	select AR71XX_DEV_USB
++	default n
++
++config AR71XX_MACH_TEW_632BRP
++	bool "TRENDnet TEW-632BRP support"
++	select AR71XX_DEV_M25P80
++	select AR71XX_DEV_AR913X_WMAC
++	select AR71XX_DEV_GPIO_BUTTONS
++	select AR71XX_DEV_LEDS_GPIO
++	select AR71XX_NVRAM
++	default n
++
++config AR71XX_MACH_UBNT
++	bool "Ubiquiti AR71xx based boards support"
++	select AR71XX_DEV_M25P80
++	select AR71XX_DEV_AP91_PCI if PCI
++	select AR71XX_DEV_GPIO_BUTTONS
++	select AR71XX_DEV_LEDS_GPIO
++	select AR71XX_DEV_PB42_PCI if PCI
++	select AR71XX_DEV_USB
++	default n
++
++endmenu
++
++config AR71XX_DEV_M25P80
++	def_bool n
++
++config AR71XX_DEV_AP91_PCI
++	def_bool n
++
++config AR71XX_DEV_AP91_ETH
++	def_bool n
++
++config AR71XX_DEV_AP94_PCI
++	def_bool n
++
++config AR71XX_DEV_AR913X_WMAC
++	def_bool n
++
++config AR71XX_DEV_DSA
++	def_bool n
++
++config AR71XX_DEV_GPIO_BUTTONS
++	def_bool n
++
++config AR71XX_DEV_LEDS_GPIO
++	def_bool n
++
++config AR71XX_DEV_PB42_PCI
++	def_bool n
++
++config AR71XX_DEV_PB9X_PCI
++	def_bool n
++
++config AR71XX_DEV_USB
++	def_bool n
++
++config AR71XX_NVRAM
++	def_bool n
++
++endif
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-ap81.c linux-2.6.33.3/arch/mips/ar71xx/mach-ap81.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-ap81.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-ap81.c	2010-03-23 20:31:04.604705903 +0100
+@@ -0,0 +1,140 @@
++/*
++ *  Atheros AP81 board support
++ *
++ *  Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2009 Imre Kaloz <kaloz@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/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ar913x-wmac.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "dev-usb.h"
++
++#define AP81_GPIO_LED_STATUS	1
++#define AP81_GPIO_LED_AOSS	3
++#define AP81_GPIO_LED_WLAN	6
++#define AP81_GPIO_LED_POWER	14
++
++#define AP81_GPIO_BTN_SW4	12
++#define AP81_GPIO_BTN_SW1	21
++
++#define AP81_BUTTONS_POLL_INTERVAL	20
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition ap81_partitions[] = {
++	{
++		.name		= "u-boot",
++		.offset		= 0,
++		.size		= 0x040000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "u-boot-env",
++		.offset		= 0x040000,
++		.size		= 0x010000,
++	} , {
++		.name		= "rootfs",
++		.offset		= 0x050000,
++		.size		= 0x500000,
++	} , {
++		.name		= "uImage",
++		.offset		= 0x550000,
++		.size		= 0x100000,
++	} , {
++		.name		= "ART",
++		.offset		= 0x650000,
++		.size		= 0x1b0000,
++		.mask_flags	= MTD_WRITEABLE,
++	}
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data ap81_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++        .parts          = ap81_partitions,
++        .nr_parts       = ARRAY_SIZE(ap81_partitions),
++#endif
++};
++
++static struct gpio_led ap81_leds_gpio[] __initdata = {
++	{
++		.name		= "ap81:green:status",
++		.gpio		= AP81_GPIO_LED_STATUS,
++		.active_low	= 1,
++	}, {
++		.name		= "ap81:amber:aoss",
++		.gpio		= AP81_GPIO_LED_AOSS,
++		.active_low	= 1,
++	}, {
++		.name		= "ap81:green:wlan",
++		.gpio		= AP81_GPIO_LED_WLAN,
++		.active_low	= 1,
++	}, {
++		.name		= "ap81:green:power",
++		.gpio		= AP81_GPIO_LED_POWER,
++		.active_low	= 1,
++	}
++};
++
++static struct gpio_button ap81_gpio_buttons[] __initdata = {
++	{
++		.desc		= "sw1",
++		.type		= EV_KEY,
++		.code		= BTN_0,
++		.threshold	= 3,
++		.gpio		= AP81_GPIO_BTN_SW1,
++		.active_low	= 1,
++	} , {
++		.desc		= "sw4",
++		.type		= EV_KEY,
++		.code		= BTN_1,
++		.threshold	= 3,
++		.gpio		= AP81_GPIO_BTN_SW4,
++		.active_low	= 1,
++	}
++};
++
++static void __init ap81_setup(void)
++{
++	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
++
++	ar71xx_set_mac_base(eeprom);
++	ar71xx_add_device_mdio(0x0);
++
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth0_data.speed = SPEED_100;
++	ar71xx_eth0_data.duplex = DUPLEX_FULL;
++	ar71xx_eth0_data.has_ar8216 = 1;
++
++	ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth1_data.phy_mask = 0x10;
++
++	ar71xx_add_device_eth(0);
++	ar71xx_add_device_eth(1);
++
++	ar71xx_add_device_usb();
++
++	ar71xx_add_device_m25p80(&ap81_flash_data);
++
++	ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(ap81_leds_gpio),
++					ap81_leds_gpio);
++
++	ar71xx_add_device_gpio_buttons(-1, AP81_BUTTONS_POLL_INTERVAL,
++					ARRAY_SIZE(ap81_gpio_buttons),
++					ap81_gpio_buttons);
++
++	ar913x_add_device_wmac(eeprom, NULL);
++}
++
++MIPS_MACHINE(AR71XX_MACH_AP81, "AP81", "Atheros AP81", ap81_setup);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-ap83.c linux-2.6.33.3/arch/mips/ar71xx/mach-ap83.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-ap83.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-ap83.c	2010-05-16 13:17:31.787602077 +0200
+@@ -0,0 +1,266 @@
++/*
++ *  Atheros AP83 board support
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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/delay.h>
++#include <linux/platform_device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spi_gpio.h>
++#include <linux/spi/vsc7385.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/ar91xx_flash.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-ar913x-wmac.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "dev-usb.h"
++
++#define AP83_GPIO_LED_WLAN	6
++#define AP83_GPIO_LED_POWER	14
++#define AP83_GPIO_LED_JUMPSTART	15
++#define AP83_GPIO_BTN_JUMPSTART	12
++#define AP83_GPIO_BTN_RESET	21
++
++#define AP83_050_GPIO_VSC7385_CS	1
++#define AP83_050_GPIO_VSC7385_MISO	3
++#define AP83_050_GPIO_VSC7385_MOSI	16
++#define AP83_050_GPIO_VSC7385_SCK	17
++
++#define AP83_BUTTONS_POLL_INTERVAL	20
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition ap83_flash_partitions[] = {
++	{
++		.name		= "u-boot",
++		.offset		= 0,
++		.size		= 0x040000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "u-boot-env",
++		.offset		= 0x040000,
++		.size		= 0x020000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "kernel",
++		.offset		= 0x060000,
++		.size		= 0x140000,
++	} , {
++		.name		= "rootfs",
++		.offset		= 0x1a0000,
++		.size		= 0x650000,
++	} , {
++		.name		= "art",
++		.offset		= 0x7f0000,
++		.size		= 0x010000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "firmware",
++		.offset		= 0x060000,
++		.size		= 0x790000,
++	}
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct ar91xx_flash_platform_data ap83_flash_data = {
++	.width		= 2,
++#ifdef CONFIG_MTD_PARTITIONS
++        .parts          = ap83_flash_partitions,
++        .nr_parts       = ARRAY_SIZE(ap83_flash_partitions),
++#endif
++};
++
++static struct resource ap83_flash_resources[] = {
++	[0] = {
++		.start	= AR71XX_SPI_BASE,
++		.end	= AR71XX_SPI_BASE + AR71XX_SPI_SIZE - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++};
++
++static struct platform_device ap83_flash_device = {
++	.name		= "ar91xx-flash",
++	.id		= -1,
++	.resource	= ap83_flash_resources,
++	.num_resources	= ARRAY_SIZE(ap83_flash_resources),
++	.dev		= {
++		.platform_data = &ap83_flash_data,
++	}
++};
++
++static struct gpio_led ap83_leds_gpio[] __initdata = {
++	{
++		.name		= "ap83:green:jumpstart",
++		.gpio		= AP83_GPIO_LED_JUMPSTART,
++		.active_low	= 0,
++	}, {
++		.name		= "ap83:green:power",
++		.gpio		= AP83_GPIO_LED_POWER,
++		.active_low	= 0,
++	}, {
++		.name		= "ap83:green:wlan",
++		.gpio		= AP83_GPIO_LED_WLAN,
++		.active_low	= 0,
++	},
++};
++
++static struct gpio_button ap83_gpio_buttons[] __initdata = {
++	{
++		.desc		= "soft_reset",
++		.type		= EV_KEY,
++		.code		= KEY_RESTART,
++		.threshold	= 3,
++		.gpio		= AP83_GPIO_BTN_RESET,
++		.active_low	= 1,
++	} , {
++		.desc		= "jumpstart",
++		.type		= EV_KEY,
++		.code		= KEY_WPS_BUTTON,
++		.threshold	= 3,
++		.gpio		= AP83_GPIO_BTN_JUMPSTART,
++		.active_low	= 1,
++	}
++};
++
++static struct resource ap83_040_spi_resources[] = {
++	[0] = {
++		.start	= AR71XX_SPI_BASE,
++		.end	= AR71XX_SPI_BASE + AR71XX_SPI_SIZE - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++};
++
++static struct platform_device ap83_040_spi_device = {
++	.name		= "ap83-spi",
++	.id		= 0,
++	.resource	= ap83_040_spi_resources,
++	.num_resources	= ARRAY_SIZE(ap83_040_spi_resources),
++};
++
++static struct spi_gpio_platform_data ap83_050_spi_data = {
++	.miso	= AP83_050_GPIO_VSC7385_MISO,
++	.mosi	= AP83_050_GPIO_VSC7385_MOSI,
++	.sck	= AP83_050_GPIO_VSC7385_SCK,
++	.num_chipselect = 1,
++};
++
++static struct platform_device ap83_050_spi_device = {
++	.name		= "spi_gpio",
++	.id		= 0,
++	.dev		= {
++		.platform_data = &ap83_050_spi_data,
++	}
++};
++
++static void ap83_vsc7385_reset(void)
++{
++	ar71xx_device_stop(RESET_MODULE_GE1_PHY);
++	udelay(10);
++	ar71xx_device_start(RESET_MODULE_GE1_PHY);
++	mdelay(50);
++}
++
++static struct vsc7385_platform_data ap83_vsc7385_data = {
++	.reset		= ap83_vsc7385_reset,
++	.ucode_name	= "vsc7385_ucode_ap83.bin",
++	.mac_cfg = {
++		.tx_ipg		= 6,
++		.bit2		= 0,
++		.clk_sel	= 3,
++	},
++};
++
++static struct spi_board_info ap83_spi_info[] = {
++	{
++		.bus_num	= 0,
++		.chip_select	= 0,
++		.max_speed_hz	= 25000000,
++		.modalias	= "spi-vsc7385",
++		.platform_data	= &ap83_vsc7385_data,
++		.controller_data = (void *) AP83_050_GPIO_VSC7385_CS,
++	}
++};
++
++static void __init ap83_generic_setup(void)
++{
++	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
++
++	ar71xx_set_mac_base(eeprom);
++
++	ar71xx_add_device_mdio(0xfffffffe);
++
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++	ar71xx_eth0_data.phy_mask = 0x1;
++
++	ar71xx_add_device_eth(0);
++
++	ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++	ar71xx_eth1_data.speed = SPEED_1000;
++	ar71xx_eth1_data.duplex = DUPLEX_FULL;
++
++	ar71xx_eth1_pll_data.pll_1000 = 0x1f000000;
++
++	ar71xx_add_device_eth(1);
++
++	ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(ap83_leds_gpio),
++					ap83_leds_gpio);
++
++	ar71xx_add_device_gpio_buttons(-1, AP83_BUTTONS_POLL_INTERVAL,
++					ARRAY_SIZE(ap83_gpio_buttons),
++					ap83_gpio_buttons);
++
++	ar71xx_add_device_usb();
++
++	ar913x_add_device_wmac(eeprom, NULL);
++
++	platform_device_register(&ap83_flash_device);
++
++	spi_register_board_info(ap83_spi_info, ARRAY_SIZE(ap83_spi_info));
++}
++
++static void __init ap83_040_setup(void)
++{
++	ap83_flash_data.is_shared=1;
++	ap83_generic_setup();
++	platform_device_register(&ap83_040_spi_device);
++}
++
++static void __init ap83_050_setup(void)
++{
++	ap83_generic_setup();
++	platform_device_register(&ap83_050_spi_device);
++}
++
++static void __init ap83_setup(void)
++{
++	u8 *board_id = (u8 *) KSEG1ADDR(0x1fff1244);
++	unsigned int board_version;
++
++	board_version = (unsigned int)(board_id[0] - '0');
++	board_version += ((unsigned int)(board_id[1] - '0')) * 10;
++
++	switch (board_version) {
++	case 40:
++		ap83_040_setup();
++		break;
++	case 50:
++		ap83_050_setup();
++		break;
++	default:
++		printk(KERN_WARNING "AP83-%03u board is not yet supported\n",
++		       board_version);
++	}
++}
++
++MIPS_MACHINE(AR71XX_MACH_AP83, "AP83", "Atheros AP83", ap83_setup);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-aw-nr580.c linux-2.6.33.3/arch/mips/ar71xx/mach-aw-nr580.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-aw-nr580.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-aw-nr580.c	2010-05-16 13:17:33.024519409 +0200
+@@ -0,0 +1,101 @@
++/*
++ *  AzureWave AW-NR580 board support
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mips_machine.h>
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-gpio-buttons.h"
++#include "dev-pb42-pci.h"
++#include "dev-leds-gpio.h"
++
++#define AW_NR580_GPIO_LED_READY_RED	0
++#define AW_NR580_GPIO_LED_WLAN		1
++#define AW_NR580_GPIO_LED_READY_GREEN	2
++#define AW_NR580_GPIO_LED_WPS_GREEN	4
++#define AW_NR580_GPIO_LED_WPS_AMBER	5
++
++#define AW_NR580_GPIO_BTN_WPS		3
++#define AW_NR580_GPIO_BTN_RESET		11
++
++#define AW_NR580_BUTTONS_POLL_INTERVAL	20
++
++static struct gpio_led aw_nr580_leds_gpio[] __initdata = {
++	{
++		.name		= "aw-nr580:red:ready",
++		.gpio		= AW_NR580_GPIO_LED_READY_RED,
++		.active_low	= 0,
++	}, {
++		.name		= "aw-nr580:green:ready",
++		.gpio		= AW_NR580_GPIO_LED_READY_GREEN,
++		.active_low	= 0,
++	}, {
++		.name		= "aw-nr580:green:wps",
++		.gpio		= AW_NR580_GPIO_LED_WPS_GREEN,
++		.active_low	= 0,
++	}, {
++		.name		= "aw-nr580:amber:wps",
++		.gpio		= AW_NR580_GPIO_LED_WPS_AMBER,
++		.active_low	= 0,
++	}, {
++		.name		= "aw-nr580:green:wlan",
++		.gpio		= AW_NR580_GPIO_LED_WLAN,
++		.active_low	= 0,
++	}
++};
++
++static struct gpio_button aw_nr580_gpio_buttons[] __initdata = {
++	{
++		.desc		= "reset",
++		.type		= EV_KEY,
++		.code		= KEY_RESTART,
++		.threshold	= 3,
++		.gpio		= AW_NR580_GPIO_BTN_RESET,
++		.active_low	= 1,
++	}, {
++		.desc		= "wps",
++		.type		= EV_KEY,
++		.code		= KEY_WPS_BUTTON,
++		.threshold	= 3,
++		.gpio		= AW_NR580_GPIO_BTN_WPS,
++		.active_low	= 1,
++	}
++};
++
++static void __init aw_nr580_setup(void)
++{
++	ar71xx_add_device_mdio(0x0);
++
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
++	ar71xx_eth0_data.speed = SPEED_100;
++	ar71xx_eth0_data.duplex = DUPLEX_FULL;
++
++	ar71xx_add_device_eth(0);
++
++	pb42_pci_init();
++
++	ar71xx_add_device_m25p80(NULL);
++
++	ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(aw_nr580_leds_gpio),
++					aw_nr580_leds_gpio);
++
++	ar71xx_add_device_gpio_buttons(-1, AW_NR580_BUTTONS_POLL_INTERVAL,
++					ARRAY_SIZE(aw_nr580_gpio_buttons),
++					aw_nr580_gpio_buttons);
++}
++
++MIPS_MACHINE(AR71XX_MACH_AW_NR580, "AW-NR580", "AzureWave AW-NR580",
++	     aw_nr580_setup);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-dir-600-a1.c linux-2.6.33.3/arch/mips/ar71xx/mach-dir-600-a1.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-dir-600-a1.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-dir-600-a1.c	2010-05-16 13:17:31.839599757 +0200
+@@ -0,0 +1,138 @@
++/*
++ *  D-Link DIR-600 rev. A1 board support
++ *
++ *  Copyright (C) 2010 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/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ap91-eth.h"
++#include "dev-ap91-pci.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "nvram.h"
++
++#define DIR_600_A1_GPIO_LED_WPS			0
++#define DIR_600_A1_GPIO_LED_POWER_AMBER		1
++#define DIR_600_A1_GPIO_LED_POWER_GREEN		6
++
++#define DIR_600_A1_GPIO_BTN_RESET		8
++#define DIR_600_A1_GPIO_BTN_WPS			12
++
++#define DIR_600_A1_BUTTONS_POLL_INTERVAL	20
++
++#define DIR_600_A1_NVRAM_ADDR	0x1f030000
++#define DIR_600_A1_NVRAM_SIZE	0x10000
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition dir_600_a1_partitions[] = {
++	{
++		.name		= "u-boot",
++		.offset		= 0,
++		.size		= 0x030000,
++		.mask_flags	= MTD_WRITEABLE,
++	}, {
++		.name		= "nvram",
++		.offset		= 0x030000,
++		.size		= 0x010000,
++	}, {
++		.name		= "kernel",
++		.offset		= 0x040000,
++		.size		= 0x0e0000,
++	}, {
++		.name		= "rootfs",
++		.offset		= 0x120000,
++		.size		= 0x2c0000,
++	}, {
++		.name		= "mac",
++		.offset		= 0x3e0000,
++		.size		= 0x010000,
++		.mask_flags	= MTD_WRITEABLE,
++	}, {
++		.name		= "art",
++		.offset		= 0x3f0000,
++		.size		= 0x010000,
++		.mask_flags	= MTD_WRITEABLE,
++	}, {
++		.name		= "firmware",
++		.offset		= 0x040000,
++		.size		= 0x3a0000,
++	}
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data dir_600_a1_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++        .parts          = dir_600_a1_partitions,
++        .nr_parts       = ARRAY_SIZE(dir_600_a1_partitions),
++#endif
++};
++
++static struct gpio_led dir_600_a1_leds_gpio[] __initdata = {
++	{
++		.name		= "dir-600-a1:green:power",
++		.gpio		= DIR_600_A1_GPIO_LED_POWER_GREEN,
++	}, {
++		.name		= "dir-600-a1:amber:power",
++		.gpio		= DIR_600_A1_GPIO_LED_POWER_AMBER,
++	}, {
++		.name		= "dir-600-a1:blue:wps",
++		.gpio		= DIR_600_A1_GPIO_LED_WPS,
++		.active_low	= 1,
++	}
++};
++
++static struct gpio_button dir_600_a1_gpio_buttons[] __initdata = {
++	{
++		.desc		= "reset",
++		.type		= EV_KEY,
++		.code		= KEY_RESTART,
++		.threshold	= 3,
++		.gpio		= DIR_600_A1_GPIO_BTN_RESET,
++		.active_low	= 1,
++	}, {
++		.desc		= "wps",
++		.type		= EV_KEY,
++		.code		= KEY_WPS_BUTTON,
++		.threshold	= 3,
++		.gpio		= DIR_600_A1_GPIO_BTN_WPS,
++		.active_low	= 1,
++	}
++};
++
++static void __init dir_600_a1_setup(void)
++{
++	const char *nvram = (char *) KSEG1ADDR(DIR_600_A1_NVRAM_ADDR);
++	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
++	u8 mac_buff[6];
++	u8 *mac = NULL;
++
++	if (nvram_parse_mac_addr(nvram, DIR_600_A1_NVRAM_SIZE,
++			         "lan_mac=", mac_buff) == 0)
++		mac = mac_buff;
++
++	ar71xx_add_device_m25p80(&dir_600_a1_flash_data);
++
++	ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(dir_600_a1_leds_gpio),
++					dir_600_a1_leds_gpio);
++
++	ar71xx_add_device_gpio_buttons(-1, DIR_600_A1_BUTTONS_POLL_INTERVAL,
++					ARRAY_SIZE(dir_600_a1_gpio_buttons),
++					dir_600_a1_gpio_buttons);
++
++	ap91_eth_init(mac, NULL);
++	ap91_pci_init(ee, mac);
++}
++
++MIPS_MACHINE(AR71XX_MACH_DIR_600_A1, "DIR-600-A1", "D-Link DIR-600 rev. A1",
++	     dir_600_a1_setup);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-dir-615-c1.c linux-2.6.33.3/arch/mips/ar71xx/mach-dir-615-c1.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-dir-615-c1.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-dir-615-c1.c	2010-05-16 13:17:31.775600829 +0200
+@@ -0,0 +1,173 @@
++/*
++ *  D-Link DIR-615 rev C1 board support
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ar913x-wmac.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "nvram.h"
++
++#define DIR_615C1_GPIO_LED_ORANGE_STATUS 1	/* ORANGE:STATUS:TRICOLOR */
++#define DIR_615C1_GPIO_LED_BLUE_WPS	3	/* BLUE:WPS */
++#define DIR_615C1_GPIO_LED_GREEN_WAN	4       /* GREEN:WAN:TRICOLOR */
++#define DIR_615C1_GPIO_LED_GREEN_WANCPU	5       /* GREEN:WAN:CPU:TRICOLOR */
++#define DIR_615C1_GPIO_LED_GREEN_WLAN	6	/* GREEN:WLAN */
++#define DIR_615C1_GPIO_LED_GREEN_STATUS	14	/* GREEN:STATUS:TRICOLOR */
++#define DIR_615C1_GPIO_LED_ORANGE_WAN	15	/* ORANGE:WAN:TRICOLOR */
++
++/* buttons may need refinement */
++
++#define DIR_615C1_GPIO_BTN_WPS		12
++#define DIR_615C1_GPIO_BTN_RESET	21
++
++#define DIR_615C1_BUTTONS_POLL_INTERVAL	20
++
++#define DIR_615C1_CONFIG_ADDR		0x1f020000
++#define DIR_615C1_CONFIG_SIZE		0x10000
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition dir_615c1_partitions[] = {
++	{
++		.name		= "u-boot",
++		.offset		= 0,
++		.size		= 0x020000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "config",
++		.offset		= 0x020000,
++		.size		= 0x010000,
++	} , {
++		.name		= "kernel",
++		.offset		= 0x030000,
++		.size		= 0x0d0000,
++	} , {
++		.name		= "rootfs",
++		.offset		= 0x100000,
++		.size		= 0x2f0000,
++	} , {
++		.name		= "art",
++		.offset		= 0x3f0000,
++		.size		= 0x010000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "firmware",
++		.offset		= 0x030000,
++		.size		= 0x3c0000,
++	}
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data dir_615c1_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++        .parts          = dir_615c1_partitions,
++        .nr_parts       = ARRAY_SIZE(dir_615c1_partitions),
++#endif
++};
++
++static struct gpio_led dir_615c1_leds_gpio[] __initdata = {
++	{
++		.name		= "dir-615c1:orange:status",
++		.gpio		= DIR_615C1_GPIO_LED_ORANGE_STATUS,
++		.active_low	= 1,
++	}, {
++		.name		= "dir-615c1:blue:wps",
++		.gpio		= DIR_615C1_GPIO_LED_BLUE_WPS,
++		.active_low	= 1,
++	}, {
++		.name		= "dir-615c1:green:wan",
++		.gpio		= DIR_615C1_GPIO_LED_GREEN_WAN,
++		.active_low	= 1,
++	}, {
++		.name		= "dir-615c1:green:wancpu",
++		.gpio		= DIR_615C1_GPIO_LED_GREEN_WANCPU,
++		.active_low	= 1,
++        }, {
++		.name		= "dir-615c1:green:wlan",
++		.gpio		= DIR_615C1_GPIO_LED_GREEN_WLAN,
++		.active_low	= 1,
++        }, {
++		.name           = "dir-615c1:green:status",
++		.gpio           = DIR_615C1_GPIO_LED_GREEN_STATUS,
++		.active_low     = 1,
++	}, {
++		.name		= "dir-615c1:orange:wan",
++		.gpio		= DIR_615C1_GPIO_LED_ORANGE_WAN,
++		.active_low	= 1,
++	}
++
++};
++
++static struct gpio_button dir_615c1_gpio_buttons[] __initdata = {
++	{
++		.desc		= "reset",
++		.type		= EV_KEY,
++		.code		= KEY_RESTART,
++		.threshold	= 3,
++		.gpio		= DIR_615C1_GPIO_BTN_RESET,
++	}, {
++		.desc		= "wps",
++		.type		= EV_KEY,
++		.code		= KEY_WPS_BUTTON,
++		.threshold	= 3,
++		.gpio		= DIR_615C1_GPIO_BTN_WPS,
++	}
++};
++
++#define DIR_615C1_LAN_PHYMASK	BIT(0)
++#define DIR_615C1_WAN_PHYMASK	BIT(4)
++#define DIR_615C1_MDIO_MASK	(~(DIR_615C1_LAN_PHYMASK | \
++				   DIR_615C1_WAN_PHYMASK))
++
++static void __init dir_615c1_setup(void)
++{
++	const char *config = (char *) KSEG1ADDR(DIR_615C1_CONFIG_ADDR);
++	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
++	u8 mac[6];
++	u8 *wlan_mac = NULL;
++
++	if (nvram_parse_mac_addr(config, DIR_615C1_CONFIG_SIZE,
++			         "lan_mac=", mac) == 0) {
++		ar71xx_set_mac_base(mac);
++		wlan_mac = mac;
++	}
++
++	ar71xx_add_device_mdio(DIR_615C1_MDIO_MASK);
++
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth0_data.phy_mask = DIR_615C1_LAN_PHYMASK;
++
++	ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth1_data.phy_mask = DIR_615C1_WAN_PHYMASK;
++
++	ar71xx_add_device_eth(0);
++	ar71xx_add_device_eth(1);
++
++	ar71xx_add_device_m25p80(&dir_615c1_flash_data);
++
++	ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(dir_615c1_leds_gpio),
++					dir_615c1_leds_gpio);
++
++	ar71xx_add_device_gpio_buttons(-1, DIR_615C1_BUTTONS_POLL_INTERVAL,
++					ARRAY_SIZE(dir_615c1_gpio_buttons),
++					dir_615c1_gpio_buttons);
++
++	ar913x_add_device_wmac(eeprom, wlan_mac);
++}
++
++MIPS_MACHINE(AR71XX_MACH_DIR_615_C1, "DIR-615-C1", "D-Link DIR-615 rev. C1",
++	     dir_615c1_setup);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-dir-825-b1.c linux-2.6.33.3/arch/mips/ar71xx/mach-dir-825-b1.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-dir-825-b1.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-dir-825-b1.c	2010-05-16 13:17:32.715628389 +0200
+@@ -0,0 +1,192 @@
++/*
++ *  D-Link DIR-825 rev. B1 board support
++ *
++ *  Copyright (C) 2009 Lukas Kuna, Evkanet, s.r.o.
++ *
++ *  based on mach-wndr3700.c
++ *
++ *  This program is free software; you can redistribute it and/or modify it
++ *  under the terms of the GNU General Public License version 2 as published
++ *  by the Free Software Foundation.
++ */
++
++#include <linux/platform_device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/delay.h>
++#include <linux/rtl8366s.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ap94-pci.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "dev-usb.h"
++
++#define DIR825B1_GPIO_LED_BLUE_USB		0
++#define DIR825B1_GPIO_LED_ORANGE_POWER		1
++#define DIR825B1_GPIO_LED_BLUE_POWER		2
++#define DIR825B1_GPIO_LED_BLUE_POWERSAVE	4
++#define DIR825B1_GPIO_LED_ORANGE_PLANET		6
++#define DIR825B1_GPIO_LED_BLUE_PLANET		11
++
++#define DIR825B1_GPIO_BTN_RESET			3
++#define DIR825B1_GPIO_BTN_POWERSAVE		8
++
++#define DIR825B1_GPIO_RTL8366_SDA		5
++#define DIR825B1_GPIO_RTL8366_SCK		7
++
++#define DIR825B1_BUTTONS_POLL_INTERVAL		20
++
++#define DIR825B1_CAL_LOCATION_0			0x1f661000
++#define DIR825B1_CAL_LOCATION_1			0x1f665000
++
++#define DIR825B1_MAC_LOCATION_0			0x2ffa81b8
++#define DIR825B1_MAC_LOCATION_1			0x2ffa8370
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition dir825b1_partitions[] = {
++	{
++		.name		= "uboot",
++		.offset		= 0,
++		.size		= 0x040000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "config",
++		.offset		= 0x040000,
++		.size		= 0x010000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "firmware",
++		.offset		= 0x050000,
++		.size		= 0x610000,
++	} , {
++		.name		= "caldata",
++		.offset		= 0x660000,
++		.size		= 0x010000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "unknown",
++		.offset		= 0x670000,
++		.size		= 0x190000,
++		.mask_flags	= MTD_WRITEABLE,
++	}
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data dir825b1_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++        .parts          = dir825b1_partitions,
++        .nr_parts       = ARRAY_SIZE(dir825b1_partitions),
++#endif
++};
++
++static struct gpio_led dir825b1_leds_gpio[] __initdata = {
++	{
++		.name		= "dir825b1:blue:usb",
++		.gpio		= DIR825B1_GPIO_LED_BLUE_USB,
++		.active_low	= 1,
++	}, {
++		.name		= "dir825b1:orange:power",
++		.gpio		= DIR825B1_GPIO_LED_ORANGE_POWER,
++		.active_low	= 1,
++	}, {
++		.name		= "dir825b1:blue:power",
++		.gpio		= DIR825B1_GPIO_LED_BLUE_POWER,
++		.active_low	= 1,
++	}, {
++		.name		= "dir825b1:blue:powersave",
++		.gpio		= DIR825B1_GPIO_LED_BLUE_POWERSAVE,
++		.active_low	= 1,
++	}, {
++		.name		= "dir825b1:orange:planet",
++		.gpio		= DIR825B1_GPIO_LED_ORANGE_PLANET,
++		.active_low	= 1,
++	}, {
++		.name		= "dir825b1:blue:planet",
++		.gpio		= DIR825B1_GPIO_LED_BLUE_PLANET,
++		.active_low	= 1,
++	}
++};
++
++static struct gpio_button dir825b1_gpio_buttons[] __initdata = {
++	{
++		.desc		= "reset",
++		.type		= EV_KEY,
++		.code		= KEY_RESTART,
++		.threshold	= 3,
++		.gpio		= DIR825B1_GPIO_BTN_RESET,
++		.active_low	= 1,
++	} , {
++		.desc		= "powersave",
++		.type		= EV_KEY,
++		.code		= BTN_1,
++		.threshold	= 3,
++		.gpio		= DIR825B1_GPIO_BTN_POWERSAVE,
++		.active_low	= 1,
++	}
++};
++
++static struct rtl8366s_platform_data dir825b1_rtl8366s_data = {
++	.gpio_sda        = DIR825B1_GPIO_RTL8366_SDA,
++	.gpio_sck        = DIR825B1_GPIO_RTL8366_SCK,
++};
++
++static struct platform_device dir825b1_rtl8366s_device = {
++	.name		= RTL8366S_DRIVER_NAME,
++	.id		= -1,
++	.dev = {
++		.platform_data	= &dir825b1_rtl8366s_data,
++	}
++};
++
++static void __init dir825b1_setup(void)
++{
++        u8 mac[6], i;
++
++	memcpy(mac, (u8*)KSEG1ADDR(DIR825B1_MAC_LOCATION_1), 6);
++	for(i = 5; i >= 3; i--)
++		if(++mac[i] != 0x00) break;
++
++	ar71xx_set_mac_base(mac);
++
++	ar71xx_add_device_mdio(0x0);
++
++	ar71xx_eth0_data.mii_bus_dev = &dir825b1_rtl8366s_device.dev;
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++	ar71xx_eth0_data.speed = SPEED_1000;
++	ar71xx_eth0_data.duplex = DUPLEX_FULL;
++	ar71xx_eth0_pll_data.pll_1000 = 0x11110000;
++
++	ar71xx_eth1_data.mii_bus_dev = &dir825b1_rtl8366s_device.dev;
++	ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++	ar71xx_eth1_data.phy_mask = 0x10;
++	ar71xx_eth1_pll_data.pll_1000 = 0x11110000;
++
++	ar71xx_add_device_eth(0);
++	ar71xx_add_device_eth(1);
++
++	ar71xx_add_device_m25p80(&dir825b1_flash_data);
++
++	ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(dir825b1_leds_gpio),
++					dir825b1_leds_gpio);
++
++	ar71xx_add_device_gpio_buttons(-1, DIR825B1_BUTTONS_POLL_INTERVAL,
++					ARRAY_SIZE(dir825b1_gpio_buttons),
++					dir825b1_gpio_buttons);
++
++	ar71xx_add_device_usb();
++
++	platform_device_register(&dir825b1_rtl8366s_device);
++
++	ap94_pci_init((u8 *) KSEG1ADDR(DIR825B1_CAL_LOCATION_0),
++		      (u8 *) KSEG1ADDR(DIR825B1_MAC_LOCATION_0),
++		      (u8 *) KSEG1ADDR(DIR825B1_CAL_LOCATION_1),
++		      (u8 *) KSEG1ADDR(DIR825B1_MAC_LOCATION_1));
++}
++
++MIPS_MACHINE(AR71XX_MACH_DIR_825_B1, "DIR-825-B1", "D-Link DIR-825 rev. B1",
++	     dir825b1_setup);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-mzk-w04nu.c linux-2.6.33.3/arch/mips/ar71xx/mach-mzk-w04nu.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-mzk-w04nu.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-mzk-w04nu.c	2010-05-16 13:17:31.807598757 +0200
+@@ -0,0 +1,165 @@
++/*
++ *  Planex MZK-W04NU board support
++ *
++ *  Copyright (C) 2009 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/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-ar913x-wmac.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "dev-m25p80.h"
++#include "dev-usb.h"
++
++#define MZK_W04NU_GPIO_LED_USB		0
++#define MZK_W04NU_GPIO_LED_STATUS	1
++#define MZK_W04NU_GPIO_LED_WPS		3
++#define MZK_W04NU_GPIO_LED_WLAN		6
++#define MZK_W04NU_GPIO_LED_AP		15
++#define MZK_W04NU_GPIO_LED_ROUTER	16
++
++#define MZK_W04NU_GPIO_BTN_APROUTER	5
++#define MZK_W04NU_GPIO_BTN_WPS		12
++#define MZK_W04NU_GPIO_BTN_RESET	21
++
++#define MZK_W04NU_BUTTONS_POLL_INTERVAL	20
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition mzk_w04nu_partitions[] = {
++	{
++		.name		= "u-boot",
++		.offset		= 0,
++		.size		= 0x040000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "u-boot-env",
++		.offset		= 0x040000,
++		.size		= 0x010000,
++	} , {
++		.name		= "kernel",
++		.offset		= 0x050000,
++		.size		= 0x160000,
++	} , {
++		.name		= "rootfs",
++		.offset		= 0x1b0000,
++		.size		= 0x630000,
++	} , {
++		.name		= "art",
++		.offset		= 0x7e0000,
++		.size		= 0x020000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "firmware",
++		.offset		= 0x050000,
++		.size		= 0x790000,
++	}
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data mzk_w04nu_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++        .parts          = mzk_w04nu_partitions,
++        .nr_parts       = ARRAY_SIZE(mzk_w04nu_partitions),
++#endif
++};
++
++static struct gpio_led mzk_w04nu_leds_gpio[] __initdata = {
++	{
++		.name		= "mzk-w04nu:green:status",
++		.gpio		= MZK_W04NU_GPIO_LED_STATUS,
++		.active_low	= 1,
++	}, {
++		.name		= "mzk-w04nu:blue:wps",
++		.gpio		= MZK_W04NU_GPIO_LED_WPS,
++		.active_low	= 1,
++	}, {
++		.name		= "mzk-w04nu:green:wlan",
++		.gpio		= MZK_W04NU_GPIO_LED_WLAN,
++		.active_low	= 1,
++	}, {
++		.name		= "mzk-w04nu:green:usb",
++		.gpio		= MZK_W04NU_GPIO_LED_USB,
++		.active_low	= 1,
++	}, {
++		.name		= "mzk-w04nu:green:ap",
++		.gpio		= MZK_W04NU_GPIO_LED_AP,
++		.active_low	= 1,
++	}, {
++		.name		= "mzk-w04nu:green:router",
++		.gpio		= MZK_W04NU_GPIO_LED_ROUTER,
++		.active_low	= 1,
++	}
++};
++
++static struct gpio_button mzk_w04nu_gpio_buttons[] __initdata = {
++	{
++		.desc		= "reset",
++		.type		= EV_KEY,
++		.code		= KEY_RESTART,
++		.threshold	= 3,
++		.gpio		= MZK_W04NU_GPIO_BTN_RESET,
++		.active_low	= 1,
++	}, {
++		.desc		= "wps",
++		.type		= EV_KEY,
++		.code		= KEY_WPS_BUTTON,
++		.threshold	= 3,
++		.gpio		= MZK_W04NU_GPIO_BTN_WPS,
++		.active_low	= 1,
++	}, {
++		.desc		= "aprouter",
++		.type		= EV_KEY,
++		.code		= BTN_2,
++		.threshold	= 3,
++		.gpio		= MZK_W04NU_GPIO_BTN_APROUTER,
++		.active_low	= 0,
++	}
++};
++
++#define MZK_W04NU_WAN_PHYMASK	BIT(4)
++#define MZK_W04NU_MDIO_MASK	(~MZK_W04NU_WAN_PHYMASK)
++
++static void __init mzk_w04nu_setup(void)
++{
++	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
++
++	ar71xx_set_mac_base(eeprom);
++
++	ar71xx_add_device_mdio(MZK_W04NU_MDIO_MASK);
++
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth0_data.speed = SPEED_100;
++	ar71xx_eth0_data.duplex = DUPLEX_FULL;
++	ar71xx_eth0_data.has_ar8216 = 1;
++
++	ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth1_data.phy_mask = MZK_W04NU_WAN_PHYMASK;
++
++	ar71xx_add_device_eth(0);
++	ar71xx_add_device_eth(1);
++
++	ar71xx_add_device_m25p80(&mzk_w04nu_flash_data);
++
++	ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(mzk_w04nu_leds_gpio),
++					mzk_w04nu_leds_gpio);
++
++	ar71xx_add_device_gpio_buttons(-1, MZK_W04NU_BUTTONS_POLL_INTERVAL,
++					ARRAY_SIZE(mzk_w04nu_gpio_buttons),
++					mzk_w04nu_gpio_buttons);
++	ar71xx_add_device_usb();
++
++	ar913x_add_device_wmac(eeprom, NULL);
++}
++
++MIPS_MACHINE(AR71XX_MACH_MZK_W04NU, "MZK-W04NU", "Planex MZK-W04NU",
++	     mzk_w04nu_setup);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-mzk-w300nh.c linux-2.6.33.3/arch/mips/ar71xx/mach-mzk-w300nh.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-mzk-w300nh.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-mzk-w300nh.c	2010-05-16 13:17:32.931648635 +0200
+@@ -0,0 +1,158 @@
++/*
++ *  Planex MZK-W300NH board support
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ar913x-wmac.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++
++#define MZK_W300NH_GPIO_LED_STATUS	1
++#define MZK_W300NH_GPIO_LED_WPS		3
++#define MZK_W300NH_GPIO_LED_WLAN	6
++#define MZK_W300NH_GPIO_LED_AP		15
++#define MZK_W300NH_GPIO_LED_ROUTER	16
++
++#define MZK_W300NH_GPIO_BTN_APROUTER	5
++#define MZK_W300NH_GPIO_BTN_WPS		12
++#define MZK_W300NH_GPIO_BTN_RESET	21
++
++#define MZK_W04NU_BUTTONS_POLL_INTERVAL	20
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition mzk_w300nh_partitions[] = {
++	{
++		.name		= "u-boot",
++		.offset		= 0,
++		.size		= 0x040000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "u-boot-env",
++		.offset		= 0x040000,
++		.size		= 0x010000,
++	} , {
++		.name		= "kernel",
++		.offset		= 0x050000,
++		.size		= 0x160000,
++	} , {
++		.name		= "rootfs",
++		.offset		= 0x1b0000,
++		.size		= 0x630000,
++	} , {
++		.name		= "art",
++		.offset		= 0x7e0000,
++		.size		= 0x020000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "firmware",
++		.offset		= 0x050000,
++		.size		= 0x790000,
++	}
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data mzk_w300nh_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++        .parts          = mzk_w300nh_partitions,
++        .nr_parts       = ARRAY_SIZE(mzk_w300nh_partitions),
++#endif
++};
++
++static struct gpio_led mzk_w300nh_leds_gpio[] __initdata = {
++	{
++		.name		= "mzk-w300nh:green:status",
++		.gpio		= MZK_W300NH_GPIO_LED_STATUS,
++		.active_low	= 1,
++	}, {
++		.name		= "mzk-w300nh:blue:wps",
++		.gpio		= MZK_W300NH_GPIO_LED_WPS,
++		.active_low	= 1,
++	}, {
++		.name		= "mzk-w300nh:green:wlan",
++		.gpio		= MZK_W300NH_GPIO_LED_WLAN,
++		.active_low	= 1,
++	}, {
++		.name		= "mzk-w300nh:green:ap",
++		.gpio		= MZK_W300NH_GPIO_LED_AP,
++		.active_low	= 1,
++	}, {
++		.name		= "mzk-w300nh:green:router",
++		.gpio		= MZK_W300NH_GPIO_LED_ROUTER,
++		.active_low	= 1,
++	}
++};
++
++static struct gpio_button mzk_w300nh_gpio_buttons[] __initdata = {
++	{
++		.desc		= "reset",
++		.type		= EV_KEY,
++		.code		= KEY_RESTART,
++		.threshold	= 3,
++		.gpio		= MZK_W300NH_GPIO_BTN_RESET,
++		.active_low	= 1,
++	}, {
++		.desc		= "wps",
++		.type		= EV_KEY,
++		.code		= KEY_WPS_BUTTON,
++		.threshold	= 3,
++		.gpio		= MZK_W300NH_GPIO_BTN_WPS,
++		.active_low	= 1,
++	}, {
++		.desc		= "aprouter",
++		.type		= EV_KEY,
++		.code		= BTN_2,
++		.threshold	= 3,
++		.gpio		= MZK_W300NH_GPIO_BTN_APROUTER,
++		.active_low	= 0,
++	}
++};
++
++#define MZK_W300NH_WAN_PHYMASK	BIT(4)
++#define MZK_W300NH_MDIO_MASK	(~MZK_W300NH_WAN_PHYMASK)
++
++static void __init mzk_w300nh_setup(void)
++{
++	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
++
++	ar71xx_set_mac_base(eeprom);
++
++	ar71xx_add_device_mdio(MZK_W300NH_MDIO_MASK);
++
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth0_data.speed = SPEED_100;
++	ar71xx_eth0_data.duplex = DUPLEX_FULL;
++	ar71xx_eth0_data.has_ar8216 = 1;
++
++	ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth1_data.phy_mask = MZK_W300NH_WAN_PHYMASK;
++
++	ar71xx_add_device_eth(0);
++	ar71xx_add_device_eth(1);
++
++	ar71xx_add_device_m25p80(&mzk_w300nh_flash_data);
++
++	ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(mzk_w300nh_leds_gpio),
++				    mzk_w300nh_leds_gpio);
++
++	ar71xx_add_device_gpio_buttons(-1, MZK_W04NU_BUTTONS_POLL_INTERVAL,
++				       ARRAY_SIZE(mzk_w300nh_gpio_buttons),
++				       mzk_w300nh_gpio_buttons);
++	ar913x_add_device_wmac(eeprom, NULL);
++}
++
++MIPS_MACHINE(AR71XX_MACH_MZK_W300NH, "MZK-W300NH", "Planex MZK-W300NH",
++	     mzk_w300nh_setup);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-nbg460n.c linux-2.6.33.3/arch/mips/ar71xx/mach-nbg460n.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-nbg460n.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-nbg460n.c	2010-05-16 13:17:32.947611843 +0200
+@@ -0,0 +1,222 @@
++/*
++ *  Zyxel NBG 460N/550N/550NH board support
++ *
++ *  Copyright (C) 2010 Michael Kurz <michi.kurz@googlemail.com>
++ *
++ *  based on mach-tl-wr1043nd.c
++ *
++ *  This program is free software; you can redistribute it and/or modify it
++ *  under the terms of the GNU General Public License version 2 as published
++ *  by the Free Software Foundation.
++ */
++
++#include <linux/platform_device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/delay.h>
++#include <linux/rtl8366s.h>
++
++#include <linux/i2c.h>
++#include <linux/i2c-algo-bit.h>
++#include <linux/i2c-gpio.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ar913x-wmac.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++
++/* LEDs */
++#define NBG460N_GPIO_LED_WPS		3
++#define NBG460N_GPIO_LED_WAN		6
++#define NBG460N_GPIO_LED_POWER		14
++#define NBG460N_GPIO_LED_WLAN		15
++
++/* Buttons */
++#define NBG460N_GPIO_BTN_WPS		12
++#define NBG460N_GPIO_BTN_RESET		21
++#define NBG460N_BUTTONS_POLL_INTERVAL	20
++
++/* RTC chip PCF8563 I2C interface */
++#define NBG460N_GPIO_PCF8563_SDA	8
++#define NBG460N_GPIO_PCF8563_SCK	7
++
++/* Switch configuration I2C interface */
++#define NBG460N_GPIO_RTL8366_SDA	16
++#define NBG460N_GPIO_RTL8366_SCK	18
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition nbg460n_partitions[] = {
++	{
++		.name		= "Bootbase",
++		.offset		= 0,
++		.size		= 0x010000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "U-Boot Config",
++		.offset		= 0x010000,
++		.size		= 0x030000,
++	} , {
++		.name		= "U-Boot",
++		.offset		= 0x040000,
++		.size		= 0x030000,
++	} , {
++		.name		= "linux",
++		.offset		= 0x070000,
++		.size		= 0x0e0000,
++	} , {
++		.name		= "rootfs",
++		.offset		= 0x150000,
++		.size		= 0x2a0000,
++	} , {
++		.name		= "CalibData",
++		.offset		= 0x3f0000,
++		.size		= 0x010000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "firmware",
++		.offset		= 0x070000,
++		.size		= 0x380000,
++	}
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data nbg460n_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++        .parts          = nbg460n_partitions,
++        .nr_parts       = ARRAY_SIZE(nbg460n_partitions),
++#endif
++};
++
++static struct gpio_led nbg460n_leds_gpio[] __initdata = {
++	{
++		.name		= "nbg460n:green:power",
++		.gpio		= NBG460N_GPIO_LED_POWER,
++		.active_low	= 0,
++		.default_trigger = "default-on",
++	}, {
++		.name		= "nbg460n:green:wps",
++		.gpio		= NBG460N_GPIO_LED_WPS,
++		.active_low	= 0,
++	}, {
++		.name		= "nbg460n:green:wlan",
++		.gpio		= NBG460N_GPIO_LED_WLAN,
++		.active_low	= 0,
++	}, {
++		/* Not really for controlling the LED,
++		   when set low the LED blinks uncontrollable  */
++		.name		= "nbg460n:green:wan",
++		.gpio		= NBG460N_GPIO_LED_WAN,
++		.active_low	= 0,
++	}
++};
++
++static struct gpio_button nbg460n_gpio_buttons[] __initdata = {
++	{
++		.desc		= "reset",
++		.type		= EV_KEY,
++		.code		= KEY_RESTART,
++		.threshold	= 3,
++		.gpio		= NBG460N_GPIO_BTN_RESET,
++		.active_low	= 1,
++	}, {
++		.desc		= "wps",
++		.type		= EV_KEY,
++		.code		= KEY_WPS_BUTTON,
++		.threshold	= 3,
++		.gpio		= NBG460N_GPIO_BTN_WPS,
++		.active_low	= 1,
++	}
++};
++
++static struct i2c_gpio_platform_data nbg460n_i2c_device_platdata = {
++	.sda_pin	= NBG460N_GPIO_PCF8563_SDA,
++	.scl_pin	= NBG460N_GPIO_PCF8563_SCK,
++	.udelay		= 10,
++};
++
++static struct platform_device nbg460n_i2c_device = {
++	.name		= "i2c-gpio",
++	.id		= -1,
++	.num_resources	= 0,
++	.resource	= NULL,
++	.dev		= {
++		.platform_data	= &nbg460n_i2c_device_platdata,
++	},
++};
++
++static struct i2c_board_info nbg460n_i2c_devs[] __initdata = {
++	{
++		I2C_BOARD_INFO("pcf8563", 0x51),
++	},
++};
++
++static void __devinit nbg460n_i2c_init(void)
++{
++	/* The gpio interface */
++	platform_device_register(&nbg460n_i2c_device);
++	/* I2C devices */
++	i2c_register_board_info(0, nbg460n_i2c_devs,
++				ARRAY_SIZE(nbg460n_i2c_devs));
++}
++
++
++static struct rtl8366s_platform_data nbg460n_rtl8366s_data = {
++	.gpio_sda        = NBG460N_GPIO_RTL8366_SDA,
++	.gpio_sck        = NBG460N_GPIO_RTL8366_SCK,
++};
++
++static struct platform_device nbg460n_rtl8366s_device = {
++	.name		= RTL8366S_DRIVER_NAME,
++	.id		= -1,
++	.dev = {
++		.platform_data	= &nbg460n_rtl8366s_data,
++	}
++};
++
++static void __init nbg460n_setup(void)
++{
++	/* end of bootloader sector contains mac address*/
++	u8 *mac = (u8 *) KSEG1ADDR(0x1fc0fff8);
++	/* last sector contains wlan calib data */
++	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
++
++	ar71xx_set_mac_base(mac);
++
++	/* LAN Port */
++	ar71xx_eth0_data.mii_bus_dev = &nbg460n_rtl8366s_device.dev;
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++	ar71xx_eth0_data.speed = SPEED_1000;
++	ar71xx_eth0_data.duplex = DUPLEX_FULL;
++
++	/* WAN Port */
++	ar71xx_eth1_data.mii_bus_dev = &nbg460n_rtl8366s_device.dev;
++	ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++	ar71xx_eth1_data.phy_mask = 0x10;
++
++	ar71xx_add_device_eth(0);
++	ar71xx_add_device_eth(1);
++
++	/* register the switch phy */
++	platform_device_register(&nbg460n_rtl8366s_device);
++
++	/* register flash */
++	ar71xx_add_device_m25p80(&nbg460n_flash_data);
++
++	ar913x_add_device_wmac(eeprom, mac);
++
++	/* register RTC chip */
++	nbg460n_i2c_init();
++
++	ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(nbg460n_leds_gpio),
++					nbg460n_leds_gpio);
++
++	ar71xx_add_device_gpio_buttons(-1, NBG460N_BUTTONS_POLL_INTERVAL,
++					ARRAY_SIZE(nbg460n_gpio_buttons),
++					nbg460n_gpio_buttons);
++}
++
++MIPS_MACHINE(AR71XX_MACH_NBG460N, "NBG460N", "Zyxel NBG460N/550N/550NH", nbg460n_setup);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-pb42.c linux-2.6.33.3/arch/mips/ar71xx/mach-pb42.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-pb42.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-pb42.c	2010-03-23 20:31:05.092710513 +0100
+@@ -0,0 +1,71 @@
++/*
++ *  Atheros PB42 board support
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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 <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-gpio-buttons.h"
++#include "dev-pb42-pci.h"
++#include "dev-usb.h"
++
++#define PB42_BUTTONS_POLL_INTERVAL	20
++
++#define PB42_GPIO_BTN_SW4	8
++#define PB42_GPIO_BTN_SW5	3
++
++static struct gpio_button pb42_gpio_buttons[] __initdata = {
++	{
++		.desc		= "sw4",
++		.type		= EV_KEY,
++		.code		= BTN_0,
++		.threshold	= 3,
++		.gpio		= PB42_GPIO_BTN_SW4,
++		.active_low	= 1,
++	} , {
++		.desc		= "sw5",
++		.type		= EV_KEY,
++		.code		= BTN_1,
++		.threshold	= 3,
++		.gpio		= PB42_GPIO_BTN_SW5,
++		.active_low	= 1,
++	}
++};
++
++#define PB42_WAN_PHYMASK	BIT(20)
++#define PB42_LAN_PHYMASK	(BIT(16) | BIT(17) | BIT(18) | BIT(19))
++#define PB42_MDIO_PHYMASK	(PB42_LAN_PHYMASK | PB42_WAN_PHYMASK)
++
++static void __init pb42_init(void)
++{
++	ar71xx_add_device_m25p80(NULL);
++
++	ar71xx_add_device_mdio(~PB42_MDIO_PHYMASK);
++
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
++	ar71xx_eth0_data.phy_mask = PB42_WAN_PHYMASK;
++
++	ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth1_data.speed = SPEED_100;
++	ar71xx_eth1_data.duplex = DUPLEX_FULL;
++
++	ar71xx_add_device_eth(0);
++	ar71xx_add_device_eth(1);
++
++	ar71xx_add_device_gpio_buttons(-1, PB42_BUTTONS_POLL_INTERVAL,
++				       ARRAY_SIZE(pb42_gpio_buttons),
++				       pb42_gpio_buttons);
++
++	pb42_pci_init();
++}
++
++MIPS_MACHINE(AR71XX_MACH_PB42, "PB42", "Atheros PB42", pb42_init);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-pb44.c linux-2.6.33.3/arch/mips/ar71xx/mach-pb44.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-pb44.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-pb44.c	2010-05-16 13:17:32.783600171 +0200
+@@ -0,0 +1,207 @@
++/*
++ *  Atheros PB44 board support
++ *
++ *  Copyright (C) 2009 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/init.h>
++#include <linux/bitops.h>
++#include <linux/delay.h>
++#include <linux/platform_device.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/flash.h>
++#include <linux/spi/vsc7385.h>
++#include <linux/i2c.h>
++#include <linux/i2c-gpio.h>
++#include <linux/i2c/pcf857x.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-pb42-pci.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "dev-usb.h"
++
++#define PB44_PCF8757_VSC7395_CS	0
++#define PB44_PCF8757_STEREO_CS	1
++#define PB44_PCF8757_SLIC_CS0	2
++#define PB44_PCF8757_SLIC_TEST	3
++#define PB44_PCF8757_SLIC_INT0	4
++#define PB44_PCF8757_SLIC_INT1	5
++#define PB44_PCF8757_SW_RESET	6
++#define PB44_PCF8757_SW_JUMP	8
++#define PB44_PCF8757_LED_JUMP1	9
++#define PB44_PCF8757_LED_JUMP2	10
++#define PB44_PCF8757_TP24	11
++#define PB44_PCF8757_TP25	12
++#define PB44_PCF8757_TP26	13
++#define PB44_PCF8757_TP27	14
++#define PB44_PCF8757_TP28	15
++
++#define PB44_GPIO_I2C_SCL	0
++#define PB44_GPIO_I2C_SDA	1
++
++#define PB44_GPIO_EXP_BASE	16
++#define PB44_GPIO_VSC7395_CS	(PB44_GPIO_EXP_BASE + PB44_PCF8757_VSC7395_CS)
++#define PB44_GPIO_SW_RESET	(PB44_GPIO_EXP_BASE + PB44_PCF8757_SW_RESET)
++#define PB44_GPIO_SW_JUMP	(PB44_GPIO_EXP_BASE + PB44_PCF8757_SW_JUMP)
++#define PB44_GPIO_LED_JUMP1	(PB44_GPIO_EXP_BASE + PB44_PCF8757_LED_JUMP1)
++#define PB44_GPIO_LED_JUMP2	(PB44_GPIO_EXP_BASE + PB44_PCF8757_LED_JUMP2)
++
++static struct i2c_gpio_platform_data pb44_i2c_gpio_data = {
++	.sda_pin        = PB44_GPIO_I2C_SDA,
++	.scl_pin        = PB44_GPIO_I2C_SCL,
++};
++
++static struct platform_device pb44_i2c_gpio_device = {
++	.name		= "i2c-gpio",
++	.id		= 0,
++	.dev = {
++		.platform_data	= &pb44_i2c_gpio_data,
++	}
++};
++
++static struct pcf857x_platform_data pb44_pcf857x_data = {
++	.gpio_base	= PB44_GPIO_EXP_BASE,
++};
++
++static struct i2c_board_info pb44_i2c_board_info[] __initdata = {
++	{
++		I2C_BOARD_INFO("pcf8575", 0x20),
++		.platform_data  = &pb44_pcf857x_data,
++	},
++};
++
++static struct gpio_led pb44_leds_gpio[] __initdata = {
++	{
++		.name		= "pb44:amber:jump1",
++		.gpio		= PB44_GPIO_LED_JUMP1,
++		.active_low	= 1,
++	}, {
++		.name		= "pb44:green:jump2",
++		.gpio		= PB44_GPIO_LED_JUMP2,
++		.active_low	= 1,
++	},
++};
++
++static struct gpio_button pb44_gpio_buttons[] __initdata = {
++	{
++		.desc		= "soft_reset",
++		.type		= EV_KEY,
++		.code		= KEY_RESTART,
++		.threshold	= 3,
++		.gpio		= PB44_GPIO_SW_RESET,
++		.active_low	= 1,
++	} , {
++		.desc		= "jumpstart",
++		.type		= EV_KEY,
++		.code		= KEY_WPS_BUTTON,
++		.threshold	= 3,
++		.gpio		= PB44_GPIO_SW_JUMP,
++		.active_low	= 1,
++	}
++};
++
++static void pb44_vsc7395_reset(void)
++{
++	ar71xx_device_stop(RESET_MODULE_GE1_PHY);
++	udelay(10);
++	ar71xx_device_start(RESET_MODULE_GE1_PHY);
++	mdelay(50);
++}
++
++static struct vsc7385_platform_data pb44_vsc7395_data = {
++	.reset		= pb44_vsc7395_reset,
++	.ucode_name	= "vsc7395_ucode_pb44.bin",
++	.mac_cfg = {
++		.tx_ipg		= 6,
++		.bit2		= 1,
++		.clk_sel	= 0,
++	},
++};
++
++static struct spi_board_info pb44_spi_info[] = {
++	{
++		.bus_num	= 0,
++		.chip_select	= 0,
++		.max_speed_hz	= 25000000,
++		.modalias	= "m25p80",
++	}, {
++		.bus_num	= 0,
++		.chip_select	= 1,
++		.max_speed_hz	= 25000000,
++		.modalias	= "spi-vsc7385",
++		.platform_data	= &pb44_vsc7395_data,
++		.controller_data = (void *) PB44_GPIO_VSC7395_CS,
++	},
++};
++
++static struct resource pb44_spi_resources[] = {
++	[0] = {
++		.start	= AR71XX_SPI_BASE,
++		.end	= AR71XX_SPI_BASE + AR71XX_SPI_SIZE - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++};
++
++static struct ar71xx_spi_platform_data pb44_spi_data = {
++	.bus_num		= 0,
++	.num_chipselect		= 2,
++};
++
++static struct platform_device pb44_spi_device = {
++	.name		= "pb44-spi",
++	.id		= -1,
++	.resource	= pb44_spi_resources,
++	.num_resources	= ARRAY_SIZE(pb44_spi_resources),
++	.dev = {
++		.platform_data = &pb44_spi_data,
++	},
++};
++
++#define PB44_WAN_PHYMASK	BIT(0)
++#define PB44_LAN_PHYMASK	0
++#define PB44_MDIO_PHYMASK	(PB44_LAN_PHYMASK | PB44_WAN_PHYMASK)
++
++static void __init pb44_init(void)
++{
++	ar71xx_add_device_mdio(~PB44_MDIO_PHYMASK);
++
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++	ar71xx_eth0_data.phy_mask = PB44_WAN_PHYMASK;
++
++	ar71xx_add_device_eth(0);
++
++	ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++	ar71xx_eth1_data.speed = SPEED_1000;
++	ar71xx_eth1_data.duplex = DUPLEX_FULL;
++	ar71xx_eth1_pll_data.pll_1000 = 0x110000;
++
++	ar71xx_add_device_eth(1);
++
++	ar71xx_add_device_usb();
++
++	pb42_pci_init();
++
++	i2c_register_board_info(0, pb44_i2c_board_info,
++ 				ARRAY_SIZE(pb44_i2c_board_info));
++
++	platform_device_register(&pb44_i2c_gpio_device);
++
++	spi_register_board_info(pb44_spi_info, ARRAY_SIZE(pb44_spi_info));
++	platform_device_register(&pb44_spi_device);
++
++	ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(pb44_leds_gpio),
++				    pb44_leds_gpio);
++
++	ar71xx_add_device_gpio_buttons(-1, 20, ARRAY_SIZE(pb44_gpio_buttons),
++				       pb44_gpio_buttons);
++}
++
++MIPS_MACHINE(AR71XX_MACH_PB44, "PB44", "Atheros PB44", pb44_init);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-pb92.c linux-2.6.33.3/arch/mips/ar71xx/mach-pb92.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-pb92.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-pb92.c	2010-04-14 21:17:12.138345698 +0200
+@@ -0,0 +1,109 @@
++/*
++ *  Atheros PB92 board support
++ *
++ *  Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-gpio-buttons.h"
++#include "dev-pb9x-pci.h"
++#include "dev-usb.h"
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition pb92_partitions[] = {
++	{
++		.name		= "u-boot",
++		.offset		= 0,
++		.size		= 0x040000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "u-boot-env",
++		.offset		= 0x040000,
++		.size		= 0x010000,
++	} , {
++		.name		= "rootfs",
++		.offset		= 0x050000,
++		.size		= 0x2b0000,
++	} , {
++		.name		= "uImage",
++		.offset		= 0x300000,
++		.size		= 0x0e0000,
++	} , {
++		.name		= "ART",
++		.offset		= 0x3e0000,
++		.size		= 0x020000,
++		.mask_flags	= MTD_WRITEABLE,
++	}
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data pb92_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++        .parts          = pb92_partitions,
++        .nr_parts       = ARRAY_SIZE(pb92_partitions),
++#endif
++};
++
++
++#define PB92_BUTTONS_POLL_INTERVAL	20
++
++#define PB92_GPIO_BTN_SW4	8
++#define PB92_GPIO_BTN_SW5	3
++
++static struct gpio_button pb92_gpio_buttons[] __initdata = {
++	{
++		.desc		= "sw4",
++		.type		= EV_KEY,
++		.code		= BTN_0,
++		.threshold	= 3,
++		.gpio		= PB92_GPIO_BTN_SW4,
++		.active_low	= 1,
++	} , {
++		.desc		= "sw5",
++		.type		= EV_KEY,
++		.code		= BTN_1,
++		.threshold	= 3,
++		.gpio		= PB92_GPIO_BTN_SW5,
++		.active_low	= 1,
++	}
++};
++
++static void __init pb92_init(void)
++{
++	u8 *mac = (u8 *) KSEG1ADDR(0x1fff0000);
++
++	ar71xx_set_mac_base(mac);
++	ar71xx_add_device_m25p80(&pb92_flash_data);
++
++	ar71xx_add_device_mdio(~0);
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth0_data.speed = SPEED_1000;
++	ar71xx_eth0_data.duplex = DUPLEX_FULL;
++
++	ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth1_data.speed = SPEED_1000;
++	ar71xx_eth1_data.duplex = DUPLEX_FULL;
++
++	ar71xx_add_device_eth(0);
++	ar71xx_add_device_eth(1);
++
++	ar71xx_add_device_gpio_buttons(-1, PB92_BUTTONS_POLL_INTERVAL,
++				       ARRAY_SIZE(pb92_gpio_buttons),
++				       pb92_gpio_buttons);
++
++	pb9x_pci_init();
++}
++
++MIPS_MACHINE(AR71XX_MACH_PB92, "PB92", "Atheros PB92", pb92_init);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-rb4xx.c linux-2.6.33.3/arch/mips/ar71xx/mach-rb4xx.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-rb4xx.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-rb4xx.c	2010-05-16 13:17:32.763620812 +0200
+@@ -0,0 +1,290 @@
++/*
++ *  MikroTik RouterBOARD 4xx series support
++ *
++ *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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/platform_device.h>
++#include <linux/irq.h>
++#include <linux/mmc/host.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/flash.h>
++#include <linux/spi/mmc_spi.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/pci.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "dev-usb.h"
++
++#define RB4XX_GPIO_USER_LED	4
++#define RB4XX_GPIO_RESET_SWITCH	7
++
++#define RB4XX_BUTTONS_POLL_INTERVAL	20
++
++static struct gpio_led rb4xx_leds_gpio[] __initdata = {
++	{
++		.name		= "rb4xx:yellow:user",
++		.gpio		= RB4XX_GPIO_USER_LED,
++		.active_low	= 0,
++	},
++};
++
++static struct gpio_button rb4xx_gpio_buttons[] __initdata = {
++	{
++		.desc		= "reset_switch",
++		.type		= EV_KEY,
++		.code		= KEY_RESTART,
++		.threshold	= 3,
++		.gpio		= RB4XX_GPIO_RESET_SWITCH,
++		.active_low	= 1,
++	}
++};
++
++static struct platform_device rb4xx_nand_device = {
++	.name	= "rb4xx-nand",
++	.id	= -1,
++};
++
++static struct ar71xx_pci_irq rb4xx_pci_irqs[] __initdata = {
++	{
++		.slot	= 0,
++		.pin	= 1,
++		.irq	= AR71XX_PCI_IRQ_DEV2,
++	}, {
++		.slot	= 1,
++		.pin	= 1,
++		.irq	= AR71XX_PCI_IRQ_DEV0,
++	}, {
++		.slot	= 1,
++		.pin	= 2,
++		.irq	= AR71XX_PCI_IRQ_DEV1,
++	}, {
++		.slot	= 2,
++		.pin	= 1,
++		.irq	= AR71XX_PCI_IRQ_DEV1,
++	}, {
++		.slot	= 3,
++		.pin	= 1,
++		.irq	= AR71XX_PCI_IRQ_DEV2,
++	}
++};
++
++#if 0
++/*
++ * SPI device support is experimental
++ */
++static struct flash_platform_data rb4xx_flash_data = {
++	.type	= "pm25lv512",
++};
++
++static struct spi_board_info rb4xx_spi_info[] = {
++	{
++		.bus_num	= 0,
++		.chip_select	= 0,
++		.max_speed_hz	= 25000000,
++		.modalias	= "m25p80",
++		.platform_data	= &rb4xx_flash_data,
++	}
++};
++
++static struct mmc_spi_platform_data rb433_mmc_data = {
++	.ocr_mask	= MMC_VDD_32_33 | MMC_VDD_33_34,
++};
++
++static struct spi_board_info rb433_spi_info[] = {
++	{
++		.bus_num	= 0,
++		.chip_select	= 0,
++		.max_speed_hz	= 25000000,
++		.modalias	= "m25p80",
++		.platform_data	= &rb433_flash_data,
++	}, {
++		.bus_num	= 0,
++		.chip_select	= 2,
++		.max_speed_hz	= 25000000,
++		.modalias	= "mmc_spi",
++		.platform_data	= &rb433_mmc_data,
++	}
++};
++
++static u32 rb433_spi_get_ioc_base(u8 chip_select, int cs_high, int is_on)
++{
++	u32 ret;
++
++	if (is_on == AR71XX_SPI_CS_INACTIVE) {
++		ret = SPI_IOC_CS0 | SPI_IOC_CS1;
++	} else {
++		if (cs_high) {
++			ret = SPI_IOC_CS0 | SPI_IOC_CS1;
++		} else {
++			if ((chip_select ^ 2) == 0)
++				ret = SPI_IOC_CS1 ^ (SPI_IOC_CS0 | SPI_IOC_CS1);
++			else
++				ret = SPI_IOC_CS0 ^ (SPI_IOC_CS0 | SPI_IOC_CS1);
++		}
++	}
++
++	return ret;
++}
++
++struct ar71xx_spi_platform_data rb433_spi_data = {
++	.bus_num		= 0,
++	.num_chipselect		= 3,
++	.get_ioc_base		= rb433_spi_get_ioc_base,
++};
++
++static void rb4xx_add_device_spi(void)
++{
++	ar71xx_add_device_spi(NULL, rb4xx_spi_info, ARRAY_SIZE(rb4xx_spi_info));
++}
++
++static void rb433_add_device_spi(void)
++{
++	ar71xx_add_device_spi(&rb433_spi_data, rb433_spi_info,
++				ARRAY_SIZE(rb433_spi_info));
++}
++#else
++static inline void rb4xx_add_device_spi(void) {}
++static inline void rb433_add_device_spi(void) {}
++#endif
++
++static void __init rb4xx_generic_setup(void)
++{
++	ar71xx_gpio_function_enable(AR71XX_GPIO_FUNC_SPI_CS1_EN |
++				    AR71XX_GPIO_FUNC_SPI_CS2_EN);
++
++	ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(rb4xx_leds_gpio),
++					rb4xx_leds_gpio);
++
++	ar71xx_add_device_gpio_buttons(-1, RB4XX_BUTTONS_POLL_INTERVAL,
++					ARRAY_SIZE(rb4xx_gpio_buttons),
++					rb4xx_gpio_buttons);
++
++	platform_device_register(&rb4xx_nand_device);
++}
++
++static void __init rb411_setup(void)
++{
++	rb4xx_generic_setup();
++	rb4xx_add_device_spi();
++
++	ar71xx_add_device_mdio(0xfffffffc);
++
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
++	ar71xx_eth0_data.phy_mask = 0x00000003;
++
++	ar71xx_add_device_eth(0);
++
++	ar71xx_pci_init(ARRAY_SIZE(rb4xx_pci_irqs), rb4xx_pci_irqs);
++}
++
++MIPS_MACHINE(AR71XX_MACH_RB_411, "411", "MikroTik RouterBOARD 411/A/AH",
++	     rb411_setup);
++
++static void __init rb411u_setup(void)
++{
++	rb411_setup();
++	ar71xx_add_device_usb();
++}
++
++MIPS_MACHINE(AR71XX_MACH_RB_411U, "411U", "MikroTik RouterBOARD 411U",
++	     rb411u_setup);
++
++static void __init rb433_setup(void)
++{
++	rb4xx_generic_setup();
++	rb433_add_device_spi();
++
++	ar71xx_add_device_mdio(0xffffffe9);
++
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
++	ar71xx_eth0_data.speed = SPEED_100;
++	ar71xx_eth0_data.duplex = DUPLEX_FULL;
++
++	ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth1_data.phy_mask = 0x00000010;
++
++	ar71xx_add_device_eth(1);
++	ar71xx_add_device_eth(0);
++
++	ar71xx_pci_init(ARRAY_SIZE(rb4xx_pci_irqs), rb4xx_pci_irqs);
++}
++
++MIPS_MACHINE(AR71XX_MACH_RB_433, "433", "MikroTik RouterBOARD 433/AH",
++	     rb433_setup);
++
++static void __init rb433u_setup(void)
++{
++	rb433_setup();
++	ar71xx_add_device_usb();
++}
++
++MIPS_MACHINE(AR71XX_MACH_RB_433U, "433U", "MikroTik RouterBOARD 433UAH",
++	     rb433u_setup);
++
++static void __init rb450_generic_setup(int gige)
++{
++	rb4xx_generic_setup();
++	rb4xx_add_device_spi();
++
++	ar71xx_add_device_mdio(0xffffffe0);
++
++	ar71xx_eth0_data.phy_if_mode = (gige) ? PHY_INTERFACE_MODE_RGMII : PHY_INTERFACE_MODE_MII;
++	ar71xx_eth0_data.phy_mask = (gige) ? (1 << 0) : 0;
++	ar71xx_eth0_data.speed = (gige) ? SPEED_1000 : SPEED_100;
++	ar71xx_eth0_data.duplex = DUPLEX_FULL;
++
++	ar71xx_eth1_data.phy_if_mode = (gige) ? PHY_INTERFACE_MODE_RGMII : PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth1_data.phy_mask = 0x00000010;
++
++	ar71xx_add_device_eth(1);
++	ar71xx_add_device_eth(0);
++}
++
++static void __init rb450_setup(void)
++{
++	rb450_generic_setup(0);
++}
++
++MIPS_MACHINE(AR71XX_MACH_RB_450, "450", "MikroTik RouterBOARD 450",
++	     rb450_setup);
++
++static void __init rb450g_setup(void)
++{
++	rb450_generic_setup(1);
++}
++
++MIPS_MACHINE(AR71XX_MACH_RB_450G, "450G", "MikroTik RouterBOARD 450G",
++	     rb450g_setup);
++
++static void __init rb493_setup(void)
++{
++	rb4xx_generic_setup();
++	rb4xx_add_device_spi();
++
++	ar71xx_add_device_mdio(0x3fffff00);
++
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
++	ar71xx_eth0_data.speed = SPEED_100;
++	ar71xx_eth0_data.duplex = DUPLEX_FULL;
++
++	ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth1_data.phy_mask = 0x00000001;
++
++	ar71xx_add_device_eth(0);
++	ar71xx_add_device_eth(1);
++
++	ar71xx_pci_init(ARRAY_SIZE(rb4xx_pci_irqs), rb4xx_pci_irqs);
++}
++
++MIPS_MACHINE(AR71XX_MACH_RB_493, "493", "MikroTik RouterBOARD 493/AH",
++	     rb493_setup);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-rb750.c linux-2.6.33.3/arch/mips/ar71xx/mach-rb750.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-rb750.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-rb750.c	2010-03-12 19:31:46.886045750 +0100
+@@ -0,0 +1,133 @@
++/*
++ *  MikroTik RouterBOARD 750 support
++ *
++ *  Copyright (C) 2010 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/platform_device.h>
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/mach-rb750.h>
++
++#include "machtype.h"
++#include "dev-ap91-eth.h"
++
++static struct rb750_led_data rb750_leds[] = {
++	{
++		.name		= "rb750:green:act",
++		.mask		= RB750_LED_ACT,
++		.active_low	= 1,
++	}, {
++		.name		= "rb750:green:port1",
++		.mask		= RB750_LED_PORT5,
++		.active_low	= 1,
++	}, {
++		.name		= "rb750:green:port2",
++		.mask		= RB750_LED_PORT4,
++		.active_low	= 1,
++	}, {
++		.name		= "rb750:green:port3",
++		.mask		= RB750_LED_PORT3,
++		.active_low	= 1,
++	}, {
++		.name		= "rb750:green:port4",
++		.mask		= RB750_LED_PORT2,
++		.active_low	= 1,
++	}, {
++		.name		= "rb750:green:port5",
++		.mask		= RB750_LED_PORT1,
++		.active_low	= 1,
++	}
++};
++
++static struct rb750_led_platform_data rb750_leds_data = {
++	.num_leds	= ARRAY_SIZE(rb750_leds),
++	.leds		= rb750_leds,
++};
++
++static struct platform_device rb750_leds_device = {
++	.name	= "leds-rb750",
++	.dev	= {
++		.platform_data = &rb750_leds_data,
++	}
++};
++
++static const char *rb750_port_names[AP91_ETH_NUM_PORT_NAMES] __initdata = {
++	"port5",
++	"port4",
++	"port3",
++	"port2",
++};
++
++static struct platform_device rb750_nand_device = {
++	.name	= "rb750-nand",
++	.id	= -1,
++};
++
++int rb750_latch_change(u32 mask_clr, u32 mask_set)
++{
++	static DEFINE_SPINLOCK(lock);
++	static u32 latch_set = RB750_LED_BITS | RB750_LVC573_LE;
++	static u32 latch_oe;
++	static u32 latch_clr;
++	unsigned long flags;
++	u32 t;
++	int ret = 0;
++
++	spin_lock_irqsave(&lock, flags);
++
++	if ((mask_clr & BIT(31)) != 0 &&
++	    (latch_set & RB750_LVC573_LE) == 0) {
++		goto unlock;
++	}
++
++	latch_set = (latch_set | mask_set) & ~mask_clr;
++	latch_clr = (latch_clr | mask_clr) & ~mask_set;
++
++	if (latch_oe == 0)
++		latch_oe = __raw_readl(ar71xx_gpio_base + GPIO_REG_OE);
++
++	if (likely(latch_set & RB750_LVC573_LE)) {
++		void __iomem *base = ar71xx_gpio_base;
++
++		t = __raw_readl(base + GPIO_REG_OE);
++		t |= mask_clr | latch_oe | mask_set;
++
++		__raw_writel(t, base + GPIO_REG_OE);
++		__raw_writel(latch_clr, base + GPIO_REG_CLEAR);
++		__raw_writel(latch_set, base + GPIO_REG_SET);
++	} else if (mask_clr & RB750_LVC573_LE) {
++		void __iomem *base = ar71xx_gpio_base;
++
++		latch_oe = __raw_readl(base + GPIO_REG_OE);
++		__raw_writel(RB750_LVC573_LE, base + GPIO_REG_CLEAR);
++		/* flush write */
++		__raw_readl(base + GPIO_REG_CLEAR);
++	}
++
++	ret = 1;
++
++ unlock:
++	spin_unlock_irqrestore(&lock, flags);
++	return ret;
++}
++EXPORT_SYMBOL_GPL(rb750_latch_change);
++
++static void __init rb750_setup(void)
++{
++	ar71xx_gpio_function_disable(AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
++				     AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
++				     AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
++				     AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
++				     AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
++
++	ap91_eth_init(NULL, rb750_port_names);
++	platform_device_register(&rb750_leds_device);
++	platform_device_register(&rb750_nand_device);
++}
++
++MIPS_MACHINE(AR71XX_MACH_RB_750, "750i", "MikroTik RouterBOARD 750",
++	     rb750_setup);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-tew-632brp.c linux-2.6.33.3/arch/mips/ar71xx/mach-tew-632brp.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-tew-632brp.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-tew-632brp.c	2010-05-16 13:17:32.899597622 +0200
+@@ -0,0 +1,149 @@
++/*
++ *  TrendNET TEW-632BRP board support
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ar913x-wmac.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "nvram.h"
++
++#define TEW_632BRP_GPIO_LED_STATUS	1
++#define TEW_632BRP_GPIO_LED_WPS		3
++#define TEW_632BRP_GPIO_LED_WLAN	6
++#define TEW_632BRP_GPIO_BTN_WPS		12
++#define TEW_632BRP_GPIO_BTN_RESET	21
++
++#define TEW_632BRP_BUTTONS_POLL_INTERVAL	20
++
++#define TEW_632BRP_CONFIG_ADDR	0x1f020000
++#define TEW_632BRP_CONFIG_SIZE	0x10000
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition tew_632brp_partitions[] = {
++	{
++		.name		= "u-boot",
++		.offset		= 0,
++		.size		= 0x020000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "config",
++		.offset		= 0x020000,
++		.size		= 0x010000,
++	} , {
++		.name		= "kernel",
++		.offset		= 0x030000,
++		.size		= 0x0d0000,
++	} , {
++		.name		= "rootfs",
++		.offset		= 0x100000,
++		.size		= 0x2f0000,
++	} , {
++		.name		= "art",
++		.offset		= 0x3f0000,
++		.size		= 0x010000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "firmware",
++		.offset		= 0x030000,
++		.size		= 0x3c0000,
++	}
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data tew_632brp_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++        .parts          = tew_632brp_partitions,
++        .nr_parts       = ARRAY_SIZE(tew_632brp_partitions),
++#endif
++};
++
++static struct gpio_led tew_632brp_leds_gpio[] __initdata = {
++	{
++		.name		= "tew-632brp:green:status",
++		.gpio		= TEW_632BRP_GPIO_LED_STATUS,
++		.active_low	= 1,
++	}, {
++		.name		= "tew-632brp:blue:wps",
++		.gpio		= TEW_632BRP_GPIO_LED_WPS,
++		.active_low	= 1,
++	}, {
++		.name		= "tew-632brp:green:wlan",
++		.gpio		= TEW_632BRP_GPIO_LED_WLAN,
++		.active_low	= 1,
++	}
++};
++
++static struct gpio_button tew_632brp_gpio_buttons[] __initdata = {
++	{
++		.desc		= "reset",
++		.type		= EV_KEY,
++		.code		= KEY_RESTART,
++		.threshold	= 3,
++		.gpio		= TEW_632BRP_GPIO_BTN_RESET,
++	}, {
++		.desc		= "wps",
++		.type		= EV_KEY,
++		.code		= KEY_WPS_BUTTON,
++		.threshold	= 3,
++		.gpio		= TEW_632BRP_GPIO_BTN_WPS,
++	}
++};
++
++#define TEW_632BRP_LAN_PHYMASK	BIT(0)
++#define TEW_632BRP_WAN_PHYMASK	BIT(4)
++#define TEW_632BRP_MDIO_MASK	(~(TEW_632BRP_LAN_PHYMASK | \
++				   TEW_632BRP_WAN_PHYMASK))
++
++static void __init tew_632brp_setup(void)
++{
++	const char *config = (char *) KSEG1ADDR(TEW_632BRP_CONFIG_ADDR);
++	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
++	u8 mac[6];
++	u8 *wlan_mac = NULL;
++
++	if (nvram_parse_mac_addr(config, TEW_632BRP_CONFIG_SIZE,
++			         "lan_mac=", mac) == 0) {
++		ar71xx_set_mac_base(mac);
++		wlan_mac = mac;
++	}
++
++	ar71xx_add_device_mdio(TEW_632BRP_MDIO_MASK);
++
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth0_data.phy_mask = TEW_632BRP_LAN_PHYMASK;
++
++	ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth1_data.phy_mask = TEW_632BRP_WAN_PHYMASK;
++
++	ar71xx_add_device_eth(0);
++	ar71xx_add_device_eth(1);
++
++	ar71xx_add_device_m25p80(&tew_632brp_flash_data);
++
++	ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(tew_632brp_leds_gpio),
++					tew_632brp_leds_gpio);
++
++	ar71xx_add_device_gpio_buttons(-1, TEW_632BRP_BUTTONS_POLL_INTERVAL,
++					ARRAY_SIZE(tew_632brp_gpio_buttons),
++					tew_632brp_gpio_buttons);
++
++	ar913x_add_device_wmac(eeprom, wlan_mac);
++}
++
++MIPS_MACHINE(AR71XX_MACH_TEW_632BRP, "TEW-632BRP", "TRENDnet TEW-632BRP",
++	     tew_632brp_setup);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-tl-wr1043nd.c linux-2.6.33.3/arch/mips/ar71xx/mach-tl-wr1043nd.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-tl-wr1043nd.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-tl-wr1043nd.c	2010-05-16 13:17:31.779600220 +0200
+@@ -0,0 +1,156 @@
++/*
++ *  TP-LINK TL-WR1043ND board support
++ *
++ *  Copyright (C) 2009 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/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/platform_device.h>
++#include <linux/rtl8366rb.h>
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ar913x-wmac.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "dev-usb.h"
++
++#define TL_WR1043ND_GPIO_LED_USB        1
++#define TL_WR1043ND_GPIO_LED_SYSTEM     2
++#define TL_WR1043ND_GPIO_LED_QSS        5
++#define TL_WR1043ND_GPIO_LED_WLAN       9
++
++#define TL_WR1043ND_GPIO_BTN_RESET      3
++#define TL_WR1043ND_GPIO_BTN_QSS        7
++
++#define TL_WR1043ND_GPIO_RTL8366_SDA	18
++#define TL_WR1043ND_GPIO_RTL8366_SCK	19
++
++#define TL_WR1043ND_BUTTONS_POLL_INTERVAL     20
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition tl_wr1043nd_partitions[] = {
++	{
++		.name		= "u-boot",
++		.offset		= 0,
++		.size		= 0x020000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "kernel",
++		.offset		= 0x020000,
++		.size		= 0x140000,
++	} , {
++		.name		= "rootfs",
++		.offset		= 0x160000,
++		.size		= 0x690000,
++	} , {
++		.name		= "art",
++		.offset		= 0x7f0000,
++		.size		= 0x010000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "firmware",
++		.offset		= 0x020000,
++		.size		= 0x7d0000,
++	}
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data tl_wr1043nd_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++	.parts		= tl_wr1043nd_partitions,
++	.nr_parts	= ARRAY_SIZE(tl_wr1043nd_partitions),
++#endif
++};
++
++static struct gpio_led tl_wr1043nd_leds_gpio[] __initdata = {
++	{
++		.name		= "tl-wr1043nd:green:usb",
++		.gpio		= TL_WR1043ND_GPIO_LED_USB,
++		.active_low	= 1,
++	}, {
++		.name		= "tl-wr1043nd:green:system",
++		.gpio		= TL_WR1043ND_GPIO_LED_SYSTEM,
++		.active_low	= 1,
++	}, {
++		.name		= "tl-wr1043nd:green:qss",
++		.gpio		= TL_WR1043ND_GPIO_LED_QSS,
++		.active_low	= 0,
++	}, {
++		.name		= "tl-wr1043nd:green:wlan",
++		.gpio		= TL_WR1043ND_GPIO_LED_WLAN,
++		.active_low	= 1,
++	}
++};
++
++static struct gpio_button tl_wr1043nd_gpio_buttons[] __initdata = {
++	{
++		.desc		= "reset",
++		.type		= EV_KEY,
++		.code		= KEY_RESTART,
++		.threshold	= 3,
++		.gpio		= TL_WR1043ND_GPIO_BTN_RESET,
++		.active_low	= 1,
++	}, {
++		.desc		= "qss",
++		.type		= EV_KEY,
++		.code		= KEY_WPS_BUTTON,
++		.threshold	= 3,
++		.gpio		= TL_WR1043ND_GPIO_BTN_QSS,
++		.active_low	= 1,
++	}
++};
++
++static struct rtl8366rb_platform_data tl_wr1043nd_rtl8366rb_data = {
++	.gpio_sda        = TL_WR1043ND_GPIO_RTL8366_SDA,
++	.gpio_sck        = TL_WR1043ND_GPIO_RTL8366_SCK,
++};
++
++static struct platform_device tl_wr1043nd_rtl8366rb_device = {
++	.name		= RTL8366RB_DRIVER_NAME,
++	.id		= -1,
++	.dev = {
++		.platform_data	= &tl_wr1043nd_rtl8366rb_data,
++	}
++};
++
++static void __init tl_wr1043nd_setup(void)
++{
++	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
++	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
++
++	ar71xx_set_mac_base(mac);
++
++	ar71xx_eth0_data.mii_bus_dev = &tl_wr1043nd_rtl8366rb_device.dev;
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++	ar71xx_eth0_data.speed = SPEED_1000;
++	ar71xx_eth0_data.duplex = DUPLEX_FULL;
++	ar71xx_eth0_pll_data.pll_1000 = 0x1a000000;
++
++	ar71xx_add_device_eth(0);
++
++	ar71xx_add_device_usb();
++
++	ar71xx_add_device_m25p80(&tl_wr1043nd_flash_data);
++
++	ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(tl_wr1043nd_leds_gpio),
++					tl_wr1043nd_leds_gpio);
++
++	platform_device_register(&tl_wr1043nd_rtl8366rb_device);
++
++	ar71xx_add_device_gpio_buttons(-1, TL_WR1043ND_BUTTONS_POLL_INTERVAL,
++					ARRAY_SIZE(tl_wr1043nd_gpio_buttons),
++					tl_wr1043nd_gpio_buttons);
++
++	ar913x_add_device_wmac(eeprom, mac);
++}
++
++MIPS_MACHINE(AR71XX_MACH_TL_WR1043ND, "TL-WR1043ND", "TP-LINK TL-WR1043ND",
++	     tl_wr1043nd_setup);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-tl-wr741nd.c linux-2.6.33.3/arch/mips/ar71xx/mach-tl-wr741nd.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-tl-wr741nd.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-tl-wr741nd.c	2010-05-16 13:17:33.043600332 +0200
+@@ -0,0 +1,115 @@
++/*
++ *  TP-LINK TL-WR741ND board support
++ *
++ *  Copyright (C) 2009-2010 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/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ap91-eth.h"
++#include "dev-ap91-pci.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++
++#define TL_WR741ND_GPIO_LED_QSS		0
++#define TL_WR741ND_GPIO_LED_SYSTEM	1
++
++#define TL_WR741ND_GPIO_BTN_RESET	11
++#define TL_WR741ND_GPIO_BTN_QSS		12
++
++#define TL_WR741ND_BUTTONS_POLL_INTERVAL	20
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition tl_wr741nd_partitions[] = {
++	{
++		.name		= "u-boot",
++		.offset		= 0,
++		.size		= 0x020000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "kernel",
++		.offset		= 0x020000,
++		.size		= 0x140000,
++	} , {
++		.name		= "rootfs",
++		.offset		= 0x160000,
++		.size		= 0x290000,
++	} , {
++		.name		= "art",
++		.offset		= 0x3f0000,
++		.size		= 0x010000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "firmware",
++		.offset		= 0x020000,
++		.size		= 0x3d0000,
++	}
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data tl_wr741nd_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++        .parts          = tl_wr741nd_partitions,
++        .nr_parts       = ARRAY_SIZE(tl_wr741nd_partitions),
++#endif
++};
++
++static struct gpio_led tl_wr741nd_leds_gpio[] __initdata = {
++	{
++		.name		= "tl-wr741nd:green:system",
++		.gpio		= TL_WR741ND_GPIO_LED_SYSTEM,
++		.active_low	= 1,
++	}, {
++		.name		= "tl-wr741nd:green:qss",
++		.gpio		= TL_WR741ND_GPIO_LED_QSS,
++		.active_low	= 1,
++	}
++};
++
++static struct gpio_button tl_wr741nd_gpio_buttons[] __initdata = {
++	{
++		.desc		= "reset",
++		.type		= EV_KEY,
++		.code		= KEY_RESTART,
++		.threshold	= 3,
++		.gpio		= TL_WR741ND_GPIO_BTN_RESET,
++		.active_low	= 1,
++	}, {
++		.desc		= "qss",
++		.type		= EV_KEY,
++		.code		= KEY_WPS_BUTTON,
++		.threshold	= 3,
++		.gpio		= TL_WR741ND_GPIO_BTN_QSS,
++		.active_low	= 1,
++	}
++};
++
++static void __init tl_wr741nd_setup(void)
++{
++	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
++	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
++
++	ar71xx_add_device_m25p80(&tl_wr741nd_flash_data);
++
++	ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(tl_wr741nd_leds_gpio),
++					tl_wr741nd_leds_gpio);
++
++	ar71xx_add_device_gpio_buttons(-1, TL_WR741ND_BUTTONS_POLL_INTERVAL,
++					ARRAY_SIZE(tl_wr741nd_gpio_buttons),
++					tl_wr741nd_gpio_buttons);
++
++	ap91_eth_init(mac, NULL);
++	ap91_pci_init(ee, mac);
++}
++MIPS_MACHINE(AR71XX_MACH_TL_WR741ND, "TL-WR741ND", "TP-LINK TL-WR741ND",
++	     tl_wr741nd_setup);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-tl-wr841n.c linux-2.6.33.3/arch/mips/ar71xx/mach-tl-wr841n.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-tl-wr841n.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-tl-wr841n.c	2010-05-16 13:17:32.951604530 +0200
+@@ -0,0 +1,143 @@
++/*
++ *  TP-LINK TL-WR841N board support
++ *
++ *  Copyright (C) 2009 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/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-dsa.h"
++#include "dev-m25p80.h"
++#include "dev-gpio-buttons.h"
++#include "dev-pb42-pci.h"
++#include "dev-leds-gpio.h"
++
++#define TL_WR841ND_V1_GPIO_LED_SYSTEM		2
++#define TL_WR841ND_V1_GPIO_LED_QSS_GREEN	4
++#define TL_WR841ND_V1_GPIO_LED_QSS_RED		5
++
++#define TL_WR841ND_V1_GPIO_BTN_RESET	3
++#define TL_WR841ND_V1_GPIO_BTN_QSS	7
++
++#define TL_WR841ND_V1_BUTTONS_POLL_INTERVAL	20
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition tl_wr841n_v1_partitions[] = {
++	{
++		.name		= "redboot",
++		.offset		= 0,
++		.size		= 0x020000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "kernel",
++		.offset		= 0x020000,
++		.size		= 0x140000,
++	} , {
++		.name		= "rootfs",
++		.offset		= 0x160000,
++		.size		= 0x280000,
++	} , {
++		.name		= "config",
++		.offset		= 0x3e0000,
++		.size		= 0x020000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "firmware",
++		.offset		= 0x020000,
++		.size		= 0x3c0000,
++	}
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data tl_wr841n_v1_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++        .parts          = tl_wr841n_v1_partitions,
++        .nr_parts       = ARRAY_SIZE(tl_wr841n_v1_partitions),
++#endif
++};
++
++static struct gpio_led tl_wr841n_v1_leds_gpio[] __initdata = {
++	{
++		.name		= "tl-wr841n:green:system",
++		.gpio		= TL_WR841ND_V1_GPIO_LED_SYSTEM,
++		.active_low	= 1,
++	}, {
++		.name		= "tl-wr841n:red:qss",
++		.gpio		= TL_WR841ND_V1_GPIO_LED_QSS_RED,
++	}, {
++		.name		= "tl-wr841n:green:qss",
++		.gpio		= TL_WR841ND_V1_GPIO_LED_QSS_GREEN,
++	}
++};
++
++static struct gpio_button tl_wr841n_v1_gpio_buttons[] __initdata = {
++	{
++		.desc		= "reset",
++		.type		= EV_KEY,
++		.code		= KEY_RESTART,
++		.threshold	= 3,
++		.gpio		= TL_WR841ND_V1_GPIO_BTN_RESET,
++		.active_low	= 1,
++	}, {
++		.desc		= "qss",
++		.type		= EV_KEY,
++		.code		= KEY_WPS_BUTTON,
++		.threshold	= 3,
++		.gpio		= TL_WR841ND_V1_GPIO_BTN_QSS,
++		.active_low	= 1,
++	}
++};
++
++static struct dsa_chip_data tl_wr841n_v1_dsa_chip = {
++	.port_names[0]  = "wan",
++	.port_names[1]  = "lan1",
++	.port_names[2]  = "lan2",
++	.port_names[3]  = "lan3",
++	.port_names[4]  = "lan4",
++	.port_names[5]  = "cpu",
++};
++
++static struct dsa_platform_data tl_wr841n_v1_dsa_data = {
++	.nr_chips	= 1,
++	.chip		= &tl_wr841n_v1_dsa_chip,
++};
++
++static void __init tl_wr841n_v1_setup(void)
++{
++	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
++
++	ar71xx_set_mac_base(mac);
++
++	ar71xx_add_device_mdio(0x0);
++
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth0_data.speed = SPEED_100;
++	ar71xx_eth0_data.duplex = DUPLEX_FULL;
++
++	ar71xx_add_device_eth(0);
++
++	ar71xx_add_device_dsa(0, &tl_wr841n_v1_dsa_data);
++
++	ar71xx_add_device_m25p80(&tl_wr841n_v1_flash_data);
++
++	ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(tl_wr841n_v1_leds_gpio),
++					tl_wr841n_v1_leds_gpio);
++
++	ar71xx_add_device_gpio_buttons(-1, TL_WR841ND_V1_BUTTONS_POLL_INTERVAL,
++					ARRAY_SIZE(tl_wr841n_v1_gpio_buttons),
++					tl_wr841n_v1_gpio_buttons);
++
++	pb42_pci_init();
++}
++
++MIPS_MACHINE(AR71XX_MACH_TL_WR841N_V1, "TL-WR841N-v1.5", "TP-LINK TL-WR841N v1",
++	     tl_wr841n_v1_setup);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-tl-wr941nd.c linux-2.6.33.3/arch/mips/ar71xx/mach-tl-wr941nd.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-tl-wr941nd.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-tl-wr941nd.c	2010-05-16 13:17:33.088566117 +0200
+@@ -0,0 +1,142 @@
++/*
++ *  TP-LINK TL-WR941ND board support
++ *
++ *  Copyright (C) 2009-2010 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/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-dsa.h"
++#include "dev-m25p80.h"
++#include "dev-ar913x-wmac.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++
++#define TL_WR941ND_GPIO_LED_SYSTEM	2
++#define TL_WR941ND_GPIO_LED_QSS_RED	4
++#define TL_WR941ND_GPIO_LED_QSS_GREEN	5
++
++#define TL_WR941ND_GPIO_BTN_RESET	3
++#define TL_WR941ND_GPIO_BTN_QSS		7
++
++#define TL_WR941ND_BUTTONS_POLL_INTERVAL	20
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition tl_wr941nd_partitions[] = {
++	{
++		.name		= "u-boot",
++		.offset		= 0,
++		.size		= 0x020000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "kernel",
++		.offset		= 0x020000,
++		.size		= 0x140000,
++	} , {
++		.name		= "rootfs",
++		.offset		= 0x160000,
++		.size		= 0x290000,
++	} , {
++		.name		= "art",
++		.offset		= 0x3f0000,
++		.size		= 0x010000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "firmware",
++		.offset		= 0x020000,
++		.size		= 0x3d0000,
++	}
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data tl_wr941nd_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++        .parts          = tl_wr941nd_partitions,
++        .nr_parts       = ARRAY_SIZE(tl_wr941nd_partitions),
++#endif
++};
++
++static struct gpio_led tl_wr941nd_leds_gpio[] __initdata = {
++	{
++		.name		= "tl-wr941nd:green:system",
++		.gpio		= TL_WR941ND_GPIO_LED_SYSTEM,
++		.active_low	= 1,
++	}, {
++		.name		= "tl-wr941nd:red:qss",
++		.gpio		= TL_WR941ND_GPIO_LED_QSS_RED,
++	}, {
++		.name		= "tl-wr941nd:green:qss",
++		.gpio		= TL_WR941ND_GPIO_LED_QSS_GREEN,
++	}
++};
++
++static struct gpio_button tl_wr941nd_gpio_buttons[] __initdata = {
++	{
++		.desc		= "reset",
++		.type		= EV_KEY,
++		.code		= KEY_RESTART,
++		.threshold	= 3,
++		.gpio		= TL_WR941ND_GPIO_BTN_RESET,
++		.active_low	= 1,
++	}, {
++		.desc		= "qss",
++		.type		= EV_KEY,
++		.code		= KEY_WPS_BUTTON,
++		.threshold	= 3,
++		.gpio		= TL_WR941ND_GPIO_BTN_QSS,
++		.active_low	= 1,
++	}
++};
++
++static struct dsa_chip_data tl_wr941nd_dsa_chip = {
++	.port_names[0]  = "wan",
++	.port_names[1]  = "lan1",
++	.port_names[2]  = "lan2",
++	.port_names[3]  = "lan3",
++	.port_names[4]  = "lan4",
++	.port_names[5]  = "cpu",
++};
++
++static struct dsa_platform_data tl_wr941nd_dsa_data = {
++	.nr_chips	= 1,
++	.chip		= &tl_wr941nd_dsa_chip,
++};
++
++static void __init tl_wr941nd_setup(void)
++{
++	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
++	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
++
++	ar71xx_set_mac_base(mac);
++
++	ar71xx_add_device_mdio(0x0);
++
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth0_data.speed = SPEED_100;
++	ar71xx_eth0_data.duplex = DUPLEX_FULL;
++
++	ar71xx_add_device_eth(0);
++	ar71xx_add_device_dsa(0, &tl_wr941nd_dsa_data);
++
++	ar71xx_add_device_m25p80(&tl_wr941nd_flash_data);
++
++	ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(tl_wr941nd_leds_gpio),
++					tl_wr941nd_leds_gpio);
++
++	ar71xx_add_device_gpio_buttons(-1, TL_WR941ND_BUTTONS_POLL_INTERVAL,
++					ARRAY_SIZE(tl_wr941nd_gpio_buttons),
++					tl_wr941nd_gpio_buttons);
++	ar913x_add_device_wmac(eeprom, mac);
++}
++
++MIPS_MACHINE(AR71XX_MACH_TL_WR941ND, "TL-WR941ND", "TP-LINK TL-WR941ND",
++	     tl_wr941nd_setup);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/machtype.h linux-2.6.33.3/arch/mips/ar71xx/machtype.h
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/machtype.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/machtype.h	2010-05-16 13:17:32.799599694 +0200
+@@ -0,0 +1,60 @@
++/*
++ *  Atheros AR71xx machine type definitions
++ *
++ *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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.
++ */
++
++#ifndef _AR71XX_MACHTYPE_H
++#define _AR71XX_MACHTYPE_H
++
++#include <asm/mips_machine.h>
++
++enum ar71xx_mach_type {
++	AR71XX_MACH_GENERIC = 0,
++	AR71XX_MACH_AP81,	/* Atheros AP81 */
++	AR71XX_MACH_AP83,	/* Atheros AP83 */
++	AR71XX_MACH_AW_NR580,	/* AzureWave AW-NR580 */
++	AR71XX_MACH_DIR_600_A1,	/* D-Link DIR-600 rev. A1 */
++	AR71XX_MACH_DIR_615_C1,	/* D-Link DIR-615 rev. C1 */
++	AR71XX_MACH_DIR_825_B1,	/* D-Link DIR-825 rev. B1 */
++	AR71XX_MACH_RB_411,	/* MikroTik RouterBOARD 411/411A/411AH */
++	AR71XX_MACH_RB_411U,	/* MikroTik RouterBOARD 411U */
++	AR71XX_MACH_RB_433,	/* MikroTik RouterBOARD 433/433AH */
++	AR71XX_MACH_RB_433U,	/* MikroTik RouterBOARD 433UAH */
++	AR71XX_MACH_RB_450,	/* MikroTik RouterBOARD 450 */
++	AR71XX_MACH_RB_450G,	/* MikroTik RouterBOARD 450G */
++	AR71XX_MACH_RB_493,	/* Mikrotik RouterBOARD 493/493AH */
++	AR71XX_MACH_RB_750,	/* MikroTik RouterBOARD 750 */
++	AR71XX_MACH_PB42,	/* Atheros PB42 */
++	AR71XX_MACH_PB44,	/* Atheros PB44 */
++	AR71XX_MACH_PB92,	/* Atheros PB92 */
++	AR71XX_MACH_MZK_W04NU,	/* Planex MZK-W04NU */
++	AR71XX_MACH_MZK_W300NH,	/* Planex MZK-W300NH */
++	AR71XX_MACH_NBG460N,	/* Zyxel NBG460N/550N/550NH */
++	AR71XX_MACH_TEW_632BRP,	/* TRENDnet TEW-632BRP */
++	AR71XX_MACH_TL_WR741ND,	/* TP-LINK TL-WR741ND */
++	AR71XX_MACH_TL_WR841N_V1, /* TP-LINK TL-WR841N v1 */
++	AR71XX_MACH_TL_WR941ND,	/* TP-LINK TL-WR941ND */
++	AR71XX_MACH_TL_WR1043ND, /* TP-LINK TL-WR1041ND */
++	AR71XX_MACH_UBNT_LSSR71, /* Ubiquiti LS-SR71 */
++	AR71XX_MACH_UBNT_LSX,	/* Ubiquiti LSX */
++	AR71XX_MACH_UBNT_RS,	/* Ubiquiti RouterStation */
++	AR71XX_MACH_UBNT_AR71XX, /* Ubiquiti AR71xx-based board */
++	AR71XX_MACH_UBNT_RSPRO,	/* Ubiquiti RouterStation Pro */
++	AR71XX_MACH_UBNT_BULLET_M, /* Ubiquiti Bullet M */
++	AR71XX_MACH_UBNT_ROCKET_M, /* Ubiquiti Rocket M */
++	AR71XX_MACH_UBNT_NANO_M, /* Ubiquiti NanoStation M */
++	AR71XX_MACH_WNDR3700,	/* NETGEAR WNDR3700 */
++	AR71XX_MACH_WNR2000,	/* NETGEAR WNR2000 */
++	AR71XX_MACH_WP543,	/* Compex WP543 */
++	AR71XX_MACH_WRT160NL,	/* Linksys WRT160NL */
++	AR71XX_MACH_WRT400N,	/* Linksys WRT400N */
++	AR71XX_MACH_WZR_HP_G300NH, /* Buffalo WZR-HP-G300NH */
++};
++
++#endif /* _AR71XX_MACHTYPE_H */
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-ubnt.c linux-2.6.33.3/arch/mips/ar71xx/mach-ubnt.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-ubnt.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-ubnt.c	2010-05-16 13:17:31.783601847 +0200
+@@ -0,0 +1,281 @@
++/*
++ *  Ubiquiti RouterStation support
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *  Copyright (C) 2008 Ubiquiti <support@ubnt.com>
++ *
++ *  This program is free software; you can redistribute it and/or modify it
++ *  under the terms of the GNU General Public License version 2 as published
++ *  by the Free Software Foundation.
++ */
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ap91-pci.h"
++#include "dev-gpio-buttons.h"
++#include "dev-pb42-pci.h"
++#include "dev-leds-gpio.h"
++#include "dev-usb.h"
++
++#define UBNT_RS_GPIO_LED_RF	2
++#define UBNT_RS_GPIO_SW4	8
++
++#define UBNT_LS_SR71_GPIO_LED_D25	0
++#define UBNT_LS_SR71_GPIO_LED_D26	1
++#define UBNT_LS_SR71_GPIO_LED_D24	2
++#define UBNT_LS_SR71_GPIO_LED_D23	4
++#define UBNT_LS_SR71_GPIO_LED_D22	5
++#define UBNT_LS_SR71_GPIO_LED_D27	6
++#define UBNT_LS_SR71_GPIO_LED_D28	7
++
++#define UBNT_M_GPIO_LED_L1	0
++#define UBNT_M_GPIO_LED_L2	1
++#define UBNT_M_GPIO_LED_L3	11
++#define UBNT_M_GPIO_LED_L4	7
++#define UBNT_M_GPIO_BTN_RESET	12
++
++#define UBNT_BUTTONS_POLL_INTERVAL	20
++
++static struct gpio_led ubnt_rs_leds_gpio[] __initdata = {
++	{
++		.name		= "ubnt:green:rf",
++		.gpio		= UBNT_RS_GPIO_LED_RF,
++		.active_low	= 0,
++	}
++};
++
++static struct gpio_led ubnt_ls_sr71_leds_gpio[] __initdata = {
++	{
++		.name		= "ubnt:green:d22",
++		.gpio		= UBNT_LS_SR71_GPIO_LED_D22,
++		.active_low	= 0,
++	}, {
++		.name		= "ubnt:green:d23",
++		.gpio		= UBNT_LS_SR71_GPIO_LED_D23,
++		.active_low	= 0,
++	}, {
++		.name		= "ubnt:green:d24",
++		.gpio		= UBNT_LS_SR71_GPIO_LED_D24,
++		.active_low	= 0,
++	}, {
++		.name		= "ubnt:red:d25",
++		.gpio		= UBNT_LS_SR71_GPIO_LED_D25,
++		.active_low	= 0,
++	}, {
++		.name		= "ubnt:red:d26",
++		.gpio		= UBNT_LS_SR71_GPIO_LED_D26,
++		.active_low	= 0,
++	}, {
++		.name		= "ubnt:green:d27",
++		.gpio		= UBNT_LS_SR71_GPIO_LED_D27,
++		.active_low	= 0,
++	}, {
++		.name		= "ubnt:green:d28",
++		.gpio		= UBNT_LS_SR71_GPIO_LED_D28,
++		.active_low	= 0,
++	}
++};
++
++static struct gpio_led ubnt_m_leds_gpio[] __initdata = {
++	{
++		.name		= "ubnt:red:link1",
++		.gpio		= UBNT_M_GPIO_LED_L1,
++		.active_low	= 0,
++	}, {
++		.name		= "ubnt:orange:link2",
++		.gpio		= UBNT_M_GPIO_LED_L2,
++		.active_low	= 0,
++	}, {
++		.name		= "ubnt:green:link3",
++		.gpio		= UBNT_M_GPIO_LED_L3,
++		.active_low	= 0,
++	}, {
++		.name		= "ubnt:green:link4",
++		.gpio		= UBNT_M_GPIO_LED_L4,
++		.active_low	= 0,
++	}
++};
++
++static struct gpio_button ubnt_gpio_buttons[] __initdata = {
++	{
++		.desc		= "sw4",
++		.type		= EV_KEY,
++		.code		= KEY_RESTART,
++		.threshold	= 3,
++		.gpio		= UBNT_RS_GPIO_SW4,
++		.active_low	= 1,
++	}
++};
++
++static struct gpio_button ubnt_m_gpio_buttons[] __initdata = {
++	{
++		.desc		= "reset",
++		.type		= EV_KEY,
++		.code		= KEY_RESTART,
++		.threshold	= 3,
++		.gpio		= UBNT_M_GPIO_BTN_RESET,
++		.active_low	= 1,
++	}
++};
++
++static void __init ubnt_generic_setup(void)
++{
++	ar71xx_add_device_m25p80(NULL);
++
++	ar71xx_add_device_gpio_buttons(-1, UBNT_BUTTONS_POLL_INTERVAL,
++					ARRAY_SIZE(ubnt_gpio_buttons),
++					ubnt_gpio_buttons);
++
++	pb42_pci_init();
++}
++
++#define UBNT_RS_WAN_PHYMASK	(1 << 20)
++#define UBNT_RS_LAN_PHYMASK	((1 << 16) | (1 << 17) | (1 << 18) | (1 << 19))
++
++static void __init ubnt_rs_setup(void)
++{
++	ubnt_generic_setup();
++
++	ar71xx_add_device_mdio(~(UBNT_RS_WAN_PHYMASK | UBNT_RS_LAN_PHYMASK));
++
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
++	ar71xx_eth0_data.phy_mask = UBNT_RS_WAN_PHYMASK;
++
++	ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth1_data.speed = SPEED_100;
++	ar71xx_eth1_data.duplex = DUPLEX_FULL;
++
++	ar71xx_add_device_eth(0);
++	ar71xx_add_device_eth(1);
++
++	ar71xx_add_device_usb();
++
++	ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(ubnt_rs_leds_gpio),
++					ubnt_rs_leds_gpio);
++}
++
++MIPS_MACHINE(AR71XX_MACH_UBNT_RS, "UBNT-RS", "Ubiquiti RouterStation",
++	     ubnt_rs_setup);
++
++MIPS_MACHINE(AR71XX_MACH_UBNT_AR71XX, "Ubiquiti AR71xx-based board",
++	     "Ubiquiti RouterStation", ubnt_rs_setup);
++
++#define UBNT_RSPRO_WAN_PHYMASK	(1 << 4)
++#define UBNT_RSPRO_LAN_PHYMASK	((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3))
++
++static void __init ubnt_rspro_setup(void)
++{
++	ubnt_generic_setup();
++
++	ar71xx_add_device_mdio(~(UBNT_RSPRO_WAN_PHYMASK | UBNT_RSPRO_LAN_PHYMASK));
++
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++	ar71xx_eth0_data.phy_mask = UBNT_RSPRO_WAN_PHYMASK;
++
++	ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++	ar71xx_eth1_data.phy_mask = UBNT_RSPRO_LAN_PHYMASK;
++	ar71xx_eth1_data.speed = SPEED_1000;
++	ar71xx_eth1_data.duplex = DUPLEX_FULL;
++
++	ar71xx_add_device_eth(0);
++	ar71xx_add_device_eth(1);
++
++	ar71xx_add_device_usb();
++
++	ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(ubnt_rs_leds_gpio),
++					ubnt_rs_leds_gpio);
++}
++
++MIPS_MACHINE(AR71XX_MACH_UBNT_RSPRO, "UBNT-RSPRO", "Ubiquiti RouterStation Pro",
++	     ubnt_rspro_setup);
++
++static void __init ubnt_lsx_setup(void)
++{
++	ubnt_generic_setup();
++}
++
++MIPS_MACHINE(AR71XX_MACH_UBNT_LSX, "UBNT-LSX", "Ubiquiti LSX", ubnt_lsx_setup);
++
++#define UBNT_LSSR71_PHY_MASK	(1 << 1)
++
++static void __init ubnt_lssr71_setup(void)
++{
++	ubnt_generic_setup();
++
++	ar71xx_add_device_mdio(~UBNT_LSSR71_PHY_MASK);
++
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
++	ar71xx_eth0_data.phy_mask = UBNT_LSSR71_PHY_MASK;
++
++	ar71xx_add_device_eth(0);
++
++	ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(ubnt_ls_sr71_leds_gpio),
++					ubnt_ls_sr71_leds_gpio);
++}
++
++MIPS_MACHINE(AR71XX_MACH_UBNT_LSSR71, "UBNT-LS-SR71", "Ubiquiti LS-SR71",
++	     ubnt_lssr71_setup);
++
++static void __init ubnt_m_setup(void)
++{
++	u8 *mac = (u8 *) KSEG1ADDR(0x1fff0000);
++	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
++
++	ar71xx_set_mac_base(mac);
++
++	ar71xx_add_device_m25p80(NULL);
++
++	ar71xx_add_device_mdio(~0);
++
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
++	ar71xx_eth0_data.speed = SPEED_100;
++	ar71xx_eth0_data.duplex = DUPLEX_FULL;
++	ar71xx_eth0_data.fifo_cfg1 = 0x0010ffff;
++	ar71xx_eth0_data.fifo_cfg2 = 0x015500aa;
++	ar71xx_eth0_data.fifo_cfg3 = 0x01f00140;
++
++	ar71xx_add_device_eth(0);
++
++	ap91_pci_init(ee, NULL);
++
++	ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(ubnt_m_leds_gpio),
++					ubnt_m_leds_gpio);
++
++	ar71xx_add_device_gpio_buttons(-1, UBNT_BUTTONS_POLL_INTERVAL,
++					ARRAY_SIZE(ubnt_m_gpio_buttons),
++					ubnt_m_gpio_buttons);
++}
++
++static void __init ubnt_rocket_m_setup(void)
++{
++	ubnt_m_setup();
++	ar71xx_add_device_usb();
++}
++
++MIPS_MACHINE(AR71XX_MACH_UBNT_BULLET_M, "UBNT-BM", "Ubiquiti Bullet M",
++	     ubnt_m_setup);
++MIPS_MACHINE(AR71XX_MACH_UBNT_ROCKET_M, "UBNT-RM", "Ubiquiti Rocket M",
++	     ubnt_rocket_m_setup);
++
++/* TODO detect the second ethernet port and use one
++   init function for all Ubiquiti MIMO series products */
++static void __init ubnt_nano_m_setup(void)
++{
++	ubnt_m_setup();
++
++	ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth1_data.speed = SPEED_1000;
++	ar71xx_eth1_data.duplex = DUPLEX_FULL;
++	ar71xx_eth1_data.fifo_cfg1 = 0x0010ffff;
++	ar71xx_eth1_data.fifo_cfg2 = 0x015500aa;
++	ar71xx_eth1_data.fifo_cfg3 = 0x01f00140;
++
++	ar71xx_add_device_eth(1);
++}
++
++MIPS_MACHINE(AR71XX_MACH_UBNT_NANO_M, "UBNT-NM", "Ubiquiti Nanostation M",
++	     ubnt_nano_m_setup);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-wndr3700.c linux-2.6.33.3/arch/mips/ar71xx/mach-wndr3700.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-wndr3700.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-wndr3700.c	2010-05-16 13:17:33.059599577 +0200
+@@ -0,0 +1,209 @@
++/*
++ *  Netgear WNDR3700 board support
++ *
++ *  Copyright (C) 2009 Marco Porsch
++ *  Copyright (C) 2009-2010 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/platform_device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/delay.h>
++#include <linux/rtl8366s.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ap94-pci.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "dev-usb.h"
++
++#define WNDR3700_GPIO_LED_WPS_ORANGE	0
++#define WNDR3700_GPIO_LED_POWER_ORANGE	1
++#define WNDR3700_GPIO_LED_POWER_GREEN	2
++#define WNDR3700_GPIO_LED_WPS_GREEN	4
++#define WNDR3700_GPIO_LED_WAN_GREEN	6
++
++#define WNDR3700_GPIO_BTN_WPS		3
++#define WNDR3700_GPIO_BTN_RESET		8
++#define WNDR3700_GPIO_BTN_WIFI		11
++
++#define WNDR3700_GPIO_RTL8366_SDA	5
++#define WNDR3700_GPIO_RTL8366_SCK	7
++
++#define WNDR3700_BUTTONS_POLL_INTERVAL    20
++
++#define WNDR3700_WMAC0_MAC_OFFSET	0
++#define WNDR3700_WMAC1_MAC_OFFSET	0xc
++#define WNDR3700_CALDATA0_OFFSET	0x1000
++#define WNDR3700_CALDATA1_OFFSET	0x5000
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition wndr3700_partitions[] = {
++	{
++		.name		= "uboot",
++		.offset		= 0,
++		.size		= 0x050000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "env",
++		.offset		= 0x050000,
++		.size		= 0x020000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "rootfs",
++		.offset		= 0x070000,
++		.size		= 0x720000,
++	} , {
++		.name		= "config",
++		.offset		= 0x790000,
++		.size		= 0x010000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "config_bak",
++		.offset		= 0x7a0000,
++		.size		= 0x010000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "pot",
++		.offset		= 0x7b0000,
++		.size		= 0x010000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "traffic_meter",
++		.offset		= 0x7c0000,
++		.size		= 0x010000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "language",
++		.offset		= 0x7d0000,
++		.size		= 0x020000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "caldata",
++		.offset		= 0x7f0000,
++		.size		= 0x010000,
++		.mask_flags	= MTD_WRITEABLE,
++	}
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data wndr3700_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++        .parts          = wndr3700_partitions,
++        .nr_parts       = ARRAY_SIZE(wndr3700_partitions),
++#endif
++};
++
++static struct gpio_led wndr3700_leds_gpio[] __initdata = {
++	{
++		.name		= "wndr3700:green:power",
++		.gpio		= WNDR3700_GPIO_LED_POWER_GREEN,
++		.active_low	= 1,
++	}, {
++		.name		= "wndr3700:orange:power",
++		.gpio		= WNDR3700_GPIO_LED_POWER_ORANGE,
++		.active_low	= 1,
++	}, {
++		.name		= "wndr3700:green:wps",
++		.gpio		= WNDR3700_GPIO_LED_WPS_GREEN,
++		.active_low	= 1,
++	}, {
++		.name		= "wndr3700:orange:wps",
++		.gpio		= WNDR3700_GPIO_LED_WPS_ORANGE,
++		.active_low	= 1,
++	}, {
++		.name		= "wndr3700:green:wan",
++		.gpio		= WNDR3700_GPIO_LED_WAN_GREEN,
++		.active_low	= 1,
++	}
++};
++
++static struct gpio_button wndr3700_gpio_buttons[] __initdata = {
++	{
++		.desc		= "reset",
++		.type		= EV_KEY,
++		.code		= KEY_RESTART,
++		.threshold	= 3,
++		.gpio		= WNDR3700_GPIO_BTN_RESET,
++		.active_low	= 1,
++	}, {
++		.desc		= "wps",
++		.type		= EV_KEY,
++		.code		= KEY_WPS_BUTTON,
++		.threshold	= 3,
++		.gpio		= WNDR3700_GPIO_BTN_WPS,
++		.active_low	= 1,
++	} , {
++		.desc		= "wifi",
++		.type		= EV_KEY,
++		.code		= BTN_2,
++		.threshold	= 3,
++		.gpio		= WNDR3700_GPIO_BTN_WIFI,
++		.active_low	= 1,
++	}
++};
++
++static struct rtl8366s_platform_data wndr3700_rtl8366s_data = {
++	.gpio_sda        = WNDR3700_GPIO_RTL8366_SDA,
++	.gpio_sck        = WNDR3700_GPIO_RTL8366_SCK,
++};
++
++static struct platform_device wndr3700_rtl8366s_device = {
++	.name		= RTL8366S_DRIVER_NAME,
++	.id		= -1,
++	.dev = {
++		.platform_data	= &wndr3700_rtl8366s_data,
++	}
++};
++
++static void __init wndr3700_setup(void)
++{
++	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
++
++	ar71xx_set_mac_base(art);
++
++	ar71xx_eth0_pll_data.pll_1000 = 0x11110000;
++	ar71xx_eth0_data.mii_bus_dev = &wndr3700_rtl8366s_device.dev;
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++	ar71xx_eth0_data.speed = SPEED_1000;
++	ar71xx_eth0_data.duplex = DUPLEX_FULL;
++
++	ar71xx_eth1_pll_data.pll_1000 = 0x11110000;
++	ar71xx_eth1_data.mii_bus_dev = &wndr3700_rtl8366s_device.dev;
++	ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++	ar71xx_eth1_data.phy_mask = 0x10;
++
++	ar71xx_add_device_eth(0);
++	ar71xx_add_device_eth(1);
++
++	ar71xx_add_device_usb();
++
++	ar71xx_add_device_m25p80(&wndr3700_flash_data);
++
++        ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(wndr3700_leds_gpio),
++				    wndr3700_leds_gpio);
++
++	ar71xx_add_device_gpio_buttons(-1, WNDR3700_BUTTONS_POLL_INTERVAL,
++				      ARRAY_SIZE(wndr3700_gpio_buttons),
++				      wndr3700_gpio_buttons);
++
++	platform_device_register(&wndr3700_rtl8366s_device);
++	platform_device_register_simple("wndr3700-led-usb", -1, NULL, 0);
++
++	ap94_pci_enable_quirk_wndr3700();
++	ap94_pci_init(art + WNDR3700_CALDATA0_OFFSET,
++		      art + WNDR3700_WMAC0_MAC_OFFSET,
++		      art + WNDR3700_CALDATA1_OFFSET,
++		      art + WNDR3700_WMAC1_MAC_OFFSET);
++}
++
++MIPS_MACHINE(AR71XX_MACH_WNDR3700, "WNDR3700", "NETGEAR WNDR3700",
++	     wndr3700_setup);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-wnr2000.c linux-2.6.33.3/arch/mips/ar71xx/mach-wnr2000.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-wnr2000.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-wnr2000.c	2010-05-16 13:17:31.783601847 +0200
+@@ -0,0 +1,148 @@
++/*
++ *  NETGEAR WNR2000 board support
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *  Copyright (C) 2008-2009 Andy Boyett <agb@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/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ar913x-wmac.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++
++#define WNR2000_GPIO_LED_PWR_GREEN	14
++#define WNR2000_GPIO_LED_PWR_AMBER	7
++#define WNR2000_GPIO_LED_WPS		4
++#define WNR2000_GPIO_LED_WLAN		6
++#define WNR2000_GPIO_BTN_RESET		21
++#define WNR2000_GPIO_BTN_WPS		8
++
++#define WNR2000_BUTTONS_POLL_INTERVAL	20
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition wnr2000_partitions[] = {
++	{
++		.name		= "u-boot",
++		.offset		= 0,
++		.size		= 0x040000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "u-boot-env",
++		.offset		= 0x040000,
++		.size		= 0x010000,
++	} , {
++		.name		= "rootfs",
++		.offset		= 0x050000,
++		.size		= 0x240000,
++	} , {
++		.name		= "user-config",
++		.offset		= 0x290000,
++		.size		= 0x010000,
++	} , {
++		.name		= "uImage",
++		.offset		= 0x2a0000,
++		.size		= 0x120000,
++	} , {
++		.name		= "language_table",
++		.offset		= 0x3c0000,
++		.size		= 0x020000,
++	} , {
++		.name		= "rootfs_checksum",
++		.offset		= 0x3e0000,
++		.size		= 0x010000,
++	} , {
++		.name		= "art",
++		.offset		= 0x3f0000,
++		.size		= 0x010000,
++		.mask_flags	= MTD_WRITEABLE,
++	}
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data wnr2000_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++        .parts          = wnr2000_partitions,
++        .nr_parts       = ARRAY_SIZE(wnr2000_partitions),
++#endif
++};
++
++static struct gpio_led wnr2000_leds_gpio[] __initdata = {
++	{
++		.name		= "wnr2000:green:power",
++		.gpio		= WNR2000_GPIO_LED_PWR_GREEN,
++		.active_low	= 1,
++	}, {
++		.name		= "wnr2000:amber:power",
++		.gpio		= WNR2000_GPIO_LED_PWR_AMBER,
++		.active_low	= 1,
++	}, {
++		.name		= "wnr2000:green:wps",
++		.gpio		= WNR2000_GPIO_LED_WPS,
++		.active_low	= 1,
++	}, {
++		.name		= "wnr2000:blue:wlan",
++		.gpio		= WNR2000_GPIO_LED_WLAN,
++		.active_low	= 1,
++	}
++};
++
++static struct gpio_button wnr2000_gpio_buttons[] __initdata = {
++	{
++		.desc		= "reset",
++		.type		= EV_KEY,
++		.code		= KEY_RESTART,
++		.threshold	= 3,
++		.gpio		= WNR2000_GPIO_BTN_RESET,
++	}, {
++		.desc		= "wps",
++		.type		= EV_KEY,
++		.code		= KEY_WPS_BUTTON,
++		.threshold	= 3,
++		.gpio		= WNR2000_GPIO_BTN_WPS,
++	}
++};
++
++static void __init wnr2000_setup(void)
++{
++	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
++
++	ar71xx_set_mac_base(eeprom);
++	ar71xx_add_device_mdio(0x0);
++
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth0_data.speed = SPEED_100;
++	ar71xx_eth0_data.duplex = DUPLEX_FULL;
++	ar71xx_eth0_data.has_ar8216 = 1;
++
++	ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth1_data.phy_mask = 0x10;
++
++	ar71xx_add_device_eth(0);
++	ar71xx_add_device_eth(1);
++
++	ar71xx_add_device_m25p80(&wnr2000_flash_data);
++
++	ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(wnr2000_leds_gpio),
++					wnr2000_leds_gpio);
++
++	ar71xx_add_device_gpio_buttons(-1, WNR2000_BUTTONS_POLL_INTERVAL,
++					ARRAY_SIZE(wnr2000_gpio_buttons),
++					wnr2000_gpio_buttons);
++
++
++	ar913x_add_device_wmac(eeprom, NULL);
++}
++
++MIPS_MACHINE(AR71XX_MACH_WNR2000, "WNR2000", "NETGEAR WNR2000", wnr2000_setup);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-wp543.c linux-2.6.33.3/arch/mips/ar71xx/mach-wp543.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-wp543.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-wp543.c	2010-03-23 20:31:05.506280502 +0100
+@@ -0,0 +1,99 @@
++/*
++ *  Compex WP543/WPJ543 board support
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-pb42-pci.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "dev-usb.h"
++
++#define WP543_GPIO_SW6		2
++#define WP543_GPIO_LED_1	3
++#define WP543_GPIO_LED_2	4
++#define WP543_GPIO_LED_WLAN	5
++#define WP543_GPIO_LED_CONN	6
++#define WP543_GPIO_LED_DIAG	7
++#define WP543_GPIO_SW4		8
++
++#define WP543_BUTTONS_POLL_INTERVAL	20
++
++static struct gpio_led wp543_leds_gpio[] __initdata = {
++	{
++		.name		= "wp543:green:led1",
++		.gpio		= WP543_GPIO_LED_1,
++		.active_low	= 1,
++	}, {
++		.name		= "wp543:green:led2",
++		.gpio		= WP543_GPIO_LED_2,
++		.active_low	= 1,
++	}, {
++		.name		= "wp543:green:wlan",
++		.gpio		= WP543_GPIO_LED_WLAN,
++		.active_low	= 1,
++	}, {
++		.name		= "wp543:green:conn",
++		.gpio		= WP543_GPIO_LED_CONN,
++		.active_low	= 1,
++	}, {
++		.name		= "wp543:green:diag",
++		.gpio		= WP543_GPIO_LED_DIAG,
++		.active_low	= 1,
++	}
++};
++
++static struct gpio_button wp543_gpio_buttons[] __initdata = {
++	{
++		.desc		= "sw6",
++		.type		= EV_KEY,
++		.code		= BTN_0,
++		.threshold	= 3,
++		.gpio		= WP543_GPIO_SW6,
++	}, {
++		.desc		= "sw4",
++		.type		= EV_KEY,
++		.code		= BTN_1,
++		.threshold	= 3,
++		.gpio		= WP543_GPIO_SW4,
++	}
++};
++
++static void __init wp543_setup(void)
++{
++	ar71xx_add_device_m25p80(NULL);
++
++	ar71xx_add_device_mdio(0xfffffff7);
++
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
++	ar71xx_eth0_data.phy_mask = 0x08;
++	ar71xx_eth0_data.reset_bit = RESET_MODULE_GE0_MAC |
++				     RESET_MODULE_GE0_PHY;
++	ar71xx_add_device_eth(0);
++
++	ar71xx_add_device_usb();
++
++	pb42_pci_init();
++
++	ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(wp543_leds_gpio),
++					wp543_leds_gpio);
++
++	ar71xx_add_device_gpio_buttons(-1, WP543_BUTTONS_POLL_INTERVAL,
++					ARRAY_SIZE(wp543_gpio_buttons),
++					wp543_gpio_buttons);
++}
++
++MIPS_MACHINE(AR71XX_MACH_WP543, "WP543", "Compex WP543", wp543_setup);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-wrt160nl.c linux-2.6.33.3/arch/mips/ar71xx/mach-wrt160nl.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-wrt160nl.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-wrt160nl.c	2010-05-16 13:17:32.731626515 +0200
+@@ -0,0 +1,158 @@
++/*
++ *  Linksys WRT160NL board support
++ *
++ *  Copyright (C) 2009 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/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ar913x-wmac.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "dev-usb.h"
++#include "nvram.h"
++
++#define WRT160NL_GPIO_LED_POWER		14
++#define WRT160NL_GPIO_LED_WPS_AMBER	9
++#define WRT160NL_GPIO_LED_WPS_BLUE	8
++#define WRT160NL_GPIO_LED_WLAN		6
++
++#define WRT160NL_GPIO_BTN_WPS		7
++#define WRT160NL_GPIO_BTN_RESET		21
++
++#define WRT160NL_BUTTONS_POLL_INTERVAL	20
++
++#define WRT160NL_NVRAM_ADDR	0x1f7e0000
++#define WRT160NL_NVRAM_SIZE	0x10000
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition wrt160nl_partitions[] = {
++	{
++		.name		= "u-boot",
++		.offset		= 0,
++		.size		= 0x040000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "kernel",
++		.offset		= 0x040000,
++		.size		= 0x0e0000,
++	} , {
++		.name		= "filesytem",
++		.offset		= 0x120000,
++		.size		= 0x6c0000,
++	} , {
++		.name		= "nvram",
++		.offset		= 0x7e0000,
++		.size		= 0x010000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "ART",
++		.offset		= 0x7f0000,
++		.size		= 0x010000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "firmware",
++		.offset		= 0x040000,
++		.size		= 0x7a0000,
++	}
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data wrt160nl_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++        .parts          = wrt160nl_partitions,
++        .nr_parts       = ARRAY_SIZE(wrt160nl_partitions),
++#endif
++};
++
++static struct gpio_led wrt160nl_leds_gpio[] __initdata = {
++	{
++		.name		= "wrt160nl:blue:power",
++		.gpio		= WRT160NL_GPIO_LED_POWER,
++		.active_low	= 1,
++		.default_trigger = "default-on",
++	}, {
++		.name		= "wrt160nl:amber:wps",
++		.gpio		= WRT160NL_GPIO_LED_WPS_AMBER,
++		.active_low	= 1,
++	}, {
++		.name		= "wrt160nl:blue:wps",
++		.gpio		= WRT160NL_GPIO_LED_WPS_BLUE,
++		.active_low	= 1,
++	}, {
++		.name		= "wrt160nl:blue:wlan",
++		.gpio		= WRT160NL_GPIO_LED_WLAN,
++		.active_low	= 1,
++	}
++};
++
++static struct gpio_button wrt160nl_gpio_buttons[] __initdata = {
++	{
++		.desc		= "reset",
++		.type		= EV_KEY,
++		.code		= KEY_RESTART,
++		.threshold	= 3,
++		.gpio		= WRT160NL_GPIO_BTN_RESET,
++		.active_low	= 1,
++	}, {
++		.desc		= "wps",
++		.type		= EV_KEY,
++		.code		= KEY_WPS_BUTTON,
++		.threshold	= 3,
++		.gpio		= WRT160NL_GPIO_BTN_WPS,
++		.active_low	= 1,
++	}
++};
++
++static void __init wrt160nl_setup(void)
++{
++	const char *nvram = (char *) KSEG1ADDR(WRT160NL_NVRAM_ADDR);
++	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
++	u8 mac[6];
++
++	if (nvram_parse_mac_addr(nvram, WRT160NL_NVRAM_SIZE,
++			         "lan_hwaddr=", mac) == 0)
++		ar71xx_set_mac_base(mac);
++
++	ar71xx_add_device_mdio(0x0);
++
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth0_data.phy_mask = 0x01;
++
++	ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth1_data.phy_mask = 0x10;
++
++	ar71xx_add_device_eth(0);
++	ar71xx_add_device_eth(1);
++
++	ar71xx_add_device_m25p80(&wrt160nl_flash_data);
++
++	ar71xx_add_device_usb();
++
++	if (nvram_parse_mac_addr(nvram, WRT160NL_NVRAM_SIZE,
++			         "wl0_hwaddr=", mac) == 0)
++		ar913x_add_device_wmac(eeprom, mac);
++	else
++		ar913x_add_device_wmac(eeprom, NULL);
++
++	ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(wrt160nl_leds_gpio),
++					wrt160nl_leds_gpio);
++
++	ar71xx_add_device_gpio_buttons(-1, WRT160NL_BUTTONS_POLL_INTERVAL,
++					ARRAY_SIZE(wrt160nl_gpio_buttons),
++					wrt160nl_gpio_buttons);
++
++}
++
++MIPS_MACHINE(AR71XX_MACH_WRT160NL, "WRT160NL", "Linksys WRT160NL",
++	     wrt160nl_setup);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-wrt400n.c linux-2.6.33.3/arch/mips/ar71xx/mach-wrt400n.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-wrt400n.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-wrt400n.c	2010-05-16 13:17:31.823599676 +0200
+@@ -0,0 +1,168 @@
++/*
++ *  Linksys WRT400N board support
++ *
++ *  Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2009 Imre Kaloz <kaloz@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/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-ap94-pci.h"
++#include "dev-m25p80.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++
++#define WRT400N_GPIO_LED_ORANGE	5
++#define WRT400N_GPIO_LED_GREEN	4
++#define WRT400N_GPIO_LED_POWER	1
++#define WRT400N_GPIO_LED_WLAN	0
++
++#define WRT400N_GPIO_BTN_RESET	8
++#define WRT400N_GPIO_BTN_WLSEC	3
++
++#define WRT400N_BUTTONS_POLL_INTERVAL	20
++
++#define WRT400N_MAC_ADDR_OFFSET		0x120c
++#define WRT400N_CALDATA0_OFFSET		0x1000
++#define WRT400N_CALDATA1_OFFSET		0x5000
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition wrt400n_partitions[] = {
++	{
++		.name		= "uboot",
++		.offset		= 0,
++		.size		= 0x030000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "env",
++		.offset		= 0x030000,
++		.size		= 0x010000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "linux",
++		.offset		= 0x040000,
++		.size		= 0x140000,
++	} , {
++		.name		= "rootfs",
++		.offset		= 0x180000,
++		.size		= 0x630000,
++	} , {
++		.name		= "nvram",
++		.offset		= 0x7b0000,
++		.size		= 0x010000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "factory",
++		.offset		= 0x7c0000,
++		.size		= 0x010000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "language",
++		.offset		= 0x7d0000,
++		.size		= 0x020000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "caldata",
++		.offset		= 0x7f0000,
++		.size		= 0x010000,
++		.mask_flags	= MTD_WRITEABLE,
++	} , {
++		.name		= "firmware",
++		.offset		= 0x040000,
++		.size		= 0x770000,
++	}
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data wrt400n_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++        .parts          = wrt400n_partitions,
++        .nr_parts       = ARRAY_SIZE(wrt400n_partitions),
++#endif
++};
++
++static struct gpio_led wrt400n_leds_gpio[] __initdata = {
++	{
++		.name		= "wrt400n:green:status",
++		.gpio		= WRT400N_GPIO_LED_GREEN,
++		.active_low	= 1,
++	}, {
++		.name		= "wrt400n:amber:aoss",
++		.gpio		= WRT400N_GPIO_LED_ORANGE,
++		.active_low	= 1,
++	}, {
++		.name		= "wrt400n:green:wlan",
++		.gpio		= WRT400N_GPIO_LED_WLAN,
++		.active_low	= 1,
++	}, {
++		.name		= "wrt400n:green:power",
++		.gpio		= WRT400N_GPIO_LED_POWER,
++		.active_low	= 1,
++	}
++};
++
++static struct gpio_button wrt400n_gpio_buttons[] __initdata = {
++	{
++		.desc		= "reset",
++		.type		= EV_KEY,
++		.code		= KEY_RESTART,
++		.threshold	= 3,
++		.gpio		= WRT400N_GPIO_BTN_RESET,
++		.active_low	= 1,
++	} , {
++		.desc		= "wlsec",
++		.type		= EV_KEY,
++		.code		= KEY_WPS_BUTTON,
++		.threshold	= 3,
++		.gpio		= WRT400N_GPIO_BTN_WLSEC,
++		.active_low	= 1,
++	}
++};
++
++static void __init wrt400n_setup(void)
++{
++	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
++	u8 mac[6];
++	int i;
++
++	memcpy(mac, art + WRT400N_MAC_ADDR_OFFSET, 6);
++	for (i = 5; i >= 3; i--)
++		if (++mac[i] != 0x00) break;
++
++	ar71xx_set_mac_base(mac);
++
++	ar71xx_add_device_mdio(0x0);
++
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth0_data.speed = SPEED_100;
++	ar71xx_eth0_data.duplex = DUPLEX_FULL;
++
++	ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ar71xx_eth1_data.phy_mask = 0x10;
++
++	ar71xx_add_device_eth(0);
++	ar71xx_add_device_eth(1);
++
++	ar71xx_add_device_m25p80(&wrt400n_flash_data);
++
++	ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(wrt400n_leds_gpio),
++					wrt400n_leds_gpio);
++
++	ar71xx_add_device_gpio_buttons(-1, WRT400N_BUTTONS_POLL_INTERVAL,
++					ARRAY_SIZE(wrt400n_gpio_buttons),
++					wrt400n_gpio_buttons);
++
++	ap94_pci_init(art + WRT400N_CALDATA0_OFFSET, NULL,
++		      art + WRT400N_CALDATA1_OFFSET, NULL);
++}
++
++MIPS_MACHINE(AR71XX_MACH_WRT400N, "WRT400N", "Linksys WRT400N", wrt400n_setup);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/mach-wzr-hp-g300nh.c linux-2.6.33.3/arch/mips/ar71xx/mach-wzr-hp-g300nh.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/mach-wzr-hp-g300nh.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/mach-wzr-hp-g300nh.c	2010-05-16 13:17:31.855600117 +0200
+@@ -0,0 +1,265 @@
++/*
++ *  Buffalo WZR-HP-G300NH board support
++ *
++ *  Copyright (C) 2010 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/platform_device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/nxp_74hc153.h>
++#include <linux/rtl8366s.h>
++
++#include <asm/mips_machine.h>
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/ar91xx_flash.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-ar913x-wmac.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "dev-usb.h"
++
++#define WZRHPG300NH_GPIO_LED_USB	0
++#define WZRHPG300NH_GPIO_LED_DIAG	1
++#define WZRHPG300NH_GPIO_LED_WIRELESS	6
++#define WZRHPG300NH_GPIO_LED_SECURITY	17
++#define WZRHPG300NH_GPIO_LED_ROUTER	18
++
++#define WZRHPG300NH_GPIO_RTL8366_SDA	19
++#define WZRHPG300NH_GPIO_RTL8366_SCK	20
++
++#define WZRHPG300NH_GPIO_74HC153_S0	9
++#define WZRHPG300NH_GPIO_74HC153_S1	11
++#define WZRHPG300NH_GPIO_74HC153_1Y	12
++#define WZRHPG300NH_GPIO_74HC153_2Y	14
++
++#define WZRHPG300NH_GPIO_EXP_BASE	32
++#define WZRHPG300NH_GPIO_BTN_AOSS	(WZRHPG300NH_GPIO_EXP_BASE + 0)
++#define WZRHPG300NH_GPIO_BTN_RESET	(WZRHPG300NH_GPIO_EXP_BASE + 1)
++#define WZRHPG300NH_GPIO_BTN_ROUTER_ON	(WZRHPG300NH_GPIO_EXP_BASE + 2)
++#define WZRHPG300NH_GPIO_BTN_QOS_ON	(WZRHPG300NH_GPIO_EXP_BASE + 3)
++#define WZRHPG300NH_GPIO_BTN_USB	(WZRHPG300NH_GPIO_EXP_BASE + 5)
++#define WZRHPG300NH_GPIO_BTN_ROUTER_AUTO (WZRHPG300NH_GPIO_EXP_BASE + 6)
++#define WZRHPG300NH_GPIO_BTN_QOS_OFF	(WZRHPG300NH_GPIO_EXP_BASE + 7)
++
++#define WZRHPG300NH_BUTTONS_POLL_INTERVAL	20
++
++#define WZRHPG300NH_MAC_OFFSET		0x20c
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition wzrhpg300nh_flash_partitions[] = {
++	{
++		.name		= "u-boot",
++		.offset		= 0,
++		.size		= 0x0040000,
++		.mask_flags	= MTD_WRITEABLE,
++	}, {
++		.name		= "u-boot-env",
++		.offset		= 0x0040000,
++		.size		= 0x0020000,
++		.mask_flags	= MTD_WRITEABLE,
++	}, {
++		.name		= "kernel",
++		.offset		= 0x0060000,
++		.size		= 0x0100000,
++	}, {
++		.name		= "rootfs",
++		.offset		= 0x0160000,
++		.size		= 0x1e60000,
++	}, {
++		.name		= "user_property",
++		.offset		= 0x1fc0000,
++		.size		= 0x0020000,
++		.mask_flags	= MTD_WRITEABLE,
++	}, {
++		.name		= "art",
++		.offset		= 0x1fe0000,
++		.size		= 0x0020000,
++		.mask_flags	= MTD_WRITEABLE,
++	}, {
++		.name		= "firmware",
++		.offset		= 0x0060000,
++		.size		= 0x1f60000,
++	}
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct ar91xx_flash_platform_data wzrhpg300nh_flash_data = {
++	.width		= 2,
++#ifdef CONFIG_MTD_PARTITIONS
++        .parts          = wzrhpg300nh_flash_partitions,
++        .nr_parts       = ARRAY_SIZE(wzrhpg300nh_flash_partitions),
++#endif
++};
++
++#define WZRHPG300NH_FLASH_BASE	0x1e000000
++#define WZRHPG300NH_FLASH_SIZE	(32 * 1024 * 1024)
++
++static struct resource wzrhpg300nh_flash_resources[] = {
++	[0] = {
++		.start	= WZRHPG300NH_FLASH_BASE,
++		.end	= WZRHPG300NH_FLASH_BASE + WZRHPG300NH_FLASH_SIZE - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++};
++
++static struct platform_device wzrhpg300nh_flash_device = {
++	.name		= "ar91xx-flash",
++	.id		= -1,
++	.resource	= wzrhpg300nh_flash_resources,
++	.num_resources	= ARRAY_SIZE(wzrhpg300nh_flash_resources),
++	.dev		= {
++		.platform_data = &wzrhpg300nh_flash_data,
++	}
++};
++
++static struct gpio_led wzrhpg300nh_leds_gpio[] __initdata = {
++	{
++		.name		= "wzr-hp-g300nh:orange:security",
++		.gpio		= WZRHPG300NH_GPIO_LED_SECURITY,
++		.active_low	= 1,
++	}, {
++		.name		= "wzr-hp-g300nh:green:wireless",
++		.gpio		= WZRHPG300NH_GPIO_LED_WIRELESS,
++		.active_low	= 1,
++	}, {
++		.name		= "wzr-hp-g300nh:green:router",
++		.gpio		= WZRHPG300NH_GPIO_LED_ROUTER,
++		.active_low	= 1,
++	}, {
++		.name		= "wzr-hp-g300nh:red:diag",
++		.gpio		= WZRHPG300NH_GPIO_LED_DIAG,
++		.active_low	= 1,
++	}, {
++		.name		= "wzr-hp-g300nh:blue:usb",
++		.gpio		= WZRHPG300NH_GPIO_LED_USB,
++		.active_low	= 1,
++	}
++};
++
++static struct gpio_button wzrhpg300nh_gpio_buttons[] __initdata = {
++	{
++		.desc		= "reset",
++		.type		= EV_KEY,
++		.code		= KEY_RESTART,
++		.threshold	= 3,
++		.gpio		= WZRHPG300NH_GPIO_BTN_RESET,
++		.active_low	= 1,
++	}, {
++		.desc		= "aoss",
++		.type		= EV_KEY,
++		.code		= KEY_WPS_BUTTON,
++		.threshold	= 3,
++		.gpio		= WZRHPG300NH_GPIO_BTN_AOSS,
++		.active_low	= 1,
++	}, {
++		.desc		= "usb",
++		.type		= EV_KEY,
++		.code		= BTN_2,
++		.threshold	= 3,
++		.gpio		= WZRHPG300NH_GPIO_BTN_USB,
++		.active_low	= 1,
++	}, {
++		.desc		= "qos_on",
++		.type		= EV_KEY,
++		.code		= BTN_3,
++		.threshold	= 3,
++		.gpio		= WZRHPG300NH_GPIO_BTN_QOS_ON,
++		.active_low	= 0,
++	}, {
++		.desc		= "qos_off",
++		.type		= EV_KEY,
++		.code		= BTN_4,
++		.threshold	= 3,
++		.gpio		= WZRHPG300NH_GPIO_BTN_QOS_OFF,
++		.active_low	= 0,
++	}, {
++		.desc		= "router_on",
++		.type		= EV_KEY,
++		.code		= BTN_5,
++		.threshold	= 3,
++		.gpio		= WZRHPG300NH_GPIO_BTN_ROUTER_ON,
++		.active_low	= 0,
++	}, {
++		.desc		= "router_auto",
++		.type		= EV_KEY,
++		.code		= BTN_6,
++		.threshold	= 3,
++		.gpio		= WZRHPG300NH_GPIO_BTN_ROUTER_AUTO,
++		.active_low	= 0,
++	}
++};
++
++static struct nxp_74hc153_platform_data wzrhpg300nh_74hc153_data = {
++	.gpio_base	= WZRHPG300NH_GPIO_EXP_BASE,
++	.gpio_pin_s0	= WZRHPG300NH_GPIO_74HC153_S0,
++	.gpio_pin_s1	= WZRHPG300NH_GPIO_74HC153_S1,
++	.gpio_pin_1y	= WZRHPG300NH_GPIO_74HC153_1Y,
++	.gpio_pin_2y	= WZRHPG300NH_GPIO_74HC153_2Y,
++};
++
++static struct platform_device wzrhpg300nh_74hc153_device = {
++	.name		= NXP_74HC153_DRIVER_NAME,
++	.id		= -1,
++	.dev = {
++		.platform_data	= &wzrhpg300nh_74hc153_data,
++	}
++};
++
++static struct rtl8366s_platform_data wzrhpg300nh_rtl8366s_data = {
++	.gpio_sda        = WZRHPG300NH_GPIO_RTL8366_SDA,
++	.gpio_sck        = WZRHPG300NH_GPIO_RTL8366_SCK,
++};
++
++static struct platform_device wzrhpg300nh_rtl8366s_device = {
++	.name		= RTL8366S_DRIVER_NAME,
++	.id		= -1,
++	.dev = {
++		.platform_data	= &wzrhpg300nh_rtl8366s_data,
++	}
++};
++
++static void __init wzrhpg300nh_setup(void)
++{
++	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
++
++	ar71xx_set_mac_base(eeprom + WZRHPG300NH_MAC_OFFSET);
++
++	ar71xx_eth0_pll_data.pll_1000 = 0x1e000100;
++	ar71xx_eth0_data.mii_bus_dev = &wzrhpg300nh_rtl8366s_device.dev;
++	ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++	ar71xx_eth0_data.speed = SPEED_1000;
++	ar71xx_eth0_data.duplex = DUPLEX_FULL;
++
++	ar71xx_eth1_pll_data.pll_1000 = 0x1e000100;
++	ar71xx_eth1_data.mii_bus_dev = &wzrhpg300nh_rtl8366s_device.dev;
++	ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++	ar71xx_eth1_data.phy_mask = 0x10;
++
++	ar71xx_add_device_eth(0);
++	ar71xx_add_device_eth(1);
++
++	ar71xx_add_device_usb();
++	ar913x_add_device_wmac(eeprom, NULL);
++
++	platform_device_register(&wzrhpg300nh_74hc153_device);
++	platform_device_register(&wzrhpg300nh_flash_device);
++	platform_device_register(&wzrhpg300nh_rtl8366s_device);
++
++	ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(wzrhpg300nh_leds_gpio),
++				    wzrhpg300nh_leds_gpio);
++
++	ar71xx_add_device_gpio_buttons(-1, WZRHPG300NH_BUTTONS_POLL_INTERVAL,
++				       ARRAY_SIZE(wzrhpg300nh_gpio_buttons),
++				       wzrhpg300nh_gpio_buttons);
++
++}
++
++MIPS_MACHINE(AR71XX_MACH_WZR_HP_G300NH, "WZR-HP-G300NH",
++	     "Buffalo WZR-HP-G300NH", wzrhpg300nh_setup);
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/Makefile linux-2.6.33.3/arch/mips/ar71xx/Makefile
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/Makefile	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/Makefile	2010-05-17 21:19:51.539114190 +0200
+@@ -0,0 +1,54 @@
++#
++# Makefile for the Atheros AR71xx SoC specific parts of the kernel
++#
++# Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++# Copyright (C) 2008 Imre Kaloz <kaloz@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.
++
++obj-y	:= prom.o irq.o setup.o devices.o gpio.o ar71xx.o
++
++obj-$(CONFIG_EARLY_PRINTK)		+= early_printk.o
++obj-$(CONFIG_PCI)			+= pci.o
++
++obj-$(CONFIG_AR71XX_DEV_AP91_ETH)	+= dev-ap91-eth.o
++obj-$(CONFIG_AR71XX_DEV_AP91_PCI)	+= dev-ap91-pci.o
++obj-$(CONFIG_AR71XX_DEV_AP94_PCI)	+= dev-ap94-pci.o
++obj-$(CONFIG_AR71XX_DEV_AR913X_WMAC)	+= dev-ar913x-wmac.o
++obj-$(CONFIG_AR71XX_DEV_DSA)		+= dev-dsa.o
++obj-$(CONFIG_AR71XX_DEV_GPIO_BUTTONS)	+= dev-gpio-buttons.o
++obj-$(CONFIG_AR71XX_DEV_LEDS_GPIO)	+= dev-leds-gpio.o
++obj-$(CONFIG_AR71XX_DEV_M25P80)		+= dev-m25p80.o
++obj-$(CONFIG_AR71XX_DEV_PB42_PCI)	+= dev-pb42-pci.o
++obj-$(CONFIG_AR71XX_DEV_PB9X_PCI)	+= dev-pb9x-pci.o
++obj-$(CONFIG_AR71XX_DEV_USB)		+= dev-usb.o
++
++obj-$(CONFIG_AR71XX_NVRAM)		+= nvram.o
++
++obj-$(CONFIG_AR71XX_MACH_AP81)		+= mach-ap81.o
++obj-$(CONFIG_AR71XX_MACH_AP83)		+= mach-ap83.o
++obj-$(CONFIG_AR71XX_MACH_AW_NR580)	+= mach-aw-nr580.o
++obj-$(CONFIG_AR71XX_MACH_DIR_600_A1)	+= mach-dir-600-a1.o
++obj-$(CONFIG_AR71XX_MACH_DIR_615_C1)	+= mach-dir-615-c1.o
++obj-$(CONFIG_AR71XX_MACH_DIR_825_B1)	+= mach-dir-825-b1.o
++obj-$(CONFIG_AR71XX_MACH_MZK_W04NU)	+= mach-mzk-w04nu.o
++obj-$(CONFIG_AR71XX_MACH_MZK_W300NH)	+= mach-mzk-w300nh.o
++obj-$(CONFIG_AR71XX_MACH_NBG460N)	+= mach-nbg460n.o
++obj-$(CONFIG_AR71XX_MACH_PB42)		+= mach-pb42.o
++obj-$(CONFIG_AR71XX_MACH_PB44)		+= mach-pb44.o
++obj-$(CONFIG_AR71XX_MACH_PB92)		+= mach-pb92.o
++obj-$(CONFIG_AR71XX_MACH_RB4XX)		+= mach-rb4xx.o
++obj-$(CONFIG_AR71XX_MACH_RB750)		+= mach-rb750.o
++obj-$(CONFIG_AR71XX_MACH_TEW_632BRP)	+= mach-tew-632brp.o
++obj-$(CONFIG_AR71XX_MACH_TL_WR741ND)	+= mach-tl-wr741nd.o
++obj-$(CONFIG_AR71XX_MACH_TL_WR841N_V1)	+= mach-tl-wr841n.o
++obj-$(CONFIG_AR71XX_MACH_TL_WR941ND)	+= mach-tl-wr941nd.o
++obj-$(CONFIG_AR71XX_MACH_TL_WR1043ND)	+= mach-tl-wr1043nd.o
++obj-$(CONFIG_AR71XX_MACH_UBNT)		+= mach-ubnt.o
++obj-$(CONFIG_AR71XX_MACH_WNDR3700)	+= mach-wndr3700.o
++obj-$(CONFIG_AR71XX_MACH_WNR2000)	+= mach-wnr2000.o
++obj-$(CONFIG_AR71XX_MACH_WP543)		+= mach-wp543.o
++obj-$(CONFIG_AR71XX_MACH_WRT160NL)	+= mach-wrt160nl.o
++obj-$(CONFIG_AR71XX_MACH_WRT400N)	+= mach-wrt400n.o
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/nvram.c linux-2.6.33.3/arch/mips/ar71xx/nvram.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/nvram.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/nvram.c	2010-01-05 20:38:52.061278082 +0100
+@@ -0,0 +1,75 @@
++/*
++ *  Atheros AR71xx minimal nvram support
++ *
++ *  Copyright (C) 2009 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/vmalloc.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/string.h>
++
++#include "nvram.h"
++
++char *nvram_find_var(const char *name, const char *buf, unsigned buf_len)
++{
++	unsigned len = strlen(name);
++	char *cur, *last;
++
++	if (buf_len == 0 || len == 0)
++		return NULL;
++
++	if (buf_len < len)
++		return NULL;
++
++	if (len == 1)
++		return memchr(buf, (int) *name, buf_len);
++
++	last = (char *) buf + buf_len - len;
++	for (cur = (char *) buf; cur <= last; cur++)
++		if (cur[0] == name[0] && memcmp(cur, name, len) == 0)
++			return cur + len;
++
++	return NULL;
++}
++
++int nvram_parse_mac_addr(const char *nvram, unsigned nvram_len,
++			 const char *name, char *mac)
++{
++	char *buf;
++	char *mac_str;
++	int ret;
++	int t;
++
++	buf = vmalloc(nvram_len);
++	if (!buf)
++		return -ENOMEM;
++
++	memcpy(buf, nvram, nvram_len);
++	buf[nvram_len - 1] = '\0';
++
++	mac_str = nvram_find_var(name, buf, nvram_len);
++	if (!mac_str) {
++		ret = -EINVAL;
++		goto free;
++	}
++
++	t = sscanf(mac_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
++		   &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
++
++	if (t != 6) {
++		ret = -EINVAL;
++		goto free;
++	}
++
++	ret = 0;
++
++ free:
++	vfree(buf);
++	return ret;
++}
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/nvram.h linux-2.6.33.3/arch/mips/ar71xx/nvram.h
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/nvram.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/nvram.h	2010-01-05 20:38:52.137278273 +0100
+@@ -0,0 +1,19 @@
++/*
++ *  Atheros AR71xx minimal nvram support
++ *
++ *  Copyright (C) 2009 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.
++ */
++
++#ifndef _AR71XX_NVRAM_H
++#define _AR71XX_NVRAM_H
++
++char *nvram_find_var(const char *name, const char *buf,
++		     unsigned buf_len) __init;
++int nvram_parse_mac_addr(const char *nvram, unsigned nvram_len,
++			 const char *name, char *mac) __init;
++
++#endif /* _AR71XX_NVRAM_H */
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/pci.c linux-2.6.33.3/arch/mips/ar71xx/pci.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/pci.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/pci.c	2010-04-02 11:07:51.847025813 +0200
+@@ -0,0 +1,93 @@
++/*
++ *  Atheros AR71xx PCI setup code
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ *  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 <asm/traps.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/pci.h>
++
++unsigned ar71xx_pci_nr_irqs __initdata;
++struct ar71xx_pci_irq *ar71xx_pci_irq_map __initdata;
++
++int (*ar71xx_pci_plat_dev_init)(struct pci_dev *dev);
++
++static int ar71xx_be_handler(struct pt_regs *regs, int is_fixup)
++{
++	int err = 0;
++
++	err = ar71xx_pci_be_handler(is_fixup);
++
++	return (is_fixup && !err) ? MIPS_BE_FIXUP : MIPS_BE_FATAL;
++}
++
++int pcibios_plat_dev_init(struct pci_dev *dev)
++{
++	if (ar71xx_pci_plat_dev_init)
++		return ar71xx_pci_plat_dev_init(dev);
++
++	return 0;
++}
++
++int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin)
++{
++	int ret = 0;
++
++	switch (ar71xx_soc) {
++	case AR71XX_SOC_AR7130:
++	case AR71XX_SOC_AR7141:
++	case AR71XX_SOC_AR7161:
++		ret = ar71xx_pcibios_map_irq(dev, slot, pin);
++		break;
++
++	case AR71XX_SOC_AR7240:
++	case AR71XX_SOC_AR7241:
++	case AR71XX_SOC_AR7242:
++		ret = ar724x_pcibios_map_irq(dev, slot, pin);
++		break;
++
++	default:
++		break;
++	}
++
++	return ret;
++}
++
++int __init ar71xx_pci_init(unsigned nr_irqs, struct ar71xx_pci_irq *map)
++{
++	int ret = 0;
++
++	switch (ar71xx_soc) {
++	case AR71XX_SOC_AR7130:
++	case AR71XX_SOC_AR7141:
++	case AR71XX_SOC_AR7161:
++		board_be_handler = ar71xx_be_handler;
++		ret = ar71xx_pcibios_init();
++		break;
++
++	case AR71XX_SOC_AR7240:
++	case AR71XX_SOC_AR7241:
++	case AR71XX_SOC_AR7242:
++		ret = ar724x_pcibios_init();
++		break;
++
++	default:
++		return 0;
++	}
++
++	ar71xx_pci_nr_irqs = nr_irqs;
++	ar71xx_pci_irq_map = map;
++
++	return ret;
++}
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/prom.c linux-2.6.33.3/arch/mips/ar71xx/prom.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/prom.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/prom.c	2010-05-20 17:47:32.151849828 +0200
+@@ -0,0 +1,105 @@
++/*
++ *  Atheros AR71xx SoC specific prom routines
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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/init.h>
++#include <linux/io.h>
++#include <linux/string.h>
++
++#include <asm/bootinfo.h>
++#include <asm/addrspace.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++static inline int is_valid_ram_addr(void *addr)
++{
++	if (((u32) addr > KSEG0) &&
++	    ((u32) addr < (KSEG0 + AR71XX_MEM_SIZE_MAX)))
++		return 1;
++
++	if (((u32) addr > KSEG1) &&
++	    ((u32) addr < (KSEG1 + AR71XX_MEM_SIZE_MAX)))
++		return 1;
++
++	return 0;
++}
++
++static void __init ar71xx_prom_append_cmdline(const char *name,
++					      const char *value)
++{
++	char buf[COMMAND_LINE_SIZE];
++
++	snprintf(buf, sizeof(buf), " %s=%s", name, value);
++	strlcat(arcs_cmdline, buf, sizeof(arcs_cmdline));
++}
++
++static void __init ar71xx_prom_find_env(char **envp, const char *name)
++{
++	int len = strlen(name);
++	char **p;
++
++	if (!is_valid_ram_addr(envp))
++		return;
++
++	for (p = envp; is_valid_ram_addr(*p); p++) {
++		if (strncmp(name, *p, len) == 0 && (*p)[len] == '=') {
++			ar71xx_prom_append_cmdline(name, *p + len + 1);
++			break;
++		}
++
++		/* RedBoot env comes in pointer pairs - key, value */
++		if (strncmp(name, *p, len) == 0 && (*p)[len] == 0)
++			if (is_valid_ram_addr(*(++p))) {
++				ar71xx_prom_append_cmdline(name, *p);
++				break;
++			}
++	}
++}
++
++static int inline ar71xx_use__image_cmdline(void) { return 0; }
++
++static __init void ar71xx_prom_init_cmdline(int argc, char **argv)
++{
++	int i;
++
++	if (ar71xx_use__image_cmdline())
++		return;
++
++	if (!is_valid_ram_addr(argv))
++		return;
++
++	for (i = 0; i < argc; i++)
++		if (is_valid_ram_addr(argv[i])) {
++			strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline));
++			strlcat(arcs_cmdline, argv[i], sizeof(arcs_cmdline));
++		}
++}
++
++void __init prom_init(void)
++{
++	char **envp;
++
++	printk(KERN_DEBUG "prom: fw_arg0=%08x, fw_arg1=%08x, "
++			"fw_arg2=%08x, fw_arg3=%08x\n",
++			(unsigned int)fw_arg0, (unsigned int)fw_arg1,
++			(unsigned int)fw_arg2, (unsigned int)fw_arg3);
++
++
++	ar71xx_prom_init_cmdline(fw_arg0, (char **)fw_arg1);
++
++	envp = (char **)fw_arg2;
++	ar71xx_prom_find_env(envp, "board");
++}
++
++void __init prom_free_prom_memory(void)
++{
++	/* We do not have to prom memory to free */
++}
+diff -Nur linux-2.6.33.3.orig/arch/mips/ar71xx/setup.c linux-2.6.33.3/arch/mips/ar71xx/setup.c
+--- linux-2.6.33.3.orig/arch/mips/ar71xx/setup.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/ar71xx/setup.c	2010-04-02 11:07:51.650955594 +0200
+@@ -0,0 +1,310 @@
++/*
++ *  Atheros AR71xx SoC specific setup
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ *  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/init.h>
++#include <linux/bootmem.h>
++
++#include <asm/bootinfo.h>
++#include <asm/time.h>		/* for mips_hpt_frequency */
++#include <asm/reboot.h>		/* for _machine_{restart,halt} */
++#include <asm/mips_machine.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++
++#define AR71XX_SYS_TYPE_LEN	64
++#define AR71XX_BASE_FREQ	40000000
++#define AR91XX_BASE_FREQ	5000000
++#define AR724X_BASE_FREQ	5000000
++
++u32 ar71xx_cpu_freq;
++EXPORT_SYMBOL_GPL(ar71xx_cpu_freq);
++
++u32 ar71xx_ahb_freq;
++EXPORT_SYMBOL_GPL(ar71xx_ahb_freq);
++
++u32 ar71xx_ddr_freq;
++EXPORT_SYMBOL_GPL(ar71xx_ddr_freq);
++
++enum ar71xx_soc_type ar71xx_soc;
++EXPORT_SYMBOL_GPL(ar71xx_soc);
++
++static char ar71xx_sys_type[AR71XX_SYS_TYPE_LEN];
++
++static void ar71xx_restart(char *command)
++{
++	ar71xx_device_stop(RESET_MODULE_FULL_CHIP);
++	for (;;)
++		if (cpu_wait)
++			cpu_wait();
++}
++
++static void ar71xx_halt(void)
++{
++	while (1)
++		cpu_wait();
++}
++
++static void __init ar71xx_detect_mem_size(void)
++{
++	unsigned long size;
++
++	for (size = AR71XX_MEM_SIZE_MIN; size < AR71XX_MEM_SIZE_MAX;
++	     size <<= 1 ) {
++		if (!memcmp(ar71xx_detect_mem_size,
++			    ar71xx_detect_mem_size + size, 1024))
++			break;
++	}
++
++	add_memory_region(0, size, BOOT_MEM_RAM);
++}
++
++static void __init ar71xx_detect_sys_type(void)
++{
++	char *chip = "????";
++	u32 id;
++	u32 major;
++	u32 minor;
++	u32 rev = 0;
++
++	id = ar71xx_reset_rr(AR71XX_RESET_REG_REV_ID);
++	major = id & REV_ID_MAJOR_MASK;
++
++	switch (major) {
++	case REV_ID_MAJOR_AR71XX:
++		minor = id & AR71XX_REV_ID_MINOR_MASK;
++		rev = id >> AR71XX_REV_ID_REVISION_SHIFT;
++		rev &= AR71XX_REV_ID_REVISION_MASK;
++		switch (minor) {
++		case AR71XX_REV_ID_MINOR_AR7130:
++			ar71xx_soc = AR71XX_SOC_AR7130;
++			chip = "7130";
++			break;
++
++		case AR71XX_REV_ID_MINOR_AR7141:
++			ar71xx_soc = AR71XX_SOC_AR7141;
++			chip = "7141";
++			break;
++
++		case AR71XX_REV_ID_MINOR_AR7161:
++			ar71xx_soc = AR71XX_SOC_AR7161;
++			chip = "7161";
++			break;
++		}
++		break;
++
++	case REV_ID_MAJOR_AR7240:
++		ar71xx_soc = AR71XX_SOC_AR7240;
++		chip = "7240";
++		rev = (id & AR724X_REV_ID_REVISION_MASK);
++		break;
++
++	case REV_ID_MAJOR_AR7241:
++		ar71xx_soc = AR71XX_SOC_AR7241;
++		chip = "7241";
++		rev = (id & AR724X_REV_ID_REVISION_MASK);
++		break;
++
++	case REV_ID_MAJOR_AR7242:
++		ar71xx_soc = AR71XX_SOC_AR7242;
++		chip = "7242";
++		rev = (id & AR724X_REV_ID_REVISION_MASK);
++		break;
++
++	case REV_ID_MAJOR_AR913X:
++		minor = id & AR91XX_REV_ID_MINOR_MASK;
++		rev = id >> AR91XX_REV_ID_REVISION_SHIFT;
++		rev &= AR91XX_REV_ID_REVISION_MASK;
++		switch (minor) {
++		case AR91XX_REV_ID_MINOR_AR9130:
++			ar71xx_soc = AR71XX_SOC_AR9130;
++			chip = "9130";
++			break;
++
++		case AR91XX_REV_ID_MINOR_AR9132:
++			ar71xx_soc = AR71XX_SOC_AR9132;
++			chip = "9132";
++			break;
++		}
++		break;
++
++	default:
++		panic("ar71xx: unknown chip id:0x%08x\n", id);
++	}
++
++	sprintf(ar71xx_sys_type, "Atheros AR%s rev %u", chip, rev);
++}
++
++static void __init ar91xx_detect_sys_frequency(void)
++{
++	u32 pll;
++	u32 freq;
++	u32 div;
++
++	pll = ar71xx_pll_rr(AR91XX_PLL_REG_CPU_CONFIG);
++
++	div = ((pll >> AR91XX_PLL_DIV_SHIFT) & AR91XX_PLL_DIV_MASK);
++	freq = div * AR91XX_BASE_FREQ;
++
++	ar71xx_cpu_freq = freq;
++
++	div = ((pll >> AR91XX_DDR_DIV_SHIFT) & AR91XX_DDR_DIV_MASK) + 1;
++	ar71xx_ddr_freq = freq / div;
++
++	div = (((pll >> AR91XX_AHB_DIV_SHIFT) & AR91XX_AHB_DIV_MASK) + 1) * 2;
++	ar71xx_ahb_freq = ar71xx_cpu_freq / div;
++}
++
++static void __init ar71xx_detect_sys_frequency(void)
++{
++	u32 pll;
++	u32 freq;
++	u32 div;
++
++	pll = ar71xx_pll_rr(AR71XX_PLL_REG_CPU_CONFIG);
++
++	div = ((pll >> AR71XX_PLL_DIV_SHIFT) & AR71XX_PLL_DIV_MASK) + 1;
++	freq = div * AR71XX_BASE_FREQ;
++
++	div = ((pll >> AR71XX_CPU_DIV_SHIFT) & AR71XX_CPU_DIV_MASK) + 1;
++	ar71xx_cpu_freq = freq / div;
++
++	div = ((pll >> AR71XX_DDR_DIV_SHIFT) & AR71XX_DDR_DIV_MASK) + 1;
++	ar71xx_ddr_freq = freq / div;
++
++	div = (((pll >> AR71XX_AHB_DIV_SHIFT) & AR71XX_AHB_DIV_MASK) + 1) * 2;
++	ar71xx_ahb_freq = ar71xx_cpu_freq / div;
++}
++
++static void __init ar724x_detect_sys_frequency(void)
++{
++	u32 pll;
++	u32 freq;
++	u32 div;
++
++	pll = ar71xx_pll_rr(AR724X_PLL_REG_CPU_CONFIG);
++
++	div = ((pll >> AR724X_PLL_DIV_SHIFT) & AR724X_PLL_DIV_MASK);
++	freq = div * AR724X_BASE_FREQ;
++
++	div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK);
++	freq *= div;
++
++	ar71xx_cpu_freq = freq;
++
++	div = ((pll >> AR724X_DDR_DIV_SHIFT) & AR724X_DDR_DIV_MASK) + 1;
++	ar71xx_ddr_freq = freq / div;
++
++	div = (((pll >> AR724X_AHB_DIV_SHIFT) & AR724X_AHB_DIV_MASK) + 1) * 2;
++	ar71xx_ahb_freq = ar71xx_cpu_freq / div;
++}
++
++static void __init detect_sys_frequency(void)
++{
++	switch (ar71xx_soc) {
++	case AR71XX_SOC_AR7130:
++	case AR71XX_SOC_AR7141:
++	case AR71XX_SOC_AR7161:
++		ar71xx_detect_sys_frequency();
++		break;
++
++	case AR71XX_SOC_AR7240:
++	case AR71XX_SOC_AR7241:
++	case AR71XX_SOC_AR7242:
++		ar724x_detect_sys_frequency();
++		break;
++
++	case AR71XX_SOC_AR9130:
++	case AR71XX_SOC_AR9132:
++		ar91xx_detect_sys_frequency();
++		break;
++
++	default:
++		BUG();
++	}
++}
++
++const char *get_system_type(void)
++{
++	return ar71xx_sys_type;
++}
++
++unsigned int __cpuinit get_c0_compare_irq(void)
++{
++	return CP0_LEGACY_COMPARE_IRQ;
++}
++
++void __init plat_mem_setup(void)
++{
++	set_io_port_base(KSEG1);
++
++	ar71xx_ddr_base = ioremap_nocache(AR71XX_DDR_CTRL_BASE,
++						AR71XX_DDR_CTRL_SIZE);
++
++	ar71xx_pll_base = ioremap_nocache(AR71XX_PLL_BASE,
++						AR71XX_PLL_SIZE);
++
++	ar71xx_reset_base = ioremap_nocache(AR71XX_RESET_BASE,
++						AR71XX_RESET_SIZE);
++
++	ar71xx_gpio_base = ioremap_nocache(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE);
++
++	ar71xx_usb_ctrl_base = ioremap_nocache(AR71XX_USB_CTRL_BASE,
++						AR71XX_USB_CTRL_SIZE);
++
++	ar71xx_detect_mem_size();
++	ar71xx_detect_sys_type();
++	detect_sys_frequency();
++
++	printk(KERN_INFO
++		"%s, CPU:%u.%03u MHz, AHB:%u.%03u MHz, DDR:%u.%03u MHz\n",
++		ar71xx_sys_type,
++		ar71xx_cpu_freq / 1000000, (ar71xx_cpu_freq / 1000) % 1000,
++		ar71xx_ahb_freq / 1000000, (ar71xx_ahb_freq / 1000) % 1000,
++		ar71xx_ddr_freq / 1000000, (ar71xx_ddr_freq / 1000) % 1000);
++
++	_machine_restart = ar71xx_restart;
++	_machine_halt = ar71xx_halt;
++	pm_power_off = ar71xx_halt;
++}
++
++void __init plat_time_init(void)
++{
++	mips_hpt_frequency = ar71xx_cpu_freq / 2;
++}
++
++__setup("board=", mips_machtype_setup);
++
++static int __init ar71xx_machine_setup(void)
++{
++	ar71xx_gpio_init();
++
++	ar71xx_add_device_uart();
++	ar71xx_add_device_wdt();
++
++	mips_machine_setup();
++	return 0;
++}
++
++arch_initcall(ar71xx_machine_setup);
++
++static void __init ar71xx_generic_init(void)
++{
++	/* Nothing to do */
++}
++
++MIPS_MACHINE(AR71XX_MACH_GENERIC, "Generic", "Generic AR71xx board",
++	     ar71xx_generic_init);
+diff -Nur linux-2.6.33.3.orig/arch/mips/include/asm/mach-ar71xx/ar71xx.h linux-2.6.33.3/arch/mips/include/asm/mach-ar71xx/ar71xx.h
+--- linux-2.6.33.3.orig/arch/mips/include/asm/mach-ar71xx/ar71xx.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/include/asm/mach-ar71xx/ar71xx.h	2010-04-02 11:07:50.806953666 +0200
+@@ -0,0 +1,514 @@
++/*
++ *  Atheros AR71xx SoC specific definitions
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ *  This program is free software; you can redistribute it and/or modify it
++ *  under the terms of the GNU General Public License version 2 as published
++ *  by the Free Software Foundation.
++ */
++
++#ifndef __ASM_MACH_AR71XX_H
++#define __ASM_MACH_AR71XX_H
++
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/bitops.h>
++
++#ifndef __ASSEMBLER__
++
++#define AR71XX_PCI_MEM_BASE	0x10000000
++#define AR71XX_PCI_MEM_SIZE	0x08000000
++#define AR71XX_APB_BASE		0x18000000
++#define AR71XX_GE0_BASE		0x19000000
++#define AR71XX_GE0_SIZE		0x01000000
++#define AR71XX_GE1_BASE		0x1a000000
++#define AR71XX_GE1_SIZE		0x01000000
++#define AR71XX_EHCI_BASE	0x1b000000
++#define AR71XX_EHCI_SIZE	0x01000000
++#define AR71XX_OHCI_BASE	0x1c000000
++#define AR71XX_OHCI_SIZE	0x01000000
++#define AR7240_OHCI_BASE	0x1b000000
++#define AR7240_OHCI_SIZE	0x01000000
++#define AR71XX_SPI_BASE		0x1f000000
++#define AR71XX_SPI_SIZE		0x01000000
++
++#define AR71XX_DDR_CTRL_BASE	(AR71XX_APB_BASE + 0x00000000)
++#define AR71XX_DDR_CTRL_SIZE	0x10000
++#define AR71XX_CPU_BASE		(AR71XX_APB_BASE + 0x00010000)
++#define AR71XX_UART_BASE	(AR71XX_APB_BASE + 0x00020000)
++#define AR71XX_UART_SIZE	0x10000
++#define AR71XX_USB_CTRL_BASE	(AR71XX_APB_BASE + 0x00030000)
++#define AR71XX_USB_CTRL_SIZE	0x10000
++#define AR71XX_GPIO_BASE	(AR71XX_APB_BASE + 0x00040000)
++#define AR71XX_GPIO_SIZE	0x10000
++#define AR71XX_PLL_BASE		(AR71XX_APB_BASE + 0x00050000)
++#define AR71XX_PLL_SIZE		0x10000
++#define AR71XX_RESET_BASE	(AR71XX_APB_BASE + 0x00060000)
++#define AR71XX_RESET_SIZE	0x10000
++#define AR71XX_MII_BASE		(AR71XX_APB_BASE + 0x00070000)
++#define AR71XX_MII_SIZE		0x10000
++#define AR71XX_SLIC_BASE	(AR71XX_APB_BASE + 0x00090000)
++#define AR71XX_SLIC_SIZE	0x10000
++#define AR71XX_DMA_BASE		(AR71XX_APB_BASE + 0x000A0000)
++#define AR71XX_DMA_SIZE		0x10000
++#define AR71XX_STEREO_BASE	(AR71XX_APB_BASE + 0x000B0000)
++#define AR71XX_STEREO_SIZE	0x10000
++
++#define AR724X_PCI_CRP_BASE	(AR71XX_APB_BASE + 0x000C0000)
++#define AR724X_PCI_CRP_SIZE	0x100
++
++#define AR724X_PCI_CTRL_BASE	(AR71XX_APB_BASE + 0x000F0000)
++#define AR724X_PCI_CTRL_SIZE	0x100
++
++#define AR91XX_WMAC_BASE	(AR71XX_APB_BASE + 0x000C0000)
++#define AR91XX_WMAC_SIZE	0x30000
++
++#define AR71XX_MEM_SIZE_MIN	0x0200000
++#define AR71XX_MEM_SIZE_MAX	0x10000000
++
++#define AR71XX_CPU_IRQ_BASE	0
++#define AR71XX_MISC_IRQ_BASE	8
++#define AR71XX_MISC_IRQ_COUNT	8
++#define AR71XX_GPIO_IRQ_BASE	16
++#define AR71XX_GPIO_IRQ_COUNT	32
++#define AR71XX_PCI_IRQ_BASE     48
++#define AR71XX_PCI_IRQ_COUNT	8
++
++#define AR71XX_CPU_IRQ_IP2	(AR71XX_CPU_IRQ_BASE + 2)
++#define AR71XX_CPU_IRQ_USB	(AR71XX_CPU_IRQ_BASE + 3)
++#define AR71XX_CPU_IRQ_GE0	(AR71XX_CPU_IRQ_BASE + 4)
++#define AR71XX_CPU_IRQ_GE1	(AR71XX_CPU_IRQ_BASE + 5)
++#define AR71XX_CPU_IRQ_MISC	(AR71XX_CPU_IRQ_BASE + 6)
++#define AR71XX_CPU_IRQ_TIMER	(AR71XX_CPU_IRQ_BASE + 7)
++
++#define AR71XX_MISC_IRQ_TIMER	(AR71XX_MISC_IRQ_BASE + 0)
++#define AR71XX_MISC_IRQ_ERROR	(AR71XX_MISC_IRQ_BASE + 1)
++#define AR71XX_MISC_IRQ_GPIO	(AR71XX_MISC_IRQ_BASE + 2)
++#define AR71XX_MISC_IRQ_UART	(AR71XX_MISC_IRQ_BASE + 3)
++#define AR71XX_MISC_IRQ_WDOG	(AR71XX_MISC_IRQ_BASE + 4)
++#define AR71XX_MISC_IRQ_PERFC	(AR71XX_MISC_IRQ_BASE + 5)
++#define AR71XX_MISC_IRQ_OHCI	(AR71XX_MISC_IRQ_BASE + 6)
++#define AR71XX_MISC_IRQ_DMA	(AR71XX_MISC_IRQ_BASE + 7)
++
++#define AR71XX_GPIO_IRQ(_x)	(AR71XX_GPIO_IRQ_BASE + (_x))
++
++#define AR71XX_PCI_IRQ_DEV0	(AR71XX_PCI_IRQ_BASE + 0)
++#define AR71XX_PCI_IRQ_DEV1	(AR71XX_PCI_IRQ_BASE + 1)
++#define AR71XX_PCI_IRQ_DEV2	(AR71XX_PCI_IRQ_BASE + 2)
++#define AR71XX_PCI_IRQ_CORE	(AR71XX_PCI_IRQ_BASE + 4)
++
++extern u32 ar71xx_ahb_freq;
++extern u32 ar71xx_cpu_freq;
++extern u32 ar71xx_ddr_freq;
++
++enum ar71xx_soc_type {
++	AR71XX_SOC_UNKNOWN,
++	AR71XX_SOC_AR7130,
++	AR71XX_SOC_AR7141,
++	AR71XX_SOC_AR7161,
++	AR71XX_SOC_AR7240,
++	AR71XX_SOC_AR7241,
++	AR71XX_SOC_AR7242,
++	AR71XX_SOC_AR9130,
++	AR71XX_SOC_AR9132
++};
++
++extern enum ar71xx_soc_type ar71xx_soc;
++
++/*
++ * PLL block
++ */
++#define AR71XX_PLL_REG_CPU_CONFIG	0x00
++#define AR71XX_PLL_REG_SEC_CONFIG	0x04
++#define AR71XX_PLL_REG_ETH0_INT_CLOCK	0x10
++#define AR71XX_PLL_REG_ETH1_INT_CLOCK	0x14
++
++#define AR71XX_PLL_DIV_SHIFT		3
++#define AR71XX_PLL_DIV_MASK		0x1f
++#define AR71XX_CPU_DIV_SHIFT		16
++#define AR71XX_CPU_DIV_MASK		0x3
++#define AR71XX_DDR_DIV_SHIFT		18
++#define AR71XX_DDR_DIV_MASK		0x3
++#define AR71XX_AHB_DIV_SHIFT		20
++#define AR71XX_AHB_DIV_MASK		0x7
++
++#define AR71XX_ETH0_PLL_SHIFT		17
++#define AR71XX_ETH1_PLL_SHIFT		19
++
++#define AR724X_PLL_REG_CPU_CONFIG	0x00
++#define AR724X_PLL_REG_PCIE_CONFIG	0x18
++
++#define AR724X_PLL_DIV_SHIFT		0
++#define AR724X_PLL_DIV_MASK		0x3ff
++#define AR724X_PLL_REF_DIV_SHIFT	10
++#define AR724X_PLL_REF_DIV_MASK		0xf
++#define AR724X_AHB_DIV_SHIFT		19
++#define AR724X_AHB_DIV_MASK		0x1
++#define AR724X_DDR_DIV_SHIFT		22
++#define AR724X_DDR_DIV_MASK		0x3
++
++#define AR91XX_PLL_REG_CPU_CONFIG	0x00
++#define AR91XX_PLL_REG_ETH_CONFIG	0x04
++#define AR91XX_PLL_REG_ETH0_INT_CLOCK	0x14
++#define AR91XX_PLL_REG_ETH1_INT_CLOCK	0x18
++
++#define AR91XX_PLL_DIV_SHIFT		0
++#define AR91XX_PLL_DIV_MASK		0x3ff
++#define AR91XX_DDR_DIV_SHIFT		22
++#define AR91XX_DDR_DIV_MASK		0x3
++#define AR91XX_AHB_DIV_SHIFT		19
++#define AR91XX_AHB_DIV_MASK		0x1
++
++#define AR91XX_ETH0_PLL_SHIFT		20
++#define AR91XX_ETH1_PLL_SHIFT		22
++
++extern void __iomem *ar71xx_pll_base;
++
++static inline void ar71xx_pll_wr(unsigned reg, u32 val)
++{
++	__raw_writel(val, ar71xx_pll_base + reg);
++}
++
++static inline u32 ar71xx_pll_rr(unsigned reg)
++{
++	return __raw_readl(ar71xx_pll_base + reg);
++}
++
++/*
++ * USB_CONFIG block
++ */
++#define USB_CTRL_REG_FLADJ	0x00
++#define USB_CTRL_REG_CONFIG	0x04
++
++extern void __iomem *ar71xx_usb_ctrl_base;
++
++static inline void ar71xx_usb_ctrl_wr(unsigned reg, u32 val)
++{
++	__raw_writel(val, ar71xx_usb_ctrl_base + reg);
++}
++
++static inline u32 ar71xx_usb_ctrl_rr(unsigned reg)
++{
++	return __raw_readl(ar71xx_usb_ctrl_base + reg);
++}
++
++/*
++ * GPIO block
++ */
++#define GPIO_REG_OE		0x00
++#define GPIO_REG_IN		0x04
++#define GPIO_REG_OUT		0x08
++#define GPIO_REG_SET		0x0c
++#define GPIO_REG_CLEAR		0x10
++#define GPIO_REG_INT_MODE	0x14
++#define GPIO_REG_INT_TYPE	0x18
++#define GPIO_REG_INT_POLARITY	0x1c
++#define GPIO_REG_INT_PENDING	0x20
++#define GPIO_REG_INT_ENABLE	0x24
++#define GPIO_REG_FUNC		0x28
++
++#define AR71XX_GPIO_FUNC_STEREO_EN	BIT(17)
++#define AR71XX_GPIO_FUNC_SLIC_EN	BIT(16)
++#define AR71XX_GPIO_FUNC_SPI_CS2_EN	BIT(13)
++#define AR71XX_GPIO_FUNC_SPI_CS1_EN	BIT(12)
++#define AR71XX_GPIO_FUNC_UART_EN	BIT(8)
++#define AR71XX_GPIO_FUNC_USB_OC_EN	BIT(4)
++#define AR71XX_GPIO_FUNC_USB_CLK_EN	BIT(0)
++
++#define AR71XX_GPIO_COUNT	16
++
++#define AR724X_GPIO_FUNC_GE0_MII_CLK_EN		BIT(19)
++#define AR724X_GPIO_FUNC_SPI_EN			BIT(18)
++#define AR724X_GPIO_FUNC_SPI_CS_EN2		BIT(14)
++#define AR724X_GPIO_FUNC_SPI_CS_EN1		BIT(13)
++#define AR724X_GPIO_FUNC_CLK_OBS5_EN		BIT(12)
++#define AR724X_GPIO_FUNC_CLK_OBS4_EN		BIT(11)
++#define AR724X_GPIO_FUNC_CLK_OBS3_EN		BIT(10)
++#define AR724X_GPIO_FUNC_CLK_OBS2_EN		BIT(9)
++#define AR724X_GPIO_FUNC_CLK_OBS1_EN		BIT(8)
++#define AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN	BIT(7)
++#define AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN	BIT(6)
++#define AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN	BIT(5)
++#define AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN	BIT(4)
++#define AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN	BIT(3)
++#define AR724X_GPIO_FUNC_UART_RTS_CTS_EN	BIT(2)
++#define AR724X_GPIO_FUNC_UART_EN		BIT(1)
++#define AR724X_GPIO_FUNC_JTAG_DISABLE		BIT(0)
++
++#define AR724X_GPIO_COUNT	18
++
++#define AR91XX_GPIO_FUNC_WMAC_LED_EN	BIT(22)
++#define AR91XX_GPIO_FUNC_EXP_PORT_CS_EN	BIT(21)
++#define AR91XX_GPIO_FUNC_I2S_REFCLKEN	BIT(20)
++#define AR91XX_GPIO_FUNC_I2S_MCKEN	BIT(19)
++#define AR91XX_GPIO_FUNC_I2S1_EN	BIT(18)
++#define AR91XX_GPIO_FUNC_I2S0_EN	BIT(17)
++#define AR91XX_GPIO_FUNC_SLIC_EN	BIT(16)
++#define AR91XX_GPIO_FUNC_UART_RTSCTS_EN	BIT(9)
++#define AR91XX_GPIO_FUNC_UART_EN	BIT(8)
++#define AR91XX_GPIO_FUNC_USB_CLK_EN	BIT(4)
++
++#define AR91XX_GPIO_COUNT	22
++
++extern void __iomem *ar71xx_gpio_base;
++
++static inline void ar71xx_gpio_wr(unsigned reg, u32 value)
++{
++	__raw_writel(value, ar71xx_gpio_base + reg);
++}
++
++static inline u32 ar71xx_gpio_rr(unsigned reg)
++{
++	return __raw_readl(ar71xx_gpio_base + reg);
++}
++
++void ar71xx_gpio_init(void) __init;
++void ar71xx_gpio_function_enable(u32 mask);
++void ar71xx_gpio_function_disable(u32 mask);
++void ar71xx_gpio_function_setup(u32 set, u32 clear);
++
++/*
++ * DDR_CTRL block
++ */
++#define AR71XX_DDR_REG_PCI_WIN0		0x7c
++#define AR71XX_DDR_REG_PCI_WIN1		0x80
++#define AR71XX_DDR_REG_PCI_WIN2		0x84
++#define AR71XX_DDR_REG_PCI_WIN3		0x88
++#define AR71XX_DDR_REG_PCI_WIN4		0x8c
++#define AR71XX_DDR_REG_PCI_WIN5		0x90
++#define AR71XX_DDR_REG_PCI_WIN6		0x94
++#define AR71XX_DDR_REG_PCI_WIN7		0x98
++#define AR71XX_DDR_REG_FLUSH_GE0	0x9c
++#define AR71XX_DDR_REG_FLUSH_GE1	0xa0
++#define AR71XX_DDR_REG_FLUSH_USB	0xa4
++#define AR71XX_DDR_REG_FLUSH_PCI	0xa8
++
++#define AR724X_DDR_REG_FLUSH_GE0	0x7c
++#define AR724X_DDR_REG_FLUSH_GE1	0x80
++#define AR724X_DDR_REG_FLUSH_USB	0x84
++#define AR724X_DDR_REG_FLUSH_PCIE	0x88
++
++#define AR91XX_DDR_REG_FLUSH_GE0	0x7c
++#define AR91XX_DDR_REG_FLUSH_GE1	0x80
++#define AR91XX_DDR_REG_FLUSH_USB	0x84
++#define AR91XX_DDR_REG_FLUSH_WMAC	0x88
++
++#define PCI_WIN0_OFFS	0x10000000
++#define PCI_WIN1_OFFS	0x11000000
++#define PCI_WIN2_OFFS	0x12000000
++#define PCI_WIN3_OFFS	0x13000000
++#define PCI_WIN4_OFFS	0x14000000
++#define PCI_WIN5_OFFS	0x15000000
++#define PCI_WIN6_OFFS	0x16000000
++#define PCI_WIN7_OFFS	0x07000000
++
++extern void __iomem *ar71xx_ddr_base;
++
++static inline void ar71xx_ddr_wr(unsigned reg, u32 val)
++{
++	__raw_writel(val, ar71xx_ddr_base + reg);
++}
++
++static inline u32 ar71xx_ddr_rr(unsigned reg)
++{
++	return __raw_readl(ar71xx_ddr_base + reg);
++}
++
++void ar71xx_ddr_flush(u32 reg);
++
++/*
++ * PCI block
++ */
++#define AR71XX_PCI_CFG_BASE	(AR71XX_PCI_MEM_BASE + PCI_WIN7_OFFS + 0x10000)
++#define AR71XX_PCI_CFG_SIZE	0x100
++
++#define PCI_REG_CRP_AD_CBE	0x00
++#define PCI_REG_CRP_WRDATA	0x04
++#define PCI_REG_CRP_RDDATA	0x08
++#define PCI_REG_CFG_AD		0x0c
++#define PCI_REG_CFG_CBE		0x10
++#define PCI_REG_CFG_WRDATA	0x14
++#define PCI_REG_CFG_RDDATA	0x18
++#define PCI_REG_PCI_ERR		0x1c
++#define PCI_REG_PCI_ERR_ADDR	0x20
++#define PCI_REG_AHB_ERR		0x24
++#define PCI_REG_AHB_ERR_ADDR	0x28
++
++#define PCI_CRP_CMD_WRITE	0x00010000
++#define PCI_CRP_CMD_READ	0x00000000
++#define PCI_CFG_CMD_READ	0x0000000a
++#define PCI_CFG_CMD_WRITE	0x0000000b
++
++#define PCI_IDSEL_ADL_START	17
++
++#define AR724X_PCI_CFG_BASE	(AR71XX_PCI_MEM_BASE + 0x4000000)
++#define AR724X_PCI_CFG_SIZE	0x1000
++
++#define AR724X_PCI_REG_APP		0x00
++#define AR724X_PCI_REG_RESET		0x18
++#define AR724X_PCI_REG_INT_STATUS	0x4c
++#define AR724X_PCI_REG_INT_MASK		0x50
++
++#define AR724X_PCI_APP_LTSSM_ENABLE	BIT(0)
++#define AR724X_PCI_RESET_LINK_UP	BIT(0)
++
++#define AR724X_PCI_INT_DEV0		BIT(14)
++
++/*
++ * RESET block
++ */
++#define AR71XX_RESET_REG_TIMER			0x00
++#define AR71XX_RESET_REG_TIMER_RELOAD		0x04
++#define AR71XX_RESET_REG_WDOG_CTRL		0x08
++#define AR71XX_RESET_REG_WDOG			0x0c
++#define AR71XX_RESET_REG_MISC_INT_STATUS	0x10
++#define AR71XX_RESET_REG_MISC_INT_ENABLE	0x14
++#define AR71XX_RESET_REG_PCI_INT_STATUS		0x18
++#define AR71XX_RESET_REG_PCI_INT_ENABLE		0x1c
++#define AR71XX_RESET_REG_GLOBAL_INT_STATUS	0x20
++#define AR71XX_RESET_REG_RESET_MODULE		0x24
++#define AR71XX_RESET_REG_PERFC_CTRL		0x2c
++#define AR71XX_RESET_REG_PERFC0			0x30
++#define AR71XX_RESET_REG_PERFC1			0x34
++#define AR71XX_RESET_REG_REV_ID			0x90
++
++#define AR91XX_RESET_REG_GLOBAL_INT_STATUS	0x18
++#define AR91XX_RESET_REG_RESET_MODULE		0x1c
++#define AR91XX_RESET_REG_PERF_CTRL		0x20
++#define AR91XX_RESET_REG_PERFC0			0x24
++#define AR91XX_RESET_REG_PERFC1			0x28
++
++#define AR724X_RESET_REG_RESET_MODULE		0x1c
++
++#define WDOG_CTRL_LAST_RESET		BIT(31)
++#define WDOG_CTRL_ACTION_MASK		3
++#define WDOG_CTRL_ACTION_NONE		0	/* no action */
++#define WDOG_CTRL_ACTION_GPI		1	/* general purpose interrupt */
++#define WDOG_CTRL_ACTION_NMI		2	/* NMI */
++#define WDOG_CTRL_ACTION_FCR		3	/* full chip reset */
++
++#define MISC_INT_DMA			BIT(7)
++#define MISC_INT_OHCI			BIT(6)
++#define MISC_INT_PERFC			BIT(5)
++#define MISC_INT_WDOG			BIT(4)
++#define MISC_INT_UART			BIT(3)
++#define MISC_INT_GPIO			BIT(2)
++#define MISC_INT_ERROR			BIT(1)
++#define MISC_INT_TIMER			BIT(0)
++
++#define PCI_INT_CORE			BIT(4)
++#define PCI_INT_DEV2			BIT(2)
++#define PCI_INT_DEV1			BIT(1)
++#define PCI_INT_DEV0			BIT(0)
++
++#define RESET_MODULE_EXTERNAL		BIT(28)
++#define RESET_MODULE_FULL_CHIP		BIT(24)
++#define RESET_MODULE_AMBA2WMAC		BIT(22)
++#define RESET_MODULE_CPU_NMI		BIT(21)
++#define RESET_MODULE_CPU_COLD		BIT(20)
++#define RESET_MODULE_DMA		BIT(19)
++#define RESET_MODULE_SLIC		BIT(18)
++#define RESET_MODULE_STEREO		BIT(17)
++#define RESET_MODULE_DDR		BIT(16)
++#define RESET_MODULE_GE1_MAC		BIT(13)
++#define RESET_MODULE_GE1_PHY		BIT(12)
++#define RESET_MODULE_USBSUS_OVERRIDE	BIT(10)
++#define RESET_MODULE_GE0_MAC		BIT(9)
++#define RESET_MODULE_GE0_PHY		BIT(8)
++#define RESET_MODULE_USB_OHCI_DLL	BIT(6)
++#define RESET_MODULE_USB_HOST		BIT(5)
++#define RESET_MODULE_USB_PHY		BIT(4)
++#define RESET_MODULE_USB_OHCI_DLL_7240	BIT(3)
++#define RESET_MODULE_PCI_BUS		BIT(1)
++#define RESET_MODULE_PCI_CORE		BIT(0)
++
++#define AR724X_RESET_GE1_MDIO		BIT(23)
++#define AR724X_RESET_GE0_MDIO		BIT(22)
++#define AR724X_RESET_PCIE_PHY_SERIAL	BIT(10)
++#define AR724X_RESET_PCIE_PHY		BIT(7)
++#define AR724X_RESET_PCIE		BIT(6)
++
++#define REV_ID_MAJOR_MASK	0xfff0
++#define REV_ID_MAJOR_AR71XX	0x00a0
++#define REV_ID_MAJOR_AR913X	0x00b0
++#define REV_ID_MAJOR_AR7240	0x00c0
++#define REV_ID_MAJOR_AR7241	0x0100
++#define REV_ID_MAJOR_AR7242	0x1100
++
++#define AR71XX_REV_ID_MINOR_MASK	0x3
++#define AR71XX_REV_ID_MINOR_AR7130	0x0
++#define AR71XX_REV_ID_MINOR_AR7141	0x1
++#define AR71XX_REV_ID_MINOR_AR7161	0x2
++#define AR71XX_REV_ID_REVISION_MASK	0x3
++#define AR71XX_REV_ID_REVISION_SHIFT	2
++
++#define AR91XX_REV_ID_MINOR_MASK	0x3
++#define AR91XX_REV_ID_MINOR_AR9130	0x0
++#define AR91XX_REV_ID_MINOR_AR9132	0x1
++#define AR91XX_REV_ID_REVISION_MASK	0x3
++#define AR91XX_REV_ID_REVISION_SHIFT	2
++
++#define AR724X_REV_ID_REVISION_MASK	0x3
++
++extern void __iomem *ar71xx_reset_base;
++
++static inline void ar71xx_reset_wr(unsigned reg, u32 val)
++{
++	__raw_writel(val, ar71xx_reset_base + reg);
++}
++
++static inline u32 ar71xx_reset_rr(unsigned reg)
++{
++	return __raw_readl(ar71xx_reset_base + reg);
++}
++
++void ar71xx_device_stop(u32 mask);
++void ar71xx_device_start(u32 mask);
++int ar71xx_device_stopped(u32 mask);
++
++/*
++ * SPI block
++ */
++#define SPI_REG_FS		0x00	/* Function Select */
++#define SPI_REG_CTRL		0x04	/* SPI Control */
++#define SPI_REG_IOC		0x08	/* SPI I/O Control */
++#define SPI_REG_RDS		0x0c	/* Read Data Shift */
++
++#define SPI_FS_GPIO		BIT(0)	/* Enable GPIO mode */
++
++#define SPI_CTRL_RD		BIT(6)	/* Remap Disable */
++#define SPI_CTRL_DIV_MASK	0x3f
++
++#define SPI_IOC_DO		BIT(0)	/* Data Out pin */
++#define SPI_IOC_CLK		BIT(8)	/* CLK pin */
++#define SPI_IOC_CS(n)		BIT(16 + (n))
++#define SPI_IOC_CS0		SPI_IOC_CS(0)
++#define SPI_IOC_CS1		SPI_IOC_CS(1)
++#define SPI_IOC_CS2		SPI_IOC_CS(2)
++#define SPI_IOC_CS_ALL		(SPI_IOC_CS0 | SPI_IOC_CS1 | SPI_IOC_CS2)
++
++void ar71xx_flash_acquire(void);
++void ar71xx_flash_release(void);
++
++/*
++ * MII_CTRL block
++ */
++#define MII_REG_MII0_CTRL	0x00
++#define MII_REG_MII1_CTRL	0x04
++
++#define MII0_CTRL_IF_GMII	0
++#define MII0_CTRL_IF_MII	1
++#define MII0_CTRL_IF_RGMII	2
++#define MII0_CTRL_IF_RMII	3
++
++#define MII1_CTRL_IF_RGMII	0
++#define MII1_CTRL_IF_RMII	1
++
++#endif /* __ASSEMBLER__ */
++
++#endif /* __ASM_MACH_AR71XX_H */
+diff -Nur linux-2.6.33.3.orig/arch/mips/include/asm/mach-ar71xx/ar91xx_flash.h linux-2.6.33.3/arch/mips/include/asm/mach-ar71xx/ar91xx_flash.h
+--- linux-2.6.33.3.orig/arch/mips/include/asm/mach-ar71xx/ar91xx_flash.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/include/asm/mach-ar71xx/ar91xx_flash.h	2009-12-13 20:45:20.439922318 +0100
+@@ -0,0 +1,26 @@
++/*
++ *  AR91xx parallel flash driver platform data definitions
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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.
++ */
++
++#ifndef __AR91XX_FLASH_H
++#define __AR91XX_FLASH_H
++
++struct mtd_partition;
++
++struct ar91xx_flash_platform_data {
++	unsigned int		width;
++	u8			is_shared:1;
++#ifdef CONFIG_MTD_PARTITIONS
++	unsigned int		nr_parts;
++	struct mtd_partition	*parts;
++#endif
++};
++
++#endif /* __AR91XX_FLASH_H */
+diff -Nur linux-2.6.33.3.orig/arch/mips/include/asm/mach-ar71xx/cpu-feature-overrides.h linux-2.6.33.3/arch/mips/include/asm/mach-ar71xx/cpu-feature-overrides.h
+--- linux-2.6.33.3.orig/arch/mips/include/asm/mach-ar71xx/cpu-feature-overrides.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/include/asm/mach-ar71xx/cpu-feature-overrides.h	2009-12-13 20:45:20.471921431 +0100
+@@ -0,0 +1,56 @@
++/*
++ *  Atheros AR71xx specific CPU feature overrides
++ *
++ *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  This file was derived from: include/asm-mips/cpu-features.h
++ *	Copyright (C) 2003, 2004 Ralf Baechle
++ *	Copyright (C) 2004 Maciej W. Rozycki
++ *
++ *  This program is free software; you can redistribute it and/or modify it
++ *  under the terms of the GNU General Public License version 2 as published
++ *  by the Free Software Foundation.
++ *
++ */
++#ifndef __ASM_MACH_AR71XX_CPU_FEATURE_OVERRIDES_H
++#define __ASM_MACH_AR71XX_CPU_FEATURE_OVERRIDES_H
++
++#define cpu_has_tlb		1
++#define cpu_has_4kex		1
++#define cpu_has_3k_cache	0
++#define cpu_has_4k_cache	1
++#define cpu_has_tx39_cache	0
++#define cpu_has_sb1_cache	0
++#define cpu_has_fpu		0
++#define cpu_has_32fpr		0
++#define cpu_has_counter		1
++#define cpu_has_watch		1
++#define cpu_has_divec		1
++
++#define cpu_has_prefetch	1
++#define cpu_has_ejtag		1
++#define cpu_has_llsc		1
++
++#define cpu_has_mips16		1
++#define cpu_has_mdmx		0
++#define cpu_has_mips3d		0
++#define cpu_has_smartmips	0
++
++#define cpu_has_mips32r1	1
++#define cpu_has_mips32r2	1
++#define cpu_has_mips64r1	0
++#define cpu_has_mips64r2	0
++
++#define cpu_has_dsp		0
++#define cpu_has_mipsmt		0
++
++#define cpu_has_64bits		0
++#define cpu_has_64bit_zero_reg	0
++#define cpu_has_64bit_gp_regs	0
++#define cpu_has_64bit_addresses	0
++
++#define cpu_dcache_line_size()	32
++#define cpu_icache_line_size()	32
++
++#endif /* __ASM_MACH_AR71XX_CPU_FEATURE_OVERRIDES_H */
+diff -Nur linux-2.6.33.3.orig/arch/mips/include/asm/mach-ar71xx/gpio.h linux-2.6.33.3/arch/mips/include/asm/mach-ar71xx/gpio.h
+--- linux-2.6.33.3.orig/arch/mips/include/asm/mach-ar71xx/gpio.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/include/asm/mach-ar71xx/gpio.h	2009-12-13 20:45:20.471921431 +0100
+@@ -0,0 +1,53 @@
++/*
++ *  Atheros AR71xx GPIO API definitions
++ *
++ *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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.
++ *
++ */
++
++#ifndef __ASM_MACH_AR71XX_GPIO_H
++#define __ASM_MACH_AR71XX_GPIO_H
++
++#define ARCH_NR_GPIOS	64
++#include <asm-generic/gpio.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++extern unsigned long ar71xx_gpio_count;
++extern void __ar71xx_gpio_set_value(unsigned gpio, int value);
++extern int __ar71xx_gpio_get_value(unsigned gpio);
++
++static inline int gpio_to_irq(unsigned gpio)
++{
++	return AR71XX_GPIO_IRQ(gpio);
++}
++
++static inline int irq_to_gpio(unsigned irq)
++{
++	return irq - AR71XX_GPIO_IRQ_BASE;
++}
++
++static inline int gpio_get_value(unsigned gpio)
++{
++	if (gpio < ar71xx_gpio_count)
++		return __ar71xx_gpio_get_value(gpio);
++
++	return __gpio_get_value(gpio);
++}
++
++static inline void gpio_set_value(unsigned gpio, int value)
++{
++	if (gpio < ar71xx_gpio_count)
++		__ar71xx_gpio_set_value(gpio, value);
++	else
++		__gpio_set_value(gpio, value);
++}
++
++#define gpio_cansleep	__gpio_cansleep
++
++#endif /* __ASM_MACH_AR71XX_GPIO_H */
+diff -Nur linux-2.6.33.3.orig/arch/mips/include/asm/mach-ar71xx/irq.h linux-2.6.33.3/arch/mips/include/asm/mach-ar71xx/irq.h
+--- linux-2.6.33.3.orig/arch/mips/include/asm/mach-ar71xx/irq.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/include/asm/mach-ar71xx/irq.h	2009-12-13 20:45:20.447923983 +0100
+@@ -0,0 +1,17 @@
++/*
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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.
++ */
++#ifndef __ASM_MACH_AR71XX_IRQ_H
++#define __ASM_MACH_AR71XX_IRQ_H
++
++#define MIPS_CPU_IRQ_BASE	0
++#define NR_IRQS			56
++
++#include_next <irq.h>
++
++#endif /* __ASM_MACH_AR71XX_IRQ_H */
+diff -Nur linux-2.6.33.3.orig/arch/mips/include/asm/mach-ar71xx/kernel-entry-init.h linux-2.6.33.3/arch/mips/include/asm/mach-ar71xx/kernel-entry-init.h
+--- linux-2.6.33.3.orig/arch/mips/include/asm/mach-ar71xx/kernel-entry-init.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/include/asm/mach-ar71xx/kernel-entry-init.h	2009-12-13 20:45:20.611920954 +0100
+@@ -0,0 +1,32 @@
++/*
++ *  Atheros AR71xx specific kernel entry setup
++ *
++ *  Copyright (C) 2009 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.
++ *
++ */
++#ifndef __ASM_MACH_AR71XX_KERNEL_ENTRY_H
++#define __ASM_MACH_AR71XX_KERNEL_ENTRY_H
++
++	/*
++	 * Some bootloaders set the 'Kseg0 coherency algorithm' to
++	 * 'Cacheable, noncoherent, write-through, no write allocate'
++	 * and this cause performance issues. Let's go and change it to
++	 * 'Cacheable, noncoherent, write-back, write allocate'
++	 */
++	.macro	kernel_entry_setup
++	mfc0	t0, CP0_CONFIG
++	li	t1, ~CONF_CM_CMASK
++	and	t0, t1
++	ori	t0, CONF_CM_CACHABLE_NONCOHERENT
++	mtc0	t0, CP0_CONFIG
++	nop
++	.endm
++
++	.macro	smp_slave_setup
++	.endm
++
++#endif /* __ASM_MACH_AR71XX_KERNEL_ENTRY_H */
+diff -Nur linux-2.6.33.3.orig/arch/mips/include/asm/mach-ar71xx/mach-rb750.h linux-2.6.33.3/arch/mips/include/asm/mach-ar71xx/mach-rb750.h
+--- linux-2.6.33.3.orig/arch/mips/include/asm/mach-ar71xx/mach-rb750.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/include/asm/mach-ar71xx/mach-rb750.h	2010-03-12 19:31:45.750044904 +0100
+@@ -0,0 +1,66 @@
++/*
++ *  MikroTik RouterBOARD 750 definitions
++ *
++ *  Copyright (C) 2010 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.
++ */
++#ifndef _MACH_RB750_H
++#define _MACH_RB750_H
++
++#include <linux/bitops.h>
++
++#define RB750_GPIO_LVC573_LE	0	/* Latch enable on LVC573 */
++#define RB750_GPIO_NAND_IO0	1	/* NAND I/O 0 */
++#define RB750_GPIO_NAND_IO1	2	/* NAND I/O 1 */
++#define RB750_GPIO_NAND_IO2	3	/* NAND I/O 2 */
++#define RB750_GPIO_NAND_IO3	4	/* NAND I/O 3 */
++#define RB750_GPIO_NAND_IO4	5	/* NAND I/O 4 */
++#define RB750_GPIO_NAND_IO5	6	/* NAND I/O 5 */
++#define RB750_GPIO_NAND_IO6	7	/* NAND I/O 6 */
++#define RB750_GPIO_NAND_IO7	8	/* NAND I/O 7 */
++#define RB750_GPIO_NAND_NCE	11	/* NAND Chip Enable (active low) */
++#define RB750_GPIO_NAND_RDY	12	/* NAND Ready */
++#define RB750_GPIO_NAND_CLE	14	/* NAND Command Latch Enable */
++#define RB750_GPIO_NAND_ALE	15	/* NAND Address Latch Enable */
++#define RB750_GPIO_NAND_NRE	16	/* NAND Read Enable (active low) */
++#define RB750_GPIO_NAND_NWE	17	/* NAND Write Enable (active low) */
++
++#define RB750_GPIO_BTN_RESET	1
++#define RB750_GPIO_SPI_CS0	2
++#define RB750_GPIO_LED_ACT	12
++#define RB750_GPIO_LED_PORT1	13
++#define RB750_GPIO_LED_PORT2	14
++#define RB750_GPIO_LED_PORT3	15
++#define RB750_GPIO_LED_PORT4	16
++#define RB750_GPIO_LED_PORT5	17
++
++#define RB750_LED_ACT		BIT(RB750_GPIO_LED_ACT)
++#define RB750_LED_PORT1		BIT(RB750_GPIO_LED_PORT1)
++#define RB750_LED_PORT2		BIT(RB750_GPIO_LED_PORT2)
++#define RB750_LED_PORT3		BIT(RB750_GPIO_LED_PORT3)
++#define RB750_LED_PORT4		BIT(RB750_GPIO_LED_PORT4)
++#define RB750_LED_PORT5		BIT(RB750_GPIO_LED_PORT5)
++
++#define RB750_LVC573_LE		BIT(RB750_GPIO_LVC573_LE)
++
++#define RB750_LED_BITS	(RB750_LED_PORT1 | RB750_LED_PORT2 | RB750_LED_PORT3 | \
++			 RB750_LED_PORT4 | RB750_LED_PORT5 | RB750_LED_ACT)
++
++struct rb750_led_data {
++	char	*name;
++	char	*default_trigger;
++	u32	mask;
++	int	active_low;
++};
++
++struct rb750_led_platform_data {
++	int			num_leds;
++	struct rb750_led_data	*leds;
++};
++
++int rb750_latch_change(u32 mask_clr, u32 mask_set);
++
++#endif /* _MACH_RB750_H */
+\ No newline at end of file
+diff -Nur linux-2.6.33.3.orig/arch/mips/include/asm/mach-ar71xx/mangle-port.h linux-2.6.33.3/arch/mips/include/asm/mach-ar71xx/mangle-port.h
+--- linux-2.6.33.3.orig/arch/mips/include/asm/mach-ar71xx/mangle-port.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/include/asm/mach-ar71xx/mangle-port.h	2009-12-13 20:45:20.615923464 +0100
+@@ -0,0 +1,45 @@
++/*
++ *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  This file was derived from: inlude/asm-mips/mach-generic/mangle-port.h
++ * 	Copyright (C) 2003, 2004 Ralf Baechle
++ *
++ *  This program is free software; you can redistribute it and/or modify it
++ *  under the terms of the GNU General Public License version 2 as published
++ *  by the Free Software Foundation.
++ */
++
++#ifndef __ASM_MACH_AR71XX_MANGLE_PORT_H
++#define __ASM_MACH_AR71XX_MANGLE_PORT_H
++
++#define __swizzle_addr_b(port)	((port) ^ 3)
++#define __swizzle_addr_w(port)	((port) ^ 2)
++#define __swizzle_addr_l(port)	(port)
++#define __swizzle_addr_q(port)	(port)
++
++#if defined(CONFIG_SWAP_IO_SPACE)
++
++# define ioswabb(a, x)           (x)
++# define __mem_ioswabb(a, x)     (x)
++# define ioswabw(a, x)           le16_to_cpu(x)
++# define __mem_ioswabw(a, x)     (x)
++# define ioswabl(a, x)           le32_to_cpu(x)
++# define __mem_ioswabl(a, x)     (x)
++# define ioswabq(a, x)           le64_to_cpu(x)
++# define __mem_ioswabq(a, x)     (x)
++
++#else
++
++# define ioswabb(a, x)           (x)
++# define __mem_ioswabb(a, x)     (x)
++# define ioswabw(a, x)           (x)
++# define __mem_ioswabw(a, x)     cpu_to_le16(x)
++# define ioswabl(a, x)           (x)
++# define __mem_ioswabl(a, x)     cpu_to_le32(x)
++# define ioswabq(a, x)           (x)
++# define __mem_ioswabq(a, x)     cpu_to_le64(x)
++
++#endif
++
++#endif /* __ASM_MACH_AR71XX_MANGLE_PORT_H */
+diff -Nur linux-2.6.33.3.orig/arch/mips/include/asm/mach-ar71xx/pci.h linux-2.6.33.3/arch/mips/include/asm/mach-ar71xx/pci.h
+--- linux-2.6.33.3.orig/arch/mips/include/asm/mach-ar71xx/pci.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/include/asm/mach-ar71xx/pci.h	2009-12-13 20:45:20.471921431 +0100
+@@ -0,0 +1,39 @@
++/*
++ *  Atheros AR71xx SoC specific PCI definitions
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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.
++ */
++
++#ifndef __ASM_MACH_AR71XX_PCI_H
++#define __ASM_MACH_AR71XX_PCI_H
++
++struct pci_dev;
++
++struct ar71xx_pci_irq {
++	int	irq;
++	u8	slot;
++	u8	pin;
++};
++
++extern int (*ar71xx_pci_plat_dev_init)(struct pci_dev *dev);
++extern unsigned ar71xx_pci_nr_irqs __initdata;
++extern struct ar71xx_pci_irq *ar71xx_pci_irq_map __initdata;
++
++int ar71xx_pcibios_map_irq(const struct pci_dev *dev,
++			   uint8_t slot, uint8_t pin) __init;
++int ar71xx_pcibios_init(void) __init;
++
++int ar71xx_pci_be_handler(int is_fixup);
++
++int ar724x_pcibios_map_irq(const struct pci_dev *dev,
++			   uint8_t slot, uint8_t pin) __init;
++int ar724x_pcibios_init(void) __init;
++
++int ar71xx_pci_init(unsigned nr_irqs, struct ar71xx_pci_irq *map) __init;
++
++#endif /* __ASM_MACH_AR71XX_PCI_H */
+diff -Nur linux-2.6.33.3.orig/arch/mips/include/asm/mach-ar71xx/platform.h linux-2.6.33.3/arch/mips/include/asm/mach-ar71xx/platform.h
+--- linux-2.6.33.3.orig/arch/mips/include/asm/mach-ar71xx/platform.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/include/asm/mach-ar71xx/platform.h	2009-12-13 20:45:20.611920954 +0100
+@@ -0,0 +1,61 @@
++/*
++ *  Atheros AR71xx SoC specific platform data definitions
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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.
++ */
++
++#ifndef __ASM_MACH_AR71XX_PLATFORM_H
++#define __ASM_MACH_AR71XX_PLATFORM_H
++
++#include <linux/if_ether.h>
++#include <linux/skbuff.h>
++#include <linux/phy.h>
++#include <linux/spi/spi.h>
++
++struct ag71xx_platform_data {
++	phy_interface_t	phy_if_mode;
++	u32		phy_mask;
++	int		speed;
++	int		duplex;
++	u32		reset_bit;
++	u32		mii_if;
++	u8		mac_addr[ETH_ALEN];
++	struct device	*mii_bus_dev;
++
++	u8		has_gbit:1;
++	u8		is_ar91xx:1;
++	u8		is_ar724x:1;
++	u8		has_ar8216:1;
++
++	void		(* ddr_flush)(void);
++	void		(* set_pll)(int speed);
++
++	u32		fifo_cfg1;
++	u32		fifo_cfg2;
++	u32		fifo_cfg3;
++};
++
++struct ag71xx_mdio_platform_data {
++	u32		phy_mask;
++	int		is_ar7240;
++};
++
++struct ar71xx_ehci_platform_data {
++	u8		is_ar91xx;
++};
++
++struct ar71xx_spi_platform_data {
++	unsigned	bus_num;
++	unsigned	num_chipselect;
++	u32		(*get_ioc_base)(u8 chip_select, int cs_high, int is_on);
++};
++
++#define AR71XX_SPI_CS_INACTIVE	0
++#define AR71XX_SPI_CS_ACTIVE	1
++
++#endif /* __ASM_MACH_AR71XX_PLATFORM_H */
+diff -Nur linux-2.6.33.3.orig/arch/mips/include/asm/mach-ar71xx/war.h linux-2.6.33.3/arch/mips/include/asm/mach-ar71xx/war.h
+--- linux-2.6.33.3.orig/arch/mips/include/asm/mach-ar71xx/war.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/include/asm/mach-ar71xx/war.h	2009-12-13 20:45:20.443925666 +0100
+@@ -0,0 +1,25 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
++ */
++#ifndef __ASM_MACH_AR71XX_WAR_H
++#define __ASM_MACH_AR71XX_WAR_H
++
++#define R4600_V1_INDEX_ICACHEOP_WAR	0
++#define R4600_V1_HIT_CACHEOP_WAR	0
++#define R4600_V2_HIT_CACHEOP_WAR	0
++#define R5432_CP0_INTERRUPT_WAR		0
++#define BCM1250_M3_WAR			0
++#define SIBYTE_1956_WAR			0
++#define MIPS4K_ICACHE_REFILL_WAR	0
++#define MIPS_CACHE_SYNC_WAR		0
++#define TX49XX_ICACHE_INDEX_INV_WAR	0
++#define RM9000_CDEX_SMP_WAR		0
++#define ICACHE_REFILLS_WORKAROUND_WAR	0
++#define R10000_LLSC_WAR			0
++#define MIPS34K_MISSED_ITLB_WAR		0
++
++#endif /* __ASM_MACH_AR71XX_WAR_H */
+diff -Nur linux-2.6.33.3.orig/arch/mips/include/asm/mips_machine.h linux-2.6.33.3/arch/mips/include/asm/mips_machine.h
+--- linux-2.6.33.3.orig/arch/mips/include/asm/mips_machine.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/include/asm/mips_machine.h	2010-05-17 19:36:16.051124934 +0200
+@@ -0,0 +1,54 @@
++/*
++ *  Copyright (C) 2008-2009 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.
++ *
++ */
++
++#ifndef __ASM_MIPS_MACHINE_H
++#define __ASM_MIPS_MACHINE_H
++
++#include <linux/init.h>
++#include <linux/list.h>
++
++#include <asm/bootinfo.h>
++
++struct mips_machine {
++	unsigned long		mach_type;
++	char			*mach_id;
++	char			*mach_name;
++	void			(*mach_setup)(void);
++	struct list_head	list;
++};
++
++void mips_machine_register(struct mips_machine *) __init;
++void mips_machine_setup(void) __init;
++int  mips_machtype_setup(char *id) __init;
++void mips_machine_set_name(char *name) __init;
++
++extern char *mips_machine_name;
++
++#define MIPS_MACHINE(_type, _id, _name, _setup) 		\
++static const char machine_name_##_type[] __initconst		\
++			__aligned(1) = _name;			\
++static const char machine_id_##_type[] __initconst		\
++			__aligned(1) = _id;			\
++static struct mips_machine machine_##_type __initdata =		\
++{								\
++	.mach_type	= _type,				\
++	.mach_id	= (char *) machine_id_##_type,		\
++	.mach_name	= (char *) machine_name_##_type,	\
++	.mach_setup	= _setup,				\
++};								\
++								\
++static int __init register_machine_##_type(void)		\
++{								\
++	mips_machine_register(&machine_##_type);		\
++	return 0;						\
++}								\
++								\
++pure_initcall(register_machine_##_type)
++
++#endif /* __ASM_MIPS_MACHINE_H */
+diff -Nur linux-2.6.33.3.orig/arch/mips/include/asm/time.h linux-2.6.33.3/arch/mips/include/asm/time.h
+--- linux-2.6.33.3.orig/arch/mips/include/asm/time.h	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/arch/mips/include/asm/time.h	2010-05-18 19:33:35.811338021 +0200
+@@ -52,6 +52,7 @@
+  */
+ #ifdef CONFIG_CEVT_R4K_LIB
+ extern unsigned int __weak get_c0_compare_int(void);
++extern unsigned int __weak get_c0_compare_irq(void);
+ extern int r4k_clockevent_init(void);
+ #endif
+ 
+diff -Nur linux-2.6.33.3.orig/arch/mips/Kconfig linux-2.6.33.3/arch/mips/Kconfig
+--- linux-2.6.33.3.orig/arch/mips/Kconfig	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/arch/mips/Kconfig	2010-05-20 16:39:56.083849540 +0200
+@@ -48,6 +48,23 @@
+ 	  Support for the Texas Instruments AR7 System-on-a-Chip
+ 	  family: TNETD7100, 7200 and 7300.
+ 
++config ATHEROS_AR71XX
++	bool "Atheros AR71xx based boards"
++	select CEVT_R4K
++	select CSRC_R4K
++	select DMA_NONCOHERENT
++	select HW_HAS_PCI
++	select IRQ_CPU
++	select ARCH_REQUIRE_GPIOLIB
++	select SYS_HAS_CPU_MIPS32_R1
++	select SYS_HAS_CPU_MIPS32_R2
++	select SYS_SUPPORTS_32BIT_KERNEL
++	select SYS_SUPPORTS_BIG_ENDIAN
++	select SYS_HAS_EARLY_PRINTK
++	select MIPS_MACHINE
++	help
++	  Support for Atheros AR71xx based boards.
++
+ config BCM47XX
+ 	bool "BCM47XX based boards"
+ 	select CEVT_R4K
+@@ -682,6 +699,7 @@
+ endchoice
+ 
+ source "arch/mips/alchemy/Kconfig"
++source "arch/mips/ar71xx/Kconfig"
+ source "arch/mips/bcm63xx/Kconfig"
+ source "arch/mips/jazz/Kconfig"
+ source "arch/mips/lasat/Kconfig"
+@@ -848,9 +866,15 @@
+ config MIPS_DISABLE_OBSOLETE_IDE
+ 	bool
+ 
++config MYLOADER
++	bool
++
+ config SYNC_R4K
+ 	bool
+ 
++config MIPS_MACHINE
++	def_bool n
++
+ config NO_IOPORT
+ 	def_bool n
+ 
+diff -Nur linux-2.6.33.3.orig/arch/mips/kernel/Makefile linux-2.6.33.3/arch/mips/kernel/Makefile
+--- linux-2.6.33.3.orig/arch/mips/kernel/Makefile	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/arch/mips/kernel/Makefile	2010-05-17 18:51:38.331117283 +0200
+@@ -93,6 +93,7 @@
+ 
+ obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
+ obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
++obj-$(CONFIG_MIPS_MACHINE)	+= mips_machine.o
+ 
+ CFLAGS_cpu-bugs64.o	= $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi)
+ 
+diff -Nur linux-2.6.33.3.orig/arch/mips/kernel/mips_machine.c linux-2.6.33.3/arch/mips/kernel/mips_machine.c
+--- linux-2.6.33.3.orig/arch/mips/kernel/mips_machine.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/kernel/mips_machine.c	2010-05-17 19:36:16.035122334 +0200
+@@ -0,0 +1,120 @@
++/*
++ *  Copyright (C) 2008-2009 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/mm.h>
++#include <linux/string.h>
++
++#include <asm/mips_machine.h>
++
++static struct list_head mips_machines __initdata =
++		LIST_HEAD_INIT(mips_machines);
++static char *mips_machid __initdata;
++
++char *mips_machine_name = "Unknown";
++
++static struct mips_machine * __init mips_machine_find(unsigned long machtype)
++{
++	struct list_head *this;
++
++	list_for_each(this, &mips_machines) {
++		struct mips_machine *mach;
++
++		mach = list_entry(this, struct mips_machine, list);
++		if (mach->mach_type == machtype)
++			return mach;
++	}
++
++	return NULL;
++}
++
++void __init mips_machine_register(struct mips_machine *mach)
++{
++	list_add_tail(&mach->list, &mips_machines);
++}
++
++void __init mips_machine_set_name(char *name)
++{
++	unsigned int len;
++	char *p;
++
++	if (name == NULL)
++		return;
++
++	len = strlen(name);
++	p = kmalloc(len + 1, GFP_KERNEL);
++	if (p) {
++		strncpy(p, name, len);
++		p[len] = '\0';
++		mips_machine_name = p;
++	} else {
++		printk(KERN_WARNING "MIPS: no memory for machine_name\n");
++	}
++}
++
++void __init mips_machine_setup(void)
++{
++	struct mips_machine *mach;
++
++	mach = mips_machine_find(mips_machtype);
++	if (!mach) {
++		printk(KERN_WARNING "MIPS: no machine registered for "
++			"machtype %lu\n", mips_machtype);
++		return;
++	}
++
++	mips_machine_set_name(mach->mach_name);
++	printk(KERN_NOTICE "MIPS: machine is %s\n", mips_machine_name);
++
++	if (mach->mach_setup)
++		mach->mach_setup();
++}
++
++int __init mips_machtype_setup(char *id)
++{
++	if (mips_machid == NULL)
++		mips_machid = id;
++
++	return 1;
++}
++
++__setup("machtype=", mips_machtype_setup);
++
++static int __init mips_machtype_init(void)
++{
++	struct list_head *this;
++	struct mips_machine *mach;
++
++	if (mips_machid == NULL)
++		return 0;
++
++	list_for_each(this, &mips_machines) {
++		mach = list_entry(this, struct mips_machine, list);
++		if (mach->mach_id == NULL)
++			continue;
++
++		if (strcmp(mach->mach_id, mips_machid) == 0) {
++			mips_machtype = mach->mach_type;
++			return 0;
++		}
++	}
++
++	printk(KERN_WARNING
++	       "MIPS: no machine found for id: '%s', registered machines:\n",
++	       mips_machid);
++	printk(KERN_WARNING "%32s %s\n", "id", "name");
++
++	list_for_each(this, &mips_machines) {
++		mach = list_entry(this, struct mips_machine, list);
++		printk(KERN_WARNING "%32s %s\n",
++		       mach->mach_id ? mach->mach_id : "", mach->mach_name);
++	}
++
++	return 0;
++}
++
++core_initcall(mips_machtype_init);
+diff -Nur linux-2.6.33.3.orig/arch/mips/kernel/proc.c linux-2.6.33.3/arch/mips/kernel/proc.c
+--- linux-2.6.33.3.orig/arch/mips/kernel/proc.c	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/arch/mips/kernel/proc.c	2010-05-17 18:51:38.335115558 +0200
+@@ -12,6 +12,7 @@
+ #include <asm/cpu-features.h>
+ #include <asm/mipsregs.h>
+ #include <asm/processor.h>
++#include <asm/mips_machine.h>
+ 
+ unsigned int vced_count, vcei_count;
+ 
+@@ -31,8 +32,12 @@
+ 	/*
+ 	 * For the first processor also print the system type
+ 	 */
+-	if (n == 0)
++	if (n == 0) {
+ 		seq_printf(m, "system type\t\t: %s\n", get_system_type());
++#ifdef CONFIG_MIPS_MACHINE
++		seq_printf(m, "machine\t\t\t: %s\n", mips_machine_name);
++#endif
++	}
+ 
+ 	seq_printf(m, "processor\t\t: %ld\n", n);
+ 	sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n",
+diff -Nur linux-2.6.33.3.orig/arch/mips/kernel/traps.c linux-2.6.33.3/arch/mips/kernel/traps.c
+--- linux-2.6.33.3.orig/arch/mips/kernel/traps.c	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/arch/mips/kernel/traps.c	2010-05-18 19:33:35.691116007 +0200
+@@ -50,6 +50,7 @@
+ #include <asm/types.h>
+ #include <asm/stacktrace.h>
+ #include <asm/irq.h>
++#include <asm/time.h>
+ 
+ extern void check_wait(void);
+ extern asmlinkage void r4k_wait(void);
+@@ -1496,6 +1497,8 @@
+ 	if (cpu_has_mips_r2) {
+ 		cp0_compare_irq_shift = CAUSEB_TI - CAUSEB_IP;
+ 		cp0_compare_irq = (read_c0_intctl() >> INTCTLB_IPTI) & 7;
++		if (get_c0_compare_irq)
++			cp0_compare_irq = get_c0_compare_irq();
+ 		cp0_perfcount_irq = (read_c0_intctl() >> INTCTLB_IPPCI) & 7;
+ 		if (cp0_perfcount_irq == cp0_compare_irq)
+ 			cp0_perfcount_irq = -1;
+diff -Nur linux-2.6.33.3.orig/arch/mips/Makefile linux-2.6.33.3/arch/mips/Makefile
+--- linux-2.6.33.3.orig/arch/mips/Makefile	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/arch/mips/Makefile	2010-05-20 17:40:10.159860905 +0200
+@@ -166,6 +166,13 @@
+ cflags-$(CONFIG_CPU_CAVIUM_OCTEON) += -Wa,-march=octeon
+ endif
+ 
++#
++# Atheros AR71xx
++#
++core-$(CONFIG_ATHEROS_AR71XX)	+= arch/mips/ar71xx/
++cflags-$(CONFIG_ATHEROS_AR71XX)	+= -I$(srctree)/arch/mips/include/asm/mach-ar71xx
++load-$(CONFIG_ATHEROS_AR71XX)	+= 0xffffffff80060000
++
+ cflags-$(CONFIG_CPU_R4000_WORKAROUNDS)	+= $(call cc-option,-mfix-r4000,)
+ cflags-$(CONFIG_CPU_R4400_WORKAROUNDS)	+= $(call cc-option,-mfix-r4400,)
+ cflags-$(CONFIG_CPU_DADDI_WORKAROUNDS)	+= $(call cc-option,-mno-daddi,)
+diff -Nur linux-2.6.33.3.orig/arch/mips/pci/Makefile linux-2.6.33.3/arch/mips/pci/Makefile
+--- linux-2.6.33.3.orig/arch/mips/pci/Makefile	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/arch/mips/pci/Makefile	2010-05-17 16:28:23.988293766 +0200
+@@ -18,6 +18,7 @@
+ obj-$(CONFIG_BCM47XX)		+= pci-bcm47xx.o
+ obj-$(CONFIG_BCM63XX)		+= pci-bcm63xx.o fixup-bcm63xx.o \
+ 					ops-bcm63xx.o
++obj-$(CONFIG_ATHEROS_AR71XX)	+= pci-ar71xx.o pci-ar724x.o
+ 
+ #
+ # These are still pretty much in the old state, watch, go blind.
+diff -Nur linux-2.6.33.3.orig/arch/mips/pci/pci-ar71xx.c linux-2.6.33.3/arch/mips/pci/pci-ar71xx.c
+--- linux-2.6.33.3.orig/arch/mips/pci/pci-ar71xx.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/pci/pci-ar71xx.c	2010-03-23 20:31:05.824706267 +0100
+@@ -0,0 +1,409 @@
++/*
++ *  Atheros AR71xx PCI host controller driver
++ *
++ *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ *  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/resource.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++#include <linux/bitops.h>
++#include <linux/pci.h>
++#include <linux/pci_regs.h>
++#include <linux/interrupt.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/pci.h>
++
++#undef DEBUG
++#ifdef DEBUG
++#define DBG(fmt, args...)	printk(KERN_DEBUG fmt, ## args)
++#else
++#define DBG(fmt, args...)
++#endif
++
++#define AR71XX_PCI_DELAY	100 /* msecs */
++
++#if 0
++#define PCI_IDSEL_BASE	PCI_IDSEL_ADL_START
++#else
++#define PCI_IDSEL_BASE	0
++#endif
++
++static void __iomem *ar71xx_pcicfg_base;
++static DEFINE_SPINLOCK(ar71xx_pci_lock);
++static int ar71xx_pci_fixup_enable;
++
++static inline void ar71xx_pci_delay(void)
++{
++	mdelay(AR71XX_PCI_DELAY);
++}
++
++/* Byte lane enable bits */
++static u8 ble_table[4][4] = {
++	{0x0, 0xf, 0xf, 0xf},
++	{0xe, 0xd, 0xb, 0x7},
++	{0xc, 0xf, 0x3, 0xf},
++	{0xf, 0xf, 0xf, 0xf},
++};
++
++static inline u32 ar71xx_pci_get_ble(int where, int size, int local)
++{
++	u32 t;
++
++	t = ble_table[size & 3][where & 3];
++	BUG_ON(t == 0xf);
++	t <<= (local) ? 20 : 4;
++	return t;
++}
++
++static inline u32 ar71xx_pci_bus_addr(struct pci_bus *bus, unsigned int devfn,
++					int where)
++{
++	u32 ret;
++
++	if (!bus->number) {
++		/* type 0 */
++		ret = (1 << (PCI_IDSEL_BASE + PCI_SLOT(devfn)))
++		    | (PCI_FUNC(devfn) << 8) | (where & ~3);
++	} else {
++		/* type 1 */
++		ret = (bus->number << 16) | (PCI_SLOT(devfn) << 11)
++		    | (PCI_FUNC(devfn) << 8) | (where & ~3) | 1;
++	}
++
++	return ret;
++}
++
++int ar71xx_pci_be_handler(int is_fixup)
++{
++	void __iomem *base = ar71xx_pcicfg_base;
++	u32 pci_err;
++	u32 ahb_err;
++
++	pci_err = __raw_readl(base + PCI_REG_PCI_ERR) & 3;
++	if (pci_err) {
++		if (!is_fixup)
++			printk(KERN_ALERT "PCI error %d at PCI addr 0x%x\n",
++				pci_err,
++				__raw_readl(base + PCI_REG_PCI_ERR_ADDR));
++
++		__raw_writel(pci_err, base + PCI_REG_PCI_ERR);
++	}
++
++	ahb_err = __raw_readl(base + PCI_REG_AHB_ERR) & 1;
++	if (ahb_err) {
++		if (!is_fixup)
++			printk(KERN_ALERT "AHB error at AHB address 0x%x\n",
++				__raw_readl(base + PCI_REG_AHB_ERR_ADDR));
++
++		__raw_writel(ahb_err, base + PCI_REG_AHB_ERR);
++	}
++
++	return ((ahb_err | pci_err) ? 1 : 0);
++}
++
++static inline int ar71xx_pci_set_cfgaddr(struct pci_bus *bus,
++			unsigned int devfn, int where, int size, u32 cmd)
++{
++	void __iomem *base = ar71xx_pcicfg_base;
++	u32 addr;
++
++	addr = ar71xx_pci_bus_addr(bus, devfn, where);
++
++	DBG("PCI: set cfgaddr: %02x:%02x.%01x/%02x:%01d, addr=%08x\n",
++		bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn),
++		where, size, addr);
++
++	__raw_writel(addr, base + PCI_REG_CFG_AD);
++	__raw_writel(cmd | ar71xx_pci_get_ble(where, size, 0),
++		     base + PCI_REG_CFG_CBE);
++
++	return ar71xx_pci_be_handler(1);
++}
++
++static int ar71xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
++				  int where, int size, u32 *value)
++{
++	void __iomem *base = ar71xx_pcicfg_base;
++	static u32 mask[8] = {0, 0xff, 0xffff, 0, 0xffffffff, 0, 0, 0};
++	unsigned long flags;
++	u32 data;
++	int ret;
++
++	ret = PCIBIOS_SUCCESSFUL;
++
++	DBG("PCI: read config: %02x:%02x.%01x/%02x:%01d\n", bus->number,
++			PCI_SLOT(devfn), PCI_FUNC(devfn), where, size);
++
++	spin_lock_irqsave(&ar71xx_pci_lock, flags);
++
++	if (bus->number == 0 && devfn == 0) {
++		u32 t;
++
++		t = PCI_CRP_CMD_READ | (where & ~3);
++
++		__raw_writel(t, base + PCI_REG_CRP_AD_CBE);
++		data = __raw_readl(base + PCI_REG_CRP_RDDATA);
++
++		DBG("PCI: rd local cfg, ad_cbe:%08x, data:%08x\n", t, data);
++
++	} else {
++		int err;
++
++		err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size,
++						PCI_CFG_CMD_READ);
++
++		if (err == 0) {
++			data = __raw_readl(base + PCI_REG_CFG_RDDATA);
++		} else {
++			ret = PCIBIOS_DEVICE_NOT_FOUND;
++			data = ~0;
++		}
++	}
++
++	spin_unlock_irqrestore(&ar71xx_pci_lock, flags);
++
++	DBG("PCI: read config: data=%08x raw=%08x\n",
++		(data >> (8 * (where & 3))) & mask[size & 7], data);
++
++	*value = (data >> (8 * (where & 3))) & mask[size & 7];
++
++	return ret;
++}
++
++static int ar71xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
++				   int where, int size, u32 value)
++{
++	void __iomem *base = ar71xx_pcicfg_base;
++	unsigned long flags;
++	int ret;
++
++	DBG("PCI: write config: %02x:%02x.%01x/%02x:%01d value=%08x\n",
++		bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn),
++		where, size, value);
++
++	value = value << (8 * (where & 3));
++	ret = PCIBIOS_SUCCESSFUL;
++
++	spin_lock_irqsave(&ar71xx_pci_lock, flags);
++	if (bus->number == 0 && devfn == 0) {
++		u32 t;
++
++		t = PCI_CRP_CMD_WRITE | (where & ~3);
++		t |= ar71xx_pci_get_ble(where, size, 1);
++
++		DBG("PCI: wr local cfg, ad_cbe:%08x, value:%08x\n", t, value);
++
++		__raw_writel(t, base + PCI_REG_CRP_AD_CBE);
++		__raw_writel(value, base + PCI_REG_CRP_WRDATA);
++	} else {
++		int err;
++
++		err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size,
++						PCI_CFG_CMD_WRITE);
++
++		if (err == 0)
++			__raw_writel(value, base + PCI_REG_CFG_WRDATA);
++		else
++			ret = PCIBIOS_DEVICE_NOT_FOUND;
++	}
++	spin_unlock_irqrestore(&ar71xx_pci_lock, flags);
++
++	return ret;
++}
++
++static void ar71xx_pci_fixup(struct pci_dev *dev)
++{
++	u32 t;
++
++	if (!ar71xx_pci_fixup_enable)
++		return;
++
++	if (dev->bus->number != 0 || dev->devfn != 0)
++		return;
++
++	DBG("PCI: fixup host controller %s (%04x:%04x)\n", pci_name(dev),
++		dev->vendor, dev->device);
++
++	/* setup COMMAND register */
++	t = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
++	  | PCI_COMMAND_PARITY | PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK;
++
++	pci_write_config_word(dev, PCI_COMMAND, t);
++}
++DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ar71xx_pci_fixup);
++
++int __init ar71xx_pcibios_map_irq(const struct pci_dev *dev, uint8_t slot,
++				  uint8_t pin)
++{
++	int irq = -1;
++	int i;
++
++	slot -= PCI_IDSEL_ADL_START - PCI_IDSEL_BASE;
++
++	for (i = 0; i < ar71xx_pci_nr_irqs; i++) {
++		struct ar71xx_pci_irq *entry;
++
++		entry = &ar71xx_pci_irq_map[i];
++		if (entry->slot == slot && entry->pin == pin) {
++			irq = entry->irq;
++			break;
++		}
++	}
++
++	if (irq < 0) {
++		printk(KERN_ALERT "PCI: no irq found for pin%u@%s\n",
++				pin, pci_name((struct pci_dev *)dev));
++	} else {
++		printk(KERN_INFO "PCI: mapping irq %d to pin%u@%s\n",
++				irq, pin, pci_name((struct pci_dev *)dev));
++	}
++
++	return irq;
++}
++
++static struct pci_ops ar71xx_pci_ops = {
++	.read	= ar71xx_pci_read_config,
++	.write	= ar71xx_pci_write_config,
++};
++
++static struct resource ar71xx_pci_io_resource = {
++	.name		= "PCI IO space",
++	.start		= 0,
++	.end		= 0,
++	.flags		= IORESOURCE_IO,
++};
++
++static struct resource ar71xx_pci_mem_resource = {
++	.name		= "PCI memory space",
++	.start		= AR71XX_PCI_MEM_BASE,
++	.end		= AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE - 1,
++	.flags		= IORESOURCE_MEM
++};
++
++static struct pci_controller ar71xx_pci_controller = {
++	.pci_ops	= &ar71xx_pci_ops,
++	.mem_resource	= &ar71xx_pci_mem_resource,
++	.io_resource	= &ar71xx_pci_io_resource,
++};
++
++static void ar71xx_pci_irq_handler(unsigned int irq, struct irq_desc *desc)
++{
++	void __iomem *base = ar71xx_reset_base;
++	u32 pending;
++
++	pending = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_STATUS) &
++		  __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
++
++	if (pending & PCI_INT_DEV0)
++		generic_handle_irq(AR71XX_PCI_IRQ_DEV0);
++
++	else if (pending & PCI_INT_DEV1)
++		generic_handle_irq(AR71XX_PCI_IRQ_DEV1);
++
++	else if (pending & PCI_INT_DEV2)
++		generic_handle_irq(AR71XX_PCI_IRQ_DEV2);
++
++	else if (pending & PCI_INT_CORE)
++		generic_handle_irq(AR71XX_PCI_IRQ_CORE);
++
++	else
++		spurious_interrupt();
++}
++
++static void ar71xx_pci_irq_unmask(unsigned int irq)
++{
++	void __iomem *base = ar71xx_reset_base;
++	u32 t;
++
++	irq -= AR71XX_PCI_IRQ_BASE;
++
++	t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
++	__raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE);
++
++	/* flush write */
++	(void) __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
++}
++
++static void ar71xx_pci_irq_mask(unsigned int irq)
++{
++	void __iomem *base = ar71xx_reset_base;
++	u32 t;
++
++	irq -= AR71XX_PCI_IRQ_BASE;
++
++	t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
++	__raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE);
++
++	/* flush write */
++	(void) __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
++}
++
++static struct irq_chip ar71xx_pci_irq_chip = {
++	.name		= "AR71XX PCI ",
++	.mask		= ar71xx_pci_irq_mask,
++	.unmask		= ar71xx_pci_irq_unmask,
++	.mask_ack	= ar71xx_pci_irq_mask,
++};
++
++static void __init ar71xx_pci_irq_init(void)
++{
++	void __iomem *base = ar71xx_reset_base;
++	int i;
++
++	__raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_ENABLE);
++	__raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_STATUS);
++
++	for (i = AR71XX_PCI_IRQ_BASE;
++	     i < AR71XX_PCI_IRQ_BASE + AR71XX_PCI_IRQ_COUNT; i++) {
++		irq_desc[i].status = IRQ_DISABLED;
++		set_irq_chip_and_handler(i, &ar71xx_pci_irq_chip,
++					 handle_level_irq);
++	}
++
++	set_irq_chained_handler(AR71XX_CPU_IRQ_IP2, ar71xx_pci_irq_handler);
++}
++
++int __init ar71xx_pcibios_init(void)
++{
++	void __iomem *ddr_base = ar71xx_ddr_base;
++
++	ar71xx_device_stop(RESET_MODULE_PCI_BUS | RESET_MODULE_PCI_CORE);
++	ar71xx_pci_delay();
++
++	ar71xx_device_start(RESET_MODULE_PCI_BUS | RESET_MODULE_PCI_CORE);
++	ar71xx_pci_delay();
++
++	ar71xx_pcicfg_base = ioremap_nocache(AR71XX_PCI_CFG_BASE,
++						AR71XX_PCI_CFG_SIZE);
++	if (ar71xx_pcicfg_base == NULL)
++		return -ENOMEM;
++
++	__raw_writel(PCI_WIN0_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN0);
++	__raw_writel(PCI_WIN1_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN1);
++	__raw_writel(PCI_WIN2_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN2);
++	__raw_writel(PCI_WIN3_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN3);
++	__raw_writel(PCI_WIN4_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN4);
++	__raw_writel(PCI_WIN5_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN5);
++	__raw_writel(PCI_WIN6_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN6);
++	__raw_writel(PCI_WIN7_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN7);
++
++	ar71xx_pci_delay();
++
++	/* clear bus errors */
++	(void)ar71xx_pci_be_handler(1);
++
++	ar71xx_pci_fixup_enable = 1;
++	ar71xx_pci_irq_init();
++	register_pci_controller(&ar71xx_pci_controller);
++
++	return 0;
++}
+diff -Nur linux-2.6.33.3.orig/arch/mips/pci/pci-ar724x.c linux-2.6.33.3/arch/mips/pci/pci-ar724x.c
+--- linux-2.6.33.3.orig/arch/mips/pci/pci-ar724x.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/arch/mips/pci/pci-ar724x.c	2010-04-02 11:07:52.002954061 +0200
+@@ -0,0 +1,395 @@
++/*
++ *  Atheros AR724x PCI host controller driver
++ *
++ *  Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ *  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/resource.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++#include <linux/bitops.h>
++#include <linux/pci.h>
++#include <linux/pci_regs.h>
++#include <linux/interrupt.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/pci.h>
++
++#undef DEBUG
++#ifdef DEBUG
++#define DBG(fmt, args...)	printk(KERN_INFO fmt, ## args)
++#else
++#define DBG(fmt, args...)
++#endif
++
++static void __iomem *ar724x_pci_localcfg_base;
++static void __iomem *ar724x_pci_devcfg_base;
++static void __iomem *ar724x_pci_ctrl_base;
++static int ar724x_pci_fixup_enable;
++
++static DEFINE_SPINLOCK(ar724x_pci_lock);
++
++static void ar724x_pci_read(void __iomem *base, int where, int size, u32 *value)
++{
++	unsigned long flags;
++	u32 data;
++
++	spin_lock_irqsave(&ar724x_pci_lock, flags);
++	data = __raw_readl(base + (where & ~3));
++
++	switch (size) {
++	case 1:
++		if (where & 1)
++			data >>= 8;
++		if (where & 2)
++			data >>= 16;
++		data &= 0xFF;
++		break;
++	case 2:
++		if (where & 2)
++			data >>= 16;
++		data &= 0xFFFF;
++		break;
++	}
++
++	*value = data;
++	spin_unlock_irqrestore(&ar724x_pci_lock, flags);
++}
++
++static void ar724x_pci_write(void __iomem *base, int where, int size, u32 value)
++{
++	unsigned long flags;
++	u32 data;
++	int s;
++
++	spin_lock_irqsave(&ar724x_pci_lock, flags);
++	data = __raw_readl(base + (where & ~3));
++
++	switch (size) {
++	case 1:
++		s = ((where & 3) << 3);
++		data &= ~(0xFF << s);
++		data |= ((value & 0xFF) << s);
++		break;
++	case 2:
++		s = ((where & 2) << 3);
++		data &= ~(0xFFFF << s);
++		data |= ((value & 0xFFFF) << s);
++		break;
++	case 4:
++		data = value;
++		break;
++	}
++
++	__raw_writel(data, base + (where & ~3));
++	/* flush write */
++	(void)__raw_readl(base + (where & ~3));
++	spin_unlock_irqrestore(&ar724x_pci_lock, flags);
++}
++
++static int ar724x_pci_read_config(struct pci_bus *bus, unsigned int devfn,
++				  int where, int size, u32 *value)
++{
++
++	if (bus->number != 0 || devfn != 0)
++		return PCIBIOS_DEVICE_NOT_FOUND;
++
++	ar724x_pci_read(ar724x_pci_devcfg_base, where, size, value);
++
++	DBG("PCI: read config: %02x:%02x.%01x/%02x:%01d, value=%08x\n",
++			bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn),
++			where, size, *value);
++
++	/*
++	 * WAR for BAR issue - We are unable to access the PCI device space
++	 * if we set the BAR with proper base address
++	 */
++	if ((where == 0x10) && (size == 4)) {
++		if (ar71xx_soc == AR71XX_SOC_AR7240)
++			ar724x_pci_write(ar724x_pci_devcfg_base, where, size, 0xffff);
++		else
++			ar724x_pci_write(ar724x_pci_devcfg_base, where, size, 0x1000ffff);
++	}
++
++	return PCIBIOS_SUCCESSFUL;
++}
++
++static int ar724x_pci_write_config(struct pci_bus *bus, unsigned int devfn,
++				   int where, int size, u32 value)
++{
++	if (bus->number != 0 || devfn != 0)
++		return PCIBIOS_DEVICE_NOT_FOUND;
++
++	DBG("PCI: write config: %02x:%02x.%01x/%02x:%01d, value=%08x\n",
++		bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn),
++		where, size, value);
++
++	ar724x_pci_write(ar724x_pci_devcfg_base, where, size, value);
++
++	return PCIBIOS_SUCCESSFUL;
++}
++
++static void ar724x_pci_fixup(struct pci_dev *dev)
++{
++	u16 cmd;
++
++	if (!ar724x_pci_fixup_enable)
++		return;
++
++	if (dev->bus->number != 0 || dev->devfn != 0)
++		return;
++
++	/* setup COMMAND register */
++	pci_read_config_word(dev, PCI_COMMAND, &cmd);
++	cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
++	       PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR |
++	       PCI_COMMAND_FAST_BACK;
++
++	pci_write_config_word(dev, PCI_COMMAND, cmd);
++}
++DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ar724x_pci_fixup);
++
++int __init ar724x_pcibios_map_irq(const struct pci_dev *dev, uint8_t slot,
++				  uint8_t pin)
++{
++	int irq = -1;
++	int i;
++
++	for (i = 0; i < ar71xx_pci_nr_irqs; i++) {
++		struct ar71xx_pci_irq *entry;
++		entry = &ar71xx_pci_irq_map[i];
++
++		if (entry->slot == slot && entry->pin == pin) {
++			irq = entry->irq;
++			break;
++		}
++	}
++
++	if (irq < 0)
++		printk(KERN_ALERT "PCI: no irq found for pin%u@%s\n",
++				pin, pci_name((struct pci_dev *)dev));
++	else
++		printk(KERN_INFO "PCI: mapping irq %d to pin%u@%s\n",
++				irq, pin, pci_name((struct pci_dev *)dev));
++
++	return irq;
++}
++
++static struct pci_ops ar724x_pci_ops = {
++	.read	= ar724x_pci_read_config,
++	.write	= ar724x_pci_write_config,
++};
++
++static struct resource ar724x_pci_io_resource = {
++	.name		= "PCI IO space",
++	.start		= 0,
++	.end		= 0,
++	.flags		= IORESOURCE_IO,
++};
++
++static struct resource ar724x_pci_mem_resource = {
++	.name		= "PCI memory space",
++	.start		= AR71XX_PCI_MEM_BASE,
++	.end		= AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE - 1,
++	.flags		= IORESOURCE_MEM
++};
++
++static struct pci_controller ar724x_pci_controller = {
++	.pci_ops	= &ar724x_pci_ops,
++	.mem_resource	= &ar724x_pci_mem_resource,
++	.io_resource	= &ar724x_pci_io_resource,
++};
++
++static void __init ar724x_pci_reset(void)
++{
++	ar71xx_device_stop(AR724X_RESET_PCIE);
++	ar71xx_device_stop(AR724X_RESET_PCIE_PHY);
++	ar71xx_device_stop(AR724X_RESET_PCIE_PHY_SERIAL);
++	udelay(100);
++
++	ar71xx_device_start(AR724X_RESET_PCIE_PHY_SERIAL);
++	udelay(100);
++	ar71xx_device_start(AR724X_RESET_PCIE_PHY);
++	ar71xx_device_start(AR724X_RESET_PCIE);
++}
++
++static int __init ar724x_pci_setup(void)
++{
++	void __iomem *base = ar724x_pci_ctrl_base;
++	u32 t;
++
++	/* setup COMMAND register */
++	t = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE |
++	    PCI_COMMAND_PARITY|PCI_COMMAND_SERR|PCI_COMMAND_FAST_BACK;
++
++	ar724x_pci_write(ar724x_pci_localcfg_base, PCI_COMMAND, 4, t);
++	ar724x_pci_write(ar724x_pci_localcfg_base, 0x20, 4, 0x1ff01000);
++	ar724x_pci_write(ar724x_pci_localcfg_base, 0x24, 4, 0x1ff01000);
++
++	t = __raw_readl(base + AR724X_PCI_REG_RESET);
++	if (t != 0x7) {
++		udelay(100000);
++		__raw_writel(0, base + AR724X_PCI_REG_RESET);
++		udelay(100);
++		__raw_writel(4, base + AR724X_PCI_REG_RESET);
++		udelay(100000);
++	}
++
++	if (ar71xx_soc == AR71XX_SOC_AR7240)
++		t = AR724X_PCI_APP_LTSSM_ENABLE;
++	else
++		t = 0x1ffc1;
++	__raw_writel(t, base + AR724X_PCI_REG_APP);
++	/* flush write */
++	(void) __raw_readl(base + AR724X_PCI_REG_APP);
++	udelay(1000);
++
++	t = __raw_readl(base + AR724X_PCI_REG_RESET);
++	if ((t & AR724X_PCI_RESET_LINK_UP) == 0x0) {
++		printk(KERN_WARNING "PCI: no PCIe module found\n");
++		return -ENODEV;
++	}
++
++	if (ar71xx_soc == AR71XX_SOC_AR7241 || ar71xx_soc == AR71XX_SOC_AR7242) {
++		t = __raw_readl(base + AR724X_PCI_REG_APP);
++		t |= BIT(16);
++		__raw_writel(t, base + AR724X_PCI_REG_APP);
++	}
++
++	return 0;
++}
++
++static void ar724x_pci_irq_handler(unsigned int irq, struct irq_desc *desc)
++{
++	void __iomem *base = ar724x_pci_ctrl_base;
++	u32 pending;
++
++	pending = __raw_readl(base + AR724X_PCI_REG_INT_STATUS) &
++		  __raw_readl(base + AR724X_PCI_REG_INT_MASK);
++
++	if (pending & AR724X_PCI_INT_DEV0)
++		generic_handle_irq(AR71XX_PCI_IRQ_DEV0);
++
++	else
++		spurious_interrupt();
++}
++
++static void ar724x_pci_irq_unmask(unsigned int irq)
++{
++	void __iomem *base = ar724x_pci_ctrl_base;
++	u32 t;
++
++	switch (irq) {
++	case AR71XX_PCI_IRQ_DEV0:
++		irq -= AR71XX_PCI_IRQ_BASE;
++
++		t = __raw_readl(base + AR724X_PCI_REG_INT_MASK);
++		__raw_writel(t | AR724X_PCI_INT_DEV0,
++			     base + AR724X_PCI_REG_INT_MASK);
++		/* flush write */
++		(void) __raw_readl(base + AR724X_PCI_REG_INT_MASK);
++	}
++}
++
++static void ar724x_pci_irq_mask(unsigned int irq)
++{
++	void __iomem *base = ar724x_pci_ctrl_base;
++	u32 t;
++
++	switch (irq) {
++	case AR71XX_PCI_IRQ_DEV0:
++		irq -= AR71XX_PCI_IRQ_BASE;
++
++		t = __raw_readl(base + AR724X_PCI_REG_INT_MASK);
++		__raw_writel(t & ~AR724X_PCI_INT_DEV0,
++			     base + AR724X_PCI_REG_INT_MASK);
++
++		/* flush write */
++		(void) __raw_readl(base + AR724X_PCI_REG_INT_MASK);
++
++		t = __raw_readl(base + AR724X_PCI_REG_INT_STATUS);
++		__raw_writel(t | AR724X_PCI_INT_DEV0,
++			     base + AR724X_PCI_REG_INT_STATUS);
++
++		/* flush write */
++		(void) __raw_readl(base + AR724X_PCI_REG_INT_STATUS);
++	}
++}
++
++static struct irq_chip ar724x_pci_irq_chip = {
++	.name		= "AR724X PCI ",
++	.mask		= ar724x_pci_irq_mask,
++	.unmask		= ar724x_pci_irq_unmask,
++	.mask_ack	= ar724x_pci_irq_mask,
++};
++
++static void __init ar724x_pci_irq_init(void)
++{
++	void __iomem *base = ar724x_pci_ctrl_base;
++	u32 t;
++	int i;
++
++	t = ar71xx_reset_rr(AR724X_RESET_REG_RESET_MODULE);
++	if (t & (AR724X_RESET_PCIE | AR724X_RESET_PCIE_PHY |
++		 AR724X_RESET_PCIE_PHY_SERIAL)) {
++		return;
++	}
++
++	__raw_writel(0, base + AR724X_PCI_REG_INT_MASK);
++	__raw_writel(0, base + AR724X_PCI_REG_INT_STATUS);
++
++	for (i = AR71XX_PCI_IRQ_BASE;
++	     i < AR71XX_PCI_IRQ_BASE + AR71XX_PCI_IRQ_COUNT; i++) {
++		irq_desc[i].status = IRQ_DISABLED;
++		set_irq_chip_and_handler(i, &ar724x_pci_irq_chip,
++					 handle_level_irq);
++	}
++
++	set_irq_chained_handler(AR71XX_CPU_IRQ_IP2, ar724x_pci_irq_handler);
++}
++
++int __init ar724x_pcibios_init(void)
++{
++	int ret = -ENOMEM;
++
++	ar724x_pci_localcfg_base = ioremap_nocache(AR724X_PCI_CRP_BASE,
++						   AR724X_PCI_CRP_SIZE);
++	if (ar724x_pci_localcfg_base == NULL)
++		goto err;
++
++	ar724x_pci_devcfg_base = ioremap_nocache(AR724X_PCI_CFG_BASE,
++						 AR724X_PCI_CFG_SIZE);
++	if (ar724x_pci_devcfg_base == NULL)
++		goto err_unmap_localcfg;
++
++	ar724x_pci_ctrl_base = ioremap_nocache(AR724X_PCI_CTRL_BASE,
++					       AR724X_PCI_CTRL_SIZE);
++	if (ar724x_pci_ctrl_base == NULL)
++		goto err_unmap_devcfg;
++
++	ar724x_pci_reset();
++	ret = ar724x_pci_setup();
++	if (ret)
++		goto err_unmap_ctrl;
++
++	ar724x_pci_fixup_enable = 1;
++	ar724x_pci_irq_init();
++	register_pci_controller(&ar724x_pci_controller);
++
++	return 0;
++
++ err_unmap_ctrl:
++	iounmap(ar724x_pci_ctrl_base);
++  err_unmap_devcfg:
++	iounmap(ar724x_pci_devcfg_base);
++ err_unmap_localcfg:
++	iounmap(ar724x_pci_localcfg_base);
++ err:
++	return ret;
++}
+diff -Nur linux-2.6.33.3.orig/drivers/char/Kconfig linux-2.6.33.3/drivers/char/Kconfig
+--- linux-2.6.33.3.orig/drivers/char/Kconfig	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/drivers/char/Kconfig	2010-05-17 20:29:49.263661210 +0200
+@@ -1016,6 +1016,14 @@
+ 
+ 	  If compiled as a module, it will be called cs5535_gpio.
+ 
++config GPIO_DEVICE
++	tristate "GPIO device support"
++	depends on GENERIC_GPIO
++	help
++	  Say Y to enable Linux GPIO device support.  This allows control of
++	  GPIO pins using a character device
++
++
+ config RAW_DRIVER
+ 	tristate "RAW driver (/dev/raw/rawN)"
+ 	depends on BLOCK
+diff -Nur linux-2.6.33.3.orig/drivers/char/Makefile linux-2.6.33.3/drivers/char/Makefile
+--- linux-2.6.33.3.orig/drivers/char/Makefile	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/drivers/char/Makefile	2010-05-17 20:29:49.267113605 +0200
+@@ -95,6 +95,7 @@
+ obj-$(CONFIG_PC8736x_GPIO)	+= pc8736x_gpio.o
+ obj-$(CONFIG_NSC_GPIO)		+= nsc_gpio.o
+ obj-$(CONFIG_CS5535_GPIO)	+= cs5535_gpio.o
++obj-$(CONFIG_GPIO_DEVICE)	+= gpio_dev.o
+ obj-$(CONFIG_GPIO_TB0219)	+= tb0219.o
+ obj-$(CONFIG_TELCLOCK)		+= tlclk.o
+ 
+diff -Nur linux-2.6.33.3.orig/drivers/gpio/nxp_74hc153.c linux-2.6.33.3/drivers/gpio/nxp_74hc153.c
+--- linux-2.6.33.3.orig/drivers/gpio/nxp_74hc153.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/drivers/gpio/nxp_74hc153.c	2010-01-19 19:26:38.721436935 +0100
+@@ -0,0 +1,246 @@
++/*
++ *  NXP 74HC153 - Dual 4-input multiplexer GPIO driver
++ *
++ *  Copyright (C) 2010 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/module.h>
++#include <linux/init.h>
++#include <linux/gpio.h>
++#include <linux/platform_device.h>
++#include <linux/nxp_74hc153.h>
++
++#define NXP_74HC153_NUM_GPIOS	8
++#define NXP_74HC153_S0_MASK	0x1
++#define NXP_74HC153_S1_MASK	0x2
++#define NXP_74HC153_BANK_MASK	0x4
++
++struct nxp_74hc153_chip {
++	struct device		*parent;
++	struct gpio_chip	gpio_chip;
++	struct mutex		lock;
++};
++
++static struct nxp_74hc153_chip *gpio_to_nxp(struct gpio_chip *gc)
++{
++	return container_of(gc, struct nxp_74hc153_chip, gpio_chip);
++}
++
++static int nxp_74hc153_direction_input(struct gpio_chip *gc, unsigned offset)
++{
++	return 0;
++}
++
++static int nxp_74hc153_direction_output(struct gpio_chip *gc,
++					unsigned offset, int val)
++{
++	return -EINVAL;
++}
++
++static int nxp_74hc153_get_value(struct gpio_chip *gc, unsigned offset)
++{
++	struct nxp_74hc153_chip *nxp;
++	struct nxp_74hc153_platform_data *pdata;
++	unsigned s0;
++	unsigned s1;
++	unsigned pin;
++	int ret;
++
++	nxp = gpio_to_nxp(gc);
++	pdata = nxp->parent->platform_data;
++
++	s0 = !!(offset & NXP_74HC153_S0_MASK);
++	s1 = !!(offset & NXP_74HC153_S1_MASK);
++	pin = (offset & NXP_74HC153_BANK_MASK) ? pdata->gpio_pin_2y
++					       : pdata->gpio_pin_1y;
++
++	mutex_lock(&nxp->lock);
++	gpio_set_value(pdata->gpio_pin_s0, s0);
++	gpio_set_value(pdata->gpio_pin_s1, s1);
++	ret = gpio_get_value(pin);
++	mutex_unlock(&nxp->lock);
++
++	return ret;
++}
++
++static void nxp_74hc153_set_value(struct gpio_chip *gc,
++				  unsigned offset, int val)
++{
++	/* not supported */
++}
++
++static int __devinit nxp_74hc153_probe(struct platform_device *pdev)
++{
++	struct nxp_74hc153_platform_data *pdata;
++	struct nxp_74hc153_chip *nxp;
++	struct gpio_chip *gc;
++	int err;
++
++	pdata = pdev->dev.platform_data;
++	if (pdata == NULL) {
++		dev_dbg(&pdev->dev, "no platform data specified\n");
++		return -EINVAL;
++	}
++
++	nxp = kzalloc(sizeof(struct nxp_74hc153_chip), GFP_KERNEL);
++	if (nxp == NULL) {
++		dev_err(&pdev->dev, "no memory for private data\n");
++		return -ENOMEM;
++	}
++
++	err = gpio_request(pdata->gpio_pin_s0, dev_name(&pdev->dev));
++	if (err) {
++		dev_err(&pdev->dev, "unable to claim gpio %u, err=%d\n",
++			pdata->gpio_pin_s0, err);
++		goto err_free_nxp;
++	}
++
++	err = gpio_request(pdata->gpio_pin_s1, dev_name(&pdev->dev));
++	if (err) {
++		dev_err(&pdev->dev, "unable to claim gpio %u, err=%d\n",
++			pdata->gpio_pin_s1, err);
++		goto err_free_s0;
++	}
++
++	err = gpio_request(pdata->gpio_pin_1y, dev_name(&pdev->dev));
++	if (err) {
++		dev_err(&pdev->dev, "unable to claim gpio %u, err=%d\n",
++			pdata->gpio_pin_1y, err);
++		goto err_free_s1;
++	}
++
++	err = gpio_request(pdata->gpio_pin_2y, dev_name(&pdev->dev));
++	if (err) {
++		dev_err(&pdev->dev, "unable to claim gpio %u, err=%d\n",
++			pdata->gpio_pin_2y, err);
++		goto err_free_1y;
++	}
++
++	err = gpio_direction_output(pdata->gpio_pin_s0, 0);
++	if (err) {
++		dev_err(&pdev->dev,
++			"unable to set direction of gpio %u, err=%d\n",
++			pdata->gpio_pin_s0, err);
++		goto err_free_2y;
++	}
++
++	err = gpio_direction_output(pdata->gpio_pin_s1, 0);
++	if (err) {
++		dev_err(&pdev->dev,
++			"unable to set direction of gpio %u, err=%d\n",
++			pdata->gpio_pin_s1, err);
++		goto err_free_2y;
++	}
++
++	err = gpio_direction_input(pdata->gpio_pin_1y);
++	if (err) {
++		dev_err(&pdev->dev,
++			"unable to set direction of gpio %u, err=%d\n",
++			pdata->gpio_pin_1y, err);
++		goto err_free_2y;
++	}
++
++	err = gpio_direction_input(pdata->gpio_pin_2y);
++	if (err) {
++		dev_err(&pdev->dev,
++			"unable to set direction of gpio %u, err=%d\n",
++			pdata->gpio_pin_2y, err);
++		goto err_free_2y;
++	}
++
++	nxp->parent = &pdev->dev;
++	mutex_init(&nxp->lock);
++
++	gc = &nxp->gpio_chip;
++
++	gc->direction_input  = nxp_74hc153_direction_input;
++	gc->direction_output = nxp_74hc153_direction_output;
++	gc->get = nxp_74hc153_get_value;
++	gc->set = nxp_74hc153_set_value;
++	gc->can_sleep = 1;
++
++	gc->base = pdata->gpio_base;
++	gc->ngpio = NXP_74HC153_NUM_GPIOS;
++	gc->label = dev_name(nxp->parent);
++	gc->dev = nxp->parent;
++	gc->owner = THIS_MODULE;
++
++	err = gpiochip_add(&nxp->gpio_chip);
++	if (err) {
++		dev_err(&pdev->dev, "unable to add gpio chip, err=%d\n", err);
++		goto err_free_2y;
++	}
++
++	platform_set_drvdata(pdev, nxp);
++	return 0;
++
++ err_free_2y:
++	gpio_free(pdata->gpio_pin_2y);
++ err_free_1y:
++	gpio_free(pdata->gpio_pin_1y);
++ err_free_s1:
++	gpio_free(pdata->gpio_pin_s1);
++ err_free_s0:
++	gpio_free(pdata->gpio_pin_s0);
++ err_free_nxp:
++	kfree(nxp);
++	return err;
++}
++
++static int nxp_74hc153_remove(struct platform_device *pdev)
++{
++	struct nxp_74hc153_chip *nxp = platform_get_drvdata(pdev);
++	struct nxp_74hc153_platform_data *pdata = pdev->dev.platform_data;
++
++	if (nxp) {
++		int err;
++
++		err = gpiochip_remove(&nxp->gpio_chip);
++		if (err) {
++			dev_err(&pdev->dev,
++				"unable to remove gpio chip, err=%d\n",
++				err);
++			return err;
++		}
++
++		gpio_free(pdata->gpio_pin_2y);
++		gpio_free(pdata->gpio_pin_1y);
++		gpio_free(pdata->gpio_pin_s1);
++		gpio_free(pdata->gpio_pin_s0);
++
++		kfree(nxp);
++		platform_set_drvdata(pdev, NULL);
++	}
++
++	return 0;
++}
++
++static struct platform_driver nxp_74hc153_driver = {
++	.probe		= nxp_74hc153_probe,
++	.remove		= __devexit_p(nxp_74hc153_remove),
++	.driver = {
++		.name	= NXP_74HC153_DRIVER_NAME,
++		.owner	= THIS_MODULE,
++	},
++};
++
++static int __init nxp_74hc153_init(void)
++{
++	return platform_driver_register(&nxp_74hc153_driver);
++}
++subsys_initcall(nxp_74hc153_init);
++
++static void __exit nxp_74hc153_exit(void)
++{
++	platform_driver_unregister(&nxp_74hc153_driver);
++}
++module_exit(nxp_74hc153_exit);
++
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_DESCRIPTION("GPIO expander driver for NXP 74HC153");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:" NXP_74HC153_DRIVER_NAME);
+diff -Nur linux-2.6.33.3.orig/drivers/input/misc/gpio_buttons.c linux-2.6.33.3/drivers/input/misc/gpio_buttons.c
+--- linux-2.6.33.3.orig/drivers/input/misc/gpio_buttons.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/drivers/input/misc/gpio_buttons.c	2010-05-16 13:16:51.715600731 +0200
+@@ -0,0 +1,216 @@
++/*
++ *  Driver for buttons on GPIO lines not capable of generating interrupts
++ *
++ *  Copyright (C) 2007-2010 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2010 Nuno Goncalves <nunojpg@gmail.com>
++ *
++ *  This file was based on: /drivers/input/misc/cobalt_btns.c
++ *	Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
++ *
++ *  also was based on: /drivers/input/keyboard/gpio_keys.c
++ *	Copyright 2005 Phil Blundell
++ *
++ *  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/slab.h>
++
++#include <linux/input.h>
++#include <linux/input-polldev.h>
++#include <linux/ioport.h>
++#include <linux/platform_device.h>
++
++#include <linux/gpio_buttons.h>
++
++#include <asm/gpio.h>
++
++#define DRV_NAME	"gpio-buttons"
++#define DRV_VERSION	"0.1.2"
++#define PFX		DRV_NAME ": "
++
++struct gpio_button_data {
++	int last_state;
++	int count;
++};
++
++struct gpio_buttons_dev {
++	struct input_polled_dev *poll_dev;
++	struct gpio_buttons_platform_data *pdata;
++	struct gpio_button_data *data;
++};
++
++static void gpio_buttons_poll(struct input_polled_dev *dev)
++{
++	struct gpio_buttons_dev *bdev = dev->private;
++	struct gpio_buttons_platform_data *pdata = bdev->pdata;
++	struct input_dev *input = dev->input;
++	int i;
++
++	for (i = 0; i < bdev->pdata->nbuttons; i++) {
++		struct gpio_button *button = &pdata->buttons[i];
++		unsigned int type = button->type ?: EV_KEY;
++		int state;
++
++		if (bdev->data[i].count < button->threshold) {
++			bdev->data[i].count++;
++			continue;
++		}
++
++		state = gpio_get_value(button->gpio) ? 1 : 0;
++		if (state != bdev->data[i].last_state) {
++			input_event(input, type, button->code,
++				    !!(state ^ button->active_low));
++			input_sync(input);
++			bdev->data[i].count = 0;
++			bdev->data[i].last_state = state;
++		}
++	}
++}
++
++static int __devinit gpio_buttons_probe(struct platform_device *pdev)
++{
++	struct gpio_buttons_platform_data *pdata = pdev->dev.platform_data;
++	struct gpio_buttons_dev *bdev;
++	struct input_polled_dev *poll_dev;
++	struct input_dev *input;
++	int error, i;
++
++	if (!pdata)
++		return -ENXIO;
++
++	bdev = kzalloc(sizeof(struct gpio_buttons_dev) +
++		       sizeof(struct gpio_button_data) * pdata->nbuttons,
++		       GFP_KERNEL);
++	if (!bdev) {
++		printk(KERN_ERR DRV_NAME "no memory for device\n");
++		return -ENOMEM;
++	}
++
++	bdev->data = (struct gpio_button_data *) &bdev[1];
++
++	poll_dev = input_allocate_polled_device();
++	if (!poll_dev) {
++		printk(KERN_ERR DRV_NAME "no memory for polled device\n");
++		error = -ENOMEM;
++		goto err_free_bdev;
++	}
++
++	poll_dev->private = bdev;
++	poll_dev->poll = gpio_buttons_poll;
++	poll_dev->poll_interval = pdata->poll_interval;
++
++	input = poll_dev->input;
++
++	input->evbit[0] = BIT(EV_KEY);
++	input->name = pdev->name;
++	input->phys = "gpio-buttons/input0";
++	input->dev.parent = &pdev->dev;
++
++	input->id.bustype = BUS_HOST;
++	input->id.vendor = 0x0001;
++	input->id.product = 0x0001;
++	input->id.version = 0x0100;
++
++	for (i = 0; i < pdata->nbuttons; i++) {
++		struct gpio_button *button = &pdata->buttons[i];
++		unsigned int gpio = button->gpio;
++		unsigned int type = button->type ?: EV_KEY;
++
++		error = gpio_request(gpio, button->desc ?
++				button->desc : DRV_NAME);
++		if (error) {
++			printk(KERN_ERR PFX "unable to claim gpio %u, "
++				"error %d\n", gpio, error);
++			goto err_free_gpio;
++		}
++
++		error = gpio_direction_input(gpio);
++		if (error) {
++			printk(KERN_ERR PFX "unable to set direction on "
++				"gpio %u, error %d\n", gpio, error);
++			goto err_free_gpio;
++		}
++
++		input_set_capability(input, type, button->code);
++		bdev->data[i].last_state = gpio_get_value(button->gpio) ? 1 : 0;
++	}
++
++	bdev->poll_dev = poll_dev;
++	bdev->pdata = pdata;
++	platform_set_drvdata(pdev, bdev);
++
++	error = input_register_polled_device(poll_dev);
++	if (error) {
++		printk(KERN_ERR PFX "unable to register polled device, "
++			"error %d\n", error);
++		goto err_free_gpio;
++	}
++
++	return 0;
++
++err_free_gpio:
++	for (i = i - 1; i >= 0; i--)
++		gpio_free(pdata->buttons[i].gpio);
++
++	input_free_polled_device(poll_dev);
++
++err_free_bdev:
++	kfree(bdev);
++
++	platform_set_drvdata(pdev, NULL);
++	return error;
++}
++
++static int __devexit gpio_buttons_remove(struct platform_device *pdev)
++{
++	struct gpio_buttons_dev *bdev = platform_get_drvdata(pdev);
++	struct gpio_buttons_platform_data *pdata = bdev->pdata;
++	int i;
++
++	input_unregister_polled_device(bdev->poll_dev);
++
++	for (i = 0; i < pdata->nbuttons; i++)
++		gpio_free(pdata->buttons[i].gpio);
++
++	input_free_polled_device(bdev->poll_dev);
++
++	kfree(bdev);
++	platform_set_drvdata(pdev, NULL);
++
++	return 0;
++}
++
++static struct platform_driver gpio_buttons_driver = {
++	.probe	= gpio_buttons_probe,
++	.remove	= __devexit_p(gpio_buttons_remove),
++	.driver	= {
++		.name	= DRV_NAME,
++		.owner	= THIS_MODULE,
++	},
++};
++
++static int __init gpio_buttons_init(void)
++{
++	printk(KERN_INFO DRV_NAME " driver version " DRV_VERSION "\n");
++	return platform_driver_register(&gpio_buttons_driver);
++}
++
++static void __exit gpio_buttons_exit(void)
++{
++	platform_driver_unregister(&gpio_buttons_driver);
++}
++
++module_init(gpio_buttons_init);
++module_exit(gpio_buttons_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>");
++MODULE_VERSION(DRV_VERSION);
++MODULE_DESCRIPTION("Polled buttons driver for CPU GPIOs");
++
+diff -Nur linux-2.6.33.3.orig/drivers/input/misc/Kconfig linux-2.6.33.3/drivers/input/misc/Kconfig
+--- linux-2.6.33.3.orig/drivers/input/misc/Kconfig	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/drivers/input/misc/Kconfig	2010-05-17 20:29:41.363933213 +0200
+@@ -319,4 +319,20 @@
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called pcap_keys.
+ 
++config INPUT_GPIO_BUTTONS
++	tristate "Polled GPIO buttons interface"
++	depends on GENERIC_GPIO
++	select INPUT_POLLDEV
++	help
++	  This driver implements support for buttons connected
++	  to GPIO pins of various CPUs (and some other chips).
++
++	  Say Y here if your device has buttons connected
++	  directly to such GPIO pins.  Your board-specific
++	  setup logic must also provide a platform device,
++	  with configuration data saying which GPIOs are used.
++
++	  To compile this driver as a module, choose M here: the
++	  module will be called gpio-buttons.
++
+ endif
+diff -Nur linux-2.6.33.3.orig/drivers/input/misc/Makefile linux-2.6.33.3/drivers/input/misc/Makefile
+--- linux-2.6.33.3.orig/drivers/input/misc/Makefile	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/drivers/input/misc/Makefile	2010-05-17 20:29:41.363933213 +0200
+@@ -30,4 +30,5 @@
+ obj-$(CONFIG_INPUT_WISTRON_BTNS)	+= wistron_btns.o
+ obj-$(CONFIG_INPUT_WM831X_ON)		+= wm831x-on.o
+ obj-$(CONFIG_INPUT_YEALINK)		+= yealink.o
++obj-$(CONFIG_INPUT_GPIO_BUTTONS)	+= gpio_buttons.o
+ 
+diff -Nur linux-2.6.33.3.orig/drivers/leds/leds-rb750.c linux-2.6.33.3/drivers/leds/leds-rb750.c
+--- linux-2.6.33.3.orig/drivers/leds/leds-rb750.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/drivers/leds/leds-rb750.c	2010-03-12 19:31:47.358041350 +0100
+@@ -0,0 +1,140 @@
++/*
++ * LED driver for the RouterBOARD 750
++ *
++ * Copyright (C) 2010 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/init.h>
++#include <linux/platform_device.h>
++#include <linux/leds.h>
++
++#include <asm/mach-ar71xx/mach-rb750.h>
++
++#define DRV_NAME	"leds-rb750"
++
++struct rb750_led_dev {
++	struct led_classdev	cdev;
++	u32			mask;
++	int			active_low;
++};
++
++struct rb750_led_drvdata {
++	struct rb750_led_dev	*led_devs;
++	int			num_leds;
++};
++
++static inline struct rb750_led_dev *to_rbled(struct led_classdev *led_cdev)
++{
++	return (struct rb750_led_dev *)container_of(led_cdev,
++		struct rb750_led_dev, cdev);
++}
++
++static void rb750_led_brightness_set(struct led_classdev *led_cdev,
++				     enum led_brightness value)
++{
++	struct rb750_led_dev *rbled = to_rbled(led_cdev);
++	int level;
++
++	level = (value == LED_OFF) ? 0 : 1;
++	level ^= rbled->active_low;
++
++	if (level)
++		rb750_latch_change(0, rbled->mask);
++	else
++		rb750_latch_change(rbled->mask, 0);
++}
++
++static int __devinit rb750_led_probe(struct platform_device *pdev)
++{
++	struct rb750_led_platform_data *pdata;
++	struct rb750_led_drvdata *drvdata;
++	int ret = 0;
++	int i;
++
++	pdata = pdev->dev.platform_data;
++	if (!pdata)
++		return -EINVAL;
++
++	drvdata = kzalloc(sizeof(struct rb750_led_drvdata) +
++			  sizeof(struct rb750_led_dev) * pdata->num_leds,
++			  GFP_KERNEL);
++	if (!drvdata)
++		return -ENOMEM;
++
++	drvdata->num_leds = pdata->num_leds;
++	drvdata->led_devs = (struct rb750_led_dev *) &drvdata[1];
++
++	for (i = 0; i < drvdata->num_leds; i++) {
++		struct rb750_led_dev *rbled = &drvdata->led_devs[i];
++		struct rb750_led_data *led_data = &pdata->leds[i];
++
++		rbled->cdev.name = led_data->name;
++		rbled->cdev.default_trigger = led_data->default_trigger;
++		rbled->cdev.brightness_set = rb750_led_brightness_set;
++		rbled->cdev.brightness = LED_OFF;
++
++		rbled->mask = led_data->mask;
++		rbled->active_low = !!led_data->active_low;
++
++		ret = led_classdev_register(&pdev->dev, &rbled->cdev);
++		if (ret)
++			goto err;
++	}
++
++	platform_set_drvdata(pdev, drvdata);
++	return 0;
++
++ err:
++	for (i = i - 1; i >= 0; i--)
++		led_classdev_unregister(&drvdata->led_devs[i].cdev);
++
++	kfree(drvdata);
++	return ret;
++}
++
++static int __devexit rb750_led_remove(struct platform_device *pdev)
++{
++	struct rb750_led_drvdata *drvdata;
++	int i;
++
++	drvdata = platform_get_drvdata(pdev);
++	for (i = 0; i < drvdata->num_leds; i++)
++		led_classdev_unregister(&drvdata->led_devs[i].cdev);
++
++	kfree(drvdata);
++	return 0;
++}
++
++static struct platform_driver rb750_led_driver = {
++	.probe		= rb750_led_probe,
++	.remove		= __devexit_p(rb750_led_remove),
++	.driver		= {
++		.name	= DRV_NAME,
++		.owner	= THIS_MODULE,
++	},
++};
++
++MODULE_ALIAS("platform:leds-rb750");
++
++static int __init rb750_led_init(void)
++{
++	return platform_driver_register(&rb750_led_driver);
++}
++
++static void __exit rb750_led_exit(void)
++{
++	platform_driver_unregister(&rb750_led_driver);
++}
++
++module_init(rb750_led_init);
++module_exit(rb750_led_exit);
++
++MODULE_DESCRIPTION(DRV_NAME);
++MODULE_DESCRIPTION("LED driver for the RouterBOARD 750");
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_LICENSE("GPL v2");
+diff -Nur linux-2.6.33.3.orig/drivers/leds/leds-wndr3700-usb.c linux-2.6.33.3/drivers/leds/leds-wndr3700-usb.c
+--- linux-2.6.33.3.orig/drivers/leds/leds-wndr3700-usb.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/drivers/leds/leds-wndr3700-usb.c	2009-12-13 20:45:24.579920576 +0100
+@@ -0,0 +1,75 @@
++/*
++ *  USB LED driver for the NETGEAR WNDR3700
++ *
++ *  Copyright (C) 2009 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/leds.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#define DRIVER_NAME	"wndr3700-led-usb"
++
++static void wndr3700_usb_led_set(struct led_classdev *cdev,
++				 enum led_brightness brightness)
++{
++	if (brightness)
++		ar71xx_device_start(RESET_MODULE_GE1_PHY);
++	else
++		ar71xx_device_stop(RESET_MODULE_GE1_PHY);
++}
++
++static enum led_brightness wndr3700_usb_led_get(struct led_classdev *cdev)
++{
++	return ar71xx_device_stopped(RESET_MODULE_GE1_PHY) ? LED_OFF : LED_FULL;
++}
++
++static struct led_classdev wndr3700_usb_led = {
++	.name = "wndr3700:green:usb",
++	.brightness_set = wndr3700_usb_led_set,
++	.brightness_get = wndr3700_usb_led_get,
++};
++
++static int __devinit wndr3700_usb_led_probe(struct platform_device *pdev)
++{
++	return led_classdev_register(&pdev->dev, &wndr3700_usb_led);
++}
++
++static int __devexit wndr3700_usb_led_remove(struct platform_device *pdev)
++{
++	led_classdev_unregister(&wndr3700_usb_led);
++	return 0;
++}
++
++static struct platform_driver wndr3700_usb_led_driver = {
++	.probe = wndr3700_usb_led_probe,
++	.remove = __devexit_p(wndr3700_usb_led_remove),
++	.driver = {
++		.name = DRIVER_NAME,
++		.owner = THIS_MODULE,
++	},
++};
++
++static int __init wndr3700_usb_led_init(void)
++{
++	return platform_driver_register(&wndr3700_usb_led_driver);
++}
++
++static void __exit wndr3700_usb_led_exit(void)
++{
++	platform_driver_unregister(&wndr3700_usb_led_driver);
++}
++
++module_init(wndr3700_usb_led_init);
++module_exit(wndr3700_usb_led_exit);
++
++MODULE_DESCRIPTION("USB LED driver for the NETGEAR WNDR3700");
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:" DRIVER_NAME);
+diff -Nur linux-2.6.33.3.orig/drivers/mtd/maps/ar91xx_flash.c linux-2.6.33.3/drivers/mtd/maps/ar91xx_flash.c
+--- linux-2.6.33.3.orig/drivers/mtd/maps/ar91xx_flash.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/drivers/mtd/maps/ar91xx_flash.c	2009-12-13 20:45:22.067931737 +0100
+@@ -0,0 +1,310 @@
++/*
++ * Parallel flash driver for the Atheros AR91xx SoC
++ *
++ * Copyright (C) 2009 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/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++#include <linux/io.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/ar91xx_flash.h>
++
++#define DRV_NAME	"ar91xx-flash"
++
++struct ar91xx_flash_info {
++	struct mtd_info		*mtd;
++	struct map_info		map;
++#ifdef CONFIG_MTD_PARTITIONS
++	int			nr_parts;
++	struct mtd_partition	*parts;
++#endif
++};
++
++static map_word ar91xx_flash_read(struct map_info *map, unsigned long ofs)
++{
++	map_word val;
++
++	if (map_bankwidth_is_1(map))
++		val.x[0] = __raw_readb(map->virt + (ofs ^ 3));
++	else if (map_bankwidth_is_2(map))
++		val.x[0] = __raw_readw(map->virt + (ofs ^ 2));
++	else
++		val = map_word_ff(map);
++
++	return val;
++}
++
++static void ar91xx_flash_write(struct map_info *map, map_word d,
++			       unsigned long ofs)
++{
++	if (map_bankwidth_is_1(map))
++		__raw_writeb(d.x[0], map->virt + (ofs ^ 3));
++	else if (map_bankwidth_is_2(map))
++		__raw_writew(d.x[0], map->virt + (ofs ^ 2));
++
++	mb();
++}
++
++static map_word ar91xx_flash_read_lock(struct map_info *map, unsigned long ofs)
++{
++	map_word ret;
++
++	ar71xx_flash_acquire();
++	ret = ar91xx_flash_read(map, ofs);
++	ar71xx_flash_release();
++
++	return ret;
++}
++
++static void ar91xx_flash_write_lock(struct map_info *map, map_word d,
++			       unsigned long ofs)
++{
++	ar71xx_flash_acquire();
++	ar91xx_flash_write(map, d, ofs);
++	ar71xx_flash_release();
++}
++
++static void ar91xx_flash_copy_from_lock(struct map_info *map, void *to,
++					unsigned long from, ssize_t len)
++{
++	ar71xx_flash_acquire();
++	inline_map_copy_from(map, to, from, len);
++	ar71xx_flash_release();
++}
++
++static void ar91xx_flash_copy_to_lock(struct map_info *map, unsigned long to,
++				      const void *from, ssize_t len)
++{
++	ar71xx_flash_acquire();
++	inline_map_copy_to(map, to, from, len);
++	ar71xx_flash_release();
++}
++
++static int ar91xx_flash_remove(struct platform_device *pdev)
++{
++	struct ar91xx_flash_platform_data *pdata;
++	struct ar91xx_flash_info *info;
++
++	info = platform_get_drvdata(pdev);
++	if (info == NULL)
++		return 0;
++
++	platform_set_drvdata(pdev, NULL);
++
++	if (info->mtd == NULL)
++		return 0;
++
++	pdata = pdev->dev.platform_data;
++#ifdef CONFIG_MTD_PARTITIONS
++	if (info->nr_parts) {
++		del_mtd_partitions(info->mtd);
++		kfree(info->parts);
++	} else if (pdata->nr_parts) {
++		del_mtd_partitions(info->mtd);
++	} else {
++		del_mtd_device(info->mtd);
++	}
++#else
++	del_mtd_device(info->mtd);
++#endif
++	map_destroy(info->mtd);
++
++	return 0;
++}
++
++static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
++#ifdef CONFIG_MTD_PARTITIONS
++static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
++#endif
++
++static int ar91xx_flash_probe(struct platform_device *pdev)
++{
++	struct ar91xx_flash_platform_data *pdata;
++	struct ar91xx_flash_info *info;
++	struct resource *res;
++	struct resource *region;
++	const char **probe_type;
++	int err = 0;
++
++	pdata = pdev->dev.platform_data;
++	if (pdata == NULL)
++		return -EINVAL;
++
++	info = devm_kzalloc(&pdev->dev, sizeof(struct ar91xx_flash_info),
++			    GFP_KERNEL);
++	if (info == NULL) {
++		err = -ENOMEM;
++		goto err_out;
++	}
++
++	platform_set_drvdata(pdev, info);
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (res == NULL) {
++		err = -ENOENT;
++		goto err_out;
++	}
++
++	dev_info(&pdev->dev, "%.8llx at %.8llx\n",
++		 (unsigned long long)(res->end - res->start + 1),
++		 (unsigned long long)res->start);
++
++	region = devm_request_mem_region(&pdev->dev,
++					 res->start, res->end - res->start + 1,
++					 dev_name(&pdev->dev));
++	if (region == NULL) {
++		dev_err(&pdev->dev, "could not reserve memory region\n");
++		err = -ENOMEM;
++		goto err_out;
++	}
++
++	info->map.name = dev_name(&pdev->dev);
++	info->map.phys = res->start;
++	info->map.size = res->end - res->start + 1;
++	info->map.bankwidth = pdata->width;
++
++	info->map.virt = devm_ioremap(&pdev->dev, info->map.phys,
++				      info->map.size);
++	if (info->map.virt == NULL) {
++		dev_err(&pdev->dev, "failed to ioremap flash region\n");
++		err = -EIO;
++		goto err_out;
++	}
++
++	simple_map_init(&info->map);
++	if (pdata->is_shared) {
++		info->map.read = ar91xx_flash_read_lock;
++		info->map.write = ar91xx_flash_write_lock;
++		info->map.copy_from = ar91xx_flash_copy_from_lock;
++		info->map.copy_to = ar91xx_flash_copy_to_lock;
++	} else {
++		info->map.read = ar91xx_flash_read;
++		info->map.write = ar91xx_flash_write;
++	}
++
++	probe_type = rom_probe_types;
++	for (; info->mtd == NULL && *probe_type != NULL; probe_type++)
++		info->mtd = do_map_probe(*probe_type, &info->map);
++
++	if (info->mtd == NULL) {
++		dev_err(&pdev->dev, "map_probe failed\n");
++		err = -ENXIO;
++		goto err_out;
++	}
++
++	info->mtd->owner = THIS_MODULE;
++
++#ifdef CONFIG_MTD_PARTITIONS
++	if (pdata->nr_parts) {
++		dev_info(&pdev->dev, "using static partition mapping\n");
++		add_mtd_partitions(info->mtd, pdata->parts, pdata->nr_parts);
++		return 0;
++	}
++
++	err = parse_mtd_partitions(info->mtd, part_probe_types,
++				   &info->parts, 0);
++	if (err > 0) {
++		add_mtd_partitions(info->mtd, info->parts, err);
++		return 0;
++	}
++#endif
++
++	add_mtd_device(info->mtd);
++	return 0;
++
++ err_out:
++	ar91xx_flash_remove(pdev);
++	return err;
++}
++
++#ifdef CONFIG_PM
++static int ar91xx_flash_suspend(struct platform_device *dev, pm_message_t state)
++{
++	struct ar91xx_flash_info *info = platform_get_drvdata(dev);
++	int ret = 0;
++
++	if (info->mtd->suspend)
++		ret = info->mtd->suspend(info->mtd);
++
++	if (ret)
++		goto fail;
++
++	return 0;
++
++ fail:
++	if (info->mtd->suspend) {
++		BUG_ON(!info->mtd->resume);
++		info->mtd->resume(info->mtd);
++	}
++
++	return ret;
++}
++
++static int ar91xx_flash_resume(struct platform_device *pdev)
++{
++	struct ar91xx_flash_info *info = platform_get_drvdata(pdev);
++
++	if (info->mtd->resume)
++		info->mtd->resume(info->mtd);
++
++	return 0;
++}
++
++static void ar91xx_flash_shutdown(struct platform_device *pdev)
++{
++	struct ar91xx_flash_info *info = platform_get_drvdata(pdev);
++
++	if (info->mtd->suspend && info->mtd->resume)
++		if (info->mtd->suspend(info->mtd) == 0)
++			info->mtd->resume(info->mtd);
++}
++#else
++#define ar91xx_flash_suspend	NULL
++#define ar91xx_flash_resume	NULL
++#define ar91xx_flash_shutdown	NULL
++#endif
++
++static struct platform_driver ar91xx_flash_driver = {
++	.probe		= ar91xx_flash_probe,
++	.remove		= ar91xx_flash_remove,
++	.suspend	= ar91xx_flash_suspend,
++	.resume		= ar91xx_flash_resume,
++	.shutdown	= ar91xx_flash_shutdown,
++	.driver		= {
++		.name	= DRV_NAME,
++		.owner	= THIS_MODULE,
++	},
++};
++
++static int __init ar91xx_flash_init(void)
++{
++	return platform_driver_register(&ar91xx_flash_driver);
++}
++
++static void __exit ar91xx_flash_exit(void)
++{
++	platform_driver_unregister(&ar91xx_flash_driver);
++}
++
++module_init(ar91xx_flash_init);
++module_exit(ar91xx_flash_exit);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_DESCRIPTION("Parallel flash driver for the Atheros AR91xx SoC");
++MODULE_ALIAS("platform:" DRV_NAME);
+diff -Nur linux-2.6.33.3.orig/drivers/mtd/maps/Kconfig linux-2.6.33.3/drivers/mtd/maps/Kconfig
+--- linux-2.6.33.3.orig/drivers/mtd/maps/Kconfig	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/drivers/mtd/maps/Kconfig	2010-05-17 16:28:48.419315145 +0200
+@@ -257,6 +257,13 @@
+ 	help
+ 	  Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards
+ 
++config MTD_AR91XX_FLASH
++	tristate "Atheros AR91xx parallel flash support"
++	depends on ATHEROS_AR71XX
++	select MTD_COMPLEX_MAPPINGS
++	help
++	  Parallel flash driver for the Atheros AR91xx based boards.
++
+ config MTD_DILNETPC
+ 	tristate "CFI Flash device mapped on DIL/Net PC"
+ 	depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN
+diff -Nur linux-2.6.33.3.orig/drivers/mtd/maps/Makefile linux-2.6.33.3/drivers/mtd/maps/Makefile
+--- linux-2.6.33.3.orig/drivers/mtd/maps/Makefile	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/drivers/mtd/maps/Makefile	2010-05-17 16:28:48.419315145 +0200
+@@ -41,6 +41,7 @@
+ obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
+ obj-$(CONFIG_MTD_PCI)		+= pci.o
+ obj-$(CONFIG_MTD_ALCHEMY)       += alchemy-flash.o
++obj-$(CONFIG_MTD_AR91XX_FLASH)	+= ar91xx_flash.o
+ obj-$(CONFIG_MTD_AUTCPU12)	+= autcpu12-nvram.o
+ obj-$(CONFIG_MTD_EDB7312)	+= edb7312.o
+ obj-$(CONFIG_MTD_IMPA7)		+= impa7.o
+diff -Nur linux-2.6.33.3.orig/drivers/mtd/nand/Kconfig linux-2.6.33.3/drivers/mtd/nand/Kconfig
+--- linux-2.6.33.3.orig/drivers/mtd/nand/Kconfig	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/drivers/mtd/nand/Kconfig	2010-05-17 16:29:54.255116284 +0200
+@@ -488,4 +488,8 @@
+ 	  This enables the driver for the NAND Flash on evaluation board based
+ 	  on w90p910.
+ 
++config MTD_NAND_RB4XX
++	tristate "NAND flash driver for RouterBoard 4xx series"
++	depends on MTD_NAND && AR71XX_MACH_RB4XX
++
+ endif # MTD_NAND
+diff -Nur linux-2.6.33.3.orig/drivers/mtd/nand/Makefile linux-2.6.33.3/drivers/mtd/nand/Makefile
+--- linux-2.6.33.3.orig/drivers/mtd/nand/Makefile	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/drivers/mtd/nand/Makefile	2010-05-17 16:29:54.255116284 +0200
+@@ -30,6 +30,7 @@
+ obj-$(CONFIG_MTD_NAND_PXA3xx)		+= pxa3xx_nand.o
+ obj-$(CONFIG_MTD_NAND_TMIO)		+= tmio_nand.o
+ obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
++obj-$(CONFIG_MTD_NAND_RB4XX)		+= rb4xx_nand.o
+ obj-$(CONFIG_MTD_ALAUDA)		+= alauda.o
+ obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
+ obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
+diff -Nur linux-2.6.33.3.orig/drivers/mtd/nand/rb4xx_nand.c linux-2.6.33.3/drivers/mtd/nand/rb4xx_nand.c
+--- linux-2.6.33.3.orig/drivers/mtd/nand/rb4xx_nand.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/drivers/mtd/nand/rb4xx_nand.c	2010-05-19 18:58:03.499116406 +0200
+@@ -0,0 +1,512 @@
++/*
++ *  NAND flash driver for the MikroTik RouterBoard 4xx series
++ *
++ *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  This file was based on the driver for Linux 2.6.22 published by
++ *  MikroTik for their RouterBoard 4xx series devices.
++ *
++ *  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/init.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <linux/gpio.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#define DRV_NAME        "rb4xx-nand"
++#define DRV_VERSION     "0.1.10"
++#define DRV_DESC        "NAND flash driver for RouterBoard 4xx series"
++
++#define USE_FAST_READ	1
++#define USE_FAST_WRITE	1
++#undef RB4XX_NAND_DEBUG
++
++#ifdef RB4XX_NAND_DEBUG
++#define DBG(fmt, arg...)	printk(KERN_DEBUG DRV_NAME ": " fmt, ## arg)
++#else
++#define DBG(fmt, arg...)	do {} while (0)
++#endif
++
++#define RB4XX_NAND_GPIO_RDY	5
++#define RB4XX_FLASH_HZ		33333334
++#define RB4XX_NAND_HZ		33333334
++
++#define SPI_CTRL_FASTEST	0x40
++#define SPI_CTRL_SAFE		0x43	/* 25 MHz for AHB 200 MHz */
++#define SBIT_IOC_BASE		SPI_IOC_CS1
++#define SBIT_IOC_DO_SHIFT	0
++#define SBIT_IOC_DO		(1u << SBIT_IOC_DO_SHIFT)
++#define SBIT_IOC_DO2_SHIFT	18
++#define SBIT_IOC_DO2		(1u << SBIT_IOC_DO2_SHIFT)
++
++#define CPLD_CMD_WRITE_MULT	0x08	/* send cmd, n x send data, read data */
++#define CPLD_CMD_WRITE_CFG	0x09	/* send cmd, n x send cfg */
++#define CPLD_CMD_READ_MULT	0x0a	/* send cmd, send idle, n x read data */
++#define CPLD_CMD_READ_FAST	0x0b	/* send cmd, 4 x idle, n x read data */
++
++#define CFG_BIT_nCE	0x80
++#define CFG_BIT_CLE	0x40
++#define CFG_BIT_ALE	0x20
++#define CFG_BIT_FAN	0x10
++#define CFG_BIT_nLED4	0x08
++#define CFG_BIT_nLED3	0x04
++#define CFG_BIT_nLED2	0x02
++#define CFG_BIT_nLED1	0x01
++
++#define CFG_BIT_nLEDS \
++	(CFG_BIT_nLED1 | CFG_BIT_nLED2 | CFG_BIT_nLED3 | CFG_BIT_nLED4)
++
++struct rb4xx_nand_info {
++	struct nand_chip	chip;
++	struct mtd_info		mtd;
++};
++
++/*
++ * We need to use the OLD Yaffs-1 OOB layout, otherwise the RB bootloader
++ * will not be able to find the kernel that we load.
++ */
++static struct nand_ecclayout rb4xx_nand_ecclayout = {
++	.eccbytes	= 6,
++	.eccpos		= { 8, 9, 10, 13, 14, 15 },
++	.oobavail	= 9,
++	.oobfree	= { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
++};
++
++static struct mtd_partition rb4xx_nand_partitions[] = {
++	{
++		.name	= "booter",
++		.offset	= 0,
++		.size	= (256 * 1024),
++		.mask_flags = MTD_WRITEABLE,
++	},
++	{
++		.name	= "kernel",
++		.offset	= (256 * 1024),
++		.size	= (4 * 1024 * 1024) - (256 * 1024),
++	},
++	{
++		.name	= "rootfs",
++		.offset	= MTDPART_OFS_NXTBLK,
++		.size	= (1024*1024*64) - (1024*256) - (4 * 1024 * 1024)
++	},
++	{
++		.name	= "cfgfs",
++		.offset	= (1024*1024*64) - (1024*256),
++		.size	= (1024*256),
++	},
++};
++
++#if USE_FAST_READ
++#define SPI_NDATA_BASE	0x00800000
++static unsigned spi_ctrl_fread = SPI_CTRL_SAFE;
++static unsigned spi_ctrl_flash = SPI_CTRL_SAFE;
++extern unsigned mips_hpt_frequency;
++#endif
++
++static inline unsigned rb4xx_spi_rreg(unsigned r)
++{
++	return __raw_readl((void * __iomem)(KSEG1ADDR(AR71XX_SPI_BASE) + r));
++}
++
++static inline void rb4xx_spi_wreg(unsigned r, unsigned v)
++{
++	__raw_writel(v, (void * __iomem)(KSEG1ADDR(AR71XX_SPI_BASE) + r));
++}
++
++static inline void do_spi_clk(int bit)
++{
++	unsigned bval = SBIT_IOC_BASE | (bit & 1);
++
++	rb4xx_spi_wreg(SPI_REG_IOC, bval);
++	rb4xx_spi_wreg(SPI_REG_IOC, bval | SPI_IOC_CLK);
++}
++
++static void do_spi_byte(uint8_t byte)
++{
++	do_spi_clk(byte >> 7);
++	do_spi_clk(byte >> 6);
++	do_spi_clk(byte >> 5);
++	do_spi_clk(byte >> 4);
++	do_spi_clk(byte >> 3);
++	do_spi_clk(byte >> 2);
++	do_spi_clk(byte >> 1);
++	do_spi_clk(byte);
++
++	DBG("spi_byte sent 0x%02x got 0x%x\n",
++					byte, rb4xx_spi_rreg(SPI_REG_RDS));
++}
++
++#if USE_FAST_WRITE
++static inline void do_spi_clk_fast(int bit1, int bit2)
++{
++	unsigned bval = (SBIT_IOC_BASE |
++			((bit1 << SBIT_IOC_DO_SHIFT) & SBIT_IOC_DO) |
++			((bit2 << SBIT_IOC_DO2_SHIFT) & SBIT_IOC_DO2));
++
++	rb4xx_spi_wreg(SPI_REG_IOC, bval);
++	rb4xx_spi_wreg(SPI_REG_IOC, bval | SPI_IOC_CLK);
++}
++
++static inline void do_spi_byte_fast(uint8_t byte)
++{
++	do_spi_clk_fast(byte >> 7, byte >> 6);
++	do_spi_clk_fast(byte >> 5, byte >> 4);
++	do_spi_clk_fast(byte >> 3, byte >> 2);
++	do_spi_clk_fast(byte >> 1, byte >> 0);
++
++	DBG("spi_byte_fast sent 0x%02x got 0x%x\n",
++					byte, rb4xx_spi_rreg(SPI_REG_RDS));
++}
++#else
++static inline void do_spi_byte_fast(uint8_t byte)
++{
++	do_spi_byte(byte);
++}
++#endif /* USE_FAST_WRITE */
++
++static int do_spi_cmd(unsigned cmd, unsigned sendCnt, const uint8_t *sendData,
++		unsigned recvCnt, uint8_t *recvData,
++		const uint8_t *verifyData, int fastWrite)
++{
++	unsigned i;
++
++	DBG("SPI cmd 0x%x send %u recv %u\n", cmd, sendCnt, recvCnt);
++
++	rb4xx_spi_wreg(SPI_REG_FS, SPI_FS_GPIO);
++	rb4xx_spi_wreg(SPI_REG_CTRL, SPI_CTRL_FASTEST);
++
++	do_spi_byte(cmd);
++#if 0
++	if (cmd == CPLD_CMD_READ_FAST) {
++		do_spi_byte(0x80);
++		do_spi_byte(0);
++		do_spi_byte(0);
++	}
++#endif
++	for (i = 0; i < sendCnt; ++i) {
++		if (fastWrite)
++			do_spi_byte_fast(sendData[i]);
++		else
++			do_spi_byte(sendData[i]);
++	}
++
++	for (i = 0; i < recvCnt; ++i) {
++		if (fastWrite)
++			do_spi_byte_fast(0);
++		else
++			do_spi_byte(0);
++
++		if (recvData) {
++			recvData[i] = rb4xx_spi_rreg(SPI_REG_RDS) & 0xff;
++		} else if (verifyData) {
++			if (verifyData[i] != (rb4xx_spi_rreg(SPI_REG_RDS)
++							 & 0xff))
++				break;
++		}
++	}
++
++	rb4xx_spi_wreg(SPI_REG_IOC, SBIT_IOC_BASE | SPI_IOC_CS0);
++	rb4xx_spi_wreg(SPI_REG_CTRL, spi_ctrl_flash);
++	rb4xx_spi_wreg(SPI_REG_FS, 0);
++
++	return i == recvCnt;
++}
++
++static int got_write = 1;
++
++static void rb4xx_nand_write_data(const uint8_t *byte, unsigned cnt)
++{
++	do_spi_cmd(CPLD_CMD_WRITE_MULT, cnt, byte, 1, NULL, NULL, 1);
++	got_write = 1;
++}
++
++static void rb4xx_nand_write_byte(uint8_t byte)
++{
++	rb4xx_nand_write_data(&byte, 1);
++}
++
++#if USE_FAST_READ
++static uint8_t *rb4xx_nand_read_getaddr(unsigned cnt)
++{
++	static unsigned nboffset = 0x100000;
++	unsigned addr;
++
++	if (got_write) {
++		nboffset = (nboffset + 31) & ~31;
++		if (nboffset >= 0x100000)	/* 1MB */
++			nboffset = 0;
++
++		got_write = 0;
++		rb4xx_spi_wreg(SPI_REG_FS, SPI_FS_GPIO);
++		rb4xx_spi_wreg(SPI_REG_CTRL, spi_ctrl_fread);
++		rb4xx_spi_wreg(SPI_REG_FS, 0);
++	}
++
++	addr = KSEG1ADDR(AR71XX_SPI_BASE + SPI_NDATA_BASE) + nboffset;
++	DBG("rb4xx_nand_read_getaddr 0x%x cnt 0x%x\n", addr, cnt);
++
++	nboffset += cnt;
++	return (uint8_t *)addr;
++}
++
++static void rb4xx_nand_read_data(uint8_t *buf, unsigned cnt)
++{
++	unsigned size32 = cnt & ~31;
++	unsigned remain = cnt & 31;
++
++	if (size32) {
++		uint8_t *addr = rb4xx_nand_read_getaddr(size32);
++		memcpy(buf, (void *)addr, size32);
++	}
++
++	if (remain) {
++		do_spi_cmd(CPLD_CMD_READ_MULT, 1, buf, remain,
++			   buf + size32, NULL, 0);
++	}
++}
++
++static int rb4xx_nand_verify_data(const uint8_t *buf, unsigned cnt)
++{
++	unsigned size32 = cnt & ~31;
++	unsigned remain = cnt & 31;
++
++	if (size32) {
++		uint8_t *addr = rb4xx_nand_read_getaddr(size32);
++		if (memcmp(buf, (void *)addr, size32) != 0)
++			return 0;
++	}
++
++	if (remain) {
++		return do_spi_cmd(CPLD_CMD_READ_MULT, 1, buf, remain,
++				  NULL, buf + size32, 0);
++	}
++	return 1;
++}
++#else /* USE_FAST_READ */
++static void rb4xx_nand_read_data(uint8_t *buf, unsigned cnt)
++{
++	do_spi_cmd(CPLD_CMD_READ_MULT, 1, buf, cnt, buf, NULL, 0);
++}
++
++static int rb4xx_nand_verify_data(const uint8_t *buf, unsigned cnt)
++{
++	return do_spi_cmd(CPLD_CMD_READ_MULT, 1, buf, cnt, NULL, buf, 0);
++}
++#endif /* USE_FAST_READ */
++
++static void rb4xx_nand_write_cfg(uint8_t byte)
++{
++	do_spi_cmd(CPLD_CMD_WRITE_CFG, 1, &byte, 0, NULL, NULL, 0);
++	got_write = 1;
++}
++
++static int rb4xx_nand_dev_ready(struct mtd_info *mtd)
++{
++	return gpio_get_value(RB4XX_NAND_GPIO_RDY);
++}
++
++static void rb4xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
++				unsigned int ctrl)
++{
++	if (ctrl & NAND_CTRL_CHANGE) {
++		uint8_t cfg = CFG_BIT_nLEDS;
++
++		cfg |= (ctrl & NAND_CLE) ? CFG_BIT_CLE : 0;
++		cfg |= (ctrl & NAND_ALE) ? CFG_BIT_ALE : 0;
++		cfg |= (ctrl & NAND_NCE) ? 0 : CFG_BIT_nCE;
++
++		rb4xx_nand_write_cfg(cfg);
++	}
++
++	if (cmd != NAND_CMD_NONE)
++		rb4xx_nand_write_byte(cmd);
++}
++
++static uint8_t rb4xx_nand_read_byte(struct mtd_info *mtd)
++{
++	uint8_t byte = 0;
++
++	rb4xx_nand_read_data(&byte, 1);
++	return byte;
++}
++
++static void rb4xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf,
++				int len)
++{
++	rb4xx_nand_write_data(buf, len);
++}
++
++static void rb4xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf,
++				int len)
++{
++	rb4xx_nand_read_data(buf, len);
++}
++
++static int rb4xx_nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf,
++				int len)
++{
++	if (!rb4xx_nand_verify_data(buf, len))
++		return -EFAULT;
++
++	return 0;
++}
++
++static unsigned get_spi_ctrl(unsigned hz_max, const char *name)
++{
++	unsigned div;
++
++	div = (ar71xx_ahb_freq - 1) / (2 * hz_max);
++	/*
++	 * CPU has a bug at (div == 0) - first bit read is random
++	 */
++	if (div == 0)
++		++div;
++
++	if (name) {
++		unsigned ahb_khz = (ar71xx_ahb_freq + 500) / 1000;
++		unsigned div_real = 2 * (div + 1);
++		printk(KERN_INFO "%s SPI clock %u kHz (AHB %u kHz / %u)\n",
++		       name,
++		       ahb_khz / div_real,
++		       ahb_khz, div_real);
++	}
++
++	return SPI_CTRL_FASTEST + div;
++}
++
++static int __init rb4xx_nand_probe(struct platform_device *pdev)
++{
++	struct rb4xx_nand_info	*info;
++	int ret;
++
++	printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n");
++
++	ret = gpio_request(RB4XX_NAND_GPIO_RDY, "NAND RDY");
++	if (ret) {
++		printk(KERN_ERR "rb4xx-nand: gpio request failed\n");
++		return ret;
++	}
++
++	ret = gpio_direction_input(RB4XX_NAND_GPIO_RDY);
++	if (ret) {
++		printk(KERN_ERR "rb4xx-nand: unable to set input mode "
++					"on gpio%d\n", RB4XX_NAND_GPIO_RDY);
++		goto err_free_gpio;
++	}
++
++	info = kzalloc(sizeof(*info), GFP_KERNEL);
++	if (!info) {
++		printk(KERN_ERR "rb4xx-nand: no memory for private data\n");
++		ret = -ENOMEM;
++		goto err_free_gpio;
++	}
++
++#if USE_FAST_READ
++	spi_ctrl_fread = get_spi_ctrl(RB4XX_NAND_HZ, "NAND");
++#endif
++	spi_ctrl_flash = get_spi_ctrl(RB4XX_FLASH_HZ, "FLASH");
++
++	rb4xx_nand_write_cfg(CFG_BIT_nLEDS | CFG_BIT_nCE);
++
++	info->chip.priv	= &info;
++	info->mtd.priv	= &info->chip;
++	info->mtd.owner	= THIS_MODULE;
++
++	info->chip.cmd_ctrl	= rb4xx_nand_cmd_ctrl;
++	info->chip.dev_ready	= rb4xx_nand_dev_ready;
++	info->chip.read_byte	= rb4xx_nand_read_byte;
++	info->chip.write_buf	= rb4xx_nand_write_buf;
++	info->chip.read_buf	= rb4xx_nand_read_buf;
++	info->chip.verify_buf	= rb4xx_nand_verify_buf;
++
++	info->chip.chip_delay	= 25;
++	info->chip.ecc.mode	= NAND_ECC_SOFT;
++	info->chip.options	|= NAND_NO_AUTOINCR;
++
++	platform_set_drvdata(pdev, info);
++
++	ret = nand_scan_ident(&info->mtd, 1);
++	if (ret) {
++		ret = -ENXIO;
++		goto err_free_info;
++	}
++
++	if (info->mtd.writesize == 512)
++		info->chip.ecc.layout = &rb4xx_nand_ecclayout;
++
++	ret = nand_scan_tail(&info->mtd);
++	if (ret) {
++		return -ENXIO;
++		goto err_set_drvdata;
++	}
++
++#ifdef CONFIG_MTD_PARTITIONS
++	ret = add_mtd_partitions(&info->mtd, rb4xx_nand_partitions,
++				ARRAY_SIZE(rb4xx_nand_partitions));
++#else
++	ret = add_mtd_device(&info->mtd);
++#endif
++	if (ret)
++		goto err_release_nand;
++
++	return 0;
++
++err_release_nand:
++	nand_release(&info->mtd);
++err_set_drvdata:
++	platform_set_drvdata(pdev, NULL);
++err_free_info:
++	kfree(info);
++err_free_gpio:
++	gpio_free(RB4XX_NAND_GPIO_RDY);
++	return ret;
++}
++
++static int __devexit rb4xx_nand_remove(struct platform_device *pdev)
++{
++	struct rb4xx_nand_info *info = platform_get_drvdata(pdev);
++
++	nand_release(&info->mtd);
++	platform_set_drvdata(pdev, NULL);
++	kfree(info);
++
++	return 0;
++}
++
++static struct platform_driver rb4xx_nand_driver = {
++	.probe	= rb4xx_nand_probe,
++	.remove	= __devexit_p(rb4xx_nand_remove),
++	.driver	= {
++		.name	= DRV_NAME,
++		.owner	= THIS_MODULE,
++	},
++};
++
++static int __init rb4xx_nand_init(void)
++{
++	return platform_driver_register(&rb4xx_nand_driver);
++}
++
++static void __exit rb4xx_nand_exit(void)
++{
++	platform_driver_unregister(&rb4xx_nand_driver);
++}
++
++module_init(rb4xx_nand_init);
++module_exit(rb4xx_nand_exit);
++
++MODULE_DESCRIPTION(DRV_DESC);
++MODULE_VERSION(DRV_VERSION);
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_AUTHOR("Imre Kaloz <kaloz@openwrt.org>");
++MODULE_LICENSE("GPL v2");
+diff -Nur linux-2.6.33.3.orig/drivers/mtd/nand/rb750_nand.c linux-2.6.33.3/drivers/mtd/nand/rb750_nand.c
+--- linux-2.6.33.3.orig/drivers/mtd/nand/rb750_nand.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/drivers/mtd/nand/rb750_nand.c	2010-03-12 19:31:47.026043474 +0100
+@@ -0,0 +1,360 @@
++/*
++ *  NAND flash driver for the MikroTik RouterBOARD 750
++ *
++ *  Copyright (C) 2010 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/init.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/mach-rb750.h>
++
++#define DRV_NAME	"rb750-nand"
++#define DRV_VERSION	"0.1.0"
++#define DRV_DESC	"NAND flash driver for the RouterBOARD 750"
++
++#define RB750_NAND_IO0		BIT(RB750_GPIO_NAND_IO0)
++#define RB750_NAND_ALE		BIT(RB750_GPIO_NAND_ALE)
++#define RB750_NAND_CLE		BIT(RB750_GPIO_NAND_CLE)
++#define RB750_NAND_NRE		BIT(RB750_GPIO_NAND_NRE)
++#define RB750_NAND_NWE		BIT(RB750_GPIO_NAND_NWE)
++#define RB750_NAND_RDY		BIT(RB750_GPIO_NAND_RDY)
++#define RB750_NAND_NCE		BIT(RB750_GPIO_NAND_NCE)
++
++#define RB750_NAND_DATA_SHIFT	1
++#define RB750_NAND_DATA_BITS	(0xff << RB750_NAND_DATA_SHIFT)
++#define RB750_NAND_INPUT_BITS	(RB750_NAND_DATA_BITS | RB750_NAND_RDY)
++#define RB750_NAND_OUTPUT_BITS	(RB750_NAND_ALE | RB750_NAND_CLE | \
++				 RB750_NAND_NRE | RB750_NAND_NWE | \
++				 RB750_NAND_NCE)
++
++struct rb750_nand_info {
++	struct nand_chip	chip;
++	struct mtd_info		mtd;
++};
++
++/*
++ * We need to use the OLD Yaffs-1 OOB layout, otherwise the RB bootloader
++ * will not be able to find the kernel that we load.
++ */
++static struct nand_ecclayout rb750_nand_ecclayout = {
++	.eccbytes	= 6,
++	.eccpos		= { 8, 9, 10, 13, 14, 15 },
++	.oobavail	= 9,
++	.oobfree	= { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
++};
++
++static struct mtd_partition rb750_nand_partitions[] = {
++	{
++		.name	= "booter",
++		.offset	= 0,
++		.size	= (256 * 1024),
++		.mask_flags = MTD_WRITEABLE,
++	}, {
++		.name	= "kernel",
++		.offset	= (256 * 1024),
++		.size	= (4 * 1024 * 1024) - (256 * 1024),
++	}, {
++		.name	= "rootfs",
++		.offset	= MTDPART_OFS_NXTBLK,
++		.size	= MTDPART_SIZ_FULL,
++	},
++};
++
++static void rb750_nand_write(const u8 *buf, unsigned len)
++{
++	void __iomem *base = ar71xx_gpio_base;
++	u32 out;
++	unsigned i;
++
++	/* set data lines to output mode */
++	__raw_writel(__raw_readl(base + GPIO_REG_OE) | RB750_NAND_DATA_BITS,
++		     base + GPIO_REG_OE);
++
++	out = __raw_readl(base + GPIO_REG_OUT);
++	out &= ~(RB750_NAND_DATA_BITS | RB750_NAND_NWE);
++	for (i = 0; i != len; i++) {
++		u32 data;
++
++		data = buf[i];
++		data <<= RB750_NAND_DATA_SHIFT;
++		data |= out;
++		__raw_writel(data, base + GPIO_REG_OUT);
++
++		__raw_writel(data | RB750_NAND_NWE, base + GPIO_REG_OUT);
++		/* flush write */
++		__raw_readl(base + GPIO_REG_OUT);
++	}
++
++	/* set data lines to input mode */
++	__raw_writel(__raw_readl(base + GPIO_REG_OE) & ~RB750_NAND_DATA_BITS,
++		     base + GPIO_REG_OE);
++	/* flush write */
++	__raw_readl(base + GPIO_REG_OE);
++}
++
++static int rb750_nand_read_verify(u8 *read_buf, unsigned len,
++				  const u8 *verify_buf)
++{
++	void __iomem *base = ar71xx_gpio_base;
++	unsigned i;
++
++	for (i = 0; i < len; i++) {
++		u8 data;
++
++		/* activate RE line */
++		__raw_writel(RB750_NAND_NRE, base + GPIO_REG_CLEAR);
++		/* flush write */
++		__raw_readl(base + GPIO_REG_CLEAR);
++
++		/* read input lines */
++		data = __raw_readl(base + GPIO_REG_IN) >> RB750_NAND_DATA_SHIFT;
++
++		/* deactivate RE line */
++		__raw_writel(RB750_NAND_NRE, base + GPIO_REG_SET);
++
++		if (read_buf)
++			read_buf[i] = data;
++		else if (verify_buf && verify_buf[i] != data)
++			return -EFAULT;
++	}
++
++	return 0;
++}
++
++static void rb750_nand_select_chip(struct mtd_info *mtd, int chip)
++{
++	void __iomem *base = ar71xx_gpio_base;
++	u32 func;
++
++	func = __raw_readl(base + GPIO_REG_FUNC);
++	if (chip >= 0) {
++		/* disable latch */
++		rb750_latch_change(RB750_LVC573_LE, 0);
++
++		/* disable alternate functions */
++		ar71xx_gpio_function_setup(AR724X_GPIO_FUNC_JTAG_DISABLE,
++					   AR724X_GPIO_FUNC_SPI_EN);
++
++		/* set input mode for data lines */
++		__raw_writel(__raw_readl(base + GPIO_REG_OE) &
++			     ~RB750_NAND_INPUT_BITS,
++			     base + GPIO_REG_OE);
++
++		/* deactivate RE and WE lines */
++		__raw_writel(RB750_NAND_NRE | RB750_NAND_NWE,
++			     base + GPIO_REG_SET);
++		/* flush write */
++		(void) __raw_readl(base + GPIO_REG_SET);
++
++		/* activate CE line */
++		__raw_writel(RB750_NAND_NCE, base + GPIO_REG_CLEAR);
++	} else {
++		/* deactivate CE line */
++		__raw_writel(RB750_NAND_NCE, base + GPIO_REG_SET);
++		/* flush write */
++		(void) __raw_readl(base + GPIO_REG_SET);
++
++		__raw_writel(__raw_readl(base + GPIO_REG_OE) |
++			     RB750_NAND_IO0 | RB750_NAND_RDY,
++			     base + GPIO_REG_OE);
++
++		/* restore alternate functions */
++		ar71xx_gpio_function_setup(AR724X_GPIO_FUNC_SPI_EN,
++					   AR724X_GPIO_FUNC_JTAG_DISABLE);
++
++		/* enable latch */
++		rb750_latch_change(0, RB750_LVC573_LE);
++	}
++}
++
++static int rb750_nand_dev_ready(struct mtd_info *mtd)
++{
++	void __iomem *base = ar71xx_gpio_base;
++
++	return !!(__raw_readl(base + GPIO_REG_IN) & RB750_NAND_RDY);
++}
++
++static void rb750_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
++				unsigned int ctrl)
++{
++	if (ctrl & NAND_CTRL_CHANGE) {
++		void __iomem *base = ar71xx_gpio_base;
++		u32 t;
++
++		t = __raw_readl(base + GPIO_REG_OUT);
++
++		t &= ~(RB750_NAND_CLE | RB750_NAND_ALE);
++		t |= (ctrl & NAND_CLE) ? RB750_NAND_CLE : 0;
++		t |= (ctrl & NAND_ALE) ? RB750_NAND_ALE : 0;
++
++		__raw_writel(t, base + GPIO_REG_OUT);
++		/* flush write */
++		__raw_readl(base + GPIO_REG_OUT);
++	}
++
++	if (cmd != NAND_CMD_NONE) {
++		u8 t = cmd;
++		rb750_nand_write(&t, 1);
++	}
++}
++
++static u8 rb750_nand_read_byte(struct mtd_info *mtd)
++{
++	u8 data = 0;
++	rb750_nand_read_verify(&data, 1, NULL);
++	return data;
++}
++
++static void rb750_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
++{
++	rb750_nand_read_verify(buf, len, NULL);
++}
++
++static void rb750_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
++{
++	rb750_nand_write(buf, len);
++}
++
++static int rb750_nand_verify_buf(struct mtd_info *mtd, const u8 *buf, int len)
++{
++	return rb750_nand_read_verify(NULL, len, buf);
++}
++
++static void __init rb750_nand_gpio_init(void)
++{
++	void __iomem *base = ar71xx_gpio_base;
++	u32 out;
++
++	out = __raw_readl(base + GPIO_REG_OUT);
++
++	/* setup output levels */
++	__raw_writel(RB750_NAND_NCE | RB750_NAND_NRE | RB750_NAND_NWE,
++		     base + GPIO_REG_SET);
++
++	__raw_writel(RB750_NAND_ALE | RB750_NAND_CLE,
++		     base + GPIO_REG_CLEAR);
++
++	/* setup input lines */
++	__raw_writel(__raw_readl(base + GPIO_REG_OE) & ~(RB750_NAND_INPUT_BITS),
++		     base + GPIO_REG_OE);
++
++	/* setup output lines */
++	__raw_writel(__raw_readl(base + GPIO_REG_OE) | RB750_NAND_OUTPUT_BITS,
++		     base + GPIO_REG_OE);
++
++	rb750_latch_change(~out & RB750_NAND_IO0, out & RB750_NAND_IO0);
++}
++
++static int __init rb750_nand_probe(struct platform_device *pdev)
++{
++	struct rb750_nand_info	*info;
++	int ret;
++
++	printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n");
++
++	rb750_nand_gpio_init();
++
++	info = kzalloc(sizeof(*info), GFP_KERNEL);
++	if (!info)
++		return -ENOMEM;
++
++	info->chip.priv	= &info;
++	info->mtd.priv	= &info->chip;
++	info->mtd.owner	= THIS_MODULE;
++
++	info->chip.select_chip	= rb750_nand_select_chip;
++	info->chip.cmd_ctrl	= rb750_nand_cmd_ctrl;
++	info->chip.dev_ready	= rb750_nand_dev_ready;
++	info->chip.read_byte	= rb750_nand_read_byte;
++	info->chip.write_buf	= rb750_nand_write_buf;
++	info->chip.read_buf	= rb750_nand_read_buf;
++	info->chip.verify_buf	= rb750_nand_verify_buf;
++
++	info->chip.chip_delay	= 25;
++	info->chip.ecc.mode	= NAND_ECC_SOFT;
++	info->chip.options	|= NAND_NO_AUTOINCR;
++
++	platform_set_drvdata(pdev, info);
++
++	ret = nand_scan_ident(&info->mtd, 1);
++	if (ret) {
++		ret = -ENXIO;
++		goto err_free_info;
++	}
++
++	if (info->mtd.writesize == 512)
++		info->chip.ecc.layout = &rb750_nand_ecclayout;
++
++	ret = nand_scan_tail(&info->mtd);
++	if (ret) {
++		return -ENXIO;
++		goto err_set_drvdata;
++	}
++
++#ifdef CONFIG_MTD_PARTITIONS
++	ret = add_mtd_partitions(&info->mtd, rb750_nand_partitions,
++				 ARRAY_SIZE(rb750_nand_partitions));
++#else
++	ret = add_mtd_device(&info->mtd);
++#endif
++	if (ret)
++		goto err_release_nand;
++
++	return 0;
++
++ err_release_nand:
++	nand_release(&info->mtd);
++ err_set_drvdata:
++	platform_set_drvdata(pdev, NULL);
++ err_free_info:
++	kfree(info);
++	return ret;
++}
++
++static int __devexit rb750_nand_remove(struct platform_device *pdev)
++{
++	struct rb750_nand_info *info = platform_get_drvdata(pdev);
++
++	nand_release(&info->mtd);
++	platform_set_drvdata(pdev, NULL);
++	kfree(info);
++
++	return 0;
++}
++
++static struct platform_driver rb750_nand_driver = {
++	.probe	= rb750_nand_probe,
++	.remove	= __devexit_p(rb750_nand_remove),
++	.driver	= {
++		.name	= DRV_NAME,
++		.owner	= THIS_MODULE,
++	},
++};
++
++static int __init rb750_nand_init(void)
++{
++	return platform_driver_register(&rb750_nand_driver);
++}
++
++static void __exit rb750_nand_exit(void)
++{
++	platform_driver_unregister(&rb750_nand_driver);
++}
++
++module_init(rb750_nand_init);
++module_exit(rb750_nand_exit);
++
++MODULE_DESCRIPTION(DRV_DESC);
++MODULE_VERSION(DRV_VERSION);
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_LICENSE("GPL v2");
+diff -Nur linux-2.6.33.3.orig/drivers/mtd/wrt160nl_part.c linux-2.6.33.3/drivers/mtd/wrt160nl_part.c
+--- linux-2.6.33.3.orig/drivers/mtd/wrt160nl_part.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/drivers/mtd/wrt160nl_part.c	2010-04-02 11:07:52.154964482 +0200
+@@ -0,0 +1,181 @@
++/*
++ * Copyright (C) 2009 Christian Daniel <cd@maintech.de>
++ * Copyright (C) 2009 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ *
++ * TRX flash partition table.
++ * Based on ar7 map by Felix Fietkau <nbd@openwrt.org>
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++struct cybertan_header {
++	char	magic[4];
++	u8	res1[4];
++	char	fw_date[3];
++	char	fw_ver[3];
++	char	id[4];
++	char	hw_ver;
++	char	unused;
++	u8	flags[2];
++	u8	res2[10];
++};
++
++#define TRX_PARTS	6
++#define TRX_MAGIC	0x30524448
++#define TRX_MAX_OFFSET	3
++
++struct trx_header {
++	uint32_t magic;           /* "HDR0" */
++	uint32_t len;             /* Length of file including header */
++	uint32_t crc32;           /* 32-bit CRC from flag_version to end of file */
++	uint32_t flag_version;    /* 0:15 flags, 16:31 version */
++	uint32_t offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */
++};
++
++#define IH_MAGIC	0x27051956	/* Image Magic Number */
++#define IH_NMLEN	32		/* Image Name Length */
++
++struct uimage_header {
++	uint32_t	ih_magic;	/* Image Header Magic Number */
++	uint32_t	ih_hcrc;	/* Image Header CRC Checksum */
++	uint32_t	ih_time;	/* Image Creation Timestamp */
++	uint32_t	ih_size;	/* Image Data Size */
++	uint32_t	ih_load;	/* Data» Load  Address */
++	uint32_t	ih_ep;		/* Entry Point Address */
++	uint32_t	ih_dcrc;	/* Image Data CRC Checksum */
++	uint8_t		ih_os;		/* Operating System */
++	uint8_t		ih_arch;	/* CPU architecture */
++	uint8_t		ih_type;	/* Image Type */
++	uint8_t		ih_comp;	/* Compression Type */
++	uint8_t		ih_name[IH_NMLEN];	/* Image Name */
++};
++
++struct wrt160nl_header {
++	struct cybertan_header	cybertan;
++	struct trx_header	trx;
++	struct uimage_header	uimage;
++} __attribute__ ((packed));
++
++static struct mtd_partition trx_parts[TRX_PARTS];
++
++static int wrt160nl_parse_partitions(struct mtd_info *master,
++				     struct mtd_partition **pparts,
++				     unsigned long origin)
++{
++	struct wrt160nl_header *header;
++	struct trx_header *theader;
++	struct uimage_header *uheader;
++	size_t retlen;
++	unsigned int kernel_len;
++	int ret;
++
++	header = vmalloc(sizeof(*header));
++	if (!header) {
++		return -ENOMEM;
++		goto out;
++	}
++
++	ret = master->read(master, 4 * master->erasesize, sizeof(*header),
++			   &retlen, (void *) header);
++	if (ret)
++		goto free_hdr;
++
++	if (retlen != sizeof(*header)) {
++		ret = -EIO;
++		goto free_hdr;
++	}
++
++	if (strncmp(header->cybertan.magic, "NL16", 4) != 0) {
++		printk(KERN_NOTICE "%s: no WRT160NL signature found\n",
++			master->name);
++		goto free_hdr;
++	}
++
++	theader = &header->trx;
++	if (le32_to_cpu(theader->magic) != TRX_MAGIC) {
++		printk(KERN_NOTICE "%s: no TRX header found\n", master->name);
++		goto free_hdr;
++	}
++
++	uheader = &header->uimage;
++	if (uheader->ih_magic != IH_MAGIC) {
++		printk(KERN_NOTICE "%s: no uImage found\n", master->name);
++		goto free_hdr;
++	}
++
++	kernel_len = le32_to_cpu(theader->offsets[1]) + sizeof(struct cybertan_header);
++
++	trx_parts[0].name = "u-boot";
++	trx_parts[0].offset = 0;
++	trx_parts[0].size = 4 * master->erasesize;
++	trx_parts[0].mask_flags = MTD_WRITEABLE;
++
++	trx_parts[1].name = "kernel";
++	trx_parts[1].offset = trx_parts[0].offset + trx_parts[0].size;
++	trx_parts[1].size = kernel_len;
++	trx_parts[1].mask_flags = 0;
++
++	trx_parts[2].name = "rootfs";
++	trx_parts[2].offset = trx_parts[1].offset + trx_parts[1].size;
++	trx_parts[2].size = master->size - 6 * master->erasesize - trx_parts[1].size;
++	trx_parts[2].mask_flags = 0;
++
++	trx_parts[3].name = "nvram";
++	trx_parts[3].offset = master->size - 2 * master->erasesize;
++	trx_parts[3].size = master->erasesize;
++	trx_parts[3].mask_flags = MTD_WRITEABLE;
++
++	trx_parts[4].name = "art";
++	trx_parts[4].offset = master->size - master->erasesize;
++	trx_parts[4].size = master->erasesize;
++	trx_parts[4].mask_flags = MTD_WRITEABLE;
++
++	trx_parts[5].name = "firmware";
++	trx_parts[5].offset = 4 * master->erasesize;
++	trx_parts[5].size = master->size - 6 * master->erasesize;
++	trx_parts[5].mask_flags = 0;
++
++	*pparts = trx_parts;
++	ret = TRX_PARTS;
++
++ free_hdr:
++	vfree(header);
++ out:
++	return ret;
++}
++
++static struct mtd_part_parser wrt160nl_parser = {
++	.owner		= THIS_MODULE,
++	.parse_fn	= wrt160nl_parse_partitions,
++	.name		= "wrt160nl",
++};
++
++static int __init wrt160nl_parser_init(void)
++{
++	return register_mtd_parser(&wrt160nl_parser);
++}
++
++module_init(wrt160nl_parser_init);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Christian Daniel <cd@maintech.de>");
+diff -Nur linux-2.6.33.3.orig/drivers/net/ag71xx/ag71xx_ar8216.c linux-2.6.33.3/drivers/net/ag71xx/ag71xx_ar8216.c
+--- linux-2.6.33.3.orig/drivers/net/ag71xx/ag71xx_ar8216.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/drivers/net/ag71xx/ag71xx_ar8216.c	2010-05-16 13:17:33.387600561 +0200
+@@ -0,0 +1,44 @@
++/*
++ *  Atheros AR71xx built-in ethernet mac driver
++ *  Special support for the Atheros ar8216 switch chip
++ *
++ *  Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  Based on Atheros' AG7100 driver
++ *
++ *  This program is free software; you can redistribute it and/or modify it
++ *  under the terms of the GNU General Public License version 2 as published
++ *  by the Free Software Foundation.
++ */
++
++#include "ag71xx.h"
++
++#define AR8216_PACKET_TYPE_MASK		0xf
++#define AR8216_PACKET_TYPE_NORMAL	0
++
++#define AR8216_HEADER_LEN	2
++
++void ag71xx_add_ar8216_header(struct ag71xx *ag, struct sk_buff *skb)
++{
++	skb_push(skb, AR8216_HEADER_LEN);
++	skb->data[0] = 0x10;
++	skb->data[1] = 0x80;
++}
++
++int ag71xx_remove_ar8216_header(struct ag71xx *ag, struct sk_buff *skb,
++				int pktlen)
++{
++	u8 type;
++
++	type = skb->data[1] & AR8216_PACKET_TYPE_MASK;
++	switch (type) {
++	case AR8216_PACKET_TYPE_NORMAL:
++		break;
++
++	default:
++		return -EINVAL;
++	}
++
++	skb_pull(skb, AR8216_HEADER_LEN);
++	return 0;
++}
+diff -Nur linux-2.6.33.3.orig/drivers/net/ag71xx/ag71xx_debugfs.c linux-2.6.33.3/drivers/net/ag71xx/ag71xx_debugfs.c
+--- linux-2.6.33.3.orig/drivers/net/ag71xx/ag71xx_debugfs.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/drivers/net/ag71xx/ag71xx_debugfs.c	2010-01-11 19:25:55.893395656 +0100
+@@ -0,0 +1,197 @@
++/*
++ *  Atheros AR71xx built-in ethernet mac driver
++ *
++ *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  Based on Atheros' AG7100 driver
++ *
++ *  This program is free software; you can redistribute it and/or modify it
++ *  under the terms of the GNU General Public License version 2 as published
++ *  by the Free Software Foundation.
++ */
++
++#include <linux/debugfs.h>
++
++#include "ag71xx.h"
++
++static struct dentry *ag71xx_debugfs_root;
++
++static int ag71xx_debugfs_generic_open(struct inode *inode, struct file *file)
++{
++	file->private_data = inode->i_private;
++	return 0;
++}
++
++void ag71xx_debugfs_update_int_stats(struct ag71xx *ag, u32 status)
++{
++	if (status)
++		ag->debug.int_stats.total++;
++	if (status & AG71XX_INT_TX_PS)
++		ag->debug.int_stats.tx_ps++;
++	if (status & AG71XX_INT_TX_UR)
++		ag->debug.int_stats.tx_ur++;
++	if (status & AG71XX_INT_TX_BE)
++		ag->debug.int_stats.tx_be++;
++	if (status & AG71XX_INT_RX_PR)
++		ag->debug.int_stats.rx_pr++;
++	if (status & AG71XX_INT_RX_OF)
++		ag->debug.int_stats.rx_of++;
++	if (status & AG71XX_INT_RX_BE)
++		ag->debug.int_stats.rx_be++;
++}
++
++static ssize_t read_file_int_stats(struct file *file, char __user *user_buf,
++				   size_t count, loff_t *ppos)
++{
++#define PR_INT_STAT(_label, _field) 					\
++	len += snprintf(buf + len, sizeof(buf) - len, 			\
++		"%20s: %10lu\n", _label, ag->debug.int_stats._field);
++
++	struct ag71xx *ag = file->private_data;
++	char buf[256];
++	unsigned int len = 0;
++
++	PR_INT_STAT("TX Packet Sent", tx_ps);
++	PR_INT_STAT("TX Underrun", tx_ur);
++	PR_INT_STAT("TX Bus Error", tx_be);
++	PR_INT_STAT("RX Packet Received", rx_pr);
++	PR_INT_STAT("RX Overflow", rx_of);
++	PR_INT_STAT("RX Bus Error", rx_be);
++	len += snprintf(buf + len, sizeof(buf) - len, "\n");
++	PR_INT_STAT("Total", total);
++
++	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
++#undef PR_INT_STAT
++}
++
++static const struct file_operations ag71xx_fops_int_stats = {
++	.open	= ag71xx_debugfs_generic_open,
++	.read	= read_file_int_stats,
++	.owner	= THIS_MODULE
++};
++
++void ag71xx_debugfs_update_napi_stats(struct ag71xx *ag, int rx, int tx)
++{
++	struct ag71xx_napi_stats *stats = &ag->debug.napi_stats;
++
++	if (rx) {
++		stats->rx_count++;
++		stats->rx_packets += rx;
++		if (rx <= AG71XX_NAPI_WEIGHT)
++			stats->rx[rx]++;
++		if (rx > stats->rx_packets_max)
++			stats->rx_packets_max = rx;
++	}
++
++	if (tx) {
++		stats->tx_count++;
++		stats->tx_packets += tx;
++		if (tx <= AG71XX_NAPI_WEIGHT)
++			stats->tx[tx]++;
++		if (tx > stats->tx_packets_max)
++			stats->tx_packets_max = tx;
++	}
++}
++
++static ssize_t read_file_napi_stats(struct file *file, char __user *user_buf,
++				    size_t count, loff_t *ppos)
++{
++	struct ag71xx *ag = file->private_data;
++	struct ag71xx_napi_stats *stats = &ag->debug.napi_stats;
++	char buf[2048];
++	unsigned int len = 0;
++	unsigned long rx_avg = 0;
++	unsigned long tx_avg = 0;
++	int i;
++
++	if (stats->rx_count)
++		rx_avg = stats->rx_packets / stats->rx_count;
++
++	if (stats->tx_count)
++		tx_avg = stats->tx_packets / stats->tx_count;
++
++	len += snprintf(buf + len, sizeof(buf) - len, "%3s  %10s %10s\n",
++			"len", "rx", "tx");
++
++	for (i = 1; i <= AG71XX_NAPI_WEIGHT; i++)
++		len += snprintf(buf + len, sizeof(buf) - len,
++				"%3d: %10lu %10lu\n",
++				i, stats->rx[i], stats->tx[i]);
++
++	len += snprintf(buf + len, sizeof(buf) - len, "\n");
++
++	len += snprintf(buf + len, sizeof(buf) - len, "%3s: %10lu %10lu\n",
++			"sum", stats->rx_count, stats->tx_count);
++	len += snprintf(buf + len, sizeof(buf) - len, "%3s: %10lu %10lu\n",
++			"avg", rx_avg, tx_avg);
++	len += snprintf(buf + len, sizeof(buf) - len, "%3s: %10lu %10lu\n",
++			"max", stats->rx_packets_max, stats->tx_packets_max);
++	len += snprintf(buf + len, sizeof(buf) - len, "%3s: %10lu %10lu\n",
++			"pkt", stats->rx_packets, stats->tx_packets);
++
++	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
++}
++
++static const struct file_operations ag71xx_fops_napi_stats = {
++	.open	= ag71xx_debugfs_generic_open,
++	.read	= read_file_napi_stats,
++	.owner	= THIS_MODULE
++};
++
++void ag71xx_debugfs_exit(struct ag71xx *ag)
++{
++	debugfs_remove(ag->debug.debugfs_napi_stats);
++	debugfs_remove(ag->debug.debugfs_int_stats);
++	debugfs_remove(ag->debug.debugfs_dir);
++}
++
++int ag71xx_debugfs_init(struct ag71xx *ag)
++{
++	ag->debug.debugfs_dir = debugfs_create_dir(ag->dev->name,
++						   ag71xx_debugfs_root);
++	if (!ag->debug.debugfs_dir)
++		goto err;
++
++	ag->debug.debugfs_int_stats =
++			debugfs_create_file("int_stats",
++					    S_IRUGO,
++					    ag->debug.debugfs_dir,
++					    ag,
++					    &ag71xx_fops_int_stats);
++	if (!ag->debug.debugfs_int_stats)
++		goto err;
++
++	ag->debug.debugfs_napi_stats =
++			debugfs_create_file("napi_stats",
++					    S_IRUGO,
++					    ag->debug.debugfs_dir,
++					    ag,
++					    &ag71xx_fops_napi_stats);
++	if (!ag->debug.debugfs_napi_stats)
++		goto err;
++
++	return 0;
++
++ err:
++	ag71xx_debugfs_exit(ag);
++	return -ENOMEM;
++}
++
++int ag71xx_debugfs_root_init(void)
++{
++	if (ag71xx_debugfs_root)
++		return -EBUSY;
++
++	ag71xx_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
++	if (!ag71xx_debugfs_root)
++		return -ENOENT;
++
++	return 0;
++}
++
++void ag71xx_debugfs_root_exit(void)
++{
++	debugfs_remove(ag71xx_debugfs_root);
++	ag71xx_debugfs_root = NULL;
++}
+diff -Nur linux-2.6.33.3.orig/drivers/net/ag71xx/ag71xx_ethtool.c linux-2.6.33.3/drivers/net/ag71xx/ag71xx_ethtool.c
+--- linux-2.6.33.3.orig/drivers/net/ag71xx/ag71xx_ethtool.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/drivers/net/ag71xx/ag71xx_ethtool.c	2010-01-05 20:38:53.433277722 +0100
+@@ -0,0 +1,71 @@
++/*
++ *  Atheros AR71xx built-in ethernet mac driver
++ *
++ *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  Based on Atheros' AG7100 driver
++ *
++ *  This program is free software; you can redistribute it and/or modify it
++ *  under the terms of the GNU General Public License version 2 as published
++ *  by the Free Software Foundation.
++ */
++
++#include "ag71xx.h"
++
++static int ag71xx_ethtool_get_settings(struct net_device *dev,
++				       struct ethtool_cmd *cmd)
++{
++	struct ag71xx *ag = netdev_priv(dev);
++	struct phy_device *phydev = ag->phy_dev;
++
++	if (!phydev)
++		return -ENODEV;
++
++	return phy_ethtool_gset(phydev, cmd);
++}
++
++static int ag71xx_ethtool_set_settings(struct net_device *dev,
++				       struct ethtool_cmd *cmd)
++{
++	struct ag71xx *ag = netdev_priv(dev);
++	struct phy_device *phydev = ag->phy_dev;
++
++	if (!phydev)
++		return -ENODEV;
++
++	return phy_ethtool_sset(phydev, cmd);
++}
++
++static void ag71xx_ethtool_get_drvinfo(struct net_device *dev,
++				       struct ethtool_drvinfo *info)
++{
++	struct ag71xx *ag = netdev_priv(dev);
++
++	strcpy(info->driver, ag->pdev->dev.driver->name);
++	strcpy(info->version, AG71XX_DRV_VERSION);
++	strcpy(info->bus_info, dev_name(&ag->pdev->dev));
++}
++
++static u32 ag71xx_ethtool_get_msglevel(struct net_device *dev)
++{
++	struct ag71xx *ag = netdev_priv(dev);
++
++	return ag->msg_enable;
++}
++
++static void ag71xx_ethtool_set_msglevel(struct net_device *dev, u32 msg_level)
++{
++	struct ag71xx *ag = netdev_priv(dev);
++
++	ag->msg_enable = msg_level;
++}
++
++struct ethtool_ops ag71xx_ethtool_ops = {
++	.set_settings	= ag71xx_ethtool_set_settings,
++	.get_settings	= ag71xx_ethtool_get_settings,
++	.get_drvinfo	= ag71xx_ethtool_get_drvinfo,
++	.get_msglevel	= ag71xx_ethtool_get_msglevel,
++	.set_msglevel	= ag71xx_ethtool_set_msglevel,
++	.get_link	= ethtool_op_get_link,
++};
+diff -Nur linux-2.6.33.3.orig/drivers/net/ag71xx/ag71xx.h linux-2.6.33.3/drivers/net/ag71xx/ag71xx.h
+--- linux-2.6.33.3.orig/drivers/net/ag71xx/ag71xx.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/drivers/net/ag71xx/ag71xx.h	2010-04-14 21:17:13.718345809 +0200
+@@ -0,0 +1,500 @@
++/*
++ *  Atheros AR71xx built-in ethernet mac driver
++ *
++ *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  Based on Atheros' AG7100 driver
++ *
++ *  This program is free software; you can redistribute it and/or modify it
++ *  under the terms of the GNU General Public License version 2 as published
++ *  by the Free Software Foundation.
++ */
++
++#ifndef __AG71XX_H
++#define __AG71XX_H
++
++#include <linux/kernel.h>
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/random.h>
++#include <linux/spinlock.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++#include <linux/ethtool.h>
++#include <linux/etherdevice.h>
++#include <linux/phy.h>
++#include <linux/skbuff.h>
++#include <linux/dma-mapping.h>
++#include <linux/workqueue.h>
++
++#include <linux/bitops.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/platform.h>
++
++#define ETH_FCS_LEN	4
++
++#define AG71XX_DRV_NAME		"ag71xx"
++#define AG71XX_DRV_VERSION	"0.5.35"
++
++#define AG71XX_NAPI_WEIGHT	64
++#define AG71XX_OOM_REFILL	(1 + HZ/10)
++
++#define AG71XX_INT_ERR	(AG71XX_INT_RX_BE | AG71XX_INT_TX_BE)
++#define AG71XX_INT_TX	(AG71XX_INT_TX_PS)
++#define AG71XX_INT_RX	(AG71XX_INT_RX_PR | AG71XX_INT_RX_OF)
++
++#define AG71XX_INT_POLL	(AG71XX_INT_RX | AG71XX_INT_TX)
++#define AG71XX_INT_INIT	(AG71XX_INT_ERR | AG71XX_INT_POLL)
++
++#define AG71XX_TX_FIFO_LEN	2048
++#define AG71XX_TX_MTU_LEN	1536
++#define AG71XX_RX_PKT_RESERVE	64
++#define AG71XX_RX_PKT_SIZE	\
++	(AG71XX_RX_PKT_RESERVE + ETH_HLEN + ETH_FRAME_LEN + ETH_FCS_LEN)
++
++#define AG71XX_TX_RING_SIZE	64
++#define AG71XX_TX_THRES_STOP	(AG71XX_TX_RING_SIZE - 4)
++#define AG71XX_TX_THRES_WAKEUP	\
++		(AG71XX_TX_RING_SIZE - (AG71XX_TX_RING_SIZE / 4))
++
++#define AG71XX_RX_RING_SIZE	128
++
++#ifdef CONFIG_AG71XX_DEBUG
++#define DBG(fmt, args...)	printk(KERN_DEBUG fmt, ## args)
++#else
++#define DBG(fmt, args...)	do {} while (0)
++#endif
++
++#define ag71xx_assert(_cond)						\
++do {									\
++	if (_cond)							\
++		break;							\
++	printk("%s,%d: assertion failed\n", __FILE__, __LINE__);	\
++	BUG();								\
++} while (0)
++
++struct ag71xx_desc {
++	u32	data;
++	u32	ctrl;
++#define DESC_EMPTY	BIT(31)
++#define DESC_MORE	BIT(24)
++#define DESC_PKTLEN_M	0xfff
++	u32	next;
++	u32	pad;
++} __attribute__((aligned(4)));
++
++struct ag71xx_buf {
++	struct sk_buff		*skb;
++	struct ag71xx_desc 	*desc;
++	dma_addr_t		dma_addr;
++	u32			pad;
++};
++
++struct ag71xx_ring {
++	struct ag71xx_buf	*buf;
++	u8			*descs_cpu;
++	dma_addr_t		descs_dma;
++	unsigned int		desc_size;
++	unsigned int		curr;
++	unsigned int		dirty;
++	unsigned int		size;
++};
++
++struct ag71xx_mdio {
++	struct mii_bus		*mii_bus;
++	int			mii_irq[PHY_MAX_ADDR];
++	void __iomem		*mdio_base;
++	struct ag71xx_mdio_platform_data *pdata;
++};
++
++struct ag71xx_int_stats {
++	unsigned long		rx_pr;
++	unsigned long		rx_be;
++	unsigned long		rx_of;
++	unsigned long		tx_ps;
++	unsigned long		tx_be;
++	unsigned long		tx_ur;
++	unsigned long		total;
++};
++
++struct ag71xx_napi_stats {
++	unsigned long		napi_calls;
++	unsigned long		rx_count;
++	unsigned long		rx_packets;
++	unsigned long		rx_packets_max;
++	unsigned long		tx_count;
++	unsigned long		tx_packets;
++	unsigned long		tx_packets_max;
++
++	unsigned long		rx[AG71XX_NAPI_WEIGHT + 1];
++	unsigned long		tx[AG71XX_NAPI_WEIGHT + 1];
++};
++
++struct ag71xx_debug {
++	struct dentry		*debugfs_dir;
++	struct dentry		*debugfs_int_stats;
++	struct dentry		*debugfs_napi_stats;
++
++	struct ag71xx_int_stats int_stats;
++	struct ag71xx_napi_stats napi_stats;
++};
++
++struct ag71xx {
++	void __iomem		*mac_base;
++	void __iomem		*mii_ctrl;
++
++	spinlock_t		lock;
++	struct platform_device	*pdev;
++	struct net_device	*dev;
++	struct napi_struct	napi;
++	u32			msg_enable;
++
++	struct ag71xx_ring	rx_ring;
++	struct ag71xx_ring	tx_ring;
++
++	struct mii_bus		*mii_bus;
++	struct phy_device	*phy_dev;
++
++	unsigned int		link;
++	unsigned int		speed;
++	int 			duplex;
++
++	struct work_struct	restart_work;
++	struct timer_list	oom_timer;
++
++#ifdef CONFIG_AG71XX_DEBUG_FS
++	struct ag71xx_debug	debug;
++#endif
++};
++
++extern struct ethtool_ops ag71xx_ethtool_ops;
++void ag71xx_link_adjust(struct ag71xx *ag);
++
++int ag71xx_mdio_driver_init(void) __init;
++void ag71xx_mdio_driver_exit(void);
++
++int ag71xx_phy_connect(struct ag71xx *ag);
++void ag71xx_phy_disconnect(struct ag71xx *ag);
++void ag71xx_phy_start(struct ag71xx *ag);
++void ag71xx_phy_stop(struct ag71xx *ag);
++
++static inline struct ag71xx_platform_data *ag71xx_get_pdata(struct ag71xx *ag)
++{
++	return ag->pdev->dev.platform_data;
++}
++
++static inline int ag71xx_desc_empty(struct ag71xx_desc *desc)
++{
++	return ((desc->ctrl & DESC_EMPTY) != 0);
++}
++
++static inline int ag71xx_desc_pktlen(struct ag71xx_desc *desc)
++{
++	return (desc->ctrl & DESC_PKTLEN_M);
++}
++
++/* Register offsets */
++#define AG71XX_REG_MAC_CFG1	0x0000
++#define AG71XX_REG_MAC_CFG2	0x0004
++#define AG71XX_REG_MAC_IPG	0x0008
++#define AG71XX_REG_MAC_HDX	0x000c
++#define AG71XX_REG_MAC_MFL	0x0010
++#define AG71XX_REG_MII_CFG	0x0020
++#define AG71XX_REG_MII_CMD	0x0024
++#define AG71XX_REG_MII_ADDR	0x0028
++#define AG71XX_REG_MII_CTRL	0x002c
++#define AG71XX_REG_MII_STATUS	0x0030
++#define AG71XX_REG_MII_IND	0x0034
++#define AG71XX_REG_MAC_IFCTL	0x0038
++#define AG71XX_REG_MAC_ADDR1	0x0040
++#define AG71XX_REG_MAC_ADDR2	0x0044
++#define AG71XX_REG_FIFO_CFG0	0x0048
++#define AG71XX_REG_FIFO_CFG1	0x004c
++#define AG71XX_REG_FIFO_CFG2	0x0050
++#define AG71XX_REG_FIFO_CFG3	0x0054
++#define AG71XX_REG_FIFO_CFG4	0x0058
++#define AG71XX_REG_FIFO_CFG5	0x005c
++#define AG71XX_REG_FIFO_RAM0	0x0060
++#define AG71XX_REG_FIFO_RAM1	0x0064
++#define AG71XX_REG_FIFO_RAM2	0x0068
++#define AG71XX_REG_FIFO_RAM3	0x006c
++#define AG71XX_REG_FIFO_RAM4	0x0070
++#define AG71XX_REG_FIFO_RAM5	0x0074
++#define AG71XX_REG_FIFO_RAM6	0x0078
++#define AG71XX_REG_FIFO_RAM7	0x007c
++
++#define AG71XX_REG_TX_CTRL	0x0180
++#define AG71XX_REG_TX_DESC	0x0184
++#define AG71XX_REG_TX_STATUS	0x0188
++#define AG71XX_REG_RX_CTRL	0x018c
++#define AG71XX_REG_RX_DESC	0x0190
++#define AG71XX_REG_RX_STATUS	0x0194
++#define AG71XX_REG_INT_ENABLE	0x0198
++#define AG71XX_REG_INT_STATUS	0x019c
++
++#define MAC_CFG1_TXE		BIT(0)	/* Tx Enable */
++#define MAC_CFG1_STX		BIT(1)	/* Synchronize Tx Enable */
++#define MAC_CFG1_RXE		BIT(2)	/* Rx Enable */
++#define MAC_CFG1_SRX		BIT(3)	/* Synchronize Rx Enable */
++#define MAC_CFG1_TFC		BIT(4)	/* Tx Flow Control Enable */
++#define MAC_CFG1_RFC		BIT(5)	/* Rx Flow Control Enable */
++#define MAC_CFG1_LB		BIT(8)	/* Loopback mode */
++#define MAC_CFG1_SR		BIT(31)	/* Soft Reset */
++
++#define MAC_CFG2_FDX		BIT(0)
++#define MAC_CFG2_CRC_EN		BIT(1)
++#define MAC_CFG2_PAD_CRC_EN	BIT(2)
++#define MAC_CFG2_LEN_CHECK	BIT(4)
++#define MAC_CFG2_HUGE_FRAME_EN	BIT(5)
++#define MAC_CFG2_IF_1000	BIT(9)
++#define MAC_CFG2_IF_10_100	BIT(8)
++
++#define FIFO_CFG0_WTM		BIT(0)	/* Watermark Module */
++#define FIFO_CFG0_RXS		BIT(1)	/* Rx System Module */
++#define FIFO_CFG0_RXF		BIT(2)	/* Rx Fabric Module */
++#define FIFO_CFG0_TXS		BIT(3)	/* Tx System Module */
++#define FIFO_CFG0_TXF		BIT(4)	/* Tx Fabric Module */
++#define FIFO_CFG0_ALL	(FIFO_CFG0_WTM | FIFO_CFG0_RXS | FIFO_CFG0_RXF \
++			| FIFO_CFG0_TXS | FIFO_CFG0_TXF)
++
++#define FIFO_CFG0_ENABLE_SHIFT	8
++
++#define FIFO_CFG4_DE		BIT(0)	/* Drop Event */
++#define FIFO_CFG4_DV		BIT(1)	/* RX_DV Event */
++#define FIFO_CFG4_FC		BIT(2)	/* False Carrier */
++#define FIFO_CFG4_CE		BIT(3)	/* Code Error */
++#define FIFO_CFG4_CR		BIT(4)	/* CRC error */
++#define FIFO_CFG4_LM		BIT(5)	/* Length Mismatch */
++#define FIFO_CFG4_LO		BIT(6)	/* Length out of range */
++#define FIFO_CFG4_OK		BIT(7)	/* Packet is OK */
++#define FIFO_CFG4_MC		BIT(8)	/* Multicast Packet */
++#define FIFO_CFG4_BC		BIT(9)	/* Broadcast Packet */
++#define FIFO_CFG4_DR		BIT(10)	/* Dribble */
++#define FIFO_CFG4_LE		BIT(11)	/* Long Event */
++#define FIFO_CFG4_CF		BIT(12)	/* Control Frame */
++#define FIFO_CFG4_PF		BIT(13)	/* Pause Frame */
++#define FIFO_CFG4_UO		BIT(14)	/* Unsupported Opcode */
++#define FIFO_CFG4_VT		BIT(15)	/* VLAN tag detected */
++#define FIFO_CFG4_FT		BIT(16)	/* Frame Truncated */
++#define FIFO_CFG4_UC		BIT(17)	/* Unicast Packet */
++
++#define FIFO_CFG5_DE		BIT(0)	/* Drop Event */
++#define FIFO_CFG5_DV		BIT(1)	/* RX_DV Event */
++#define FIFO_CFG5_FC		BIT(2)	/* False Carrier */
++#define FIFO_CFG5_CE		BIT(3)	/* Code Error */
++#define FIFO_CFG5_LM		BIT(4)	/* Length Mismatch */
++#define FIFO_CFG5_LO		BIT(5)	/* Length Out of Range */
++#define FIFO_CFG5_OK		BIT(6)	/* Packet is OK */
++#define FIFO_CFG5_MC		BIT(7)	/* Multicast Packet */
++#define FIFO_CFG5_BC		BIT(8)	/* Broadcast Packet */
++#define FIFO_CFG5_DR		BIT(9)	/* Dribble */
++#define FIFO_CFG5_CF		BIT(10)	/* Control Frame */
++#define FIFO_CFG5_PF		BIT(11)	/* Pause Frame */
++#define FIFO_CFG5_UO		BIT(12)	/* Unsupported Opcode */
++#define FIFO_CFG5_VT		BIT(13)	/* VLAN tag detected */
++#define FIFO_CFG5_LE		BIT(14)	/* Long Event */
++#define FIFO_CFG5_FT		BIT(15)	/* Frame Truncated */
++#define FIFO_CFG5_16		BIT(16)	/* unknown */
++#define FIFO_CFG5_17		BIT(17)	/* unknown */
++#define FIFO_CFG5_SF		BIT(18)	/* Short Frame */
++#define FIFO_CFG5_BM		BIT(19)	/* Byte Mode */
++
++#define AG71XX_INT_TX_PS	BIT(0)
++#define AG71XX_INT_TX_UR	BIT(1)
++#define AG71XX_INT_TX_BE	BIT(3)
++#define AG71XX_INT_RX_PR	BIT(4)
++#define AG71XX_INT_RX_OF	BIT(6)
++#define AG71XX_INT_RX_BE	BIT(7)
++
++#define MAC_IFCTL_SPEED		BIT(16)
++
++#define MII_CFG_CLK_DIV_4	0
++#define MII_CFG_CLK_DIV_6	2
++#define MII_CFG_CLK_DIV_8	3
++#define MII_CFG_CLK_DIV_10	4
++#define MII_CFG_CLK_DIV_14	5
++#define MII_CFG_CLK_DIV_20	6
++#define MII_CFG_CLK_DIV_28	7
++#define MII_CFG_RESET		BIT(31)
++
++#define MII_CMD_WRITE		0x0
++#define MII_CMD_READ		0x1
++#define MII_ADDR_SHIFT		8
++#define MII_IND_BUSY		BIT(0)
++#define MII_IND_INVALID		BIT(2)
++
++#define TX_CTRL_TXE		BIT(0)	/* Tx Enable */
++
++#define TX_STATUS_PS		BIT(0)	/* Packet Sent */
++#define TX_STATUS_UR		BIT(1)	/* Tx Underrun */
++#define TX_STATUS_BE		BIT(3)	/* Bus Error */
++
++#define RX_CTRL_RXE		BIT(0)	/* Rx Enable */
++
++#define RX_STATUS_PR		BIT(0)	/* Packet Received */
++#define RX_STATUS_OF		BIT(2)	/* Rx Overflow */
++#define RX_STATUS_BE		BIT(3)	/* Bus Error */
++
++#define MII_CTRL_IF_MASK	3
++#define MII_CTRL_SPEED_SHIFT	4
++#define MII_CTRL_SPEED_MASK	3
++#define MII_CTRL_SPEED_10	0
++#define MII_CTRL_SPEED_100	1
++#define MII_CTRL_SPEED_1000	2
++
++static inline void ag71xx_check_reg_offset(struct ag71xx *ag, unsigned reg)
++{
++	switch (reg) {
++	case AG71XX_REG_MAC_CFG1 ... AG71XX_REG_MAC_MFL:
++	case AG71XX_REG_MAC_IFCTL ... AG71XX_REG_INT_STATUS:
++		break;
++
++	default:
++		BUG();
++	}
++}
++
++static inline void ag71xx_wr(struct ag71xx *ag, unsigned reg, u32 value)
++{
++	ag71xx_check_reg_offset(ag, reg);
++
++	__raw_writel(value, ag->mac_base + reg);
++	/* flush write */
++	(void) __raw_readl(ag->mac_base + reg);
++}
++
++static inline u32 ag71xx_rr(struct ag71xx *ag, unsigned reg)
++{
++	ag71xx_check_reg_offset(ag, reg);
++
++	return __raw_readl(ag->mac_base + reg);
++}
++
++static inline void ag71xx_sb(struct ag71xx *ag, unsigned reg, u32 mask)
++{
++	void __iomem *r;
++
++	ag71xx_check_reg_offset(ag, reg);
++
++	r = ag->mac_base + reg;
++	__raw_writel(__raw_readl(r) | mask, r);
++	/* flush write */
++	(void)__raw_readl(r);
++}
++
++static inline void ag71xx_cb(struct ag71xx *ag, unsigned reg, u32 mask)
++{
++	void __iomem *r;
++
++	ag71xx_check_reg_offset(ag, reg);
++
++	r = ag->mac_base + reg;
++	__raw_writel(__raw_readl(r) & ~mask, r);
++	/* flush write */
++	(void) __raw_readl(r);
++}
++
++static inline void ag71xx_int_enable(struct ag71xx *ag, u32 ints)
++{
++	ag71xx_sb(ag, AG71XX_REG_INT_ENABLE, ints);
++}
++
++static inline void ag71xx_int_disable(struct ag71xx *ag, u32 ints)
++{
++	ag71xx_cb(ag, AG71XX_REG_INT_ENABLE, ints);
++}
++
++static inline void ag71xx_mii_ctrl_wr(struct ag71xx *ag, u32 value)
++{
++	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++
++	if (pdata->is_ar724x)
++		return;
++
++	__raw_writel(value, ag->mii_ctrl);
++
++	/* flush write */
++	__raw_readl(ag->mii_ctrl);
++}
++
++static inline u32 ag71xx_mii_ctrl_rr(struct ag71xx *ag)
++{
++	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++
++	if (pdata->is_ar724x)
++		return 0xffffffff;
++
++	return __raw_readl(ag->mii_ctrl);
++}
++
++static void inline ag71xx_mii_ctrl_set_if(struct ag71xx *ag,
++					  unsigned int mii_if)
++{
++	u32 t;
++
++	t = ag71xx_mii_ctrl_rr(ag);
++	t &= ~(MII_CTRL_IF_MASK);
++	t |= (mii_if & MII_CTRL_IF_MASK);
++	ag71xx_mii_ctrl_wr(ag, t);
++}
++
++static void inline ag71xx_mii_ctrl_set_speed(struct ag71xx *ag,
++					     unsigned int speed)
++{
++	u32 t;
++
++	t = ag71xx_mii_ctrl_rr(ag);
++	t &= ~(MII_CTRL_SPEED_MASK << MII_CTRL_SPEED_SHIFT);
++	t |= (speed & MII_CTRL_SPEED_MASK) << MII_CTRL_SPEED_SHIFT;
++	ag71xx_mii_ctrl_wr(ag, t);
++}
++
++#ifdef CONFIG_AG71XX_AR8216_SUPPORT
++void ag71xx_add_ar8216_header(struct ag71xx *ag, struct sk_buff *skb);
++int ag71xx_remove_ar8216_header(struct ag71xx *ag, struct sk_buff *skb,
++				int pktlen);
++static inline int ag71xx_has_ar8216(struct ag71xx *ag)
++{
++	return ag71xx_get_pdata(ag)->has_ar8216;
++}
++#else
++static inline void ag71xx_add_ar8216_header(struct ag71xx *ag,
++					   struct sk_buff *skb)
++{
++}
++
++static inline int ag71xx_remove_ar8216_header(struct ag71xx *ag,
++					      struct sk_buff *skb,
++					      int pktlen)
++{
++	return 0;
++}
++static inline int ag71xx_has_ar8216(struct ag71xx *ag)
++{
++	return 0;
++}
++#endif
++
++#ifdef CONFIG_AG71XX_DEBUG_FS
++int ag71xx_debugfs_root_init(void);
++void ag71xx_debugfs_root_exit(void);
++int ag71xx_debugfs_init(struct ag71xx *ag);
++void ag71xx_debugfs_exit(struct ag71xx *ag);
++void ag71xx_debugfs_update_int_stats(struct ag71xx *ag, u32 status);
++void ag71xx_debugfs_update_napi_stats(struct ag71xx *ag, int rx, int tx);
++#else
++static inline int ag71xx_debugfs_root_init(void) { return 0; }
++static inline void ag71xx_debugfs_root_exit(void) {}
++static inline int ag71xx_debugfs_init(struct ag71xx *ag) { return 0; }
++static inline void ag71xx_debugfs_exit(struct ag71xx *ag) {}
++static inline void ag71xx_debugfs_update_int_stats(struct ag71xx *ag,
++						   u32 status) {}
++static inline void ag71xx_debugfs_update_napi_stats(struct ag71xx *ag,
++						    int rx, int tx) {}
++#endif /* CONFIG_AG71XX_DEBUG_FS */
++
++#endif /* _AG71XX_H */
+diff -Nur linux-2.6.33.3.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.33.3/drivers/net/ag71xx/ag71xx_main.c
+--- linux-2.6.33.3.orig/drivers/net/ag71xx/ag71xx_main.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/drivers/net/ag71xx/ag71xx_main.c	2010-05-16 13:17:33.403605954 +0200
+@@ -0,0 +1,1184 @@
++/*
++ *  Atheros AR71xx built-in ethernet mac driver
++ *
++ *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  Based on Atheros' AG7100 driver
++ *
++ *  This program is free software; you can redistribute it and/or modify it
++ *  under the terms of the GNU General Public License version 2 as published
++ *  by the Free Software Foundation.
++ */
++
++#include "ag71xx.h"
++
++#define AG71XX_DEFAULT_MSG_ENABLE	\
++	( NETIF_MSG_DRV 		\
++	| NETIF_MSG_PROBE		\
++	| NETIF_MSG_LINK		\
++	| NETIF_MSG_TIMER		\
++	| NETIF_MSG_IFDOWN		\
++	| NETIF_MSG_IFUP		\
++	| NETIF_MSG_RX_ERR		\
++	| NETIF_MSG_TX_ERR )
++
++static int ag71xx_msg_level = -1;
++
++module_param_named(msg_level, ag71xx_msg_level, int, 0);
++MODULE_PARM_DESC(msg_level, "Message level (-1=defaults,0=none,...,16=all)");
++
++static void ag71xx_dump_dma_regs(struct ag71xx *ag)
++{
++	DBG("%s: dma_tx_ctrl=%08x, dma_tx_desc=%08x, dma_tx_status=%08x\n",
++		ag->dev->name,
++		ag71xx_rr(ag, AG71XX_REG_TX_CTRL),
++		ag71xx_rr(ag, AG71XX_REG_TX_DESC),
++		ag71xx_rr(ag, AG71XX_REG_TX_STATUS));
++
++	DBG("%s: dma_rx_ctrl=%08x, dma_rx_desc=%08x, dma_rx_status=%08x\n",
++		ag->dev->name,
++		ag71xx_rr(ag, AG71XX_REG_RX_CTRL),
++		ag71xx_rr(ag, AG71XX_REG_RX_DESC),
++		ag71xx_rr(ag, AG71XX_REG_RX_STATUS));
++}
++
++static void ag71xx_dump_regs(struct ag71xx *ag)
++{
++	DBG("%s: mac_cfg1=%08x, mac_cfg2=%08x, ipg=%08x, hdx=%08x, mfl=%08x\n",
++		ag->dev->name,
++		ag71xx_rr(ag, AG71XX_REG_MAC_CFG1),
++		ag71xx_rr(ag, AG71XX_REG_MAC_CFG2),
++		ag71xx_rr(ag, AG71XX_REG_MAC_IPG),
++		ag71xx_rr(ag, AG71XX_REG_MAC_HDX),
++		ag71xx_rr(ag, AG71XX_REG_MAC_MFL));
++	DBG("%s: mac_ifctl=%08x, mac_addr1=%08x, mac_addr2=%08x\n",
++		ag->dev->name,
++		ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL),
++		ag71xx_rr(ag, AG71XX_REG_MAC_ADDR1),
++		ag71xx_rr(ag, AG71XX_REG_MAC_ADDR2));
++	DBG("%s: fifo_cfg0=%08x, fifo_cfg1=%08x, fifo_cfg2=%08x\n",
++		ag->dev->name,
++		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG0),
++		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG1),
++		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG2));
++	DBG("%s: fifo_cfg3=%08x, fifo_cfg4=%08x, fifo_cfg5=%08x\n",
++		ag->dev->name,
++		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG3),
++		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG4),
++		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5));
++}
++
++static inline void ag71xx_dump_intr(struct ag71xx *ag, char *label, u32 intr)
++{
++	DBG("%s: %s intr=%08x %s%s%s%s%s%s\n",
++		ag->dev->name, label, intr,
++		(intr & AG71XX_INT_TX_PS) ? "TXPS " : "",
++		(intr & AG71XX_INT_TX_UR) ? "TXUR " : "",
++		(intr & AG71XX_INT_TX_BE) ? "TXBE " : "",
++		(intr & AG71XX_INT_RX_PR) ? "RXPR " : "",
++		(intr & AG71XX_INT_RX_OF) ? "RXOF " : "",
++		(intr & AG71XX_INT_RX_BE) ? "RXBE " : "");
++}
++
++static void ag71xx_ring_free(struct ag71xx_ring *ring)
++{
++	kfree(ring->buf);
++
++	if (ring->descs_cpu)
++		dma_free_coherent(NULL, ring->size * ring->desc_size,
++				  ring->descs_cpu, ring->descs_dma);
++}
++
++static int ag71xx_ring_alloc(struct ag71xx_ring *ring, unsigned int size)
++{
++	int err;
++	int i;
++
++	ring->desc_size = sizeof(struct ag71xx_desc);
++	if (ring->desc_size % cache_line_size()) {
++		DBG("ag71xx: ring %p, desc size %u rounded to %u\n",
++			ring, ring->desc_size,
++			roundup(ring->desc_size, cache_line_size()));
++		ring->desc_size = roundup(ring->desc_size, cache_line_size());
++	}
++
++	ring->descs_cpu = dma_alloc_coherent(NULL, size * ring->desc_size,
++					     &ring->descs_dma, GFP_ATOMIC);
++	if (!ring->descs_cpu) {
++		err = -ENOMEM;
++		goto err;
++	}
++
++	ring->size = size;
++
++	ring->buf = kzalloc(size * sizeof(*ring->buf), GFP_KERNEL);
++	if (!ring->buf) {
++		err = -ENOMEM;
++		goto err;
++	}
++
++	for (i = 0; i < size; i++) {
++		ring->buf[i].desc = (struct ag71xx_desc *)&ring->descs_cpu[i * ring->desc_size];
++		DBG("ag71xx: ring %p, desc %d at %p\n",
++			ring, i, ring->buf[i].desc);
++	}
++
++	return 0;
++
++ err:
++	return err;
++}
++
++static void ag71xx_ring_tx_clean(struct ag71xx *ag)
++{
++	struct ag71xx_ring *ring = &ag->tx_ring;
++	struct net_device *dev = ag->dev;
++
++	while (ring->curr != ring->dirty) {
++		u32 i = ring->dirty % AG71XX_TX_RING_SIZE;
++
++		if (!ag71xx_desc_empty(ring->buf[i].desc)) {
++			ring->buf[i].desc->ctrl = 0;
++			dev->stats.tx_errors++;
++		}
++
++		if (ring->buf[i].skb)
++			dev_kfree_skb_any(ring->buf[i].skb);
++
++		ring->buf[i].skb = NULL;
++
++		ring->dirty++;
++	}
++
++	/* flush descriptors */
++	wmb();
++
++}
++
++static void ag71xx_ring_tx_init(struct ag71xx *ag)
++{
++	struct ag71xx_ring *ring = &ag->tx_ring;
++	int i;
++
++	for (i = 0; i < AG71XX_TX_RING_SIZE; i++) {
++		ring->buf[i].desc->next = (u32) (ring->descs_dma +
++			ring->desc_size * ((i + 1) % AG71XX_TX_RING_SIZE));
++
++		ring->buf[i].desc->ctrl = DESC_EMPTY;
++		ring->buf[i].skb = NULL;
++	}
++
++	/* flush descriptors */
++	wmb();
++
++	ring->curr = 0;
++	ring->dirty = 0;
++}
++
++static void ag71xx_ring_rx_clean(struct ag71xx *ag)
++{
++	struct ag71xx_ring *ring = &ag->rx_ring;
++	int i;
++
++	if (!ring->buf)
++		return;
++
++	for (i = 0; i < AG71XX_RX_RING_SIZE; i++)
++		if (ring->buf[i].skb) {
++			dma_unmap_single(&ag->dev->dev, ring->buf[i].dma_addr,
++					 AG71XX_RX_PKT_SIZE, DMA_FROM_DEVICE);
++			kfree_skb(ring->buf[i].skb);
++		}
++}
++
++static int ag71xx_rx_reserve(struct ag71xx *ag)
++{
++	int reserve = 0;
++
++	if (ag71xx_get_pdata(ag)->is_ar724x) {
++		if (!ag71xx_has_ar8216(ag))
++			reserve = 2;
++
++		if (ag->phy_dev)
++			reserve += 4 - (ag->phy_dev->pkt_align % 4);
++
++		reserve %= 4;
++	}
++
++	return reserve + AG71XX_RX_PKT_RESERVE;
++}
++
++
++static int ag71xx_ring_rx_init(struct ag71xx *ag)
++{
++	struct ag71xx_ring *ring = &ag->rx_ring;
++	unsigned int reserve = ag71xx_rx_reserve(ag);
++	unsigned int i;
++	int ret;
++
++	ret = 0;
++	for (i = 0; i < AG71XX_RX_RING_SIZE; i++) {
++		ring->buf[i].desc->next = (u32) (ring->descs_dma +
++			ring->desc_size * ((i + 1) % AG71XX_RX_RING_SIZE));
++
++		DBG("ag71xx: RX desc at %p, next is %08x\n",
++			ring->buf[i].desc,
++			ring->buf[i].desc->next);
++	}
++
++	for (i = 0; i < AG71XX_RX_RING_SIZE; i++) {
++		struct sk_buff *skb;
++		dma_addr_t dma_addr;
++
++		skb = dev_alloc_skb(AG71XX_RX_PKT_SIZE + reserve);
++		if (!skb) {
++			ret = -ENOMEM;
++			break;
++		}
++
++		skb->dev = ag->dev;
++		skb_reserve(skb, reserve);
++
++		dma_addr = dma_map_single(&ag->dev->dev, skb->data,
++					  AG71XX_RX_PKT_SIZE,
++					  DMA_FROM_DEVICE);
++		ring->buf[i].skb = skb;
++		ring->buf[i].dma_addr = dma_addr;
++		ring->buf[i].desc->data = (u32) dma_addr;
++		ring->buf[i].desc->ctrl = DESC_EMPTY;
++	}
++
++	/* flush descriptors */
++	wmb();
++
++	ring->curr = 0;
++	ring->dirty = 0;
++
++	return ret;
++}
++
++static int ag71xx_ring_rx_refill(struct ag71xx *ag)
++{
++	struct ag71xx_ring *ring = &ag->rx_ring;
++	unsigned int reserve = ag71xx_rx_reserve(ag);
++	unsigned int count;
++
++	count = 0;
++	for (; ring->curr - ring->dirty > 0; ring->dirty++) {
++		unsigned int i;
++
++		i = ring->dirty % AG71XX_RX_RING_SIZE;
++
++		if (ring->buf[i].skb == NULL) {
++			dma_addr_t dma_addr;
++			struct sk_buff *skb;
++
++			skb = dev_alloc_skb(AG71XX_RX_PKT_SIZE + reserve);
++			if (skb == NULL)
++				break;
++
++			skb_reserve(skb, reserve);
++			skb->dev = ag->dev;
++
++			dma_addr = dma_map_single(&ag->dev->dev, skb->data,
++						  AG71XX_RX_PKT_SIZE,
++						  DMA_FROM_DEVICE);
++
++			ring->buf[i].skb = skb;
++			ring->buf[i].dma_addr = dma_addr;
++			ring->buf[i].desc->data = (u32) dma_addr;
++		}
++
++		ring->buf[i].desc->ctrl = DESC_EMPTY;
++		count++;
++	}
++
++	/* flush descriptors */
++	wmb();
++
++	DBG("%s: %u rx descriptors refilled\n", ag->dev->name, count);
++
++	return count;
++}
++
++static int ag71xx_rings_init(struct ag71xx *ag)
++{
++	int ret;
++
++	ret = ag71xx_ring_alloc(&ag->tx_ring, AG71XX_TX_RING_SIZE);
++	if (ret)
++		return ret;
++
++	ag71xx_ring_tx_init(ag);
++
++	ret = ag71xx_ring_alloc(&ag->rx_ring, AG71XX_RX_RING_SIZE);
++	if (ret)
++		return ret;
++
++	ret = ag71xx_ring_rx_init(ag);
++	return ret;
++}
++
++static void ag71xx_rings_cleanup(struct ag71xx *ag)
++{
++	ag71xx_ring_rx_clean(ag);
++	ag71xx_ring_free(&ag->rx_ring);
++
++	ag71xx_ring_tx_clean(ag);
++	ag71xx_ring_free(&ag->tx_ring);
++}
++
++static unsigned char *ag71xx_speed_str(struct ag71xx *ag)
++{
++	switch (ag->speed) {
++	case SPEED_1000:
++		return "1000";
++	case SPEED_100:
++		return "100";
++	case SPEED_10:
++		return "10";
++	}
++
++	return "?";
++}
++
++void ag71xx_link_adjust(struct ag71xx *ag)
++{
++	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++	u32 cfg2;
++	u32 ifctl;
++	u32 fifo5;
++	u32 mii_speed;
++
++	if (!ag->link) {
++		netif_carrier_off(ag->dev);
++		if (netif_msg_link(ag))
++			printk(KERN_INFO "%s: link down\n", ag->dev->name);
++		return;
++	}
++
++	cfg2 = ag71xx_rr(ag, AG71XX_REG_MAC_CFG2);
++	cfg2 &= ~(MAC_CFG2_IF_1000 | MAC_CFG2_IF_10_100 | MAC_CFG2_FDX);
++	cfg2 |= (ag->duplex) ? MAC_CFG2_FDX : 0;
++
++	ifctl = ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL);
++	ifctl &= ~(MAC_IFCTL_SPEED);
++
++	fifo5 = ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5);
++	fifo5 &= ~FIFO_CFG5_BM;
++
++	switch (ag->speed) {
++	case SPEED_1000:
++		mii_speed =  MII_CTRL_SPEED_1000;
++		cfg2 |= MAC_CFG2_IF_1000;
++		fifo5 |= FIFO_CFG5_BM;
++		break;
++	case SPEED_100:
++		mii_speed = MII_CTRL_SPEED_100;
++		cfg2 |= MAC_CFG2_IF_10_100;
++		ifctl |= MAC_IFCTL_SPEED;
++		break;
++	case SPEED_10:
++		mii_speed = MII_CTRL_SPEED_10;
++		cfg2 |= MAC_CFG2_IF_10_100;
++		break;
++	default:
++		BUG();
++		return;
++	}
++
++	if (pdata->is_ar91xx)
++		ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, 0x00780fff);
++	else if (pdata->is_ar724x)
++		ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, pdata->fifo_cfg3);
++	else
++		ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, 0x008001ff);
++
++	if (pdata->set_pll)
++		pdata->set_pll(ag->speed);
++
++	ag71xx_mii_ctrl_set_speed(ag, mii_speed);
++
++	ag71xx_wr(ag, AG71XX_REG_MAC_CFG2, cfg2);
++	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, fifo5);
++	ag71xx_wr(ag, AG71XX_REG_MAC_IFCTL, ifctl);
++
++	netif_carrier_on(ag->dev);
++	if (netif_msg_link(ag))
++		printk(KERN_INFO "%s: link up (%sMbps/%s duplex)\n",
++			ag->dev->name,
++			ag71xx_speed_str(ag),
++			(DUPLEX_FULL == ag->duplex) ? "Full" : "Half");
++
++	DBG("%s: fifo_cfg0=%#x, fifo_cfg1=%#x, fifo_cfg2=%#x\n",
++		ag->dev->name,
++		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG0),
++		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG1),
++		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG2));
++
++	DBG("%s: fifo_cfg3=%#x, fifo_cfg4=%#x, fifo_cfg5=%#x\n",
++		ag->dev->name,
++		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG3),
++		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG4),
++		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5));
++
++	DBG("%s: mac_cfg2=%#x, mac_ifctl=%#x, mii_ctrl=%#x\n",
++		ag->dev->name,
++		ag71xx_rr(ag, AG71XX_REG_MAC_CFG2),
++		ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL),
++		ag71xx_mii_ctrl_rr(ag));
++}
++
++static void ag71xx_hw_set_macaddr(struct ag71xx *ag, unsigned char *mac)
++{
++	u32 t;
++
++	t = (((u32) mac[5]) << 24) | (((u32) mac[4]) << 16)
++	  | (((u32) mac[3]) << 8) | ((u32) mac[2]);
++
++	ag71xx_wr(ag, AG71XX_REG_MAC_ADDR1, t);
++
++	t = (((u32) mac[1]) << 24) | (((u32) mac[0]) << 16);
++	ag71xx_wr(ag, AG71XX_REG_MAC_ADDR2, t);
++}
++
++static void ag71xx_dma_reset(struct ag71xx *ag)
++{
++	u32 val;
++	int i;
++
++	ag71xx_dump_dma_regs(ag);
++
++	/* stop RX and TX */
++	ag71xx_wr(ag, AG71XX_REG_RX_CTRL, 0);
++	ag71xx_wr(ag, AG71XX_REG_TX_CTRL, 0);
++
++	/* clear descriptor addresses */
++	ag71xx_wr(ag, AG71XX_REG_TX_DESC, 0);
++	ag71xx_wr(ag, AG71XX_REG_RX_DESC, 0);
++
++	/* clear pending RX/TX interrupts */
++	for (i = 0; i < 256; i++) {
++		ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_PR);
++		ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_PS);
++	}
++
++	/* clear pending errors */
++	ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_BE | RX_STATUS_OF);
++	ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_BE | TX_STATUS_UR);
++
++	val = ag71xx_rr(ag, AG71XX_REG_RX_STATUS);
++	if (val)
++		printk(KERN_ALERT "%s: unable to clear DMA Rx status: %08x\n",
++			ag->dev->name, val);
++
++	val = ag71xx_rr(ag, AG71XX_REG_TX_STATUS);
++
++	/* mask out reserved bits */
++	val &= ~0xff000000;
++
++	if (val)
++		printk(KERN_ALERT "%s: unable to clear DMA Tx status: %08x\n",
++			ag->dev->name, val);
++
++	ag71xx_dump_dma_regs(ag);
++}
++
++#define MAC_CFG1_INIT	(MAC_CFG1_RXE | MAC_CFG1_TXE | \
++			 MAC_CFG1_SRX | MAC_CFG1_STX)
++
++#define FIFO_CFG0_INIT	(FIFO_CFG0_ALL << FIFO_CFG0_ENABLE_SHIFT)
++
++#define FIFO_CFG4_INIT	(FIFO_CFG4_DE | FIFO_CFG4_DV | FIFO_CFG4_FC | \
++			 FIFO_CFG4_CE | FIFO_CFG4_CR | FIFO_CFG4_LM | \
++			 FIFO_CFG4_LO | FIFO_CFG4_OK | FIFO_CFG4_MC | \
++			 FIFO_CFG4_BC | FIFO_CFG4_DR | FIFO_CFG4_LE | \
++			 FIFO_CFG4_CF | FIFO_CFG4_PF | FIFO_CFG4_UO | \
++			 FIFO_CFG4_VT)
++
++#define FIFO_CFG5_INIT	(FIFO_CFG5_DE | FIFO_CFG5_DV | FIFO_CFG5_FC | \
++			 FIFO_CFG5_CE | FIFO_CFG5_LO | FIFO_CFG5_OK | \
++			 FIFO_CFG5_MC | FIFO_CFG5_BC | FIFO_CFG5_DR | \
++			 FIFO_CFG5_CF | FIFO_CFG5_PF | FIFO_CFG5_VT | \
++			 FIFO_CFG5_LE | FIFO_CFG5_FT | FIFO_CFG5_16 | \
++			 FIFO_CFG5_17 | FIFO_CFG5_SF)
++
++static void ag71xx_hw_init(struct ag71xx *ag)
++{
++	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++
++	ag71xx_sb(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_SR);
++	udelay(20);
++
++	ar71xx_device_stop(pdata->reset_bit);
++	mdelay(100);
++	ar71xx_device_start(pdata->reset_bit);
++	mdelay(100);
++
++	/* setup MAC configuration registers */
++	if (pdata->is_ar724x)
++		ag71xx_wr(ag, AG71XX_REG_MAC_CFG1,
++			  MAC_CFG1_INIT | MAC_CFG1_TFC | MAC_CFG1_RFC);
++	else
++		ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_INIT);
++
++	ag71xx_sb(ag, AG71XX_REG_MAC_CFG2,
++		  MAC_CFG2_PAD_CRC_EN | MAC_CFG2_LEN_CHECK);
++
++	/* setup max frame length */
++	ag71xx_wr(ag, AG71XX_REG_MAC_MFL, AG71XX_TX_MTU_LEN);
++
++	/* setup MII interface type */
++	ag71xx_mii_ctrl_set_if(ag, pdata->mii_if);
++
++	/* setup FIFO configuration registers */
++	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG0, FIFO_CFG0_INIT);
++	if (pdata->is_ar724x) {
++		ag71xx_wr(ag, AG71XX_REG_FIFO_CFG1, pdata->fifo_cfg1);
++		ag71xx_wr(ag, AG71XX_REG_FIFO_CFG2, pdata->fifo_cfg2);
++	} else {
++		ag71xx_wr(ag, AG71XX_REG_FIFO_CFG1, 0x0fff0000);
++		ag71xx_wr(ag, AG71XX_REG_FIFO_CFG2, 0x00001fff);
++	}
++	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG4, FIFO_CFG4_INIT);
++	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, FIFO_CFG5_INIT);
++
++	ag71xx_dma_reset(ag);
++}
++
++static void ag71xx_hw_start(struct ag71xx *ag)
++{
++	/* start RX engine */
++	ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE);
++
++	/* enable interrupts */
++	ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, AG71XX_INT_INIT);
++}
++
++static void ag71xx_hw_stop(struct ag71xx *ag)
++{
++	/* disable all interrupts */
++	ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, 0);
++
++	ag71xx_dma_reset(ag);
++}
++
++static int ag71xx_open(struct net_device *dev)
++{
++	struct ag71xx *ag = netdev_priv(dev);
++	int ret;
++
++	ret = ag71xx_rings_init(ag);
++	if (ret)
++		goto err;
++
++	napi_enable(&ag->napi);
++
++	netif_carrier_off(dev);
++	ag71xx_phy_start(ag);
++
++	ag71xx_wr(ag, AG71XX_REG_TX_DESC, ag->tx_ring.descs_dma);
++	ag71xx_wr(ag, AG71XX_REG_RX_DESC, ag->rx_ring.descs_dma);
++
++	ag71xx_hw_set_macaddr(ag, dev->dev_addr);
++
++	ag71xx_hw_start(ag);
++
++	netif_start_queue(dev);
++
++	return 0;
++
++ err:
++	ag71xx_rings_cleanup(ag);
++	return ret;
++}
++
++static int ag71xx_stop(struct net_device *dev)
++{
++	struct ag71xx *ag = netdev_priv(dev);
++	unsigned long flags;
++
++	netif_carrier_off(dev);
++	ag71xx_phy_stop(ag);
++
++	spin_lock_irqsave(&ag->lock, flags);
++
++	netif_stop_queue(dev);
++
++	ag71xx_hw_stop(ag);
++
++	napi_disable(&ag->napi);
++	del_timer_sync(&ag->oom_timer);
++
++	spin_unlock_irqrestore(&ag->lock, flags);
++
++	ag71xx_rings_cleanup(ag);
++
++	return 0;
++}
++
++static netdev_tx_t ag71xx_hard_start_xmit(struct sk_buff *skb,
++					  struct net_device *dev)
++{
++	struct ag71xx *ag = netdev_priv(dev);
++	struct ag71xx_ring *ring = &ag->tx_ring;
++	struct ag71xx_desc *desc;
++	dma_addr_t dma_addr;
++	int i;
++
++	i = ring->curr % AG71XX_TX_RING_SIZE;
++	desc = ring->buf[i].desc;
++
++	if (!ag71xx_desc_empty(desc))
++		goto err_drop;
++
++	if (ag71xx_has_ar8216(ag))
++		ag71xx_add_ar8216_header(ag, skb);
++
++	if (skb->len <= 0) {
++		DBG("%s: packet len is too small\n", ag->dev->name);
++		goto err_drop;
++	}
++
++	dma_addr = dma_map_single(&dev->dev, skb->data, skb->len,
++				  DMA_TO_DEVICE);
++
++	ring->buf[i].skb = skb;
++
++	/* setup descriptor fields */
++	desc->data = (u32) dma_addr;
++	desc->ctrl = (skb->len & DESC_PKTLEN_M);
++
++	/* flush descriptor */
++	wmb();
++
++	ring->curr++;
++	if (ring->curr == (ring->dirty + AG71XX_TX_THRES_STOP)) {
++		DBG("%s: tx queue full\n", ag->dev->name);
++		netif_stop_queue(dev);
++	}
++
++	DBG("%s: packet injected into TX queue\n", ag->dev->name);
++
++	/* enable TX engine */
++	ag71xx_wr(ag, AG71XX_REG_TX_CTRL, TX_CTRL_TXE);
++
++	return NETDEV_TX_OK;
++
++ err_drop:
++	dev->stats.tx_dropped++;
++
++	dev_kfree_skb(skb);
++	return NETDEV_TX_OK;
++}
++
++static int ag71xx_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
++{
++	struct mii_ioctl_data *data = (struct mii_ioctl_data *) &ifr->ifr_data;
++	struct ag71xx *ag = netdev_priv(dev);
++	int ret;
++
++	switch (cmd) {
++	case SIOCETHTOOL:
++		if (ag->phy_dev == NULL)
++			break;
++
++		spin_lock_irq(&ag->lock);
++		ret = phy_ethtool_ioctl(ag->phy_dev, (void *) ifr->ifr_data);
++		spin_unlock_irq(&ag->lock);
++		return ret;
++
++	case SIOCSIFHWADDR:
++		if (copy_from_user
++			(dev->dev_addr, ifr->ifr_data, sizeof(dev->dev_addr)))
++			return -EFAULT;
++		return 0;
++
++	case SIOCGIFHWADDR:
++		if (copy_to_user
++			(ifr->ifr_data, dev->dev_addr, sizeof(dev->dev_addr)))
++			return -EFAULT;
++		return 0;
++
++	case SIOCGMIIPHY:
++	case SIOCGMIIREG:
++	case SIOCSMIIREG:
++		if (ag->phy_dev == NULL)
++			break;
++
++		return phy_mii_ioctl(ag->phy_dev, data, cmd);
++
++	default:
++		break;
++	}
++
++	return -EOPNOTSUPP;
++}
++
++static void ag71xx_oom_timer_handler(unsigned long data)
++{
++	struct net_device *dev = (struct net_device *) data;
++	struct ag71xx *ag = netdev_priv(dev);
++
++	napi_schedule(&ag->napi);
++}
++
++static void ag71xx_tx_timeout(struct net_device *dev)
++{
++	struct ag71xx *ag = netdev_priv(dev);
++
++	if (netif_msg_tx_err(ag))
++		printk(KERN_DEBUG "%s: tx timeout\n", ag->dev->name);
++
++	schedule_work(&ag->restart_work);
++}
++
++static void ag71xx_restart_work_func(struct work_struct *work)
++{
++	struct ag71xx *ag = container_of(work, struct ag71xx, restart_work);
++
++	ag71xx_stop(ag->dev);
++	ag71xx_open(ag->dev);
++}
++
++static int ag71xx_tx_packets(struct ag71xx *ag)
++{
++	struct ag71xx_ring *ring = &ag->tx_ring;
++	int sent;
++
++	DBG("%s: processing TX ring\n", ag->dev->name);
++
++	sent = 0;
++	while (ring->dirty != ring->curr) {
++		unsigned int i = ring->dirty % AG71XX_TX_RING_SIZE;
++		struct ag71xx_desc *desc = ring->buf[i].desc;
++		struct sk_buff *skb = ring->buf[i].skb;
++
++		if (!ag71xx_desc_empty(desc))
++			break;
++
++		ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_PS);
++
++		ag->dev->stats.tx_bytes += skb->len;
++		ag->dev->stats.tx_packets++;
++
++		dev_kfree_skb_any(skb);
++		ring->buf[i].skb = NULL;
++
++		ring->dirty++;
++		sent++;
++	}
++
++	DBG("%s: %d packets sent out\n", ag->dev->name, sent);
++
++	if ((ring->curr - ring->dirty) < AG71XX_TX_THRES_WAKEUP)
++		netif_wake_queue(ag->dev);
++
++	return sent;
++}
++
++static int ag71xx_rx_packets(struct ag71xx *ag, int limit)
++{
++	struct net_device *dev = ag->dev;
++	struct ag71xx_ring *ring = &ag->rx_ring;
++	int done = 0;
++
++	DBG("%s: rx packets, limit=%d, curr=%u, dirty=%u\n",
++			dev->name, limit, ring->curr, ring->dirty);
++
++	while (done < limit) {
++		unsigned int i = ring->curr % AG71XX_RX_RING_SIZE;
++		struct ag71xx_desc *desc = ring->buf[i].desc;
++		struct sk_buff *skb;
++		int pktlen;
++		int err = 0;
++
++		if (ag71xx_desc_empty(desc))
++			break;
++
++		if ((ring->dirty + AG71XX_RX_RING_SIZE) == ring->curr) {
++			ag71xx_assert(0);
++			break;
++		}
++
++		ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_PR);
++
++		skb = ring->buf[i].skb;
++		pktlen = ag71xx_desc_pktlen(desc);
++		pktlen -= ETH_FCS_LEN;
++
++		dma_unmap_single(&dev->dev, ring->buf[i].dma_addr,
++				 AG71XX_RX_PKT_SIZE, DMA_FROM_DEVICE);
++
++		dev->last_rx = jiffies;
++		dev->stats.rx_packets++;
++		dev->stats.rx_bytes += pktlen;
++
++		skb_put(skb, pktlen);
++		if (ag71xx_has_ar8216(ag))
++			err = ag71xx_remove_ar8216_header(ag, skb, pktlen);
++
++		if (err) {
++			dev->stats.rx_dropped++;
++			kfree_skb(skb);
++		} else {
++			skb->dev = dev;
++			skb->ip_summed = CHECKSUM_NONE;
++			if (ag->phy_dev) {
++				ag->phy_dev->netif_receive_skb(skb);
++			} else {
++				skb->protocol = eth_type_trans(skb, dev);
++				netif_receive_skb(skb);
++			}
++		}
++
++		ring->buf[i].skb = NULL;
++		done++;
++
++		ring->curr++;
++	}
++
++	ag71xx_ring_rx_refill(ag);
++
++	DBG("%s: rx finish, curr=%u, dirty=%u, done=%d\n",
++		dev->name, ring->curr, ring->dirty, done);
++
++	return done;
++}
++
++static int ag71xx_poll(struct napi_struct *napi, int limit)
++{
++	struct ag71xx *ag = container_of(napi, struct ag71xx, napi);
++	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++	struct net_device *dev = ag->dev;
++	struct ag71xx_ring *rx_ring;
++	unsigned long flags;
++	u32 status;
++	int tx_done;
++	int rx_done;
++
++	pdata->ddr_flush();
++	tx_done = ag71xx_tx_packets(ag);
++
++	DBG("%s: processing RX ring\n", dev->name);
++	rx_done = ag71xx_rx_packets(ag, limit);
++
++	ag71xx_debugfs_update_napi_stats(ag, rx_done, tx_done);
++
++	rx_ring = &ag->rx_ring;
++	if (rx_ring->buf[rx_ring->dirty % AG71XX_RX_RING_SIZE].skb == NULL)
++		goto oom;
++
++	status = ag71xx_rr(ag, AG71XX_REG_RX_STATUS);
++	if (unlikely(status & RX_STATUS_OF)) {
++		ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_OF);
++		dev->stats.rx_fifo_errors++;
++
++		/* restart RX */
++		ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE);
++	}
++
++	if (rx_done < limit) {
++		if (status & RX_STATUS_PR)
++			goto more;
++
++		status = ag71xx_rr(ag, AG71XX_REG_TX_STATUS);
++		if (status & TX_STATUS_PS)
++			goto more;
++
++		DBG("%s: disable polling mode, rx=%d, tx=%d,limit=%d\n",
++			dev->name, rx_done, tx_done, limit);
++
++		napi_complete(napi);
++
++		/* enable interrupts */
++		spin_lock_irqsave(&ag->lock, flags);
++		ag71xx_int_enable(ag, AG71XX_INT_POLL);
++		spin_unlock_irqrestore(&ag->lock, flags);
++		return rx_done;
++	}
++
++ more:
++	DBG("%s: stay in polling mode, rx=%d, tx=%d, limit=%d\n",
++			dev->name, rx_done, tx_done, limit);
++	return rx_done;
++
++ oom:
++	if (netif_msg_rx_err(ag))
++		printk(KERN_DEBUG "%s: out of memory\n", dev->name);
++
++	mod_timer(&ag->oom_timer, jiffies + AG71XX_OOM_REFILL);
++	napi_complete(napi);
++	return 0;
++}
++
++static irqreturn_t ag71xx_interrupt(int irq, void *dev_id)
++{
++	struct net_device *dev = dev_id;
++	struct ag71xx *ag = netdev_priv(dev);
++	u32 status;
++
++	status = ag71xx_rr(ag, AG71XX_REG_INT_STATUS);
++	ag71xx_dump_intr(ag, "raw", status);
++
++	if (unlikely(!status))
++		return IRQ_NONE;
++
++	if (unlikely(status & AG71XX_INT_ERR)) {
++		if (status & AG71XX_INT_TX_BE) {
++			ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_BE);
++			dev_err(&dev->dev, "TX BUS error\n");
++		}
++		if (status & AG71XX_INT_RX_BE) {
++			ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_BE);
++			dev_err(&dev->dev, "RX BUS error\n");
++		}
++	}
++
++	if (likely(status & AG71XX_INT_POLL)) {
++		ag71xx_int_disable(ag, AG71XX_INT_POLL);
++		DBG("%s: enable polling mode\n", dev->name);
++		napi_schedule(&ag->napi);
++	}
++
++	ag71xx_debugfs_update_int_stats(ag, status);
++
++	return IRQ_HANDLED;
++}
++
++static void ag71xx_set_multicast_list(struct net_device *dev)
++{
++	/* TODO */
++}
++
++#ifdef CONFIG_NET_POLL_CONTROLLER
++/*
++ * Polling 'interrupt' - used by things like netconsole to send skbs
++ * without having to re-enable interrupts. It's not called while
++ * the interrupt routine is executing.
++ */
++static void ag71xx_netpoll(struct net_device *dev)
++{
++	disable_irq(dev->irq);
++	ag71xx_interrupt(dev->irq, dev);
++	enable_irq(dev->irq);
++}
++#endif
++
++static const struct net_device_ops ag71xx_netdev_ops = {
++	.ndo_open		= ag71xx_open,
++	.ndo_stop		= ag71xx_stop,
++	.ndo_start_xmit		= ag71xx_hard_start_xmit,
++	.ndo_set_multicast_list	= ag71xx_set_multicast_list,
++	.ndo_do_ioctl		= ag71xx_do_ioctl,
++	.ndo_tx_timeout		= ag71xx_tx_timeout,
++	.ndo_change_mtu		= eth_change_mtu,
++	.ndo_set_mac_address	= eth_mac_addr,
++	.ndo_validate_addr	= eth_validate_addr,
++#ifdef CONFIG_NET_POLL_CONTROLLER
++	.ndo_poll_controller	= ag71xx_netpoll,
++#endif
++};
++
++static int __init ag71xx_probe(struct platform_device *pdev)
++{
++	struct net_device *dev;
++	struct resource *res;
++	struct ag71xx *ag;
++	struct ag71xx_platform_data *pdata;
++	int err;
++
++	pdata = pdev->dev.platform_data;
++	if (!pdata) {
++		dev_err(&pdev->dev, "no platform data specified\n");
++		err = -ENXIO;
++		goto err_out;
++	}
++
++	if (pdata->mii_bus_dev == NULL) {
++		dev_err(&pdev->dev, "no MII bus device specified\n");
++		err = -EINVAL;
++		goto err_out;
++	}
++
++	dev = alloc_etherdev(sizeof(*ag));
++	if (!dev) {
++		dev_err(&pdev->dev, "alloc_etherdev failed\n");
++		err = -ENOMEM;
++		goto err_out;
++	}
++
++	SET_NETDEV_DEV(dev, &pdev->dev);
++
++	ag = netdev_priv(dev);
++	ag->pdev = pdev;
++	ag->dev = dev;
++	ag->msg_enable = netif_msg_init(ag71xx_msg_level,
++					AG71XX_DEFAULT_MSG_ENABLE);
++	spin_lock_init(&ag->lock);
++
++	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mac_base");
++	if (!res) {
++		dev_err(&pdev->dev, "no mac_base resource found\n");
++		err = -ENXIO;
++		goto err_out;
++	}
++
++	ag->mac_base = ioremap_nocache(res->start, res->end - res->start + 1);
++	if (!ag->mac_base) {
++		dev_err(&pdev->dev, "unable to ioremap mac_base\n");
++		err = -ENOMEM;
++		goto err_free_dev;
++	}
++
++	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mii_ctrl");
++	if (!res) {
++		dev_err(&pdev->dev, "no mii_ctrl resource found\n");
++		err = -ENXIO;
++		goto err_unmap_base;
++	}
++
++	ag->mii_ctrl = ioremap_nocache(res->start, res->end - res->start + 1);
++	if (!ag->mii_ctrl) {
++		dev_err(&pdev->dev, "unable to ioremap mii_ctrl\n");
++		err = -ENOMEM;
++		goto err_unmap_base;
++	}
++
++	dev->irq = platform_get_irq(pdev, 0);
++	err = request_irq(dev->irq, ag71xx_interrupt,
++			  IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
++			  dev->name, dev);
++	if (err) {
++		dev_err(&pdev->dev, "unable to request IRQ %d\n", dev->irq);
++		goto err_unmap_mii_ctrl;
++	}
++
++	dev->base_addr = (unsigned long)ag->mac_base;
++	dev->netdev_ops = &ag71xx_netdev_ops;
++	dev->ethtool_ops = &ag71xx_ethtool_ops;
++
++	INIT_WORK(&ag->restart_work, ag71xx_restart_work_func);
++
++	init_timer(&ag->oom_timer);
++	ag->oom_timer.data = (unsigned long) dev;
++	ag->oom_timer.function = ag71xx_oom_timer_handler;
++
++	memcpy(dev->dev_addr, pdata->mac_addr, ETH_ALEN);
++
++	netif_napi_add(dev, &ag->napi, ag71xx_poll, AG71XX_NAPI_WEIGHT);
++
++	err = register_netdev(dev);
++	if (err) {
++		dev_err(&pdev->dev, "unable to register net device\n");
++		goto err_free_irq;
++	}
++
++	printk(KERN_INFO "%s: Atheros AG71xx at 0x%08lx, irq %d\n",
++	       dev->name, dev->base_addr, dev->irq);
++
++	ag71xx_dump_regs(ag);
++
++	ag71xx_hw_init(ag);
++
++	ag71xx_dump_regs(ag);
++
++	err = ag71xx_phy_connect(ag);
++	if (err)
++		goto err_unregister_netdev;
++
++	err = ag71xx_debugfs_init(ag);
++	if (err)
++		goto err_phy_disconnect;
++
++	platform_set_drvdata(pdev, dev);
++
++	return 0;
++
++ err_phy_disconnect:
++	ag71xx_phy_disconnect(ag);
++ err_unregister_netdev:
++	unregister_netdev(dev);
++ err_free_irq:
++	free_irq(dev->irq, dev);
++ err_unmap_mii_ctrl:
++	iounmap(ag->mii_ctrl);
++ err_unmap_base:
++	iounmap(ag->mac_base);
++ err_free_dev:
++	kfree(dev);
++ err_out:
++	platform_set_drvdata(pdev, NULL);
++	return err;
++}
++
++static int __exit ag71xx_remove(struct platform_device *pdev)
++{
++	struct net_device *dev = platform_get_drvdata(pdev);
++
++	if (dev) {
++		struct ag71xx *ag = netdev_priv(dev);
++
++		ag71xx_debugfs_exit(ag);
++		ag71xx_phy_disconnect(ag);
++		unregister_netdev(dev);
++		free_irq(dev->irq, dev);
++		iounmap(ag->mii_ctrl);
++		iounmap(ag->mac_base);
++		kfree(dev);
++		platform_set_drvdata(pdev, NULL);
++	}
++
++	return 0;
++}
++
++static struct platform_driver ag71xx_driver = {
++	.probe		= ag71xx_probe,
++	.remove		= __exit_p(ag71xx_remove),
++	.driver = {
++		.name	= AG71XX_DRV_NAME,
++	}
++};
++
++static int __init ag71xx_module_init(void)
++{
++	int ret;
++
++	ret = ag71xx_debugfs_root_init();
++	if (ret)
++		goto err_out;
++
++	ret = ag71xx_mdio_driver_init();
++	if (ret)
++		goto err_debugfs_exit;
++
++	ret = platform_driver_register(&ag71xx_driver);
++	if (ret)
++		goto err_mdio_exit;
++
++	return 0;
++
++ err_mdio_exit:
++	ag71xx_mdio_driver_exit();
++ err_debugfs_exit:
++	ag71xx_debugfs_root_exit();
++ err_out:
++	return ret;
++}
++
++static void __exit ag71xx_module_exit(void)
++{
++	platform_driver_unregister(&ag71xx_driver);
++	ag71xx_mdio_driver_exit();
++	ag71xx_debugfs_root_exit();
++}
++
++module_init(ag71xx_module_init);
++module_exit(ag71xx_module_exit);
++
++MODULE_VERSION(AG71XX_DRV_VERSION);
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_AUTHOR("Imre Kaloz <kaloz@openwrt.org>");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:" AG71XX_DRV_NAME);
+diff -Nur linux-2.6.33.3.orig/drivers/net/ag71xx/ag71xx_mdio.c linux-2.6.33.3/drivers/net/ag71xx/ag71xx_mdio.c
+--- linux-2.6.33.3.orig/drivers/net/ag71xx/ag71xx_mdio.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/drivers/net/ag71xx/ag71xx_mdio.c	2010-01-05 20:38:53.413280204 +0100
+@@ -0,0 +1,243 @@
++/*
++ *  Atheros AR71xx built-in ethernet mac driver
++ *
++ *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  Based on Atheros' AG7100 driver
++ *
++ *  This program is free software; you can redistribute it and/or modify it
++ *  under the terms of the GNU General Public License version 2 as published
++ *  by the Free Software Foundation.
++ */
++
++#include "ag71xx.h"
++
++#define AG71XX_MDIO_RETRY	1000
++#define AG71XX_MDIO_DELAY	5
++
++static inline void ag71xx_mdio_wr(struct ag71xx_mdio *am, unsigned reg,
++				  u32 value)
++{
++	void __iomem *r;
++
++	r = am->mdio_base + reg;
++	__raw_writel(value, r);
++
++	/* flush write */
++	(void) __raw_readl(r);
++}
++
++static inline u32 ag71xx_mdio_rr(struct ag71xx_mdio *am, unsigned reg)
++{
++	return __raw_readl(am->mdio_base + reg);
++}
++
++static void ag71xx_mdio_dump_regs(struct ag71xx_mdio *am)
++{
++	DBG("%s: mii_cfg=%08x, mii_cmd=%08x, mii_addr=%08x\n",
++		am->mii_bus->name,
++		ag71xx_mdio_rr(am, AG71XX_REG_MII_CFG),
++		ag71xx_mdio_rr(am, AG71XX_REG_MII_CMD),
++		ag71xx_mdio_rr(am, AG71XX_REG_MII_ADDR));
++	DBG("%s: mii_ctrl=%08x, mii_status=%08x, mii_ind=%08x\n",
++		am->mii_bus->name,
++		ag71xx_mdio_rr(am, AG71XX_REG_MII_CTRL),
++		ag71xx_mdio_rr(am, AG71XX_REG_MII_STATUS),
++		ag71xx_mdio_rr(am, AG71XX_REG_MII_IND));
++}
++
++static int ag71xx_mdio_mii_read(struct ag71xx_mdio *am, int addr, int reg)
++{
++	int ret;
++	int i;
++
++	ag71xx_mdio_wr(am, AG71XX_REG_MII_CMD, MII_CMD_WRITE);
++	ag71xx_mdio_wr(am, AG71XX_REG_MII_ADDR,
++			((addr & 0xff) << MII_ADDR_SHIFT) | (reg & 0xff));
++	ag71xx_mdio_wr(am, AG71XX_REG_MII_CMD, MII_CMD_READ);
++
++	i = AG71XX_MDIO_RETRY;
++	while (ag71xx_mdio_rr(am, AG71XX_REG_MII_IND) & MII_IND_BUSY) {
++		if (i-- == 0) {
++			printk(KERN_ERR "%s: mii_read timed out\n",
++				am->mii_bus->name);
++			ret = 0xffff;
++			goto out;
++		}
++		udelay(AG71XX_MDIO_DELAY);
++	}
++
++	ret = ag71xx_mdio_rr(am, AG71XX_REG_MII_STATUS) & 0xffff;
++	ag71xx_mdio_wr(am, AG71XX_REG_MII_CMD, MII_CMD_WRITE);
++
++	DBG("mii_read: addr=%04x, reg=%04x, value=%04x\n", addr, reg, ret);
++
++ out:
++	return ret;
++}
++
++static void ag71xx_mdio_mii_write(struct ag71xx_mdio *am,
++				  int addr, int reg, u16 val)
++{
++	int i;
++
++	DBG("mii_write: addr=%04x, reg=%04x, value=%04x\n", addr, reg, val);
++
++	ag71xx_mdio_wr(am, AG71XX_REG_MII_ADDR,
++			((addr & 0xff) << MII_ADDR_SHIFT) | (reg & 0xff));
++	ag71xx_mdio_wr(am, AG71XX_REG_MII_CTRL, val);
++
++	i = AG71XX_MDIO_RETRY;
++	while (ag71xx_mdio_rr(am, AG71XX_REG_MII_IND) & MII_IND_BUSY) {
++		if (i-- == 0) {
++			printk(KERN_ERR "%s: mii_write timed out\n",
++				am->mii_bus->name);
++			break;
++		}
++		udelay(AG71XX_MDIO_DELAY);
++	}
++}
++
++static int ag71xx_mdio_reset(struct mii_bus *bus)
++{
++	struct ag71xx_mdio *am = bus->priv;
++	u32 t;
++
++	if (am->pdata->is_ar7240)
++		t = MII_CFG_CLK_DIV_6;
++	else
++		t = MII_CFG_CLK_DIV_28;
++
++	ag71xx_mdio_wr(am, AG71XX_REG_MII_CFG, t | MII_CFG_RESET);
++	udelay(100);
++
++	ag71xx_mdio_wr(am, AG71XX_REG_MII_CFG, t);
++	udelay(100);
++
++	return 0;
++}
++
++static int ag71xx_mdio_read(struct mii_bus *bus, int addr, int reg)
++{
++	struct ag71xx_mdio *am = bus->priv;
++
++	return ag71xx_mdio_mii_read(am, addr, reg);
++}
++
++static int ag71xx_mdio_write(struct mii_bus *bus, int addr, int reg, u16 val)
++{
++	struct ag71xx_mdio *am = bus->priv;
++
++	ag71xx_mdio_mii_write(am, addr, reg, val);
++	return 0;
++}
++
++static int __init ag71xx_mdio_probe(struct platform_device *pdev)
++{
++	struct ag71xx_mdio_platform_data *pdata;
++	struct ag71xx_mdio *am;
++	struct resource *res;
++	int i;
++	int err;
++
++	pdata = pdev->dev.platform_data;
++	if (!pdata) {
++		dev_err(&pdev->dev, "no platform data specified\n");
++		return -EINVAL;
++	}
++
++	am = kzalloc(sizeof(*am), GFP_KERNEL);
++	if (!am) {
++		err = -ENOMEM;
++		goto err_out;
++	}
++
++	am->pdata = pdata;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		dev_err(&pdev->dev, "no iomem resource found\n");
++		err = -ENXIO;
++		goto err_out;
++	}
++
++	am->mdio_base = ioremap_nocache(res->start, res->end - res->start + 1);
++	if (!am->mdio_base) {
++		dev_err(&pdev->dev, "unable to ioremap registers\n");
++		err = -ENOMEM;
++		goto err_free_mdio;
++	}
++
++	am->mii_bus = mdiobus_alloc();
++	if (am->mii_bus == NULL) {
++		err = -ENOMEM;
++		goto err_iounmap;
++	}
++
++	am->mii_bus->name = "ag71xx_mdio";
++	am->mii_bus->read = ag71xx_mdio_read;
++	am->mii_bus->write = ag71xx_mdio_write;
++	am->mii_bus->reset = ag71xx_mdio_reset;
++	am->mii_bus->irq = am->mii_irq;
++	am->mii_bus->priv = am;
++	am->mii_bus->parent = &pdev->dev;
++	snprintf(am->mii_bus->id, MII_BUS_ID_SIZE, "%s", dev_name(&pdev->dev));
++	am->mii_bus->phy_mask = pdata->phy_mask;
++
++	for (i = 0; i < PHY_MAX_ADDR; i++)
++		am->mii_irq[i] = PHY_POLL;
++
++	ag71xx_mdio_wr(am, AG71XX_REG_MAC_CFG1, 0);
++
++	err = mdiobus_register(am->mii_bus);
++	if (err)
++		goto err_free_bus;
++
++	ag71xx_mdio_dump_regs(am);
++
++	platform_set_drvdata(pdev, am);
++	return 0;
++
++ err_free_bus:
++	mdiobus_free(am->mii_bus);
++ err_iounmap:
++	iounmap(am->mdio_base);
++ err_free_mdio:
++	kfree(am);
++ err_out:
++	return err;
++}
++
++static int __exit ag71xx_mdio_remove(struct platform_device *pdev)
++{
++	struct ag71xx_mdio *am = platform_get_drvdata(pdev);
++
++	if (am) {
++		mdiobus_unregister(am->mii_bus);
++		mdiobus_free(am->mii_bus);
++		iounmap(am->mdio_base);
++		kfree(am);
++		platform_set_drvdata(pdev, NULL);
++	}
++
++	return 0;
++}
++
++static struct platform_driver ag71xx_mdio_driver = {
++	.probe		= ag71xx_mdio_probe,
++	.remove		= __exit_p(ag71xx_mdio_remove),
++	.driver = {
++		.name	= "ag71xx-mdio",
++	}
++};
++
++int ag71xx_mdio_driver_init(void)
++{
++	return platform_driver_register(&ag71xx_mdio_driver);
++}
++
++void ag71xx_mdio_driver_exit(void)
++{
++	platform_driver_unregister(&ag71xx_mdio_driver);
++}
+diff -Nur linux-2.6.33.3.orig/drivers/net/ag71xx/ag71xx_phy.c linux-2.6.33.3/drivers/net/ag71xx/ag71xx_phy.c
+--- linux-2.6.33.3.orig/drivers/net/ag71xx/ag71xx_phy.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/drivers/net/ag71xx/ag71xx_phy.c	2010-03-23 20:31:06.040706961 +0100
+@@ -0,0 +1,213 @@
++/*
++ *  Atheros AR71xx built-in ethernet mac driver
++ *
++ *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  Based on Atheros' AG7100 driver
++ *
++ *  This program is free software; you can redistribute it and/or modify it
++ *  under the terms of the GNU General Public License version 2 as published
++ *  by the Free Software Foundation.
++ */
++
++#include "ag71xx.h"
++
++static void ag71xx_phy_link_adjust(struct net_device *dev)
++{
++	struct ag71xx *ag = netdev_priv(dev);
++	struct phy_device *phydev = ag->phy_dev;
++	unsigned long flags;
++	int status_change = 0;
++
++	spin_lock_irqsave(&ag->lock, flags);
++
++	if (phydev->link) {
++		if (ag->duplex != phydev->duplex
++		    || ag->speed != phydev->speed) {
++			status_change = 1;
++		}
++	}
++
++	if (phydev->link != ag->link)
++		status_change = 1;
++
++	ag->link = phydev->link;
++	ag->duplex = phydev->duplex;
++	ag->speed = phydev->speed;
++
++	if (status_change)
++		ag71xx_link_adjust(ag);
++
++	spin_unlock_irqrestore(&ag->lock, flags);
++}
++
++void ag71xx_phy_start(struct ag71xx *ag)
++{
++	if (ag->phy_dev) {
++		phy_start(ag->phy_dev);
++	} else {
++		ag->link = 1;
++		ag71xx_link_adjust(ag);
++	}
++}
++
++void ag71xx_phy_stop(struct ag71xx *ag)
++{
++	if (ag->phy_dev) {
++		phy_stop(ag->phy_dev);
++	} else {
++		ag->link = 0;
++		ag71xx_link_adjust(ag);
++	}
++}
++
++static int ag71xx_phy_connect_fixed(struct ag71xx *ag)
++{
++	struct net_device *dev = ag->dev;
++	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++	int ret = 0;
++
++	/* use fixed settings */
++	switch (pdata->speed) {
++	case SPEED_10:
++	case SPEED_100:
++	case SPEED_1000:
++		break;
++	default:
++		printk(KERN_ERR "%s: invalid speed specified\n", dev->name);
++		ret = -EINVAL;
++		break;
++	}
++
++	printk(KERN_DEBUG "%s: using fixed link parameters\n", dev->name);
++
++	ag->duplex = pdata->duplex;
++	ag->speed = pdata->speed;
++
++	return ret;
++}
++
++static int ag71xx_phy_connect_multi(struct ag71xx *ag)
++{
++	struct net_device *dev = ag->dev;
++	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++	struct phy_device *phydev = NULL;
++	int phy_addr;
++	int ret = 0;
++
++	for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
++		if (!(pdata->phy_mask & (1 << phy_addr)))
++			continue;
++
++		if (ag->mii_bus->phy_map[phy_addr] == NULL)
++			continue;
++
++		DBG("%s: PHY found at %s, uid=%08x\n",
++			dev->name,
++			dev_name(&ag->mii_bus->phy_map[phy_addr]->dev),
++			ag->mii_bus->phy_map[phy_addr]->phy_id);
++
++		if (phydev == NULL)
++			phydev = ag->mii_bus->phy_map[phy_addr];
++	}
++
++	if (!phydev) {
++		printk(KERN_ERR "%s: no PHY found with phy_mask=%08x\n",
++			dev->name, pdata->phy_mask);
++		return -ENODEV;
++	}
++
++	ag->phy_dev = phy_connect(dev, dev_name(&phydev->dev),
++				  &ag71xx_phy_link_adjust, 0,
++				  pdata->phy_if_mode);
++
++	if (IS_ERR(ag->phy_dev)) {
++		printk(KERN_ERR "%s: could not connect to PHY at %s\n",
++			dev->name, dev_name(&phydev->dev));
++		return PTR_ERR(ag->phy_dev);
++	}
++
++	/* mask with MAC supported features */
++	if (pdata->has_gbit)
++		phydev->supported &= PHY_GBIT_FEATURES;
++	else
++		phydev->supported &= PHY_BASIC_FEATURES;
++
++	phydev->advertising = phydev->supported;
++
++	printk(KERN_DEBUG "%s: connected to PHY at %s [uid=%08x, driver=%s]\n",
++		dev->name, dev_name(&phydev->dev),
++		phydev->phy_id, phydev->drv->name);
++
++	ag->link = 0;
++	ag->speed = 0;
++	ag->duplex = -1;
++
++	return ret;
++}
++
++static int dev_is_class(struct device *dev, void *class)
++{
++	if (dev->class != NULL && !strcmp(dev->class->name, class))
++		return 1;
++
++	return 0;
++}
++
++static struct device *dev_find_class(struct device *parent, char *class)
++{
++	if (dev_is_class(parent, class)) {
++		get_device(parent);
++		return parent;
++	}
++
++	return device_find_child(parent, class, dev_is_class);
++}
++
++static struct mii_bus *dev_to_mii_bus(struct device *dev)
++{
++	struct device *d;
++
++	d = dev_find_class(dev, "mdio_bus");
++	if (d != NULL) {
++		struct mii_bus *bus;
++
++		bus = to_mii_bus(d);
++		put_device(d);
++
++		return bus;
++	}
++
++	return NULL;
++}
++
++int ag71xx_phy_connect(struct ag71xx *ag)
++{
++	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++
++	ag->mii_bus = dev_to_mii_bus(pdata->mii_bus_dev);
++	if (ag->mii_bus == NULL) {
++		printk(KERN_ERR "%s: unable to find MII bus on device '%s'\n",
++			ag->dev->name, dev_name(pdata->mii_bus_dev));
++		return -ENODEV;
++	}
++
++	/* Reset the mdio bus explicitly */
++	if (ag->mii_bus->reset) {
++		mutex_lock(&ag->mii_bus->mdio_lock);
++		ag->mii_bus->reset(ag->mii_bus);
++		mutex_unlock(&ag->mii_bus->mdio_lock);
++	}
++
++	if (pdata->phy_mask)
++		return ag71xx_phy_connect_multi(ag);
++
++	return ag71xx_phy_connect_fixed(ag);
++}
++
++void ag71xx_phy_disconnect(struct ag71xx *ag)
++{
++	if (ag->phy_dev)
++		phy_disconnect(ag->phy_dev);
++}
+diff -Nur linux-2.6.33.3.orig/drivers/net/ag71xx/Kconfig linux-2.6.33.3/drivers/net/ag71xx/Kconfig
+--- linux-2.6.33.3.orig/drivers/net/ag71xx/Kconfig	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/drivers/net/ag71xx/Kconfig	2010-04-02 11:07:52.574971060 +0200
+@@ -0,0 +1,33 @@
++config AG71XX
++	tristate "Atheros AR71xx built-in ethernet mac support"
++	depends on ATHEROS_AR71XX
++	select PHYLIB
++	help
++	  If you wish to compile a kernel for AR71xx/91xx and enable
++	  ethernet support, then you should always answer Y to this.
++
++if AG71XX
++
++config AG71XX_DEBUG
++	bool "Atheros AR71xx built-in ethernet driver debugging"
++	default n
++	help
++	  Atheros AR71xx built-in ethernet driver debugging messages.
++
++config AG71XX_DEBUG_FS
++	bool "Atheros AR71xx built-in ethernet driver debugfs support"
++	depends on DEBUG_FS
++	default n
++	help
++	  Say Y, if you need access to various statistics provided by
++	  the ag71xx driver.
++
++config AG71XX_AR8216_SUPPORT
++	bool "special support for the Atheros AR8216 switch"
++	default n
++	default y if AR71XX_MACH_WNR2000 || AR71XX_MACH_MZK_W04NU
++	help
++	  Say 'y' here if you want to enable special support for the
++	  Atheros AR8216 switch found on some boards.
++
++endif
+diff -Nur linux-2.6.33.3.orig/drivers/net/ag71xx/Makefile linux-2.6.33.3/drivers/net/ag71xx/Makefile
+--- linux-2.6.33.3.orig/drivers/net/ag71xx/Makefile	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/drivers/net/ag71xx/Makefile	2010-01-05 20:38:53.413280204 +0100
+@@ -0,0 +1,14 @@
++#
++# Makefile for the Atheros AR71xx built-in ethernet macs
++#
++
++ag71xx-y	+= ag71xx_main.o
++ag71xx-y	+= ag71xx_ethtool.o
++ag71xx-y	+= ag71xx_phy.o
++ag71xx-y	+= ag71xx_mdio.o
++
++ag71xx-$(CONFIG_AG71XX_DEBUG_FS)	+= ag71xx_debugfs.o
++ag71xx-$(CONFIG_AG71XX_AR8216_SUPPORT)	+= ag71xx_ar8216.o
++
++obj-$(CONFIG_AG71XX)	+= ag71xx.o
++
+diff -Nur linux-2.6.33.3.orig/drivers/net/Kconfig linux-2.6.33.3/drivers/net/Kconfig
+--- linux-2.6.33.3.orig/drivers/net/Kconfig	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/drivers/net/Kconfig	2010-05-17 16:28:38.519115009 +0200
+@@ -2005,6 +2005,8 @@
+ 
+ 	  The safe and default value for this is N.
+ 
++source drivers/net/ag71xx/Kconfig
++
+ config DL2K
+ 	tristate "DL2000/TC902x-based Gigabit Ethernet support"
+ 	depends on PCI
+diff -Nur linux-2.6.33.3.orig/drivers/net/Makefile linux-2.6.33.3/drivers/net/Makefile
+--- linux-2.6.33.3.orig/drivers/net/Makefile	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/drivers/net/Makefile	2010-05-17 16:28:38.519115009 +0200
+@@ -106,6 +106,7 @@
+ # end link order section
+ #
+ 
++obj-$(CONFIG_AG71XX) += ag71xx/
+ obj-$(CONFIG_SUNDANCE) += sundance.o
+ obj-$(CONFIG_HAMACHI) += hamachi.o
+ obj-$(CONFIG_NET) += Space.o loopback.o
+diff -Nur linux-2.6.33.3.orig/drivers/net/phy/Kconfig linux-2.6.33.3/drivers/net/phy/Kconfig
+--- linux-2.6.33.3.orig/drivers/net/phy/Kconfig	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/drivers/net/phy/Kconfig	2010-05-17 22:25:24.119127715 +0200
+@@ -88,6 +88,10 @@
+ 	---help---
+ 	  Supports the LSI ET1011C PHY.
+ 
++config IP175C_PHY
++	tristate "Driver for IC+ IP175C/IP178C switches"
++	select SWCONFIG
++
+ config FIXED_PHY
+ 	bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
+ 	depends on PHYLIB=y
+diff -Nur linux-2.6.33.3.orig/drivers/net/phy/micrel.c linux-2.6.33.3/drivers/net/phy/micrel.c
+--- linux-2.6.33.3.orig/drivers/net/phy/micrel.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/drivers/net/phy/micrel.c	2009-12-13 20:45:24.083925758 +0100
+@@ -0,0 +1,82 @@
++/*
++ *  Driver for Micrel/Kendin PHYs
++ *
++ *  Copyright (c) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@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/delay.h>
++#include <linux/skbuff.h>
++#include <linux/phy.h>
++
++#define KSZ_REG_INT_CTRL	0x1b
++
++#define KSZ_INT_LU_EN	(1 << 8)	/* enable Link Up interrupt */
++#define KSZ_INT_RF_EN	(1 << 9)	/* enable Remote Fault interrupt */
++#define KSZ_INT_LD_EN	(1 << 10)	/* enable Link Down interrupt */
++
++#define KSZ_INT_INIT	(KSZ_INT_LU_EN | KSZ_INT_LD_EN)
++
++static int ksz8041_ack_interrupt(struct phy_device *phydev)
++{
++	int err;
++
++	err = phy_read(phydev, KSZ_REG_INT_CTRL);
++
++	return (err < 0) ? err : 0;
++}
++
++static int ksz8041_config_intr(struct phy_device *phydev)
++{
++	int err;
++
++	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
++		err = phy_write(phydev, KSZ_REG_INT_CTRL,
++				KSZ_INT_INIT);
++	else
++		err = phy_write(phydev, KSZ_REG_INT_CTRL, 0);
++
++	return err;
++}
++
++static struct phy_driver ksz8041_phy_driver = {
++	.phy_id		= 0x00221512,
++	.name		= "Micrel KSZ8041",
++	.phy_id_mask	= 0x001fffff,
++	.features	= PHY_BASIC_FEATURES,
++	.flags		= PHY_HAS_INTERRUPT,
++	.config_aneg	= genphy_config_aneg,
++	.read_status	= genphy_read_status,
++	.ack_interrupt	= ksz8041_ack_interrupt,
++	.config_intr	= ksz8041_config_intr,
++	.driver	= {
++		.owner	= THIS_MODULE,
++	},
++};
++
++static int __init micrel_phy_init(void)
++{
++	return phy_driver_register(&ksz8041_phy_driver);
++}
++
++static void __exit micrel_phy_exit(void)
++{
++	phy_driver_unregister(&ksz8041_phy_driver);
++}
++
++#ifdef MODULE
++module_init(micrel_phy_init);
++module_exit(micrel_phy_exit);
++#else
++subsys_initcall(micrel_phy_init);
++#endif
++
++MODULE_DESCRIPTION("Micrel/Kendin PHY driver");
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_AUTHOR("Imre Kaloz <kaloz@openwrt.org>");
++MODULE_LICENSE("GPL v2");
+diff -Nur linux-2.6.33.3.orig/drivers/net/phy/phy.c linux-2.6.33.3/drivers/net/phy/phy.c
+--- linux-2.6.33.3.orig/drivers/net/phy/phy.c	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/drivers/net/phy/phy.c	2010-05-17 21:40:09.635111896 +0200
+@@ -299,6 +299,50 @@
+ }
+ EXPORT_SYMBOL(phy_ethtool_gset);
+ 
++int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr)
++{
++	u32 cmd;
++	int tmp;
++	struct ethtool_cmd ecmd = { ETHTOOL_GSET };
++	struct ethtool_value edata = { ETHTOOL_GLINK };
++
++	if (get_user(cmd, (u32 *) useraddr))
++		return -EFAULT;
++
++	switch (cmd) {
++	case ETHTOOL_GSET:
++		phy_ethtool_gset(phydev, &ecmd);
++		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
++			return -EFAULT;
++		return 0;
++
++	case ETHTOOL_SSET:
++		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
++			return -EFAULT;
++		return phy_ethtool_sset(phydev, &ecmd);
++
++	case ETHTOOL_NWAY_RST:
++		/* if autoneg is off, it's an error */
++		tmp = phy_read(phydev, MII_BMCR);
++		if (tmp & BMCR_ANENABLE) {
++			tmp |= (BMCR_ANRESTART);
++			phy_write(phydev, MII_BMCR, tmp);
++			return 0;
++		}
++		return -EINVAL;
++
++	case ETHTOOL_GLINK:
++		edata.data = (phy_read(phydev,
++				MII_BMSR) & BMSR_LSTATUS) ? 1 : 0;
++		if (copy_to_user(useraddr, &edata, sizeof(edata)))
++			return -EFAULT;
++		return 0;
++	}
++
++	return -EOPNOTSUPP;
++}
++EXPORT_SYMBOL(phy_ethtool_ioctl);
++
+ /**
+  * phy_mii_ioctl - generic PHY MII ioctl interface
+  * @phydev: the phy_device struct
+@@ -352,7 +396,7 @@
+ 		}
+ 
+ 		phy_write(phydev, mii_data->reg_num, val);
+-		
++
+ 		if (mii_data->reg_num == MII_BMCR &&
+ 		    val & BMCR_RESET &&
+ 		    phydev->drv->config_init) {
+@@ -466,7 +510,7 @@
+ 	int idx;
+ 
+ 	idx = phy_find_setting(phydev->speed, phydev->duplex);
+-	
++
+ 	idx++;
+ 
+ 	idx = phy_find_valid(idx, phydev->supported);
+diff -Nur linux-2.6.33.3.orig/drivers/net/phy/phy_device.c linux-2.6.33.3/drivers/net/phy/phy_device.c
+--- linux-2.6.33.3.orig/drivers/net/phy/phy_device.c	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/drivers/net/phy/phy_device.c	2010-05-17 21:40:17.019371728 +0200
+@@ -146,6 +146,18 @@
+ }
+ EXPORT_SYMBOL(phy_scan_fixups);
+ 
++static int generic_receive_skb(struct sk_buff *skb)
++{
++	skb->protocol = eth_type_trans(skb, skb->dev);
++	return netif_receive_skb(skb);
++}
++
++static int generic_rx(struct sk_buff *skb)
++{
++	skb->protocol = eth_type_trans(skb, skb->dev);
++	return netif_rx(skb);
++}
++
+ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
+ {
+ 	struct phy_device *dev;
+@@ -175,6 +187,8 @@
+ 	dev_set_name(&dev->dev, PHY_ID_FMT, bus->id, addr);
+ 
+ 	dev->state = PHY_DOWN;
++	dev->netif_receive_skb = &generic_receive_skb;
++	dev->netif_rx = &generic_rx;
+ 
+ 	mutex_init(&dev->lock);
+ 	INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine);
+diff -Nur linux-2.6.33.3.orig/drivers/spi/ap83_spi.c linux-2.6.33.3/drivers/spi/ap83_spi.c
+--- linux-2.6.33.3.orig/drivers/spi/ap83_spi.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/drivers/spi/ap83_spi.c	2009-12-13 20:45:24.855922705 +0100
+@@ -0,0 +1,282 @@
++/*
++ * Atheros AP83 board specific SPI Controller driver
++ *
++ * Copyright (C) 2009 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/init.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/workqueue.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spi_bitbang.h>
++#include <linux/bitops.h>
++#include <linux/gpio.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/platform.h>
++
++#define DRV_DESC	"Atheros AP83 board SPI Controller driver"
++#define DRV_VERSION	"0.1.0"
++#define DRV_NAME	"ap83-spi"
++
++#define AP83_SPI_CLK_HIGH	(1 << 23)
++#define AP83_SPI_CLK_LOW	0
++#define AP83_SPI_MOSI_HIGH	(1 << 22)
++#define AP83_SPI_MOSI_LOW	0
++
++#define AP83_SPI_GPIO_CS	1
++#define AP83_SPI_GPIO_MISO	3
++
++struct ap83_spi {
++	struct	spi_bitbang 	bitbang;
++	void __iomem 		*base;
++	u32			addr;
++
++	struct platform_device	*pdev;
++};
++
++static inline u32 ap83_spi_rr(struct ap83_spi *sp, u32 reg)
++{
++	return __raw_readl(sp->base + reg);
++}
++
++static inline struct ap83_spi *spidev_to_sp(struct spi_device *spi)
++{
++	return spi_master_get_devdata(spi->master);
++}
++
++static inline void setsck(struct spi_device *spi, int val)
++{
++	struct ap83_spi *sp = spidev_to_sp(spi);
++
++	if (val)
++		sp->addr |= AP83_SPI_CLK_HIGH;
++	else
++		sp->addr &= ~AP83_SPI_CLK_HIGH;
++
++	dev_dbg(&spi->dev, "addr=%08x,  SCK set to %s\n",
++		sp->addr, (val) ? "HIGH" : "LOW");
++
++	ap83_spi_rr(sp, sp->addr);
++}
++
++static inline void setmosi(struct spi_device *spi, int val)
++{
++	struct ap83_spi *sp = spidev_to_sp(spi);
++
++	if (val)
++		sp->addr |= AP83_SPI_MOSI_HIGH;
++	else
++		sp->addr &= ~AP83_SPI_MOSI_HIGH;
++
++	dev_dbg(&spi->dev, "addr=%08x, MOSI set to %s\n",
++		sp->addr, (val) ? "HIGH" : "LOW");
++
++	ap83_spi_rr(sp, sp->addr);
++}
++
++static inline u32 getmiso(struct spi_device *spi)
++{
++	u32 ret;
++
++	ret = gpio_get_value(AP83_SPI_GPIO_MISO) ? 1 : 0;
++	dev_dbg(&spi->dev, "get MISO: %d\n", ret);
++
++	return ret;
++}
++
++static inline void do_spidelay(struct spi_device *spi, unsigned nsecs)
++{
++	ndelay(nsecs);
++}
++
++static void ap83_spi_chipselect(struct spi_device *spi, int on)
++{
++	struct ap83_spi *sp = spidev_to_sp(spi);
++
++	dev_dbg(&spi->dev, "set CS to %d\n", (on) ? 0 : 1);
++
++	if (on) {
++		ar71xx_flash_acquire();
++
++		sp->addr = 0;
++		ap83_spi_rr(sp, sp->addr);
++
++		gpio_set_value(AP83_SPI_GPIO_CS, 0);
++	} else {
++		gpio_set_value(AP83_SPI_GPIO_CS, 1);
++		ar71xx_flash_release();
++	}
++}
++
++#define spidelay(nsecs)							\
++	do {								\
++		/* Steal the spi_device pointer from our caller.	\
++		 * The bitbang-API should probably get fixed here... */	\
++		do_spidelay(spi, nsecs);				\
++	} while (0)
++
++#define EXPAND_BITBANG_TXRX
++#include <linux/spi/spi_bitbang.h>
++
++static u32 ap83_spi_txrx_mode0(struct spi_device *spi,
++			       unsigned nsecs, u32 word, u8 bits)
++{
++	dev_dbg(&spi->dev, "TXRX0 word=%08x, bits=%u\n", word, bits);
++	return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
++}
++
++static u32 ap83_spi_txrx_mode1(struct spi_device *spi,
++			       unsigned nsecs, u32 word, u8 bits)
++{
++	dev_dbg(&spi->dev, "TXRX1 word=%08x, bits=%u\n", word, bits);
++	return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
++}
++
++static u32 ap83_spi_txrx_mode2(struct spi_device *spi,
++			       unsigned nsecs, u32 word, u8 bits)
++{
++	dev_dbg(&spi->dev, "TXRX2 word=%08x, bits=%u\n", word, bits);
++	return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits);
++}
++
++static u32 ap83_spi_txrx_mode3(struct spi_device *spi,
++			       unsigned nsecs, u32 word, u8 bits)
++{
++	dev_dbg(&spi->dev, "TXRX3 word=%08x, bits=%u\n", word, bits);
++	return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits);
++}
++
++static int ap83_spi_probe(struct platform_device *pdev)
++{
++	struct spi_master *master;
++	struct ap83_spi *sp;
++	struct ap83_spi_platform_data *pdata;
++	struct resource	*r;
++	int ret;
++
++	ret = gpio_request(AP83_SPI_GPIO_MISO, "spi-miso");
++	if (ret) {
++		dev_err(&pdev->dev, "gpio request failed for MISO\n");
++		return ret;
++	}
++
++	ret = gpio_request(AP83_SPI_GPIO_CS, "spi-cs");
++	if (ret) {
++		dev_err(&pdev->dev, "gpio request failed for CS\n");
++		goto err_free_miso;
++	}
++
++	ret = gpio_direction_input(AP83_SPI_GPIO_MISO);
++	if (ret) {
++		dev_err(&pdev->dev, "unable to set direction of MISO\n");
++		goto err_free_cs;
++	}
++
++	ret = gpio_direction_output(AP83_SPI_GPIO_CS, 0);
++	if (ret) {
++		dev_err(&pdev->dev, "unable to set direction of CS\n");
++		goto err_free_cs;
++	}
++
++	master = spi_alloc_master(&pdev->dev, sizeof(*sp));
++	if (master == NULL) {
++		dev_err(&pdev->dev, "failed to allocate spi master\n");
++		return -ENOMEM;
++	}
++
++	sp = spi_master_get_devdata(master);
++	platform_set_drvdata(pdev, sp);
++
++	pdata = pdev->dev.platform_data;
++
++	sp->bitbang.master = spi_master_get(master);
++	sp->bitbang.chipselect = ap83_spi_chipselect;
++	sp->bitbang.txrx_word[SPI_MODE_0] = ap83_spi_txrx_mode0;
++	sp->bitbang.txrx_word[SPI_MODE_1] = ap83_spi_txrx_mode1;
++	sp->bitbang.txrx_word[SPI_MODE_2] = ap83_spi_txrx_mode2;
++	sp->bitbang.txrx_word[SPI_MODE_3] = ap83_spi_txrx_mode3;
++
++	sp->bitbang.master->bus_num = pdev->id;
++	sp->bitbang.master->num_chipselect = 1;
++
++	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (r == NULL) {
++		ret = -ENOENT;
++		goto err_spi_put;
++	}
++
++	sp->base = ioremap_nocache(r->start, r->end - r->start + 1);
++	if (!sp->base) {
++		ret = -ENXIO;
++		goto err_spi_put;
++	}
++
++	ret = spi_bitbang_start(&sp->bitbang);
++	if (!ret)
++		goto err_unmap;
++
++	dev_info(&pdev->dev, "AP83 SPI adapter at %08x\n", r->start);
++
++	return 0;
++
++ err_unmap:
++	iounmap(sp->base);
++ err_spi_put:
++	platform_set_drvdata(pdev, NULL);
++	spi_master_put(sp->bitbang.master);
++
++ err_free_cs:
++	gpio_free(AP83_SPI_GPIO_CS);
++ err_free_miso:
++	gpio_free(AP83_SPI_GPIO_MISO);
++	return ret;
++}
++
++static int ap83_spi_remove(struct platform_device *pdev)
++{
++	struct ap83_spi *sp = platform_get_drvdata(pdev);
++
++	spi_bitbang_stop(&sp->bitbang);
++	iounmap(sp->base);
++	platform_set_drvdata(pdev, NULL);
++	spi_master_put(sp->bitbang.master);
++
++	return 0;
++}
++
++static struct platform_driver ap83_spi_drv = {
++	.probe		= ap83_spi_probe,
++	.remove		= ap83_spi_remove,
++	.driver		= {
++		.name	= DRV_NAME,
++		.owner	= THIS_MODULE,
++	},
++};
++
++static int __init ap83_spi_init(void)
++{
++	return platform_driver_register(&ap83_spi_drv);
++}
++module_init(ap83_spi_init);
++
++static void __exit ap83_spi_exit(void)
++{
++	platform_driver_unregister(&ap83_spi_drv);
++}
++module_exit(ap83_spi_exit);
++
++MODULE_ALIAS("platform:" DRV_NAME);
++MODULE_DESCRIPTION(DRV_DESC);
++MODULE_VERSION(DRV_VERSION);
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_LICENSE("GPL v2");
+diff -Nur linux-2.6.33.3.orig/drivers/spi/ar71xx_spi.c linux-2.6.33.3/drivers/spi/ar71xx_spi.c
+--- linux-2.6.33.3.orig/drivers/spi/ar71xx_spi.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/drivers/spi/ar71xx_spi.c	2009-12-13 20:45:24.851921034 +0100
+@@ -0,0 +1,283 @@
++/*
++ * Atheros AR71xx SPI Controller driver
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@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/init.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/workqueue.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spi_bitbang.h>
++#include <linux/bitops.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/platform.h>
++
++#define DRV_DESC	"Atheros AR71xx SPI Controller driver"
++#define DRV_VERSION	"0.2.4"
++#define DRV_NAME	"ar71xx-spi"
++
++#undef PER_BIT_READ
++
++struct ar71xx_spi {
++	struct	spi_bitbang 	bitbang;
++	u32			ioc_base;
++	u32			reg_ctrl;
++
++	void __iomem 		*base;
++
++	struct platform_device	*pdev;
++	u32			(*get_ioc_base)(u8 chip_select, int cs_high,
++						int is_on);
++};
++
++static inline u32 ar71xx_spi_rr(struct ar71xx_spi *sp, unsigned reg)
++{
++	return __raw_readl(sp->base + reg);
++}
++
++static inline void ar71xx_spi_wr(struct ar71xx_spi *sp, unsigned reg, u32 val)
++{
++	__raw_writel(val, sp->base + reg);
++}
++
++static inline struct ar71xx_spi *spidev_to_sp(struct spi_device *spi)
++{
++	return spi_master_get_devdata(spi->master);
++}
++
++static u32 ar71xx_spi_get_ioc_base(u8 chip_select, int cs_high, int is_on)
++{
++	u32 ret;
++
++	if (is_on == AR71XX_SPI_CS_INACTIVE)
++		ret = SPI_IOC_CS_ALL;
++	else
++		ret = SPI_IOC_CS_ALL & ~SPI_IOC_CS(chip_select);
++
++	return ret;
++}
++
++static void ar71xx_spi_chipselect(struct spi_device *spi, int value)
++{
++	struct ar71xx_spi *sp = spidev_to_sp(spi);
++	void __iomem *base = sp->base;
++	u32 ioc_base;
++
++	switch (value) {
++	case BITBANG_CS_INACTIVE:
++		ioc_base = sp->get_ioc_base(spi->chip_select,
++					(spi->mode & SPI_CS_HIGH) != 0,
++					AR71XX_SPI_CS_INACTIVE);
++		__raw_writel(ioc_base, base + SPI_REG_IOC);
++		break;
++
++	case BITBANG_CS_ACTIVE:
++		ioc_base = sp->get_ioc_base(spi->chip_select,
++					(spi->mode & SPI_CS_HIGH) != 0,
++					AR71XX_SPI_CS_ACTIVE);
++
++		__raw_writel(ioc_base, base + SPI_REG_IOC);
++		sp->ioc_base = ioc_base;
++		break;
++	}
++}
++
++static void ar71xx_spi_setup_regs(struct spi_device *spi)
++{
++	struct ar71xx_spi *sp = spidev_to_sp(spi);
++
++	/* enable GPIO mode */
++	ar71xx_spi_wr(sp, SPI_REG_FS, SPI_FS_GPIO);
++
++	/* save CTRL register */
++	sp->reg_ctrl = ar71xx_spi_rr(sp, SPI_REG_CTRL);
++
++	/* TODO: setup speed? */
++	ar71xx_spi_wr(sp, SPI_REG_CTRL, 0x43);
++}
++
++static void ar71xx_spi_restore_regs(struct spi_device *spi)
++{
++	struct ar71xx_spi *sp = spidev_to_sp(spi);
++
++	/* restore CTRL register */
++	ar71xx_spi_wr(sp, SPI_REG_CTRL, sp->reg_ctrl);
++	/* disable GPIO mode */
++	ar71xx_spi_wr(sp, SPI_REG_FS, 0);
++}
++
++static int ar71xx_spi_setup(struct spi_device *spi)
++{
++	int status;
++
++	if (spi->bits_per_word > 32)
++		return -EINVAL;
++
++	if (!spi->controller_state)
++		ar71xx_spi_setup_regs(spi);
++
++	status = spi_bitbang_setup(spi);
++	if (status && !spi->controller_state)
++		ar71xx_spi_restore_regs(spi);
++
++	return status;
++}
++
++static void ar71xx_spi_cleanup(struct spi_device *spi)
++{
++	ar71xx_spi_restore_regs(spi);
++	spi_bitbang_cleanup(spi);
++}
++
++static u32 ar71xx_spi_txrx_mode0(struct spi_device *spi, unsigned nsecs,
++					u32 word, u8 bits)
++{
++	struct ar71xx_spi *sp = spidev_to_sp(spi);
++	void __iomem *base = sp->base;
++	u32 ioc = sp->ioc_base;
++	u32 ret;
++
++	/* clock starts at inactive polarity */
++	for (word <<= (32 - bits); likely(bits); bits--) {
++		u32 out;
++
++		if (word & (1 << 31))
++			out = ioc | SPI_IOC_DO;
++		else
++			out = ioc & ~SPI_IOC_DO;
++
++		/* setup MSB (to slave) on trailing edge */
++		__raw_writel(out, base + SPI_REG_IOC);
++
++		__raw_writel(out | SPI_IOC_CLK, base + SPI_REG_IOC);
++
++		word <<= 1;
++
++#ifdef PER_BIT_READ
++		/* sample MSB (from slave) on leading edge */
++		ret = __raw_readl(base + SPI_REG_RDS);
++		__raw_writel(out, base + SPI_REG_IOC);
++#endif
++
++	}
++
++#ifndef PER_BIT_READ
++	ret = __raw_readl(base + SPI_REG_RDS);
++#endif
++	return ret;
++}
++
++static int ar71xx_spi_probe(struct platform_device *pdev)
++{
++	struct spi_master *master;
++	struct ar71xx_spi *sp;
++	struct ar71xx_spi_platform_data *pdata;
++	struct resource	*r;
++	int ret;
++
++	master = spi_alloc_master(&pdev->dev, sizeof(*sp));
++	if (master == NULL) {
++		dev_err(&pdev->dev, "failed to allocate spi master\n");
++		return -ENOMEM;
++	}
++
++	sp = spi_master_get_devdata(master);
++	platform_set_drvdata(pdev, sp);
++
++	pdata = pdev->dev.platform_data;
++
++	master->setup = ar71xx_spi_setup;
++	master->cleanup = ar71xx_spi_cleanup;
++
++	sp->bitbang.master = spi_master_get(master);
++	sp->bitbang.chipselect = ar71xx_spi_chipselect;
++	sp->bitbang.txrx_word[SPI_MODE_0] = ar71xx_spi_txrx_mode0;
++	sp->bitbang.setup_transfer = spi_bitbang_setup_transfer;
++
++	sp->get_ioc_base = ar71xx_spi_get_ioc_base;
++	if (pdata) {
++		sp->bitbang.master->bus_num = pdata->bus_num;
++		sp->bitbang.master->num_chipselect = pdata->num_chipselect;
++		if (pdata->get_ioc_base)
++			sp->get_ioc_base = pdata->get_ioc_base;
++	} else {
++		sp->bitbang.master->bus_num = 0;
++		sp->bitbang.master->num_chipselect = 3;
++	}
++
++	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (r == NULL) {
++		ret = -ENOENT;
++		goto err1;
++	}
++
++	sp->base = ioremap_nocache(r->start, r->end - r->start + 1);
++	if (!sp->base) {
++		ret = -ENXIO;
++		goto err1;
++	}
++
++	ret = spi_bitbang_start(&sp->bitbang);
++	if (!ret)
++		return 0;
++
++	iounmap(sp->base);
++ err1:
++	platform_set_drvdata(pdev, NULL);
++	spi_master_put(sp->bitbang.master);
++
++	return ret;
++}
++
++static int ar71xx_spi_remove(struct platform_device *pdev)
++{
++	struct ar71xx_spi *sp = platform_get_drvdata(pdev);
++
++	spi_bitbang_stop(&sp->bitbang);
++	iounmap(sp->base);
++	platform_set_drvdata(pdev, NULL);
++	spi_master_put(sp->bitbang.master);
++
++	return 0;
++}
++
++static struct platform_driver ar71xx_spi_drv = {
++	.probe		= ar71xx_spi_probe,
++	.remove		= ar71xx_spi_remove,
++	.driver		= {
++		.name	= DRV_NAME,
++		.owner	= THIS_MODULE,
++	},
++};
++
++static int __init ar71xx_spi_init(void)
++{
++	printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n");
++	return platform_driver_register(&ar71xx_spi_drv);
++}
++module_init(ar71xx_spi_init);
++
++static void __exit ar71xx_spi_exit(void)
++{
++	platform_driver_unregister(&ar71xx_spi_drv);
++}
++module_exit(ar71xx_spi_exit);
++
++MODULE_ALIAS("platform:" DRV_NAME);
++MODULE_DESCRIPTION(DRV_DESC);
++MODULE_VERSION(DRV_VERSION);
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_AUTHOR("Imre Kaloz <kaloz@openwrt.org>");
++MODULE_LICENSE("GPL v2");
+diff -Nur linux-2.6.33.3.orig/drivers/spi/Kconfig linux-2.6.33.3/drivers/spi/Kconfig
+--- linux-2.6.33.3.orig/drivers/spi/Kconfig	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/drivers/spi/Kconfig	2010-05-17 16:28:32.431125868 +0200
+@@ -53,6 +53,13 @@
+ 
+ comment "SPI Master Controller Drivers"
+ 
++config SPI_AR71XX
++	tristate "Atheros AR71xx SPI Controller"
++	depends on SPI_MASTER && ATHEROS_AR71XX
++	select SPI_BITBANG
++	help
++	  This is the SPI contoller driver for Atheros AR71xx.
++
+ config SPI_ATMEL
+ 	tristate "Atmel SPI Controller"
+ 	depends on (ARCH_AT91 || AVR32)
+diff -Nur linux-2.6.33.3.orig/drivers/spi/Makefile linux-2.6.33.3/drivers/spi/Makefile
+--- linux-2.6.33.3.orig/drivers/spi/Makefile	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/drivers/spi/Makefile	2010-05-17 16:28:32.431125868 +0200
+@@ -11,6 +11,7 @@
+ obj-$(CONFIG_SPI_MASTER)		+= spi.o
+ 
+ # SPI master controller drivers (bus)
++obj-$(CONFIG_SPI_AR71XX)		+= ar71xx_spi.o
+ obj-$(CONFIG_SPI_ATMEL)			+= atmel_spi.o
+ obj-$(CONFIG_SPI_BFIN)			+= spi_bfin5xx.o
+ obj-$(CONFIG_SPI_BITBANG)		+= spi_bitbang.o
+diff -Nur linux-2.6.33.3.orig/drivers/spi/pb44_spi.c linux-2.6.33.3/drivers/spi/pb44_spi.c
+--- linux-2.6.33.3.orig/drivers/spi/pb44_spi.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/drivers/spi/pb44_spi.c	2009-12-13 20:45:24.847920760 +0100
+@@ -0,0 +1,299 @@
++/*
++ * Atheros PB44 board SPI controller driver
++ *
++ * Copyright (C) 2009 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/init.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/workqueue.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spi_bitbang.h>
++#include <linux/bitops.h>
++#include <linux/gpio.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/platform.h>
++
++#define DRV_DESC	"Atheros PB44 SPI Controller driver"
++#define DRV_VERSION	"0.1.0"
++#define DRV_NAME	"pb44-spi"
++
++#undef PER_BIT_READ
++
++struct ar71xx_spi {
++	struct	spi_bitbang 	bitbang;
++	u32			ioc_base;
++	u32			reg_ctrl;
++
++	void __iomem 		*base;
++
++	struct platform_device	*pdev;
++};
++
++static inline u32 pb44_spi_rr(struct ar71xx_spi *sp, unsigned reg)
++{
++	return __raw_readl(sp->base + reg);
++}
++
++static inline void pb44_spi_wr(struct ar71xx_spi *sp, unsigned reg, u32 val)
++{
++	__raw_writel(val, sp->base + reg);
++}
++
++static inline struct ar71xx_spi *spidev_to_sp(struct spi_device *spi)
++{
++	return spi_master_get_devdata(spi->master);
++}
++
++static void pb44_spi_chipselect(struct spi_device *spi, int is_active)
++{
++	struct ar71xx_spi *sp = spidev_to_sp(spi);
++	int cs_high = (spi->mode & SPI_CS_HIGH) ? is_active : !is_active;
++
++	if (is_active) {
++		/* set initial clock polarity */
++		if (spi->mode & SPI_CPOL)
++			sp->ioc_base |= SPI_IOC_CLK;
++		else
++			sp->ioc_base &= ~SPI_IOC_CLK;
++
++		pb44_spi_wr(sp, SPI_REG_IOC, sp->ioc_base);
++	}
++
++	if (spi->chip_select) {
++		unsigned long gpio = (unsigned long) spi->controller_data;
++
++		/* SPI is normally active-low */
++		gpio_set_value(gpio, cs_high);
++	} else {
++		if (cs_high)
++			sp->ioc_base |= SPI_IOC_CS0;
++		else
++			sp->ioc_base &= ~SPI_IOC_CS0;
++
++		pb44_spi_wr(sp, SPI_REG_IOC, sp->ioc_base);
++	}
++
++}
++
++static int pb44_spi_setup_cs(struct spi_device *spi)
++{
++	struct ar71xx_spi *sp = spidev_to_sp(spi);
++
++	/* enable GPIO mode */
++	pb44_spi_wr(sp, SPI_REG_FS, SPI_FS_GPIO);
++
++	/* save CTRL register */
++	sp->reg_ctrl = pb44_spi_rr(sp, SPI_REG_CTRL);
++	sp->ioc_base = pb44_spi_rr(sp, SPI_REG_IOC);
++
++	/* TODO: setup speed? */
++	pb44_spi_wr(sp, SPI_REG_CTRL, 0x43);
++
++	if (spi->chip_select) {
++		unsigned long gpio = (unsigned long) spi->controller_data;
++		int status = 0;
++
++		status = gpio_request(gpio, dev_name(&spi->dev));
++		if (status)
++			return status;
++
++		status = gpio_direction_output(gpio, spi->mode & SPI_CS_HIGH);
++		if (status) {
++			gpio_free(gpio);
++			return status;
++		}
++	} else {
++		if (spi->mode & SPI_CS_HIGH)
++			sp->ioc_base |= SPI_IOC_CS0;
++		else
++			sp->ioc_base &= ~SPI_IOC_CS0;
++		pb44_spi_wr(sp, SPI_REG_IOC, sp->ioc_base);
++	}
++
++	return 0;
++}
++
++static void pb44_spi_cleanup_cs(struct spi_device *spi)
++{
++	struct ar71xx_spi *sp = spidev_to_sp(spi);
++
++	if (spi->chip_select) {
++		unsigned long gpio = (unsigned long) spi->controller_data;
++		gpio_free(gpio);
++	}
++
++	/* restore CTRL register */
++	pb44_spi_wr(sp, SPI_REG_CTRL, sp->reg_ctrl);
++	/* disable GPIO mode */
++	pb44_spi_wr(sp, SPI_REG_FS, 0);
++}
++
++static int pb44_spi_setup(struct spi_device *spi)
++{
++	int status = 0;
++
++	if (spi->bits_per_word > 32)
++		return -EINVAL;
++
++	if (!spi->controller_state) {
++		status = pb44_spi_setup_cs(spi);
++		if (status)
++			return status;
++	}
++
++	status = spi_bitbang_setup(spi);
++	if (status && !spi->controller_state)
++		pb44_spi_cleanup_cs(spi);
++
++	return status;
++}
++
++static void pb44_spi_cleanup(struct spi_device *spi)
++{
++	pb44_spi_cleanup_cs(spi);
++	spi_bitbang_cleanup(spi);
++}
++
++static u32 pb44_spi_txrx_mode0(struct spi_device *spi, unsigned nsecs,
++			       u32 word, u8 bits)
++{
++	struct ar71xx_spi *sp = spidev_to_sp(spi);
++	u32 ioc = sp->ioc_base;
++	u32 ret;
++
++	/* clock starts at inactive polarity */
++	for (word <<= (32 - bits); likely(bits); bits--) {
++		u32 out;
++
++		if (word & (1 << 31))
++			out = ioc | SPI_IOC_DO;
++		else
++			out = ioc & ~SPI_IOC_DO;
++
++		/* setup MSB (to slave) on trailing edge */
++		pb44_spi_wr(sp, SPI_REG_IOC, out);
++		pb44_spi_wr(sp, SPI_REG_IOC, out | SPI_IOC_CLK);
++
++		word <<= 1;
++
++#ifdef PER_BIT_READ
++		/* sample MSB (from slave) on leading edge */
++		ret = pb44_spi_rr(sp, SPI_REG_RDS);
++		pb44_spi_wr(sp, SPI_REG_IOC, out);
++#endif
++	}
++
++#ifndef PER_BIT_READ
++	ret = pb44_spi_rr(sp, SPI_REG_RDS);
++#endif
++	return ret;
++}
++
++static int pb44_spi_probe(struct platform_device *pdev)
++{
++	struct spi_master *master;
++	struct ar71xx_spi *sp;
++	struct ar71xx_spi_platform_data *pdata;
++	struct resource	*r;
++	int ret;
++
++	master = spi_alloc_master(&pdev->dev, sizeof(*sp));
++	if (master == NULL) {
++		dev_err(&pdev->dev, "failed to allocate spi master\n");
++		return -ENOMEM;
++	}
++
++	sp = spi_master_get_devdata(master);
++	platform_set_drvdata(pdev, sp);
++
++	pdata = pdev->dev.platform_data;
++
++	master->setup = pb44_spi_setup;
++	master->cleanup = pb44_spi_cleanup;
++	if (pdata) {
++		master->bus_num = pdata->bus_num;
++		master->num_chipselect = pdata->num_chipselect;
++	} else {
++		master->bus_num = 0;
++		master->num_chipselect = 1;
++	}
++
++	sp->bitbang.master = spi_master_get(master);
++	sp->bitbang.chipselect = pb44_spi_chipselect;
++	sp->bitbang.txrx_word[SPI_MODE_0] = pb44_spi_txrx_mode0;
++	sp->bitbang.setup_transfer = spi_bitbang_setup_transfer;
++	sp->bitbang.flags = SPI_CS_HIGH;
++
++	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (r == NULL) {
++		ret = -ENOENT;
++		goto err1;
++	}
++
++	sp->base = ioremap_nocache(r->start, r->end - r->start + 1);
++	if (!sp->base) {
++		ret = -ENXIO;
++		goto err1;
++	}
++
++	ret = spi_bitbang_start(&sp->bitbang);
++	if (!ret)
++		return 0;
++
++	iounmap(sp->base);
++ err1:
++	platform_set_drvdata(pdev, NULL);
++	spi_master_put(sp->bitbang.master);
++
++	return ret;
++}
++
++static int pb44_spi_remove(struct platform_device *pdev)
++{
++	struct ar71xx_spi *sp = platform_get_drvdata(pdev);
++
++	spi_bitbang_stop(&sp->bitbang);
++	iounmap(sp->base);
++	platform_set_drvdata(pdev, NULL);
++	spi_master_put(sp->bitbang.master);
++
++	return 0;
++}
++
++static struct platform_driver pb44_spi_drv = {
++	.probe		= pb44_spi_probe,
++	.remove		= pb44_spi_remove,
++	.driver		= {
++		.name	= DRV_NAME,
++		.owner	= THIS_MODULE,
++	},
++};
++
++static int __init pb44_spi_init(void)
++{
++	return platform_driver_register(&pb44_spi_drv);
++}
++module_init(pb44_spi_init);
++
++static void __exit pb44_spi_exit(void)
++{
++	platform_driver_unregister(&pb44_spi_drv);
++}
++module_exit(pb44_spi_exit);
++
++MODULE_ALIAS("platform:" DRV_NAME);
++MODULE_DESCRIPTION(DRV_DESC);
++MODULE_VERSION(DRV_VERSION);
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_LICENSE("GPL v2");
+diff -Nur linux-2.6.33.3.orig/drivers/spi/spi_vsc7385.c linux-2.6.33.3/drivers/spi/spi_vsc7385.c
+--- linux-2.6.33.3.orig/drivers/spi/spi_vsc7385.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/drivers/spi/spi_vsc7385.c	2009-12-13 20:45:24.863922134 +0100
+@@ -0,0 +1,620 @@
++/*
++ * SPI driver for the Vitesse VSC7385 ethernet switch
++ *
++ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ * 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/types.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/bitops.h>
++#include <linux/firmware.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/vsc7385.h>
++
++#define DRV_NAME	"spi-vsc7385"
++#define DRV_DESC	"Vitesse VSC7385 Gbit ethernet switch driver"
++#define DRV_VERSION	"0.1.0"
++
++#define VSC73XX_BLOCK_MAC	0x1
++#define VSC73XX_BLOCK_2		0x2
++#define VSC73XX_BLOCK_MII	0x3
++#define VSC73XX_BLOCK_4		0x4
++#define VSC73XX_BLOCK_5		0x5
++#define VSC73XX_BLOCK_SYSTEM	0x7
++
++#define VSC73XX_SUBBLOCK_PORT_0		0
++#define VSC73XX_SUBBLOCK_PORT_1		1
++#define VSC73XX_SUBBLOCK_PORT_2		2
++#define VSC73XX_SUBBLOCK_PORT_3		3
++#define VSC73XX_SUBBLOCK_PORT_4		4
++#define VSC73XX_SUBBLOCK_PORT_MAC	6
++
++/* MAC Block registers */
++#define VSC73XX_MAC_CFG		0x0
++#define VSC73XX_ADVPORTM	0x19
++#define VSC73XX_RXOCT		0x50
++#define VSC73XX_TXOCT		0x51
++#define VSC73XX_C_RX0		0x52
++#define VSC73XX_C_RX1		0x53
++#define VSC73XX_C_RX2		0x54
++#define VSC73XX_C_TX0		0x55
++#define VSC73XX_C_TX1		0x56
++#define VSC73XX_C_TX2		0x57
++#define VSC73XX_C_CFG		0x58
++
++/* MAC_CFG register bits */
++#define VSC73XX_MAC_CFG_WEXC_DIS	(1 << 31)
++#define VSC73XX_MAC_CFG_PORT_RST	(1 << 29)
++#define VSC73XX_MAC_CFG_TX_EN		(1 << 28)
++#define VSC73XX_MAC_CFG_SEED_LOAD      	(1 << 27)
++#define VSC73XX_MAC_CFG_FDX	        (1 << 18)
++#define VSC73XX_MAC_CFG_GIGE		(1 << 17)
++#define VSC73XX_MAC_CFG_RX_EN		(1 << 16)
++#define VSC73XX_MAC_CFG_VLAN_DBLAWR	(1 << 15)
++#define VSC73XX_MAC_CFG_VLAN_AWR	(1 << 14)
++#define VSC73XX_MAC_CFG_100_BASE_T	(1 << 13)
++#define VSC73XX_MAC_CFG_TX_IPG(x)	(((x) & 0x1f) << 6)
++#define VSC73XX_MAC_CFG_MAC_RX_RST	(1 << 5)
++#define VSC73XX_MAC_CFG_MAC_TX_RST	(1 << 4)
++#define VSC73XX_MAC_CFG_BIT2		(1 << 2)
++#define VSC73XX_MAC_CFG_CLK_SEL(x)	((x) & 0x3)
++
++/* ADVPORTM register bits */
++#define VSC73XX_ADVPORTM_IFG_PPM	(1 << 7)
++#define VSC73XX_ADVPORTM_EXC_COL_CONT	(1 << 6)
++#define VSC73XX_ADVPORTM_EXT_PORT	(1 << 5)
++#define VSC73XX_ADVPORTM_INV_GTX	(1 << 4)
++#define VSC73XX_ADVPORTM_ENA_GTX	(1 << 3)
++#define VSC73XX_ADVPORTM_DDR_MODE	(1 << 2)
++#define VSC73XX_ADVPORTM_IO_LOOPBACK	(1 << 1)
++#define VSC73XX_ADVPORTM_HOST_LOOPBACK	(1 << 0)
++
++/* MII Block registers */
++#define VSC73XX_MII_STAT	0x0
++#define VSC73XX_MII_CMD		0x1
++#define VSC73XX_MII_DATA	0x2
++
++/* System Block registers */
++#define VSC73XX_ICPU_SIPAD		0x01
++#define VSC73XX_ICPU_CLOCK_DELAY	0x05
++#define VSC73XX_ICPU_CTRL		0x10
++#define VSC73XX_ICPU_ADDR		0x11
++#define VSC73XX_ICPU_SRAM		0x12
++#define VSC73XX_ICPU_MBOX_VAL		0x15
++#define VSC73XX_ICPU_MBOX_SET		0x16
++#define VSC73XX_ICPU_MBOX_CLR		0x17
++#define VSC73XX_ICPU_CHIPID		0x18
++#define VSC73XX_ICPU_GPIO		0x34
++
++#define VSC73XX_ICPU_CTRL_CLK_DIV	(1 << 8)
++#define VSC73XX_ICPU_CTRL_SRST_HOLD	(1 << 7)
++#define VSC73XX_ICPU_CTRL_BOOT_EN	(1 << 3)
++#define VSC73XX_ICPU_CTRL_EXT_ACC_EN	(1 << 2)
++#define VSC73XX_ICPU_CTRL_CLK_EN	(1 << 1)
++#define VSC73XX_ICPU_CTRL_SRST		(1 << 0)
++
++#define VSC73XX_ICPU_CHIPID_ID_SHIFT	12
++#define VSC73XX_ICPU_CHIPID_ID_MASK	0xffff
++#define VSC73XX_ICPU_CHIPID_REV_SHIFT	28
++#define VSC73XX_ICPU_CHIPID_REV_MASK	0xf
++#define VSC73XX_ICPU_CHIPID_ID_7385	0x7385
++#define VSC73XX_ICPU_CHIPID_ID_7395	0x7395
++
++#define VSC73XX_CMD_MODE_READ		0
++#define VSC73XX_CMD_MODE_WRITE		1
++#define VSC73XX_CMD_MODE_SHIFT		4
++#define VSC73XX_CMD_BLOCK_SHIFT		5
++#define VSC73XX_CMD_BLOCK_MASK		0x7
++#define VSC73XX_CMD_SUBBLOCK_MASK	0xf
++
++#define VSC7385_CLOCK_DELAY		((3 << 4) | 3)
++#define VSC7385_CLOCK_DELAY_MASK	((3 << 4) | 3)
++
++#define VSC73XX_ICPU_CTRL_STOP	(VSC73XX_ICPU_CTRL_SRST_HOLD | \
++				 VSC73XX_ICPU_CTRL_BOOT_EN | \
++				 VSC73XX_ICPU_CTRL_EXT_ACC_EN)
++
++#define VSC73XX_ICPU_CTRL_START	(VSC73XX_ICPU_CTRL_CLK_DIV | \
++				 VSC73XX_ICPU_CTRL_BOOT_EN | \
++				 VSC73XX_ICPU_CTRL_CLK_EN | \
++				 VSC73XX_ICPU_CTRL_SRST)
++
++#define VSC7385_ADVPORTM_MASK	(VSC73XX_ADVPORTM_IFG_PPM | \
++				 VSC73XX_ADVPORTM_EXC_COL_CONT | \
++				 VSC73XX_ADVPORTM_EXT_PORT | \
++				 VSC73XX_ADVPORTM_INV_GTX | \
++				 VSC73XX_ADVPORTM_ENA_GTX | \
++				 VSC73XX_ADVPORTM_DDR_MODE | \
++				 VSC73XX_ADVPORTM_IO_LOOPBACK | \
++				 VSC73XX_ADVPORTM_HOST_LOOPBACK)
++
++#define VSC7385_ADVPORTM_INIT	(VSC73XX_ADVPORTM_EXT_PORT | \
++				 VSC73XX_ADVPORTM_ENA_GTX | \
++				 VSC73XX_ADVPORTM_DDR_MODE)
++
++#define VSC7385_MAC_CFG_RESET	(VSC73XX_MAC_CFG_PORT_RST | \
++				 VSC73XX_MAC_CFG_MAC_RX_RST | \
++				 VSC73XX_MAC_CFG_MAC_TX_RST)
++
++#define VSC73XX_MAC_CFG_INIT	(VSC73XX_MAC_CFG_TX_EN | \
++				 VSC73XX_MAC_CFG_FDX | \
++				 VSC73XX_MAC_CFG_GIGE | \
++				 VSC73XX_MAC_CFG_RX_EN)
++
++#define VSC73XX_RESET_DELAY	100
++
++struct vsc7385 {
++	struct spi_device		*spi;
++	struct mutex			lock;
++	struct vsc7385_platform_data	*pdata;
++};
++
++static int vsc7385_is_addr_valid(u8 block, u8 subblock)
++{
++	switch (block) {
++	case VSC73XX_BLOCK_MAC:
++		switch (subblock) {
++		case 0 ... 4:
++		case 6:
++			return 1;
++		}
++		break;
++
++	case VSC73XX_BLOCK_2:
++	case VSC73XX_BLOCK_SYSTEM:
++		switch (subblock) {
++		case 0:
++			return 1;
++		}
++		break;
++
++	case VSC73XX_BLOCK_MII:
++	case VSC73XX_BLOCK_4:
++	case VSC73XX_BLOCK_5:
++		switch (subblock) {
++		case 0 ... 1:
++			return 1;
++		}
++		break;
++	}
++
++	return 0;
++}
++
++static inline u8 vsc7385_make_addr(u8 mode, u8 block, u8 subblock)
++{
++	u8 ret;
++
++	ret = (block & VSC73XX_CMD_BLOCK_MASK) << VSC73XX_CMD_BLOCK_SHIFT;
++	ret |= (mode & 1) << VSC73XX_CMD_MODE_SHIFT;
++	ret |= subblock & VSC73XX_CMD_SUBBLOCK_MASK;
++
++	return ret;
++}
++
++static int vsc7385_read(struct vsc7385 *vsc, u8 block, u8 subblock, u8 reg,
++			u32 *value)
++{
++	u8 cmd[4];
++	u8 buf[4];
++	struct spi_transfer t[2];
++	struct spi_message m;
++	int err;
++
++	if (!vsc7385_is_addr_valid(block, subblock))
++		return -EINVAL;
++
++	spi_message_init(&m);
++
++	memset(&t, 0, sizeof(t));
++
++	t[0].tx_buf = cmd;
++	t[0].len = sizeof(cmd);
++	spi_message_add_tail(&t[0], &m);
++
++	t[1].rx_buf = buf;
++	t[1].len = sizeof(buf);
++	spi_message_add_tail(&t[1], &m);
++
++	cmd[0] = vsc7385_make_addr(VSC73XX_CMD_MODE_READ, block, subblock);
++	cmd[1] = reg;
++	cmd[2] = 0;
++	cmd[3] = 0;
++
++	mutex_lock(&vsc->lock);
++	err = spi_sync(vsc->spi, &m);
++	mutex_unlock(&vsc->lock);
++
++	if (err)
++		return err;
++
++	*value = (((u32) buf[0]) << 24) | (((u32) buf[1]) << 16) |
++		 (((u32) buf[2]) << 8) | ((u32) buf[3]);
++
++	return 0;
++}
++
++
++static int vsc7385_write(struct vsc7385 *vsc, u8 block, u8 subblock, u8 reg,
++			 u32 value)
++{
++	u8 cmd[2];
++	u8 buf[4];
++	struct spi_transfer t[2];
++	struct spi_message m;
++	int err;
++
++	if (!vsc7385_is_addr_valid(block, subblock))
++		return -EINVAL;
++
++	spi_message_init(&m);
++
++	memset(&t, 0, sizeof(t));
++
++	t[0].tx_buf = cmd;
++	t[0].len = sizeof(cmd);
++	spi_message_add_tail(&t[0], &m);
++
++	t[1].tx_buf = buf;
++	t[1].len = sizeof(buf);
++	spi_message_add_tail(&t[1], &m);
++
++	cmd[0] = vsc7385_make_addr(VSC73XX_CMD_MODE_WRITE, block, subblock);
++	cmd[1] = reg;
++
++	buf[0] = (value >> 24) & 0xff;
++	buf[1] = (value >> 16) & 0xff;
++	buf[2] = (value >> 8) & 0xff;
++	buf[3] = value & 0xff;
++
++	mutex_lock(&vsc->lock);
++	err = spi_sync(vsc->spi, &m);
++	mutex_unlock(&vsc->lock);
++
++	return err;
++}
++
++static inline int vsc7385_write_verify(struct vsc7385 *vsc, u8 block,
++				       u8 subblock, u8 reg, u32 value,
++				       u32 read_mask, u32 read_val)
++{
++	struct spi_device *spi = vsc->spi;
++	u32 t;
++	int err;
++
++	err = vsc7385_write(vsc, block, subblock, reg, value);
++	if (err)
++		return err;
++
++	err = vsc7385_read(vsc, block, subblock, reg, &t);
++	if (err)
++		return err;
++
++	if ((t & read_mask) != read_val) {
++		dev_err(&spi->dev, "register write error\n");
++		return -EIO;
++	}
++
++	return 0;
++}
++
++static inline int vsc7385_set_clock_delay(struct vsc7385 *vsc, u32 val)
++{
++	return vsc7385_write(vsc, VSC73XX_BLOCK_SYSTEM, 0,
++			     VSC73XX_ICPU_CLOCK_DELAY, val);
++}
++
++static inline int vsc7385_get_clock_delay(struct vsc7385 *vsc, u32 *val)
++{
++	return vsc7385_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
++			    VSC73XX_ICPU_CLOCK_DELAY, val);
++}
++
++static inline int vsc7385_icpu_stop(struct vsc7385 *vsc)
++{
++	return vsc7385_write(vsc, VSC73XX_BLOCK_SYSTEM, 0, VSC73XX_ICPU_CTRL,
++			     VSC73XX_ICPU_CTRL_STOP);
++}
++
++static inline int vsc7385_icpu_start(struct vsc7385 *vsc)
++{
++	return vsc7385_write(vsc, VSC73XX_BLOCK_SYSTEM, 0, VSC73XX_ICPU_CTRL,
++			     VSC73XX_ICPU_CTRL_START);
++}
++
++static inline int vsc7385_icpu_reset(struct vsc7385 *vsc)
++{
++	int rc;
++
++	rc = vsc7385_write(vsc, VSC73XX_BLOCK_SYSTEM, 0, VSC73XX_ICPU_ADDR,
++			   0x0000);
++	if (rc)
++		dev_err(&vsc->spi->dev,
++			"could not reset microcode, err=%d\n", rc);
++
++	return rc;
++}
++
++static int vsc7385_upload_ucode(struct vsc7385 *vsc)
++{
++	struct spi_device *spi = vsc->spi;
++	const struct firmware *firmware;
++	char *ucode_name;
++	unsigned char *dp;
++	unsigned int curVal;
++	int i;
++	int diffs;
++	int rc;
++
++	ucode_name = (vsc->pdata->ucode_name) ? vsc->pdata->ucode_name
++					      : "vsc7385_ucode.bin";
++	rc = request_firmware(&firmware, ucode_name, &spi->dev);
++	if (rc) {
++		dev_err(&spi->dev, "request_firmware failed, err=%d\n",
++			rc);
++		return rc;
++	}
++
++	rc = vsc7385_icpu_stop(vsc);
++	if (rc)
++		goto out;
++
++	rc = vsc7385_icpu_reset(vsc);
++	if (rc)
++		goto out;
++
++	dev_info(&spi->dev, "uploading microcode...\n");
++
++	dp = (unsigned char *) firmware->data;
++	for (i = 0; i < firmware->size; i++) {
++		rc = vsc7385_write(vsc, VSC73XX_BLOCK_SYSTEM, 0,
++				   VSC73XX_ICPU_SRAM, *dp++);
++		if (rc) {
++			dev_err(&spi->dev, "could not load microcode, err=%d\n",
++				rc);
++			goto out;
++		}
++	}
++
++	rc = vsc7385_icpu_reset(vsc);
++	if (rc)
++		goto out;
++
++	dev_info(&spi->dev, "verifying microcode...\n");
++
++	dp = (unsigned char *) firmware->data;
++	diffs = 0;
++	for (i = 0; i < firmware->size; i++) {
++		rc = vsc7385_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
++				  VSC73XX_ICPU_SRAM, &curVal);
++		if (rc) {
++			dev_err(&spi->dev, "could not read microcode %d\n",rc);
++			goto out;
++		}
++
++		if (curVal > 0xff) {
++			dev_err(&spi->dev, "bad val read: %04x : %02x  %02x\n",
++				i, *dp, curVal);
++			rc = -EIO;
++			goto out;
++		}
++
++		if ((curVal & 0xff) != *dp) {
++			diffs++;
++			dev_err(&spi->dev, "verify error: %04x : %02x  %02x\n",
++				i, *dp, curVal);
++
++			if (diffs > 4)
++				break;
++			}
++		dp++;
++	}
++
++	if (diffs) {
++		dev_err(&spi->dev, "microcode verification failed\n");
++		rc = -EIO;
++		goto out;
++	}
++
++	dev_info(&spi->dev, "microcode uploaded\n");
++
++	rc = vsc7385_icpu_start(vsc);
++
++ out:
++	release_firmware(firmware);
++	return rc;
++}
++
++static int vsc7385_setup(struct vsc7385 *vsc)
++{
++	struct vsc7385_platform_data *pdata = vsc->pdata;
++	u32 t;
++	int err;
++
++	err = vsc7385_write_verify(vsc, VSC73XX_BLOCK_SYSTEM, 0,
++				   VSC73XX_ICPU_CLOCK_DELAY,
++				   VSC7385_CLOCK_DELAY,
++				   VSC7385_CLOCK_DELAY_MASK,
++				   VSC7385_CLOCK_DELAY);
++	if (err)
++		goto err;
++
++	err = vsc7385_write_verify(vsc, VSC73XX_BLOCK_MAC,
++				   VSC73XX_SUBBLOCK_PORT_MAC, VSC73XX_ADVPORTM,
++				   VSC7385_ADVPORTM_INIT,
++				   VSC7385_ADVPORTM_MASK,
++				   VSC7385_ADVPORTM_INIT);
++	if (err)
++		goto err;
++
++	err = vsc7385_write(vsc, VSC73XX_BLOCK_MAC, VSC73XX_SUBBLOCK_PORT_MAC,
++			    VSC73XX_MAC_CFG, VSC7385_MAC_CFG_RESET);
++	if (err)
++		goto err;
++
++	t = VSC73XX_MAC_CFG_INIT;
++	t |= VSC73XX_MAC_CFG_TX_IPG(pdata->mac_cfg.tx_ipg);
++	t |= VSC73XX_MAC_CFG_CLK_SEL(pdata->mac_cfg.clk_sel);
++	if (pdata->mac_cfg.bit2)
++		t |= VSC73XX_MAC_CFG_BIT2;
++
++	err = vsc7385_write(vsc, VSC73XX_BLOCK_MAC, VSC73XX_SUBBLOCK_PORT_MAC,
++			    VSC73XX_MAC_CFG, t);
++	if (err)
++		goto err;
++
++	return 0;
++
++ err:
++	return err;
++}
++
++static int vsc7385_detect(struct vsc7385 *vsc)
++{
++	struct spi_device *spi = vsc->spi;
++	u32 t;
++	u32 id;
++	u32 rev;
++	int err;
++
++	err = vsc7385_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
++				VSC73XX_ICPU_MBOX_VAL, &t);
++	if (err) {
++		dev_err(&spi->dev, "unable to read mailbox, err=%d\n", err);
++		return err;
++	}
++
++	if (t == 0xffffffff) {
++		dev_dbg(&spi->dev, "assert chip reset\n");
++		if (vsc->pdata->reset)
++			vsc->pdata->reset();
++
++	}
++
++	err = vsc7385_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
++				VSC73XX_ICPU_CHIPID, &t);
++	if (err) {
++		dev_err(&spi->dev, "unable to read chip id, err=%d\n", err);
++		return err;
++	}
++
++	id = (t >> VSC73XX_ICPU_CHIPID_ID_SHIFT) & VSC73XX_ICPU_CHIPID_ID_MASK;
++	switch (id) {
++	case VSC73XX_ICPU_CHIPID_ID_7385:
++	case VSC73XX_ICPU_CHIPID_ID_7395:
++		break;
++	default:
++		dev_err(&spi->dev, "unsupported chip, id=%04x\n", id);
++		return -ENODEV;
++	}
++
++	rev = (t >> VSC73XX_ICPU_CHIPID_REV_SHIFT) &
++	      VSC73XX_ICPU_CHIPID_REV_MASK;
++	dev_info(&spi->dev, "VSC%04X (rev. %d) switch found \n", id, rev);
++
++	return 0;
++}
++
++static int __devinit vsc7385_probe(struct spi_device *spi)
++{
++	struct vsc7385 *vsc;
++	struct vsc7385_platform_data *pdata;
++	int	err;
++
++	printk(KERN_INFO DRV_DESC " version " DRV_VERSION"\n");
++
++	pdata = spi->dev.platform_data;
++	if (!pdata) {
++		dev_err(&spi->dev, "no platform data specified\n");
++		return-ENODEV;
++	}
++
++	vsc = kzalloc(sizeof(*vsc), GFP_KERNEL);
++	if (!vsc) {
++		dev_err(&spi->dev, "no memory for private data\n");
++		return-ENOMEM;
++	}
++
++	mutex_init(&vsc->lock);
++	vsc->pdata = pdata;
++	vsc->spi = spi_dev_get(spi);
++	dev_set_drvdata(&spi->dev, vsc);
++
++	spi->mode = SPI_MODE_0;
++	spi->bits_per_word = 8;
++	err = spi_setup(spi);
++	if (err) {
++		dev_err(&spi->dev, "spi_setup failed, err=%d \n", err);
++		goto err_drvdata;
++	}
++
++	err = vsc7385_detect(vsc);
++	if (err) {
++		dev_err(&spi->dev, "no chip found, err=%d \n", err);
++		goto err_drvdata;
++	}
++
++	err = vsc7385_upload_ucode(vsc);
++	if (err)
++		goto err_drvdata;
++
++	err = vsc7385_setup(vsc);
++	if (err)
++		goto err_drvdata;
++
++	return 0;
++
++ err_drvdata:
++	dev_set_drvdata(&spi->dev, NULL);
++	kfree(vsc);
++	return err;
++}
++
++static int __devexit vsc7385_remove(struct spi_device *spi)
++{
++	struct vsc7385_data	*vsc;
++
++	vsc = dev_get_drvdata(&spi->dev);
++	dev_set_drvdata(&spi->dev, NULL);
++	kfree(vsc);
++
++	return 0;
++}
++
++static struct spi_driver vsc7385_driver = {
++	.driver = {
++		.name		= DRV_NAME,
++		.bus		= &spi_bus_type,
++		.owner		= THIS_MODULE,
++	},
++	.probe		= vsc7385_probe,
++	.remove		= __devexit_p(vsc7385_remove),
++};
++
++static int __init vsc7385_init(void)
++{
++	return spi_register_driver(&vsc7385_driver);
++}
++module_init(vsc7385_init);
++
++static void __exit vsc7385_exit(void)
++{
++	spi_unregister_driver(&vsc7385_driver);
++}
++module_exit(vsc7385_exit);
++
++MODULE_DESCRIPTION(DRV_DESC);
++MODULE_VERSION(DRV_VERSION);
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_LICENSE("GPL v2");
++
+diff -Nur linux-2.6.33.3.orig/drivers/usb/host/ehci-ar71xx.c linux-2.6.33.3/drivers/usb/host/ehci-ar71xx.c
+--- linux-2.6.33.3.orig/drivers/usb/host/ehci-ar71xx.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/drivers/usb/host/ehci-ar71xx.c	2010-02-09 00:28:55.636370581 +0100
+@@ -0,0 +1,242 @@
++/*
++ *  Bus Glue for Atheros AR71xx built-in EHCI controller.
++ *
++ *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  Parts of this file are based on Atheros' 2.6.15 BSP
++ *	Copyright (C) 2007 Atheros Communications, Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify it
++ *  under the terms of the GNU General Public License version 2 as published
++ *  by the Free Software Foundation.
++ */
++
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++
++#include <asm/mach-ar71xx/platform.h>
++
++extern int usb_disabled(void);
++
++static int ehci_ar71xx_init(struct usb_hcd *hcd)
++{
++	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++	int ret;
++
++	ehci->caps = hcd->regs;
++	ehci->regs = hcd->regs +
++			HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
++	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
++
++	ehci->sbrn = 0x20;
++	ehci->has_synopsys_hc_bug = 1;
++
++	ehci_reset(ehci);
++
++	ret = ehci_init(hcd);
++	if (ret)
++		return ret;
++
++	ehci_port_power(ehci, 0);
++
++	return 0;
++}
++
++static int ehci_ar91xx_init(struct usb_hcd *hcd)
++{
++	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++	int ret;
++
++	ehci->caps = hcd->regs + 0x100;
++	ehci->regs = hcd->regs + 0x100 +
++			HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
++	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
++
++	hcd->has_tt = 1;
++	ehci->sbrn = 0x20;
++
++	ehci_reset(ehci);
++
++	ret = ehci_init(hcd);
++	if (ret)
++		return ret;
++
++	ehci_port_power(ehci, 0);
++
++	return 0;
++}
++
++static int ehci_ar71xx_probe(const struct hc_driver *driver,
++			     struct usb_hcd **hcd_out,
++			     struct platform_device *pdev)
++{
++	struct usb_hcd *hcd;
++	struct resource *res;
++	int irq;
++	int ret;
++
++	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;
++
++	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));
++		return -ENODEV;
++	}
++
++	hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
++	if (!hcd)
++		return -ENOMEM;
++
++	hcd->rsrc_start	= res->start;
++	hcd->rsrc_len	= 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;
++	}
++
++	ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
++	if (ret)
++		goto err_iounmap;
++
++	return 0;
++
++ err_iounmap:
++	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 void ehci_ar71xx_remove(struct usb_hcd *hcd,
++			       struct platform_device *pdev)
++{
++	usb_remove_hcd(hcd);
++	iounmap(hcd->regs);
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++	usb_put_hcd(hcd);
++}
++
++static const struct hc_driver ehci_ar71xx_hc_driver = {
++	.description		= hcd_name,
++	.product_desc		= "Atheros AR71xx built-in EHCI controller",
++	.hcd_priv_size		= sizeof(struct ehci_hcd),
++
++	.irq			= ehci_irq,
++	.flags			= HCD_MEMORY | HCD_USB2,
++
++	.reset			= ehci_ar71xx_init,
++	.start			= ehci_run,
++	.stop			= ehci_stop,
++	.shutdown		= ehci_shutdown,
++
++	.urb_enqueue		= ehci_urb_enqueue,
++	.urb_dequeue		= ehci_urb_dequeue,
++	.endpoint_disable	= ehci_endpoint_disable,
++	.endpoint_reset		= ehci_endpoint_reset,
++
++	.get_frame_number	= ehci_get_frame,
++
++	.hub_status_data	= ehci_hub_status_data,
++	.hub_control		= ehci_hub_control,
++#ifdef CONFIG_PM
++	.hub_suspend		= ehci_hub_suspend,
++	.hub_resume		= ehci_hub_resume,
++#endif
++	.relinquish_port	= ehci_relinquish_port,
++	.port_handed_over	= ehci_port_handed_over,
++
++	.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
++};
++
++static const struct hc_driver ehci_ar91xx_hc_driver = {
++	.description		= hcd_name,
++	.product_desc		= "Atheros AR91xx built-in EHCI controller",
++	.hcd_priv_size		= sizeof(struct ehci_hcd),
++	.irq			= ehci_irq,
++	.flags			= HCD_MEMORY | HCD_USB2,
++
++	.reset			= ehci_ar91xx_init,
++	.start			= ehci_run,
++	.stop			= ehci_stop,
++	.shutdown		= ehci_shutdown,
++
++	.urb_enqueue		= ehci_urb_enqueue,
++	.urb_dequeue		= ehci_urb_dequeue,
++	.endpoint_disable	= ehci_endpoint_disable,
++	.endpoint_reset		= ehci_endpoint_reset,
++
++	.get_frame_number	= ehci_get_frame,
++
++	.hub_status_data	= ehci_hub_status_data,
++	.hub_control		= ehci_hub_control,
++#ifdef CONFIG_PM
++	.hub_suspend		= ehci_hub_suspend,
++	.hub_resume		= ehci_hub_resume,
++#endif
++	.relinquish_port	= ehci_relinquish_port,
++	.port_handed_over	= ehci_port_handed_over,
++
++	.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
++};
++
++static int ehci_ar71xx_driver_probe(struct platform_device *pdev)
++{
++	struct ar71xx_ehci_platform_data *pdata;
++	struct usb_hcd *hcd = NULL;
++	int ret;
++
++	if (usb_disabled())
++		return -ENODEV;
++
++	pdata = pdev->dev.platform_data;
++	if (!pdata) {
++		dev_err(&pdev->dev, "no platform data specified for %s\n",
++			dev_name(&pdev->dev));
++		return -ENODEV;
++	}
++
++	if (pdata->is_ar91xx)
++		ret = ehci_ar71xx_probe(&ehci_ar91xx_hc_driver, &hcd, pdev);
++	else
++		ret = ehci_ar71xx_probe(&ehci_ar71xx_hc_driver, &hcd, pdev);
++
++	return ret;
++}
++
++static int ehci_ar71xx_driver_remove(struct platform_device *pdev)
++{
++	struct usb_hcd *hcd = platform_get_drvdata(pdev);
++
++	ehci_ar71xx_remove(hcd, pdev);
++	return 0;
++}
++
++MODULE_ALIAS("platform:ar71xx-ehci");
++
++static struct platform_driver ehci_ar71xx_driver = {
++	.probe		= ehci_ar71xx_driver_probe,
++	.remove		= ehci_ar71xx_driver_remove,
++	.driver = {
++		.name	= "ar71xx-ehci",
++	}
++};
+diff -Nur linux-2.6.33.3.orig/drivers/usb/host/ehci-hcd.c linux-2.6.33.3/drivers/usb/host/ehci-hcd.c
+--- linux-2.6.33.3.orig/drivers/usb/host/ehci-hcd.c	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/drivers/usb/host/ehci-hcd.c	2010-05-17 16:28:28.159113855 +0200
+@@ -1158,6 +1158,11 @@
+ #define	PLATFORM_DRIVER		ehci_atmel_driver
+ #endif
+ 
++#ifdef CONFIG_USB_EHCI_AR71XX
++#include "ehci-ar71xx.c"
++#define PLATFORM_DRIVER		ehci_ar71xx_driver
++#endif
++
+ #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
+     !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER)
+ #error "missing bus glue for ehci-hcd"
+diff -Nur linux-2.6.33.3.orig/drivers/usb/host/Kconfig linux-2.6.33.3/drivers/usb/host/Kconfig
+--- linux-2.6.33.3.orig/drivers/usb/host/Kconfig	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/drivers/usb/host/Kconfig	2010-05-17 16:28:28.155130666 +0200
+@@ -109,6 +109,13 @@
+ 		support both high speed and full speed devices, or high speed
+ 		devices only.
+ 
++config USB_EHCI_AR71XX
++	bool "USB EHCI support for AR71xx"
++	depends on USB_EHCI_HCD && ATHEROS_AR71XX
++	default y
++	help
++	  Support for Atheros AR71xx built-in EHCI controller
++
+ config USB_EHCI_FSL
+ 	bool "Support for Freescale on-chip EHCI USB controller"
+ 	depends on USB_EHCI_HCD && FSL_SOC
+@@ -207,6 +214,13 @@
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called ohci-hcd.
+ 
++config USB_OHCI_AR71XX
++	bool "USB OHCI support for Atheros AR71xx"
++	depends on USB_OHCI_HCD && ATHEROS_AR71XX
++	default y
++	help
++	  Support for Atheros AR71xx built-in OHCI controller
++
+ config USB_OHCI_HCD_PPC_SOC
+ 	bool "OHCI support for on-chip PPC USB controller"
+ 	depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx)
+diff -Nur linux-2.6.33.3.orig/drivers/usb/host/ohci-ar71xx.c linux-2.6.33.3/drivers/usb/host/ohci-ar71xx.c
+--- linux-2.6.33.3.orig/drivers/usb/host/ohci-ar71xx.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/drivers/usb/host/ohci-ar71xx.c	2009-12-13 20:45:24.747935158 +0100
+@@ -0,0 +1,165 @@
++/*
++ *  OHCI HCD (Host Controller Driver) for USB.
++ *
++ *  Bus Glue for Atheros AR71xx built-in OHCI controller.
++ *
++ *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  Parts of this file are based on Atheros' 2.6.15 BSP
++ *	Copyright (C) 2007 Atheros Communications, Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify it
++ *  under the terms of the GNU General Public License version 2 as published
++ *  by the Free Software Foundation.
++ */
++
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++
++extern int usb_disabled(void);
++
++static int usb_hcd_ar71xx_probe(const struct hc_driver *driver,
++				struct platform_device *pdev)
++{
++	struct usb_hcd *hcd;
++	struct resource *res;
++	int irq;
++	int ret;
++
++	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(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;
++	}
++
++	ohci_hcd_init(hcd_to_ohci(hcd));
++
++	ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
++	if (ret)
++		goto err_stop_hcd;
++
++	return 0;
++
++ err_stop_hcd:
++	iounmap(hcd->regs);
++ err_release_region:
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++ err_put_hcd:
++	usb_put_hcd(hcd);
++	return ret;
++}
++
++void usb_hcd_ar71xx_remove(struct usb_hcd *hcd, struct platform_device *pdev)
++{
++	usb_remove_hcd(hcd);
++	iounmap(hcd->regs);
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++	usb_put_hcd(hcd);
++}
++
++static int __devinit ohci_ar71xx_start(struct usb_hcd *hcd)
++{
++	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
++	int ret;
++
++	ret = ohci_init(ohci);
++	if (ret < 0)
++		return ret;
++
++	ret = ohci_run(ohci);
++	if (ret < 0)
++		goto err;
++
++	return 0;
++
++ err:
++	ohci_stop(hcd);
++	return ret;
++}
++
++static const struct hc_driver ohci_ar71xx_hc_driver = {
++	.description		= hcd_name,
++	.product_desc		= "Atheros AR71xx built-in OHCI controller",
++	.hcd_priv_size		= sizeof(struct ohci_hcd),
++
++	.irq			= ohci_irq,
++	.flags			= HCD_USB11 | HCD_MEMORY,
++
++	.start			= ohci_ar71xx_start,
++	.stop			= ohci_stop,
++	.shutdown		= ohci_shutdown,
++
++	.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 int ohci_hcd_ar71xx_drv_probe(struct platform_device *pdev)
++{
++	if (usb_disabled())
++		return -ENODEV;
++
++	return usb_hcd_ar71xx_probe(&ohci_ar71xx_hc_driver, pdev);
++}
++
++static int ohci_hcd_ar71xx_drv_remove(struct platform_device *pdev)
++{
++	struct usb_hcd *hcd = platform_get_drvdata(pdev);
++
++	usb_hcd_ar71xx_remove(hcd, pdev);
++	return 0;
++}
++
++MODULE_ALIAS("platform:ar71xx-ohci");
++
++static struct platform_driver ohci_hcd_ar71xx_driver = {
++	.probe		= ohci_hcd_ar71xx_drv_probe,
++	.remove		= ohci_hcd_ar71xx_drv_remove,
++	.shutdown	= usb_hcd_platform_shutdown,
++	.driver		= {
++		.name	= "ar71xx-ohci",
++		.owner	= THIS_MODULE,
++	},
++};
+diff -Nur linux-2.6.33.3.orig/drivers/usb/host/ohci-hcd.c linux-2.6.33.3/drivers/usb/host/ohci-hcd.c
+--- linux-2.6.33.3.orig/drivers/usb/host/ohci-hcd.c	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/drivers/usb/host/ohci-hcd.c	2010-05-17 16:28:28.163114085 +0200
+@@ -1085,6 +1085,11 @@
+ #define TMIO_OHCI_DRIVER	ohci_hcd_tmio_driver
+ #endif
+ 
++#ifdef CONFIG_USB_OHCI_AR71XX
++#include "ohci-ar71xx.c"
++#define PLATFORM_DRIVER		ohci_hcd_ar71xx_driver
++#endif
++
+ #if	!defined(PCI_DRIVER) &&		\
+ 	!defined(PLATFORM_DRIVER) &&	\
+ 	!defined(OF_PLATFORM_DRIVER) &&	\
+diff -Nur linux-2.6.33.3.orig/drivers/watchdog/ar71xx_wdt.c linux-2.6.33.3/drivers/watchdog/ar71xx_wdt.c
+--- linux-2.6.33.3.orig/drivers/watchdog/ar71xx_wdt.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/drivers/watchdog/ar71xx_wdt.c	2009-12-13 20:45:21.895926395 +0100
+@@ -0,0 +1,270 @@
++/*
++ * Driver for the Atheros AR71xx SoC's built-in hardware watchdog timer.
++ *
++ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This driver was based on: drivers/watchdog/ixp4xx_wdt.c
++ *	Author: Deepak Saxena <dsaxena@plexity.net>
++ *	Copyright 2004 (c) MontaVista, Software, Inc.
++ *
++ * which again was based on sa1100 driver,
++ *	Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
++ *
++ * 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/bitops.h>
++#include <linux/errno.h>
++#include <linux/fs.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/miscdevice.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/platform_device.h>
++#include <linux/types.h>
++#include <linux/watchdog.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#define DRV_NAME	"ar71xx-wdt"
++#define DRV_DESC	"Atheros AR71xx hardware watchdog driver"
++#define DRV_VERSION	"0.1.0"
++
++#define WDT_TIMEOUT	15	/* seconds */
++
++static int nowayout = WATCHDOG_NOWAYOUT;
++
++#ifdef CONFIG_WATCHDOG_NOWAYOUT
++module_param(nowayout, int, 0);
++MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
++			   "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
++#endif
++
++static unsigned long wdt_flags;
++
++#define WDT_FLAGS_BUSY		0
++#define WDT_FLAGS_EXPECT_CLOSE	1
++
++static int wdt_timeout = WDT_TIMEOUT;
++static int boot_status;
++static int max_timeout;
++
++static void inline ar71xx_wdt_keepalive(void)
++{
++	ar71xx_reset_wr(AR71XX_RESET_REG_WDOG, ar71xx_ahb_freq * wdt_timeout);
++}
++
++static void inline ar71xx_wdt_enable(void)
++{
++	printk(KERN_DEBUG DRV_NAME ": enabling watchdog timer\n");
++	ar71xx_wdt_keepalive();
++	ar71xx_reset_wr(AR71XX_RESET_REG_WDOG_CTRL, WDOG_CTRL_ACTION_FCR);
++}
++
++static void inline ar71xx_wdt_disable(void)
++{
++	printk(KERN_DEBUG DRV_NAME ": disabling watchdog timer\n");
++	ar71xx_reset_wr(AR71XX_RESET_REG_WDOG_CTRL, WDOG_CTRL_ACTION_NONE);
++}
++
++static int ar71xx_wdt_set_timeout(int val)
++{
++	if (val < 1 || val > max_timeout)
++		return -EINVAL;
++
++	wdt_timeout = val;
++	ar71xx_wdt_keepalive();
++
++	printk(KERN_DEBUG DRV_NAME ": timeout=%d secs\n", wdt_timeout);
++
++	return 0;
++}
++
++static int ar71xx_wdt_open(struct inode *inode, struct file *file)
++{
++	if (test_and_set_bit(WDT_FLAGS_BUSY, &wdt_flags))
++		return -EBUSY;
++
++	clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags);
++
++	ar71xx_wdt_enable();
++
++	return nonseekable_open(inode, file);
++}
++
++static int ar71xx_wdt_release(struct inode *inode, struct file *file)
++{
++	if (test_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags)) {
++		ar71xx_wdt_disable();
++	} else {
++		printk(KERN_CRIT DRV_NAME ": device closed unexpectedly, "
++					"watchdog timer will not stop!\n");
++	}
++
++	clear_bit(WDT_FLAGS_BUSY, &wdt_flags);
++	clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags);
++
++	return 0;
++}
++
++static ssize_t ar71xx_wdt_write(struct file *file, const char *data,
++				size_t len, loff_t *ppos)
++{
++        if (len) {
++		if (!nowayout) {
++			size_t i;
++
++			clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags);
++
++			for (i = 0; i != len; i++) {
++				char c;
++
++				if (get_user(c, data + i))
++					return -EFAULT;
++
++				if (c == 'V')
++					set_bit(WDT_FLAGS_EXPECT_CLOSE,
++						&wdt_flags);
++			}
++		}
++
++		ar71xx_wdt_keepalive();
++	}
++
++	return len;
++}
++
++static struct watchdog_info ar71xx_wdt_info = {
++	.options		= WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
++				  WDIOF_MAGICCLOSE | WDIOF_CARDRESET,
++	.firmware_version 	= 0,
++	.identity		= "AR71XX watchdog",
++};
++
++static int ar71xx_wdt_ioctl(struct inode *inode, struct file *file,
++			    unsigned int cmd, unsigned long arg)
++{
++	int t;
++	int ret;
++
++	switch (cmd) {
++	case WDIOC_GETSUPPORT:
++		ret = copy_to_user((struct watchdog_info *)arg,
++				   &ar71xx_wdt_info,
++				   sizeof(&ar71xx_wdt_info)) ? -EFAULT : 0;
++		break;
++
++	case WDIOC_GETSTATUS:
++		ret = put_user(0, (int *)arg) ? -EFAULT : 0;
++		break;
++
++	case WDIOC_GETBOOTSTATUS:
++		ret = put_user(boot_status, (int *)arg) ? -EFAULT : 0;
++		break;
++
++	case WDIOC_KEEPALIVE:
++		ar71xx_wdt_keepalive();
++		ret = 0;
++		break;
++
++	case WDIOC_SETTIMEOUT:
++		ret = get_user(t, (int *)arg) ? -EFAULT : 0;
++		if (ret)
++			break;
++
++		ret = ar71xx_wdt_set_timeout(t);
++		if (ret)
++			break;
++
++		/* fallthrough */
++	case WDIOC_GETTIMEOUT:
++		ret = put_user(wdt_timeout, (int *)arg) ? -EFAULT : 0;
++		break;
++
++	default:
++		ret = -ENOTTY;
++		break;
++	}
++
++	return ret;
++}
++
++static const struct file_operations ar71xx_wdt_fops = {
++	.owner		= THIS_MODULE,
++	.write		= ar71xx_wdt_write,
++	.ioctl		= ar71xx_wdt_ioctl,
++	.open		= ar71xx_wdt_open,
++	.release	= ar71xx_wdt_release,
++};
++
++static struct miscdevice ar71xx_wdt_miscdev = {
++	.minor = WATCHDOG_MINOR,
++	.name = "watchdog",
++	.fops = &ar71xx_wdt_fops,
++};
++
++static int __devinit ar71xx_wdt_probe(struct platform_device *pdev)
++{
++	int ret;
++
++	max_timeout = (0xfffffffful / ar71xx_ahb_freq);
++	wdt_timeout = (max_timeout < WDT_TIMEOUT) ? max_timeout : WDT_TIMEOUT;
++
++	boot_status =
++		(ar71xx_reset_rr(AR71XX_RESET_REG_WDOG_CTRL) & WDOG_CTRL_LAST_RESET) ?
++		WDIOF_CARDRESET : 0;
++
++	ret = misc_register(&ar71xx_wdt_miscdev);
++	if (ret)
++		goto err_out;
++
++	printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n");
++
++	printk(KERN_DEBUG DRV_NAME ": timeout=%d secs (max=%d)\n",
++				 	wdt_timeout, max_timeout);
++
++	return 0;
++
++err_out:
++	return ret;
++}
++
++static int __devexit ar71xx_wdt_remove(struct platform_device *pdev)
++{
++	misc_deregister(&ar71xx_wdt_miscdev);
++	return 0;
++}
++
++static struct platform_driver ar71xx_wdt_driver = {
++	.probe		= ar71xx_wdt_probe,
++	.remove		= __devexit_p(ar71xx_wdt_remove),
++	.driver		= {
++		.name	= DRV_NAME,
++		.owner	= THIS_MODULE,
++	},
++};
++
++static int __init ar71xx_wdt_init(void)
++{
++	return platform_driver_register(&ar71xx_wdt_driver);
++}
++module_init(ar71xx_wdt_init);
++
++static void __exit ar71xx_wdt_exit(void)
++{
++	platform_driver_unregister(&ar71xx_wdt_driver);
++}
++module_exit(ar71xx_wdt_exit);
++
++MODULE_DESCRIPTION(DRV_DESC);
++MODULE_VERSION(DRV_VERSION);
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org");
++MODULE_AUTHOR("Imre Kaloz <kaloz@openwrt.org");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:" DRV_NAME);
++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+diff -Nur linux-2.6.33.3.orig/drivers/watchdog/Kconfig linux-2.6.33.3/drivers/watchdog/Kconfig
+--- linux-2.6.33.3.orig/drivers/watchdog/Kconfig	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/drivers/watchdog/Kconfig	2010-05-17 16:28:43.991113674 +0200
+@@ -840,6 +840,13 @@
+ 	help
+ 	  Hardware driver for the built-in watchdog timer on TXx9 MIPS SoCs.
+ 
++config AR71XX_WDT
++	tristate "Atheros AR71xx Watchdog Timer"
++	depends on ATHEROS_AR71XX
++	help
++	  Hardware driver for the built-in watchdog timer on the Atheros
++	  AR71xx SoCs.
++
+ # PARISC Architecture
+ 
+ # POWERPC Architecture
+diff -Nur linux-2.6.33.3.orig/drivers/watchdog/Makefile linux-2.6.33.3/drivers/watchdog/Makefile
+--- linux-2.6.33.3.orig/drivers/watchdog/Makefile	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/drivers/watchdog/Makefile	2010-05-17 16:28:43.991113674 +0200
+@@ -112,6 +112,7 @@
+ obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
+ obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
+ obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
++obj-$(CONFIG_AR71XX_WDT) += ar71xx_wdt.o
+ 
+ # PARISC Architecture
+ 
+diff -Nur linux-2.6.33.3.orig/include/linux/ath9k_platform.h linux-2.6.33.3/include/linux/ath9k_platform.h
+--- linux-2.6.33.3.orig/include/linux/ath9k_platform.h	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/include/linux/ath9k_platform.h	2010-02-13 16:30:06.932691714 +0100
+@@ -1,19 +1,11 @@
+ /*
+- * Copyright (c) 2008 Atheros Communications Inc.
+- * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
+- * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org>
++ * ath9k platform data defines
+  *
+- * Permission to use, copy, modify, and/or distribute this software for any
+- * purpose with or without fee is hereby granted, provided that the above
+- * copyright notice and this permission notice appear in all copies.
++ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
+  *
+- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
+  */
+ 
+ #ifndef _LINUX_ATH9K_PLATFORM_H
+@@ -23,6 +15,9 @@
+ 
+ struct ath9k_platform_data {
+ 	u16 eeprom_data[ATH9K_PLAT_EEP_MAX_WORDS];
++	u8 *macaddr;
++
++	unsigned long quirk_wndr3700:1;
+ };
+ 
+ #endif /* _LINUX_ATH9K_PLATFORM_H */
+diff -Nur linux-2.6.33.3.orig/include/linux/gpio_buttons.h linux-2.6.33.3/include/linux/gpio_buttons.h
+--- linux-2.6.33.3.orig/include/linux/gpio_buttons.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/include/linux/gpio_buttons.h	2010-05-17 20:56:04.279120442 +0200
+@@ -0,0 +1,33 @@
++/*
++ *  Definitions for the GPIO buttons interface driver
++ *
++ *  Copyright (C) 2007-2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file was based on: /include/linux/gpio_keys.h
++ *	The original gpio_keys.h seems not to have a license.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ *
++ */
++
++#ifndef _GPIO_BUTTONS_H_
++#define _GPIO_BUTTONS_H_
++
++struct gpio_button {
++	int	gpio;		/* GPIO line number */
++	int	active_low;
++	char	*desc;		/* button description */
++	int	type;		/* input event type (EV_KEY, EV_SW) */
++	int	code;		/* input event code (KEY_*, SW_*) */
++	int	threshold;	/* count threshold */
++};
++
++struct gpio_buttons_platform_data {
++	struct gpio_button *buttons;
++	int	nbuttons;		/* number of buttons */
++	int	poll_interval;		/* polling interval */
++};
++
++#endif /* _GPIO_BUTTONS_H_ */
+diff -Nur linux-2.6.33.3.orig/include/linux/gpio_dev.h linux-2.6.33.3/include/linux/gpio_dev.h
+--- linux-2.6.33.3.orig/include/linux/gpio_dev.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/include/linux/gpio_dev.h	2010-05-17 20:56:04.293291521 +0200
+@@ -0,0 +1,11 @@
++#ifndef _GPIODEV_H__
++#define _GPIODEV_H__
++
++#define IOC_GPIODEV_MAGIC  'B'
++#define GPIO_GET        _IO(IOC_GPIODEV_MAGIC, 10)
++#define GPIO_SET        _IO(IOC_GPIODEV_MAGIC, 11)
++#define GPIO_CLEAR      _IO(IOC_GPIODEV_MAGIC, 12)
++#define GPIO_DIR_IN     _IO(IOC_GPIODEV_MAGIC, 13)
++#define GPIO_DIR_OUT    _IO(IOC_GPIODEV_MAGIC, 14)
++
++#endif
+diff -Nur linux-2.6.33.3.orig/include/linux/netdevice.h linux-2.6.33.3/include/linux/netdevice.h
+--- linux-2.6.33.3.orig/include/linux/netdevice.h	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/include/linux/netdevice.h	2010-05-17 21:40:17.027115732 +0200
+@@ -844,6 +844,7 @@
+ 	void			*ax25_ptr;	/* AX.25 specific data */
+ 	struct wireless_dev	*ieee80211_ptr;	/* IEEE 802.11 specific data,
+ 						   assign before registering */
++	void			*phy_ptr; /* PHY device specific data */
+ 
+ /*
+  * Cache line mostly used on receive path (including eth_type_trans())
+diff -Nur linux-2.6.33.3.orig/include/linux/nxp_74hc153.h linux-2.6.33.3/include/linux/nxp_74hc153.h
+--- linux-2.6.33.3.orig/include/linux/nxp_74hc153.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/include/linux/nxp_74hc153.h	2010-01-19 19:26:36.441435904 +0100
+@@ -0,0 +1,24 @@
++/*
++ *  NXP 74HC153 - Dual 4-input multiplexer defines
++ *
++ *  Copyright (C) 2010 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.
++ */
++
++#ifndef _NXP_74HC153_H
++#define _NXP_74HC153_H
++
++#define NXP_74HC153_DRIVER_NAME "nxp-74hc153"
++
++struct nxp_74hc153_platform_data {
++	unsigned	gpio_base;
++	unsigned	gpio_pin_s0;
++	unsigned	gpio_pin_s1;
++	unsigned	gpio_pin_1y;
++	unsigned	gpio_pin_2y;
++};
++
++#endif /* _NXP_74HC153_H */
+diff -Nur linux-2.6.33.3.orig/include/linux/phy.h linux-2.6.33.3/include/linux/phy.h
+--- linux-2.6.33.3.orig/include/linux/phy.h	2010-04-26 16:48:30.000000000 +0200
++++ linux-2.6.33.3/include/linux/phy.h	2010-05-17 21:40:17.023114663 +0200
+@@ -325,6 +325,20 @@
+ 	void (*adjust_link)(struct net_device *dev);
+ 
+ 	void (*adjust_state)(struct net_device *dev);
++
++	/*
++	 * By default these point to the original functions
++	 * with the same name. adding them to the phy_device
++	 * allows the phy driver to override them for packet
++	 * mangling if the ethernet driver supports it
++	 * This is required to support some really horrible
++	 * switches such as the Marvell 88E6060
++	 */
++	int (*netif_receive_skb)(struct sk_buff *skb);
++	int (*netif_rx)(struct sk_buff *skb);
++
++	/* alignment offset for packets */
++	int pkt_align;
+ };
+ #define to_phy_device(d) container_of(d, struct phy_device, dev)
+ 
+@@ -491,6 +505,7 @@
+ void phy_stop_machine(struct phy_device *phydev);
+ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd);
+ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd);
++int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr);
+ int phy_mii_ioctl(struct phy_device *phydev,
+ 		struct mii_ioctl_data *mii_data, int cmd);
+ int phy_start_interrupts(struct phy_device *phydev);
+diff -Nur linux-2.6.33.3.orig/include/linux/spi/vsc7385.h linux-2.6.33.3/include/linux/spi/vsc7385.h
+--- linux-2.6.33.3.orig/include/linux/spi/vsc7385.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/include/linux/spi/vsc7385.h	2009-12-13 20:45:19.923921372 +0100
+@@ -0,0 +1,19 @@
++/*
++ * Platform data definition for the Vitesse VSC7385 ethernet switch driver
++ *
++ * Copyright (C) 2009 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.
++ */
++
++struct vsc7385_platform_data {
++	void		(* reset)(void);
++	char		*ucode_name;
++	struct {
++		u32	tx_ipg:5;
++		u32	bit2:1;
++		u32	clk_sel:3;
++	} mac_cfg;
++};
+diff -Nur linux-2.6.33.3.orig/net/dsa/ar7240.c linux-2.6.33.3/net/dsa/ar7240.c
+--- linux-2.6.33.3.orig/net/dsa/ar7240.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/net/dsa/ar7240.c	2010-03-12 19:31:45.562053091 +0100
+@@ -0,0 +1,736 @@
++/*
++ *  DSA driver for the built-in ethernet switch of the Atheros AR7240 SoC
++ *  Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file was based on:
++ *    net/dsa/mv88e6060.c - Driver for Marvell 88e6060 switch chips
++ *    Copyright (c) 2008 Marvell Semiconductor
++ *
++ *  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/etherdevice.h>
++#include <linux/list.h>
++#include <linux/netdevice.h>
++#include <linux/phy.h>
++#include <linux/mii.h>
++#include <linux/bitops.h>
++
++#include "dsa_priv.h"
++
++#define BITM(_count)	(BIT(_count) - 1)
++
++#define AR7240_REG_MASK_CTRL		0x00
++#define AR7240_MASK_CTRL_REVISION_M	BITM(8)
++#define AR7240_MASK_CTRL_VERSION_M	BITM(8)
++#define AR7240_MASK_CTRL_VERSION_S	8
++#define AR7240_MASK_CTRL_SOFT_RESET	BIT(31)
++
++#define AR7240_REG_MAC_ADDR0		0x20
++#define AR7240_REG_MAC_ADDR1		0x24
++
++#define AR7240_REG_FLOOD_MASK		0x2c
++#define AR7240_FLOOD_MASK_BROAD_TO_CPU	BIT(26)
++
++#define AR7240_REG_GLOBAL_CTRL		0x30
++#define AR7240_GLOBAL_CTRL_MTU_M	BITM(12)
++
++#define AR7240_REG_AT_CTRL		0x5c
++#define AR7240_AT_CTRL_ARP_EN		BIT(20)
++
++#define AR7240_REG_TAG_PRIORITY		0x70
++
++#define AR7240_REG_SERVICE_TAG		0x74
++#define AR7240_SERVICE_TAG_M		BITM(16)
++
++#define AR7240_REG_CPU_PORT		0x78
++#define AR7240_MIRROR_PORT_S		4
++#define AR7240_CPU_PORT_EN		BIT(8)
++
++#define AR7240_REG_MIB_FUNCTION0	0x80
++#define AR7240_MIB_TIMER_M		BITM(16)
++#define AR7240_MIB_AT_HALF_EN		BIT(16)
++#define AR7240_MIB_BUSY			BIT(17)
++#define AR7240_MIB_FUNC_S		24
++#define AR7240_MIB_FUNC_NO_OP		0x0
++#define AR7240_MIB_FUNC_FLUSH		0x1
++#define AR7240_MIB_FUNC_CAPTURE		0x3
++
++#define AR7240_REG_MDIO_CTRL		0x98
++#define AR7240_MDIO_CTRL_DATA_M		BITM(16)
++#define AR7240_MDIO_CTRL_REG_ADDR_S	16
++#define AR7240_MDIO_CTRL_PHY_ADDR_S	21
++#define AR7240_MDIO_CTRL_CMD_WRITE	0
++#define AR7240_MDIO_CTRL_CMD_READ	BIT(27)
++#define AR7240_MDIO_CTRL_MASTER_EN	BIT(30)
++#define AR7240_MDIO_CTRL_BUSY		BIT(31)
++
++#define AR7240_REG_PORT_BASE(_port)	(0x100 + (_port) * 0x100)
++
++#define AR7240_REG_PORT_STATUS(_port)	(AR7240_REG_PORT_BASE((_port)) + 0x00)
++#define AR7240_PORT_STATUS_SPEED_M	BITM(2)
++#define AR7240_PORT_STATUS_SPEED_10	0
++#define AR7240_PORT_STATUS_SPEED_100	1
++#define AR7240_PORT_STATUS_SPEED_1000	2
++#define AR7240_PORT_STATUS_TXMAC	BIT(2)
++#define AR7240_PORT_STATUS_RXMAC	BIT(3)
++#define AR7240_PORT_STATUS_TXFLOW	BIT(4)
++#define AR7240_PORT_STATUS_RXFLOW	BIT(5)
++#define AR7240_PORT_STATUS_DUPLEX	BIT(6)
++#define AR7240_PORT_STATUS_LINK_UP	BIT(8)
++#define AR7240_PORT_STATUS_LINK_AUTO	BIT(9)
++#define AR7240_PORT_STATUS_LINK_PAUSE	BIT(10)
++
++#define AR7240_REG_PORT_CTRL(_port)	(AR7240_REG_PORT_BASE((_port)) + 0x04)
++#define AR7240_PORT_CTRL_STATE_M	BITM(3)
++#define	AR7240_PORT_CTRL_STATE_DISABLED	0
++#define AR7240_PORT_CTRL_STATE_BLOCK	1
++#define AR7240_PORT_CTRL_STATE_LISTEN	2
++#define AR7240_PORT_CTRL_STATE_LEARN	3
++#define AR7240_PORT_CTRL_STATE_FORWARD	4
++#define AR7240_PORT_CTRL_LEARN_LOCK	BIT(7)
++#define AR7240_PORT_CTRL_VLAN_MODE_S	8
++#define AR7240_PORT_CTRL_VLAN_MODE_KEEP	0
++#define AR7240_PORT_CTRL_VLAN_MODE_STRIP 1
++#define AR7240_PORT_CTRL_VLAN_MODE_ADD	2
++#define AR7240_PORT_CTRL_VLAN_MODE_DOUBLE_TAG 3
++#define AR7240_PORT_CTRL_IGMP_SNOOP	BIT(10)
++#define AR7240_PORT_CTRL_HEADER		BIT(11)
++#define AR7240_PORT_CTRL_MAC_LOOP	BIT(12)
++#define AR7240_PORT_CTRL_SINGLE_VLAN	BIT(13)
++#define AR7240_PORT_CTRL_LEARN		BIT(14)
++#define AR7240_PORT_CTRL_DOUBLE_TAG	BIT(15)
++#define AR7240_PORT_CTRL_MIRROR_TX	BIT(16)
++#define AR7240_PORT_CTRL_MIRROR_RX	BIT(17)
++
++#define AR7240_REG_PORT_VLAN(_port)	(AR7240_REG_PORT_BASE((_port)) + 0x08)
++
++#define AR7240_PORT_VLAN_DEFAULT_ID_S	0
++#define AR7240_PORT_VLAN_DEST_PORTS_S	16
++
++#define AR7240_REG_STATS_BASE(_port)	(0x20000 + (_port) * 0x100)
++
++#define AR7240_STATS_RXBROAD		0x00
++#define AR7240_STATS_RXPAUSE		0x04
++#define AR7240_STATS_RXMULTI		0x08
++#define AR7240_STATS_RXFCSERR		0x0c
++#define AR7240_STATS_RXALIGNERR		0x10
++#define AR7240_STATS_RXRUNT		0x14
++#define AR7240_STATS_RXFRAGMENT		0x18
++#define AR7240_STATS_RX64BYTE		0x1c
++#define AR7240_STATS_RX128BYTE		0x20
++#define AR7240_STATS_RX256BYTE		0x24
++#define AR7240_STATS_RX512BYTE		0x28
++#define AR7240_STATS_RX1024BYTE		0x2c
++#define AR7240_STATS_RX1518BYTE		0x30
++#define AR7240_STATS_RXMAXBYTE		0x34
++#define AR7240_STATS_RXTOOLONG		0x38
++#define AR7240_STATS_RXGOODBYTE		0x3c
++#define AR7240_STATS_RXBADBYTE		0x44
++#define AR7240_STATS_RXOVERFLOW		0x4c
++#define AR7240_STATS_FILTERED		0x50
++#define AR7240_STATS_TXBROAD		0x54
++#define AR7240_STATS_TXPAUSE		0x58
++#define AR7240_STATS_TXMULTI		0x5c
++#define AR7240_STATS_TXUNDERRUN		0x60
++#define AR7240_STATS_TX64BYTE		0x64
++#define AR7240_STATS_TX128BYTE		0x68
++#define AR7240_STATS_TX256BYTE		0x6c
++#define AR7240_STATS_TX512BYTE		0x70
++#define AR7240_STATS_TX1024BYTE		0x74
++#define AR7240_STATS_TX1518BYTE		0x78
++#define AR7240_STATS_TXMAXBYTE		0x7c
++#define AR7240_STATS_TXOVERSIZE		0x80
++#define AR7240_STATS_TXBYTE		0x84
++#define AR7240_STATS_TXCOLLISION	0x8c
++#define AR7240_STATS_TXABORTCOL		0x90
++#define AR7240_STATS_TXMULTICOL		0x94
++#define AR7240_STATS_TXSINGLECOL	0x98
++#define AR7240_STATS_TXEXCDEFER		0x9c
++#define AR7240_STATS_TXDEFER		0xa0
++#define AR7240_STATS_TXLATECOL		0xa4
++
++#define AR7240_PORT_CPU		0
++#define AR7240_NUM_PORTS	6
++#define AR7240_NUM_PHYS		5
++
++#define AR7240_PHY_ID1		0x004d
++#define AR7240_PHY_ID2		0xd041
++
++#define AR7240_PORT_MASK(_port)		BIT((_port))
++#define AR7240_PORT_MASK_ALL		BITM(AR7240_NUM_PORTS)
++#define AR7240_PORT_MASK_BUT(_port)	(AR7240_PORT_MASK_ALL & ~BIT((_port)))
++
++struct ar7240sw {
++	struct mii_bus	*mii_bus;
++	struct mutex	reg_mutex;
++	struct mutex	stats_mutex;
++};
++
++struct ar7240sw_hw_stat {
++	char string[ETH_GSTRING_LEN];
++	int sizeof_stat;
++	int reg;
++};
++
++static inline struct ar7240sw *dsa_to_ar7240sw(struct dsa_switch *ds)
++{
++	return (struct ar7240sw *)(ds + 1);
++}
++
++static inline void ar7240sw_init(struct ar7240sw *as, struct mii_bus *mii)
++{
++	as->mii_bus = mii;
++	mutex_init(&as->reg_mutex);
++	mutex_init(&as->stats_mutex);
++}
++
++static inline u16 mk_phy_addr(u32 reg)
++{
++	return (0x17 & ((reg >> 4) | 0x10));
++}
++
++static inline u16 mk_phy_reg(u32 reg)
++{
++	return ((reg << 1) & 0x1e);
++}
++
++static inline u16 mk_high_addr(u32 reg)
++{
++	return ((reg >> 7) & 0x1ff);
++}
++
++static u32 __ar7240sw_reg_read(struct ar7240sw *as, u32 reg)
++{
++	struct mii_bus *mii = as->mii_bus;
++	u16 phy_addr;
++	u16 phy_reg;
++	u32 hi, lo;
++
++	reg = (reg & 0xfffffffc) >> 2;
++
++	mdiobus_write(mii, 0x1f, 0x10, mk_high_addr(reg));
++
++	phy_addr = mk_phy_addr(reg);
++	phy_reg = mk_phy_reg(reg);
++
++	lo = (u32) mdiobus_read(mii, phy_addr, phy_reg);
++	hi = (u32) mdiobus_read(mii, phy_addr, phy_reg + 1);
++
++	return ((hi << 16) | lo);
++}
++
++static void __ar7240sw_reg_write(struct ar7240sw *as, u32 reg, u32 val)
++{
++	struct mii_bus *mii = as->mii_bus;
++	u16 phy_addr;
++	u16 phy_reg;
++
++	reg = (reg & 0xfffffffc) >> 2;
++
++	mdiobus_write(mii, 0x1f, 0x10, mk_high_addr(reg));
++
++	phy_addr = mk_phy_addr(reg);
++	phy_reg = mk_phy_reg(reg);
++
++	mdiobus_write(mii, phy_addr, phy_reg + 1, (val >> 16));
++	mdiobus_write(mii, phy_addr, phy_reg, (val & 0xffff));
++}
++
++static u32 ar7240sw_reg_read(struct ar7240sw *as, u32 reg_addr)
++{
++	u32 ret;
++
++	mutex_lock(&as->reg_mutex);
++	ret = __ar7240sw_reg_read(as, reg_addr);
++	mutex_unlock(&as->reg_mutex);
++
++	return ret;
++}
++
++static void ar7240sw_reg_write(struct ar7240sw *as, u32 reg_addr, u32 reg_val)
++{
++	mutex_lock(&as->reg_mutex);
++	__ar7240sw_reg_write(as, reg_addr, reg_val);
++	mutex_unlock(&as->reg_mutex);
++}
++
++static u32 ar7240sw_reg_rmw(struct ar7240sw *as, u32 reg, u32 mask, u32 val)
++{
++	u32 t;
++
++	mutex_lock(&as->reg_mutex);
++	t = __ar7240sw_reg_read(as, reg);
++	t &= ~mask;
++	t |= val;
++	__ar7240sw_reg_write(as, reg, t);
++	mutex_unlock(&as->reg_mutex);
++
++	return t;
++}
++
++static void ar7240sw_reg_set(struct ar7240sw *as, u32 reg, u32 val)
++{
++	u32 t;
++
++	mutex_lock(&as->reg_mutex);
++	t = __ar7240sw_reg_read(as, reg);
++	t |= val;
++	__ar7240sw_reg_write(as, reg, t);
++	mutex_unlock(&as->reg_mutex);
++}
++
++static int ar7240sw_reg_wait(struct ar7240sw *as, u32 reg, u32 mask, u32 val,
++			     unsigned timeout)
++{
++	int i;
++
++	for (i = 0; i < timeout; i++) {
++		u32 t;
++
++		t = ar7240sw_reg_read(as, reg);
++		if ((t & mask) == val)
++			return 0;
++
++		msleep(1);
++	}
++
++	return -ETIMEDOUT;
++}
++
++static u16 ar7240sw_phy_read(struct ar7240sw *as, unsigned phy_addr,
++			     unsigned reg_addr)
++{
++	u32 t;
++	int err;
++
++	if (phy_addr >= AR7240_NUM_PHYS)
++		return 0xffff;
++
++	t = (reg_addr << AR7240_MDIO_CTRL_REG_ADDR_S) |
++	    (phy_addr << AR7240_MDIO_CTRL_PHY_ADDR_S) |
++	    AR7240_MDIO_CTRL_MASTER_EN |
++	    AR7240_MDIO_CTRL_BUSY |
++	    AR7240_MDIO_CTRL_CMD_READ;
++
++	ar7240sw_reg_write(as, AR7240_REG_MDIO_CTRL, t);
++	err = ar7240sw_reg_wait(as, AR7240_REG_MDIO_CTRL,
++				AR7240_MDIO_CTRL_BUSY, 0, 5);
++	if (err)
++		return 0xffff;
++
++	t = ar7240sw_reg_read(as, AR7240_REG_MDIO_CTRL);
++	return (t & AR7240_MDIO_CTRL_DATA_M);
++}
++
++static int ar7240sw_phy_write(struct ar7240sw *as, unsigned phy_addr,
++			      unsigned reg_addr, u16 reg_val)
++{
++	u32 t;
++	int ret;
++
++	if (phy_addr >= AR7240_NUM_PHYS)
++		return -EINVAL;
++
++	t = (phy_addr << AR7240_MDIO_CTRL_PHY_ADDR_S) |
++	    (reg_addr << AR7240_MDIO_CTRL_REG_ADDR_S) |
++	    AR7240_MDIO_CTRL_MASTER_EN |
++	    AR7240_MDIO_CTRL_BUSY |
++	    AR7240_MDIO_CTRL_CMD_WRITE |
++	    reg_val;
++
++	ar7240sw_reg_write(as, AR7240_REG_MDIO_CTRL, t);
++	ret = ar7240sw_reg_wait(as, AR7240_REG_MDIO_CTRL,
++				AR7240_MDIO_CTRL_BUSY, 0, 5);
++	return ret;
++}
++
++static int ar7240sw_capture_stats(struct ar7240sw *as)
++{
++	int ret;
++
++	/* Capture the hardware statistics for all ports */
++	ar7240sw_reg_write(as, AR7240_REG_MIB_FUNCTION0,
++			   (AR7240_MIB_FUNC_CAPTURE << AR7240_MIB_FUNC_S));
++
++	/* Wait for the capturing to complete. */
++	ret = ar7240sw_reg_wait(as, AR7240_REG_MIB_FUNCTION0,
++				AR7240_MIB_BUSY, 0, 10);
++	return ret;
++}
++
++static void ar7240sw_disable_port(struct ar7240sw *as, unsigned port)
++{
++	ar7240sw_reg_write(as, AR7240_REG_PORT_CTRL(port),
++			   AR7240_PORT_CTRL_STATE_DISABLED);
++}
++
++static int ar7240sw_reset(struct ar7240sw *as)
++{
++	int ret;
++	int i;
++
++	/* Set all ports to disabled state. */
++	for (i = 0; i < AR7240_NUM_PORTS; i++)
++		ar7240sw_disable_port(as, i);
++
++	/* Wait for transmit queues to drain. */
++	msleep(2);
++
++	/* Reset the switch. */
++	ar7240sw_reg_write(as, AR7240_REG_MASK_CTRL,
++			   AR7240_MASK_CTRL_SOFT_RESET);
++
++	ret = ar7240sw_reg_wait(as, AR7240_REG_MASK_CTRL,
++			        AR7240_MASK_CTRL_SOFT_RESET, 0, 1000);
++	return ret;
++}
++
++static void ar7240sw_setup(struct ar7240sw *as)
++{
++	/* Enable CPU port, and disable mirror port */
++	ar7240sw_reg_write(as, AR7240_REG_CPU_PORT,
++			   AR7240_CPU_PORT_EN |
++			   (15 << AR7240_MIRROR_PORT_S));
++
++	/* Setup TAG priority mapping */
++	ar7240sw_reg_write(as, AR7240_REG_TAG_PRIORITY, 0xfa50);
++
++	/* Enable ARP frame acknowledge */
++	ar7240sw_reg_set(as, AR7240_REG_AT_CTRL, AR7240_AT_CTRL_ARP_EN);
++
++	/* Enable Broadcast frames transmitted to the CPU */
++	ar7240sw_reg_set(as, AR7240_REG_FLOOD_MASK,
++			 AR7240_FLOOD_MASK_BROAD_TO_CPU);
++
++	/* setup MTU */
++	ar7240sw_reg_rmw(as, AR7240_REG_GLOBAL_CTRL, AR7240_GLOBAL_CTRL_MTU_M,
++			 1536);
++
++	/* setup Service TAG */
++	ar7240sw_reg_rmw(as, AR7240_REG_SERVICE_TAG, AR7240_SERVICE_TAG_M,
++			 ETH_P_QINQ);
++}
++
++static void ar7240sw_setup_port(struct ar7240sw *as, unsigned port)
++{
++	u32 ctrl;
++	u32 dest_ports;
++	u32 vlan;
++
++	ctrl = AR7240_PORT_CTRL_STATE_FORWARD;
++
++	if (port == AR7240_PORT_CPU) {
++		ar7240sw_reg_write(as, AR7240_REG_PORT_STATUS(port),
++				   AR7240_PORT_STATUS_SPEED_1000 |
++				   AR7240_PORT_STATUS_TXFLOW |
++				   AR7240_PORT_STATUS_RXFLOW |
++				   AR7240_PORT_STATUS_TXMAC |
++				   AR7240_PORT_STATUS_RXMAC |
++				   AR7240_PORT_STATUS_DUPLEX);
++
++		/* allow the CPU port to talk to each of the 'real' ports */
++		dest_ports = AR7240_PORT_MASK_BUT(port);
++
++		/* remove service tag from ingress frames */
++		ctrl |= AR7240_PORT_CTRL_DOUBLE_TAG;
++	} else {
++		ar7240sw_reg_write(as, AR7240_REG_PORT_STATUS(port),
++				   AR7240_PORT_STATUS_LINK_AUTO);
++
++		/*
++		 * allow each of the 'real' ports to only talk to the CPU
++		 * port.
++		 */
++		dest_ports = AR7240_PORT_MASK(port) |
++			     AR7240_PORT_MASK(AR7240_PORT_CPU);
++
++		/* add service tag to egress frames */
++		ctrl |= (AR7240_PORT_CTRL_VLAN_MODE_DOUBLE_TAG <<
++			 AR7240_PORT_CTRL_VLAN_MODE_S);
++	}
++
++	/* set default VID and and destination ports for this VLAN */
++	vlan = port;
++	vlan |= (dest_ports << AR7240_PORT_VLAN_DEST_PORTS_S);
++
++	ar7240sw_reg_write(as, AR7240_REG_PORT_CTRL(port), ctrl);
++	ar7240sw_reg_write(as, AR7240_REG_PORT_VLAN(port), vlan);
++}
++
++static char *ar7240_dsa_probe(struct mii_bus *mii, int sw_addr)
++{
++	struct ar7240sw as;
++	u32 ctrl;
++	u16 phy_id1;
++	u16 phy_id2;
++	u8 ver;
++
++	ar7240sw_init(&as, mii);
++
++	ctrl = ar7240sw_reg_read(&as, AR7240_REG_MASK_CTRL);
++
++	ver = (ctrl >> AR7240_MASK_CTRL_VERSION_S) & AR7240_MASK_CTRL_VERSION_M;
++	if (ver != 1) {
++		pr_err("ar7240_dsa: unsupported chip, ctrl=%08x\n", ctrl);
++		return NULL;
++	}
++
++	phy_id1 = ar7240sw_phy_read(&as, 0, MII_PHYSID1);
++	phy_id2 = ar7240sw_phy_read(&as, 0, MII_PHYSID2);
++	if (phy_id1 != AR7240_PHY_ID1 || phy_id2 != AR7240_PHY_ID2) {
++		pr_err("ar7240_dsa: unknown phy id '%04x:%04x'\n",
++		       phy_id1, phy_id2);
++		return NULL;
++	}
++
++	return "Atheros AR7240 built-in";
++}
++
++static int ar7240_dsa_setup(struct dsa_switch *ds)
++{
++	struct ar7240sw *as = dsa_to_ar7240sw(ds);
++	int i;
++	int ret;
++
++	ar7240sw_init(as, ds->master_mii_bus);
++
++	ret = ar7240sw_reset(as);
++	if (ret)
++		return ret;
++
++	ar7240sw_setup(as);
++
++	for (i = 0; i < AR7240_NUM_PORTS; i++) {
++		if (dsa_is_cpu_port(ds, i) || (ds->phys_port_mask & (1 << i)))
++			ar7240sw_setup_port(as, i);
++		else
++			ar7240sw_disable_port(as, i);
++	}
++
++	return 0;
++}
++
++static int ar7240_dsa_set_addr(struct dsa_switch *ds, u8 *addr)
++{
++	struct ar7240sw *as = dsa_to_ar7240sw(ds);
++	u32 t;
++
++	t = (addr[4] << 8) | addr[5];
++	ar7240sw_reg_write(as, AR7240_REG_MAC_ADDR0, t);
++
++	t = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3];
++	ar7240sw_reg_write(as, AR7240_REG_MAC_ADDR1, t);
++
++	return 0;
++}
++
++static int ar7240_iort_to_phy_addr(int port)
++{
++	if (port > 0 && port < AR7240_NUM_PORTS)
++		return port - 1;
++
++	return -EINVAL;
++}
++
++static int ar7240_dsa_phy_read(struct dsa_switch *ds, int port, int regnum)
++{
++	struct ar7240sw *as = dsa_to_ar7240sw(ds);
++	int phy_addr;
++
++	phy_addr = ar7240_iort_to_phy_addr(port);
++	if (phy_addr < 0)
++		return 0xffff;
++
++	return ar7240sw_phy_read(as, phy_addr, regnum);
++}
++
++static int ar7240_dsa_phy_write(struct dsa_switch *ds, int port, int regnum,
++				u16 val)
++{
++	struct ar7240sw *as = dsa_to_ar7240sw(ds);
++	int phy_addr;
++
++	phy_addr = ar7240_iort_to_phy_addr(port);
++	if (phy_addr < 0)
++		return 0xffff;
++
++	return ar7240sw_phy_write(as, phy_addr, regnum, val);
++}
++
++static const char *ar7240sw_speed_str(unsigned speed)
++{
++	switch (speed) {
++	case AR7240_PORT_STATUS_SPEED_10:
++		return "10";
++	case AR7240_PORT_STATUS_SPEED_100:
++		return "100";
++	case AR7240_PORT_STATUS_SPEED_1000:
++		return "1000";
++	}
++
++	return "????";
++}
++
++static void ar7240_dsa_poll_link(struct dsa_switch *ds)
++{
++	struct ar7240sw *as = dsa_to_ar7240sw(ds);
++	int i;
++
++	for (i = 0; i < DSA_MAX_PORTS; i++) {
++		struct net_device *dev;
++		u32 status;
++		int link;
++		unsigned speed;
++		int duplex;
++
++		dev = ds->ports[i];
++		if (dev == NULL)
++			continue;
++
++		link = 0;
++		if (dev->flags & IFF_UP) {
++			status = ar7240sw_reg_read(as,
++						   AR7240_REG_PORT_STATUS(i));
++			link = !!(status & AR7240_PORT_STATUS_LINK_UP);
++		}
++
++		if (!link) {
++			if (netif_carrier_ok(dev)) {
++				pr_info("%s: link down\n", dev->name);
++				netif_carrier_off(dev);
++			}
++			continue;
++		}
++
++		speed = (status & AR7240_PORT_STATUS_SPEED_M);
++		duplex = (status & AR7240_PORT_STATUS_DUPLEX) ? 1 : 0;
++		if (!netif_carrier_ok(dev)) {
++			pr_info("%s: link up, %sMb/s, %s duplex",
++				dev->name,
++				ar7240sw_speed_str(speed),
++				duplex ? "full" : "half");
++			netif_carrier_on(dev);
++		}
++	}
++}
++
++static const struct ar7240sw_hw_stat ar7240_hw_stats[] = {
++	{ "rx_broadcast"	, 4, AR7240_STATS_RXBROAD, },
++	{ "rx_pause"		, 4, AR7240_STATS_RXPAUSE, },
++	{ "rx_multicast"	, 4, AR7240_STATS_RXMULTI, },
++	{ "rx_fcs_error"	, 4, AR7240_STATS_RXFCSERR, },
++	{ "rx_align_error"	, 4, AR7240_STATS_RXALIGNERR, },
++	{ "rx_undersize"	, 4, AR7240_STATS_RXRUNT, },
++	{ "rx_fragments"	, 4, AR7240_STATS_RXFRAGMENT, },
++	{ "rx_64bytes"		, 4, AR7240_STATS_RX64BYTE, },
++	{ "rx_65_127bytes"	, 4, AR7240_STATS_RX128BYTE, },
++	{ "rx_128_255bytes"	, 4, AR7240_STATS_RX256BYTE, },
++	{ "rx_256_511bytes"	, 4, AR7240_STATS_RX512BYTE, },
++	{ "rx_512_1023bytes"	, 4, AR7240_STATS_RX1024BYTE, },
++	{ "rx_1024_1518bytes"	, 4, AR7240_STATS_RX1518BYTE, },
++	{ "rx_1519_max_bytes"	, 4, AR7240_STATS_RXMAXBYTE, },
++	{ "rx_oversize"		, 4, AR7240_STATS_RXTOOLONG, },
++	{ "rx_good_bytes"	, 8, AR7240_STATS_RXGOODBYTE, },
++	{ "rx_bad_bytes"	, 8, AR7240_STATS_RXBADBYTE, },
++	{ "rx_overflow"		, 4, AR7240_STATS_RXOVERFLOW, },
++	{ "filtered"		, 4, AR7240_STATS_FILTERED, },
++	{ "tx_broadcast"	, 4, AR7240_STATS_TXBROAD, },
++	{ "tx_pause"		, 4, AR7240_STATS_TXPAUSE, },
++	{ "tx_multicast"	, 4, AR7240_STATS_TXMULTI, },
++	{ "tx_underrun"		, 4, AR7240_STATS_TXUNDERRUN, },
++	{ "tx_64bytes"		, 4, AR7240_STATS_TX64BYTE, },
++	{ "tx_65_127bytes"	, 4, AR7240_STATS_TX128BYTE, },
++	{ "tx_128_255bytes"	, 4, AR7240_STATS_TX256BYTE, },
++	{ "tx_256_511bytes"	, 4, AR7240_STATS_TX512BYTE, },
++	{ "tx_512_1023bytes"	, 4, AR7240_STATS_TX1024BYTE, },
++	{ "tx_1024_1518bytes"	, 4, AR7240_STATS_TX1518BYTE, },
++	{ "tx_1519_max_bytes"	, 4, AR7240_STATS_TXMAXBYTE, },
++	{ "tx_oversize"		, 4, AR7240_STATS_TXOVERSIZE, },
++	{ "tx_bytes"		, 8, AR7240_STATS_TXBYTE, },
++	{ "tx_collisions"	, 4, AR7240_STATS_TXCOLLISION, },
++	{ "tx_abort_collisions"	, 4, AR7240_STATS_TXABORTCOL, },
++	{ "tx_multi_collisions"	, 4, AR7240_STATS_TXMULTICOL, },
++	{ "tx_single_collisions", 4, AR7240_STATS_TXSINGLECOL, },
++	{ "tx_excessive_deferred", 4, AR7240_STATS_TXEXCDEFER, },
++	{ "tx_deferred"		, 4, AR7240_STATS_TXDEFER, },
++	{ "tx_late_collisions"	, 4, AR7240_STATS_TXLATECOL, },
++};
++
++static void ar7240_dsa_get_strings(struct dsa_switch *ds, int port,
++				   uint8_t *data)
++{
++	int i;
++
++	for (i = 0; i < ARRAY_SIZE(ar7240_hw_stats); i++) {
++		memcpy(data + i * ETH_GSTRING_LEN,
++		       ar7240_hw_stats[i].string, ETH_GSTRING_LEN);
++	}
++}
++
++static void ar7240_dsa_get_ethtool_stats(struct dsa_switch *ds, int port,
++					 uint64_t *data)
++{
++	struct ar7240sw *as = dsa_to_ar7240sw(ds);
++	int err;
++	int i;
++
++	mutex_lock(&as->stats_mutex);
++
++	err = ar7240sw_capture_stats(as);
++	if (err)
++		goto unlock;
++
++	for (i = 0; i < ARRAY_SIZE(ar7240_hw_stats); i++) {
++		const struct ar7240sw_hw_stat *s = &ar7240_hw_stats[i];
++		u32 reg = AR7240_REG_STATS_BASE(port);
++		u32 low;
++		u32 high;
++
++		low = ar7240sw_reg_read(as, reg + s->reg);
++		if (s->sizeof_stat == 8)
++			high = ar7240sw_reg_read(as, reg + s->reg);
++		else
++			high = 0;
++
++		data[i] = (((u64) high) << 32) | low;
++	}
++
++ unlock:
++	mutex_unlock(&as->stats_mutex);
++}
++
++static int ar7240_dsa_get_sset_count(struct dsa_switch *ds)
++{
++	return ARRAY_SIZE(ar7240_hw_stats);
++}
++
++static struct dsa_switch_driver ar7240_dsa_driver = {
++	.tag_protocol		= htons(ETH_P_QINQ),
++	.priv_size		= sizeof(struct ar7240sw),
++	.probe			= ar7240_dsa_probe,
++	.setup			= ar7240_dsa_setup,
++	.set_addr		= ar7240_dsa_set_addr,
++	.phy_read		= ar7240_dsa_phy_read,
++	.phy_write		= ar7240_dsa_phy_write,
++	.poll_link		= ar7240_dsa_poll_link,
++	.get_strings		= ar7240_dsa_get_strings,
++	.get_ethtool_stats	= ar7240_dsa_get_ethtool_stats,
++	.get_sset_count		= ar7240_dsa_get_sset_count,
++};
++
++int __init dsa_ar7240_init(void)
++{
++	register_switch_driver(&ar7240_dsa_driver);
++	return 0;
++}
++module_init(dsa_ar7240_init);
++
++void __exit dsa_ar7240_cleanup(void)
++{
++	unregister_switch_driver(&ar7240_dsa_driver);
++}
++module_exit(dsa_ar7240_cleanup);
+diff -Nur linux-2.6.33.3.orig/net/dsa/mv88e6063.c linux-2.6.33.3/net/dsa/mv88e6063.c
+--- linux-2.6.33.3.orig/net/dsa/mv88e6063.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/net/dsa/mv88e6063.c	2009-12-25 12:10:58.524031002 +0100
+@@ -0,0 +1,294 @@
++/*
++ * net/dsa/mv88e6063.c - Driver for Marvell 88e6063 switch chips
++ * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This driver was base on: net/dsa/mv88e6060.c
++ *   net/dsa/mv88e6063.c - Driver for Marvell 88e6060 switch chips
++ *   Copyright (c) 2008-2009 Marvell Semiconductor
++ *
++ * 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/list.h>
++#include <linux/netdevice.h>
++#include <linux/phy.h>
++#include "dsa_priv.h"
++
++#define REG_BASE		0x10
++#define REG_PHY(p)		(REG_BASE + (p))
++#define REG_PORT(p)		(REG_BASE + 8 + (p))
++#define REG_GLOBAL		(REG_BASE + 0x0f)
++#define NUM_PORTS		7
++
++static int reg_read(struct dsa_switch *ds, int addr, int reg)
++{
++	return mdiobus_read(ds->master_mii_bus, addr, reg);
++}
++
++#define REG_READ(addr, reg)					\
++	({							\
++		int __ret;					\
++								\
++		__ret = reg_read(ds, addr, reg);		\
++		if (__ret < 0)					\
++			return __ret;				\
++		__ret;						\
++	})
++
++
++static int reg_write(struct dsa_switch *ds, int addr, int reg, u16 val)
++{
++	return mdiobus_write(ds->master_mii_bus, addr, reg, val);
++}
++
++#define REG_WRITE(addr, reg, val)				\
++	({							\
++		int __ret;					\
++								\
++		__ret = reg_write(ds, addr, reg, val);		\
++		if (__ret < 0)					\
++			return __ret;				\
++	})
++
++static char *mv88e6063_probe(struct mii_bus *bus, int sw_addr)
++{
++	int ret;
++
++	ret = mdiobus_read(bus, REG_PORT(0), 0x03);
++	if (ret >= 0) {
++		ret &= 0xfff0;
++		if (ret == 0x1530)
++			return "Marvell 88E6063";
++	}
++
++	return NULL;
++}
++
++static int mv88e6063_switch_reset(struct dsa_switch *ds)
++{
++	int i;
++	int ret;
++
++	/*
++	 * Set all ports to the disabled state.
++	 */
++	for (i = 0; i < NUM_PORTS; i++) {
++		ret = REG_READ(REG_PORT(i), 0x04);
++		REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
++	}
++
++	/*
++	 * Wait for transmit queues to drain.
++	 */
++	msleep(2);
++
++	/*
++	 * Reset the switch.
++	 */
++	REG_WRITE(REG_GLOBAL, 0x0a, 0xa130);
++
++	/*
++	 * Wait up to one second for reset to complete.
++	 */
++	for (i = 0; i < 1000; i++) {
++		ret = REG_READ(REG_GLOBAL, 0x00);
++		if ((ret & 0x8000) == 0x0000)
++			break;
++
++		msleep(1);
++	}
++	if (i == 1000)
++		return -ETIMEDOUT;
++
++	return 0;
++}
++
++static int mv88e6063_setup_global(struct dsa_switch *ds)
++{
++	/*
++	 * Disable discarding of frames with excessive collisions,
++	 * set the maximum frame size to 1536 bytes, and mask all
++	 * interrupt sources.
++	 */
++	REG_WRITE(REG_GLOBAL, 0x04, 0x0800);
++
++	/*
++	 * Enable automatic address learning, set the address
++	 * database size to 1024 entries, and set the default aging
++	 * time to 5 minutes.
++	 */
++	REG_WRITE(REG_GLOBAL, 0x0a, 0x2130);
++
++	return 0;
++}
++
++static int mv88e6063_setup_port(struct dsa_switch *ds, int p)
++{
++	int addr = REG_PORT(p);
++
++	/*
++	 * Do not force flow control, disable Ingress and Egress
++	 * Header tagging, disable VLAN tunneling, and set the port
++	 * state to Forwarding.  Additionally, if this is the CPU
++	 * port, enable Ingress and Egress Trailer tagging mode.
++	 */
++	REG_WRITE(addr, 0x04, dsa_is_cpu_port(ds, p) ?  0x4103 : 0x0003);
++
++	/*
++	 * Port based VLAN map: give each port its own address
++	 * database, allow the CPU port to talk to each of the 'real'
++	 * ports, and allow each of the 'real' ports to only talk to
++	 * the CPU port.
++	 */
++	REG_WRITE(addr, 0x06,
++			((p & 0xf) << 12) |
++			 (dsa_is_cpu_port(ds, p) ?
++				ds->phys_port_mask :
++				(1 << ds->dst->cpu_port)));
++
++	/*
++	 * Port Association Vector: when learning source addresses
++	 * of packets, add the address to the address database using
++	 * a port bitmap that has only the bit for this port set and
++	 * the other bits clear.
++	 */
++	REG_WRITE(addr, 0x0b, 1 << p);
++
++	return 0;
++}
++
++static int mv88e6063_setup(struct dsa_switch *ds)
++{
++	int i;
++	int ret;
++
++	ret = mv88e6063_switch_reset(ds);
++	if (ret < 0)
++		return ret;
++
++	/* @@@ initialise atu */
++
++	ret = mv88e6063_setup_global(ds);
++	if (ret < 0)
++		return ret;
++
++	for (i = 0; i < NUM_PORTS; i++) {
++		ret = mv88e6063_setup_port(ds, i);
++		if (ret < 0)
++			return ret;
++	}
++
++	return 0;
++}
++
++static int mv88e6063_set_addr(struct dsa_switch *ds, u8 *addr)
++{
++	REG_WRITE(REG_GLOBAL, 0x01, (addr[0] << 8) | addr[1]);
++	REG_WRITE(REG_GLOBAL, 0x02, (addr[2] << 8) | addr[3]);
++	REG_WRITE(REG_GLOBAL, 0x03, (addr[4] << 8) | addr[5]);
++
++	return 0;
++}
++
++static int mv88e6063_port_to_phy_addr(int port)
++{
++	if (port >= 0 && port <= NUM_PORTS)
++		return REG_PHY(port);
++	return -1;
++}
++
++static int mv88e6063_phy_read(struct dsa_switch *ds, int port, int regnum)
++{
++	int addr;
++
++	addr = mv88e6063_port_to_phy_addr(port);
++	if (addr == -1)
++		return 0xffff;
++
++	return reg_read(ds, addr, regnum);
++}
++
++static int
++mv88e6063_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
++{
++	int addr;
++
++	addr = mv88e6063_port_to_phy_addr(port);
++	if (addr == -1)
++		return 0xffff;
++
++	return reg_write(ds, addr, regnum, val);
++}
++
++static void mv88e6063_poll_link(struct dsa_switch *ds)
++{
++	int i;
++
++	for (i = 0; i < DSA_MAX_PORTS; i++) {
++		struct net_device *dev;
++		int uninitialized_var(port_status);
++		int link;
++		int speed;
++		int duplex;
++		int fc;
++
++		dev = ds->ports[i];
++		if (dev == NULL)
++			continue;
++
++		link = 0;
++		if (dev->flags & IFF_UP) {
++			port_status = reg_read(ds, REG_PORT(i), 0x00);
++			if (port_status < 0)
++				continue;
++
++			link = !!(port_status & 0x1000);
++		}
++
++		if (!link) {
++			if (netif_carrier_ok(dev)) {
++				printk(KERN_INFO "%s: link down\n", dev->name);
++				netif_carrier_off(dev);
++			}
++			continue;
++		}
++
++		speed = (port_status & 0x0100) ? 100 : 10;
++		duplex = (port_status & 0x0200) ? 1 : 0;
++		fc = ((port_status & 0xc000) == 0xc000) ? 1 : 0;
++
++		if (!netif_carrier_ok(dev)) {
++			printk(KERN_INFO "%s: link up, %d Mb/s, %s duplex, "
++					 "flow control %sabled\n", dev->name,
++					 speed, duplex ? "full" : "half",
++					 fc ? "en" : "dis");
++			netif_carrier_on(dev);
++		}
++	}
++}
++
++static struct dsa_switch_driver mv88e6063_switch_driver = {
++	.tag_protocol	= htons(ETH_P_TRAILER),
++	.probe		= mv88e6063_probe,
++	.setup		= mv88e6063_setup,
++	.set_addr	= mv88e6063_set_addr,
++	.phy_read	= mv88e6063_phy_read,
++	.phy_write	= mv88e6063_phy_write,
++	.poll_link	= mv88e6063_poll_link,
++};
++
++static int __init mv88e6063_init(void)
++{
++	register_switch_driver(&mv88e6063_switch_driver);
++	return 0;
++}
++module_init(mv88e6063_init);
++
++static void __exit mv88e6063_cleanup(void)
++{
++	unregister_switch_driver(&mv88e6063_switch_driver);
++}
++module_exit(mv88e6063_cleanup);
+diff -Nur linux-2.6.33.3.orig/net/dsa/tag_qinq.c linux-2.6.33.3/net/dsa/tag_qinq.c
+--- linux-2.6.33.3.orig/net/dsa/tag_qinq.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.3/net/dsa/tag_qinq.c	2010-03-06 12:19:54.255959609 +0100
+@@ -0,0 +1,127 @@
++/*
++ * net/dsa/tag_qinq.c - QinQ tag format handling
++ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file was based on:
++ *    net/dsa/tag_edsa.c - Ethertype DSA tagging
++ *    Copyright (c) 2008-2009 Marvell Semiconductor
++ *
++ * 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/etherdevice.h>
++#include <linux/list.h>
++#include <linux/netdevice.h>
++#include <linux/if_vlan.h>
++
++#include "dsa_priv.h"
++
++netdev_tx_t qinq_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++	struct dsa_slave_priv *p = netdev_priv(dev);
++	struct vlan_ethhdr *veth;
++	unsigned int len;
++	int ret;
++
++	if (skb_cow_head(skb, VLAN_HLEN) < 0)
++		goto out_free_skb;
++
++	veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN);
++
++	/* Move the mac addresses to the beginning of the new header. */
++	memmove(skb->data, skb->data + VLAN_HLEN, 2 * VLAN_ETH_ALEN);
++	skb->mac_header -= VLAN_HLEN;
++
++	/* setup VLAN header fields */
++	veth->h_vlan_proto = htons(ETH_P_QINQ);
++	veth->h_vlan_TCI = htons(p->port);
++
++	len = skb->len;
++	skb->protocol = htons(ETH_P_QINQ);
++	skb->dev = p->parent->dst->master_netdev;
++
++	ret = dev_queue_xmit(skb);
++	if (unlikely(ret != NET_XMIT_SUCCESS))
++		goto out_dropped;
++
++	dev->stats.tx_packets++;
++	dev->stats.tx_bytes += len;
++
++	return NETDEV_TX_OK;
++
++ out_free_skb:
++	kfree_skb(skb);
++ out_dropped:
++	dev->stats.tx_dropped++;
++	return NETDEV_TX_OK;
++}
++
++static int qinq_rcv(struct sk_buff *skb, struct net_device *dev,
++		    struct packet_type *pt, struct net_device *orig_dev)
++{
++	struct dsa_switch_tree *dst;
++	struct dsa_switch *ds;
++	struct vlan_hdr *vhdr;
++	int source_port;
++
++	dst = dev->dsa_ptr;
++	if (unlikely(dst == NULL))
++		goto out_drop;
++	ds = dst->ds[0];
++
++	skb = skb_unshare(skb, GFP_ATOMIC);
++	if (skb == NULL)
++		goto out;
++
++	if (unlikely(!pskb_may_pull(skb, VLAN_HLEN)))
++		goto out_drop;
++
++	vhdr = (struct vlan_hdr *)skb->data;
++	source_port = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;
++	if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL)
++		goto out_drop;
++
++	/* Remove the outermost VLAN tag and update checksum. */
++	skb_pull_rcsum(skb, VLAN_HLEN);
++	memmove(skb->data - ETH_HLEN,
++		skb->data - ETH_HLEN - VLAN_HLEN,
++		2 * ETH_ALEN);
++
++	skb->dev = ds->ports[source_port];
++	skb_push(skb, ETH_HLEN);
++	skb->pkt_type = PACKET_HOST;
++	skb->protocol = eth_type_trans(skb, skb->dev);
++
++	skb->dev->stats.rx_packets++;
++	skb->dev->stats.rx_bytes += skb->len;
++
++	netif_receive_skb(skb);
++
++	return 0;
++
++ out_drop:
++	kfree_skb(skb);
++ out:
++	return 0;
++}
++
++static struct packet_type qinq_packet_type __read_mostly = {
++	.type	= cpu_to_be16(ETH_P_QINQ),
++	.func	= qinq_rcv,
++};
++
++static int __init qinq_init_module(void)
++{
++	dev_add_pack(&qinq_packet_type);
++	return 0;
++}
++module_init(qinq_init_module);
++
++static void __exit qinq_cleanup_module(void)
++{
++	dev_remove_pack(&qinq_packet_type);
++}
++module_exit(qinq_cleanup_module);

+ 7 - 0
target/rb4xx/target.mk

@@ -0,0 +1,7 @@
+ARCH:=			mips
+CPU_ARCH:=		mips
+KERNEL_VERSION:=	2.6.33.3
+KERNEL_RELEASE:=	1
+KERNEL_MD5SUM:=		f651e9aafb2f910812257a63bcd639f2
+TARGET_OPTIMIZATION:=	-Os -pipe
+TARGET_CFLAGS_ARCH:=    -march=mips32

+ 2 - 3
target/target.lst

@@ -33,9 +33,8 @@ cris_qemu	ADK_LINUX_CRIS_QEMU
 x86_qemu	ADK_LINUX_X86_QEMU
 x86_qemu	ADK_LINUX_X86_QEMU
 x86_64_qemu	ADK_LINUX_X86_64_QEMU
 x86_64_qemu	ADK_LINUX_X86_64_QEMU
 qemu		ADK_LINUX_ARM_QEMU || ADK_LINUX_MIPS_QEMU || ADK_LINUX_MIPSEL_QEMU || ADK_LINUX_MIPS64_QEMU || ADK_LINUX_MIPS64EL_QEMU || ADK_LINUX_CRIS_QEMU || ADK_LINUX_X86_QEMU || ADK_LINUX_X86_64_QEMU
 qemu		ADK_LINUX_ARM_QEMU || ADK_LINUX_MIPS_QEMU || ADK_LINUX_MIPSEL_QEMU || ADK_LINUX_MIPS64_QEMU || ADK_LINUX_MIPS64EL_QEMU || ADK_LINUX_CRIS_QEMU || ADK_LINUX_X86_QEMU || ADK_LINUX_X86_64_QEMU
-rb411		ADK_LINUX_MIPS_RB411
-rb433		ADK_LINUX_MIPS_RB433
+rb4xx		ADK_LINUX_MIPS_RB4XX
 rb532		ADK_LINUX_MIPS_RB532
 rb532		ADK_LINUX_MIPS_RB532
-routerboard	ADK_LINUX_MIPS_RB411 || ADK_LINUX_MIPS_RB433 || ADK_LINUX_MIPS_RB532
+routerboard	ADK_LINUX_MIPS_RB4XX || ADK_LINUX_MIPS_RB532
 x86		ADK_LINUX_X86_QEMU || ADK_LINUX_X86_RESCUE || ADK_LINUX_X86_ALIX1C || ADK_LINUX_X86_ALIX2D || ADK_LINUX_X86_WRAP || ADK_LINUX_X86_ALIX2D13 || ADK_LINUX_X86_IBMX40
 x86		ADK_LINUX_X86_QEMU || ADK_LINUX_X86_RESCUE || ADK_LINUX_X86_ALIX1C || ADK_LINUX_X86_ALIX2D || ADK_LINUX_X86_WRAP || ADK_LINUX_X86_ALIX2D13 || ADK_LINUX_X86_IBMX40
 x86_64		ADK_LINUX_X86_64_QEMU || ADK_LINUX_X86_64_RESCUE || ADK_LINUX_X86_64_SHUTTLE
 x86_64		ADK_LINUX_X86_64_QEMU || ADK_LINUX_X86_64_RESCUE || ADK_LINUX_X86_64_SHUTTLE