Path: blob/master/arch/arm/mach-orion5x/ts78xx-setup.c
10817 views
/*1* arch/arm/mach-orion5x/ts78xx-setup.c2*3* Maintainer: Alexander Clouter <[email protected]>4*5* This file is licensed under the terms of the GNU General Public6* License version 2. This program is licensed "as is" without any7* warranty of any kind, whether express or implied.8*/910#include <linux/kernel.h>11#include <linux/init.h>12#include <linux/sysfs.h>13#include <linux/platform_device.h>14#include <linux/mv643xx_eth.h>15#include <linux/ata_platform.h>16#include <linux/m48t86.h>17#include <linux/mtd/nand.h>18#include <linux/mtd/partitions.h>19#include <linux/timeriomem-rng.h>20#include <asm/mach-types.h>21#include <asm/mach/arch.h>22#include <asm/mach/map.h>23#include <mach/orion5x.h>24#include "common.h"25#include "mpp.h"26#include "ts78xx-fpga.h"2728/*****************************************************************************29* TS-78xx Info30****************************************************************************/3132/*33* FPGA - lives where the PCI bus would be at ORION5X_PCI_MEM_PHYS_BASE34*/35#define TS78XX_FPGA_REGS_PHYS_BASE 0xe800000036#define TS78XX_FPGA_REGS_VIRT_BASE 0xff90000037#define TS78XX_FPGA_REGS_SIZE SZ_1M3839static struct ts78xx_fpga_data ts78xx_fpga = {40.id = 0,41.state = 1,42/* .supports = ... - populated by ts78xx_fpga_supports() */43};4445/*****************************************************************************46* I/O Address Mapping47****************************************************************************/48static struct map_desc ts78xx_io_desc[] __initdata = {49{50.virtual = TS78XX_FPGA_REGS_VIRT_BASE,51.pfn = __phys_to_pfn(TS78XX_FPGA_REGS_PHYS_BASE),52.length = TS78XX_FPGA_REGS_SIZE,53.type = MT_DEVICE,54},55};5657void __init ts78xx_map_io(void)58{59orion5x_map_io();60iotable_init(ts78xx_io_desc, ARRAY_SIZE(ts78xx_io_desc));61}6263/*****************************************************************************64* Ethernet65****************************************************************************/66static struct mv643xx_eth_platform_data ts78xx_eth_data = {67.phy_addr = MV643XX_ETH_PHY_ADDR(0),68};6970/*****************************************************************************71* SATA72****************************************************************************/73static struct mv_sata_platform_data ts78xx_sata_data = {74.n_ports = 2,75};7677/*****************************************************************************78* RTC M48T86 - nicked^Wborrowed from arch/arm/mach-ep93xx/ts72xx.c79****************************************************************************/80#define TS_RTC_CTRL (TS78XX_FPGA_REGS_VIRT_BASE | 0x808)81#define TS_RTC_DATA (TS78XX_FPGA_REGS_VIRT_BASE | 0x80c)8283static unsigned char ts78xx_ts_rtc_readbyte(unsigned long addr)84{85writeb(addr, TS_RTC_CTRL);86return readb(TS_RTC_DATA);87}8889static void ts78xx_ts_rtc_writebyte(unsigned char value, unsigned long addr)90{91writeb(addr, TS_RTC_CTRL);92writeb(value, TS_RTC_DATA);93}9495static struct m48t86_ops ts78xx_ts_rtc_ops = {96.readbyte = ts78xx_ts_rtc_readbyte,97.writebyte = ts78xx_ts_rtc_writebyte,98};99100static struct platform_device ts78xx_ts_rtc_device = {101.name = "rtc-m48t86",102.id = -1,103.dev = {104.platform_data = &ts78xx_ts_rtc_ops,105},106.num_resources = 0,107};108109/*110* TS uses some of the user storage space on the RTC chip so see if it is111* present; as it's an optional feature at purchase time and not all boards112* will have it present113*114* I've used the method TS use in their rtc7800.c example for the detection115*116* TODO: track down a guinea pig without an RTC to see if we can work out a117* better RTC detection routine118*/119static int ts78xx_ts_rtc_load(void)120{121int rc;122unsigned char tmp_rtc0, tmp_rtc1;123124tmp_rtc0 = ts78xx_ts_rtc_readbyte(126);125tmp_rtc1 = ts78xx_ts_rtc_readbyte(127);126127ts78xx_ts_rtc_writebyte(0x00, 126);128ts78xx_ts_rtc_writebyte(0x55, 127);129if (ts78xx_ts_rtc_readbyte(127) == 0x55) {130ts78xx_ts_rtc_writebyte(0xaa, 127);131if (ts78xx_ts_rtc_readbyte(127) == 0xaa132&& ts78xx_ts_rtc_readbyte(126) == 0x00) {133ts78xx_ts_rtc_writebyte(tmp_rtc0, 126);134ts78xx_ts_rtc_writebyte(tmp_rtc1, 127);135136if (ts78xx_fpga.supports.ts_rtc.init == 0) {137rc = platform_device_register(&ts78xx_ts_rtc_device);138if (!rc)139ts78xx_fpga.supports.ts_rtc.init = 1;140} else141rc = platform_device_add(&ts78xx_ts_rtc_device);142143return rc;144}145}146147return -ENODEV;148};149150static void ts78xx_ts_rtc_unload(void)151{152platform_device_del(&ts78xx_ts_rtc_device);153}154155/*****************************************************************************156* NAND Flash157****************************************************************************/158#define TS_NAND_CTRL (TS78XX_FPGA_REGS_VIRT_BASE | 0x800) /* VIRT */159#define TS_NAND_DATA (TS78XX_FPGA_REGS_PHYS_BASE | 0x804) /* PHYS */160161/*162* hardware specific access to control-lines163*164* ctrl:165* NAND_NCE: bit 0 -> bit 2166* NAND_CLE: bit 1 -> bit 1167* NAND_ALE: bit 2 -> bit 0168*/169static void ts78xx_ts_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,170unsigned int ctrl)171{172struct nand_chip *this = mtd->priv;173174if (ctrl & NAND_CTRL_CHANGE) {175unsigned char bits;176177bits = (ctrl & NAND_NCE) << 2;178bits |= ctrl & NAND_CLE;179bits |= (ctrl & NAND_ALE) >> 2;180181writeb((readb(TS_NAND_CTRL) & ~0x7) | bits, TS_NAND_CTRL);182}183184if (cmd != NAND_CMD_NONE)185writeb(cmd, this->IO_ADDR_W);186}187188static int ts78xx_ts_nand_dev_ready(struct mtd_info *mtd)189{190return readb(TS_NAND_CTRL) & 0x20;191}192193static void ts78xx_ts_nand_write_buf(struct mtd_info *mtd,194const uint8_t *buf, int len)195{196struct nand_chip *chip = mtd->priv;197void __iomem *io_base = chip->IO_ADDR_W;198unsigned long off = ((unsigned long)buf & 3);199int sz;200201if (off) {202sz = min_t(int, 4 - off, len);203writesb(io_base, buf, sz);204buf += sz;205len -= sz;206}207208sz = len >> 2;209if (sz) {210u32 *buf32 = (u32 *)buf;211writesl(io_base, buf32, sz);212buf += sz << 2;213len -= sz << 2;214}215216if (len)217writesb(io_base, buf, len);218}219220static void ts78xx_ts_nand_read_buf(struct mtd_info *mtd,221uint8_t *buf, int len)222{223struct nand_chip *chip = mtd->priv;224void __iomem *io_base = chip->IO_ADDR_R;225unsigned long off = ((unsigned long)buf & 3);226int sz;227228if (off) {229sz = min_t(int, 4 - off, len);230readsb(io_base, buf, sz);231buf += sz;232len -= sz;233}234235sz = len >> 2;236if (sz) {237u32 *buf32 = (u32 *)buf;238readsl(io_base, buf32, sz);239buf += sz << 2;240len -= sz << 2;241}242243if (len)244readsb(io_base, buf, len);245}246247const char *ts_nand_part_probes[] = { "cmdlinepart", NULL };248249static struct mtd_partition ts78xx_ts_nand_parts[] = {250{251.name = "mbr",252.offset = 0,253.size = SZ_128K,254.mask_flags = MTD_WRITEABLE,255}, {256.name = "kernel",257.offset = MTDPART_OFS_APPEND,258.size = SZ_4M,259}, {260.name = "initrd",261.offset = MTDPART_OFS_APPEND,262.size = SZ_4M,263}, {264.name = "rootfs",265.offset = MTDPART_OFS_APPEND,266.size = MTDPART_SIZ_FULL,267}268};269270static struct platform_nand_data ts78xx_ts_nand_data = {271.chip = {272.nr_chips = 1,273.part_probe_types = ts_nand_part_probes,274.partitions = ts78xx_ts_nand_parts,275.nr_partitions = ARRAY_SIZE(ts78xx_ts_nand_parts),276.chip_delay = 15,277.options = NAND_USE_FLASH_BBT,278},279.ctrl = {280/*281* The HW ECC offloading functions, used to give about a 9%282* performance increase for 'dd if=/dev/mtdblockX' and 5% for283* nanddump. This all however was changed by git commit284* e6cf5df1838c28bb060ac45b5585e48e71bbc740 so now there is285* no performance advantage to be had so we no longer bother286*/287.cmd_ctrl = ts78xx_ts_nand_cmd_ctrl,288.dev_ready = ts78xx_ts_nand_dev_ready,289.write_buf = ts78xx_ts_nand_write_buf,290.read_buf = ts78xx_ts_nand_read_buf,291},292};293294static struct resource ts78xx_ts_nand_resources = {295.start = TS_NAND_DATA,296.end = TS_NAND_DATA + 4,297.flags = IORESOURCE_MEM,298};299300static struct platform_device ts78xx_ts_nand_device = {301.name = "gen_nand",302.id = -1,303.dev = {304.platform_data = &ts78xx_ts_nand_data,305},306.resource = &ts78xx_ts_nand_resources,307.num_resources = 1,308};309310static int ts78xx_ts_nand_load(void)311{312int rc;313314if (ts78xx_fpga.supports.ts_nand.init == 0) {315rc = platform_device_register(&ts78xx_ts_nand_device);316if (!rc)317ts78xx_fpga.supports.ts_nand.init = 1;318} else319rc = platform_device_add(&ts78xx_ts_nand_device);320321return rc;322};323324static void ts78xx_ts_nand_unload(void)325{326platform_device_del(&ts78xx_ts_nand_device);327}328329/*****************************************************************************330* HW RNG331****************************************************************************/332#define TS_RNG_DATA (TS78XX_FPGA_REGS_PHYS_BASE | 0x044)333334static struct resource ts78xx_ts_rng_resource = {335.flags = IORESOURCE_MEM,336.start = TS_RNG_DATA,337.end = TS_RNG_DATA + 4 - 1,338};339340static struct timeriomem_rng_data ts78xx_ts_rng_data = {341.period = 1000000, /* one second */342};343344static struct platform_device ts78xx_ts_rng_device = {345.name = "timeriomem_rng",346.id = -1,347.dev = {348.platform_data = &ts78xx_ts_rng_data,349},350.resource = &ts78xx_ts_rng_resource,351.num_resources = 1,352};353354static int ts78xx_ts_rng_load(void)355{356int rc;357358if (ts78xx_fpga.supports.ts_rng.init == 0) {359rc = platform_device_register(&ts78xx_ts_rng_device);360if (!rc)361ts78xx_fpga.supports.ts_rng.init = 1;362} else363rc = platform_device_add(&ts78xx_ts_rng_device);364365return rc;366};367368static void ts78xx_ts_rng_unload(void)369{370platform_device_del(&ts78xx_ts_rng_device);371}372373/*****************************************************************************374* FPGA 'hotplug' support code375****************************************************************************/376static void ts78xx_fpga_devices_zero_init(void)377{378ts78xx_fpga.supports.ts_rtc.init = 0;379ts78xx_fpga.supports.ts_nand.init = 0;380ts78xx_fpga.supports.ts_rng.init = 0;381}382383static void ts78xx_fpga_supports(void)384{385/* TODO: put this 'table' into ts78xx-fpga.h */386switch (ts78xx_fpga.id) {387case TS7800_REV_1:388case TS7800_REV_2:389case TS7800_REV_3:390case TS7800_REV_4:391case TS7800_REV_5:392case TS7800_REV_6:393case TS7800_REV_7:394case TS7800_REV_8:395case TS7800_REV_9:396ts78xx_fpga.supports.ts_rtc.present = 1;397ts78xx_fpga.supports.ts_nand.present = 1;398ts78xx_fpga.supports.ts_rng.present = 1;399break;400default:401/* enable devices if magic matches */402switch ((ts78xx_fpga.id >> 8) & 0xffffff) {403case TS7800_FPGA_MAGIC:404pr_warning("TS-7800 FPGA: unrecognized revision 0x%.2x\n",405ts78xx_fpga.id & 0xff);406ts78xx_fpga.supports.ts_rtc.present = 1;407ts78xx_fpga.supports.ts_nand.present = 1;408ts78xx_fpga.supports.ts_rng.present = 1;409break;410default:411ts78xx_fpga.supports.ts_rtc.present = 0;412ts78xx_fpga.supports.ts_nand.present = 0;413ts78xx_fpga.supports.ts_rng.present = 0;414}415}416}417418static int ts78xx_fpga_load_devices(void)419{420int tmp, ret = 0;421422if (ts78xx_fpga.supports.ts_rtc.present == 1) {423tmp = ts78xx_ts_rtc_load();424if (tmp) {425pr_info("TS-78xx: RTC not registered\n");426ts78xx_fpga.supports.ts_rtc.present = 0;427}428ret |= tmp;429}430if (ts78xx_fpga.supports.ts_nand.present == 1) {431tmp = ts78xx_ts_nand_load();432if (tmp) {433pr_info("TS-78xx: NAND not registered\n");434ts78xx_fpga.supports.ts_nand.present = 0;435}436ret |= tmp;437}438if (ts78xx_fpga.supports.ts_rng.present == 1) {439tmp = ts78xx_ts_rng_load();440if (tmp) {441pr_info("TS-78xx: RNG not registered\n");442ts78xx_fpga.supports.ts_rng.present = 0;443}444ret |= tmp;445}446447return ret;448}449450static int ts78xx_fpga_unload_devices(void)451{452int ret = 0;453454if (ts78xx_fpga.supports.ts_rtc.present == 1)455ts78xx_ts_rtc_unload();456if (ts78xx_fpga.supports.ts_nand.present == 1)457ts78xx_ts_nand_unload();458if (ts78xx_fpga.supports.ts_rng.present == 1)459ts78xx_ts_rng_unload();460461return ret;462}463464static int ts78xx_fpga_load(void)465{466ts78xx_fpga.id = readl(TS78XX_FPGA_REGS_VIRT_BASE);467468pr_info("TS-78xx FPGA: magic=0x%.6x, rev=0x%.2x\n",469(ts78xx_fpga.id >> 8) & 0xffffff,470ts78xx_fpga.id & 0xff);471472ts78xx_fpga_supports();473474if (ts78xx_fpga_load_devices()) {475ts78xx_fpga.state = -1;476return -EBUSY;477}478479return 0;480};481482static int ts78xx_fpga_unload(void)483{484unsigned int fpga_id;485486fpga_id = readl(TS78XX_FPGA_REGS_VIRT_BASE);487488/*489* There does not seem to be a feasible way to block access to the GPIO490* pins from userspace (/dev/mem). This if clause should hopefully warn491* those foolish enough not to follow 'policy' :)492*493* UrJTAG SVN since r1381 can be used to reprogram the FPGA494*/495if (ts78xx_fpga.id != fpga_id) {496pr_err("TS-78xx FPGA: magic/rev mismatch\n"497"TS-78xx FPGA: was 0x%.6x/%.2x but now 0x%.6x/%.2x\n",498(ts78xx_fpga.id >> 8) & 0xffffff, ts78xx_fpga.id & 0xff,499(fpga_id >> 8) & 0xffffff, fpga_id & 0xff);500ts78xx_fpga.state = -1;501return -EBUSY;502}503504if (ts78xx_fpga_unload_devices()) {505ts78xx_fpga.state = -1;506return -EBUSY;507}508509return 0;510};511512static ssize_t ts78xx_fpga_show(struct kobject *kobj,513struct kobj_attribute *attr, char *buf)514{515if (ts78xx_fpga.state < 0)516return sprintf(buf, "borked\n");517518return sprintf(buf, "%s\n", (ts78xx_fpga.state) ? "online" : "offline");519}520521static ssize_t ts78xx_fpga_store(struct kobject *kobj,522struct kobj_attribute *attr, const char *buf, size_t n)523{524int value, ret;525526if (ts78xx_fpga.state < 0) {527pr_err("TS-78xx FPGA: borked, you must powercycle asap\n");528return -EBUSY;529}530531if (strncmp(buf, "online", sizeof("online") - 1) == 0)532value = 1;533else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)534value = 0;535else {536pr_err("ts78xx_fpga_store: Invalid value\n");537return -EINVAL;538}539540if (ts78xx_fpga.state == value)541return n;542543ret = (ts78xx_fpga.state == 0)544? ts78xx_fpga_load()545: ts78xx_fpga_unload();546547if (!(ret < 0))548ts78xx_fpga.state = value;549550return n;551}552553static struct kobj_attribute ts78xx_fpga_attr =554__ATTR(ts78xx_fpga, 0644, ts78xx_fpga_show, ts78xx_fpga_store);555556/*****************************************************************************557* General Setup558****************************************************************************/559static unsigned int ts78xx_mpp_modes[] __initdata = {560MPP0_UNUSED,561MPP1_GPIO, /* JTAG Clock */562MPP2_GPIO, /* JTAG Data In */563MPP3_GPIO, /* Lat ECP2 256 FPGA - PB2B */564MPP4_GPIO, /* JTAG Data Out */565MPP5_GPIO, /* JTAG TMS */566MPP6_GPIO, /* Lat ECP2 256 FPGA - PB31A_CLK4+ */567MPP7_GPIO, /* Lat ECP2 256 FPGA - PB22B */568MPP8_UNUSED,569MPP9_UNUSED,570MPP10_UNUSED,571MPP11_UNUSED,572MPP12_UNUSED,573MPP13_UNUSED,574MPP14_UNUSED,575MPP15_UNUSED,576MPP16_UART,577MPP17_UART,578MPP18_UART,579MPP19_UART,580/*581* MPP[20] PCI Clock Out 1582* MPP[21] PCI Clock Out 0583* MPP[22] Unused584* MPP[23] Unused585* MPP[24] Unused586* MPP[25] Unused587*/5880,589};590591static void __init ts78xx_init(void)592{593int ret;594595/*596* Setup basic Orion functions. Need to be called early.597*/598orion5x_init();599600orion5x_mpp_conf(ts78xx_mpp_modes);601602/*603* Configure peripherals.604*/605orion5x_ehci0_init();606orion5x_ehci1_init();607orion5x_eth_init(&ts78xx_eth_data);608orion5x_sata_init(&ts78xx_sata_data);609orion5x_uart0_init();610orion5x_uart1_init();611orion5x_xor_init();612613/* FPGA init */614ts78xx_fpga_devices_zero_init();615ret = ts78xx_fpga_load();616ret = sysfs_create_file(power_kobj, &ts78xx_fpga_attr.attr);617if (ret)618pr_err("sysfs_create_file failed: %d\n", ret);619}620621MACHINE_START(TS78XX, "Technologic Systems TS-78xx SBC")622/* Maintainer: Alexander Clouter <[email protected]> */623.boot_params = 0x00000100,624.init_machine = ts78xx_init,625.map_io = ts78xx_map_io,626.init_early = orion5x_init_early,627.init_irq = orion5x_init_irq,628.timer = &orion5x_timer,629MACHINE_END630631632