1 /* $OpenBSD: acpiec.c,v 1.50 2014/06/25 07:46:14 kettenis 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 18 #include <sys/param.h> 19 #include <sys/proc.h> 20 #include <sys/signalvar.h> 21 #include <sys/systm.h> 22 #include <sys/device.h> 23 #include <sys/malloc.h> 24 25 #include <machine/bus.h> 26 27 #include <dev/acpi/acpireg.h> 28 #include <dev/acpi/acpivar.h> 29 #include <dev/acpi/acpidev.h> 30 #include <dev/acpi/amltypes.h> 31 #include <dev/acpi/dsdt.h> 32 33 #include <sys/sensors.h> 34 35 int acpiec_match(struct device *, void *, void *); 36 void acpiec_attach(struct device *, struct device *, void *); 37 38 u_int8_t acpiec_status(struct acpiec_softc *); 39 u_int8_t acpiec_read_data(struct acpiec_softc *); 40 void acpiec_write_cmd(struct acpiec_softc *, u_int8_t); 41 void acpiec_write_data(struct acpiec_softc *, u_int8_t); 42 void acpiec_burst_enable(struct acpiec_softc *sc); 43 void acpiec_burst_disable(struct acpiec_softc *sc); 44 45 u_int8_t acpiec_read_1(struct acpiec_softc *, u_int8_t); 46 void acpiec_write_1(struct acpiec_softc *, u_int8_t, u_int8_t); 47 48 void acpiec_read(struct acpiec_softc *, u_int8_t, int, u_int8_t *); 49 void acpiec_write(struct acpiec_softc *, u_int8_t, int, u_int8_t *); 50 51 int acpiec_getcrs(struct acpiec_softc *, 52 struct acpi_attach_args *); 53 int acpiec_getregister(const u_int8_t *, int, int *, bus_size_t *); 54 55 void acpiec_wait(struct acpiec_softc *, u_int8_t, u_int8_t); 56 void acpiec_sci_event(struct acpiec_softc *); 57 58 void acpiec_get_events(struct acpiec_softc *); 59 60 int acpiec_gpehandler(struct acpi_softc *, int, void *); 61 62 void acpiec_lock(struct acpiec_softc *); 63 void acpiec_unlock(struct acpiec_softc *); 64 65 /* EC Status bits */ 66 #define EC_STAT_SMI_EVT 0x40 /* SMI event pending */ 67 #define EC_STAT_SCI_EVT 0x20 /* SCI event pending */ 68 #define EC_STAT_BURST 0x10 /* Controller in burst mode */ 69 #define EC_STAT_CMD 0x08 /* data is command */ 70 #define EC_STAT_IBF 0x02 /* input buffer full */ 71 #define EC_STAT_OBF 0x01 /* output buffer full */ 72 73 /* EC Commands */ 74 #define EC_CMD_RD 0x80 /* Read */ 75 #define EC_CMD_WR 0x81 /* Write */ 76 #define EC_CMD_BE 0x82 /* Burst Enable */ 77 #define EC_CMD_BD 0x83 /* Burst Disable */ 78 #define EC_CMD_QR 0x84 /* Query */ 79 80 #define REG_TYPE_EC 3 81 82 int acpiec_reg(struct acpiec_softc *); 83 84 struct cfattach acpiec_ca = { 85 sizeof(struct acpiec_softc), acpiec_match, acpiec_attach 86 }; 87 88 struct cfdriver acpiec_cd = { 89 NULL, "acpiec", DV_DULL 90 }; 91 92 const char *acpiec_hids[] = { ACPI_DEV_ECD, 0 }; 93 94 void 95 acpiec_wait(struct acpiec_softc *sc, u_int8_t mask, u_int8_t val) 96 { 97 static int acpiecnowait; 98 u_int8_t stat; 99 100 dnprintf(40, "%s: EC wait_ns for: %b == %02x\n", 101 DEVNAME(sc), (int)mask, 102 "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF", (int)val); 103 104 while (((stat = acpiec_status(sc)) & mask) != val) { 105 if (stat & EC_STAT_SCI_EVT) 106 sc->sc_gotsci = 1; 107 if (cold || (stat & EC_STAT_BURST)) 108 delay(1); 109 else 110 tsleep(&acpiecnowait, PWAIT, "acpiec", 1); 111 } 112 113 dnprintf(40, "%s: EC wait_ns, stat: %b\n", DEVNAME(sc), (int)stat, 114 "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF"); 115 } 116 117 u_int8_t 118 acpiec_status(struct acpiec_softc *sc) 119 { 120 return (bus_space_read_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0)); 121 } 122 123 void 124 acpiec_write_data(struct acpiec_softc *sc, u_int8_t val) 125 { 126 acpiec_wait(sc, EC_STAT_IBF, 0); 127 dnprintf(40, "acpiec: write_data -- %d\n", (int)val); 128 bus_space_write_1(sc->sc_data_bt, sc->sc_data_bh, 0, val); 129 } 130 131 void 132 acpiec_write_cmd(struct acpiec_softc *sc, u_int8_t val) 133 { 134 acpiec_wait(sc, EC_STAT_IBF, 0); 135 dnprintf(40, "acpiec: write_cmd -- %d\n", (int)val); 136 bus_space_write_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0, val); 137 } 138 139 u_int8_t 140 acpiec_read_data(struct acpiec_softc *sc) 141 { 142 u_int8_t val; 143 144 acpiec_wait(sc, EC_STAT_OBF, EC_STAT_OBF); 145 val = bus_space_read_1(sc->sc_data_bt, sc->sc_data_bh, 0); 146 147 dnprintf(40, "acpiec: read_data %d\n", (int)val); 148 149 return (val); 150 } 151 152 void 153 acpiec_sci_event(struct acpiec_softc *sc) 154 { 155 u_int8_t evt; 156 157 sc->sc_gotsci = 0; 158 159 acpiec_wait(sc, EC_STAT_IBF, 0); 160 bus_space_write_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0, EC_CMD_QR); 161 162 acpiec_wait(sc, EC_STAT_OBF, EC_STAT_OBF); 163 evt = bus_space_read_1(sc->sc_data_bt, sc->sc_data_bh, 0); 164 165 if (evt) { 166 dnprintf(10, "%s: sci_event: 0x%02x\n", DEVNAME(sc), (int)evt); 167 aml_evalnode(sc->sc_acpi, sc->sc_events[evt].event, 0, NULL, 168 NULL); 169 } 170 } 171 172 u_int8_t 173 acpiec_read_1(struct acpiec_softc *sc, u_int8_t addr) 174 { 175 u_int8_t val; 176 177 if ((acpiec_status(sc) & EC_STAT_SCI_EVT) == EC_STAT_SCI_EVT) 178 sc->sc_gotsci = 1; 179 180 acpiec_write_cmd(sc, EC_CMD_RD); 181 acpiec_write_data(sc, addr); 182 183 val = acpiec_read_data(sc); 184 185 return (val); 186 } 187 188 void 189 acpiec_write_1(struct acpiec_softc *sc, u_int8_t addr, u_int8_t data) 190 { 191 if ((acpiec_status(sc) & EC_STAT_SCI_EVT) == EC_STAT_SCI_EVT) 192 sc->sc_gotsci = 1; 193 194 acpiec_write_cmd(sc, EC_CMD_WR); 195 acpiec_write_data(sc, addr); 196 acpiec_write_data(sc, data); 197 } 198 199 void 200 acpiec_burst_enable(struct acpiec_softc *sc) 201 { 202 acpiec_write_cmd(sc, EC_CMD_BE); 203 acpiec_read_data(sc); 204 } 205 206 void 207 acpiec_burst_disable(struct acpiec_softc *sc) 208 { 209 if ((acpiec_status(sc) & EC_STAT_BURST) == EC_STAT_BURST) 210 acpiec_write_cmd(sc, EC_CMD_BD); 211 } 212 213 void 214 acpiec_read(struct acpiec_softc *sc, u_int8_t addr, int len, u_int8_t *buffer) 215 { 216 int reg; 217 218 /* 219 * this works because everything runs in the acpi thread context. 220 * at some point add a lock to deal with concurrency so that a 221 * transaction does not get interrupted. 222 */ 223 dnprintf(20, "%s: read %d, %d\n", DEVNAME(sc), (int)addr, len); 224 sc->sc_ecbusy = 1; 225 acpiec_burst_enable(sc); 226 for (reg = 0; reg < len; reg++) 227 buffer[reg] = acpiec_read_1(sc, addr + reg); 228 acpiec_burst_disable(sc); 229 sc->sc_ecbusy = 0; 230 } 231 232 void 233 acpiec_write(struct acpiec_softc *sc, u_int8_t addr, int len, u_int8_t *buffer) 234 { 235 int reg; 236 237 /* 238 * this works because everything runs in the acpi thread context. 239 * at some point add a lock to deal with concurrency so that a 240 * transaction does not get interrupted. 241 */ 242 dnprintf(20, "%s: write %d, %d\n", DEVNAME(sc), (int)addr, len); 243 sc->sc_ecbusy = 1; 244 acpiec_burst_enable(sc); 245 for (reg = 0; reg < len; reg++) 246 acpiec_write_1(sc, addr + reg, buffer[reg]); 247 acpiec_burst_disable(sc); 248 sc->sc_ecbusy = 0; 249 } 250 251 int 252 acpiec_match(struct device *parent, void *match, void *aux) 253 { 254 struct acpi_attach_args *aa = aux; 255 struct cfdata *cf = match; 256 struct acpi_ecdt *ecdt = aa->aaa_table; 257 struct acpi_softc *acpisc = (struct acpi_softc *)parent; 258 259 /* Check for early ECDT table attach */ 260 if (ecdt && 261 !memcmp(ecdt->hdr.signature, ECDT_SIG, sizeof(ECDT_SIG) - 1)) 262 return (1); 263 if (acpisc->sc_ec) 264 return (0); 265 266 /* sanity */ 267 return (acpi_matchhids(aa, acpiec_hids, cf->cf_driver->cd_name)); 268 } 269 270 void 271 acpiec_attach(struct device *parent, struct device *self, void *aux) 272 { 273 struct acpiec_softc *sc = (struct acpiec_softc *)self; 274 struct acpi_attach_args *aa = aux; 275 struct aml_value res; 276 int64_t st; 277 278 sc->sc_acpi = (struct acpi_softc *)parent; 279 sc->sc_devnode = aa->aaa_node; 280 281 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, &st)) 282 st = STA_PRESENT | STA_ENABLED | STA_DEV_OK; 283 if ((st & STA_PRESENT) == 0) { 284 printf(": not present\n"); 285 return; 286 } 287 288 if (acpiec_getcrs(sc, aa)) { 289 printf(": Failed to read resource settings\n"); 290 return; 291 } 292 293 sc->sc_acpi->sc_ec = sc; 294 295 if (acpiec_reg(sc)) { 296 printf(": Failed to register address space\n"); 297 return; 298 } 299 300 acpiec_get_events(sc); 301 302 dnprintf(10, "%s: GPE: %d\n", DEVNAME(sc), sc->sc_gpe); 303 304 #ifndef SMALL_KERNEL 305 acpi_set_gpehandler(sc->sc_acpi, sc->sc_gpe, acpiec_gpehandler, 306 sc, 1); 307 #endif 308 309 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_GLK", 0, NULL, &res)) 310 sc->sc_glk = 0; 311 else if (res.type != AML_OBJTYPE_INTEGER) 312 sc->sc_glk = 0; 313 else 314 sc->sc_glk = res.v_integer ? 1 : 0; 315 316 printf("\n"); 317 } 318 319 void 320 acpiec_get_events(struct acpiec_softc *sc) 321 { 322 int idx; 323 char name[16]; 324 325 memset(sc->sc_events, 0, sizeof(sc->sc_events)); 326 for (idx = 0; idx < ACPIEC_MAX_EVENTS; idx++) { 327 snprintf(name, sizeof(name), "_Q%02X", idx); 328 sc->sc_events[idx].event = aml_searchname(sc->sc_devnode, name); 329 if (sc->sc_events[idx].event != NULL) 330 dnprintf(10, "%s: Found event %s\n", DEVNAME(sc), name); 331 } 332 } 333 334 int 335 acpiec_gpehandler(struct acpi_softc *acpi_sc, int gpe, void *arg) 336 { 337 struct acpiec_softc *sc = arg; 338 u_int8_t mask, stat, en; 339 int s; 340 341 KASSERT(sc->sc_ecbusy == 0); 342 dnprintf(10, "ACPIEC: got gpe\n"); 343 344 do { 345 if (sc->sc_gotsci) 346 acpiec_sci_event(sc); 347 348 stat = acpiec_status(sc); 349 dnprintf(40, "%s: EC interrupt, stat: %b\n", 350 DEVNAME(sc), (int)stat, 351 "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF"); 352 353 if (stat & EC_STAT_SCI_EVT) 354 sc->sc_gotsci = 1; 355 else 356 sc->sc_gotsci = 0; 357 } while (sc->sc_gotsci); 358 359 /* Unmask the GPE which was blocked at interrupt time */ 360 s = spltty(); 361 mask = (1L << (gpe & 7)); 362 en = acpi_read_pmreg(acpi_sc, ACPIREG_GPE_EN, gpe>>3); 363 acpi_write_pmreg(acpi_sc, ACPIREG_GPE_EN, gpe>>3, en | mask); 364 splx(s); 365 366 return (0); 367 } 368 369 /* parse the resource buffer to get a 'register' value */ 370 int 371 acpiec_getregister(const u_int8_t *buf, int size, int *type, bus_size_t *addr) 372 { 373 int len, hlen; 374 375 #define RES_TYPE_MASK 0x80 376 #define RES_LENGTH_MASK 0x07 377 #define RES_TYPE_IOPORT 0x47 378 #define RES_TYPE_ENDTAG 0x79 379 380 if (size <= 0) 381 return (0); 382 383 if (*buf & RES_TYPE_MASK) { 384 /* large resource */ 385 if (size < 3) 386 return (1); 387 len = (int)buf[1] + 256 * (int)buf[2]; 388 hlen = 3; 389 } else { 390 /* small resource */ 391 len = buf[0] & RES_LENGTH_MASK; 392 hlen = 1; 393 } 394 395 /* XXX todo: decode other types */ 396 if (*buf != RES_TYPE_IOPORT) 397 return (0); 398 399 if (size < hlen + len) 400 return (0); 401 402 /* XXX validate? */ 403 *type = GAS_SYSTEM_IOSPACE; 404 *addr = (int)buf[2] + 256 * (int)buf[3]; 405 406 return (hlen + len); 407 } 408 409 int 410 acpiec_getcrs(struct acpiec_softc *sc, struct acpi_attach_args *aa) 411 { 412 struct aml_value res; 413 bus_size_t ec_sc, ec_data; 414 int dtype, ctype; 415 char *buf; 416 int size, ret; 417 int64_t gpe; 418 struct acpi_ecdt *ecdt = aa->aaa_table; 419 extern struct aml_node aml_root; 420 421 /* Check if this is ECDT initialization */ 422 if (ecdt) { 423 /* Get GPE, Data and Control segments */ 424 sc->sc_gpe = ecdt->gpe_bit; 425 426 ctype = ecdt->ec_control.address_space_id; 427 ec_sc = ecdt->ec_control.address; 428 429 dtype = ecdt->ec_data.address_space_id; 430 ec_data = ecdt->ec_data.address; 431 432 /* Get devnode from header */ 433 sc->sc_devnode = aml_searchname(&aml_root, ecdt->ec_id); 434 435 goto ecdtdone; 436 } 437 438 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_GPE", 0, NULL, &gpe)) { 439 dnprintf(10, "%s: no _GPE\n", DEVNAME(sc)); 440 return (1); 441 } 442 443 sc->sc_gpe = gpe; 444 445 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CRS", 0, NULL, &res)) { 446 dnprintf(10, "%s: no _CRS\n", DEVNAME(sc)); 447 return (1); 448 } 449 450 /* Parse CRS to get control and data registers */ 451 452 if (res.type != AML_OBJTYPE_BUFFER) { 453 dnprintf(10, "%s: unknown _CRS type %d\n", 454 DEVNAME(sc), res.type); 455 aml_freevalue(&res); 456 return (1); 457 } 458 459 size = res.length; 460 buf = res.v_buffer; 461 462 ret = acpiec_getregister(buf, size, &dtype, &ec_data); 463 if (ret <= 0) { 464 dnprintf(10, "%s: failed to read DATA from _CRS\n", 465 DEVNAME(sc)); 466 aml_freevalue(&res); 467 return (1); 468 } 469 470 buf += ret; 471 size -= ret; 472 473 ret = acpiec_getregister(buf, size, &ctype, &ec_sc); 474 if (ret <= 0) { 475 dnprintf(10, "%s: failed to read S/C from _CRS\n", 476 DEVNAME(sc)); 477 aml_freevalue(&res); 478 return (1); 479 } 480 481 buf += ret; 482 size -= ret; 483 484 if (size != 2 || *buf != RES_TYPE_ENDTAG) { 485 dnprintf(10, "%s: no _CRS end tag\n", DEVNAME(sc)); 486 aml_freevalue(&res); 487 return (1); 488 } 489 aml_freevalue(&res); 490 491 /* XXX: todo - validate _CRS checksum? */ 492 ecdtdone: 493 494 dnprintf(10, "%s: Data: 0x%lx, S/C: 0x%lx\n", 495 DEVNAME(sc), ec_data, ec_sc); 496 497 if (ctype == GAS_SYSTEM_IOSPACE) 498 sc->sc_cmd_bt = aa->aaa_iot; 499 else 500 sc->sc_cmd_bt = aa->aaa_memt; 501 502 if (bus_space_map(sc->sc_cmd_bt, ec_sc, 1, 0, &sc->sc_cmd_bh)) { 503 dnprintf(10, "%s: failed to map S/C reg.\n", DEVNAME(sc)); 504 return (1); 505 } 506 507 if (dtype == GAS_SYSTEM_IOSPACE) 508 sc->sc_data_bt = aa->aaa_iot; 509 else 510 sc->sc_data_bt = aa->aaa_memt; 511 512 if (bus_space_map(sc->sc_data_bt, ec_data, 1, 0, &sc->sc_data_bh)) { 513 dnprintf(10, "%s: failed to map DATA reg.\n", DEVNAME(sc)); 514 bus_space_unmap(sc->sc_cmd_bt, sc->sc_cmd_bh, 1); 515 return (1); 516 } 517 518 return (0); 519 } 520 521 int 522 acpiec_reg(struct acpiec_softc *sc) 523 { 524 struct aml_value arg[2]; 525 struct aml_node *node; 526 527 memset(&arg, 0, sizeof(arg)); 528 arg[0].type = AML_OBJTYPE_INTEGER; 529 arg[0].v_integer = REG_TYPE_EC; 530 arg[1].type = AML_OBJTYPE_INTEGER; 531 arg[1].v_integer = 1; 532 533 node = aml_searchname(sc->sc_devnode, "_REG"); 534 if (node && aml_evalnode(sc->sc_acpi, node, 2, arg, NULL)) { 535 dnprintf(10, "%s: eval method _REG failed\n", DEVNAME(sc)); 536 printf("acpiec _REG failed, broken BIOS\n"); 537 } 538 539 return (0); 540 } 541 542 void 543 acpiec_lock(struct acpiec_softc *sc) 544 { 545 KASSERT(sc->sc_ecbusy == 0); 546 547 sc->sc_ecbusy = 1; 548 549 if (sc->sc_glk) { 550 acpi_glk_enter(); 551 } 552 } 553 554 void 555 acpiec_unlock(struct acpiec_softc *sc) 556 { 557 KASSERT(sc->sc_ecbusy == 1); 558 559 if (sc->sc_glk) { 560 acpi_glk_leave(); 561 } 562 563 sc->sc_ecbusy = 0; 564 } 565