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 #include <linux/kernel.h> 12 #include <linux/init.h> 13 #include <linux/sysfs.h> 14 #include <linux/platform_device.h> 15 #include <linux/mv643xx_eth.h> 16 #include <linux/ata_platform.h> 17 #include <linux/m48t86.h> 18 #include <linux/mtd/nand.h> 19 #include <linux/mtd/partitions.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 <mach/orion5x.h> 25 #include "common.h" 26 #include "mpp.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 0xff900000 38 #define TS78XX_FPGA_REGS_SIZE SZ_1M 39 40 static 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 ****************************************************************************/ 49 static struct map_desc ts78xx_io_desc[] __initdata = { 50 { 51 .virtual = 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 58 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 ****************************************************************************/ 67 static struct mv643xx_eth_platform_data ts78xx_eth_data = { 68 .phy_addr = MV643XX_ETH_PHY_ADDR(0), 69 }; 70 71 /***************************************************************************** 72 * SATA 73 ****************************************************************************/ 74 static 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_VIRT_BASE | 0x808) 82 #define TS_RTC_DATA (TS78XX_FPGA_REGS_VIRT_BASE | 0x80c) 83 84 static unsigned char ts78xx_ts_rtc_readbyte(unsigned long addr) 85 { 86 writeb(addr, TS_RTC_CTRL); 87 return readb(TS_RTC_DATA); 88 } 89 90 static void ts78xx_ts_rtc_writebyte(unsigned char value, unsigned long addr) 91 { 92 writeb(addr, TS_RTC_CTRL); 93 writeb(value, TS_RTC_DATA); 94 } 95 96 static struct m48t86_ops ts78xx_ts_rtc_ops = { 97 .readbyte = ts78xx_ts_rtc_readbyte, 98 .writebyte = ts78xx_ts_rtc_writebyte, 99 }; 100 101 static struct platform_device ts78xx_ts_rtc_device = { 102 .name = "rtc-m48t86", 103 .id = -1, 104 .dev = { 105 .platform_data = &ts78xx_ts_rtc_ops, 106 }, 107 .num_resources = 0, 108 }; 109 110 /* 111 * TS uses some of the user storage space on the RTC chip so see if it is 112 * present; as it's an optional feature at purchase time and not all boards 113 * will have it present 114 * 115 * I've used the method TS use in their rtc7800.c example for the detection 116 * 117 * TODO: track down a guinea pig without an RTC to see if we can work out a 118 * better RTC detection routine 119 */ 120 static int ts78xx_ts_rtc_load(void) 121 { 122 int rc; 123 unsigned char tmp_rtc0, tmp_rtc1; 124 125 tmp_rtc0 = ts78xx_ts_rtc_readbyte(126); 126 tmp_rtc1 = ts78xx_ts_rtc_readbyte(127); 127 128 ts78xx_ts_rtc_writebyte(0x00, 126); 129 ts78xx_ts_rtc_writebyte(0x55, 127); 130 if (ts78xx_ts_rtc_readbyte(127) == 0x55) { 131 ts78xx_ts_rtc_writebyte(0xaa, 127); 132 if (ts78xx_ts_rtc_readbyte(127) == 0xaa 133 && ts78xx_ts_rtc_readbyte(126) == 0x00) { 134 ts78xx_ts_rtc_writebyte(tmp_rtc0, 126); 135 ts78xx_ts_rtc_writebyte(tmp_rtc1, 127); 136 137 if (ts78xx_fpga.supports.ts_rtc.init == 0) { 138 rc = platform_device_register(&ts78xx_ts_rtc_device); 139 if (!rc) 140 ts78xx_fpga.supports.ts_rtc.init = 1; 141 } else 142 rc = platform_device_add(&ts78xx_ts_rtc_device); 143 144 return rc; 145 } 146 } 147 148 return -ENODEV; 149 }; 150 151 static void ts78xx_ts_rtc_unload(void) 152 { 153 platform_device_del(&ts78xx_ts_rtc_device); 154 } 155 156 /***************************************************************************** 157 * NAND Flash 158 ****************************************************************************/ 159 #define TS_NAND_CTRL (TS78XX_FPGA_REGS_VIRT_BASE | 0x800) /* VIRT */ 160 #define TS_NAND_DATA (TS78XX_FPGA_REGS_PHYS_BASE | 0x804) /* PHYS */ 161 162 /* 163 * hardware specific access to control-lines 164 * 165 * ctrl: 166 * NAND_NCE: bit 0 -> bit 2 167 * NAND_CLE: bit 1 -> bit 1 168 * NAND_ALE: bit 2 -> bit 0 169 */ 170 static void ts78xx_ts_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, 171 unsigned int ctrl) 172 { 173 struct nand_chip *this = mtd->priv; 174 175 if (ctrl & NAND_CTRL_CHANGE) { 176 unsigned char bits; 177 178 bits = (ctrl & NAND_NCE) << 2; 179 bits |= ctrl & NAND_CLE; 180 bits |= (ctrl & NAND_ALE) >> 2; 181 182 writeb((readb(TS_NAND_CTRL) & ~0x7) | bits, TS_NAND_CTRL); 183 } 184 185 if (cmd != NAND_CMD_NONE) 186 writeb(cmd, this->IO_ADDR_W); 187 } 188 189 static int ts78xx_ts_nand_dev_ready(struct mtd_info *mtd) 190 { 191 return readb(TS_NAND_CTRL) & 0x20; 192 } 193 194 const char *ts_nand_part_probes[] = { "cmdlinepart", NULL }; 195 196 static struct mtd_partition ts78xx_ts_nand_parts[] = { 197 { 198 .name = "mbr", 199 .offset = 0, 200 .size = SZ_128K, 201 .mask_flags = MTD_WRITEABLE, 202 }, { 203 .name = "kernel", 204 .offset = MTDPART_OFS_APPEND, 205 .size = SZ_4M, 206 }, { 207 .name = "initrd", 208 .offset = MTDPART_OFS_APPEND, 209 .size = SZ_4M, 210 }, { 211 .name = "rootfs", 212 .offset = MTDPART_OFS_APPEND, 213 .size = MTDPART_SIZ_FULL, 214 } 215 }; 216 217 static struct platform_nand_data ts78xx_ts_nand_data = { 218 .chip = { 219 .nr_chips = 1, 220 .part_probe_types = ts_nand_part_probes, 221 .partitions = ts78xx_ts_nand_parts, 222 .nr_partitions = ARRAY_SIZE(ts78xx_ts_nand_parts), 223 .chip_delay = 15, 224 .options = NAND_USE_FLASH_BBT, 225 }, 226 .ctrl = { 227 /* 228 * The HW ECC offloading functions, used to give about a 9% 229 * performance increase for 'dd if=/dev/mtdblockX' and 5% for 230 * nanddump. This all however was changed by git commit 231 * e6cf5df1838c28bb060ac45b5585e48e71bbc740 so now there is 232 * no performance advantage to be had so we no longer bother 233 */ 234 .cmd_ctrl = ts78xx_ts_nand_cmd_ctrl, 235 .dev_ready = ts78xx_ts_nand_dev_ready, 236 }, 237 }; 238 239 static struct resource ts78xx_ts_nand_resources = { 240 .start = TS_NAND_DATA, 241 .end = TS_NAND_DATA + 4, 242 .flags = IORESOURCE_MEM, 243 }; 244 245 static struct platform_device ts78xx_ts_nand_device = { 246 .name = "gen_nand", 247 .id = -1, 248 .dev = { 249 .platform_data = &ts78xx_ts_nand_data, 250 }, 251 .resource = &ts78xx_ts_nand_resources, 252 .num_resources = 1, 253 }; 254 255 static int ts78xx_ts_nand_load(void) 256 { 257 int rc; 258 259 if (ts78xx_fpga.supports.ts_nand.init == 0) { 260 rc = platform_device_register(&ts78xx_ts_nand_device); 261 if (!rc) 262 ts78xx_fpga.supports.ts_nand.init = 1; 263 } else 264 rc = platform_device_add(&ts78xx_ts_nand_device); 265 266 return rc; 267 }; 268 269 static void ts78xx_ts_nand_unload(void) 270 { 271 platform_device_del(&ts78xx_ts_nand_device); 272 } 273 274 /***************************************************************************** 275 * HW RNG 276 ****************************************************************************/ 277 #define TS_RNG_DATA (TS78XX_FPGA_REGS_PHYS_BASE | 0x044) 278 279 static struct resource ts78xx_ts_rng_resource = { 280 .flags = IORESOURCE_MEM, 281 .start = TS_RNG_DATA, 282 .end = TS_RNG_DATA + 4 - 1, 283 }; 284 285 static struct timeriomem_rng_data ts78xx_ts_rng_data = { 286 .period = 1000000, /* one second */ 287 }; 288 289 static struct platform_device ts78xx_ts_rng_device = { 290 .name = "timeriomem_rng", 291 .id = -1, 292 .dev = { 293 .platform_data = &ts78xx_ts_rng_data, 294 }, 295 .resource = &ts78xx_ts_rng_resource, 296 .num_resources = 1, 297 }; 298 299 static int ts78xx_ts_rng_load(void) 300 { 301 int rc; 302 303 if (ts78xx_fpga.supports.ts_rng.init == 0) { 304 rc = platform_device_register(&ts78xx_ts_rng_device); 305 if (!rc) 306 ts78xx_fpga.supports.ts_rng.init = 1; 307 } else 308 rc = platform_device_add(&ts78xx_ts_rng_device); 309 310 return rc; 311 }; 312 313 static void ts78xx_ts_rng_unload(void) 314 { 315 platform_device_del(&ts78xx_ts_rng_device); 316 } 317 318 /***************************************************************************** 319 * FPGA 'hotplug' support code 320 ****************************************************************************/ 321 static void ts78xx_fpga_devices_zero_init(void) 322 { 323 ts78xx_fpga.supports.ts_rtc.init = 0; 324 ts78xx_fpga.supports.ts_nand.init = 0; 325 ts78xx_fpga.supports.ts_rng.init = 0; 326 } 327 328 static void ts78xx_fpga_supports(void) 329 { 330 /* TODO: put this 'table' into ts78xx-fpga.h */ 331 switch (ts78xx_fpga.id) { 332 case TS7800_REV_1: 333 case TS7800_REV_2: 334 case TS7800_REV_3: 335 case TS7800_REV_4: 336 case TS7800_REV_5: 337 ts78xx_fpga.supports.ts_rtc.present = 1; 338 ts78xx_fpga.supports.ts_nand.present = 1; 339 ts78xx_fpga.supports.ts_rng.present = 1; 340 break; 341 default: 342 ts78xx_fpga.supports.ts_rtc.present = 0; 343 ts78xx_fpga.supports.ts_nand.present = 0; 344 ts78xx_fpga.supports.ts_rng.present = 0; 345 } 346 } 347 348 static int ts78xx_fpga_load_devices(void) 349 { 350 int tmp, ret = 0; 351 352 if (ts78xx_fpga.supports.ts_rtc.present == 1) { 353 tmp = ts78xx_ts_rtc_load(); 354 if (tmp) { 355 printk(KERN_INFO "TS-78xx: RTC not registered\n"); 356 ts78xx_fpga.supports.ts_rtc.present = 0; 357 } 358 ret |= tmp; 359 } 360 if (ts78xx_fpga.supports.ts_nand.present == 1) { 361 tmp = ts78xx_ts_nand_load(); 362 if (tmp) { 363 printk(KERN_INFO "TS-78xx: NAND not registered\n"); 364 ts78xx_fpga.supports.ts_nand.present = 0; 365 } 366 ret |= tmp; 367 } 368 if (ts78xx_fpga.supports.ts_rng.present == 1) { 369 tmp = ts78xx_ts_rng_load(); 370 if (tmp) { 371 printk(KERN_INFO "TS-78xx: RNG not registered\n"); 372 ts78xx_fpga.supports.ts_rng.present = 0; 373 } 374 ret |= tmp; 375 } 376 377 return ret; 378 } 379 380 static int ts78xx_fpga_unload_devices(void) 381 { 382 int ret = 0; 383 384 if (ts78xx_fpga.supports.ts_rtc.present == 1) 385 ts78xx_ts_rtc_unload(); 386 if (ts78xx_fpga.supports.ts_nand.present == 1) 387 ts78xx_ts_nand_unload(); 388 if (ts78xx_fpga.supports.ts_rng.present == 1) 389 ts78xx_ts_rng_unload(); 390 391 return ret; 392 } 393 394 static int ts78xx_fpga_load(void) 395 { 396 ts78xx_fpga.id = readl(TS78XX_FPGA_REGS_VIRT_BASE); 397 398 printk(KERN_INFO "TS-78xx FPGA: magic=0x%.6x, rev=0x%.2x\n", 399 (ts78xx_fpga.id >> 8) & 0xffffff, 400 ts78xx_fpga.id & 0xff); 401 402 ts78xx_fpga_supports(); 403 404 if (ts78xx_fpga_load_devices()) { 405 ts78xx_fpga.state = -1; 406 return -EBUSY; 407 } 408 409 return 0; 410 }; 411 412 static int ts78xx_fpga_unload(void) 413 { 414 unsigned int fpga_id; 415 416 fpga_id = readl(TS78XX_FPGA_REGS_VIRT_BASE); 417 418 /* 419 * There does not seem to be a feasible way to block access to the GPIO 420 * pins from userspace (/dev/mem). This if clause should hopefully warn 421 * those foolish enough not to follow 'policy' :) 422 * 423 * UrJTAG SVN since r1381 can be used to reprogram the FPGA 424 */ 425 if (ts78xx_fpga.id != fpga_id) { 426 printk(KERN_ERR "TS-78xx FPGA: magic/rev mismatch\n" 427 "TS-78xx FPGA: was 0x%.6x/%.2x but now 0x%.6x/%.2x\n", 428 (ts78xx_fpga.id >> 8) & 0xffffff, ts78xx_fpga.id & 0xff, 429 (fpga_id >> 8) & 0xffffff, fpga_id & 0xff); 430 ts78xx_fpga.state = -1; 431 return -EBUSY; 432 } 433 434 if (ts78xx_fpga_unload_devices()) { 435 ts78xx_fpga.state = -1; 436 return -EBUSY; 437 } 438 439 return 0; 440 }; 441 442 static ssize_t ts78xx_fpga_show(struct kobject *kobj, 443 struct kobj_attribute *attr, char *buf) 444 { 445 if (ts78xx_fpga.state < 0) 446 return sprintf(buf, "borked\n"); 447 448 return sprintf(buf, "%s\n", (ts78xx_fpga.state) ? "online" : "offline"); 449 } 450 451 static ssize_t ts78xx_fpga_store(struct kobject *kobj, 452 struct kobj_attribute *attr, const char *buf, size_t n) 453 { 454 int value, ret; 455 456 if (ts78xx_fpga.state < 0) { 457 printk(KERN_ERR "TS-78xx FPGA: borked, you must powercycle asap\n"); 458 return -EBUSY; 459 } 460 461 if (strncmp(buf, "online", sizeof("online") - 1) == 0) 462 value = 1; 463 else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0) 464 value = 0; 465 else { 466 printk(KERN_ERR "ts78xx_fpga_store: Invalid value\n"); 467 return -EINVAL; 468 } 469 470 if (ts78xx_fpga.state == value) 471 return n; 472 473 ret = (ts78xx_fpga.state == 0) 474 ? ts78xx_fpga_load() 475 : ts78xx_fpga_unload(); 476 477 if (!(ret < 0)) 478 ts78xx_fpga.state = value; 479 480 return n; 481 } 482 483 static struct kobj_attribute ts78xx_fpga_attr = 484 __ATTR(ts78xx_fpga, 0644, ts78xx_fpga_show, ts78xx_fpga_store); 485 486 /***************************************************************************** 487 * General Setup 488 ****************************************************************************/ 489 static struct orion5x_mpp_mode ts78xx_mpp_modes[] __initdata = { 490 { 0, MPP_UNUSED }, 491 { 1, MPP_GPIO }, /* JTAG Clock */ 492 { 2, MPP_GPIO }, /* JTAG Data In */ 493 { 3, MPP_GPIO }, /* Lat ECP2 256 FPGA - PB2B */ 494 { 4, MPP_GPIO }, /* JTAG Data Out */ 495 { 5, MPP_GPIO }, /* JTAG TMS */ 496 { 6, MPP_GPIO }, /* Lat ECP2 256 FPGA - PB31A_CLK4+ */ 497 { 7, MPP_GPIO }, /* Lat ECP2 256 FPGA - PB22B */ 498 { 8, MPP_UNUSED }, 499 { 9, MPP_UNUSED }, 500 { 10, MPP_UNUSED }, 501 { 11, MPP_UNUSED }, 502 { 12, MPP_UNUSED }, 503 { 13, MPP_UNUSED }, 504 { 14, MPP_UNUSED }, 505 { 15, MPP_UNUSED }, 506 { 16, MPP_UART }, 507 { 17, MPP_UART }, 508 { 18, MPP_UART }, 509 { 19, MPP_UART }, 510 /* 511 * MPP[20] PCI Clock Out 1 512 * MPP[21] PCI Clock Out 0 513 * MPP[22] Unused 514 * MPP[23] Unused 515 * MPP[24] Unused 516 * MPP[25] Unused 517 */ 518 { -1 }, 519 }; 520 521 static void __init ts78xx_init(void) 522 { 523 int ret; 524 525 /* 526 * Setup basic Orion functions. Need to be called early. 527 */ 528 orion5x_init(); 529 530 orion5x_mpp_conf(ts78xx_mpp_modes); 531 532 /* 533 * Configure peripherals. 534 */ 535 orion5x_ehci0_init(); 536 orion5x_ehci1_init(); 537 orion5x_eth_init(&ts78xx_eth_data); 538 orion5x_sata_init(&ts78xx_sata_data); 539 orion5x_uart0_init(); 540 orion5x_uart1_init(); 541 orion5x_xor_init(); 542 543 /* FPGA init */ 544 ts78xx_fpga_devices_zero_init(); 545 ret = ts78xx_fpga_load(); 546 ret = sysfs_create_file(power_kobj, &ts78xx_fpga_attr.attr); 547 if (ret) 548 printk(KERN_ERR "sysfs_create_file failed: %d\n", ret); 549 } 550 551 MACHINE_START(TS78XX, "Technologic Systems TS-78xx SBC") 552 /* Maintainer: Alexander Clouter <alex@digriz.org.uk> */ 553 .boot_params = 0x00000100, 554 .init_machine = ts78xx_init, 555 .map_io = ts78xx_map_io, 556 .init_irq = orion5x_init_irq, 557 .timer = &orion5x_timer, 558 MACHINE_END 559