olpc.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. /*
  2. * Support for the OLPC DCON and OLPC EC access
  3. *
  4. * Copyright © 2006 Advanced Micro Devices, Inc.
  5. * Copyright © 2007-2008 Andres Salomon <[email protected]>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. */
  12. #include <linux/kernel.h>
  13. #include <linux/init.h>
  14. #include <linux/export.h>
  15. #include <linux/delay.h>
  16. #include <linux/io.h>
  17. #include <linux/string.h>
  18. #include <linux/platform_device.h>
  19. #include <linux/of.h>
  20. #include <linux/syscore_ops.h>
  21. #include <linux/mutex.h>
  22. #include <linux/olpc-ec.h>
  23. #include <asm/geode.h>
  24. #include <asm/setup.h>
  25. #include <asm/olpc.h>
  26. #include <asm/olpc_ofw.h>
  27. struct olpc_platform_t olpc_platform_info;
  28. EXPORT_SYMBOL_GPL(olpc_platform_info);
  29. /* EC event mask to be applied during suspend (defining wakeup sources). */
  30. static u16 ec_wakeup_mask;
  31. /* what the timeout *should* be (in ms) */
  32. #define EC_BASE_TIMEOUT 20
  33. /* the timeout that bugs in the EC might force us to actually use */
  34. static int ec_timeout = EC_BASE_TIMEOUT;
  35. static int __init olpc_ec_timeout_set(char *str)
  36. {
  37. if (get_option(&str, &ec_timeout) != 1) {
  38. ec_timeout = EC_BASE_TIMEOUT;
  39. printk(KERN_ERR "olpc-ec: invalid argument to "
  40. "'olpc_ec_timeout=', ignoring!\n");
  41. }
  42. printk(KERN_DEBUG "olpc-ec: using %d ms delay for EC commands.\n",
  43. ec_timeout);
  44. return 1;
  45. }
  46. __setup("olpc_ec_timeout=", olpc_ec_timeout_set);
  47. /*
  48. * These {i,o}bf_status functions return whether the buffers are full or not.
  49. */
  50. static inline unsigned int ibf_status(unsigned int port)
  51. {
  52. return !!(inb(port) & 0x02);
  53. }
  54. static inline unsigned int obf_status(unsigned int port)
  55. {
  56. return inb(port) & 0x01;
  57. }
  58. #define wait_on_ibf(p, d) __wait_on_ibf(__LINE__, (p), (d))
  59. static int __wait_on_ibf(unsigned int line, unsigned int port, int desired)
  60. {
  61. unsigned int timeo;
  62. int state = ibf_status(port);
  63. for (timeo = ec_timeout; state != desired && timeo; timeo--) {
  64. mdelay(1);
  65. state = ibf_status(port);
  66. }
  67. if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) &&
  68. timeo < (ec_timeout - EC_BASE_TIMEOUT)) {
  69. printk(KERN_WARNING "olpc-ec: %d: waited %u ms for IBF!\n",
  70. line, ec_timeout - timeo);
  71. }
  72. return !(state == desired);
  73. }
  74. #define wait_on_obf(p, d) __wait_on_obf(__LINE__, (p), (d))
  75. static int __wait_on_obf(unsigned int line, unsigned int port, int desired)
  76. {
  77. unsigned int timeo;
  78. int state = obf_status(port);
  79. for (timeo = ec_timeout; state != desired && timeo; timeo--) {
  80. mdelay(1);
  81. state = obf_status(port);
  82. }
  83. if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) &&
  84. timeo < (ec_timeout - EC_BASE_TIMEOUT)) {
  85. printk(KERN_WARNING "olpc-ec: %d: waited %u ms for OBF!\n",
  86. line, ec_timeout - timeo);
  87. }
  88. return !(state == desired);
  89. }
  90. /*
  91. * This allows the kernel to run Embedded Controller commands. The EC is
  92. * documented at <http://wiki.laptop.org/go/Embedded_controller>, and the
  93. * available EC commands are here:
  94. * <http://wiki.laptop.org/go/Ec_specification>. Unfortunately, while
  95. * OpenFirmware's source is available, the EC's is not.
  96. */
  97. static int olpc_xo1_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf,
  98. size_t outlen, void *arg)
  99. {
  100. int ret = -EIO;
  101. int i;
  102. int restarts = 0;
  103. /* Clear OBF */
  104. for (i = 0; i < 10 && (obf_status(0x6c) == 1); i++)
  105. inb(0x68);
  106. if (i == 10) {
  107. printk(KERN_ERR "olpc-ec: timeout while attempting to "
  108. "clear OBF flag!\n");
  109. goto err;
  110. }
  111. if (wait_on_ibf(0x6c, 0)) {
  112. printk(KERN_ERR "olpc-ec: timeout waiting for EC to "
  113. "quiesce!\n");
  114. goto err;
  115. }
  116. restart:
  117. /*
  118. * Note that if we time out during any IBF checks, that's a failure;
  119. * we have to return. There's no way for the kernel to clear that.
  120. *
  121. * If we time out during an OBF check, we can restart the command;
  122. * reissuing it will clear the OBF flag, and we should be alright.
  123. * The OBF flag will sometimes misbehave due to what we believe
  124. * is a hardware quirk..
  125. */
  126. pr_devel("olpc-ec: running cmd 0x%x\n", cmd);
  127. outb(cmd, 0x6c);
  128. if (wait_on_ibf(0x6c, 0)) {
  129. printk(KERN_ERR "olpc-ec: timeout waiting for EC to read "
  130. "command!\n");
  131. goto err;
  132. }
  133. if (inbuf && inlen) {
  134. /* write data to EC */
  135. for (i = 0; i < inlen; i++) {
  136. pr_devel("olpc-ec: sending cmd arg 0x%x\n", inbuf[i]);
  137. outb(inbuf[i], 0x68);
  138. if (wait_on_ibf(0x6c, 0)) {
  139. printk(KERN_ERR "olpc-ec: timeout waiting for"
  140. " EC accept data!\n");
  141. goto err;
  142. }
  143. }
  144. }
  145. if (outbuf && outlen) {
  146. /* read data from EC */
  147. for (i = 0; i < outlen; i++) {
  148. if (wait_on_obf(0x6c, 1)) {
  149. printk(KERN_ERR "olpc-ec: timeout waiting for"
  150. " EC to provide data!\n");
  151. if (restarts++ < 10)
  152. goto restart;
  153. goto err;
  154. }
  155. outbuf[i] = inb(0x68);
  156. pr_devel("olpc-ec: received 0x%x\n", outbuf[i]);
  157. }
  158. }
  159. ret = 0;
  160. err:
  161. return ret;
  162. }
  163. void olpc_ec_wakeup_set(u16 value)
  164. {
  165. ec_wakeup_mask |= value;
  166. }
  167. EXPORT_SYMBOL_GPL(olpc_ec_wakeup_set);
  168. void olpc_ec_wakeup_clear(u16 value)
  169. {
  170. ec_wakeup_mask &= ~value;
  171. }
  172. EXPORT_SYMBOL_GPL(olpc_ec_wakeup_clear);
  173. /*
  174. * Returns true if the compile and runtime configurations allow for EC events
  175. * to wake the system.
  176. */
  177. bool olpc_ec_wakeup_available(void)
  178. {
  179. if (!machine_is_olpc())
  180. return false;
  181. /*
  182. * XO-1 EC wakeups are available when olpc-xo1-sci driver is
  183. * compiled in
  184. */
  185. #ifdef CONFIG_OLPC_XO1_SCI
  186. if (olpc_platform_info.boardrev < olpc_board_pre(0xd0)) /* XO-1 */
  187. return true;
  188. #endif
  189. /*
  190. * XO-1.5 EC wakeups are available when olpc-xo15-sci driver is
  191. * compiled in
  192. */
  193. #ifdef CONFIG_OLPC_XO15_SCI
  194. if (olpc_platform_info.boardrev >= olpc_board_pre(0xd0)) /* XO-1.5 */
  195. return true;
  196. #endif
  197. return false;
  198. }
  199. EXPORT_SYMBOL_GPL(olpc_ec_wakeup_available);
  200. int olpc_ec_mask_write(u16 bits)
  201. {
  202. if (olpc_platform_info.flags & OLPC_F_EC_WIDE_SCI) {
  203. __be16 ec_word = cpu_to_be16(bits);
  204. return olpc_ec_cmd(EC_WRITE_EXT_SCI_MASK, (void *) &ec_word, 2,
  205. NULL, 0);
  206. } else {
  207. unsigned char ec_byte = bits & 0xff;
  208. return olpc_ec_cmd(EC_WRITE_SCI_MASK, &ec_byte, 1, NULL, 0);
  209. }
  210. }
  211. EXPORT_SYMBOL_GPL(olpc_ec_mask_write);
  212. int olpc_ec_sci_query(u16 *sci_value)
  213. {
  214. int ret;
  215. if (olpc_platform_info.flags & OLPC_F_EC_WIDE_SCI) {
  216. __be16 ec_word;
  217. ret = olpc_ec_cmd(EC_EXT_SCI_QUERY,
  218. NULL, 0, (void *) &ec_word, 2);
  219. if (ret == 0)
  220. *sci_value = be16_to_cpu(ec_word);
  221. } else {
  222. unsigned char ec_byte;
  223. ret = olpc_ec_cmd(EC_SCI_QUERY, NULL, 0, &ec_byte, 1);
  224. if (ret == 0)
  225. *sci_value = ec_byte;
  226. }
  227. return ret;
  228. }
  229. EXPORT_SYMBOL_GPL(olpc_ec_sci_query);
  230. static bool __init check_ofw_architecture(struct device_node *root)
  231. {
  232. const char *olpc_arch;
  233. int propsize;
  234. olpc_arch = of_get_property(root, "architecture", &propsize);
  235. return propsize == 5 && strncmp("OLPC", olpc_arch, 5) == 0;
  236. }
  237. static u32 __init get_board_revision(struct device_node *root)
  238. {
  239. int propsize;
  240. const __be32 *rev;
  241. rev = of_get_property(root, "board-revision-int", &propsize);
  242. if (propsize != 4)
  243. return 0;
  244. return be32_to_cpu(*rev);
  245. }
  246. static bool __init platform_detect(void)
  247. {
  248. struct device_node *root = of_find_node_by_path("/");
  249. bool success;
  250. if (!root)
  251. return false;
  252. success = check_ofw_architecture(root);
  253. if (success) {
  254. olpc_platform_info.boardrev = get_board_revision(root);
  255. olpc_platform_info.flags |= OLPC_F_PRESENT;
  256. }
  257. of_node_put(root);
  258. return success;
  259. }
  260. static int __init add_xo1_platform_devices(void)
  261. {
  262. struct platform_device *pdev;
  263. pdev = platform_device_register_simple("xo1-rfkill", -1, NULL, 0);
  264. if (IS_ERR(pdev))
  265. return PTR_ERR(pdev);
  266. pdev = platform_device_register_simple("olpc-xo1", -1, NULL, 0);
  267. if (IS_ERR(pdev))
  268. return PTR_ERR(pdev);
  269. return 0;
  270. }
  271. static int olpc_xo1_ec_probe(struct platform_device *pdev)
  272. {
  273. /* get the EC revision */
  274. olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0,
  275. (unsigned char *) &olpc_platform_info.ecver, 1);
  276. /* EC version 0x5f adds support for wide SCI mask */
  277. if (olpc_platform_info.ecver >= 0x5f)
  278. olpc_platform_info.flags |= OLPC_F_EC_WIDE_SCI;
  279. pr_info("OLPC board revision %s%X (EC=%x)\n",
  280. ((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "",
  281. olpc_platform_info.boardrev >> 4,
  282. olpc_platform_info.ecver);
  283. return 0;
  284. }
  285. static int olpc_xo1_ec_suspend(struct platform_device *pdev)
  286. {
  287. olpc_ec_mask_write(ec_wakeup_mask);
  288. /*
  289. * Squelch SCIs while suspended. This is a fix for
  290. * <http://dev.laptop.org/ticket/1835>.
  291. */
  292. return olpc_ec_cmd(EC_SET_SCI_INHIBIT, NULL, 0, NULL, 0);
  293. }
  294. static int olpc_xo1_ec_resume(struct platform_device *pdev)
  295. {
  296. /* Tell the EC to stop inhibiting SCIs */
  297. olpc_ec_cmd(EC_SET_SCI_INHIBIT_RELEASE, NULL, 0, NULL, 0);
  298. /*
  299. * Tell the wireless module to restart USB communication.
  300. * Must be done twice.
  301. */
  302. olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0);
  303. olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0);
  304. return 0;
  305. }
  306. static struct olpc_ec_driver ec_xo1_driver = {
  307. .probe = olpc_xo1_ec_probe,
  308. .suspend = olpc_xo1_ec_suspend,
  309. .resume = olpc_xo1_ec_resume,
  310. .ec_cmd = olpc_xo1_ec_cmd,
  311. };
  312. static struct olpc_ec_driver ec_xo1_5_driver = {
  313. .probe = olpc_xo1_ec_probe,
  314. .ec_cmd = olpc_xo1_ec_cmd,
  315. };
  316. static int __init olpc_init(void)
  317. {
  318. int r = 0;
  319. if (!olpc_ofw_present() || !platform_detect())
  320. return 0;
  321. /* register the XO-1 and 1.5-specific EC handler */
  322. if (olpc_platform_info.boardrev < olpc_board_pre(0xd0)) /* XO-1 */
  323. olpc_ec_driver_register(&ec_xo1_driver, NULL);
  324. else
  325. olpc_ec_driver_register(&ec_xo1_5_driver, NULL);
  326. platform_device_register_simple("olpc-ec", -1, NULL, 0);
  327. /* assume B1 and above models always have a DCON */
  328. if (olpc_board_at_least(olpc_board(0xb1)))
  329. olpc_platform_info.flags |= OLPC_F_DCON;
  330. #ifdef CONFIG_PCI_OLPC
  331. /* If the VSA exists let it emulate PCI, if not emulate in kernel.
  332. * XO-1 only. */
  333. if (olpc_platform_info.boardrev < olpc_board_pre(0xd0) &&
  334. !cs5535_has_vsa2())
  335. x86_init.pci.arch_init = pci_olpc_init;
  336. #endif
  337. if (olpc_platform_info.boardrev < olpc_board_pre(0xd0)) { /* XO-1 */
  338. r = add_xo1_platform_devices();
  339. if (r)
  340. return r;
  341. }
  342. return 0;
  343. }
  344. postcore_initcall(olpc_init);