17171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter/*
27171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter * arch/arm/mach-orion5x/ts78xx-setup.c
37171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter *
47171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter * Maintainer: Alexander Clouter <alex@digriz.org.uk>
57171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter *
67171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter * This file is licensed under the terms of the GNU General Public
77171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter * License version 2.  This program is licensed "as is" without any
87171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter * warranty of any kind, whether express or implied.
97171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter */
107171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter
114d72cef17bb71a63526b6219bc06b7f31d86dde1Alexander Clouter#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
124d72cef17bb71a63526b6219bc06b7f31d86dde1Alexander Clouter
137171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter#include <linux/kernel.h>
147171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter#include <linux/init.h>
1539008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter#include <linux/sysfs.h>
167171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter#include <linux/platform_device.h>
177171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter#include <linux/mv643xx_eth.h>
187171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter#include <linux/ata_platform.h>
197171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter#include <linux/m48t86.h>
2075bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter#include <linux/mtd/nand.h>
2175bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter#include <linux/mtd/partitions.h>
22a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter#include <linux/timeriomem-rng.h>
237171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter#include <asm/mach-types.h>
247171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter#include <asm/mach/arch.h>
257171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter#include <asm/mach/map.h>
26a09e64fbc0094e3073dbb09c3b4bfe4ab669244bRussell King#include <mach/orion5x.h>
277171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter#include "common.h"
287171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter#include "mpp.h"
2939008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter#include "ts78xx-fpga.h"
307171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter
317171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter/*****************************************************************************
327171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter * TS-78xx Info
337171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter ****************************************************************************/
347171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter
357171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter/*
367171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter * FPGA - lives where the PCI bus would be at ORION5X_PCI_MEM_PHYS_BASE
377171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter */
387171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter#define TS78XX_FPGA_REGS_PHYS_BASE	0xe8000000
39ac3524b7f5a6b9a744fb7ea19991355354c09afbAndrew Lunn#define TS78XX_FPGA_REGS_VIRT_BASE	IOMEM(0xff900000)
407171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter#define TS78XX_FPGA_REGS_SIZE		SZ_1M
417171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter
4239008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouterstatic struct ts78xx_fpga_data ts78xx_fpga = {
4339008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	.id		= 0,
4439008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	.state		= 1,
4539008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter/*	.supports	= ... - populated by ts78xx_fpga_supports() */
4639008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter};
477171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter
487171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter/*****************************************************************************
497171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter * I/O Address Mapping
507171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter ****************************************************************************/
517171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouterstatic struct map_desc ts78xx_io_desc[] __initdata = {
527171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	{
53ac3524b7f5a6b9a744fb7ea19991355354c09afbAndrew Lunn		.virtual	= (unsigned long)TS78XX_FPGA_REGS_VIRT_BASE,
547171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter		.pfn		= __phys_to_pfn(TS78XX_FPGA_REGS_PHYS_BASE),
557171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter		.length		= TS78XX_FPGA_REGS_SIZE,
567171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter		.type		= MT_DEVICE,
577171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	},
587171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter};
597171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter
604236666688e9dbc38d0c7a98b7cfa16c8961f752Andrew Lunnstatic void __init ts78xx_map_io(void)
617171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter{
627171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	orion5x_map_io();
637171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	iotable_init(ts78xx_io_desc, ARRAY_SIZE(ts78xx_io_desc));
647171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter}
657171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter
667171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter/*****************************************************************************
677171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter * Ethernet
687171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter ****************************************************************************/
697171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouterstatic struct mv643xx_eth_platform_data ts78xx_eth_data = {
70ac840605f3b1d9b99e1e6629a54994f8e003ff91Lennert Buytenhek	.phy_addr	= MV643XX_ETH_PHY_ADDR(0),
717171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter};
727171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter
737171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter/*****************************************************************************
7439008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter * SATA
7539008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter ****************************************************************************/
7639008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouterstatic struct mv_sata_platform_data ts78xx_sata_data = {
7739008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	.n_ports	= 2,
7839008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter};
7939008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
8039008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter/*****************************************************************************
817171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter * RTC M48T86 - nicked^Wborrowed from arch/arm/mach-ep93xx/ts72xx.c
827171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter ****************************************************************************/
83ac3524b7f5a6b9a744fb7ea19991355354c09afbAndrew Lunn#define TS_RTC_CTRL	(TS78XX_FPGA_REGS_VIRT_BASE + 0x808)
84ac3524b7f5a6b9a744fb7ea19991355354c09afbAndrew Lunn#define TS_RTC_DATA	(TS78XX_FPGA_REGS_VIRT_BASE + 0x80c)
8539008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
8639008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouterstatic unsigned char ts78xx_ts_rtc_readbyte(unsigned long addr)
877171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter{
8839008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	writeb(addr, TS_RTC_CTRL);
8939008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	return readb(TS_RTC_DATA);
907171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter}
917171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter
9239008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouterstatic void ts78xx_ts_rtc_writebyte(unsigned char value, unsigned long addr)
937171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter{
9439008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	writeb(addr, TS_RTC_CTRL);
9539008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	writeb(value, TS_RTC_DATA);
967171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter}
977171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter
9839008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouterstatic struct m48t86_ops ts78xx_ts_rtc_ops = {
9939008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	.readbyte	= ts78xx_ts_rtc_readbyte,
10039008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	.writebyte	= ts78xx_ts_rtc_writebyte,
1017171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter};
1027171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter
10339008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouterstatic struct platform_device ts78xx_ts_rtc_device = {
1047171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	.name		= "rtc-m48t86",
1057171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	.id		= -1,
1067171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	.dev		= {
10739008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter		.platform_data	= &ts78xx_ts_rtc_ops,
1087171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	},
1097171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	.num_resources	= 0,
1107171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter};
1117171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter
1127171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter/*
1137171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter * TS uses some of the user storage space on the RTC chip so see if it is
1147171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter * present; as it's an optional feature at purchase time and not all boards
1157171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter * will have it present
1167171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter *
1177171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter * I've used the method TS use in their rtc7800.c example for the detection
1187171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter *
1197171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter * TODO: track down a guinea pig without an RTC to see if we can work out a
1209f234997dac445a64f5d9672bf21649e6d745bb9Alexander Clouter *		better RTC detection routine
1217171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter */
12239008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouterstatic int ts78xx_ts_rtc_load(void)
1237171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter{
124f5273fa3102fa4c25819f3034b8834c37d3e62a3Alexander Clouter	int rc;
1257171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	unsigned char tmp_rtc0, tmp_rtc1;
1267171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter
12739008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	tmp_rtc0 = ts78xx_ts_rtc_readbyte(126);
12839008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	tmp_rtc1 = ts78xx_ts_rtc_readbyte(127);
12939008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
13039008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	ts78xx_ts_rtc_writebyte(0x00, 126);
13139008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	ts78xx_ts_rtc_writebyte(0x55, 127);
13239008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	if (ts78xx_ts_rtc_readbyte(127) == 0x55) {
13339008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter		ts78xx_ts_rtc_writebyte(0xaa, 127);
13439008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter		if (ts78xx_ts_rtc_readbyte(127) == 0xaa
13539008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter				&& ts78xx_ts_rtc_readbyte(126) == 0x00) {
13639008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter			ts78xx_ts_rtc_writebyte(tmp_rtc0, 126);
13739008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter			ts78xx_ts_rtc_writebyte(tmp_rtc1, 127);
138f5273fa3102fa4c25819f3034b8834c37d3e62a3Alexander Clouter
13939008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter			if (ts78xx_fpga.supports.ts_rtc.init == 0) {
140f5273fa3102fa4c25819f3034b8834c37d3e62a3Alexander Clouter				rc = platform_device_register(&ts78xx_ts_rtc_device);
141f5273fa3102fa4c25819f3034b8834c37d3e62a3Alexander Clouter				if (!rc)
142f5273fa3102fa4c25819f3034b8834c37d3e62a3Alexander Clouter					ts78xx_fpga.supports.ts_rtc.init = 1;
14339008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter			} else
144f5273fa3102fa4c25819f3034b8834c37d3e62a3Alexander Clouter				rc = platform_device_add(&ts78xx_ts_rtc_device);
145f5273fa3102fa4c25819f3034b8834c37d3e62a3Alexander Clouter
1464d72cef17bb71a63526b6219bc06b7f31d86dde1Alexander Clouter			if (rc)
1474d72cef17bb71a63526b6219bc06b7f31d86dde1Alexander Clouter				pr_info("RTC could not be registered: %d\n",
1484d72cef17bb71a63526b6219bc06b7f31d86dde1Alexander Clouter					rc);
149f5273fa3102fa4c25819f3034b8834c37d3e62a3Alexander Clouter			return rc;
1507171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter		}
1517171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	}
1527171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter
1534d72cef17bb71a63526b6219bc06b7f31d86dde1Alexander Clouter	pr_info("RTC not found\n");
15439008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	return -ENODEV;
1557171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter};
15639008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
15739008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouterstatic void ts78xx_ts_rtc_unload(void)
15839008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter{
15939008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	platform_device_del(&ts78xx_ts_rtc_device);
16039008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter}
1617171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter
1627171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter/*****************************************************************************
16375bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter * NAND Flash
16475bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter ****************************************************************************/
165ac3524b7f5a6b9a744fb7ea19991355354c09afbAndrew Lunn#define TS_NAND_CTRL	(TS78XX_FPGA_REGS_VIRT_BASE + 0x800)	/* VIRT */
166ac3524b7f5a6b9a744fb7ea19991355354c09afbAndrew Lunn#define TS_NAND_DATA	(TS78XX_FPGA_REGS_PHYS_BASE + 0x804)	/* PHYS */
16775bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter
16875bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter/*
16975bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter * hardware specific access to control-lines
17075bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter *
17175bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter * ctrl:
17275bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter * NAND_NCE: bit 0 -> bit 2
17375bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter * NAND_CLE: bit 1 -> bit 1
17475bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter * NAND_ALE: bit 2 -> bit 0
17575bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter */
17675bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouterstatic void ts78xx_ts_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
17775bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter			unsigned int ctrl)
17875bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter{
17975bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	struct nand_chip *this = mtd->priv;
18075bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter
18175bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	if (ctrl & NAND_CTRL_CHANGE) {
18275bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		unsigned char bits;
18375bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter
18475bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		bits = (ctrl & NAND_NCE) << 2;
18575bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		bits |= ctrl & NAND_CLE;
18675bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		bits |= (ctrl & NAND_ALE) >> 2;
18775bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter
18875bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		writeb((readb(TS_NAND_CTRL) & ~0x7) | bits, TS_NAND_CTRL);
18975bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	}
19075bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter
19175bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	if (cmd != NAND_CMD_NONE)
19275bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		writeb(cmd, this->IO_ADDR_W);
19375bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter}
19475bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter
19575bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouterstatic int ts78xx_ts_nand_dev_ready(struct mtd_info *mtd)
19675bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter{
19775bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	return readb(TS_NAND_CTRL) & 0x20;
19875bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter}
19975bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter
200e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouterstatic void ts78xx_ts_nand_write_buf(struct mtd_info *mtd,
201e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter			const uint8_t *buf, int len)
202e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter{
203e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter	struct nand_chip *chip = mtd->priv;
204e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter	void __iomem *io_base = chip->IO_ADDR_W;
205e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter	unsigned long off = ((unsigned long)buf & 3);
206e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter	int sz;
207e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter
208e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter	if (off) {
20953936c56dcaf1db818fe953ae05592a8b5e345b5Alexander Clouter		sz = min_t(int, 4 - off, len);
210e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter		writesb(io_base, buf, sz);
211e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter		buf += sz;
212e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter		len -= sz;
213e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter	}
214e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter
215e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter	sz = len >> 2;
216e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter	if (sz) {
217e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter		u32 *buf32 = (u32 *)buf;
218e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter		writesl(io_base, buf32, sz);
219e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter		buf += sz << 2;
220e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter		len -= sz << 2;
221e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter	}
222e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter
223e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter	if (len)
224e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter		writesb(io_base, buf, len);
225e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter}
226e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter
227e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouterstatic void ts78xx_ts_nand_read_buf(struct mtd_info *mtd,
228e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter			uint8_t *buf, int len)
229e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter{
230e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter	struct nand_chip *chip = mtd->priv;
231e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter	void __iomem *io_base = chip->IO_ADDR_R;
232e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter	unsigned long off = ((unsigned long)buf & 3);
233e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter	int sz;
234e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter
235e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter	if (off) {
23653936c56dcaf1db818fe953ae05592a8b5e345b5Alexander Clouter		sz = min_t(int, 4 - off, len);
237e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter		readsb(io_base, buf, sz);
238e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter		buf += sz;
239e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter		len -= sz;
240e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter	}
241e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter
242e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter	sz = len >> 2;
243e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter	if (sz) {
244e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter		u32 *buf32 = (u32 *)buf;
245e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter		readsl(io_base, buf32, sz);
246e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter		buf += sz << 2;
247e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter		len -= sz << 2;
248e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter	}
249e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter
250e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter	if (len)
251e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter		readsb(io_base, buf, len);
252e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter}
253e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter
25475bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouterstatic struct mtd_partition ts78xx_ts_nand_parts[] = {
25575bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	{
25675bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		.name		= "mbr",
25775bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		.offset		= 0,
25875bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		.size		= SZ_128K,
25975bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		.mask_flags	= MTD_WRITEABLE,
26075bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	}, {
26175bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		.name		= "kernel",
26275bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		.offset		= MTDPART_OFS_APPEND,
26375bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		.size		= SZ_4M,
26475bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	}, {
26575bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		.name		= "initrd",
26675bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		.offset		= MTDPART_OFS_APPEND,
26775bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		.size		= SZ_4M,
26875bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	}, {
26975bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		.name		= "rootfs",
27075bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		.offset		= MTDPART_OFS_APPEND,
27175bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		.size		= MTDPART_SIZ_FULL,
27275bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	}
27375bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter};
27475bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter
27575bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouterstatic struct platform_nand_data ts78xx_ts_nand_data = {
27675bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	.chip	= {
277ef077179a2909d3d0d3accf29ad1ea9ebb19019bMarek Vasut		.nr_chips		= 1,
27875bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		.partitions		= ts78xx_ts_nand_parts,
27975bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		.nr_partitions		= ARRAY_SIZE(ts78xx_ts_nand_parts),
28075bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		.chip_delay		= 15,
281bb9ebd4e714385a2592a482845865ef2d58b2868Brian Norris		.bbt_options		= NAND_BBT_USE_FLASH,
28275bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	},
28375bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	.ctrl	= {
28475bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		/*
28575bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		 * The HW ECC offloading functions, used to give about a 9%
28675bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		 * performance increase for 'dd if=/dev/mtdblockX' and 5% for
28775bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		 * nanddump.  This all however was changed by git commit
28875bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		 * e6cf5df1838c28bb060ac45b5585e48e71bbc740 so now there is
28975bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		 * no performance advantage to be had so we no longer bother
29075bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		 */
29175bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		.cmd_ctrl		= ts78xx_ts_nand_cmd_ctrl,
29275bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		.dev_ready		= ts78xx_ts_nand_dev_ready,
293e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter		.write_buf		= ts78xx_ts_nand_write_buf,
294e25bac968d41d994e5295f89547bdff6cb40588aAlexander Clouter		.read_buf		= ts78xx_ts_nand_read_buf,
29575bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	},
29675bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter};
29775bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter
298167473a5937f54aaac4c3c01a192a81214933a23Alexander Clouterstatic struct resource ts78xx_ts_nand_resources
299167473a5937f54aaac4c3c01a192a81214933a23Alexander Clouter			= DEFINE_RES_MEM(TS_NAND_DATA, 4);
30075bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter
30175bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouterstatic struct platform_device ts78xx_ts_nand_device = {
30275bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	.name		= "gen_nand",
30375bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	.id		= -1,
30475bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	.dev		= {
30575bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		.platform_data	= &ts78xx_ts_nand_data,
30675bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	},
30775bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	.resource	= &ts78xx_ts_nand_resources,
30875bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	.num_resources	= 1,
30975bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter};
31075bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter
31175bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouterstatic int ts78xx_ts_nand_load(void)
31275bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter{
31375bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	int rc;
31475bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter
31575bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	if (ts78xx_fpga.supports.ts_nand.init == 0) {
31675bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		rc = platform_device_register(&ts78xx_ts_nand_device);
31775bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		if (!rc)
31875bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter			ts78xx_fpga.supports.ts_nand.init = 1;
31975bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	} else
32075bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		rc = platform_device_add(&ts78xx_ts_nand_device);
32175bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter
3224d72cef17bb71a63526b6219bc06b7f31d86dde1Alexander Clouter	if (rc)
3234d72cef17bb71a63526b6219bc06b7f31d86dde1Alexander Clouter		pr_info("NAND could not be registered: %d\n", rc);
32475bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	return rc;
32575bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter};
32675bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter
32775bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouterstatic void ts78xx_ts_nand_unload(void)
32875bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter{
32975bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	platform_device_del(&ts78xx_ts_nand_device);
33075bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter}
33175bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter
33275bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter/*****************************************************************************
333a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter * HW RNG
334a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter ****************************************************************************/
335a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter#define TS_RNG_DATA	(TS78XX_FPGA_REGS_PHYS_BASE | 0x044)
336a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter
337167473a5937f54aaac4c3c01a192a81214933a23Alexander Clouterstatic struct resource ts78xx_ts_rng_resource
338167473a5937f54aaac4c3c01a192a81214933a23Alexander Clouter			= DEFINE_RES_MEM(TS_RNG_DATA, 4);
339a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter
340a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouterstatic struct timeriomem_rng_data ts78xx_ts_rng_data = {
341a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter	.period		= 1000000, /* one second */
342a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter};
343a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter
344a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouterstatic struct platform_device ts78xx_ts_rng_device = {
345a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter	.name		= "timeriomem_rng",
346a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter	.id		= -1,
347a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter	.dev		= {
348a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter		.platform_data	= &ts78xx_ts_rng_data,
349a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter	},
350a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter	.resource	= &ts78xx_ts_rng_resource,
351a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter	.num_resources	= 1,
352a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter};
353a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter
354a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouterstatic int ts78xx_ts_rng_load(void)
355a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter{
356a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter	int rc;
357a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter
358a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter	if (ts78xx_fpga.supports.ts_rng.init == 0) {
359a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter		rc = platform_device_register(&ts78xx_ts_rng_device);
360a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter		if (!rc)
361a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter			ts78xx_fpga.supports.ts_rng.init = 1;
362a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter	} else
363a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter		rc = platform_device_add(&ts78xx_ts_rng_device);
364a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter
3654d72cef17bb71a63526b6219bc06b7f31d86dde1Alexander Clouter	if (rc)
3664d72cef17bb71a63526b6219bc06b7f31d86dde1Alexander Clouter		pr_info("RNG could not be registered: %d\n", rc);
367a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter	return rc;
368a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter};
369a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter
370a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouterstatic void ts78xx_ts_rng_unload(void)
371a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter{
372a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter	platform_device_del(&ts78xx_ts_rng_device);
373a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter}
374a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter
375a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter/*****************************************************************************
37639008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter * FPGA 'hotplug' support code
3777171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter ****************************************************************************/
37839008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouterstatic void ts78xx_fpga_devices_zero_init(void)
37939008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter{
38039008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	ts78xx_fpga.supports.ts_rtc.init = 0;
38175bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	ts78xx_fpga.supports.ts_nand.init = 0;
382a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter	ts78xx_fpga.supports.ts_rng.init = 0;
38339008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter}
38439008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
38539008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouterstatic void ts78xx_fpga_supports(void)
38639008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter{
38739008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	/* TODO: put this 'table' into ts78xx-fpga.h */
38839008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	switch (ts78xx_fpga.id) {
3890c1355e36fdc304b102851312d80a1e69c01f5a2Alexander Clouter	case TS7800_REV_1:
3900c1355e36fdc304b102851312d80a1e69c01f5a2Alexander Clouter	case TS7800_REV_2:
3910c1355e36fdc304b102851312d80a1e69c01f5a2Alexander Clouter	case TS7800_REV_3:
3920c1355e36fdc304b102851312d80a1e69c01f5a2Alexander Clouter	case TS7800_REV_4:
3930c1355e36fdc304b102851312d80a1e69c01f5a2Alexander Clouter	case TS7800_REV_5:
39417718e17a25cc989954a8430985b3133ca21422eAlexander Clouter	case TS7800_REV_6:
39517718e17a25cc989954a8430985b3133ca21422eAlexander Clouter	case TS7800_REV_7:
39617718e17a25cc989954a8430985b3133ca21422eAlexander Clouter	case TS7800_REV_8:
39717718e17a25cc989954a8430985b3133ca21422eAlexander Clouter	case TS7800_REV_9:
39839008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter		ts78xx_fpga.supports.ts_rtc.present = 1;
39975bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		ts78xx_fpga.supports.ts_nand.present = 1;
400a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter		ts78xx_fpga.supports.ts_rng.present = 1;
40139008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter		break;
40239008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	default:
403b3882330843650b751817712db57b9a7061e7879Alexander Clouter		/* enable devices if magic matches */
404b3882330843650b751817712db57b9a7061e7879Alexander Clouter		switch ((ts78xx_fpga.id >> 8) & 0xffffff) {
405b3882330843650b751817712db57b9a7061e7879Alexander Clouter		case TS7800_FPGA_MAGIC:
4069d06d34bcc62f4cc3679704ac42cff5b44a97c6eJoe Perches			pr_warn("unrecognised FPGA revision 0x%.2x\n",
4079d06d34bcc62f4cc3679704ac42cff5b44a97c6eJoe Perches				ts78xx_fpga.id & 0xff);
408b3882330843650b751817712db57b9a7061e7879Alexander Clouter			ts78xx_fpga.supports.ts_rtc.present = 1;
409b3882330843650b751817712db57b9a7061e7879Alexander Clouter			ts78xx_fpga.supports.ts_nand.present = 1;
410b3882330843650b751817712db57b9a7061e7879Alexander Clouter			ts78xx_fpga.supports.ts_rng.present = 1;
411b3882330843650b751817712db57b9a7061e7879Alexander Clouter			break;
412b3882330843650b751817712db57b9a7061e7879Alexander Clouter		default:
413b3882330843650b751817712db57b9a7061e7879Alexander Clouter			ts78xx_fpga.supports.ts_rtc.present = 0;
414b3882330843650b751817712db57b9a7061e7879Alexander Clouter			ts78xx_fpga.supports.ts_nand.present = 0;
415b3882330843650b751817712db57b9a7061e7879Alexander Clouter			ts78xx_fpga.supports.ts_rng.present = 0;
416b3882330843650b751817712db57b9a7061e7879Alexander Clouter		}
41739008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	}
41839008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter}
41939008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
42039008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouterstatic int ts78xx_fpga_load_devices(void)
42139008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter{
42239008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	int tmp, ret = 0;
42339008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
42439008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	if (ts78xx_fpga.supports.ts_rtc.present == 1) {
42539008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter		tmp = ts78xx_ts_rtc_load();
4264d72cef17bb71a63526b6219bc06b7f31d86dde1Alexander Clouter		if (tmp)
427f5273fa3102fa4c25819f3034b8834c37d3e62a3Alexander Clouter			ts78xx_fpga.supports.ts_rtc.present = 0;
42839008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter		ret |= tmp;
42939008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	}
43075bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	if (ts78xx_fpga.supports.ts_nand.present == 1) {
43175bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		tmp = ts78xx_ts_nand_load();
4324d72cef17bb71a63526b6219bc06b7f31d86dde1Alexander Clouter		if (tmp)
43375bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter			ts78xx_fpga.supports.ts_nand.present = 0;
43475bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		ret |= tmp;
43575bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	}
436a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter	if (ts78xx_fpga.supports.ts_rng.present == 1) {
437a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter		tmp = ts78xx_ts_rng_load();
4384d72cef17bb71a63526b6219bc06b7f31d86dde1Alexander Clouter		if (tmp)
439a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter			ts78xx_fpga.supports.ts_rng.present = 0;
440a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter		ret |= tmp;
441a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter	}
44239008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
44339008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	return ret;
44439008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter}
44539008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
44639008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouterstatic int ts78xx_fpga_unload_devices(void)
44739008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter{
44839008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	int ret = 0;
44939008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
45039008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	if (ts78xx_fpga.supports.ts_rtc.present == 1)
45139008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter		ts78xx_ts_rtc_unload();
45275bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter	if (ts78xx_fpga.supports.ts_nand.present == 1)
45375bb6b9aab3255f440ef4e72a31978d1681105d6Alexander Clouter		ts78xx_ts_nand_unload();
454a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter	if (ts78xx_fpga.supports.ts_rng.present == 1)
455a914d4309c4cf6e7c4d0dbce4822dcad38a7cf27Alexander Clouter		ts78xx_ts_rng_unload();
45639008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
45739008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	return ret;
45839008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter}
45939008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
46039008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouterstatic int ts78xx_fpga_load(void)
46139008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter{
46239008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	ts78xx_fpga.id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
46339008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
4644d72cef17bb71a63526b6219bc06b7f31d86dde1Alexander Clouter	pr_info("FPGA magic=0x%.6x, rev=0x%.2x\n",
46539008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter			(ts78xx_fpga.id >> 8) & 0xffffff,
46639008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter			ts78xx_fpga.id & 0xff);
46739008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
46839008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	ts78xx_fpga_supports();
46939008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
47039008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	if (ts78xx_fpga_load_devices()) {
47139008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter		ts78xx_fpga.state = -1;
47239008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter		return -EBUSY;
47339008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	}
47439008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
47539008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	return 0;
4767171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter};
4777171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter
47839008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouterstatic int ts78xx_fpga_unload(void)
47939008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter{
48039008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	unsigned int fpga_id;
48139008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
48239008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	fpga_id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
48339008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
48439008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	/*
48539008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	 * There does not seem to be a feasible way to block access to the GPIO
48639008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	 * pins from userspace (/dev/mem).  This if clause should hopefully warn
48739008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	 * those foolish enough not to follow 'policy' :)
48839008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	 *
48939008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	 * UrJTAG SVN since r1381 can be used to reprogram the FPGA
49039008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	 */
49139008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	if (ts78xx_fpga.id != fpga_id) {
4924d72cef17bb71a63526b6219bc06b7f31d86dde1Alexander Clouter		pr_err("FPGA magic/rev mismatch\n"
49339008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter			"TS-78xx FPGA: was 0x%.6x/%.2x but now 0x%.6x/%.2x\n",
49439008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter			(ts78xx_fpga.id >> 8) & 0xffffff, ts78xx_fpga.id & 0xff,
49539008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter			(fpga_id >> 8) & 0xffffff, fpga_id & 0xff);
49639008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter		ts78xx_fpga.state = -1;
49739008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter		return -EBUSY;
49839008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	}
49939008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
50039008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	if (ts78xx_fpga_unload_devices()) {
50139008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter		ts78xx_fpga.state = -1;
50239008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter		return -EBUSY;
50339008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	}
50439008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
50539008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	return 0;
5067171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter};
5077171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter
50839008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouterstatic ssize_t ts78xx_fpga_show(struct kobject *kobj,
50939008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter			struct kobj_attribute *attr, char *buf)
51039008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter{
51139008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	if (ts78xx_fpga.state < 0)
51239008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter		return sprintf(buf, "borked\n");
51339008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
51439008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	return sprintf(buf, "%s\n", (ts78xx_fpga.state) ? "online" : "offline");
51539008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter}
51639008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
51739008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouterstatic ssize_t ts78xx_fpga_store(struct kobject *kobj,
51839008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter			struct kobj_attribute *attr, const char *buf, size_t n)
51939008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter{
52039008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	int value, ret;
52139008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
52239008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	if (ts78xx_fpga.state < 0) {
5234d72cef17bb71a63526b6219bc06b7f31d86dde1Alexander Clouter		pr_err("FPGA borked, you must powercycle ASAP\n");
52439008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter		return -EBUSY;
52539008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	}
52639008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
52739008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	if (strncmp(buf, "online", sizeof("online") - 1) == 0)
52839008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter		value = 1;
52939008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
53039008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter		value = 0;
5314d72cef17bb71a63526b6219bc06b7f31d86dde1Alexander Clouter	else
53239008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter		return -EINVAL;
53339008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
53439008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	if (ts78xx_fpga.state == value)
53539008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter		return n;
53639008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
53739008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	ret = (ts78xx_fpga.state == 0)
53839008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter		? ts78xx_fpga_load()
53939008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter		: ts78xx_fpga_unload();
54039008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
54139008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	if (!(ret < 0))
54239008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter		ts78xx_fpga.state = value;
54339008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
54439008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	return n;
54539008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter}
54639008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
54739008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouterstatic struct kobj_attribute ts78xx_fpga_attr =
54839008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	__ATTR(ts78xx_fpga, 0644, ts78xx_fpga_show, ts78xx_fpga_store);
54939008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
5507171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter/*****************************************************************************
5517171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter * General Setup
5527171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter ****************************************************************************/
553554cdaefd1cf7bb54b209c4e68c7cec87ce442a9Andrew Lunnstatic unsigned int ts78xx_mpp_modes[] __initdata = {
554554cdaefd1cf7bb54b209c4e68c7cec87ce442a9Andrew Lunn	MPP0_UNUSED,
555554cdaefd1cf7bb54b209c4e68c7cec87ce442a9Andrew Lunn	MPP1_GPIO,		/* JTAG Clock */
556554cdaefd1cf7bb54b209c4e68c7cec87ce442a9Andrew Lunn	MPP2_GPIO,		/* JTAG Data In */
557554cdaefd1cf7bb54b209c4e68c7cec87ce442a9Andrew Lunn	MPP3_GPIO,		/* Lat ECP2 256 FPGA - PB2B */
558554cdaefd1cf7bb54b209c4e68c7cec87ce442a9Andrew Lunn	MPP4_GPIO,		/* JTAG Data Out */
559554cdaefd1cf7bb54b209c4e68c7cec87ce442a9Andrew Lunn	MPP5_GPIO,		/* JTAG TMS */
560554cdaefd1cf7bb54b209c4e68c7cec87ce442a9Andrew Lunn	MPP6_GPIO,		/* Lat ECP2 256 FPGA - PB31A_CLK4+ */
561554cdaefd1cf7bb54b209c4e68c7cec87ce442a9Andrew Lunn	MPP7_GPIO,		/* Lat ECP2 256 FPGA - PB22B */
562554cdaefd1cf7bb54b209c4e68c7cec87ce442a9Andrew Lunn	MPP8_UNUSED,
563554cdaefd1cf7bb54b209c4e68c7cec87ce442a9Andrew Lunn	MPP9_UNUSED,
564554cdaefd1cf7bb54b209c4e68c7cec87ce442a9Andrew Lunn	MPP10_UNUSED,
565554cdaefd1cf7bb54b209c4e68c7cec87ce442a9Andrew Lunn	MPP11_UNUSED,
566554cdaefd1cf7bb54b209c4e68c7cec87ce442a9Andrew Lunn	MPP12_UNUSED,
567554cdaefd1cf7bb54b209c4e68c7cec87ce442a9Andrew Lunn	MPP13_UNUSED,
568554cdaefd1cf7bb54b209c4e68c7cec87ce442a9Andrew Lunn	MPP14_UNUSED,
569554cdaefd1cf7bb54b209c4e68c7cec87ce442a9Andrew Lunn	MPP15_UNUSED,
570554cdaefd1cf7bb54b209c4e68c7cec87ce442a9Andrew Lunn	MPP16_UART,
571554cdaefd1cf7bb54b209c4e68c7cec87ce442a9Andrew Lunn	MPP17_UART,
572554cdaefd1cf7bb54b209c4e68c7cec87ce442a9Andrew Lunn	MPP18_UART,
573554cdaefd1cf7bb54b209c4e68c7cec87ce442a9Andrew Lunn	MPP19_UART,
574f54128609c4e7792fb52b03c3db0da78627ce607Alexander Clouter	/*
575f54128609c4e7792fb52b03c3db0da78627ce607Alexander Clouter	 * MPP[20] PCI Clock Out 1
576f54128609c4e7792fb52b03c3db0da78627ce607Alexander Clouter	 * MPP[21] PCI Clock Out 0
577f54128609c4e7792fb52b03c3db0da78627ce607Alexander Clouter	 * MPP[22] Unused
578f54128609c4e7792fb52b03c3db0da78627ce607Alexander Clouter	 * MPP[23] Unused
579f54128609c4e7792fb52b03c3db0da78627ce607Alexander Clouter	 * MPP[24] Unused
580f54128609c4e7792fb52b03c3db0da78627ce607Alexander Clouter	 * MPP[25] Unused
581f54128609c4e7792fb52b03c3db0da78627ce607Alexander Clouter	 */
582554cdaefd1cf7bb54b209c4e68c7cec87ce442a9Andrew Lunn	0,
5837171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter};
5847171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter
5857171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouterstatic void __init ts78xx_init(void)
5867171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter{
58739008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	int ret;
58839008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter
5897171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	/*
5907171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	 * Setup basic Orion functions. Need to be called early.
5917171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	 */
5927171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	orion5x_init();
5937171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter
5947171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	orion5x_mpp_conf(ts78xx_mpp_modes);
5957171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter
5967171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	/*
5977171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	 * Configure peripherals.
5987171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	 */
5997171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	orion5x_ehci0_init();
6007171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	orion5x_ehci1_init();
6017171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	orion5x_eth_init(&ts78xx_eth_data);
6027171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	orion5x_sata_init(&ts78xx_sata_data);
6037171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	orion5x_uart0_init();
6047171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	orion5x_uart1_init();
6051d5a1a6e92abb1ecb011a673e637146c4e232f1eSaeed Bishara	orion5x_xor_init();
6067171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter
60739008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	/* FPGA init */
60839008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	ts78xx_fpga_devices_zero_init();
60939008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	ret = ts78xx_fpga_load();
6104f8cf6106dcf77b9b60af23cbb35fd537b1c9c1dAlexander Clouter	ret = sysfs_create_file(firmware_kobj, &ts78xx_fpga_attr.attr);
61139008f959f4f3b60eecc5cec0ca077146c1f366bAlexander Clouter	if (ret)
6127bcdca95c039d1cd1cfddd6aa012026b409ddb14Alexander Clouter		pr_err("sysfs_create_file failed: %d\n", ret);
6137171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter}
6147171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter
6157171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander ClouterMACHINE_START(TS78XX, "Technologic Systems TS-78xx SBC")
6167171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	/* Maintainer: Alexander Clouter <alex@digriz.org.uk> */
61765aa1b1ea499a75c9920c1ebadacec0a0b8a79a6Nicolas Pitre	.atag_offset	= 0x100,
6187171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	.init_machine	= ts78xx_init,
6197171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	.map_io		= ts78xx_map_io,
6204ee1f6b574765a6c97f945e6b0277e5ccac38cb5Lennert Buytenhek	.init_early	= orion5x_init_early,
6217171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander Clouter	.init_irq	= orion5x_init_irq,
6226bb27d7349db51b50c40534710fe164ca0d58902Stephen Warren	.init_time	= orion5x_timer_init,
623764cbcc2e3fa444c205b20b3d7908b06b60716abRussell King	.restart	= orion5x_restart,
6247171d8672bb0bcb744935bd2c6108378b5c6c6adAlexander ClouterMACHINE_END
625