162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * arch/arm/mach-orion5x/ts78xx-setup.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Maintainer: Alexander Clouter <alex@digriz.org.uk>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/init.h>
1262306a36Sopenharmony_ci#include <linux/sysfs.h>
1362306a36Sopenharmony_ci#include <linux/platform_device.h>
1462306a36Sopenharmony_ci#include <linux/mv643xx_eth.h>
1562306a36Sopenharmony_ci#include <linux/ata_platform.h>
1662306a36Sopenharmony_ci#include <linux/mtd/platnand.h>
1762306a36Sopenharmony_ci#include <linux/timeriomem-rng.h>
1862306a36Sopenharmony_ci#include <asm/mach-types.h>
1962306a36Sopenharmony_ci#include <asm/mach/arch.h>
2062306a36Sopenharmony_ci#include <asm/mach/map.h>
2162306a36Sopenharmony_ci#include "common.h"
2262306a36Sopenharmony_ci#include "mpp.h"
2362306a36Sopenharmony_ci#include "orion5x.h"
2462306a36Sopenharmony_ci#include "ts78xx-fpga.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/*****************************************************************************
2762306a36Sopenharmony_ci * TS-78xx Info
2862306a36Sopenharmony_ci ****************************************************************************/
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/*
3162306a36Sopenharmony_ci * FPGA - lives where the PCI bus would be at ORION5X_PCI_MEM_PHYS_BASE
3262306a36Sopenharmony_ci */
3362306a36Sopenharmony_ci#define TS78XX_FPGA_REGS_PHYS_BASE	0xe8000000
3462306a36Sopenharmony_ci#define TS78XX_FPGA_REGS_VIRT_BASE	IOMEM(0xff900000)
3562306a36Sopenharmony_ci#define TS78XX_FPGA_REGS_SIZE		SZ_1M
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic struct ts78xx_fpga_data ts78xx_fpga = {
3862306a36Sopenharmony_ci	.id		= 0,
3962306a36Sopenharmony_ci	.state		= 1,
4062306a36Sopenharmony_ci/*	.supports	= ... - populated by ts78xx_fpga_supports() */
4162306a36Sopenharmony_ci};
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/*****************************************************************************
4462306a36Sopenharmony_ci * I/O Address Mapping
4562306a36Sopenharmony_ci ****************************************************************************/
4662306a36Sopenharmony_cistatic struct map_desc ts78xx_io_desc[] __initdata = {
4762306a36Sopenharmony_ci	{
4862306a36Sopenharmony_ci		.virtual	= (unsigned long)TS78XX_FPGA_REGS_VIRT_BASE,
4962306a36Sopenharmony_ci		.pfn		= __phys_to_pfn(TS78XX_FPGA_REGS_PHYS_BASE),
5062306a36Sopenharmony_ci		.length		= TS78XX_FPGA_REGS_SIZE,
5162306a36Sopenharmony_ci		.type		= MT_DEVICE,
5262306a36Sopenharmony_ci	},
5362306a36Sopenharmony_ci};
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic void __init ts78xx_map_io(void)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	orion5x_map_io();
5862306a36Sopenharmony_ci	iotable_init(ts78xx_io_desc, ARRAY_SIZE(ts78xx_io_desc));
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci/*****************************************************************************
6262306a36Sopenharmony_ci * Ethernet
6362306a36Sopenharmony_ci ****************************************************************************/
6462306a36Sopenharmony_cistatic struct mv643xx_eth_platform_data ts78xx_eth_data = {
6562306a36Sopenharmony_ci	.phy_addr	= MV643XX_ETH_PHY_ADDR(0),
6662306a36Sopenharmony_ci};
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/*****************************************************************************
6962306a36Sopenharmony_ci * SATA
7062306a36Sopenharmony_ci ****************************************************************************/
7162306a36Sopenharmony_cistatic struct mv_sata_platform_data ts78xx_sata_data = {
7262306a36Sopenharmony_ci	.n_ports	= 2,
7362306a36Sopenharmony_ci};
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci/*****************************************************************************
7662306a36Sopenharmony_ci * RTC M48T86 - nicked^Wborrowed from arch/arm/mach-ep93xx/ts72xx.c
7762306a36Sopenharmony_ci ****************************************************************************/
7862306a36Sopenharmony_ci#define TS_RTC_CTRL	(TS78XX_FPGA_REGS_PHYS_BASE + 0x808)
7962306a36Sopenharmony_ci#define TS_RTC_DATA	(TS78XX_FPGA_REGS_PHYS_BASE + 0x80c)
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic struct resource ts78xx_ts_rtc_resources[] = {
8262306a36Sopenharmony_ci	DEFINE_RES_MEM(TS_RTC_CTRL, 0x01),
8362306a36Sopenharmony_ci	DEFINE_RES_MEM(TS_RTC_DATA, 0x01),
8462306a36Sopenharmony_ci};
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic struct platform_device ts78xx_ts_rtc_device = {
8762306a36Sopenharmony_ci	.name		= "rtc-m48t86",
8862306a36Sopenharmony_ci	.id		= -1,
8962306a36Sopenharmony_ci	.resource	= ts78xx_ts_rtc_resources,
9062306a36Sopenharmony_ci	.num_resources 	= ARRAY_SIZE(ts78xx_ts_rtc_resources),
9162306a36Sopenharmony_ci};
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic int ts78xx_ts_rtc_load(void)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	int rc;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	if (ts78xx_fpga.supports.ts_rtc.init == 0) {
9862306a36Sopenharmony_ci		rc = platform_device_register(&ts78xx_ts_rtc_device);
9962306a36Sopenharmony_ci		if (!rc)
10062306a36Sopenharmony_ci			ts78xx_fpga.supports.ts_rtc.init = 1;
10162306a36Sopenharmony_ci	} else {
10262306a36Sopenharmony_ci		rc = platform_device_add(&ts78xx_ts_rtc_device);
10362306a36Sopenharmony_ci	}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (rc)
10662306a36Sopenharmony_ci		pr_info("RTC could not be registered: %d\n", rc);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	return rc;
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic void ts78xx_ts_rtc_unload(void)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	platform_device_del(&ts78xx_ts_rtc_device);
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci/*****************************************************************************
11762306a36Sopenharmony_ci * NAND Flash
11862306a36Sopenharmony_ci ****************************************************************************/
11962306a36Sopenharmony_ci#define TS_NAND_CTRL	(TS78XX_FPGA_REGS_VIRT_BASE + 0x800)	/* VIRT */
12062306a36Sopenharmony_ci#define TS_NAND_DATA	(TS78XX_FPGA_REGS_PHYS_BASE + 0x804)	/* PHYS */
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci/*
12362306a36Sopenharmony_ci * hardware specific access to control-lines
12462306a36Sopenharmony_ci *
12562306a36Sopenharmony_ci * ctrl:
12662306a36Sopenharmony_ci * NAND_NCE: bit 0 -> bit 2
12762306a36Sopenharmony_ci * NAND_CLE: bit 1 -> bit 1
12862306a36Sopenharmony_ci * NAND_ALE: bit 2 -> bit 0
12962306a36Sopenharmony_ci */
13062306a36Sopenharmony_cistatic void ts78xx_ts_nand_cmd_ctrl(struct nand_chip *this, int cmd,
13162306a36Sopenharmony_ci				    unsigned int ctrl)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	if (ctrl & NAND_CTRL_CHANGE) {
13462306a36Sopenharmony_ci		unsigned char bits;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci		bits = (ctrl & NAND_NCE) << 2;
13762306a36Sopenharmony_ci		bits |= ctrl & NAND_CLE;
13862306a36Sopenharmony_ci		bits |= (ctrl & NAND_ALE) >> 2;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci		writeb((readb(TS_NAND_CTRL) & ~0x7) | bits, TS_NAND_CTRL);
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	if (cmd != NAND_CMD_NONE)
14462306a36Sopenharmony_ci		writeb(cmd, this->legacy.IO_ADDR_W);
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic int ts78xx_ts_nand_dev_ready(struct nand_chip *chip)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	return readb(TS_NAND_CTRL) & 0x20;
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic void ts78xx_ts_nand_write_buf(struct nand_chip *chip,
15362306a36Sopenharmony_ci				     const uint8_t *buf, int len)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	void __iomem *io_base = chip->legacy.IO_ADDR_W;
15662306a36Sopenharmony_ci	unsigned long off = ((unsigned long)buf & 3);
15762306a36Sopenharmony_ci	int sz;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	if (off) {
16062306a36Sopenharmony_ci		sz = min_t(int, 4 - off, len);
16162306a36Sopenharmony_ci		writesb(io_base, buf, sz);
16262306a36Sopenharmony_ci		buf += sz;
16362306a36Sopenharmony_ci		len -= sz;
16462306a36Sopenharmony_ci	}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	sz = len >> 2;
16762306a36Sopenharmony_ci	if (sz) {
16862306a36Sopenharmony_ci		u32 *buf32 = (u32 *)buf;
16962306a36Sopenharmony_ci		writesl(io_base, buf32, sz);
17062306a36Sopenharmony_ci		buf += sz << 2;
17162306a36Sopenharmony_ci		len -= sz << 2;
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	if (len)
17562306a36Sopenharmony_ci		writesb(io_base, buf, len);
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic void ts78xx_ts_nand_read_buf(struct nand_chip *chip,
17962306a36Sopenharmony_ci				    uint8_t *buf, int len)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	void __iomem *io_base = chip->legacy.IO_ADDR_R;
18262306a36Sopenharmony_ci	unsigned long off = ((unsigned long)buf & 3);
18362306a36Sopenharmony_ci	int sz;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (off) {
18662306a36Sopenharmony_ci		sz = min_t(int, 4 - off, len);
18762306a36Sopenharmony_ci		readsb(io_base, buf, sz);
18862306a36Sopenharmony_ci		buf += sz;
18962306a36Sopenharmony_ci		len -= sz;
19062306a36Sopenharmony_ci	}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	sz = len >> 2;
19362306a36Sopenharmony_ci	if (sz) {
19462306a36Sopenharmony_ci		u32 *buf32 = (u32 *)buf;
19562306a36Sopenharmony_ci		readsl(io_base, buf32, sz);
19662306a36Sopenharmony_ci		buf += sz << 2;
19762306a36Sopenharmony_ci		len -= sz << 2;
19862306a36Sopenharmony_ci	}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	if (len)
20162306a36Sopenharmony_ci		readsb(io_base, buf, len);
20262306a36Sopenharmony_ci}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistatic struct mtd_partition ts78xx_ts_nand_parts[] = {
20562306a36Sopenharmony_ci	{
20662306a36Sopenharmony_ci		.name		= "mbr",
20762306a36Sopenharmony_ci		.offset		= 0,
20862306a36Sopenharmony_ci		.size		= SZ_128K,
20962306a36Sopenharmony_ci		.mask_flags	= MTD_WRITEABLE,
21062306a36Sopenharmony_ci	}, {
21162306a36Sopenharmony_ci		.name		= "kernel",
21262306a36Sopenharmony_ci		.offset		= MTDPART_OFS_APPEND,
21362306a36Sopenharmony_ci		.size		= SZ_4M,
21462306a36Sopenharmony_ci	}, {
21562306a36Sopenharmony_ci		.name		= "initrd",
21662306a36Sopenharmony_ci		.offset		= MTDPART_OFS_APPEND,
21762306a36Sopenharmony_ci		.size		= SZ_4M,
21862306a36Sopenharmony_ci	}, {
21962306a36Sopenharmony_ci		.name		= "rootfs",
22062306a36Sopenharmony_ci		.offset		= MTDPART_OFS_APPEND,
22162306a36Sopenharmony_ci		.size		= MTDPART_SIZ_FULL,
22262306a36Sopenharmony_ci	}
22362306a36Sopenharmony_ci};
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic struct platform_nand_data ts78xx_ts_nand_data = {
22662306a36Sopenharmony_ci	.chip	= {
22762306a36Sopenharmony_ci		.nr_chips		= 1,
22862306a36Sopenharmony_ci		.partitions		= ts78xx_ts_nand_parts,
22962306a36Sopenharmony_ci		.nr_partitions		= ARRAY_SIZE(ts78xx_ts_nand_parts),
23062306a36Sopenharmony_ci		.chip_delay		= 15,
23162306a36Sopenharmony_ci		.bbt_options		= NAND_BBT_USE_FLASH,
23262306a36Sopenharmony_ci	},
23362306a36Sopenharmony_ci	.ctrl	= {
23462306a36Sopenharmony_ci		/*
23562306a36Sopenharmony_ci		 * The HW ECC offloading functions, used to give about a 9%
23662306a36Sopenharmony_ci		 * performance increase for 'dd if=/dev/mtdblockX' and 5% for
23762306a36Sopenharmony_ci		 * nanddump.  This all however was changed by git commit
23862306a36Sopenharmony_ci		 * e6cf5df1838c28bb060ac45b5585e48e71bbc740 so now there is
23962306a36Sopenharmony_ci		 * no performance advantage to be had so we no longer bother
24062306a36Sopenharmony_ci		 */
24162306a36Sopenharmony_ci		.cmd_ctrl		= ts78xx_ts_nand_cmd_ctrl,
24262306a36Sopenharmony_ci		.dev_ready		= ts78xx_ts_nand_dev_ready,
24362306a36Sopenharmony_ci		.write_buf		= ts78xx_ts_nand_write_buf,
24462306a36Sopenharmony_ci		.read_buf		= ts78xx_ts_nand_read_buf,
24562306a36Sopenharmony_ci	},
24662306a36Sopenharmony_ci};
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic struct resource ts78xx_ts_nand_resources
24962306a36Sopenharmony_ci			= DEFINE_RES_MEM(TS_NAND_DATA, 4);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic struct platform_device ts78xx_ts_nand_device = {
25262306a36Sopenharmony_ci	.name		= "gen_nand",
25362306a36Sopenharmony_ci	.id		= -1,
25462306a36Sopenharmony_ci	.dev		= {
25562306a36Sopenharmony_ci		.platform_data	= &ts78xx_ts_nand_data,
25662306a36Sopenharmony_ci	},
25762306a36Sopenharmony_ci	.resource	= &ts78xx_ts_nand_resources,
25862306a36Sopenharmony_ci	.num_resources	= 1,
25962306a36Sopenharmony_ci};
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic int ts78xx_ts_nand_load(void)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	int rc;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	if (ts78xx_fpga.supports.ts_nand.init == 0) {
26662306a36Sopenharmony_ci		rc = platform_device_register(&ts78xx_ts_nand_device);
26762306a36Sopenharmony_ci		if (!rc)
26862306a36Sopenharmony_ci			ts78xx_fpga.supports.ts_nand.init = 1;
26962306a36Sopenharmony_ci	} else
27062306a36Sopenharmony_ci		rc = platform_device_add(&ts78xx_ts_nand_device);
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	if (rc)
27362306a36Sopenharmony_ci		pr_info("NAND could not be registered: %d\n", rc);
27462306a36Sopenharmony_ci	return rc;
27562306a36Sopenharmony_ci};
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cistatic void ts78xx_ts_nand_unload(void)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	platform_device_del(&ts78xx_ts_nand_device);
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci/*****************************************************************************
28362306a36Sopenharmony_ci * HW RNG
28462306a36Sopenharmony_ci ****************************************************************************/
28562306a36Sopenharmony_ci#define TS_RNG_DATA	(TS78XX_FPGA_REGS_PHYS_BASE | 0x044)
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_cistatic struct resource ts78xx_ts_rng_resource
28862306a36Sopenharmony_ci			= DEFINE_RES_MEM(TS_RNG_DATA, 4);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistatic struct timeriomem_rng_data ts78xx_ts_rng_data = {
29162306a36Sopenharmony_ci	.period		= 1000000, /* one second */
29262306a36Sopenharmony_ci};
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic struct platform_device ts78xx_ts_rng_device = {
29562306a36Sopenharmony_ci	.name		= "timeriomem_rng",
29662306a36Sopenharmony_ci	.id		= -1,
29762306a36Sopenharmony_ci	.dev		= {
29862306a36Sopenharmony_ci		.platform_data	= &ts78xx_ts_rng_data,
29962306a36Sopenharmony_ci	},
30062306a36Sopenharmony_ci	.resource	= &ts78xx_ts_rng_resource,
30162306a36Sopenharmony_ci	.num_resources	= 1,
30262306a36Sopenharmony_ci};
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic int ts78xx_ts_rng_load(void)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	int rc;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	if (ts78xx_fpga.supports.ts_rng.init == 0) {
30962306a36Sopenharmony_ci		rc = platform_device_register(&ts78xx_ts_rng_device);
31062306a36Sopenharmony_ci		if (!rc)
31162306a36Sopenharmony_ci			ts78xx_fpga.supports.ts_rng.init = 1;
31262306a36Sopenharmony_ci	} else
31362306a36Sopenharmony_ci		rc = platform_device_add(&ts78xx_ts_rng_device);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	if (rc)
31662306a36Sopenharmony_ci		pr_info("RNG could not be registered: %d\n", rc);
31762306a36Sopenharmony_ci	return rc;
31862306a36Sopenharmony_ci};
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_cistatic void ts78xx_ts_rng_unload(void)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	platform_device_del(&ts78xx_ts_rng_device);
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci/*****************************************************************************
32662306a36Sopenharmony_ci * FPGA 'hotplug' support code
32762306a36Sopenharmony_ci ****************************************************************************/
32862306a36Sopenharmony_cistatic void ts78xx_fpga_devices_zero_init(void)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	ts78xx_fpga.supports.ts_rtc.init = 0;
33162306a36Sopenharmony_ci	ts78xx_fpga.supports.ts_nand.init = 0;
33262306a36Sopenharmony_ci	ts78xx_fpga.supports.ts_rng.init = 0;
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic void ts78xx_fpga_supports(void)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	/* TODO: put this 'table' into ts78xx-fpga.h */
33862306a36Sopenharmony_ci	switch (ts78xx_fpga.id) {
33962306a36Sopenharmony_ci	case TS7800_REV_1:
34062306a36Sopenharmony_ci	case TS7800_REV_2:
34162306a36Sopenharmony_ci	case TS7800_REV_3:
34262306a36Sopenharmony_ci	case TS7800_REV_4:
34362306a36Sopenharmony_ci	case TS7800_REV_5:
34462306a36Sopenharmony_ci	case TS7800_REV_6:
34562306a36Sopenharmony_ci	case TS7800_REV_7:
34662306a36Sopenharmony_ci	case TS7800_REV_8:
34762306a36Sopenharmony_ci	case TS7800_REV_9:
34862306a36Sopenharmony_ci		ts78xx_fpga.supports.ts_rtc.present = 1;
34962306a36Sopenharmony_ci		ts78xx_fpga.supports.ts_nand.present = 1;
35062306a36Sopenharmony_ci		ts78xx_fpga.supports.ts_rng.present = 1;
35162306a36Sopenharmony_ci		break;
35262306a36Sopenharmony_ci	default:
35362306a36Sopenharmony_ci		/* enable devices if magic matches */
35462306a36Sopenharmony_ci		switch ((ts78xx_fpga.id >> 8) & 0xffffff) {
35562306a36Sopenharmony_ci		case TS7800_FPGA_MAGIC:
35662306a36Sopenharmony_ci			pr_warn("unrecognised FPGA revision 0x%.2x\n",
35762306a36Sopenharmony_ci				ts78xx_fpga.id & 0xff);
35862306a36Sopenharmony_ci			ts78xx_fpga.supports.ts_rtc.present = 1;
35962306a36Sopenharmony_ci			ts78xx_fpga.supports.ts_nand.present = 1;
36062306a36Sopenharmony_ci			ts78xx_fpga.supports.ts_rng.present = 1;
36162306a36Sopenharmony_ci			break;
36262306a36Sopenharmony_ci		default:
36362306a36Sopenharmony_ci			ts78xx_fpga.supports.ts_rtc.present = 0;
36462306a36Sopenharmony_ci			ts78xx_fpga.supports.ts_nand.present = 0;
36562306a36Sopenharmony_ci			ts78xx_fpga.supports.ts_rng.present = 0;
36662306a36Sopenharmony_ci		}
36762306a36Sopenharmony_ci	}
36862306a36Sopenharmony_ci}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_cistatic int ts78xx_fpga_load_devices(void)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	int tmp, ret = 0;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	if (ts78xx_fpga.supports.ts_rtc.present == 1) {
37562306a36Sopenharmony_ci		tmp = ts78xx_ts_rtc_load();
37662306a36Sopenharmony_ci		if (tmp)
37762306a36Sopenharmony_ci			ts78xx_fpga.supports.ts_rtc.present = 0;
37862306a36Sopenharmony_ci		ret |= tmp;
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci	if (ts78xx_fpga.supports.ts_nand.present == 1) {
38162306a36Sopenharmony_ci		tmp = ts78xx_ts_nand_load();
38262306a36Sopenharmony_ci		if (tmp)
38362306a36Sopenharmony_ci			ts78xx_fpga.supports.ts_nand.present = 0;
38462306a36Sopenharmony_ci		ret |= tmp;
38562306a36Sopenharmony_ci	}
38662306a36Sopenharmony_ci	if (ts78xx_fpga.supports.ts_rng.present == 1) {
38762306a36Sopenharmony_ci		tmp = ts78xx_ts_rng_load();
38862306a36Sopenharmony_ci		if (tmp)
38962306a36Sopenharmony_ci			ts78xx_fpga.supports.ts_rng.present = 0;
39062306a36Sopenharmony_ci		ret |= tmp;
39162306a36Sopenharmony_ci	}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	return ret;
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_cistatic int ts78xx_fpga_unload_devices(void)
39762306a36Sopenharmony_ci{
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	if (ts78xx_fpga.supports.ts_rtc.present == 1)
40062306a36Sopenharmony_ci		ts78xx_ts_rtc_unload();
40162306a36Sopenharmony_ci	if (ts78xx_fpga.supports.ts_nand.present == 1)
40262306a36Sopenharmony_ci		ts78xx_ts_nand_unload();
40362306a36Sopenharmony_ci	if (ts78xx_fpga.supports.ts_rng.present == 1)
40462306a36Sopenharmony_ci		ts78xx_ts_rng_unload();
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	return 0;
40762306a36Sopenharmony_ci}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_cistatic int ts78xx_fpga_load(void)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci	ts78xx_fpga.id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	pr_info("FPGA magic=0x%.6x, rev=0x%.2x\n",
41462306a36Sopenharmony_ci			(ts78xx_fpga.id >> 8) & 0xffffff,
41562306a36Sopenharmony_ci			ts78xx_fpga.id & 0xff);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	ts78xx_fpga_supports();
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	if (ts78xx_fpga_load_devices()) {
42062306a36Sopenharmony_ci		ts78xx_fpga.state = -1;
42162306a36Sopenharmony_ci		return -EBUSY;
42262306a36Sopenharmony_ci	}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	return 0;
42562306a36Sopenharmony_ci};
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_cistatic int ts78xx_fpga_unload(void)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	unsigned int fpga_id;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	fpga_id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	/*
43462306a36Sopenharmony_ci	 * There does not seem to be a feasible way to block access to the GPIO
43562306a36Sopenharmony_ci	 * pins from userspace (/dev/mem).  This if clause should hopefully warn
43662306a36Sopenharmony_ci	 * those foolish enough not to follow 'policy' :)
43762306a36Sopenharmony_ci	 *
43862306a36Sopenharmony_ci	 * UrJTAG SVN since r1381 can be used to reprogram the FPGA
43962306a36Sopenharmony_ci	 */
44062306a36Sopenharmony_ci	if (ts78xx_fpga.id != fpga_id) {
44162306a36Sopenharmony_ci		pr_err("FPGA magic/rev mismatch\n"
44262306a36Sopenharmony_ci			"TS-78xx FPGA: was 0x%.6x/%.2x but now 0x%.6x/%.2x\n",
44362306a36Sopenharmony_ci			(ts78xx_fpga.id >> 8) & 0xffffff, ts78xx_fpga.id & 0xff,
44462306a36Sopenharmony_ci			(fpga_id >> 8) & 0xffffff, fpga_id & 0xff);
44562306a36Sopenharmony_ci		ts78xx_fpga.state = -1;
44662306a36Sopenharmony_ci		return -EBUSY;
44762306a36Sopenharmony_ci	}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	if (ts78xx_fpga_unload_devices()) {
45062306a36Sopenharmony_ci		ts78xx_fpga.state = -1;
45162306a36Sopenharmony_ci		return -EBUSY;
45262306a36Sopenharmony_ci	}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	return 0;
45562306a36Sopenharmony_ci};
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cistatic ssize_t ts78xx_fpga_show(struct kobject *kobj,
45862306a36Sopenharmony_ci			struct kobj_attribute *attr, char *buf)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	if (ts78xx_fpga.state < 0)
46162306a36Sopenharmony_ci		return sprintf(buf, "borked\n");
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	return sprintf(buf, "%s\n", (ts78xx_fpga.state) ? "online" : "offline");
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic ssize_t ts78xx_fpga_store(struct kobject *kobj,
46762306a36Sopenharmony_ci			struct kobj_attribute *attr, const char *buf, size_t n)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	int value, ret;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	if (ts78xx_fpga.state < 0) {
47262306a36Sopenharmony_ci		pr_err("FPGA borked, you must powercycle ASAP\n");
47362306a36Sopenharmony_ci		return -EBUSY;
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	if (strncmp(buf, "online", sizeof("online") - 1) == 0)
47762306a36Sopenharmony_ci		value = 1;
47862306a36Sopenharmony_ci	else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
47962306a36Sopenharmony_ci		value = 0;
48062306a36Sopenharmony_ci	else
48162306a36Sopenharmony_ci		return -EINVAL;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	if (ts78xx_fpga.state == value)
48462306a36Sopenharmony_ci		return n;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	ret = (ts78xx_fpga.state == 0)
48762306a36Sopenharmony_ci		? ts78xx_fpga_load()
48862306a36Sopenharmony_ci		: ts78xx_fpga_unload();
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	if (!(ret < 0))
49162306a36Sopenharmony_ci		ts78xx_fpga.state = value;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	return n;
49462306a36Sopenharmony_ci}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cistatic struct kobj_attribute ts78xx_fpga_attr =
49762306a36Sopenharmony_ci	__ATTR(ts78xx_fpga, 0644, ts78xx_fpga_show, ts78xx_fpga_store);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci/*****************************************************************************
50062306a36Sopenharmony_ci * General Setup
50162306a36Sopenharmony_ci ****************************************************************************/
50262306a36Sopenharmony_cistatic unsigned int ts78xx_mpp_modes[] __initdata = {
50362306a36Sopenharmony_ci	MPP0_UNUSED,
50462306a36Sopenharmony_ci	MPP1_GPIO,		/* JTAG Clock */
50562306a36Sopenharmony_ci	MPP2_GPIO,		/* JTAG Data In */
50662306a36Sopenharmony_ci	MPP3_GPIO,		/* Lat ECP2 256 FPGA - PB2B */
50762306a36Sopenharmony_ci	MPP4_GPIO,		/* JTAG Data Out */
50862306a36Sopenharmony_ci	MPP5_GPIO,		/* JTAG TMS */
50962306a36Sopenharmony_ci	MPP6_GPIO,		/* Lat ECP2 256 FPGA - PB31A_CLK4+ */
51062306a36Sopenharmony_ci	MPP7_GPIO,		/* Lat ECP2 256 FPGA - PB22B */
51162306a36Sopenharmony_ci	MPP8_UNUSED,
51262306a36Sopenharmony_ci	MPP9_UNUSED,
51362306a36Sopenharmony_ci	MPP10_UNUSED,
51462306a36Sopenharmony_ci	MPP11_UNUSED,
51562306a36Sopenharmony_ci	MPP12_UNUSED,
51662306a36Sopenharmony_ci	MPP13_UNUSED,
51762306a36Sopenharmony_ci	MPP14_UNUSED,
51862306a36Sopenharmony_ci	MPP15_UNUSED,
51962306a36Sopenharmony_ci	MPP16_UART,
52062306a36Sopenharmony_ci	MPP17_UART,
52162306a36Sopenharmony_ci	MPP18_UART,
52262306a36Sopenharmony_ci	MPP19_UART,
52362306a36Sopenharmony_ci	/*
52462306a36Sopenharmony_ci	 * MPP[20] PCI Clock Out 1
52562306a36Sopenharmony_ci	 * MPP[21] PCI Clock Out 0
52662306a36Sopenharmony_ci	 * MPP[22] Unused
52762306a36Sopenharmony_ci	 * MPP[23] Unused
52862306a36Sopenharmony_ci	 * MPP[24] Unused
52962306a36Sopenharmony_ci	 * MPP[25] Unused
53062306a36Sopenharmony_ci	 */
53162306a36Sopenharmony_ci	0,
53262306a36Sopenharmony_ci};
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_cistatic void __init ts78xx_init(void)
53562306a36Sopenharmony_ci{
53662306a36Sopenharmony_ci	int ret;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	/*
53962306a36Sopenharmony_ci	 * Setup basic Orion functions. Need to be called early.
54062306a36Sopenharmony_ci	 */
54162306a36Sopenharmony_ci	orion5x_init();
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	orion5x_mpp_conf(ts78xx_mpp_modes);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	/*
54662306a36Sopenharmony_ci	 * Configure peripherals.
54762306a36Sopenharmony_ci	 */
54862306a36Sopenharmony_ci	orion5x_ehci0_init();
54962306a36Sopenharmony_ci	orion5x_ehci1_init();
55062306a36Sopenharmony_ci	orion5x_eth_init(&ts78xx_eth_data);
55162306a36Sopenharmony_ci	orion5x_sata_init(&ts78xx_sata_data);
55262306a36Sopenharmony_ci	orion5x_uart0_init();
55362306a36Sopenharmony_ci	orion5x_uart1_init();
55462306a36Sopenharmony_ci	orion5x_xor_init();
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	/* FPGA init */
55762306a36Sopenharmony_ci	ts78xx_fpga_devices_zero_init();
55862306a36Sopenharmony_ci	ret = ts78xx_fpga_load();
55962306a36Sopenharmony_ci	ret = sysfs_create_file(firmware_kobj, &ts78xx_fpga_attr.attr);
56062306a36Sopenharmony_ci	if (ret)
56162306a36Sopenharmony_ci		pr_err("sysfs_create_file failed: %d\n", ret);
56262306a36Sopenharmony_ci}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ciMACHINE_START(TS78XX, "Technologic Systems TS-78xx SBC")
56562306a36Sopenharmony_ci	/* Maintainer: Alexander Clouter <alex@digriz.org.uk> */
56662306a36Sopenharmony_ci	.atag_offset	= 0x100,
56762306a36Sopenharmony_ci	.nr_irqs	= ORION5X_NR_IRQS,
56862306a36Sopenharmony_ci	.init_machine	= ts78xx_init,
56962306a36Sopenharmony_ci	.map_io		= ts78xx_map_io,
57062306a36Sopenharmony_ci	.init_early	= orion5x_init_early,
57162306a36Sopenharmony_ci	.init_irq	= orion5x_init_irq,
57262306a36Sopenharmony_ci	.init_time	= orion5x_timer_init,
57362306a36Sopenharmony_ci	.restart	= orion5x_restart,
57462306a36Sopenharmony_ciMACHINE_END
575