1/* 2 * arch/arm/mach-orion5x/ts78xx-setup.c 3 * 4 * Maintainer: Alexander Clouter <alex@digriz.org.uk> 5 * 6 * This file is licensed under the terms of the GNU General Public 7 * License version 2. This program is licensed "as is" without any 8 * warranty of any kind, whether express or implied. 9 */ 10 11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 12 13#include <linux/kernel.h> 14#include <linux/init.h> 15#include <linux/sysfs.h> 16#include <linux/platform_device.h> 17#include <linux/mv643xx_eth.h> 18#include <linux/ata_platform.h> 19#include <linux/m48t86.h> 20#include <linux/mtd/nand.h> 21#include <linux/mtd/partitions.h> 22#include <linux/timeriomem-rng.h> 23#include <asm/mach-types.h> 24#include <asm/mach/arch.h> 25#include <asm/mach/map.h> 26#include <mach/orion5x.h> 27#include "common.h" 28#include "mpp.h" 29#include "ts78xx-fpga.h" 30 31/***************************************************************************** 32 * TS-78xx Info 33 ****************************************************************************/ 34 35/* 36 * FPGA - lives where the PCI bus would be at ORION5X_PCI_MEM_PHYS_BASE 37 */ 38#define TS78XX_FPGA_REGS_PHYS_BASE 0xe8000000 39#define TS78XX_FPGA_REGS_VIRT_BASE IOMEM(0xff900000) 40#define TS78XX_FPGA_REGS_SIZE SZ_1M 41 42static struct ts78xx_fpga_data ts78xx_fpga = { 43 .id = 0, 44 .state = 1, 45/* .supports = ... - populated by ts78xx_fpga_supports() */ 46}; 47 48/***************************************************************************** 49 * I/O Address Mapping 50 ****************************************************************************/ 51static struct map_desc ts78xx_io_desc[] __initdata = { 52 { 53 .virtual = (unsigned long)TS78XX_FPGA_REGS_VIRT_BASE, 54 .pfn = __phys_to_pfn(TS78XX_FPGA_REGS_PHYS_BASE), 55 .length = TS78XX_FPGA_REGS_SIZE, 56 .type = MT_DEVICE, 57 }, 58}; 59 60static void __init ts78xx_map_io(void) 61{ 62 orion5x_map_io(); 63 iotable_init(ts78xx_io_desc, ARRAY_SIZE(ts78xx_io_desc)); 64} 65 66/***************************************************************************** 67 * Ethernet 68 ****************************************************************************/ 69static struct mv643xx_eth_platform_data ts78xx_eth_data = { 70 .phy_addr = MV643XX_ETH_PHY_ADDR(0), 71}; 72 73/***************************************************************************** 74 * SATA 75 ****************************************************************************/ 76static struct mv_sata_platform_data ts78xx_sata_data = { 77 .n_ports = 2, 78}; 79 80/***************************************************************************** 81 * RTC M48T86 - nicked^Wborrowed from arch/arm/mach-ep93xx/ts72xx.c 82 ****************************************************************************/ 83#define TS_RTC_CTRL (TS78XX_FPGA_REGS_VIRT_BASE + 0x808) 84#define TS_RTC_DATA (TS78XX_FPGA_REGS_VIRT_BASE + 0x80c) 85 86static unsigned char ts78xx_ts_rtc_readbyte(unsigned long addr) 87{ 88 writeb(addr, TS_RTC_CTRL); 89 return readb(TS_RTC_DATA); 90} 91 92static void ts78xx_ts_rtc_writebyte(unsigned char value, unsigned long addr) 93{ 94 writeb(addr, TS_RTC_CTRL); 95 writeb(value, TS_RTC_DATA); 96} 97 98static struct m48t86_ops ts78xx_ts_rtc_ops = { 99 .readbyte = ts78xx_ts_rtc_readbyte, 100 .writebyte = ts78xx_ts_rtc_writebyte, 101}; 102 103static struct platform_device ts78xx_ts_rtc_device = { 104 .name = "rtc-m48t86", 105 .id = -1, 106 .dev = { 107 .platform_data = &ts78xx_ts_rtc_ops, 108 }, 109 .num_resources = 0, 110}; 111 112/* 113 * TS uses some of the user storage space on the RTC chip so see if it is 114 * present; as it's an optional feature at purchase time and not all boards 115 * will have it present 116 * 117 * I've used the method TS use in their rtc7800.c example for the detection 118 * 119 * TODO: track down a guinea pig without an RTC to see if we can work out a 120 * better RTC detection routine 121 */ 122static int ts78xx_ts_rtc_load(void) 123{ 124 int rc; 125 unsigned char tmp_rtc0, tmp_rtc1; 126 127 tmp_rtc0 = ts78xx_ts_rtc_readbyte(126); 128 tmp_rtc1 = ts78xx_ts_rtc_readbyte(127); 129 130 ts78xx_ts_rtc_writebyte(0x00, 126); 131 ts78xx_ts_rtc_writebyte(0x55, 127); 132 if (ts78xx_ts_rtc_readbyte(127) == 0x55) { 133 ts78xx_ts_rtc_writebyte(0xaa, 127); 134 if (ts78xx_ts_rtc_readbyte(127) == 0xaa 135 && ts78xx_ts_rtc_readbyte(126) == 0x00) { 136 ts78xx_ts_rtc_writebyte(tmp_rtc0, 126); 137 ts78xx_ts_rtc_writebyte(tmp_rtc1, 127); 138 139 if (ts78xx_fpga.supports.ts_rtc.init == 0) { 140 rc = platform_device_register(&ts78xx_ts_rtc_device); 141 if (!rc) 142 ts78xx_fpga.supports.ts_rtc.init = 1; 143 } else 144 rc = platform_device_add(&ts78xx_ts_rtc_device); 145 146 if (rc) 147 pr_info("RTC could not be registered: %d\n", 148 rc); 149 return rc; 150 } 151 } 152 153 pr_info("RTC not found\n"); 154 return -ENODEV; 155}; 156 157static void ts78xx_ts_rtc_unload(void) 158{ 159 platform_device_del(&ts78xx_ts_rtc_device); 160} 161 162/***************************************************************************** 163 * NAND Flash 164 ****************************************************************************/ 165#define TS_NAND_CTRL (TS78XX_FPGA_REGS_VIRT_BASE + 0x800) /* VIRT */ 166#define TS_NAND_DATA (TS78XX_FPGA_REGS_PHYS_BASE + 0x804) /* PHYS */ 167 168/* 169 * hardware specific access to control-lines 170 * 171 * ctrl: 172 * NAND_NCE: bit 0 -> bit 2 173 * NAND_CLE: bit 1 -> bit 1 174 * NAND_ALE: bit 2 -> bit 0 175 */ 176static void ts78xx_ts_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, 177 unsigned int ctrl) 178{ 179 struct nand_chip *this = mtd->priv; 180 181 if (ctrl & NAND_CTRL_CHANGE) { 182 unsigned char bits; 183 184 bits = (ctrl & NAND_NCE) << 2; 185 bits |= ctrl & NAND_CLE; 186 bits |= (ctrl & NAND_ALE) >> 2; 187 188 writeb((readb(TS_NAND_CTRL) & ~0x7) | bits, TS_NAND_CTRL); 189 } 190 191 if (cmd != NAND_CMD_NONE) 192 writeb(cmd, this->IO_ADDR_W); 193} 194 195static int ts78xx_ts_nand_dev_ready(struct mtd_info *mtd) 196{ 197 return readb(TS_NAND_CTRL) & 0x20; 198} 199 200static void ts78xx_ts_nand_write_buf(struct mtd_info *mtd, 201 const uint8_t *buf, int len) 202{ 203 struct nand_chip *chip = mtd->priv; 204 void __iomem *io_base = chip->IO_ADDR_W; 205 unsigned long off = ((unsigned long)buf & 3); 206 int sz; 207 208 if (off) { 209 sz = min_t(int, 4 - off, len); 210 writesb(io_base, buf, sz); 211 buf += sz; 212 len -= sz; 213 } 214 215 sz = len >> 2; 216 if (sz) { 217 u32 *buf32 = (u32 *)buf; 218 writesl(io_base, buf32, sz); 219 buf += sz << 2; 220 len -= sz << 2; 221 } 222 223 if (len) 224 writesb(io_base, buf, len); 225} 226 227static void ts78xx_ts_nand_read_buf(struct mtd_info *mtd, 228 uint8_t *buf, int len) 229{ 230 struct nand_chip *chip = mtd->priv; 231 void __iomem *io_base = chip->IO_ADDR_R; 232 unsigned long off = ((unsigned long)buf & 3); 233 int sz; 234 235 if (off) { 236 sz = min_t(int, 4 - off, len); 237 readsb(io_base, buf, sz); 238 buf += sz; 239 len -= sz; 240 } 241 242 sz = len >> 2; 243 if (sz) { 244 u32 *buf32 = (u32 *)buf; 245 readsl(io_base, buf32, sz); 246 buf += sz << 2; 247 len -= sz << 2; 248 } 249 250 if (len) 251 readsb(io_base, buf, len); 252} 253 254static struct mtd_partition ts78xx_ts_nand_parts[] = { 255 { 256 .name = "mbr", 257 .offset = 0, 258 .size = SZ_128K, 259 .mask_flags = MTD_WRITEABLE, 260 }, { 261 .name = "kernel", 262 .offset = MTDPART_OFS_APPEND, 263 .size = SZ_4M, 264 }, { 265 .name = "initrd", 266 .offset = MTDPART_OFS_APPEND, 267 .size = SZ_4M, 268 }, { 269 .name = "rootfs", 270 .offset = MTDPART_OFS_APPEND, 271 .size = MTDPART_SIZ_FULL, 272 } 273}; 274 275static struct platform_nand_data ts78xx_ts_nand_data = { 276 .chip = { 277 .nr_chips = 1, 278 .partitions = ts78xx_ts_nand_parts, 279 .nr_partitions = ARRAY_SIZE(ts78xx_ts_nand_parts), 280 .chip_delay = 15, 281 .bbt_options = NAND_BBT_USE_FLASH, 282 }, 283 .ctrl = { 284 /* 285 * The HW ECC offloading functions, used to give about a 9% 286 * performance increase for 'dd if=/dev/mtdblockX' and 5% for 287 * nanddump. This all however was changed by git commit 288 * e6cf5df1838c28bb060ac45b5585e48e71bbc740 so now there is 289 * no performance advantage to be had so we no longer bother 290 */ 291 .cmd_ctrl = ts78xx_ts_nand_cmd_ctrl, 292 .dev_ready = ts78xx_ts_nand_dev_ready, 293 .write_buf = ts78xx_ts_nand_write_buf, 294 .read_buf = ts78xx_ts_nand_read_buf, 295 }, 296}; 297 298static struct resource ts78xx_ts_nand_resources 299 = DEFINE_RES_MEM(TS_NAND_DATA, 4); 300 301static struct platform_device ts78xx_ts_nand_device = { 302 .name = "gen_nand", 303 .id = -1, 304 .dev = { 305 .platform_data = &ts78xx_ts_nand_data, 306 }, 307 .resource = &ts78xx_ts_nand_resources, 308 .num_resources = 1, 309}; 310 311static int ts78xx_ts_nand_load(void) 312{ 313 int rc; 314 315 if (ts78xx_fpga.supports.ts_nand.init == 0) { 316 rc = platform_device_register(&ts78xx_ts_nand_device); 317 if (!rc) 318 ts78xx_fpga.supports.ts_nand.init = 1; 319 } else 320 rc = platform_device_add(&ts78xx_ts_nand_device); 321 322 if (rc) 323 pr_info("NAND could not be registered: %d\n", rc); 324 return rc; 325}; 326 327static void ts78xx_ts_nand_unload(void) 328{ 329 platform_device_del(&ts78xx_ts_nand_device); 330} 331 332/***************************************************************************** 333 * HW RNG 334 ****************************************************************************/ 335#define TS_RNG_DATA (TS78XX_FPGA_REGS_PHYS_BASE | 0x044) 336 337static struct resource ts78xx_ts_rng_resource 338 = DEFINE_RES_MEM(TS_RNG_DATA, 4); 339 340static struct timeriomem_rng_data ts78xx_ts_rng_data = { 341 .period = 1000000, /* one second */ 342}; 343 344static 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}; 353 354static int ts78xx_ts_rng_load(void) 355{ 356 int rc; 357 358 if (ts78xx_fpga.supports.ts_rng.init == 0) { 359 rc = platform_device_register(&ts78xx_ts_rng_device); 360 if (!rc) 361 ts78xx_fpga.supports.ts_rng.init = 1; 362 } else 363 rc = platform_device_add(&ts78xx_ts_rng_device); 364 365 if (rc) 366 pr_info("RNG could not be registered: %d\n", rc); 367 return rc; 368}; 369 370static void ts78xx_ts_rng_unload(void) 371{ 372 platform_device_del(&ts78xx_ts_rng_device); 373} 374 375/***************************************************************************** 376 * FPGA 'hotplug' support code 377 ****************************************************************************/ 378static void ts78xx_fpga_devices_zero_init(void) 379{ 380 ts78xx_fpga.supports.ts_rtc.init = 0; 381 ts78xx_fpga.supports.ts_nand.init = 0; 382 ts78xx_fpga.supports.ts_rng.init = 0; 383} 384 385static void ts78xx_fpga_supports(void) 386{ 387 /* TODO: put this 'table' into ts78xx-fpga.h */ 388 switch (ts78xx_fpga.id) { 389 case TS7800_REV_1: 390 case TS7800_REV_2: 391 case TS7800_REV_3: 392 case TS7800_REV_4: 393 case TS7800_REV_5: 394 case TS7800_REV_6: 395 case TS7800_REV_7: 396 case TS7800_REV_8: 397 case TS7800_REV_9: 398 ts78xx_fpga.supports.ts_rtc.present = 1; 399 ts78xx_fpga.supports.ts_nand.present = 1; 400 ts78xx_fpga.supports.ts_rng.present = 1; 401 break; 402 default: 403 /* enable devices if magic matches */ 404 switch ((ts78xx_fpga.id >> 8) & 0xffffff) { 405 case TS7800_FPGA_MAGIC: 406 pr_warn("unrecognised FPGA revision 0x%.2x\n", 407 ts78xx_fpga.id & 0xff); 408 ts78xx_fpga.supports.ts_rtc.present = 1; 409 ts78xx_fpga.supports.ts_nand.present = 1; 410 ts78xx_fpga.supports.ts_rng.present = 1; 411 break; 412 default: 413 ts78xx_fpga.supports.ts_rtc.present = 0; 414 ts78xx_fpga.supports.ts_nand.present = 0; 415 ts78xx_fpga.supports.ts_rng.present = 0; 416 } 417 } 418} 419 420static int ts78xx_fpga_load_devices(void) 421{ 422 int tmp, ret = 0; 423 424 if (ts78xx_fpga.supports.ts_rtc.present == 1) { 425 tmp = ts78xx_ts_rtc_load(); 426 if (tmp) 427 ts78xx_fpga.supports.ts_rtc.present = 0; 428 ret |= tmp; 429 } 430 if (ts78xx_fpga.supports.ts_nand.present == 1) { 431 tmp = ts78xx_ts_nand_load(); 432 if (tmp) 433 ts78xx_fpga.supports.ts_nand.present = 0; 434 ret |= tmp; 435 } 436 if (ts78xx_fpga.supports.ts_rng.present == 1) { 437 tmp = ts78xx_ts_rng_load(); 438 if (tmp) 439 ts78xx_fpga.supports.ts_rng.present = 0; 440 ret |= tmp; 441 } 442 443 return ret; 444} 445 446static int ts78xx_fpga_unload_devices(void) 447{ 448 int ret = 0; 449 450 if (ts78xx_fpga.supports.ts_rtc.present == 1) 451 ts78xx_ts_rtc_unload(); 452 if (ts78xx_fpga.supports.ts_nand.present == 1) 453 ts78xx_ts_nand_unload(); 454 if (ts78xx_fpga.supports.ts_rng.present == 1) 455 ts78xx_ts_rng_unload(); 456 457 return ret; 458} 459 460static int ts78xx_fpga_load(void) 461{ 462 ts78xx_fpga.id = readl(TS78XX_FPGA_REGS_VIRT_BASE); 463 464 pr_info("FPGA magic=0x%.6x, rev=0x%.2x\n", 465 (ts78xx_fpga.id >> 8) & 0xffffff, 466 ts78xx_fpga.id & 0xff); 467 468 ts78xx_fpga_supports(); 469 470 if (ts78xx_fpga_load_devices()) { 471 ts78xx_fpga.state = -1; 472 return -EBUSY; 473 } 474 475 return 0; 476}; 477 478static int ts78xx_fpga_unload(void) 479{ 480 unsigned int fpga_id; 481 482 fpga_id = readl(TS78XX_FPGA_REGS_VIRT_BASE); 483 484 /* 485 * There does not seem to be a feasible way to block access to the GPIO 486 * pins from userspace (/dev/mem). This if clause should hopefully warn 487 * those foolish enough not to follow 'policy' :) 488 * 489 * UrJTAG SVN since r1381 can be used to reprogram the FPGA 490 */ 491 if (ts78xx_fpga.id != fpga_id) { 492 pr_err("FPGA magic/rev mismatch\n" 493 "TS-78xx FPGA: was 0x%.6x/%.2x but now 0x%.6x/%.2x\n", 494 (ts78xx_fpga.id >> 8) & 0xffffff, ts78xx_fpga.id & 0xff, 495 (fpga_id >> 8) & 0xffffff, fpga_id & 0xff); 496 ts78xx_fpga.state = -1; 497 return -EBUSY; 498 } 499 500 if (ts78xx_fpga_unload_devices()) { 501 ts78xx_fpga.state = -1; 502 return -EBUSY; 503 } 504 505 return 0; 506}; 507 508static ssize_t ts78xx_fpga_show(struct kobject *kobj, 509 struct kobj_attribute *attr, char *buf) 510{ 511 if (ts78xx_fpga.state < 0) 512 return sprintf(buf, "borked\n"); 513 514 return sprintf(buf, "%s\n", (ts78xx_fpga.state) ? "online" : "offline"); 515} 516 517static ssize_t ts78xx_fpga_store(struct kobject *kobj, 518 struct kobj_attribute *attr, const char *buf, size_t n) 519{ 520 int value, ret; 521 522 if (ts78xx_fpga.state < 0) { 523 pr_err("FPGA borked, you must powercycle ASAP\n"); 524 return -EBUSY; 525 } 526 527 if (strncmp(buf, "online", sizeof("online") - 1) == 0) 528 value = 1; 529 else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0) 530 value = 0; 531 else 532 return -EINVAL; 533 534 if (ts78xx_fpga.state == value) 535 return n; 536 537 ret = (ts78xx_fpga.state == 0) 538 ? ts78xx_fpga_load() 539 : ts78xx_fpga_unload(); 540 541 if (!(ret < 0)) 542 ts78xx_fpga.state = value; 543 544 return n; 545} 546 547static struct kobj_attribute ts78xx_fpga_attr = 548 __ATTR(ts78xx_fpga, 0644, ts78xx_fpga_show, ts78xx_fpga_store); 549 550/***************************************************************************** 551 * General Setup 552 ****************************************************************************/ 553static unsigned int ts78xx_mpp_modes[] __initdata = { 554 MPP0_UNUSED, 555 MPP1_GPIO, /* JTAG Clock */ 556 MPP2_GPIO, /* JTAG Data In */ 557 MPP3_GPIO, /* Lat ECP2 256 FPGA - PB2B */ 558 MPP4_GPIO, /* JTAG Data Out */ 559 MPP5_GPIO, /* JTAG TMS */ 560 MPP6_GPIO, /* Lat ECP2 256 FPGA - PB31A_CLK4+ */ 561 MPP7_GPIO, /* Lat ECP2 256 FPGA - PB22B */ 562 MPP8_UNUSED, 563 MPP9_UNUSED, 564 MPP10_UNUSED, 565 MPP11_UNUSED, 566 MPP12_UNUSED, 567 MPP13_UNUSED, 568 MPP14_UNUSED, 569 MPP15_UNUSED, 570 MPP16_UART, 571 MPP17_UART, 572 MPP18_UART, 573 MPP19_UART, 574 /* 575 * MPP[20] PCI Clock Out 1 576 * MPP[21] PCI Clock Out 0 577 * MPP[22] Unused 578 * MPP[23] Unused 579 * MPP[24] Unused 580 * MPP[25] Unused 581 */ 582 0, 583}; 584 585static void __init ts78xx_init(void) 586{ 587 int ret; 588 589 /* 590 * Setup basic Orion functions. Need to be called early. 591 */ 592 orion5x_init(); 593 594 orion5x_mpp_conf(ts78xx_mpp_modes); 595 596 /* 597 * Configure peripherals. 598 */ 599 orion5x_ehci0_init(); 600 orion5x_ehci1_init(); 601 orion5x_eth_init(&ts78xx_eth_data); 602 orion5x_sata_init(&ts78xx_sata_data); 603 orion5x_uart0_init(); 604 orion5x_uart1_init(); 605 orion5x_xor_init(); 606 607 /* FPGA init */ 608 ts78xx_fpga_devices_zero_init(); 609 ret = ts78xx_fpga_load(); 610 ret = sysfs_create_file(firmware_kobj, &ts78xx_fpga_attr.attr); 611 if (ret) 612 pr_err("sysfs_create_file failed: %d\n", ret); 613} 614 615MACHINE_START(TS78XX, "Technologic Systems TS-78xx SBC") 616 /* Maintainer: Alexander Clouter <alex@digriz.org.uk> */ 617 .atag_offset = 0x100, 618 .init_machine = ts78xx_init, 619 .map_io = ts78xx_map_io, 620 .init_early = orion5x_init_early, 621 .init_irq = orion5x_init_irq, 622 .init_time = orion5x_timer_init, 623 .restart = orion5x_restart, 624MACHINE_END 625