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