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