ts78xx-setup.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  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. int rc;
  107. unsigned char tmp_rtc0, tmp_rtc1;
  108. tmp_rtc0 = ts78xx_ts_rtc_readbyte(126);
  109. tmp_rtc1 = ts78xx_ts_rtc_readbyte(127);
  110. ts78xx_ts_rtc_writebyte(0x00, 126);
  111. ts78xx_ts_rtc_writebyte(0x55, 127);
  112. if (ts78xx_ts_rtc_readbyte(127) == 0x55) {
  113. ts78xx_ts_rtc_writebyte(0xaa, 127);
  114. if (ts78xx_ts_rtc_readbyte(127) == 0xaa
  115. && ts78xx_ts_rtc_readbyte(126) == 0x00) {
  116. ts78xx_ts_rtc_writebyte(tmp_rtc0, 126);
  117. ts78xx_ts_rtc_writebyte(tmp_rtc1, 127);
  118. if (ts78xx_fpga.supports.ts_rtc.init == 0) {
  119. rc = platform_device_register(&ts78xx_ts_rtc_device);
  120. if (!rc)
  121. ts78xx_fpga.supports.ts_rtc.init = 1;
  122. } else
  123. rc = platform_device_add(&ts78xx_ts_rtc_device);
  124. return rc;
  125. }
  126. }
  127. return -ENODEV;
  128. };
  129. static void ts78xx_ts_rtc_unload(void)
  130. {
  131. platform_device_del(&ts78xx_ts_rtc_device);
  132. }
  133. #else
  134. static int ts78xx_ts_rtc_load(void)
  135. {
  136. return -ENODEV;
  137. }
  138. static void ts78xx_ts_rtc_unload(void)
  139. {
  140. }
  141. #endif
  142. /*****************************************************************************
  143. * FPGA 'hotplug' support code
  144. ****************************************************************************/
  145. static void ts78xx_fpga_devices_zero_init(void)
  146. {
  147. ts78xx_fpga.supports.ts_rtc.init = 0;
  148. }
  149. static void ts78xx_fpga_supports(void)
  150. {
  151. /* TODO: put this 'table' into ts78xx-fpga.h */
  152. switch (ts78xx_fpga.id) {
  153. case TS7800_REV_B:
  154. ts78xx_fpga.supports.ts_rtc.present = 1;
  155. break;
  156. default:
  157. ts78xx_fpga.supports.ts_rtc.present = 0;
  158. }
  159. }
  160. static int ts78xx_fpga_load_devices(void)
  161. {
  162. int tmp, ret = 0;
  163. if (ts78xx_fpga.supports.ts_rtc.present == 1) {
  164. tmp = ts78xx_ts_rtc_load();
  165. if (tmp) {
  166. printk(KERN_INFO "TS-78xx RTC"
  167. " not detected or enabled\n");
  168. ts78xx_fpga.supports.ts_rtc.present = 0;
  169. }
  170. ret |= tmp;
  171. }
  172. return ret;
  173. }
  174. static int ts78xx_fpga_unload_devices(void)
  175. {
  176. int ret = 0;
  177. if (ts78xx_fpga.supports.ts_rtc.present == 1)
  178. ts78xx_ts_rtc_unload();
  179. return ret;
  180. }
  181. static int ts78xx_fpga_load(void)
  182. {
  183. ts78xx_fpga.id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
  184. printk(KERN_INFO "TS-78xx FPGA: magic=0x%.6x, rev=0x%.2x\n",
  185. (ts78xx_fpga.id >> 8) & 0xffffff,
  186. ts78xx_fpga.id & 0xff);
  187. ts78xx_fpga_supports();
  188. if (ts78xx_fpga_load_devices()) {
  189. ts78xx_fpga.state = -1;
  190. return -EBUSY;
  191. }
  192. return 0;
  193. };
  194. static int ts78xx_fpga_unload(void)
  195. {
  196. unsigned int fpga_id;
  197. fpga_id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
  198. /*
  199. * There does not seem to be a feasible way to block access to the GPIO
  200. * pins from userspace (/dev/mem). This if clause should hopefully warn
  201. * those foolish enough not to follow 'policy' :)
  202. *
  203. * UrJTAG SVN since r1381 can be used to reprogram the FPGA
  204. */
  205. if (ts78xx_fpga.id != fpga_id) {
  206. printk(KERN_ERR "TS-78xx FPGA: magic/rev mismatch\n"
  207. "TS-78xx FPGA: was 0x%.6x/%.2x but now 0x%.6x/%.2x\n",
  208. (ts78xx_fpga.id >> 8) & 0xffffff, ts78xx_fpga.id & 0xff,
  209. (fpga_id >> 8) & 0xffffff, fpga_id & 0xff);
  210. ts78xx_fpga.state = -1;
  211. return -EBUSY;
  212. }
  213. if (ts78xx_fpga_unload_devices()) {
  214. ts78xx_fpga.state = -1;
  215. return -EBUSY;
  216. }
  217. return 0;
  218. };
  219. static ssize_t ts78xx_fpga_show(struct kobject *kobj,
  220. struct kobj_attribute *attr, char *buf)
  221. {
  222. if (ts78xx_fpga.state < 0)
  223. return sprintf(buf, "borked\n");
  224. return sprintf(buf, "%s\n", (ts78xx_fpga.state) ? "online" : "offline");
  225. }
  226. static ssize_t ts78xx_fpga_store(struct kobject *kobj,
  227. struct kobj_attribute *attr, const char *buf, size_t n)
  228. {
  229. int value, ret;
  230. if (ts78xx_fpga.state < 0) {
  231. printk(KERN_ERR "TS-78xx FPGA: borked, you must powercycle asap\n");
  232. return -EBUSY;
  233. }
  234. if (strncmp(buf, "online", sizeof("online") - 1) == 0)
  235. value = 1;
  236. else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
  237. value = 0;
  238. else {
  239. printk(KERN_ERR "ts78xx_fpga_store: Invalid value\n");
  240. return -EINVAL;
  241. }
  242. if (ts78xx_fpga.state == value)
  243. return n;
  244. ret = (ts78xx_fpga.state == 0)
  245. ? ts78xx_fpga_load()
  246. : ts78xx_fpga_unload();
  247. if (!(ret < 0))
  248. ts78xx_fpga.state = value;
  249. return n;
  250. }
  251. static struct kobj_attribute ts78xx_fpga_attr =
  252. __ATTR(ts78xx_fpga, 0644, ts78xx_fpga_show, ts78xx_fpga_store);
  253. /*****************************************************************************
  254. * General Setup
  255. ****************************************************************************/
  256. static struct orion5x_mpp_mode ts78xx_mpp_modes[] __initdata = {
  257. { 0, MPP_UNUSED },
  258. { 1, MPP_GPIO }, /* JTAG Clock */
  259. { 2, MPP_GPIO }, /* JTAG Data In */
  260. { 3, MPP_GPIO }, /* Lat ECP2 256 FPGA - PB2B */
  261. { 4, MPP_GPIO }, /* JTAG Data Out */
  262. { 5, MPP_GPIO }, /* JTAG TMS */
  263. { 6, MPP_GPIO }, /* Lat ECP2 256 FPGA - PB31A_CLK4+ */
  264. { 7, MPP_GPIO }, /* Lat ECP2 256 FPGA - PB22B */
  265. { 8, MPP_UNUSED },
  266. { 9, MPP_UNUSED },
  267. { 10, MPP_UNUSED },
  268. { 11, MPP_UNUSED },
  269. { 12, MPP_UNUSED },
  270. { 13, MPP_UNUSED },
  271. { 14, MPP_UNUSED },
  272. { 15, MPP_UNUSED },
  273. { 16, MPP_UART },
  274. { 17, MPP_UART },
  275. { 18, MPP_UART },
  276. { 19, MPP_UART },
  277. /*
  278. * MPP[20] PCI Clock Out 1
  279. * MPP[21] PCI Clock Out 0
  280. * MPP[22] Unused
  281. * MPP[23] Unused
  282. * MPP[24] Unused
  283. * MPP[25] Unused
  284. */
  285. { -1 },
  286. };
  287. static void __init ts78xx_init(void)
  288. {
  289. int ret;
  290. /*
  291. * Setup basic Orion functions. Need to be called early.
  292. */
  293. orion5x_init();
  294. orion5x_mpp_conf(ts78xx_mpp_modes);
  295. /*
  296. * Configure peripherals.
  297. */
  298. orion5x_ehci0_init();
  299. orion5x_ehci1_init();
  300. orion5x_eth_init(&ts78xx_eth_data);
  301. orion5x_sata_init(&ts78xx_sata_data);
  302. orion5x_uart0_init();
  303. orion5x_uart1_init();
  304. orion5x_xor_init();
  305. /* FPGA init */
  306. ts78xx_fpga_devices_zero_init();
  307. ret = ts78xx_fpga_load();
  308. ret = sysfs_create_file(power_kobj, &ts78xx_fpga_attr.attr);
  309. if (ret)
  310. printk(KERN_ERR "sysfs_create_file failed: %d\n", ret);
  311. }
  312. MACHINE_START(TS78XX, "Technologic Systems TS-78xx SBC")
  313. /* Maintainer: Alexander Clouter <alex@digriz.org.uk> */
  314. .phys_io = ORION5X_REGS_PHYS_BASE,
  315. .io_pg_offst = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
  316. .boot_params = 0x00000100,
  317. .init_machine = ts78xx_init,
  318. .map_io = ts78xx_map_io,
  319. .init_irq = orion5x_init_irq,
  320. .timer = &orion5x_timer,
  321. MACHINE_END