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