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