acpiec.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. /* $OpenBSD: acpiec.c,v 1.52 2015/03/14 03:38:46 jsg Exp $ */
  2. /*
  3. * Copyright (c) 2006 Can Erkin Acar <canacar@openbsd.org>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include <sys/param.h>
  18. #include <sys/signalvar.h>
  19. #include <sys/systm.h>
  20. #include <sys/device.h>
  21. #include <machine/bus.h>
  22. #include <dev/acpi/acpireg.h>
  23. #include <dev/acpi/acpivar.h>
  24. #include <dev/acpi/acpidev.h>
  25. #include <dev/acpi/amltypes.h>
  26. #include <dev/acpi/dsdt.h>
  27. #include <sys/sensors.h>
  28. int acpiec_match(struct device *, void *, void *);
  29. void acpiec_attach(struct device *, struct device *, void *);
  30. u_int8_t acpiec_status(struct acpiec_softc *);
  31. u_int8_t acpiec_read_data(struct acpiec_softc *);
  32. void acpiec_write_cmd(struct acpiec_softc *, u_int8_t);
  33. void acpiec_write_data(struct acpiec_softc *, u_int8_t);
  34. void acpiec_burst_enable(struct acpiec_softc *sc);
  35. void acpiec_burst_disable(struct acpiec_softc *sc);
  36. u_int8_t acpiec_read_1(struct acpiec_softc *, u_int8_t);
  37. void acpiec_write_1(struct acpiec_softc *, u_int8_t, u_int8_t);
  38. void acpiec_read(struct acpiec_softc *, u_int8_t, int, u_int8_t *);
  39. void acpiec_write(struct acpiec_softc *, u_int8_t, int, u_int8_t *);
  40. int acpiec_getcrs(struct acpiec_softc *,
  41. struct acpi_attach_args *);
  42. int acpiec_getregister(const u_int8_t *, int, int *, bus_size_t *);
  43. void acpiec_wait(struct acpiec_softc *, u_int8_t, u_int8_t);
  44. void acpiec_sci_event(struct acpiec_softc *);
  45. void acpiec_get_events(struct acpiec_softc *);
  46. int acpiec_gpehandler(struct acpi_softc *, int, void *);
  47. void acpiec_lock(struct acpiec_softc *);
  48. void acpiec_unlock(struct acpiec_softc *);
  49. /* EC Status bits */
  50. #define EC_STAT_SMI_EVT 0x40 /* SMI event pending */
  51. #define EC_STAT_SCI_EVT 0x20 /* SCI event pending */
  52. #define EC_STAT_BURST 0x10 /* Controller in burst mode */
  53. #define EC_STAT_CMD 0x08 /* data is command */
  54. #define EC_STAT_IBF 0x02 /* input buffer full */
  55. #define EC_STAT_OBF 0x01 /* output buffer full */
  56. /* EC Commands */
  57. #define EC_CMD_RD 0x80 /* Read */
  58. #define EC_CMD_WR 0x81 /* Write */
  59. #define EC_CMD_BE 0x82 /* Burst Enable */
  60. #define EC_CMD_BD 0x83 /* Burst Disable */
  61. #define EC_CMD_QR 0x84 /* Query */
  62. #define REG_TYPE_EC 3
  63. int acpiec_reg(struct acpiec_softc *);
  64. struct cfattach acpiec_ca = {
  65. sizeof(struct acpiec_softc), acpiec_match, acpiec_attach
  66. };
  67. struct cfdriver acpiec_cd = {
  68. NULL, "acpiec", DV_DULL
  69. };
  70. const char *acpiec_hids[] = { ACPI_DEV_ECD, 0 };
  71. void
  72. acpiec_wait(struct acpiec_softc *sc, u_int8_t mask, u_int8_t val)
  73. {
  74. static int acpiecnowait;
  75. u_int8_t stat;
  76. dnprintf(40, "%s: EC wait_ns for: %b == %02x\n",
  77. DEVNAME(sc), (int)mask,
  78. "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF", (int)val);
  79. while (((stat = acpiec_status(sc)) & mask) != val) {
  80. if (stat & EC_STAT_SCI_EVT)
  81. sc->sc_gotsci = 1;
  82. if (cold || (stat & EC_STAT_BURST))
  83. delay(1);
  84. else
  85. tsleep(&acpiecnowait, PWAIT, "acpiec", 1);
  86. }
  87. dnprintf(40, "%s: EC wait_ns, stat: %b\n", DEVNAME(sc), (int)stat,
  88. "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF");
  89. }
  90. u_int8_t
  91. acpiec_status(struct acpiec_softc *sc)
  92. {
  93. return (bus_space_read_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0));
  94. }
  95. void
  96. acpiec_write_data(struct acpiec_softc *sc, u_int8_t val)
  97. {
  98. acpiec_wait(sc, EC_STAT_IBF, 0);
  99. dnprintf(40, "acpiec: write_data -- %d\n", (int)val);
  100. bus_space_write_1(sc->sc_data_bt, sc->sc_data_bh, 0, val);
  101. }
  102. void
  103. acpiec_write_cmd(struct acpiec_softc *sc, u_int8_t val)
  104. {
  105. acpiec_wait(sc, EC_STAT_IBF, 0);
  106. dnprintf(40, "acpiec: write_cmd -- %d\n", (int)val);
  107. bus_space_write_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0, val);
  108. }
  109. u_int8_t
  110. acpiec_read_data(struct acpiec_softc *sc)
  111. {
  112. u_int8_t val;
  113. acpiec_wait(sc, EC_STAT_OBF, EC_STAT_OBF);
  114. val = bus_space_read_1(sc->sc_data_bt, sc->sc_data_bh, 0);
  115. dnprintf(40, "acpiec: read_data %d\n", (int)val);
  116. return (val);
  117. }
  118. void
  119. acpiec_sci_event(struct acpiec_softc *sc)
  120. {
  121. u_int8_t evt;
  122. sc->sc_gotsci = 0;
  123. acpiec_wait(sc, EC_STAT_IBF, 0);
  124. bus_space_write_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0, EC_CMD_QR);
  125. acpiec_wait(sc, EC_STAT_OBF, EC_STAT_OBF);
  126. evt = bus_space_read_1(sc->sc_data_bt, sc->sc_data_bh, 0);
  127. if (evt) {
  128. dnprintf(10, "%s: sci_event: 0x%02x\n", DEVNAME(sc), (int)evt);
  129. aml_evalnode(sc->sc_acpi, sc->sc_events[evt].event, 0, NULL,
  130. NULL);
  131. }
  132. }
  133. u_int8_t
  134. acpiec_read_1(struct acpiec_softc *sc, u_int8_t addr)
  135. {
  136. u_int8_t val;
  137. if ((acpiec_status(sc) & EC_STAT_SCI_EVT) == EC_STAT_SCI_EVT)
  138. sc->sc_gotsci = 1;
  139. acpiec_write_cmd(sc, EC_CMD_RD);
  140. acpiec_write_data(sc, addr);
  141. val = acpiec_read_data(sc);
  142. return (val);
  143. }
  144. void
  145. acpiec_write_1(struct acpiec_softc *sc, u_int8_t addr, u_int8_t data)
  146. {
  147. if ((acpiec_status(sc) & EC_STAT_SCI_EVT) == EC_STAT_SCI_EVT)
  148. sc->sc_gotsci = 1;
  149. acpiec_write_cmd(sc, EC_CMD_WR);
  150. acpiec_write_data(sc, addr);
  151. acpiec_write_data(sc, data);
  152. }
  153. void
  154. acpiec_burst_enable(struct acpiec_softc *sc)
  155. {
  156. acpiec_write_cmd(sc, EC_CMD_BE);
  157. acpiec_read_data(sc);
  158. }
  159. void
  160. acpiec_burst_disable(struct acpiec_softc *sc)
  161. {
  162. if ((acpiec_status(sc) & EC_STAT_BURST) == EC_STAT_BURST)
  163. acpiec_write_cmd(sc, EC_CMD_BD);
  164. }
  165. void
  166. acpiec_read(struct acpiec_softc *sc, u_int8_t addr, int len, u_int8_t *buffer)
  167. {
  168. int reg;
  169. /*
  170. * this works because everything runs in the acpi thread context.
  171. * at some point add a lock to deal with concurrency so that a
  172. * transaction does not get interrupted.
  173. */
  174. dnprintf(20, "%s: read %d, %d\n", DEVNAME(sc), (int)addr, len);
  175. sc->sc_ecbusy = 1;
  176. acpiec_burst_enable(sc);
  177. for (reg = 0; reg < len; reg++)
  178. buffer[reg] = acpiec_read_1(sc, addr + reg);
  179. acpiec_burst_disable(sc);
  180. sc->sc_ecbusy = 0;
  181. }
  182. void
  183. acpiec_write(struct acpiec_softc *sc, u_int8_t addr, int len, u_int8_t *buffer)
  184. {
  185. int reg;
  186. /*
  187. * this works because everything runs in the acpi thread context.
  188. * at some point add a lock to deal with concurrency so that a
  189. * transaction does not get interrupted.
  190. */
  191. dnprintf(20, "%s: write %d, %d\n", DEVNAME(sc), (int)addr, len);
  192. sc->sc_ecbusy = 1;
  193. acpiec_burst_enable(sc);
  194. for (reg = 0; reg < len; reg++)
  195. acpiec_write_1(sc, addr + reg, buffer[reg]);
  196. acpiec_burst_disable(sc);
  197. sc->sc_ecbusy = 0;
  198. }
  199. int
  200. acpiec_match(struct device *parent, void *match, void *aux)
  201. {
  202. struct acpi_attach_args *aa = aux;
  203. struct cfdata *cf = match;
  204. struct acpi_ecdt *ecdt = aa->aaa_table;
  205. struct acpi_softc *acpisc = (struct acpi_softc *)parent;
  206. /* Check for early ECDT table attach */
  207. if (ecdt &&
  208. !memcmp(ecdt->hdr.signature, ECDT_SIG, sizeof(ECDT_SIG) - 1))
  209. return (1);
  210. if (acpisc->sc_ec)
  211. return (0);
  212. /* sanity */
  213. return (acpi_matchhids(aa, acpiec_hids, cf->cf_driver->cd_name));
  214. }
  215. void
  216. acpiec_attach(struct device *parent, struct device *self, void *aux)
  217. {
  218. struct acpiec_softc *sc = (struct acpiec_softc *)self;
  219. struct acpi_attach_args *aa = aux;
  220. struct aml_value res;
  221. int64_t st;
  222. sc->sc_acpi = (struct acpi_softc *)parent;
  223. sc->sc_devnode = aa->aaa_node;
  224. if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, &st))
  225. st = STA_PRESENT | STA_ENABLED | STA_DEV_OK;
  226. if ((st & STA_PRESENT) == 0) {
  227. printf(": not present\n");
  228. return;
  229. }
  230. if (acpiec_getcrs(sc, aa)) {
  231. printf(": Failed to read resource settings\n");
  232. return;
  233. }
  234. sc->sc_acpi->sc_ec = sc;
  235. if (acpiec_reg(sc)) {
  236. printf(": Failed to register address space\n");
  237. return;
  238. }
  239. acpiec_get_events(sc);
  240. dnprintf(10, "%s: GPE: %d\n", DEVNAME(sc), sc->sc_gpe);
  241. #ifndef SMALL_KERNEL
  242. acpi_set_gpehandler(sc->sc_acpi, sc->sc_gpe, acpiec_gpehandler,
  243. sc, 1);
  244. #endif
  245. if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_GLK", 0, NULL, &res))
  246. sc->sc_glk = 0;
  247. else if (res.type != AML_OBJTYPE_INTEGER)
  248. sc->sc_glk = 0;
  249. else
  250. sc->sc_glk = res.v_integer ? 1 : 0;
  251. printf("\n");
  252. }
  253. void
  254. acpiec_get_events(struct acpiec_softc *sc)
  255. {
  256. int idx;
  257. char name[16];
  258. memset(sc->sc_events, 0, sizeof(sc->sc_events));
  259. for (idx = 0; idx < ACPIEC_MAX_EVENTS; idx++) {
  260. snprintf(name, sizeof(name), "_Q%02X", idx);
  261. sc->sc_events[idx].event = aml_searchname(sc->sc_devnode, name);
  262. if (sc->sc_events[idx].event != NULL)
  263. dnprintf(10, "%s: Found event %s\n", DEVNAME(sc), name);
  264. }
  265. }
  266. int
  267. acpiec_gpehandler(struct acpi_softc *acpi_sc, int gpe, void *arg)
  268. {
  269. struct acpiec_softc *sc = arg;
  270. u_int8_t mask, stat, en;
  271. int s;
  272. KASSERT(sc->sc_ecbusy == 0);
  273. dnprintf(10, "ACPIEC: got gpe\n");
  274. do {
  275. if (sc->sc_gotsci)
  276. acpiec_sci_event(sc);
  277. stat = acpiec_status(sc);
  278. dnprintf(40, "%s: EC interrupt, stat: %b\n",
  279. DEVNAME(sc), (int)stat,
  280. "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF");
  281. if (stat & EC_STAT_SCI_EVT)
  282. sc->sc_gotsci = 1;
  283. else
  284. sc->sc_gotsci = 0;
  285. } while (sc->sc_gotsci);
  286. /* Unmask the GPE which was blocked at interrupt time */
  287. s = spltty();
  288. mask = (1L << (gpe & 7));
  289. en = acpi_read_pmreg(acpi_sc, ACPIREG_GPE_EN, gpe>>3);
  290. acpi_write_pmreg(acpi_sc, ACPIREG_GPE_EN, gpe>>3, en | mask);
  291. splx(s);
  292. return (0);
  293. }
  294. /* parse the resource buffer to get a 'register' value */
  295. int
  296. acpiec_getregister(const u_int8_t *buf, int size, int *type, bus_size_t *addr)
  297. {
  298. int len, hlen;
  299. #define RES_TYPE_MASK 0x80
  300. #define RES_LENGTH_MASK 0x07
  301. #define RES_TYPE_IOPORT 0x47
  302. #define RES_TYPE_ENDTAG 0x79
  303. if (size <= 0)
  304. return (0);
  305. if (*buf & RES_TYPE_MASK) {
  306. /* large resource */
  307. if (size < 3)
  308. return (1);
  309. len = (int)buf[1] + 256 * (int)buf[2];
  310. hlen = 3;
  311. } else {
  312. /* small resource */
  313. len = buf[0] & RES_LENGTH_MASK;
  314. hlen = 1;
  315. }
  316. /* XXX todo: decode other types */
  317. if (*buf != RES_TYPE_IOPORT)
  318. return (0);
  319. if (size < hlen + len)
  320. return (0);
  321. /* XXX validate? */
  322. *type = GAS_SYSTEM_IOSPACE;
  323. *addr = (int)buf[2] + 256 * (int)buf[3];
  324. return (hlen + len);
  325. }
  326. int
  327. acpiec_getcrs(struct acpiec_softc *sc, struct acpi_attach_args *aa)
  328. {
  329. struct aml_value res;
  330. bus_size_t ec_sc, ec_data;
  331. int dtype, ctype;
  332. char *buf;
  333. int size, ret;
  334. int64_t gpe;
  335. struct acpi_ecdt *ecdt = aa->aaa_table;
  336. extern struct aml_node aml_root;
  337. /* Check if this is ECDT initialization */
  338. if (ecdt) {
  339. /* Get GPE, Data and Control segments */
  340. sc->sc_gpe = ecdt->gpe_bit;
  341. ctype = ecdt->ec_control.address_space_id;
  342. ec_sc = ecdt->ec_control.address;
  343. dtype = ecdt->ec_data.address_space_id;
  344. ec_data = ecdt->ec_data.address;
  345. /* Get devnode from header */
  346. sc->sc_devnode = aml_searchname(&aml_root, ecdt->ec_id);
  347. goto ecdtdone;
  348. }
  349. if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_GPE", 0, NULL, &gpe)) {
  350. dnprintf(10, "%s: no _GPE\n", DEVNAME(sc));
  351. return (1);
  352. }
  353. sc->sc_gpe = gpe;
  354. if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CRS", 0, NULL, &res)) {
  355. dnprintf(10, "%s: no _CRS\n", DEVNAME(sc));
  356. return (1);
  357. }
  358. /* Parse CRS to get control and data registers */
  359. if (res.type != AML_OBJTYPE_BUFFER) {
  360. dnprintf(10, "%s: unknown _CRS type %d\n",
  361. DEVNAME(sc), res.type);
  362. aml_freevalue(&res);
  363. return (1);
  364. }
  365. size = res.length;
  366. buf = res.v_buffer;
  367. ret = acpiec_getregister(buf, size, &dtype, &ec_data);
  368. if (ret <= 0) {
  369. dnprintf(10, "%s: failed to read DATA from _CRS\n",
  370. DEVNAME(sc));
  371. aml_freevalue(&res);
  372. return (1);
  373. }
  374. buf += ret;
  375. size -= ret;
  376. ret = acpiec_getregister(buf, size, &ctype, &ec_sc);
  377. if (ret <= 0) {
  378. dnprintf(10, "%s: failed to read S/C from _CRS\n",
  379. DEVNAME(sc));
  380. aml_freevalue(&res);
  381. return (1);
  382. }
  383. buf += ret;
  384. size -= ret;
  385. if (size != 2 || *buf != RES_TYPE_ENDTAG) {
  386. dnprintf(10, "%s: no _CRS end tag\n", DEVNAME(sc));
  387. aml_freevalue(&res);
  388. return (1);
  389. }
  390. aml_freevalue(&res);
  391. /* XXX: todo - validate _CRS checksum? */
  392. ecdtdone:
  393. dnprintf(10, "%s: Data: 0x%lx, S/C: 0x%lx\n",
  394. DEVNAME(sc), ec_data, ec_sc);
  395. if (ctype == GAS_SYSTEM_IOSPACE)
  396. sc->sc_cmd_bt = aa->aaa_iot;
  397. else
  398. sc->sc_cmd_bt = aa->aaa_memt;
  399. if (bus_space_map(sc->sc_cmd_bt, ec_sc, 1, 0, &sc->sc_cmd_bh)) {
  400. dnprintf(10, "%s: failed to map S/C reg.\n", DEVNAME(sc));
  401. return (1);
  402. }
  403. if (dtype == GAS_SYSTEM_IOSPACE)
  404. sc->sc_data_bt = aa->aaa_iot;
  405. else
  406. sc->sc_data_bt = aa->aaa_memt;
  407. if (bus_space_map(sc->sc_data_bt, ec_data, 1, 0, &sc->sc_data_bh)) {
  408. dnprintf(10, "%s: failed to map DATA reg.\n", DEVNAME(sc));
  409. bus_space_unmap(sc->sc_cmd_bt, sc->sc_cmd_bh, 1);
  410. return (1);
  411. }
  412. return (0);
  413. }
  414. int
  415. acpiec_reg(struct acpiec_softc *sc)
  416. {
  417. struct aml_value arg[2];
  418. struct aml_node *node;
  419. memset(&arg, 0, sizeof(arg));
  420. arg[0].type = AML_OBJTYPE_INTEGER;
  421. arg[0].v_integer = REG_TYPE_EC;
  422. arg[1].type = AML_OBJTYPE_INTEGER;
  423. arg[1].v_integer = 1;
  424. node = aml_searchname(sc->sc_devnode, "_REG");
  425. if (node && aml_evalnode(sc->sc_acpi, node, 2, arg, NULL)) {
  426. dnprintf(10, "%s: eval method _REG failed\n", DEVNAME(sc));
  427. printf("acpiec _REG failed, broken BIOS\n");
  428. }
  429. return (0);
  430. }
  431. void
  432. acpiec_lock(struct acpiec_softc *sc)
  433. {
  434. KASSERT(sc->sc_ecbusy == 0);
  435. sc->sc_ecbusy = 1;
  436. if (sc->sc_glk) {
  437. acpi_glk_enter();
  438. }
  439. }
  440. void
  441. acpiec_unlock(struct acpiec_softc *sc)
  442. {
  443. KASSERT(sc->sc_ecbusy == 1);
  444. if (sc->sc_glk) {
  445. acpi_glk_leave();
  446. }
  447. sc->sc_ecbusy = 0;
  448. }