ts78xx-setup.c 12 KB

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