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 .part_probe_types = ts_nand_part_probes, 220 .partitions = ts78xx_ts_nand_parts, 221 .nr_partitions = ARRAY_SIZE(ts78xx_ts_nand_parts), 222 .chip_delay = 15, 223 .options = NAND_USE_FLASH_BBT, 224 }, 225 .ctrl = { 226 /* 227 * The HW ECC offloading functions, used to give about a 9% 228 * performance increase for 'dd if=/dev/mtdblockX' and 5% for 229 * nanddump. This all however was changed by git commit 230 * e6cf5df1838c28bb060ac45b5585e48e71bbc740 so now there is 231 * no performance advantage to be had so we no longer bother 232 */ 233 .cmd_ctrl = ts78xx_ts_nand_cmd_ctrl, 234 .dev_ready = ts78xx_ts_nand_dev_ready, 235 }, 236 }; 237 238 static struct resource ts78xx_ts_nand_resources = { 239 .start = TS_NAND_DATA, 240 .end = TS_NAND_DATA + 4, 241 .flags = IORESOURCE_IO, 242 }; 243 244 static struct platform_device ts78xx_ts_nand_device = { 245 .name = "gen_nand", 246 .id = -1, 247 .dev = { 248 .platform_data = &ts78xx_ts_nand_data, 249 }, 250 .resource = &ts78xx_ts_nand_resources, 251 .num_resources = 1, 252 }; 253 254 static int ts78xx_ts_nand_load(void) 255 { 256 int rc; 257 258 if (ts78xx_fpga.supports.ts_nand.init == 0) { 259 rc = platform_device_register(&ts78xx_ts_nand_device); 260 if (!rc) 261 ts78xx_fpga.supports.ts_nand.init = 1; 262 } else 263 rc = platform_device_add(&ts78xx_ts_nand_device); 264 265 return rc; 266 }; 267 268 static void ts78xx_ts_nand_unload(void) 269 { 270 platform_device_del(&ts78xx_ts_nand_device); 271 } 272 273 /***************************************************************************** 274 * HW RNG 275 ****************************************************************************/ 276 #define TS_RNG_DATA (TS78XX_FPGA_REGS_PHYS_BASE | 0x044) 277 278 static struct resource ts78xx_ts_rng_resource = { 279 .flags = IORESOURCE_MEM, 280 .start = TS_RNG_DATA, 281 .end = TS_RNG_DATA + 4 - 1, 282 }; 283 284 static struct timeriomem_rng_data ts78xx_ts_rng_data = { 285 .period = 1000000, /* one second */ 286 }; 287 288 static struct platform_device ts78xx_ts_rng_device = { 289 .name = "timeriomem_rng", 290 .id = -1, 291 .dev = { 292 .platform_data = &ts78xx_ts_rng_data, 293 }, 294 .resource = &ts78xx_ts_rng_resource, 295 .num_resources = 1, 296 }; 297 298 static int ts78xx_ts_rng_load(void) 299 { 300 int rc; 301 302 if (ts78xx_fpga.supports.ts_rng.init == 0) { 303 rc = platform_device_register(&ts78xx_ts_rng_device); 304 if (!rc) 305 ts78xx_fpga.supports.ts_rng.init = 1; 306 } else 307 rc = platform_device_add(&ts78xx_ts_rng_device); 308 309 return rc; 310 }; 311 312 static void ts78xx_ts_rng_unload(void) 313 { 314 platform_device_del(&ts78xx_ts_rng_device); 315 } 316 317 /***************************************************************************** 318 * FPGA 'hotplug' support code 319 ****************************************************************************/ 320 static void ts78xx_fpga_devices_zero_init(void) 321 { 322 ts78xx_fpga.supports.ts_rtc.init = 0; 323 ts78xx_fpga.supports.ts_nand.init = 0; 324 ts78xx_fpga.supports.ts_rng.init = 0; 325 } 326 327 static void ts78xx_fpga_supports(void) 328 { 329 /* TODO: put this 'table' into ts78xx-fpga.h */ 330 switch (ts78xx_fpga.id) { 331 case TS7800_REV_1: 332 case TS7800_REV_2: 333 case TS7800_REV_3: 334 case TS7800_REV_4: 335 case TS7800_REV_5: 336 ts78xx_fpga.supports.ts_rtc.present = 1; 337 ts78xx_fpga.supports.ts_nand.present = 1; 338 ts78xx_fpga.supports.ts_rng.present = 1; 339 break; 340 default: 341 ts78xx_fpga.supports.ts_rtc.present = 0; 342 ts78xx_fpga.supports.ts_nand.present = 0; 343 ts78xx_fpga.supports.ts_rng.present = 0; 344 } 345 } 346 347 static int ts78xx_fpga_load_devices(void) 348 { 349 int tmp, ret = 0; 350 351 if (ts78xx_fpga.supports.ts_rtc.present == 1) { 352 tmp = ts78xx_ts_rtc_load(); 353 if (tmp) { 354 printk(KERN_INFO "TS-78xx: RTC not registered\n"); 355 ts78xx_fpga.supports.ts_rtc.present = 0; 356 } 357 ret |= tmp; 358 } 359 if (ts78xx_fpga.supports.ts_nand.present == 1) { 360 tmp = ts78xx_ts_nand_load(); 361 if (tmp) { 362 printk(KERN_INFO "TS-78xx: NAND not registered\n"); 363 ts78xx_fpga.supports.ts_nand.present = 0; 364 } 365 ret |= tmp; 366 } 367 if (ts78xx_fpga.supports.ts_rng.present == 1) { 368 tmp = ts78xx_ts_rng_load(); 369 if (tmp) { 370 printk(KERN_INFO "TS-78xx: RNG not registered\n"); 371 ts78xx_fpga.supports.ts_rng.present = 0; 372 } 373 ret |= tmp; 374 } 375 376 return ret; 377 } 378 379 static int ts78xx_fpga_unload_devices(void) 380 { 381 int ret = 0; 382 383 if (ts78xx_fpga.supports.ts_rtc.present == 1) 384 ts78xx_ts_rtc_unload(); 385 if (ts78xx_fpga.supports.ts_nand.present == 1) 386 ts78xx_ts_nand_unload(); 387 if (ts78xx_fpga.supports.ts_rng.present == 1) 388 ts78xx_ts_rng_unload(); 389 390 return ret; 391 } 392 393 static int ts78xx_fpga_load(void) 394 { 395 ts78xx_fpga.id = readl(TS78XX_FPGA_REGS_VIRT_BASE); 396 397 printk(KERN_INFO "TS-78xx FPGA: magic=0x%.6x, rev=0x%.2x\n", 398 (ts78xx_fpga.id >> 8) & 0xffffff, 399 ts78xx_fpga.id & 0xff); 400 401 ts78xx_fpga_supports(); 402 403 if (ts78xx_fpga_load_devices()) { 404 ts78xx_fpga.state = -1; 405 return -EBUSY; 406 } 407 408 return 0; 409 }; 410 411 static int ts78xx_fpga_unload(void) 412 { 413 unsigned int fpga_id; 414 415 fpga_id = readl(TS78XX_FPGA_REGS_VIRT_BASE); 416 417 /* 418 * There does not seem to be a feasible way to block access to the GPIO 419 * pins from userspace (/dev/mem). This if clause should hopefully warn 420 * those foolish enough not to follow 'policy' :) 421 * 422 * UrJTAG SVN since r1381 can be used to reprogram the FPGA 423 */ 424 if (ts78xx_fpga.id != fpga_id) { 425 printk(KERN_ERR "TS-78xx FPGA: magic/rev mismatch\n" 426 "TS-78xx FPGA: was 0x%.6x/%.2x but now 0x%.6x/%.2x\n", 427 (ts78xx_fpga.id >> 8) & 0xffffff, ts78xx_fpga.id & 0xff, 428 (fpga_id >> 8) & 0xffffff, fpga_id & 0xff); 429 ts78xx_fpga.state = -1; 430 return -EBUSY; 431 } 432 433 if (ts78xx_fpga_unload_devices()) { 434 ts78xx_fpga.state = -1; 435 return -EBUSY; 436 } 437 438 return 0; 439 }; 440 441 static ssize_t ts78xx_fpga_show(struct kobject *kobj, 442 struct kobj_attribute *attr, char *buf) 443 { 444 if (ts78xx_fpga.state < 0) 445 return sprintf(buf, "borked\n"); 446 447 return sprintf(buf, "%s\n", (ts78xx_fpga.state) ? "online" : "offline"); 448 } 449 450 static ssize_t ts78xx_fpga_store(struct kobject *kobj, 451 struct kobj_attribute *attr, const char *buf, size_t n) 452 { 453 int value, ret; 454 455 if (ts78xx_fpga.state < 0) { 456 printk(KERN_ERR "TS-78xx FPGA: borked, you must powercycle asap\n"); 457 return -EBUSY; 458 } 459 460 if (strncmp(buf, "online", sizeof("online") - 1) == 0) 461 value = 1; 462 else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0) 463 value = 0; 464 else { 465 printk(KERN_ERR "ts78xx_fpga_store: Invalid value\n"); 466 return -EINVAL; 467 } 468 469 if (ts78xx_fpga.state == value) 470 return n; 471 472 ret = (ts78xx_fpga.state == 0) 473 ? ts78xx_fpga_load() 474 : ts78xx_fpga_unload(); 475 476 if (!(ret < 0)) 477 ts78xx_fpga.state = value; 478 479 return n; 480 } 481 482 static struct kobj_attribute ts78xx_fpga_attr = 483 __ATTR(ts78xx_fpga, 0644, ts78xx_fpga_show, ts78xx_fpga_store); 484 485 /***************************************************************************** 486 * General Setup 487 ****************************************************************************/ 488 static struct orion5x_mpp_mode ts78xx_mpp_modes[] __initdata = { 489 { 0, MPP_UNUSED }, 490 { 1, MPP_GPIO }, /* JTAG Clock */ 491 { 2, MPP_GPIO }, /* JTAG Data In */ 492 { 3, MPP_GPIO }, /* Lat ECP2 256 FPGA - PB2B */ 493 { 4, MPP_GPIO }, /* JTAG Data Out */ 494 { 5, MPP_GPIO }, /* JTAG TMS */ 495 { 6, MPP_GPIO }, /* Lat ECP2 256 FPGA - PB31A_CLK4+ */ 496 { 7, MPP_GPIO }, /* Lat ECP2 256 FPGA - PB22B */ 497 { 8, MPP_UNUSED }, 498 { 9, MPP_UNUSED }, 499 { 10, MPP_UNUSED }, 500 { 11, MPP_UNUSED }, 501 { 12, MPP_UNUSED }, 502 { 13, MPP_UNUSED }, 503 { 14, MPP_UNUSED }, 504 { 15, MPP_UNUSED }, 505 { 16, MPP_UART }, 506 { 17, MPP_UART }, 507 { 18, MPP_UART }, 508 { 19, MPP_UART }, 509 /* 510 * MPP[20] PCI Clock Out 1 511 * MPP[21] PCI Clock Out 0 512 * MPP[22] Unused 513 * MPP[23] Unused 514 * MPP[24] Unused 515 * MPP[25] Unused 516 */ 517 { -1 }, 518 }; 519 520 static void __init ts78xx_init(void) 521 { 522 int ret; 523 524 /* 525 * Setup basic Orion functions. Need to be called early. 526 */ 527 orion5x_init(); 528 529 orion5x_mpp_conf(ts78xx_mpp_modes); 530 531 /* 532 * Configure peripherals. 533 */ 534 orion5x_ehci0_init(); 535 orion5x_ehci1_init(); 536 orion5x_eth_init(&ts78xx_eth_data); 537 orion5x_sata_init(&ts78xx_sata_data); 538 orion5x_uart0_init(); 539 orion5x_uart1_init(); 540 orion5x_xor_init(); 541 542 /* FPGA init */ 543 ts78xx_fpga_devices_zero_init(); 544 ret = ts78xx_fpga_load(); 545 ret = sysfs_create_file(power_kobj, &ts78xx_fpga_attr.attr); 546 if (ret) 547 printk(KERN_ERR "sysfs_create_file failed: %d\n", ret); 548 } 549 550 MACHINE_START(TS78XX, "Technologic Systems TS-78xx SBC") 551 /* Maintainer: Alexander Clouter <alex@digriz.org.uk> */ 552 .phys_io = ORION5X_REGS_PHYS_BASE, 553 .io_pg_offst = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC, 554 .boot_params = 0x00000100, 555 .init_machine = ts78xx_init, 556 .map_io = ts78xx_map_io, 557 .init_irq = orion5x_init_irq, 558 .timer = &orion5x_timer, 559 MACHINE_END 560