summary refs log tree commit diff
path: root/arch/arm
diff options
context:
space:
mode:
authorNicolas Pitre <nico@cam.org>2009-02-19 22:16:36 -0500
committerNicolas Pitre <nico@cam.org>2009-02-19 22:21:57 -0500
commit22fc1db12515e1b528570c547fd27e38df792f1f (patch)
tree9c7308bbac04abbd55f1000b2122bf7f94a9eedd /arch/arm
parent402a917aca5daca69fcc91f43e6f1e6939cf393b (diff)
parent39008f959f4f3b60eecc5cec0ca077146c1f366b (diff)
downloadlinux-22fc1db12515e1b528570c547fd27e38df792f1f.tar.gz
Merge branch 'for-np' of git://git.wormnet.eu/alex/ts78xx into orion/master
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/configs/orion5x_defconfig2
-rw-r--r--arch/arm/mach-orion5x/Kconfig1
-rw-r--r--arch/arm/mach-orion5x/ts78xx-fpga.h27
-rw-r--r--arch/arm/mach-orion5x/ts78xx-setup.c310
4 files changed, 231 insertions, 109 deletions
diff --git a/arch/arm/configs/orion5x_defconfig b/arch/arm/configs/orion5x_defconfig
index a8ee6984a09e..a34ea6b2cc51 100644
--- a/arch/arm/configs/orion5x_defconfig
+++ b/arch/arm/configs/orion5x_defconfig
@@ -1177,7 +1177,7 @@ CONFIG_RTC_DRV_S35390A=y
 # CONFIG_RTC_DRV_DS1553 is not set
 # CONFIG_RTC_DRV_DS1742 is not set
 # CONFIG_RTC_DRV_STK17TA8 is not set
-# CONFIG_RTC_DRV_M48T86 is not set
+CONFIG_RTC_DRV_M48T86=y
 # CONFIG_RTC_DRV_M48T59 is not set
 # CONFIG_RTC_DRV_V3020 is not set
 
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/ts78xx-fpga.h b/arch/arm/mach-orion5x/ts78xx-fpga.h
new file mode 100644
index 000000000000..0b8e30faff14
--- /dev/null
+++ b/arch/arm/mach-orion5x/ts78xx-fpga.h
@@ -0,0 +1,27 @@
+#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_B = FPGAID(0x00b480, 0x03),
+};
+
+struct fpga_device {
+	unsigned		present:1;
+	unsigned		init:1;
+};
+
+struct fpga_devices {
+	/* Technologic Systems */
+	struct fpga_device 	ts_rtc;
+};
+
+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..baa25d0fd5c9 100644
--- a/arch/arm/mach-orion5x/ts78xx-setup.c
+++ b/arch/arm/mach-orion5x/ts78xx-setup.c
@@ -10,8 +10,8 @@
 
 #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>
@@ -21,6 +21,7 @@
 #include <mach/orion5x.h>
 #include "common.h"
 #include "mpp.h"
+#include "ts78xx-fpga.h"
 
 /*****************************************************************************
  * TS-78xx Info
@@ -33,18 +34,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 +59,48 @@ 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 +115,185 @@ 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)
 {
 	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) {
+				ts78xx_fpga.supports.ts_rtc.init = 1;
+				platform_device_register(&ts78xx_ts_rtc_device);
+			} else
+				platform_device_add(&ts78xx_ts_rtc_device);
+			return 0;
 		}
 	}
 
-	return 0;
+	ts78xx_fpga.supports.ts_rtc.present = 0;
+	return -ENODEV;
 };
+
+static void ts78xx_ts_rtc_unload(void)
+{
+	platform_device_del(&ts78xx_ts_rtc_device);
+}
 #else
-static int __init ts78xx_rtc_init(void)
+static int ts78xx_ts_rtc_load(void)
 {
 	return 0;
 }
+
+static void ts78xx_ts_rtc_unload(void)
+{
+}
 #endif
 
 /*****************************************************************************
- * SATA
+ * FPGA 'hotplug' support code
  ****************************************************************************/
-static struct mv_sata_platform_data ts78xx_sata_data = {
-	.n_ports	= 2,
+static void ts78xx_fpga_devices_zero_init(void)
+{
+	ts78xx_fpga.supports.ts_rtc.init = 0;
+}
+
+static void ts78xx_fpga_supports(void)
+{
+	/* TODO: put this 'table' into ts78xx-fpga.h */
+	switch (ts78xx_fpga.id) {
+	case TS7800_REV_B:
+		ts78xx_fpga.supports.ts_rtc.present = 1;
+		break;
+	default:
+		ts78xx_fpga.supports.ts_rtc.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 detected or enabled\n");
+		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();
+
+	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;
 };
 
-/*****************************************************************************
- * print some information regarding the board
- ****************************************************************************/
-static void __init ts78xx_print_board_id(void)
+static int ts78xx_fpga_unload(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);
+	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 +318,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 +351,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")