ts78xx-setup.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  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 <asm/mach-types.h>
  18. #include <asm/mach/arch.h>
  19. #include <asm/mach/map.h>
  20. #include <mach/orion5x.h>
  21. #include "common.h"
  22. #include "mpp.h"
  23. #include "ts78xx-fpga.h"
  24. /*****************************************************************************
  25. * TS-78xx Info
  26. ****************************************************************************/
  27. /*
  28. * FPGA - lives where the PCI bus would be at ORION5X_PCI_MEM_PHYS_BASE
  29. */
  30. #define TS78XX_FPGA_REGS_PHYS_BASE 0xe8000000
  31. #define TS78XX_FPGA_REGS_VIRT_BASE 0xff900000
  32. #define TS78XX_FPGA_REGS_SIZE SZ_1M
  33. static struct ts78xx_fpga_data ts78xx_fpga = {
  34. .id = 0,
  35. .state = 1,
  36. /* .supports = ... - populated by ts78xx_fpga_supports() */
  37. };
  38. /*****************************************************************************
  39. * I/O Address Mapping
  40. ****************************************************************************/
  41. static struct map_desc ts78xx_io_desc[] __initdata = {
  42. {
  43. .virtual = TS78XX_FPGA_REGS_VIRT_BASE,
  44. .pfn = __phys_to_pfn(TS78XX_FPGA_REGS_PHYS_BASE),
  45. .length = TS78XX_FPGA_REGS_SIZE,
  46. .type = MT_DEVICE,
  47. },
  48. };
  49. void __init ts78xx_map_io(void)
  50. {
  51. orion5x_map_io();
  52. iotable_init(ts78xx_io_desc, ARRAY_SIZE(ts78xx_io_desc));
  53. }
  54. /*****************************************************************************
  55. * Ethernet
  56. ****************************************************************************/
  57. static struct mv643xx_eth_platform_data ts78xx_eth_data = {
  58. .phy_addr = MV643XX_ETH_PHY_ADDR(0),
  59. };
  60. /*****************************************************************************
  61. * SATA
  62. ****************************************************************************/
  63. static struct mv_sata_platform_data ts78xx_sata_data = {
  64. .n_ports = 2,
  65. };
  66. /*****************************************************************************
  67. * RTC M48T86 - nicked^Wborrowed from arch/arm/mach-ep93xx/ts72xx.c
  68. ****************************************************************************/
  69. #ifdef CONFIG_RTC_DRV_M48T86
  70. #define TS_RTC_CTRL (TS78XX_FPGA_REGS_VIRT_BASE | 0x808)
  71. #define TS_RTC_DATA (TS78XX_FPGA_REGS_VIRT_BASE | 0x80c)
  72. static unsigned char ts78xx_ts_rtc_readbyte(unsigned long addr)
  73. {
  74. writeb(addr, TS_RTC_CTRL);
  75. return readb(TS_RTC_DATA);
  76. }
  77. static void ts78xx_ts_rtc_writebyte(unsigned char value, unsigned long addr)
  78. {
  79. writeb(addr, TS_RTC_CTRL);
  80. writeb(value, TS_RTC_DATA);
  81. }
  82. static struct m48t86_ops ts78xx_ts_rtc_ops = {
  83. .readbyte = ts78xx_ts_rtc_readbyte,
  84. .writebyte = ts78xx_ts_rtc_writebyte,
  85. };
  86. static struct platform_device ts78xx_ts_rtc_device = {
  87. .name = "rtc-m48t86",
  88. .id = -1,
  89. .dev = {
  90. .platform_data = &ts78xx_ts_rtc_ops,
  91. },
  92. .num_resources = 0,
  93. };
  94. /*
  95. * TS uses some of the user storage space on the RTC chip so see if it is
  96. * present; as it's an optional feature at purchase time and not all boards
  97. * will have it present
  98. *
  99. * I've used the method TS use in their rtc7800.c example for the detection
  100. *
  101. * TODO: track down a guinea pig without an RTC to see if we can work out a
  102. * better RTC detection routine
  103. */
  104. static int ts78xx_ts_rtc_load(void)
  105. {
  106. unsigned char tmp_rtc0, tmp_rtc1;
  107. tmp_rtc0 = ts78xx_ts_rtc_readbyte(126);
  108. tmp_rtc1 = ts78xx_ts_rtc_readbyte(127);
  109. ts78xx_ts_rtc_writebyte(0x00, 126);
  110. ts78xx_ts_rtc_writebyte(0x55, 127);
  111. if (ts78xx_ts_rtc_readbyte(127) == 0x55) {
  112. ts78xx_ts_rtc_writebyte(0xaa, 127);
  113. if (ts78xx_ts_rtc_readbyte(127) == 0xaa
  114. && ts78xx_ts_rtc_readbyte(126) == 0x00) {
  115. ts78xx_ts_rtc_writebyte(tmp_rtc0, 126);
  116. ts78xx_ts_rtc_writebyte(tmp_rtc1, 127);
  117. if (ts78xx_fpga.supports.ts_rtc.init == 0) {
  118. ts78xx_fpga.supports.ts_rtc.init = 1;
  119. platform_device_register(&ts78xx_ts_rtc_device);
  120. } else
  121. platform_device_add(&ts78xx_ts_rtc_device);
  122. return 0;
  123. }
  124. }
  125. ts78xx_fpga.supports.ts_rtc.present = 0;
  126. return -ENODEV;
  127. };
  128. static void ts78xx_ts_rtc_unload(void)
  129. {
  130. platform_device_del(&ts78xx_ts_rtc_device);
  131. }
  132. #else
  133. static int ts78xx_ts_rtc_load(void)
  134. {
  135. return 0;
  136. }
  137. static void ts78xx_ts_rtc_unload(void)
  138. {
  139. }
  140. #endif
  141. /*****************************************************************************
  142. * FPGA 'hotplug' support code
  143. ****************************************************************************/
  144. static void ts78xx_fpga_devices_zero_init(void)
  145. {
  146. ts78xx_fpga.supports.ts_rtc.init = 0;
  147. }
  148. static void ts78xx_fpga_supports(void)
  149. {
  150. /* TODO: put this 'table' into ts78xx-fpga.h */
  151. switch (ts78xx_fpga.id) {
  152. case TS7800_REV_B:
  153. ts78xx_fpga.supports.ts_rtc.present = 1;
  154. break;
  155. default:
  156. ts78xx_fpga.supports.ts_rtc.present = 0;
  157. }
  158. }
  159. static int ts78xx_fpga_load_devices(void)
  160. {
  161. int tmp, ret = 0;
  162. if (ts78xx_fpga.supports.ts_rtc.present == 1) {
  163. tmp = ts78xx_ts_rtc_load();
  164. if (tmp)
  165. printk(KERN_INFO "TS-78xx RTC not detected or enabled\n");
  166. ret |= tmp;
  167. }
  168. return ret;
  169. }
  170. static int ts78xx_fpga_unload_devices(void)
  171. {
  172. int ret = 0;
  173. if (ts78xx_fpga.supports.ts_rtc.present == 1)
  174. ts78xx_ts_rtc_unload();
  175. return ret;
  176. }
  177. static int ts78xx_fpga_load(void)
  178. {
  179. ts78xx_fpga.id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
  180. printk(KERN_INFO "TS-78xx FPGA: magic=0x%.6x, rev=0x%.2x\n",
  181. (ts78xx_fpga.id >> 8) & 0xffffff,
  182. ts78xx_fpga.id & 0xff);
  183. ts78xx_fpga_supports();
  184. if (ts78xx_fpga_load_devices()) {
  185. ts78xx_fpga.state = -1;
  186. return -EBUSY;
  187. }
  188. return 0;
  189. };
  190. static int ts78xx_fpga_unload(void)
  191. {
  192. unsigned int fpga_id;
  193. fpga_id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
  194. /*
  195. * There does not seem to be a feasible way to block access to the GPIO
  196. * pins from userspace (/dev/mem). This if clause should hopefully warn
  197. * those foolish enough not to follow 'policy' :)
  198. *
  199. * UrJTAG SVN since r1381 can be used to reprogram the FPGA
  200. */
  201. if (ts78xx_fpga.id != fpga_id) {
  202. printk(KERN_ERR "TS-78xx FPGA: magic/rev mismatch\n"
  203. "TS-78xx FPGA: was 0x%.6x/%.2x but now 0x%.6x/%.2x\n",
  204. (ts78xx_fpga.id >> 8) & 0xffffff, ts78xx_fpga.id & 0xff,
  205. (fpga_id >> 8) & 0xffffff, fpga_id & 0xff);
  206. ts78xx_fpga.state = -1;
  207. return -EBUSY;
  208. }
  209. if (ts78xx_fpga_unload_devices()) {
  210. ts78xx_fpga.state = -1;
  211. return -EBUSY;
  212. }
  213. return 0;
  214. };
  215. static ssize_t ts78xx_fpga_show(struct kobject *kobj,
  216. struct kobj_attribute *attr, char *buf)
  217. {
  218. if (ts78xx_fpga.state < 0)
  219. return sprintf(buf, "borked\n");
  220. return sprintf(buf, "%s\n", (ts78xx_fpga.state) ? "online" : "offline");
  221. }
  222. static ssize_t ts78xx_fpga_store(struct kobject *kobj,
  223. struct kobj_attribute *attr, const char *buf, size_t n)
  224. {
  225. int value, ret;
  226. if (ts78xx_fpga.state < 0) {
  227. printk(KERN_ERR "TS-78xx FPGA: borked, you must powercycle asap\n");
  228. return -EBUSY;
  229. }
  230. if (strncmp(buf, "online", sizeof("online") - 1) == 0)
  231. value = 1;
  232. else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
  233. value = 0;
  234. else {
  235. printk(KERN_ERR "ts78xx_fpga_store: Invalid value\n");
  236. return -EINVAL;
  237. }
  238. if (ts78xx_fpga.state == value)
  239. return n;
  240. ret = (ts78xx_fpga.state == 0)
  241. ? ts78xx_fpga_load()
  242. : ts78xx_fpga_unload();
  243. if (!(ret < 0))
  244. ts78xx_fpga.state = value;
  245. return n;
  246. }
  247. static struct kobj_attribute ts78xx_fpga_attr =
  248. __ATTR(ts78xx_fpga, 0644, ts78xx_fpga_show, ts78xx_fpga_store);
  249. /*****************************************************************************
  250. * General Setup
  251. ****************************************************************************/
  252. static struct orion5x_mpp_mode ts78xx_mpp_modes[] __initdata = {
  253. { 0, MPP_UNUSED },
  254. { 1, MPP_GPIO }, /* JTAG Clock */
  255. { 2, MPP_GPIO }, /* JTAG Data In */
  256. { 3, MPP_GPIO }, /* Lat ECP2 256 FPGA - PB2B */
  257. { 4, MPP_GPIO }, /* JTAG Data Out */
  258. { 5, MPP_GPIO }, /* JTAG TMS */
  259. { 6, MPP_GPIO }, /* Lat ECP2 256 FPGA - PB31A_CLK4+ */
  260. { 7, MPP_GPIO }, /* Lat ECP2 256 FPGA - PB22B */
  261. { 8, MPP_UNUSED },
  262. { 9, MPP_UNUSED },
  263. { 10, MPP_UNUSED },
  264. { 11, MPP_UNUSED },
  265. { 12, MPP_UNUSED },
  266. { 13, MPP_UNUSED },
  267. { 14, MPP_UNUSED },
  268. { 15, MPP_UNUSED },
  269. { 16, MPP_UART },
  270. { 17, MPP_UART },
  271. { 18, MPP_UART },
  272. { 19, MPP_UART },
  273. /*
  274. * MPP[20] PCI Clock Out 1
  275. * MPP[21] PCI Clock Out 0
  276. * MPP[22] Unused
  277. * MPP[23] Unused
  278. * MPP[24] Unused
  279. * MPP[25] Unused
  280. */
  281. { -1 },
  282. };
  283. static void __init ts78xx_init(void)
  284. {
  285. int ret;
  286. /*
  287. * Setup basic Orion functions. Need to be called early.
  288. */
  289. orion5x_init();
  290. orion5x_mpp_conf(ts78xx_mpp_modes);
  291. /*
  292. * Configure peripherals.
  293. */
  294. orion5x_ehci0_init();
  295. orion5x_ehci1_init();
  296. orion5x_eth_init(&ts78xx_eth_data);
  297. orion5x_sata_init(&ts78xx_sata_data);
  298. orion5x_uart0_init();
  299. orion5x_uart1_init();
  300. orion5x_xor_init();
  301. /* FPGA init */
  302. ts78xx_fpga_devices_zero_init();
  303. ret = ts78xx_fpga_load();
  304. ret = sysfs_create_file(power_kobj, &ts78xx_fpga_attr.attr);
  305. if (ret)
  306. printk(KERN_ERR "sysfs_create_file failed: %d\n", ret);
  307. }
  308. MACHINE_START(TS78XX, "Technologic Systems TS-78xx SBC")
  309. /* Maintainer: Alexander Clouter <alex@digriz.org.uk> */
  310. .phys_io = ORION5X_REGS_PHYS_BASE,
  311. .io_pg_offst = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
  312. .boot_params = 0x00000100,
  313. .init_machine = ts78xx_init,
  314. .map_io = ts78xx_map_io,
  315. .init_irq = orion5x_init_irq,
  316. .timer = &orion5x_timer,
  317. MACHINE_END