18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * arch/arm/mach-orion5x/ts78xx-setup.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Maintainer: Alexander Clouter <alex@digriz.org.uk> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This file is licensed under the terms of the GNU General Public 78c2ecf20Sopenharmony_ci * License version 2. This program is licensed "as is" without any 88c2ecf20Sopenharmony_ci * warranty of any kind, whether express or implied. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/init.h> 158c2ecf20Sopenharmony_ci#include <linux/sysfs.h> 168c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 178c2ecf20Sopenharmony_ci#include <linux/mv643xx_eth.h> 188c2ecf20Sopenharmony_ci#include <linux/ata_platform.h> 198c2ecf20Sopenharmony_ci#include <linux/mtd/platnand.h> 208c2ecf20Sopenharmony_ci#include <linux/timeriomem-rng.h> 218c2ecf20Sopenharmony_ci#include <asm/mach-types.h> 228c2ecf20Sopenharmony_ci#include <asm/mach/arch.h> 238c2ecf20Sopenharmony_ci#include <asm/mach/map.h> 248c2ecf20Sopenharmony_ci#include "common.h" 258c2ecf20Sopenharmony_ci#include "mpp.h" 268c2ecf20Sopenharmony_ci#include "orion5x.h" 278c2ecf20Sopenharmony_ci#include "ts78xx-fpga.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/***************************************************************************** 308c2ecf20Sopenharmony_ci * TS-78xx Info 318c2ecf20Sopenharmony_ci ****************************************************************************/ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* 348c2ecf20Sopenharmony_ci * FPGA - lives where the PCI bus would be at ORION5X_PCI_MEM_PHYS_BASE 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ci#define TS78XX_FPGA_REGS_PHYS_BASE 0xe8000000 378c2ecf20Sopenharmony_ci#define TS78XX_FPGA_REGS_VIRT_BASE IOMEM(0xff900000) 388c2ecf20Sopenharmony_ci#define TS78XX_FPGA_REGS_SIZE SZ_1M 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic struct ts78xx_fpga_data ts78xx_fpga = { 418c2ecf20Sopenharmony_ci .id = 0, 428c2ecf20Sopenharmony_ci .state = 1, 438c2ecf20Sopenharmony_ci/* .supports = ... - populated by ts78xx_fpga_supports() */ 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/***************************************************************************** 478c2ecf20Sopenharmony_ci * I/O Address Mapping 488c2ecf20Sopenharmony_ci ****************************************************************************/ 498c2ecf20Sopenharmony_cistatic struct map_desc ts78xx_io_desc[] __initdata = { 508c2ecf20Sopenharmony_ci { 518c2ecf20Sopenharmony_ci .virtual = (unsigned long)TS78XX_FPGA_REGS_VIRT_BASE, 528c2ecf20Sopenharmony_ci .pfn = __phys_to_pfn(TS78XX_FPGA_REGS_PHYS_BASE), 538c2ecf20Sopenharmony_ci .length = TS78XX_FPGA_REGS_SIZE, 548c2ecf20Sopenharmony_ci .type = MT_DEVICE, 558c2ecf20Sopenharmony_ci }, 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic void __init ts78xx_map_io(void) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci orion5x_map_io(); 618c2ecf20Sopenharmony_ci iotable_init(ts78xx_io_desc, ARRAY_SIZE(ts78xx_io_desc)); 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/***************************************************************************** 658c2ecf20Sopenharmony_ci * Ethernet 668c2ecf20Sopenharmony_ci ****************************************************************************/ 678c2ecf20Sopenharmony_cistatic struct mv643xx_eth_platform_data ts78xx_eth_data = { 688c2ecf20Sopenharmony_ci .phy_addr = MV643XX_ETH_PHY_ADDR(0), 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci/***************************************************************************** 728c2ecf20Sopenharmony_ci * SATA 738c2ecf20Sopenharmony_ci ****************************************************************************/ 748c2ecf20Sopenharmony_cistatic struct mv_sata_platform_data ts78xx_sata_data = { 758c2ecf20Sopenharmony_ci .n_ports = 2, 768c2ecf20Sopenharmony_ci}; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/***************************************************************************** 798c2ecf20Sopenharmony_ci * RTC M48T86 - nicked^Wborrowed from arch/arm/mach-ep93xx/ts72xx.c 808c2ecf20Sopenharmony_ci ****************************************************************************/ 818c2ecf20Sopenharmony_ci#define TS_RTC_CTRL (TS78XX_FPGA_REGS_PHYS_BASE + 0x808) 828c2ecf20Sopenharmony_ci#define TS_RTC_DATA (TS78XX_FPGA_REGS_PHYS_BASE + 0x80c) 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic struct resource ts78xx_ts_rtc_resources[] = { 858c2ecf20Sopenharmony_ci DEFINE_RES_MEM(TS_RTC_CTRL, 0x01), 868c2ecf20Sopenharmony_ci DEFINE_RES_MEM(TS_RTC_DATA, 0x01), 878c2ecf20Sopenharmony_ci}; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic struct platform_device ts78xx_ts_rtc_device = { 908c2ecf20Sopenharmony_ci .name = "rtc-m48t86", 918c2ecf20Sopenharmony_ci .id = -1, 928c2ecf20Sopenharmony_ci .resource = ts78xx_ts_rtc_resources, 938c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(ts78xx_ts_rtc_resources), 948c2ecf20Sopenharmony_ci}; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic int ts78xx_ts_rtc_load(void) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci int rc; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (ts78xx_fpga.supports.ts_rtc.init == 0) { 1018c2ecf20Sopenharmony_ci rc = platform_device_register(&ts78xx_ts_rtc_device); 1028c2ecf20Sopenharmony_ci if (!rc) 1038c2ecf20Sopenharmony_ci ts78xx_fpga.supports.ts_rtc.init = 1; 1048c2ecf20Sopenharmony_ci } else { 1058c2ecf20Sopenharmony_ci rc = platform_device_add(&ts78xx_ts_rtc_device); 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (rc) 1098c2ecf20Sopenharmony_ci pr_info("RTC could not be registered: %d\n", rc); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci return rc; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic void ts78xx_ts_rtc_unload(void) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci platform_device_del(&ts78xx_ts_rtc_device); 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/***************************************************************************** 1208c2ecf20Sopenharmony_ci * NAND Flash 1218c2ecf20Sopenharmony_ci ****************************************************************************/ 1228c2ecf20Sopenharmony_ci#define TS_NAND_CTRL (TS78XX_FPGA_REGS_VIRT_BASE + 0x800) /* VIRT */ 1238c2ecf20Sopenharmony_ci#define TS_NAND_DATA (TS78XX_FPGA_REGS_PHYS_BASE + 0x804) /* PHYS */ 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci/* 1268c2ecf20Sopenharmony_ci * hardware specific access to control-lines 1278c2ecf20Sopenharmony_ci * 1288c2ecf20Sopenharmony_ci * ctrl: 1298c2ecf20Sopenharmony_ci * NAND_NCE: bit 0 -> bit 2 1308c2ecf20Sopenharmony_ci * NAND_CLE: bit 1 -> bit 1 1318c2ecf20Sopenharmony_ci * NAND_ALE: bit 2 -> bit 0 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_cistatic void ts78xx_ts_nand_cmd_ctrl(struct nand_chip *this, int cmd, 1348c2ecf20Sopenharmony_ci unsigned int ctrl) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci if (ctrl & NAND_CTRL_CHANGE) { 1378c2ecf20Sopenharmony_ci unsigned char bits; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci bits = (ctrl & NAND_NCE) << 2; 1408c2ecf20Sopenharmony_ci bits |= ctrl & NAND_CLE; 1418c2ecf20Sopenharmony_ci bits |= (ctrl & NAND_ALE) >> 2; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci writeb((readb(TS_NAND_CTRL) & ~0x7) | bits, TS_NAND_CTRL); 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (cmd != NAND_CMD_NONE) 1478c2ecf20Sopenharmony_ci writeb(cmd, this->legacy.IO_ADDR_W); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic int ts78xx_ts_nand_dev_ready(struct nand_chip *chip) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci return readb(TS_NAND_CTRL) & 0x20; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic void ts78xx_ts_nand_write_buf(struct nand_chip *chip, 1568c2ecf20Sopenharmony_ci const uint8_t *buf, int len) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci void __iomem *io_base = chip->legacy.IO_ADDR_W; 1598c2ecf20Sopenharmony_ci unsigned long off = ((unsigned long)buf & 3); 1608c2ecf20Sopenharmony_ci int sz; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (off) { 1638c2ecf20Sopenharmony_ci sz = min_t(int, 4 - off, len); 1648c2ecf20Sopenharmony_ci writesb(io_base, buf, sz); 1658c2ecf20Sopenharmony_ci buf += sz; 1668c2ecf20Sopenharmony_ci len -= sz; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci sz = len >> 2; 1708c2ecf20Sopenharmony_ci if (sz) { 1718c2ecf20Sopenharmony_ci u32 *buf32 = (u32 *)buf; 1728c2ecf20Sopenharmony_ci writesl(io_base, buf32, sz); 1738c2ecf20Sopenharmony_ci buf += sz << 2; 1748c2ecf20Sopenharmony_ci len -= sz << 2; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (len) 1788c2ecf20Sopenharmony_ci writesb(io_base, buf, len); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic void ts78xx_ts_nand_read_buf(struct nand_chip *chip, 1828c2ecf20Sopenharmony_ci uint8_t *buf, int len) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci void __iomem *io_base = chip->legacy.IO_ADDR_R; 1858c2ecf20Sopenharmony_ci unsigned long off = ((unsigned long)buf & 3); 1868c2ecf20Sopenharmony_ci int sz; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci if (off) { 1898c2ecf20Sopenharmony_ci sz = min_t(int, 4 - off, len); 1908c2ecf20Sopenharmony_ci readsb(io_base, buf, sz); 1918c2ecf20Sopenharmony_ci buf += sz; 1928c2ecf20Sopenharmony_ci len -= sz; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci sz = len >> 2; 1968c2ecf20Sopenharmony_ci if (sz) { 1978c2ecf20Sopenharmony_ci u32 *buf32 = (u32 *)buf; 1988c2ecf20Sopenharmony_ci readsl(io_base, buf32, sz); 1998c2ecf20Sopenharmony_ci buf += sz << 2; 2008c2ecf20Sopenharmony_ci len -= sz << 2; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (len) 2048c2ecf20Sopenharmony_ci readsb(io_base, buf, len); 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic struct mtd_partition ts78xx_ts_nand_parts[] = { 2088c2ecf20Sopenharmony_ci { 2098c2ecf20Sopenharmony_ci .name = "mbr", 2108c2ecf20Sopenharmony_ci .offset = 0, 2118c2ecf20Sopenharmony_ci .size = SZ_128K, 2128c2ecf20Sopenharmony_ci .mask_flags = MTD_WRITEABLE, 2138c2ecf20Sopenharmony_ci }, { 2148c2ecf20Sopenharmony_ci .name = "kernel", 2158c2ecf20Sopenharmony_ci .offset = MTDPART_OFS_APPEND, 2168c2ecf20Sopenharmony_ci .size = SZ_4M, 2178c2ecf20Sopenharmony_ci }, { 2188c2ecf20Sopenharmony_ci .name = "initrd", 2198c2ecf20Sopenharmony_ci .offset = MTDPART_OFS_APPEND, 2208c2ecf20Sopenharmony_ci .size = SZ_4M, 2218c2ecf20Sopenharmony_ci }, { 2228c2ecf20Sopenharmony_ci .name = "rootfs", 2238c2ecf20Sopenharmony_ci .offset = MTDPART_OFS_APPEND, 2248c2ecf20Sopenharmony_ci .size = MTDPART_SIZ_FULL, 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci}; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic struct platform_nand_data ts78xx_ts_nand_data = { 2298c2ecf20Sopenharmony_ci .chip = { 2308c2ecf20Sopenharmony_ci .nr_chips = 1, 2318c2ecf20Sopenharmony_ci .partitions = ts78xx_ts_nand_parts, 2328c2ecf20Sopenharmony_ci .nr_partitions = ARRAY_SIZE(ts78xx_ts_nand_parts), 2338c2ecf20Sopenharmony_ci .chip_delay = 15, 2348c2ecf20Sopenharmony_ci .bbt_options = NAND_BBT_USE_FLASH, 2358c2ecf20Sopenharmony_ci }, 2368c2ecf20Sopenharmony_ci .ctrl = { 2378c2ecf20Sopenharmony_ci /* 2388c2ecf20Sopenharmony_ci * The HW ECC offloading functions, used to give about a 9% 2398c2ecf20Sopenharmony_ci * performance increase for 'dd if=/dev/mtdblockX' and 5% for 2408c2ecf20Sopenharmony_ci * nanddump. This all however was changed by git commit 2418c2ecf20Sopenharmony_ci * e6cf5df1838c28bb060ac45b5585e48e71bbc740 so now there is 2428c2ecf20Sopenharmony_ci * no performance advantage to be had so we no longer bother 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_ci .cmd_ctrl = ts78xx_ts_nand_cmd_ctrl, 2458c2ecf20Sopenharmony_ci .dev_ready = ts78xx_ts_nand_dev_ready, 2468c2ecf20Sopenharmony_ci .write_buf = ts78xx_ts_nand_write_buf, 2478c2ecf20Sopenharmony_ci .read_buf = ts78xx_ts_nand_read_buf, 2488c2ecf20Sopenharmony_ci }, 2498c2ecf20Sopenharmony_ci}; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic struct resource ts78xx_ts_nand_resources 2528c2ecf20Sopenharmony_ci = DEFINE_RES_MEM(TS_NAND_DATA, 4); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic struct platform_device ts78xx_ts_nand_device = { 2558c2ecf20Sopenharmony_ci .name = "gen_nand", 2568c2ecf20Sopenharmony_ci .id = -1, 2578c2ecf20Sopenharmony_ci .dev = { 2588c2ecf20Sopenharmony_ci .platform_data = &ts78xx_ts_nand_data, 2598c2ecf20Sopenharmony_ci }, 2608c2ecf20Sopenharmony_ci .resource = &ts78xx_ts_nand_resources, 2618c2ecf20Sopenharmony_ci .num_resources = 1, 2628c2ecf20Sopenharmony_ci}; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic int ts78xx_ts_nand_load(void) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci int rc; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (ts78xx_fpga.supports.ts_nand.init == 0) { 2698c2ecf20Sopenharmony_ci rc = platform_device_register(&ts78xx_ts_nand_device); 2708c2ecf20Sopenharmony_ci if (!rc) 2718c2ecf20Sopenharmony_ci ts78xx_fpga.supports.ts_nand.init = 1; 2728c2ecf20Sopenharmony_ci } else 2738c2ecf20Sopenharmony_ci rc = platform_device_add(&ts78xx_ts_nand_device); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (rc) 2768c2ecf20Sopenharmony_ci pr_info("NAND could not be registered: %d\n", rc); 2778c2ecf20Sopenharmony_ci return rc; 2788c2ecf20Sopenharmony_ci}; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic void ts78xx_ts_nand_unload(void) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci platform_device_del(&ts78xx_ts_nand_device); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci/***************************************************************************** 2868c2ecf20Sopenharmony_ci * HW RNG 2878c2ecf20Sopenharmony_ci ****************************************************************************/ 2888c2ecf20Sopenharmony_ci#define TS_RNG_DATA (TS78XX_FPGA_REGS_PHYS_BASE | 0x044) 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic struct resource ts78xx_ts_rng_resource 2918c2ecf20Sopenharmony_ci = DEFINE_RES_MEM(TS_RNG_DATA, 4); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic struct timeriomem_rng_data ts78xx_ts_rng_data = { 2948c2ecf20Sopenharmony_ci .period = 1000000, /* one second */ 2958c2ecf20Sopenharmony_ci}; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic struct platform_device ts78xx_ts_rng_device = { 2988c2ecf20Sopenharmony_ci .name = "timeriomem_rng", 2998c2ecf20Sopenharmony_ci .id = -1, 3008c2ecf20Sopenharmony_ci .dev = { 3018c2ecf20Sopenharmony_ci .platform_data = &ts78xx_ts_rng_data, 3028c2ecf20Sopenharmony_ci }, 3038c2ecf20Sopenharmony_ci .resource = &ts78xx_ts_rng_resource, 3048c2ecf20Sopenharmony_ci .num_resources = 1, 3058c2ecf20Sopenharmony_ci}; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic int ts78xx_ts_rng_load(void) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci int rc; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (ts78xx_fpga.supports.ts_rng.init == 0) { 3128c2ecf20Sopenharmony_ci rc = platform_device_register(&ts78xx_ts_rng_device); 3138c2ecf20Sopenharmony_ci if (!rc) 3148c2ecf20Sopenharmony_ci ts78xx_fpga.supports.ts_rng.init = 1; 3158c2ecf20Sopenharmony_ci } else 3168c2ecf20Sopenharmony_ci rc = platform_device_add(&ts78xx_ts_rng_device); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (rc) 3198c2ecf20Sopenharmony_ci pr_info("RNG could not be registered: %d\n", rc); 3208c2ecf20Sopenharmony_ci return rc; 3218c2ecf20Sopenharmony_ci}; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic void ts78xx_ts_rng_unload(void) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci platform_device_del(&ts78xx_ts_rng_device); 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci/***************************************************************************** 3298c2ecf20Sopenharmony_ci * FPGA 'hotplug' support code 3308c2ecf20Sopenharmony_ci ****************************************************************************/ 3318c2ecf20Sopenharmony_cistatic void ts78xx_fpga_devices_zero_init(void) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci ts78xx_fpga.supports.ts_rtc.init = 0; 3348c2ecf20Sopenharmony_ci ts78xx_fpga.supports.ts_nand.init = 0; 3358c2ecf20Sopenharmony_ci ts78xx_fpga.supports.ts_rng.init = 0; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic void ts78xx_fpga_supports(void) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci /* TODO: put this 'table' into ts78xx-fpga.h */ 3418c2ecf20Sopenharmony_ci switch (ts78xx_fpga.id) { 3428c2ecf20Sopenharmony_ci case TS7800_REV_1: 3438c2ecf20Sopenharmony_ci case TS7800_REV_2: 3448c2ecf20Sopenharmony_ci case TS7800_REV_3: 3458c2ecf20Sopenharmony_ci case TS7800_REV_4: 3468c2ecf20Sopenharmony_ci case TS7800_REV_5: 3478c2ecf20Sopenharmony_ci case TS7800_REV_6: 3488c2ecf20Sopenharmony_ci case TS7800_REV_7: 3498c2ecf20Sopenharmony_ci case TS7800_REV_8: 3508c2ecf20Sopenharmony_ci case TS7800_REV_9: 3518c2ecf20Sopenharmony_ci ts78xx_fpga.supports.ts_rtc.present = 1; 3528c2ecf20Sopenharmony_ci ts78xx_fpga.supports.ts_nand.present = 1; 3538c2ecf20Sopenharmony_ci ts78xx_fpga.supports.ts_rng.present = 1; 3548c2ecf20Sopenharmony_ci break; 3558c2ecf20Sopenharmony_ci default: 3568c2ecf20Sopenharmony_ci /* enable devices if magic matches */ 3578c2ecf20Sopenharmony_ci switch ((ts78xx_fpga.id >> 8) & 0xffffff) { 3588c2ecf20Sopenharmony_ci case TS7800_FPGA_MAGIC: 3598c2ecf20Sopenharmony_ci pr_warn("unrecognised FPGA revision 0x%.2x\n", 3608c2ecf20Sopenharmony_ci ts78xx_fpga.id & 0xff); 3618c2ecf20Sopenharmony_ci ts78xx_fpga.supports.ts_rtc.present = 1; 3628c2ecf20Sopenharmony_ci ts78xx_fpga.supports.ts_nand.present = 1; 3638c2ecf20Sopenharmony_ci ts78xx_fpga.supports.ts_rng.present = 1; 3648c2ecf20Sopenharmony_ci break; 3658c2ecf20Sopenharmony_ci default: 3668c2ecf20Sopenharmony_ci ts78xx_fpga.supports.ts_rtc.present = 0; 3678c2ecf20Sopenharmony_ci ts78xx_fpga.supports.ts_nand.present = 0; 3688c2ecf20Sopenharmony_ci ts78xx_fpga.supports.ts_rng.present = 0; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_cistatic int ts78xx_fpga_load_devices(void) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci int tmp, ret = 0; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if (ts78xx_fpga.supports.ts_rtc.present == 1) { 3788c2ecf20Sopenharmony_ci tmp = ts78xx_ts_rtc_load(); 3798c2ecf20Sopenharmony_ci if (tmp) 3808c2ecf20Sopenharmony_ci ts78xx_fpga.supports.ts_rtc.present = 0; 3818c2ecf20Sopenharmony_ci ret |= tmp; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci if (ts78xx_fpga.supports.ts_nand.present == 1) { 3848c2ecf20Sopenharmony_ci tmp = ts78xx_ts_nand_load(); 3858c2ecf20Sopenharmony_ci if (tmp) 3868c2ecf20Sopenharmony_ci ts78xx_fpga.supports.ts_nand.present = 0; 3878c2ecf20Sopenharmony_ci ret |= tmp; 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci if (ts78xx_fpga.supports.ts_rng.present == 1) { 3908c2ecf20Sopenharmony_ci tmp = ts78xx_ts_rng_load(); 3918c2ecf20Sopenharmony_ci if (tmp) 3928c2ecf20Sopenharmony_ci ts78xx_fpga.supports.ts_rng.present = 0; 3938c2ecf20Sopenharmony_ci ret |= tmp; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci return ret; 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic int ts78xx_fpga_unload_devices(void) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci if (ts78xx_fpga.supports.ts_rtc.present == 1) 4038c2ecf20Sopenharmony_ci ts78xx_ts_rtc_unload(); 4048c2ecf20Sopenharmony_ci if (ts78xx_fpga.supports.ts_nand.present == 1) 4058c2ecf20Sopenharmony_ci ts78xx_ts_nand_unload(); 4068c2ecf20Sopenharmony_ci if (ts78xx_fpga.supports.ts_rng.present == 1) 4078c2ecf20Sopenharmony_ci ts78xx_ts_rng_unload(); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci return 0; 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_cistatic int ts78xx_fpga_load(void) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci ts78xx_fpga.id = readl(TS78XX_FPGA_REGS_VIRT_BASE); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci pr_info("FPGA magic=0x%.6x, rev=0x%.2x\n", 4178c2ecf20Sopenharmony_ci (ts78xx_fpga.id >> 8) & 0xffffff, 4188c2ecf20Sopenharmony_ci ts78xx_fpga.id & 0xff); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci ts78xx_fpga_supports(); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci if (ts78xx_fpga_load_devices()) { 4238c2ecf20Sopenharmony_ci ts78xx_fpga.state = -1; 4248c2ecf20Sopenharmony_ci return -EBUSY; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci return 0; 4288c2ecf20Sopenharmony_ci}; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic int ts78xx_fpga_unload(void) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci unsigned int fpga_id; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci fpga_id = readl(TS78XX_FPGA_REGS_VIRT_BASE); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci /* 4378c2ecf20Sopenharmony_ci * There does not seem to be a feasible way to block access to the GPIO 4388c2ecf20Sopenharmony_ci * pins from userspace (/dev/mem). This if clause should hopefully warn 4398c2ecf20Sopenharmony_ci * those foolish enough not to follow 'policy' :) 4408c2ecf20Sopenharmony_ci * 4418c2ecf20Sopenharmony_ci * UrJTAG SVN since r1381 can be used to reprogram the FPGA 4428c2ecf20Sopenharmony_ci */ 4438c2ecf20Sopenharmony_ci if (ts78xx_fpga.id != fpga_id) { 4448c2ecf20Sopenharmony_ci pr_err("FPGA magic/rev mismatch\n" 4458c2ecf20Sopenharmony_ci "TS-78xx FPGA: was 0x%.6x/%.2x but now 0x%.6x/%.2x\n", 4468c2ecf20Sopenharmony_ci (ts78xx_fpga.id >> 8) & 0xffffff, ts78xx_fpga.id & 0xff, 4478c2ecf20Sopenharmony_ci (fpga_id >> 8) & 0xffffff, fpga_id & 0xff); 4488c2ecf20Sopenharmony_ci ts78xx_fpga.state = -1; 4498c2ecf20Sopenharmony_ci return -EBUSY; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (ts78xx_fpga_unload_devices()) { 4538c2ecf20Sopenharmony_ci ts78xx_fpga.state = -1; 4548c2ecf20Sopenharmony_ci return -EBUSY; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci return 0; 4588c2ecf20Sopenharmony_ci}; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic ssize_t ts78xx_fpga_show(struct kobject *kobj, 4618c2ecf20Sopenharmony_ci struct kobj_attribute *attr, char *buf) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci if (ts78xx_fpga.state < 0) 4648c2ecf20Sopenharmony_ci return sprintf(buf, "borked\n"); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci return sprintf(buf, "%s\n", (ts78xx_fpga.state) ? "online" : "offline"); 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic ssize_t ts78xx_fpga_store(struct kobject *kobj, 4708c2ecf20Sopenharmony_ci struct kobj_attribute *attr, const char *buf, size_t n) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci int value, ret; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci if (ts78xx_fpga.state < 0) { 4758c2ecf20Sopenharmony_ci pr_err("FPGA borked, you must powercycle ASAP\n"); 4768c2ecf20Sopenharmony_ci return -EBUSY; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci if (strncmp(buf, "online", sizeof("online") - 1) == 0) 4808c2ecf20Sopenharmony_ci value = 1; 4818c2ecf20Sopenharmony_ci else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0) 4828c2ecf20Sopenharmony_ci value = 0; 4838c2ecf20Sopenharmony_ci else 4848c2ecf20Sopenharmony_ci return -EINVAL; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci if (ts78xx_fpga.state == value) 4878c2ecf20Sopenharmony_ci return n; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci ret = (ts78xx_fpga.state == 0) 4908c2ecf20Sopenharmony_ci ? ts78xx_fpga_load() 4918c2ecf20Sopenharmony_ci : ts78xx_fpga_unload(); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci if (!(ret < 0)) 4948c2ecf20Sopenharmony_ci ts78xx_fpga.state = value; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci return n; 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_cistatic struct kobj_attribute ts78xx_fpga_attr = 5008c2ecf20Sopenharmony_ci __ATTR(ts78xx_fpga, 0644, ts78xx_fpga_show, ts78xx_fpga_store); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci/***************************************************************************** 5038c2ecf20Sopenharmony_ci * General Setup 5048c2ecf20Sopenharmony_ci ****************************************************************************/ 5058c2ecf20Sopenharmony_cistatic unsigned int ts78xx_mpp_modes[] __initdata = { 5068c2ecf20Sopenharmony_ci MPP0_UNUSED, 5078c2ecf20Sopenharmony_ci MPP1_GPIO, /* JTAG Clock */ 5088c2ecf20Sopenharmony_ci MPP2_GPIO, /* JTAG Data In */ 5098c2ecf20Sopenharmony_ci MPP3_GPIO, /* Lat ECP2 256 FPGA - PB2B */ 5108c2ecf20Sopenharmony_ci MPP4_GPIO, /* JTAG Data Out */ 5118c2ecf20Sopenharmony_ci MPP5_GPIO, /* JTAG TMS */ 5128c2ecf20Sopenharmony_ci MPP6_GPIO, /* Lat ECP2 256 FPGA - PB31A_CLK4+ */ 5138c2ecf20Sopenharmony_ci MPP7_GPIO, /* Lat ECP2 256 FPGA - PB22B */ 5148c2ecf20Sopenharmony_ci MPP8_UNUSED, 5158c2ecf20Sopenharmony_ci MPP9_UNUSED, 5168c2ecf20Sopenharmony_ci MPP10_UNUSED, 5178c2ecf20Sopenharmony_ci MPP11_UNUSED, 5188c2ecf20Sopenharmony_ci MPP12_UNUSED, 5198c2ecf20Sopenharmony_ci MPP13_UNUSED, 5208c2ecf20Sopenharmony_ci MPP14_UNUSED, 5218c2ecf20Sopenharmony_ci MPP15_UNUSED, 5228c2ecf20Sopenharmony_ci MPP16_UART, 5238c2ecf20Sopenharmony_ci MPP17_UART, 5248c2ecf20Sopenharmony_ci MPP18_UART, 5258c2ecf20Sopenharmony_ci MPP19_UART, 5268c2ecf20Sopenharmony_ci /* 5278c2ecf20Sopenharmony_ci * MPP[20] PCI Clock Out 1 5288c2ecf20Sopenharmony_ci * MPP[21] PCI Clock Out 0 5298c2ecf20Sopenharmony_ci * MPP[22] Unused 5308c2ecf20Sopenharmony_ci * MPP[23] Unused 5318c2ecf20Sopenharmony_ci * MPP[24] Unused 5328c2ecf20Sopenharmony_ci * MPP[25] Unused 5338c2ecf20Sopenharmony_ci */ 5348c2ecf20Sopenharmony_ci 0, 5358c2ecf20Sopenharmony_ci}; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_cistatic void __init ts78xx_init(void) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci int ret; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci /* 5428c2ecf20Sopenharmony_ci * Setup basic Orion functions. Need to be called early. 5438c2ecf20Sopenharmony_ci */ 5448c2ecf20Sopenharmony_ci orion5x_init(); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci orion5x_mpp_conf(ts78xx_mpp_modes); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci /* 5498c2ecf20Sopenharmony_ci * Configure peripherals. 5508c2ecf20Sopenharmony_ci */ 5518c2ecf20Sopenharmony_ci orion5x_ehci0_init(); 5528c2ecf20Sopenharmony_ci orion5x_ehci1_init(); 5538c2ecf20Sopenharmony_ci orion5x_eth_init(&ts78xx_eth_data); 5548c2ecf20Sopenharmony_ci orion5x_sata_init(&ts78xx_sata_data); 5558c2ecf20Sopenharmony_ci orion5x_uart0_init(); 5568c2ecf20Sopenharmony_ci orion5x_uart1_init(); 5578c2ecf20Sopenharmony_ci orion5x_xor_init(); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci /* FPGA init */ 5608c2ecf20Sopenharmony_ci ts78xx_fpga_devices_zero_init(); 5618c2ecf20Sopenharmony_ci ret = ts78xx_fpga_load(); 5628c2ecf20Sopenharmony_ci ret = sysfs_create_file(firmware_kobj, &ts78xx_fpga_attr.attr); 5638c2ecf20Sopenharmony_ci if (ret) 5648c2ecf20Sopenharmony_ci pr_err("sysfs_create_file failed: %d\n", ret); 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ciMACHINE_START(TS78XX, "Technologic Systems TS-78xx SBC") 5688c2ecf20Sopenharmony_ci /* Maintainer: Alexander Clouter <alex@digriz.org.uk> */ 5698c2ecf20Sopenharmony_ci .atag_offset = 0x100, 5708c2ecf20Sopenharmony_ci .nr_irqs = ORION5X_NR_IRQS, 5718c2ecf20Sopenharmony_ci .init_machine = ts78xx_init, 5728c2ecf20Sopenharmony_ci .map_io = ts78xx_map_io, 5738c2ecf20Sopenharmony_ci .init_early = orion5x_init_early, 5748c2ecf20Sopenharmony_ci .init_irq = orion5x_init_irq, 5758c2ecf20Sopenharmony_ci .init_time = orion5x_timer_init, 5768c2ecf20Sopenharmony_ci .restart = orion5x_restart, 5778c2ecf20Sopenharmony_ciMACHINE_END 578