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