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