summary refs log tree commit diff
path: root/arch/arm/mach-orion5x
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-orion5x')
-rw-r--r--arch/arm/mach-orion5x/Kconfig1
-rw-r--r--arch/arm/mach-orion5x/common.c41
-rw-r--r--arch/arm/mach-orion5x/dns323-setup.c4
-rw-r--r--arch/arm/mach-orion5x/include/mach/system.h2
-rw-r--r--arch/arm/mach-orion5x/lsmini-setup.c2
-rw-r--r--arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c9
-rw-r--r--arch/arm/mach-orion5x/rd88f5181l-ge-setup.c10
-rw-r--r--arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c10
-rw-r--r--arch/arm/mach-orion5x/ts78xx-fpga.h35
-rw-r--r--arch/arm/mach-orion5x/ts78xx-setup.c444
-rw-r--r--arch/arm/mach-orion5x/wrt350n-v2-setup.c9
11 files changed, 444 insertions, 123 deletions
diff --git a/arch/arm/mach-orion5x/Kconfig b/arch/arm/mach-orion5x/Kconfig
index f59a8d0e0824..2c7035d8dcbf 100644
--- a/arch/arm/mach-orion5x/Kconfig
+++ b/arch/arm/mach-orion5x/Kconfig
@@ -71,6 +71,7 @@ config MACH_WRT350N_V2
 
 config MACH_TS78XX
 	bool "Technologic Systems TS-78xx"
+	select PM
 	help
 	  Say 'Y' here if you want your kernel to support the
 	  Technologic Systems TS-78xx platform.
diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c
index 0a623379789f..68cc3efae567 100644
--- a/arch/arm/mach-orion5x/common.c
+++ b/arch/arm/mach-orion5x/common.c
@@ -31,6 +31,7 @@
 #include <plat/ehci-orion.h>
 #include <plat/mv_xor.h>
 #include <plat/orion_nand.h>
+#include <plat/orion5x_wdt.h>
 #include <plat/time.h>
 #include "common.h"
 
@@ -219,14 +220,17 @@ static struct platform_device orion5x_switch_device = {
 
 void __init orion5x_eth_switch_init(struct dsa_platform_data *d, int irq)
 {
+	int i;
+
 	if (irq != NO_IRQ) {
 		orion5x_switch_resources[0].start = irq;
 		orion5x_switch_resources[0].end = irq;
 		orion5x_switch_device.num_resources = 1;
 	}
 
-	d->mii_bus = &orion5x_eth_shared.dev;
 	d->netdev = &orion5x_eth.dev;
+	for (i = 0; i < d->nr_chips; i++)
+		d->chip[i].mii_bus = &orion5x_eth_shared.dev;
 	orion5x_switch_device.dev.platform_data = d;
 
 	platform_device_register(&orion5x_switch_device);
@@ -431,6 +435,10 @@ void __init orion5x_uart1_init(void)
 /*****************************************************************************
  * XOR engine
  ****************************************************************************/
+struct mv_xor_platform_shared_data orion5x_xor_shared_data = {
+	.dram		= &orion5x_mbus_dram_info,
+};
+
 static struct resource orion5x_xor_shared_resources[] = {
 	{
 		.name	= "xor low",
@@ -448,6 +456,9 @@ static struct resource orion5x_xor_shared_resources[] = {
 static struct platform_device orion5x_xor_shared = {
 	.name		= MV_XOR_SHARED_NAME,
 	.id		= 0,
+	.dev		= {
+		.platform_data	= &orion5x_xor_shared_data,
+	},
 	.num_resources	= ARRAY_SIZE(orion5x_xor_shared_resources),
 	.resource	= orion5x_xor_shared_resources,
 };
@@ -526,6 +537,29 @@ void __init orion5x_xor_init(void)
 
 
 /*****************************************************************************
+ * Watchdog
+ ****************************************************************************/
+static struct orion5x_wdt_platform_data orion5x_wdt_data = {
+	.tclk			= 0,
+};
+
+static struct platform_device orion5x_wdt_device = {
+	.name		= "orion5x_wdt",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &orion5x_wdt_data,
+	},
+	.num_resources	= 0,
+};
+
+void __init orion5x_wdt_init(void)
+{
+	orion5x_wdt_data.tclk = orion5x_tclk;
+	platform_device_register(&orion5x_wdt_device);
+}
+
+
+/*****************************************************************************
  * Time handling
  ****************************************************************************/
 int orion5x_tclk;
@@ -624,6 +658,11 @@ void __init orion5x_init(void)
 		printk(KERN_INFO "Orion: Applying 5281 D0 WFI workaround.\n");
 		disable_hlt();
 	}
+
+	/*
+	 * Register watchdog driver
+	 */
+	orion5x_wdt_init();
 }
 
 /*
diff --git a/arch/arm/mach-orion5x/dns323-setup.c b/arch/arm/mach-orion5x/dns323-setup.c
index 0722d6510df1..b31ca4cef365 100644
--- a/arch/arm/mach-orion5x/dns323-setup.c
+++ b/arch/arm/mach-orion5x/dns323-setup.c
@@ -76,7 +76,7 @@ static int __init dns323_dev_id(void)
 
 static int __init dns323_pci_init(void)
 {
-	/* The 5182 doesn't really use it's PCI bus, and initialising PCI
+	/* The 5182 doesn't really use its PCI bus, and initialising PCI
 	 * gets in the way of initialising the SATA controller.
 	 */
 	if (machine_is_dns323() && dns323_dev_id() != MV88F5182_DEV_ID)
@@ -418,7 +418,7 @@ static void __init dns323_init(void)
 	orion5x_i2c_init();
 	orion5x_uart0_init();
 
-	/* The 5182 has it's SATA controller on-chip, and needs it's own little
+	/* The 5182 has its SATA controller on-chip, and needs its own little
 	 * init routine.
 	 */
 	if (dns323_dev_id() == MV88F5182_DEV_ID)
diff --git a/arch/arm/mach-orion5x/include/mach/system.h b/arch/arm/mach-orion5x/include/mach/system.h
index 08e430757890..9b8db1dcfa83 100644
--- a/arch/arm/mach-orion5x/include/mach/system.h
+++ b/arch/arm/mach-orion5x/include/mach/system.h
@@ -19,7 +19,7 @@ static inline void arch_idle(void)
 	cpu_do_idle();
 }
 
-static inline void arch_reset(char mode)
+static inline void arch_reset(char mode, const char *cmd)
 {
 	/*
 	 * Enable and issue soft reset
diff --git a/arch/arm/mach-orion5x/lsmini-setup.c b/arch/arm/mach-orion5x/lsmini-setup.c
index e0c43b8beb72..c9bf6b81a80d 100644
--- a/arch/arm/mach-orion5x/lsmini-setup.c
+++ b/arch/arm/mach-orion5x/lsmini-setup.c
@@ -186,7 +186,7 @@ static struct mv_sata_platform_data lsmini_sata_data = {
 
 static void lsmini_power_off(void)
 {
-	arch_reset(0);
+	arch_reset(0, NULL);
 }
 
 
diff --git a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
index 15f53235ee30..9c1ca41730ba 100644
--- a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
@@ -94,7 +94,7 @@ static struct mv643xx_eth_platform_data rd88f5181l_fxo_eth_data = {
 	.duplex		= DUPLEX_FULL,
 };
 
-static struct dsa_platform_data rd88f5181l_fxo_switch_data = {
+static struct dsa_chip_data rd88f5181l_fxo_switch_chip_data = {
 	.port_names[0]	= "lan2",
 	.port_names[1]	= "lan1",
 	.port_names[2]	= "wan",
@@ -103,6 +103,11 @@ static struct dsa_platform_data rd88f5181l_fxo_switch_data = {
 	.port_names[7]	= "lan3",
 };
 
+static struct dsa_platform_data rd88f5181l_fxo_switch_plat_data = {
+	.nr_chips	= 1,
+	.chip		= &rd88f5181l_fxo_switch_chip_data,
+};
+
 static void __init rd88f5181l_fxo_init(void)
 {
 	/*
@@ -117,7 +122,7 @@ static void __init rd88f5181l_fxo_init(void)
 	 */
 	orion5x_ehci0_init();
 	orion5x_eth_init(&rd88f5181l_fxo_eth_data);
-	orion5x_eth_switch_init(&rd88f5181l_fxo_switch_data, NO_IRQ);
+	orion5x_eth_switch_init(&rd88f5181l_fxo_switch_plat_data, NO_IRQ);
 	orion5x_uart0_init();
 
 	orion5x_setup_dev_boot_win(RD88F5181L_FXO_NOR_BOOT_BASE,
diff --git a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
index 8ad3934399d4..ee1399ff0ced 100644
--- a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
@@ -95,7 +95,7 @@ static struct mv643xx_eth_platform_data rd88f5181l_ge_eth_data = {
 	.duplex		= DUPLEX_FULL,
 };
 
-static struct dsa_platform_data rd88f5181l_ge_switch_data = {
+static struct dsa_chip_data rd88f5181l_ge_switch_chip_data = {
 	.port_names[0]	= "lan2",
 	.port_names[1]	= "lan1",
 	.port_names[2]	= "wan",
@@ -104,6 +104,11 @@ static struct dsa_platform_data rd88f5181l_ge_switch_data = {
 	.port_names[7]	= "lan3",
 };
 
+static struct dsa_platform_data rd88f5181l_ge_switch_plat_data = {
+	.nr_chips	= 1,
+	.chip		= &rd88f5181l_ge_switch_chip_data,
+};
+
 static struct i2c_board_info __initdata rd88f5181l_ge_i2c_rtc = {
 	I2C_BOARD_INFO("ds1338", 0x68),
 };
@@ -122,7 +127,8 @@ static void __init rd88f5181l_ge_init(void)
 	 */
 	orion5x_ehci0_init();
 	orion5x_eth_init(&rd88f5181l_ge_eth_data);
-	orion5x_eth_switch_init(&rd88f5181l_ge_switch_data, gpio_to_irq(8));
+	orion5x_eth_switch_init(&rd88f5181l_ge_switch_plat_data,
+				gpio_to_irq(8));
 	orion5x_i2c_init();
 	orion5x_uart0_init();
 
diff --git a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
index 262e25e4dace..7737cf9a8f50 100644
--- a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
+++ b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
@@ -35,7 +35,7 @@ static struct mv643xx_eth_platform_data rd88f6183ap_ge_eth_data = {
 	.duplex		= DUPLEX_FULL,
 };
 
-static struct dsa_platform_data rd88f6183ap_ge_switch_data = {
+static struct dsa_chip_data rd88f6183ap_ge_switch_chip_data = {
 	.port_names[0]	= "lan1",
 	.port_names[1]	= "lan2",
 	.port_names[2]	= "lan3",
@@ -44,6 +44,11 @@ static struct dsa_platform_data rd88f6183ap_ge_switch_data = {
 	.port_names[5]	= "cpu",
 };
 
+static struct dsa_platform_data rd88f6183ap_ge_switch_plat_data = {
+	.nr_chips	= 1,
+	.chip		= &rd88f6183ap_ge_switch_chip_data,
+};
+
 static struct mtd_partition rd88f6183ap_ge_partitions[] = {
 	{
 		.name	= "kernel",
@@ -89,7 +94,8 @@ static void __init rd88f6183ap_ge_init(void)
 	 */
 	orion5x_ehci0_init();
 	orion5x_eth_init(&rd88f6183ap_ge_eth_data);
-	orion5x_eth_switch_init(&rd88f6183ap_ge_switch_data, gpio_to_irq(3));
+	orion5x_eth_switch_init(&rd88f6183ap_ge_switch_plat_data,
+				gpio_to_irq(3));
 	spi_register_board_info(rd88f6183ap_ge_spi_slave_info,
 				ARRAY_SIZE(rd88f6183ap_ge_spi_slave_info));
 	orion5x_spi_init();
diff --git a/arch/arm/mach-orion5x/ts78xx-fpga.h b/arch/arm/mach-orion5x/ts78xx-fpga.h
new file mode 100644
index 000000000000..0f9cdf458952
--- /dev/null
+++ b/arch/arm/mach-orion5x/ts78xx-fpga.h
@@ -0,0 +1,35 @@
+#define FPGAID(_magic, _rev) ((_magic << 8) + _rev)
+
+/*
+ * get yer id's from http://ts78xx.digriz.org.uk/
+ * do *not* make up your own or 'borrow' any!
+ */
+enum fpga_ids {
+	/* Technologic Systems */
+	TS7800_REV_1	= FPGAID(0x00b480, 0x01),
+	TS7800_REV_2	= FPGAID(0x00b480, 0x02),
+	TS7800_REV_3	= FPGAID(0x00b480, 0x03),
+	TS7800_REV_4	= FPGAID(0x00b480, 0x04),
+	TS7800_REV_5	= FPGAID(0x00b480, 0x05),
+
+	/* Unaffordable & Expensive */
+	UAE_DUMMY	= FPGAID(0xffffff, 0x01),
+};
+
+struct fpga_device {
+	unsigned		present:1;
+	unsigned		init:1;
+};
+
+struct fpga_devices {
+	/* Technologic Systems */
+	struct fpga_device 	ts_rtc;
+	struct fpga_device 	ts_nand;
+};
+
+struct ts78xx_fpga_data {
+	unsigned int		id;
+	int			state;
+
+	struct fpga_devices	supports;
+};
diff --git a/arch/arm/mach-orion5x/ts78xx-setup.c b/arch/arm/mach-orion5x/ts78xx-setup.c
index 1368e9fd1a06..9a6b397f972d 100644
--- a/arch/arm/mach-orion5x/ts78xx-setup.c
+++ b/arch/arm/mach-orion5x/ts78xx-setup.c
@@ -10,17 +10,20 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/sysfs.h>
 #include <linux/platform_device.h>
-#include <linux/mtd/physmap.h>
 #include <linux/mv643xx_eth.h>
 #include <linux/ata_platform.h>
 #include <linux/m48t86.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <mach/orion5x.h>
 #include "common.h"
 #include "mpp.h"
+#include "ts78xx-fpga.h"
 
 /*****************************************************************************
  * TS-78xx Info
@@ -33,18 +36,11 @@
 #define TS78XX_FPGA_REGS_VIRT_BASE	0xff900000
 #define TS78XX_FPGA_REGS_SIZE		SZ_1M
 
-#define TS78XX_FPGA_REGS_SYSCON_ID	(TS78XX_FPGA_REGS_VIRT_BASE | 0x000)
-#define TS78XX_FPGA_REGS_SYSCON_LCDI	(TS78XX_FPGA_REGS_VIRT_BASE | 0x004)
-#define TS78XX_FPGA_REGS_SYSCON_LCDO	(TS78XX_FPGA_REGS_VIRT_BASE | 0x008)
-
-#define TS78XX_FPGA_REGS_RTC_CTRL	(TS78XX_FPGA_REGS_VIRT_BASE | 0x808)
-#define TS78XX_FPGA_REGS_RTC_DATA	(TS78XX_FPGA_REGS_VIRT_BASE | 0x80c)
-
-/*
- * 512kB NOR flash Device
- */
-#define TS78XX_NOR_BOOT_BASE		0xff800000
-#define TS78XX_NOR_BOOT_SIZE		SZ_512K
+static struct ts78xx_fpga_data ts78xx_fpga = {
+	.id		= 0,
+	.state		= 1,
+/*	.supports	= ... - populated by ts78xx_fpga_supports() */
+};
 
 /*****************************************************************************
  * I/O Address Mapping
@@ -65,73 +61,47 @@ void __init ts78xx_map_io(void)
 }
 
 /*****************************************************************************
- * 512kB NOR Boot Flash - the chip is a M25P40
+ * Ethernet
  ****************************************************************************/
-static struct mtd_partition ts78xx_nor_boot_flash_resources[] = {
-	{
-		.name		= "ts-bootrom",
-		.offset		= 0,
-		/* only the first 256kB is used */
-		.size		= SZ_256K,
-		.mask_flags	= MTD_WRITEABLE,
-	},
-};
-
-static struct physmap_flash_data ts78xx_nor_boot_flash_data = {
-	.width		= 1,
-	.parts		= ts78xx_nor_boot_flash_resources,
-	.nr_parts	= ARRAY_SIZE(ts78xx_nor_boot_flash_resources),
-};
-
-static struct resource ts78xx_nor_boot_flash_resource = {
-	.flags		= IORESOURCE_MEM,
-	.start		= TS78XX_NOR_BOOT_BASE,
-	.end		= TS78XX_NOR_BOOT_BASE + TS78XX_NOR_BOOT_SIZE - 1,
-};
-
-static struct platform_device ts78xx_nor_boot_flash = {
-	.name		= "physmap-flash",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &ts78xx_nor_boot_flash_data,
-	},
-	.num_resources	= 1,
-	.resource	= &ts78xx_nor_boot_flash_resource,
+static struct mv643xx_eth_platform_data ts78xx_eth_data = {
+	.phy_addr	= MV643XX_ETH_PHY_ADDR(0),
 };
 
 /*****************************************************************************
- * Ethernet
+ * SATA
  ****************************************************************************/
-static struct mv643xx_eth_platform_data ts78xx_eth_data = {
-	.phy_addr	= MV643XX_ETH_PHY_ADDR(0),
+static struct mv_sata_platform_data ts78xx_sata_data = {
+	.n_ports	= 2,
 };
 
 /*****************************************************************************
  * RTC M48T86 - nicked^Wborrowed from arch/arm/mach-ep93xx/ts72xx.c
  ****************************************************************************/
-#ifdef CONFIG_RTC_DRV_M48T86
-static unsigned char ts78xx_rtc_readbyte(unsigned long addr)
+#define TS_RTC_CTRL	(TS78XX_FPGA_REGS_VIRT_BASE | 0x808)
+#define TS_RTC_DATA	(TS78XX_FPGA_REGS_VIRT_BASE | 0x80c)
+
+static unsigned char ts78xx_ts_rtc_readbyte(unsigned long addr)
 {
-	writeb(addr, TS78XX_FPGA_REGS_RTC_CTRL);
-	return readb(TS78XX_FPGA_REGS_RTC_DATA);
+	writeb(addr, TS_RTC_CTRL);
+	return readb(TS_RTC_DATA);
 }
 
-static void ts78xx_rtc_writebyte(unsigned char value, unsigned long addr)
+static void ts78xx_ts_rtc_writebyte(unsigned char value, unsigned long addr)
 {
-	writeb(addr, TS78XX_FPGA_REGS_RTC_CTRL);
-	writeb(value, TS78XX_FPGA_REGS_RTC_DATA);
+	writeb(addr, TS_RTC_CTRL);
+	writeb(value, TS_RTC_DATA);
 }
 
-static struct m48t86_ops ts78xx_rtc_ops = {
-	.readbyte	= ts78xx_rtc_readbyte,
-	.writebyte	= ts78xx_rtc_writebyte,
+static struct m48t86_ops ts78xx_ts_rtc_ops = {
+	.readbyte	= ts78xx_ts_rtc_readbyte,
+	.writebyte	= ts78xx_ts_rtc_writebyte,
 };
 
-static struct platform_device ts78xx_rtc_device = {
+static struct platform_device ts78xx_ts_rtc_device = {
 	.name		= "rtc-m48t86",
 	.id		= -1,
 	.dev		= {
-		.platform_data	= &ts78xx_rtc_ops,
+		.platform_data	= &ts78xx_ts_rtc_ops,
 	},
 	.num_resources	= 0,
 };
@@ -146,59 +116,314 @@ static struct platform_device ts78xx_rtc_device = {
  * TODO: track down a guinea pig without an RTC to see if we can work out a
  * 		better RTC detection routine
  */
-static int __init ts78xx_rtc_init(void)
+static int ts78xx_ts_rtc_load(void)
 {
+	int rc;
 	unsigned char tmp_rtc0, tmp_rtc1;
 
-	tmp_rtc0 = ts78xx_rtc_readbyte(126);
-	tmp_rtc1 = ts78xx_rtc_readbyte(127);
-
-	ts78xx_rtc_writebyte(0x00, 126);
-	ts78xx_rtc_writebyte(0x55, 127);
-	if (ts78xx_rtc_readbyte(127) == 0x55) {
-		ts78xx_rtc_writebyte(0xaa, 127);
-		if (ts78xx_rtc_readbyte(127) == 0xaa
-				&& ts78xx_rtc_readbyte(126) == 0x00) {
-			ts78xx_rtc_writebyte(tmp_rtc0, 126);
-			ts78xx_rtc_writebyte(tmp_rtc1, 127);
-			platform_device_register(&ts78xx_rtc_device);
-			return 1;
+	tmp_rtc0 = ts78xx_ts_rtc_readbyte(126);
+	tmp_rtc1 = ts78xx_ts_rtc_readbyte(127);
+
+	ts78xx_ts_rtc_writebyte(0x00, 126);
+	ts78xx_ts_rtc_writebyte(0x55, 127);
+	if (ts78xx_ts_rtc_readbyte(127) == 0x55) {
+		ts78xx_ts_rtc_writebyte(0xaa, 127);
+		if (ts78xx_ts_rtc_readbyte(127) == 0xaa
+				&& ts78xx_ts_rtc_readbyte(126) == 0x00) {
+			ts78xx_ts_rtc_writebyte(tmp_rtc0, 126);
+			ts78xx_ts_rtc_writebyte(tmp_rtc1, 127);
+
+			if (ts78xx_fpga.supports.ts_rtc.init == 0) {
+				rc = platform_device_register(&ts78xx_ts_rtc_device);
+				if (!rc)
+					ts78xx_fpga.supports.ts_rtc.init = 1;
+			} else
+				rc = platform_device_add(&ts78xx_ts_rtc_device);
+
+			return rc;
 		}
 	}
 
-	return 0;
+	return -ENODEV;
 };
-#else
-static int __init ts78xx_rtc_init(void)
+
+static void ts78xx_ts_rtc_unload(void)
 {
-	return 0;
+	platform_device_del(&ts78xx_ts_rtc_device);
 }
-#endif
 
 /*****************************************************************************
- * SATA
+ * NAND Flash
  ****************************************************************************/
-static struct mv_sata_platform_data ts78xx_sata_data = {
-	.n_ports	= 2,
+#define TS_NAND_CTRL	(TS78XX_FPGA_REGS_VIRT_BASE | 0x800)	/* VIRT */
+#define TS_NAND_DATA	(TS78XX_FPGA_REGS_PHYS_BASE | 0x804)	/* PHYS */
+
+/*
+ * hardware specific access to control-lines
+ *
+ * ctrl:
+ * NAND_NCE: bit 0 -> bit 2
+ * NAND_CLE: bit 1 -> bit 1
+ * NAND_ALE: bit 2 -> bit 0
+ */
+static void ts78xx_ts_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+			unsigned int ctrl)
+{
+	struct nand_chip *this = mtd->priv;
+
+	if (ctrl & NAND_CTRL_CHANGE) {
+		unsigned char bits;
+
+		bits = (ctrl & NAND_NCE) << 2;
+		bits |= ctrl & NAND_CLE;
+		bits |= (ctrl & NAND_ALE) >> 2;
+
+		writeb((readb(TS_NAND_CTRL) & ~0x7) | bits, TS_NAND_CTRL);
+	}
+
+	if (cmd != NAND_CMD_NONE)
+		writeb(cmd, this->IO_ADDR_W);
+}
+
+static int ts78xx_ts_nand_dev_ready(struct mtd_info *mtd)
+{
+	return readb(TS_NAND_CTRL) & 0x20;
+}
+
+const char *ts_nand_part_probes[] = { "cmdlinepart", NULL };
+
+static struct mtd_partition ts78xx_ts_nand_parts[] = {
+	{
+		.name		= "mbr",
+		.offset		= 0,
+		.size		= SZ_128K,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "kernel",
+		.offset		= MTDPART_OFS_APPEND,
+		.size		= SZ_4M,
+	}, {
+		.name		= "initrd",
+		.offset		= MTDPART_OFS_APPEND,
+		.size		= SZ_4M,
+	}, {
+		.name		= "rootfs",
+		.offset		= MTDPART_OFS_APPEND,
+		.size		= MTDPART_SIZ_FULL,
+	}
 };
 
+static struct platform_nand_data ts78xx_ts_nand_data = {
+	.chip	= {
+		.part_probe_types	= ts_nand_part_probes,
+		.partitions		= ts78xx_ts_nand_parts,
+		.nr_partitions		= ARRAY_SIZE(ts78xx_ts_nand_parts),
+		.chip_delay		= 15,
+		.options		= NAND_USE_FLASH_BBT,
+	},
+	.ctrl	= {
+		/*
+		 * The HW ECC offloading functions, used to give about a 9%
+		 * performance increase for 'dd if=/dev/mtdblockX' and 5% for
+		 * nanddump.  This all however was changed by git commit
+		 * e6cf5df1838c28bb060ac45b5585e48e71bbc740 so now there is
+		 * no performance advantage to be had so we no longer bother
+		 */
+		.cmd_ctrl		= ts78xx_ts_nand_cmd_ctrl,
+		.dev_ready		= ts78xx_ts_nand_dev_ready,
+	},
+};
+
+static struct resource ts78xx_ts_nand_resources = {
+	.start		= TS_NAND_DATA,
+	.end		= TS_NAND_DATA + 4,
+	.flags		= IORESOURCE_IO,
+};
+
+static struct platform_device ts78xx_ts_nand_device = {
+	.name		= "gen_nand",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &ts78xx_ts_nand_data,
+	},
+	.resource	= &ts78xx_ts_nand_resources,
+	.num_resources	= 1,
+};
+
+static int ts78xx_ts_nand_load(void)
+{
+	int rc;
+
+	if (ts78xx_fpga.supports.ts_nand.init == 0) {
+		rc = platform_device_register(&ts78xx_ts_nand_device);
+		if (!rc)
+			ts78xx_fpga.supports.ts_nand.init = 1;
+	} else
+		rc = platform_device_add(&ts78xx_ts_nand_device);
+
+	return rc;
+};
+
+static void ts78xx_ts_nand_unload(void)
+{
+	platform_device_del(&ts78xx_ts_nand_device);
+}
+
 /*****************************************************************************
- * print some information regarding the board
+ * FPGA 'hotplug' support code
  ****************************************************************************/
-static void __init ts78xx_print_board_id(void)
+static void ts78xx_fpga_devices_zero_init(void)
 {
-	unsigned int board_info;
-
-	board_info = readl(TS78XX_FPGA_REGS_SYSCON_ID);
-	printk(KERN_INFO "TS-78xx Info: FPGA rev=%.2x, Board Magic=%.6x, ",
-				board_info & 0xff,
-				(board_info >> 8) & 0xffffff);
-	board_info = readl(TS78XX_FPGA_REGS_SYSCON_LCDI);
-	printk("JP1=%d, JP2=%d\n",
-				(board_info >> 30) & 0x1,
-				(board_info >> 31) & 0x1);
+	ts78xx_fpga.supports.ts_rtc.init = 0;
+	ts78xx_fpga.supports.ts_nand.init = 0;
+}
+
+static void ts78xx_fpga_supports(void)
+{
+	/* TODO: put this 'table' into ts78xx-fpga.h */
+	switch (ts78xx_fpga.id) {
+	case TS7800_REV_1:
+	case TS7800_REV_2:
+	case TS7800_REV_3:
+	case TS7800_REV_4:
+	case TS7800_REV_5:
+		ts78xx_fpga.supports.ts_rtc.present = 1;
+		ts78xx_fpga.supports.ts_nand.present = 1;
+		break;
+	default:
+		ts78xx_fpga.supports.ts_rtc.present = 0;
+		ts78xx_fpga.supports.ts_nand.present = 0;
+	}
+}
+
+static int ts78xx_fpga_load_devices(void)
+{
+	int tmp, ret = 0;
+
+	if (ts78xx_fpga.supports.ts_rtc.present == 1) {
+		tmp = ts78xx_ts_rtc_load();
+		if (tmp) {
+			printk(KERN_INFO "TS-78xx: RTC not registered\n");
+			ts78xx_fpga.supports.ts_rtc.present = 0;
+		}
+		ret |= tmp;
+	}
+	if (ts78xx_fpga.supports.ts_nand.present == 1) {
+		tmp = ts78xx_ts_nand_load();
+		if (tmp) {
+			printk(KERN_INFO "TS-78xx: NAND not registered\n");
+			ts78xx_fpga.supports.ts_nand.present = 0;
+		}
+		ret |= tmp;
+	}
+
+	return ret;
+}
+
+static int ts78xx_fpga_unload_devices(void)
+{
+	int ret = 0;
+
+	if (ts78xx_fpga.supports.ts_rtc.present == 1)
+		ts78xx_ts_rtc_unload();
+	if (ts78xx_fpga.supports.ts_nand.present == 1)
+		ts78xx_ts_nand_unload();
+
+	return ret;
+}
+
+static int ts78xx_fpga_load(void)
+{
+	ts78xx_fpga.id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
+
+	printk(KERN_INFO "TS-78xx FPGA: magic=0x%.6x, rev=0x%.2x\n",
+			(ts78xx_fpga.id >> 8) & 0xffffff,
+			ts78xx_fpga.id & 0xff);
+
+	ts78xx_fpga_supports();
+
+	if (ts78xx_fpga_load_devices()) {
+		ts78xx_fpga.state = -1;
+		return -EBUSY;
+	}
+
+	return 0;
 };
 
+static int ts78xx_fpga_unload(void)
+{
+	unsigned int fpga_id;
+
+	fpga_id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
+
+	/*
+	 * There does not seem to be a feasible way to block access to the GPIO
+	 * pins from userspace (/dev/mem).  This if clause should hopefully warn
+	 * those foolish enough not to follow 'policy' :)
+	 *
+	 * UrJTAG SVN since r1381 can be used to reprogram the FPGA
+	 */
+	if (ts78xx_fpga.id != fpga_id) {
+		printk(KERN_ERR	"TS-78xx FPGA: magic/rev mismatch\n"
+			"TS-78xx FPGA: was 0x%.6x/%.2x but now 0x%.6x/%.2x\n",
+			(ts78xx_fpga.id >> 8) & 0xffffff, ts78xx_fpga.id & 0xff,
+			(fpga_id >> 8) & 0xffffff, fpga_id & 0xff);
+		ts78xx_fpga.state = -1;
+		return -EBUSY;
+	}
+
+	if (ts78xx_fpga_unload_devices()) {
+		ts78xx_fpga.state = -1;
+		return -EBUSY;
+	}
+
+	return 0;
+};
+
+static ssize_t ts78xx_fpga_show(struct kobject *kobj,
+			struct kobj_attribute *attr, char *buf)
+{
+	if (ts78xx_fpga.state < 0)
+		return sprintf(buf, "borked\n");
+
+	return sprintf(buf, "%s\n", (ts78xx_fpga.state) ? "online" : "offline");
+}
+
+static ssize_t ts78xx_fpga_store(struct kobject *kobj,
+			struct kobj_attribute *attr, const char *buf, size_t n)
+{
+	int value, ret;
+
+	if (ts78xx_fpga.state < 0) {
+		printk(KERN_ERR "TS-78xx FPGA: borked, you must powercycle asap\n");
+		return -EBUSY;
+	}
+
+	if (strncmp(buf, "online", sizeof("online") - 1) == 0)
+		value = 1;
+	else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
+		value = 0;
+	else {
+		printk(KERN_ERR "ts78xx_fpga_store: Invalid value\n");
+		return -EINVAL;
+	}
+
+	if (ts78xx_fpga.state == value)
+		return n;
+
+	ret = (ts78xx_fpga.state == 0)
+		? ts78xx_fpga_load()
+		: ts78xx_fpga_unload();
+
+	if (!(ret < 0))
+		ts78xx_fpga.state = value;
+
+	return n;
+}
+
+static struct kobj_attribute ts78xx_fpga_attr =
+	__ATTR(ts78xx_fpga, 0644, ts78xx_fpga_show, ts78xx_fpga_store);
+
 /*****************************************************************************
  * General Setup
  ****************************************************************************/
@@ -223,30 +448,29 @@ static struct orion5x_mpp_mode ts78xx_mpp_modes[] __initdata = {
 	{ 17, MPP_UART },
 	{ 18, MPP_UART },
 	{ 19, MPP_UART },
+	/*
+	 * MPP[20] PCI Clock Out 1
+	 * MPP[21] PCI Clock Out 0
+	 * MPP[22] Unused
+	 * MPP[23] Unused
+	 * MPP[24] Unused
+	 * MPP[25] Unused
+	 */
 	{ -1 },
 };
 
 static void __init ts78xx_init(void)
 {
+	int ret;
+
 	/*
 	 * Setup basic Orion functions. Need to be called early.
 	 */
 	orion5x_init();
 
-	ts78xx_print_board_id();
-
 	orion5x_mpp_conf(ts78xx_mpp_modes);
 
 	/*
-	 * MPP[20] PCI Clock Out 1
-	 * MPP[21] PCI Clock Out 0
-	 * MPP[22] Unused
-	 * MPP[23] Unused
-	 * MPP[24] Unused
-	 * MPP[25] Unused
-	 */
-
-	/*
 	 * Configure peripherals.
 	 */
 	orion5x_ehci0_init();
@@ -257,12 +481,12 @@ static void __init ts78xx_init(void)
 	orion5x_uart1_init();
 	orion5x_xor_init();
 
-	orion5x_setup_dev_boot_win(TS78XX_NOR_BOOT_BASE,
-				   TS78XX_NOR_BOOT_SIZE);
-	platform_device_register(&ts78xx_nor_boot_flash);
-
-	if (!ts78xx_rtc_init())
-		printk(KERN_INFO "TS-78xx RTC not detected or enabled\n");
+	/* FPGA init */
+	ts78xx_fpga_devices_zero_init();
+	ret = ts78xx_fpga_load();
+	ret = sysfs_create_file(power_kobj, &ts78xx_fpga_attr.attr);
+	if (ret)
+		printk(KERN_ERR "sysfs_create_file failed: %d\n", ret);
 }
 
 MACHINE_START(TS78XX, "Technologic Systems TS-78xx SBC")
diff --git a/arch/arm/mach-orion5x/wrt350n-v2-setup.c b/arch/arm/mach-orion5x/wrt350n-v2-setup.c
index cc8f89200865..1b4ad9d5e2eb 100644
--- a/arch/arm/mach-orion5x/wrt350n-v2-setup.c
+++ b/arch/arm/mach-orion5x/wrt350n-v2-setup.c
@@ -106,7 +106,7 @@ static struct mv643xx_eth_platform_data wrt350n_v2_eth_data = {
 	.duplex		= DUPLEX_FULL,
 };
 
-static struct dsa_platform_data wrt350n_v2_switch_data = {
+static struct dsa_chip_data wrt350n_v2_switch_chip_data = {
 	.port_names[0]	= "lan2",
 	.port_names[1]	= "lan1",
 	.port_names[2]	= "wan",
@@ -115,6 +115,11 @@ static struct dsa_platform_data wrt350n_v2_switch_data = {
 	.port_names[7]	= "lan4",
 };
 
+static struct dsa_platform_data wrt350n_v2_switch_plat_data = {
+	.nr_chips	= 1,
+	.chip		= &wrt350n_v2_switch_chip_data,
+};
+
 static void __init wrt350n_v2_init(void)
 {
 	/*
@@ -129,7 +134,7 @@ static void __init wrt350n_v2_init(void)
 	 */
 	orion5x_ehci0_init();
 	orion5x_eth_init(&wrt350n_v2_eth_data);
-	orion5x_eth_switch_init(&wrt350n_v2_switch_data, NO_IRQ);
+	orion5x_eth_switch_init(&wrt350n_v2_switch_plat_data, NO_IRQ);
 	orion5x_uart0_init();
 
 	orion5x_setup_dev_boot_win(WRT350N_V2_NOR_BOOT_BASE,