1 /* $OpenBSD: acpiec.c,v 1.25 2008/06/13 09:13:56 jordan 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 44 u_int8_t acpiec_read_1(struct acpiec_softc *, u_int8_t); 45 void acpiec_write_1(struct acpiec_softc *, u_int8_t, u_int8_t); 46 47 void acpiec_read(struct acpiec_softc *, u_int8_t, int, u_int8_t *); 48 void acpiec_write(struct acpiec_softc *, u_int8_t, int, u_int8_t *); 49 50 int acpiec_getcrs(struct acpiec_softc *, 51 struct acpi_attach_args *); 52 int acpiec_getregister(const u_int8_t *, int, int *, bus_size_t *); 53 54 void acpiec_wait(struct acpiec_softc *, u_int8_t, u_int8_t); 55 void acpiec_sci_event(struct acpiec_softc *); 56 57 void acpiec_get_events(struct acpiec_softc *); 58 59 int acpiec_gpehandler(struct acpi_softc *, int, void *); 60 61 struct aml_node *aml_find_name(struct acpi_softc *, struct aml_node *, 62 const char *); 63 64 /* EC Status bits */ 65 #define EC_STAT_SMI_EVT 0x40 /* SMI event pending */ 66 #define EC_STAT_SCI_EVT 0x20 /* SCI event pending */ 67 #define EC_STAT_BURST 0x10 /* Controller in burst mode */ 68 #define EC_STAT_CMD 0x08 /* data is command */ 69 #define EC_STAT_IBF 0x02 /* input buffer full */ 70 #define EC_STAT_OBF 0x01 /* output buffer full */ 71 72 /* EC Commands */ 73 #define EC_CMD_RD 0x80 /* Read */ 74 #define EC_CMD_WR 0x81 /* Write */ 75 #define EC_CMD_BE 0x82 /* Burst Enable */ 76 #define EC_CMD_BD 0x83 /* Burst Disable */ 77 #define EC_CMD_QR 0x84 /* Query */ 78 79 #define REG_TYPE_EC 3 80 81 #define ACPIEC_MAX_EVENTS 256 82 83 struct acpiec_event { 84 struct aml_node *event; 85 }; 86 87 struct acpiec_softc { 88 struct device sc_dev; 89 90 /* command/status register */ 91 bus_space_tag_t sc_cmd_bt; 92 bus_space_handle_t sc_cmd_bh; 93 94 /* data register */ 95 bus_space_tag_t sc_data_bt; 96 bus_space_handle_t sc_data_bh; 97 98 struct acpi_softc *sc_acpi; 99 struct aml_node *sc_devnode; 100 u_int32_t sc_gpe; 101 struct acpiec_event sc_events[ACPIEC_MAX_EVENTS]; 102 int sc_gotsci; 103 }; 104 105 106 int acpiec_reg(struct acpiec_softc *); 107 108 struct cfattach acpiec_ca = { 109 sizeof(struct acpiec_softc), acpiec_match, acpiec_attach 110 }; 111 112 struct cfdriver acpiec_cd = { 113 NULL, "acpiec", DV_DULL 114 }; 115 116 117 void 118 acpiec_wait(struct acpiec_softc *sc, u_int8_t mask, u_int8_t val) 119 { 120 u_int8_t stat; 121 122 dnprintf(40, "%s: EC wait_ns for: %b == %02x\n", 123 DEVNAME(sc), (int)mask, 124 "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF", (int)val); 125 126 while (((stat = acpiec_status(sc)) & mask) != val) { 127 if (stat & EC_STAT_SCI_EVT) 128 sc->sc_gotsci = 1; 129 if (cold) 130 delay(1); 131 else 132 tsleep(sc, PWAIT, "ecwait", 1); 133 } 134 135 dnprintf(40, "%s: EC wait_ns, stat: %b\n", DEVNAME(sc), (int)stat, 136 "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF"); 137 } 138 139 u_int8_t 140 acpiec_status(struct acpiec_softc *sc) 141 { 142 return (bus_space_read_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0)); 143 } 144 145 void 146 acpiec_write_data(struct acpiec_softc *sc, u_int8_t val) 147 { 148 acpiec_wait(sc, EC_STAT_IBF, 0); 149 dnprintf(40, "acpiec: write_data -- %d\n", (int)val); 150 bus_space_write_1(sc->sc_data_bt, sc->sc_data_bh, 0, val); 151 } 152 153 void 154 acpiec_write_cmd(struct acpiec_softc *sc, u_int8_t val) 155 { 156 acpiec_wait(sc, EC_STAT_IBF, 0); 157 dnprintf(40, "acpiec: write_cmd -- %d\n", (int)val); 158 bus_space_write_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0, val); 159 } 160 161 u_int8_t 162 acpiec_read_data(struct acpiec_softc *sc) 163 { 164 u_int8_t val; 165 166 acpiec_wait(sc, EC_STAT_OBF, EC_STAT_OBF); 167 dnprintf(40, "acpiec: read_data\n", (int)val); 168 val = bus_space_read_1(sc->sc_data_bt, sc->sc_data_bh, 0); 169 170 return (val); 171 } 172 173 void 174 acpiec_sci_event(struct acpiec_softc *sc) 175 { 176 u_int8_t evt; 177 178 sc->sc_gotsci = 0; 179 180 acpiec_wait(sc, EC_STAT_IBF, 0); 181 bus_space_write_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0, EC_CMD_QR); 182 183 acpiec_wait(sc, EC_STAT_OBF, EC_STAT_OBF); 184 evt = bus_space_read_1(sc->sc_data_bt, sc->sc_data_bh, 0); 185 186 if (evt) { 187 dnprintf(10, "%s: sci_event: 0x%02x\n", DEVNAME(sc), (int)evt); 188 aml_evalnode(sc->sc_acpi, sc->sc_events[evt].event, 0, NULL, 189 NULL); 190 } 191 } 192 193 u_int8_t 194 acpiec_read_1(struct acpiec_softc *sc, u_int8_t addr) 195 { 196 u_int8_t val; 197 198 if ((acpiec_status(sc) & EC_STAT_SCI_EVT) == EC_STAT_SCI_EVT) 199 sc->sc_gotsci = 1; 200 201 acpiec_write_cmd(sc, EC_CMD_RD); 202 acpiec_write_data(sc, addr); 203 204 val = acpiec_read_data(sc); 205 206 return (val); 207 } 208 209 void 210 acpiec_write_1(struct acpiec_softc *sc, u_int8_t addr, u_int8_t data) 211 { 212 if ((acpiec_status(sc) & EC_STAT_SCI_EVT) == EC_STAT_SCI_EVT) 213 sc->sc_gotsci = 1; 214 215 acpiec_write_cmd(sc, EC_CMD_WR); 216 acpiec_write_data(sc, addr); 217 acpiec_write_data(sc, data); 218 } 219 220 void 221 acpiec_burst_enable(struct acpiec_softc *sc) 222 { 223 acpiec_write_cmd(sc, EC_CMD_BE); 224 acpiec_read_data(sc); 225 } 226 227 void 228 acpiec_read(struct acpiec_softc *sc, u_int8_t addr, int len, u_int8_t *buffer) 229 { 230 int reg; 231 232 /* 233 * this works because everything runs in the acpi thread context. 234 * at some point add a lock to deal with concurrency so that a 235 * transaction does not get interrupted. 236 */ 237 acpiec_burst_enable(sc); 238 dnprintf(20, "%s: read %d, %d\n", DEVNAME(sc), (int)addr, len); 239 240 for (reg = 0; reg < len; reg++) 241 buffer[reg] = acpiec_read_1(sc, addr + reg); 242 } 243 244 void 245 acpiec_write(struct acpiec_softc *sc, u_int8_t addr, int len, u_int8_t *buffer) 246 { 247 int reg; 248 249 /* 250 * this works because everything runs in the acpi thread context. 251 * at some point add a lock to deal with concurrency so that a 252 * transaction does not get interrupted. 253 */ 254 acpiec_burst_enable(sc); 255 dnprintf(20, "%s: write %d, %d\n", DEVNAME(sc), (int)addr, len); 256 for (reg = 0; reg < len; reg++) 257 acpiec_write_1(sc, addr + reg, buffer[reg]); 258 } 259 260 int 261 acpiec_match(struct device *parent, void *match, void *aux) 262 { 263 struct acpi_attach_args *aa = aux; 264 struct cfdata *cf = match; 265 266 /* sanity */ 267 if (aa->aaa_name == NULL || 268 strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 || 269 aa->aaa_table != NULL) 270 return (0); 271 272 return (1); 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 281 sc->sc_acpi = (struct acpi_softc *)parent; 282 sc->sc_devnode = aa->aaa_node; 283 284 if (sc->sc_acpi->sc_ec != NULL) { 285 printf(": Only single EC is supported\n"); 286 return; 287 } 288 sc->sc_acpi->sc_ec = sc; 289 290 if (acpiec_getcrs(sc, aa)) { 291 printf(": Failed to read resource settings\n"); 292 return; 293 } 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, "acpiec"); 307 #endif 308 309 printf("\n"); 310 } 311 312 void 313 acpiec_get_events(struct acpiec_softc *sc) 314 { 315 int idx; 316 char name[16]; 317 318 memset(sc->sc_events, 0, sizeof(sc->sc_events)); 319 for (idx = 0; idx < ACPIEC_MAX_EVENTS; idx++) { 320 snprintf(name, sizeof(name), "_Q%02X", idx); 321 sc->sc_events[idx].event = aml_searchname(sc->sc_devnode, name); 322 if (sc->sc_events[idx].event != NULL) 323 dnprintf(10, "%s: Found event %s\n", DEVNAME(sc), name); 324 } 325 } 326 327 int 328 acpiec_gpehandler(struct acpi_softc *acpi_sc, int gpe, void *arg) 329 { 330 struct acpiec_softc *sc = arg; 331 u_int8_t mask, stat; 332 333 dnprintf(10, "ACPIEC: got gpe\n"); 334 335 /* Reset GPE event */ 336 mask = (1L << (gpe & 7)); 337 acpi_write_pmreg(acpi_sc, ACPIREG_GPE_STS, gpe>>3, mask); 338 acpi_write_pmreg(acpi_sc, ACPIREG_GPE_EN, gpe>>3, mask); 339 340 do { 341 if (sc->sc_gotsci) 342 acpiec_sci_event(sc); 343 344 stat = acpiec_status(sc); 345 dnprintf(40, "%s: EC interrupt, stat: %b\n", 346 DEVNAME(sc), (int)stat, 347 "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF"); 348 349 if (stat & EC_STAT_SCI_EVT) 350 sc->sc_gotsci = 1; 351 } while (sc->sc_gotsci); 352 353 return (0); 354 } 355 356 /* parse the resource buffer to get a 'register' value */ 357 int 358 acpiec_getregister(const u_int8_t *buf, int size, int *type, bus_size_t *addr) 359 { 360 int len, hlen; 361 362 #define RES_TYPE_MASK 0x80 363 #define RES_LENGTH_MASK 0x07 364 #define RES_TYPE_IOPORT 0x47 365 #define RES_TYPE_ENDTAG 0x79 366 367 if (size <= 0) 368 return (0); 369 370 if (*buf & RES_TYPE_MASK) { 371 /* large resource */ 372 if (size < 3) 373 return (1); 374 len = (int)buf[1] + 256 * (int)buf[2]; 375 hlen = 3; 376 } else { 377 /* small resource */ 378 len = buf[0] & RES_LENGTH_MASK; 379 hlen = 1; 380 } 381 382 /* XXX todo: decode other types */ 383 if (*buf != RES_TYPE_IOPORT) 384 return (0); 385 386 if (size < hlen + len) 387 return (0); 388 389 /* XXX validate? */ 390 *type = GAS_SYSTEM_IOSPACE; 391 *addr = (int)buf[2] + 256 * (int)buf[3]; 392 393 return (hlen + len); 394 } 395 396 int 397 acpiec_getcrs(struct acpiec_softc *sc, struct acpi_attach_args *aa) 398 { 399 struct aml_value res; 400 bus_size_t ec_sc, ec_data; 401 int type1, type2; 402 char *buf; 403 int size, ret; 404 405 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_GPE", 0, NULL, &res)) { 406 dnprintf(10, "%s: no _GPE\n", DEVNAME(sc)); 407 return (1); 408 } 409 410 sc->sc_gpe = aml_val2int(&res); 411 aml_freevalue(&res); 412 413 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CRS", 0, NULL, &res)) { 414 dnprintf(10, "%s: no _CRS\n", DEVNAME(sc)); 415 return (1); 416 } 417 418 /* Parse CRS to get control and data registers */ 419 420 if (res.type != AML_OBJTYPE_BUFFER) { 421 dnprintf(10, "%s: unknown _CRS type %d\n", 422 DEVNAME(sc), res.type); 423 aml_freevalue(&res); 424 return (1); 425 } 426 427 size = res.length; 428 buf = res.v_buffer; 429 430 ret = acpiec_getregister(buf, size, &type1, &ec_data); 431 if (ret <= 0) { 432 dnprintf(10, "%s: failed to read DATA from _CRS\n", 433 DEVNAME(sc)); 434 aml_freevalue(&res); 435 return (1); 436 } 437 438 buf += ret; 439 size -= ret; 440 441 ret = acpiec_getregister(buf, size, &type2, &ec_sc); 442 if (ret <= 0) { 443 dnprintf(10, "%s: failed to read S/C from _CRS\n", 444 DEVNAME(sc)); 445 aml_freevalue(&res); 446 return (1); 447 } 448 449 buf += ret; 450 size -= ret; 451 452 if (size != 2 || *buf != RES_TYPE_ENDTAG) { 453 dnprintf(10, "%s: no _CRS end tag\n", DEVNAME(sc)); 454 aml_freevalue(&res); 455 return (1); 456 } 457 aml_freevalue(&res); 458 459 /* XXX: todo - validate _CRS checksum? */ 460 461 dnprintf(10, "%s: Data: 0x%x, S/C: 0x%x\n", 462 DEVNAME(sc), ec_data, ec_sc); 463 464 if (type1 == GAS_SYSTEM_IOSPACE) 465 sc->sc_cmd_bt = aa->aaa_iot; 466 else 467 sc->sc_cmd_bt = aa->aaa_memt; 468 469 if (bus_space_map(sc->sc_cmd_bt, ec_sc, 1, 0, &sc->sc_cmd_bh)) { 470 dnprintf(10, "%s: failed to map S/C reg.\n", DEVNAME(sc)); 471 return (1); 472 } 473 474 if (type2 == GAS_SYSTEM_IOSPACE) 475 sc->sc_data_bt = aa->aaa_iot; 476 else 477 sc->sc_data_bt = aa->aaa_memt; 478 479 if (bus_space_map(sc->sc_data_bt, ec_data, 1, 0, &sc->sc_data_bh)) { 480 dnprintf(10, "%s: failed to map DATA reg.\n", DEVNAME(sc)); 481 bus_space_unmap(sc->sc_cmd_bt, sc->sc_cmd_bh, 1); 482 return (1); 483 } 484 485 return (0); 486 } 487 488 int 489 acpiec_reg(struct acpiec_softc *sc) 490 { 491 struct aml_value arg[2]; 492 493 memset(&arg, 0, sizeof(arg)); 494 arg[0].type = AML_OBJTYPE_INTEGER; 495 arg[0].v_integer = REG_TYPE_EC; 496 arg[1].type = AML_OBJTYPE_INTEGER; 497 arg[1].v_integer = 1; 498 499 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_REG", 2, 500 arg, NULL) != 0) { 501 dnprintf(10, "%s: eval method _REG failed\n", DEVNAME(sc)); 502 return (1); 503 } 504 505 return (0); 506 } 507