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