olpc.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  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 <dilinger@debian.org>
  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/module.h>
  15. #include <linux/delay.h>
  16. #include <linux/spinlock.h>
  17. #include <linux/io.h>
  18. #include <linux/string.h>
  19. #include <linux/platform_device.h>
  20. #include <linux/of.h>
  21. #include <linux/syscore_ops.h>
  22. #include <asm/geode.h>
  23. #include <asm/setup.h>
  24. #include <asm/olpc.h>
  25. #include <asm/olpc_ofw.h>
  26. struct olpc_platform_t olpc_platform_info;
  27. EXPORT_SYMBOL_GPL(olpc_platform_info);
  28. static DEFINE_SPINLOCK(ec_lock);
  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. int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen,
  98. unsigned char *outbuf, size_t outlen)
  99. {
  100. unsigned long flags;
  101. int ret = -EIO;
  102. int i;
  103. int restarts = 0;
  104. spin_lock_irqsave(&ec_lock, flags);
  105. /* Clear OBF */
  106. for (i = 0; i < 10 && (obf_status(0x6c) == 1); i++)
  107. inb(0x68);
  108. if (i == 10) {
  109. printk(KERN_ERR "olpc-ec: timeout while attempting to "
  110. "clear OBF flag!\n");
  111. goto err;
  112. }
  113. if (wait_on_ibf(0x6c, 0)) {
  114. printk(KERN_ERR "olpc-ec: timeout waiting for EC to "
  115. "quiesce!\n");
  116. goto err;
  117. }
  118. restart:
  119. /*
  120. * Note that if we time out during any IBF checks, that's a failure;
  121. * we have to return. There's no way for the kernel to clear that.
  122. *
  123. * If we time out during an OBF check, we can restart the command;
  124. * reissuing it will clear the OBF flag, and we should be alright.
  125. * The OBF flag will sometimes misbehave due to what we believe
  126. * is a hardware quirk..
  127. */
  128. pr_devel("olpc-ec: running cmd 0x%x\n", cmd);
  129. outb(cmd, 0x6c);
  130. if (wait_on_ibf(0x6c, 0)) {
  131. printk(KERN_ERR "olpc-ec: timeout waiting for EC to read "
  132. "command!\n");
  133. goto err;
  134. }
  135. if (inbuf && inlen) {
  136. /* write data to EC */
  137. for (i = 0; i < inlen; i++) {
  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. pr_devel("olpc-ec: sending cmd arg 0x%x\n", inbuf[i]);
  144. outb(inbuf[i], 0x68);
  145. }
  146. }
  147. if (outbuf && outlen) {
  148. /* read data from EC */
  149. for (i = 0; i < outlen; i++) {
  150. if (wait_on_obf(0x6c, 1)) {
  151. printk(KERN_ERR "olpc-ec: timeout waiting for"
  152. " EC to provide data!\n");
  153. if (restarts++ < 10)
  154. goto restart;
  155. goto err;
  156. }
  157. outbuf[i] = inb(0x68);
  158. pr_devel("olpc-ec: received 0x%x\n", outbuf[i]);
  159. }
  160. }
  161. ret = 0;
  162. err:
  163. spin_unlock_irqrestore(&ec_lock, flags);
  164. return ret;
  165. }
  166. EXPORT_SYMBOL_GPL(olpc_ec_cmd);
  167. void olpc_ec_wakeup_set(u16 value)
  168. {
  169. ec_wakeup_mask |= value;
  170. }
  171. EXPORT_SYMBOL_GPL(olpc_ec_wakeup_set);
  172. void olpc_ec_wakeup_clear(u16 value)
  173. {
  174. ec_wakeup_mask &= ~value;
  175. }
  176. EXPORT_SYMBOL_GPL(olpc_ec_wakeup_clear);
  177. /*
  178. * Returns true if the compile and runtime configurations allow for EC events
  179. * to wake the system.
  180. */
  181. bool olpc_ec_wakeup_available(void)
  182. {
  183. if (!machine_is_olpc())
  184. return false;
  185. /*
  186. * XO-1 EC wakeups are available when olpc-xo1-sci driver is
  187. * compiled in
  188. */
  189. #ifdef CONFIG_OLPC_XO1_SCI
  190. if (olpc_platform_info.boardrev < olpc_board_pre(0xd0)) /* XO-1 */
  191. return true;
  192. #endif
  193. /*
  194. * XO-1.5 EC wakeups are available when olpc-xo15-sci driver is
  195. * compiled in
  196. */
  197. #ifdef CONFIG_OLPC_XO15_SCI
  198. if (olpc_platform_info.boardrev >= olpc_board_pre(0xd0)) /* XO-1.5 */
  199. return true;
  200. #endif
  201. return false;
  202. }
  203. EXPORT_SYMBOL_GPL(olpc_ec_wakeup_available);
  204. int olpc_ec_mask_write(u16 bits)
  205. {
  206. if (olpc_platform_info.flags & OLPC_F_EC_WIDE_SCI) {
  207. __be16 ec_word = cpu_to_be16(bits);
  208. return olpc_ec_cmd(EC_WRITE_EXT_SCI_MASK, (void *) &ec_word, 2,
  209. NULL, 0);
  210. } else {
  211. unsigned char ec_byte = bits & 0xff;
  212. return olpc_ec_cmd(EC_WRITE_SCI_MASK, &ec_byte, 1, NULL, 0);
  213. }
  214. }
  215. EXPORT_SYMBOL_GPL(olpc_ec_mask_write);
  216. int olpc_ec_sci_query(u16 *sci_value)
  217. {
  218. int ret;
  219. if (olpc_platform_info.flags & OLPC_F_EC_WIDE_SCI) {
  220. __be16 ec_word;
  221. ret = olpc_ec_cmd(EC_EXT_SCI_QUERY,
  222. NULL, 0, (void *) &ec_word, 2);
  223. if (ret == 0)
  224. *sci_value = be16_to_cpu(ec_word);
  225. } else {
  226. unsigned char ec_byte;
  227. ret = olpc_ec_cmd(EC_SCI_QUERY, NULL, 0, &ec_byte, 1);
  228. if (ret == 0)
  229. *sci_value = ec_byte;
  230. }
  231. return ret;
  232. }
  233. EXPORT_SYMBOL_GPL(olpc_ec_sci_query);
  234. static int olpc_ec_suspend(void)
  235. {
  236. return olpc_ec_mask_write(ec_wakeup_mask);
  237. }
  238. static bool __init check_ofw_architecture(struct device_node *root)
  239. {
  240. const char *olpc_arch;
  241. int propsize;
  242. olpc_arch = of_get_property(root, "architecture", &propsize);
  243. return propsize == 5 && strncmp("OLPC", olpc_arch, 5) == 0;
  244. }
  245. static u32 __init get_board_revision(struct device_node *root)
  246. {
  247. int propsize;
  248. const __be32 *rev;
  249. rev = of_get_property(root, "board-revision-int", &propsize);
  250. if (propsize != 4)
  251. return 0;
  252. return be32_to_cpu(*rev);
  253. }
  254. static bool __init platform_detect(void)
  255. {
  256. struct device_node *root = of_find_node_by_path("/");
  257. bool success;
  258. if (!root)
  259. return false;
  260. success = check_ofw_architecture(root);
  261. if (success) {
  262. olpc_platform_info.boardrev = get_board_revision(root);
  263. olpc_platform_info.flags |= OLPC_F_PRESENT;
  264. }
  265. of_node_put(root);
  266. return success;
  267. }
  268. static int __init add_xo1_platform_devices(void)
  269. {
  270. struct platform_device *pdev;
  271. pdev = platform_device_register_simple("xo1-rfkill", -1, NULL, 0);
  272. if (IS_ERR(pdev))
  273. return PTR_ERR(pdev);
  274. pdev = platform_device_register_simple("olpc-xo1", -1, NULL, 0);
  275. if (IS_ERR(pdev))
  276. return PTR_ERR(pdev);
  277. return 0;
  278. }
  279. static struct syscore_ops olpc_syscore_ops = {
  280. .suspend = olpc_ec_suspend,
  281. };
  282. static int __init olpc_init(void)
  283. {
  284. int r = 0;
  285. if (!olpc_ofw_present() || !platform_detect())
  286. return 0;
  287. spin_lock_init(&ec_lock);
  288. /* assume B1 and above models always have a DCON */
  289. if (olpc_board_at_least(olpc_board(0xb1)))
  290. olpc_platform_info.flags |= OLPC_F_DCON;
  291. /* get the EC revision */
  292. olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0,
  293. (unsigned char *) &olpc_platform_info.ecver, 1);
  294. #ifdef CONFIG_PCI_OLPC
  295. /* If the VSA exists let it emulate PCI, if not emulate in kernel.
  296. * XO-1 only. */
  297. if (olpc_platform_info.boardrev < olpc_board_pre(0xd0) &&
  298. !cs5535_has_vsa2())
  299. x86_init.pci.arch_init = pci_olpc_init;
  300. #endif
  301. /* EC version 0x5f adds support for wide SCI mask */
  302. if (olpc_platform_info.ecver >= 0x5f)
  303. olpc_platform_info.flags |= OLPC_F_EC_WIDE_SCI;
  304. printk(KERN_INFO "OLPC board revision %s%X (EC=%x)\n",
  305. ((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "",
  306. olpc_platform_info.boardrev >> 4,
  307. olpc_platform_info.ecver);
  308. if (olpc_platform_info.boardrev < olpc_board_pre(0xd0)) { /* XO-1 */
  309. r = add_xo1_platform_devices();
  310. if (r)
  311. return r;
  312. }
  313. register_syscore_ops(&olpc_syscore_ops);
  314. return 0;
  315. }
  316. postcore_initcall(olpc_init);