1 /* $OpenBSD: pchgpio.c,v 1.14 2022/10/20 20:40:57 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2020 Mark Kettenis 4 * Copyright (c) 2020 James Hastings 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/malloc.h> 21 #include <sys/systm.h> 22 23 #include <dev/acpi/acpireg.h> 24 #include <dev/acpi/acpivar.h> 25 #include <dev/acpi/acpidev.h> 26 #include <dev/acpi/amltypes.h> 27 #include <dev/acpi/dsdt.h> 28 29 #define PCHGPIO_MAXCOM 5 30 31 #define PCHGPIO_CONF_TXSTATE 0x00000001 32 #define PCHGPIO_CONF_RXSTATE 0x00000002 33 #define PCHGPIO_CONF_RXINV 0x00800000 34 #define PCHGPIO_CONF_RXEV_EDGE 0x02000000 35 #define PCHGPIO_CONF_RXEV_ZERO 0x04000000 36 #define PCHGPIO_CONF_RXEV_MASK 0x06000000 37 #define PCHGPIO_CONF_PADRSTCFG_MASK 0xc0000000 38 39 #define PCHGPIO_PADBAR 0x00c 40 41 struct pchgpio_group { 42 uint8_t bar; 43 uint8_t bank; 44 uint16_t base; 45 uint16_t limit; 46 int16_t gpiobase; 47 }; 48 49 struct pchgpio_device { 50 uint16_t pad_size; 51 uint16_t gpi_is; 52 uint16_t gpi_ie; 53 const struct pchgpio_group *groups; 54 int ngroups; 55 int npins; 56 }; 57 58 struct pchgpio_match { 59 const char *hid; 60 const struct pchgpio_device *device; 61 }; 62 63 struct pchgpio_pincfg { 64 uint32_t pad_cfg_dw0; 65 uint32_t pad_cfg_dw1; 66 int gpi_ie; 67 }; 68 69 struct pchgpio_intrhand { 70 int (*ih_func)(void *); 71 void *ih_arg; 72 }; 73 74 struct pchgpio_softc { 75 struct device sc_dev; 76 struct acpi_softc *sc_acpi; 77 struct aml_node *sc_node; 78 79 bus_space_tag_t sc_memt[PCHGPIO_MAXCOM]; 80 bus_space_handle_t sc_memh[PCHGPIO_MAXCOM]; 81 void *sc_ih; 82 int sc_naddr; 83 84 const struct pchgpio_device *sc_device; 85 uint16_t sc_padbar[PCHGPIO_MAXCOM]; 86 uint16_t sc_padbase[PCHGPIO_MAXCOM]; 87 int sc_padsize; 88 89 int sc_npins; 90 struct pchgpio_pincfg *sc_pin_cfg; 91 struct pchgpio_intrhand *sc_pin_ih; 92 93 struct acpi_gpio sc_gpio; 94 }; 95 96 int pchgpio_match(struct device *, void *, void *); 97 void pchgpio_attach(struct device *, struct device *, void *); 98 int pchgpio_activate(struct device *, int); 99 100 const struct cfattach pchgpio_ca = { 101 sizeof(struct pchgpio_softc), pchgpio_match, pchgpio_attach, 102 NULL, pchgpio_activate 103 }; 104 105 struct cfdriver pchgpio_cd = { 106 NULL, "pchgpio", DV_DULL 107 }; 108 109 const char *pchgpio_hids[] = { 110 "INT344B", 111 "INT3450", 112 "INT3451", 113 "INT345D", 114 "INT34BB", 115 "INT34C5", 116 "INT34C6", 117 "INTC1055", 118 NULL 119 }; 120 121 /* Sunrisepoint-LP */ 122 123 const struct pchgpio_group spt_lp_groups[] = 124 { 125 /* Community 0 */ 126 { 0, 0, 0, 23, 0 }, /* GPP_A */ 127 { 0, 1, 24, 47, 24 }, /* GPP_B */ 128 129 /* Community 1 */ 130 { 1, 0, 48, 71, 48 }, /* GPP_C */ 131 { 1, 1, 72, 95, 72 }, /* GPP_D */ 132 { 1, 2, 96, 119, 96 }, /* GPP_E */ 133 134 /* Community 3 */ 135 { 2, 0, 120, 143, 120 }, /* GPP_F */ 136 { 2, 1, 144, 151, 144 }, /* GPP_G */ 137 }; 138 139 const struct pchgpio_device spt_lp_device = 140 { 141 .pad_size = 8, 142 .gpi_is = 0x100, 143 .gpi_ie = 0x120, 144 .groups = spt_lp_groups, 145 .ngroups = nitems(spt_lp_groups), 146 .npins = 176, 147 }; 148 149 /* Sunrisepoint-H */ 150 151 const struct pchgpio_group spt_h_groups[] = 152 { 153 /* Community 0 */ 154 { 0, 0, 0, 23, 0 }, /* GPP_A */ 155 { 0, 1, 24, 47, 24 }, /* GPP_B */ 156 157 /* Community 1 */ 158 { 1, 0, 48, 71, 48 }, /* GPP_C */ 159 { 1, 1, 72, 95, 72 }, /* GPP_D */ 160 { 1, 2, 96, 108, 96 }, /* GPP_E */ 161 { 1, 3, 109, 132, 120 }, /* GPP_F */ 162 { 1, 4, 133, 156, 144 }, /* GPP_G */ 163 { 1, 5, 157, 180, 168 }, /* GPP_H */ 164 165 /* Community 3 */ 166 { 2, 0, 181, 191, 192 }, /* GPP_I */ 167 }; 168 169 const struct pchgpio_device spt_h_device = 170 { 171 .pad_size = 8, 172 .gpi_is = 0x100, 173 .gpi_ie = 0x120, 174 .groups = spt_h_groups, 175 .ngroups = nitems(spt_h_groups), 176 .npins = 224, 177 }; 178 179 /* Cannon Lake-H */ 180 181 const struct pchgpio_group cnl_h_groups[] = 182 { 183 /* Community 0 */ 184 { 0, 0, 0, 24, 0 }, /* GPP_A */ 185 { 0, 1, 25, 50, 32 }, /* GPP_B */ 186 187 /* Community 1 */ 188 { 1, 0, 51, 74, 64 }, /* GPP_C */ 189 { 1, 1, 75, 98, 96 }, /* GPP_D */ 190 { 1, 2, 99, 106, 128 }, /* GPP_G */ 191 192 /* Community 3 */ 193 { 2, 0, 155, 178, 192 }, /* GPP_K */ 194 { 2, 1, 179, 202, 224 }, /* GPP_H */ 195 { 2, 2, 203, 215, 256 }, /* GPP_E */ 196 { 2, 3, 216, 239, 288 }, /* GPP_F */ 197 198 /* Community 4 */ 199 { 3, 2, 269, 286, 320 }, /* GPP_I */ 200 { 3, 3, 287, 298, 352 }, /* GPP_J */ 201 }; 202 203 const struct pchgpio_device cnl_h_device = 204 { 205 .pad_size = 16, 206 .gpi_is = 0x100, 207 .gpi_ie = 0x120, 208 .groups = cnl_h_groups, 209 .ngroups = nitems(cnl_h_groups), 210 .npins = 384, 211 }; 212 213 /* Cannon Lake-LP */ 214 215 const struct pchgpio_group cnl_lp_groups[] = 216 { 217 /* Community 0 */ 218 { 0, 0, 0, 24, 0 }, /* GPP_A */ 219 { 0, 1, 25, 50, 32 }, /* GPP_B */ 220 { 0, 2, 51, 58, 64 }, /* GPP_G */ 221 222 /* Community 1 */ 223 { 1, 0, 68, 92, 96 }, /* GPP_D */ 224 { 1, 1, 93, 116, 128 }, /* GPP_F */ 225 { 1, 2, 117, 140, 160 }, /* GPP_H */ 226 227 /* Community 4 */ 228 { 2, 0, 181, 204, 256 }, /* GPP_C */ 229 { 2, 1, 205, 228, 288 }, /* GPP_E */ 230 }; 231 232 const struct pchgpio_device cnl_lp_device = 233 { 234 .pad_size = 16, 235 .gpi_is = 0x100, 236 .gpi_ie = 0x120, 237 .groups = cnl_lp_groups, 238 .ngroups = nitems(cnl_lp_groups), 239 .npins = 320, 240 }; 241 242 /* Tiger Lake-LP */ 243 244 const struct pchgpio_group tgl_lp_groups[] = 245 { 246 /* Community 0 */ 247 { 0, 0, 0, 25, 0 }, /* GPP_B */ 248 { 0, 1, 26, 41, 32 }, /* GPP_T */ 249 { 0, 2, 42, 66, 64 }, /* GPP_A */ 250 251 /* Community 1 */ 252 { 1, 0, 67, 74, 96 }, /* GPP_S */ 253 { 1, 1, 75, 98, 128 }, /* GPP_H */ 254 { 1, 2, 99, 119, 160 }, /* GPP_D */ 255 { 1, 3, 120, 143, 192 }, /* GPP_U */ 256 257 /* Community 4 */ 258 { 2, 0, 171, 194, 256 }, /* GPP_C */ 259 { 2, 1, 195, 219, 288 }, /* GPP_F */ 260 { 2, 3, 226, 250, 320 }, /* GPP_E */ 261 262 /* Community 5 */ 263 { 3, 0, 260, 267, 352 }, /* GPP_R */ 264 }; 265 266 const struct pchgpio_device tgl_lp_device = 267 { 268 .pad_size = 16, 269 .gpi_is = 0x100, 270 .gpi_ie = 0x120, 271 .groups = tgl_lp_groups, 272 .ngroups = nitems(tgl_lp_groups), 273 .npins = 360, 274 }; 275 276 /* Tiger Lake-H */ 277 278 const struct pchgpio_group tgl_h_groups[] = 279 { 280 /* Community 0 */ 281 { 0, 0, 0, 24, 0 }, /* GPP_A */ 282 { 0, 1, 25, 44, 32 }, /* GPP_R */ 283 { 0, 2, 45, 70, 64 }, /* GPP_B */ 284 285 /* Community 1 */ 286 { 1, 0, 79, 104, 128 }, /* GPP_D */ 287 { 1, 1, 105, 128, 160 }, /* GPP_C */ 288 { 1, 2, 129, 136, 192 }, /* GPP_S */ 289 { 1, 3, 137, 153, 224 }, /* GPP_G */ 290 291 /* Community 3 */ 292 { 2, 0, 181, 193, 288 }, /* GPP_E */ 293 { 2, 1, 194, 217, 320 }, /* GPP_F */ 294 295 /* Community 4 */ 296 { 2, 0, 218, 241, 352 }, /* GPP_H */ 297 { 2, 1, 242, 251, 384 }, /* GPP_J */ 298 { 2, 2, 252, 266, 416 }, /* GPP_K */ 299 300 /* Community 5 */ 301 { 3, 0, 267, 281, 448 }, /* GPP_I */ 302 }; 303 304 const struct pchgpio_device tgl_h_device = 305 { 306 .pad_size = 16, 307 .gpi_is = 0x100, 308 .gpi_ie = 0x120, 309 .groups = tgl_h_groups, 310 .ngroups = nitems(tgl_h_groups), 311 .npins = 480, 312 }; 313 314 struct pchgpio_match pchgpio_devices[] = { 315 { "INT344B", &spt_lp_device }, 316 { "INT3450", &cnl_h_device }, 317 { "INT3451", &spt_h_device }, 318 { "INT345D", &spt_h_device }, 319 { "INT34BB", &cnl_lp_device }, 320 { "INT34C5", &tgl_lp_device }, 321 { "INT34C6", &tgl_h_device }, 322 { "INTC1055", &tgl_lp_device }, 323 }; 324 325 int pchgpio_read_pin(void *, int); 326 void pchgpio_write_pin(void *, int, int); 327 void pchgpio_intr_establish(void *, int, int, int (*)(void *), void *); 328 void pchgpio_intr_enable(void *, int); 329 void pchgpio_intr_disable(void *, int); 330 int pchgpio_intr(void *); 331 void pchgpio_save(struct pchgpio_softc *); 332 void pchgpio_restore(struct pchgpio_softc *); 333 334 int 335 pchgpio_match(struct device *parent, void *match, void *aux) 336 { 337 struct acpi_attach_args *aaa = aux; 338 struct cfdata *cf = match; 339 340 if (aaa->aaa_naddr < 1 || aaa->aaa_nirq < 1) 341 return 0; 342 return acpi_matchhids(aaa, pchgpio_hids, cf->cf_driver->cd_name); 343 } 344 345 void 346 pchgpio_attach(struct device *parent, struct device *self, void *aux) 347 { 348 struct pchgpio_softc *sc = (struct pchgpio_softc *)self; 349 struct acpi_attach_args *aaa = aux; 350 uint16_t bar; 351 int i; 352 353 sc->sc_acpi = (struct acpi_softc *)parent; 354 sc->sc_node = aaa->aaa_node; 355 printf(" %s", sc->sc_node->name); 356 357 printf(" addr"); 358 359 for (i = 0; i < aaa->aaa_naddr; i++) { 360 printf(" 0x%llx/0x%llx", aaa->aaa_addr[i], aaa->aaa_size[i]); 361 362 sc->sc_memt[i] = aaa->aaa_bst[i]; 363 if (bus_space_map(sc->sc_memt[i], aaa->aaa_addr[i], 364 aaa->aaa_size[i], 0, &sc->sc_memh[i])) { 365 printf(": can't map registers\n"); 366 goto unmap; 367 } 368 369 sc->sc_padbar[i] = bus_space_read_4(sc->sc_memt[i], 370 sc->sc_memh[i], PCHGPIO_PADBAR); 371 sc->sc_naddr++; 372 } 373 374 printf(" irq %d", aaa->aaa_irq[0]); 375 376 for (i = 0; i < nitems(pchgpio_devices); i++) { 377 if (strcmp(pchgpio_devices[i].hid, aaa->aaa_dev) == 0) { 378 sc->sc_device = pchgpio_devices[i].device; 379 break; 380 } 381 } 382 KASSERT(sc->sc_device); 383 384 /* Figure out the first pin for each community. */ 385 bar = -1; 386 for (i = 0; i < sc->sc_device->ngroups; i++) { 387 if (sc->sc_device->groups[i].bar != bar) { 388 bar = sc->sc_device->groups[i].bar; 389 sc->sc_padbase[bar] = sc->sc_device->groups[i].base; 390 } 391 } 392 393 sc->sc_padsize = sc->sc_device->pad_size; 394 sc->sc_npins = sc->sc_device->npins; 395 sc->sc_pin_cfg = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_cfg), 396 M_DEVBUF, M_WAITOK); 397 sc->sc_pin_ih = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_ih), 398 M_DEVBUF, M_WAITOK | M_ZERO); 399 400 sc->sc_ih = acpi_intr_establish(aaa->aaa_irq[0], aaa->aaa_irq_flags[0], 401 IPL_BIO, pchgpio_intr, sc, sc->sc_dev.dv_xname); 402 if (sc->sc_ih == NULL) { 403 printf(": can't establish interrupt\n"); 404 goto unmap; 405 } 406 407 sc->sc_gpio.cookie = sc; 408 sc->sc_gpio.read_pin = pchgpio_read_pin; 409 sc->sc_gpio.write_pin = pchgpio_write_pin; 410 sc->sc_gpio.intr_establish = pchgpio_intr_establish; 411 sc->sc_gpio.intr_enable = pchgpio_intr_enable; 412 sc->sc_gpio.intr_disable = pchgpio_intr_disable; 413 sc->sc_node->gpio = &sc->sc_gpio; 414 415 printf(", %d pins\n", sc->sc_npins); 416 417 acpi_register_gpio(sc->sc_acpi, sc->sc_node); 418 return; 419 420 unmap: 421 free(sc->sc_pin_ih, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_ih)); 422 free(sc->sc_pin_cfg, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_cfg)); 423 for (i = 0; i < sc->sc_naddr; i++) 424 bus_space_unmap(sc->sc_memt[i], sc->sc_memh[i], 425 aaa->aaa_size[i]); 426 } 427 428 int 429 pchgpio_activate(struct device *self, int act) 430 { 431 struct pchgpio_softc *sc = (struct pchgpio_softc *)self; 432 433 switch (act) { 434 case DVACT_SUSPEND: 435 pchgpio_save(sc); 436 break; 437 case DVACT_RESUME: 438 pchgpio_restore(sc); 439 break; 440 } 441 442 return 0; 443 } 444 445 const struct pchgpio_group * 446 pchgpio_find_group(struct pchgpio_softc *sc, int pin) 447 { 448 int i, npads; 449 450 for (i = 0; i < sc->sc_device->ngroups; i++) { 451 npads = 1 + sc->sc_device->groups[i].limit - 452 sc->sc_device->groups[i].base; 453 454 if (pin >= sc->sc_device->groups[i].gpiobase && 455 pin < sc->sc_device->groups[i].gpiobase + npads) 456 return &sc->sc_device->groups[i]; 457 } 458 return NULL; 459 } 460 461 int 462 pchgpio_read_pin(void *cookie, int pin) 463 { 464 struct pchgpio_softc *sc = cookie; 465 const struct pchgpio_group *group; 466 uint32_t reg; 467 uint16_t pad; 468 uint8_t bar; 469 470 group = pchgpio_find_group(sc, pin); 471 bar = group->bar; 472 pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar]; 473 474 reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 475 sc->sc_padbar[bar] + pad * sc->sc_padsize); 476 477 return !!(reg & PCHGPIO_CONF_RXSTATE); 478 } 479 480 void 481 pchgpio_write_pin(void *cookie, int pin, int value) 482 { 483 struct pchgpio_softc *sc = cookie; 484 const struct pchgpio_group *group; 485 uint32_t reg; 486 uint16_t pad; 487 uint8_t bar; 488 489 group = pchgpio_find_group(sc, pin); 490 bar = group->bar; 491 pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar]; 492 493 reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 494 sc->sc_padbar[bar] + pad * sc->sc_padsize); 495 if (value) 496 reg |= PCHGPIO_CONF_TXSTATE; 497 else 498 reg &= ~PCHGPIO_CONF_TXSTATE; 499 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 500 sc->sc_padbar[bar] + pad * sc->sc_padsize, reg); 501 } 502 503 void 504 pchgpio_intr_establish(void *cookie, int pin, int flags, 505 int (*func)(void *), void *arg) 506 { 507 struct pchgpio_softc *sc = cookie; 508 const struct pchgpio_group *group; 509 uint32_t reg; 510 uint16_t pad; 511 uint8_t bank, bar; 512 513 KASSERT(pin >= 0); 514 515 group = pchgpio_find_group(sc, pin); 516 if (group == NULL) 517 return; 518 519 bar = group->bar; 520 bank = group->bank; 521 pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar]; 522 523 sc->sc_pin_ih[pin].ih_func = func; 524 sc->sc_pin_ih[pin].ih_arg = arg; 525 526 reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 527 sc->sc_padbar[bar] + pad * sc->sc_padsize); 528 reg &= ~(PCHGPIO_CONF_RXEV_MASK | PCHGPIO_CONF_RXINV); 529 if ((flags & LR_GPIO_MODE) == 1) 530 reg |= PCHGPIO_CONF_RXEV_EDGE; 531 if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTLO) 532 reg |= PCHGPIO_CONF_RXINV; 533 if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTBOTH) 534 reg |= PCHGPIO_CONF_RXEV_EDGE | PCHGPIO_CONF_RXEV_ZERO; 535 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 536 sc->sc_padbar[bar] + pad * sc->sc_padsize, reg); 537 538 reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 539 sc->sc_device->gpi_ie + bank * 4); 540 reg |= (1 << (pin - group->gpiobase)); 541 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 542 sc->sc_device->gpi_ie + bank * 4, reg); 543 } 544 545 void 546 pchgpio_intr_enable(void *cookie, int pin) 547 { 548 struct pchgpio_softc *sc = cookie; 549 const struct pchgpio_group *group; 550 uint32_t reg; 551 uint16_t pad; 552 uint8_t bank, bar; 553 554 KASSERT(pin >= 0); 555 556 group = pchgpio_find_group(sc, pin); 557 if (group == NULL) 558 return; 559 560 bar = group->bar; 561 bank = group->bank; 562 pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar]; 563 564 reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 565 sc->sc_device->gpi_ie + bank * 4); 566 reg |= (1 << (pin - group->gpiobase)); 567 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 568 sc->sc_device->gpi_ie + bank * 4, reg); 569 } 570 571 void 572 pchgpio_intr_disable(void *cookie, int pin) 573 { 574 struct pchgpio_softc *sc = cookie; 575 const struct pchgpio_group *group; 576 uint32_t reg; 577 uint16_t pad; 578 uint8_t bank, bar; 579 580 KASSERT(pin >= 0); 581 582 group = pchgpio_find_group(sc, pin); 583 if (group == NULL) 584 return; 585 586 bar = group->bar; 587 bank = group->bank; 588 pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar]; 589 590 reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 591 sc->sc_device->gpi_ie + bank * 4); 592 reg &= ~(1 << (pin - group->gpiobase)); 593 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 594 sc->sc_device->gpi_ie + bank * 4, reg); 595 } 596 597 int 598 pchgpio_intr_handle(struct pchgpio_softc *sc, int group, int bit) 599 { 600 uint32_t enable; 601 int gpiobase, pin, handled = 0; 602 uint8_t bank, bar; 603 604 bar = sc->sc_device->groups[group].bar; 605 bank = sc->sc_device->groups[group].bank; 606 gpiobase = sc->sc_device->groups[group].gpiobase; 607 608 pin = gpiobase + bit; 609 if (sc->sc_pin_ih[pin].ih_func) { 610 sc->sc_pin_ih[pin].ih_func(sc->sc_pin_ih[pin].ih_arg); 611 handled = 1; 612 } else { 613 /* Mask unhandled interrupt */ 614 enable = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 615 sc->sc_device->gpi_ie + bank * 4); 616 enable &= ~(1 << bit); 617 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 618 sc->sc_device->gpi_ie + bank * 4, enable); 619 } 620 621 return handled; 622 } 623 624 int 625 pchgpio_intr(void *arg) 626 { 627 struct pchgpio_softc *sc = arg; 628 uint32_t status, enable; 629 int group, bit, handled = 0; 630 uint16_t base, limit; 631 uint8_t bank, bar; 632 633 for (group = 0; group < sc->sc_device->ngroups; group++) { 634 bar = sc->sc_device->groups[group].bar; 635 bank = sc->sc_device->groups[group].bank; 636 base = sc->sc_device->groups[group].base; 637 limit = sc->sc_device->groups[group].limit; 638 639 status = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 640 sc->sc_device->gpi_is + bank * 4); 641 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 642 sc->sc_device->gpi_is + bank * 4, status); 643 enable = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 644 sc->sc_device->gpi_ie + bank * 4); 645 status &= enable; 646 if (status == 0) 647 continue; 648 649 for (bit = 0; bit <= (limit - base); bit++) { 650 if (status & (1 << bit)) 651 handled |= pchgpio_intr_handle(sc, group, bit); 652 } 653 } 654 655 return handled; 656 } 657 658 void 659 pchgpio_save_pin(struct pchgpio_softc *sc, int pin) 660 { 661 const struct pchgpio_group *group; 662 uint32_t gpi_ie; 663 uint16_t pad; 664 uint8_t bank, bar; 665 666 group = pchgpio_find_group(sc, pin); 667 if (group == NULL) 668 return; 669 670 bar = group->bar; 671 bank = group->bank; 672 pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar]; 673 674 sc->sc_pin_cfg[pin].pad_cfg_dw0 = 675 bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 676 sc->sc_padbar[bar] + pad * sc->sc_padsize); 677 sc->sc_pin_cfg[pin].pad_cfg_dw1 = 678 bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 679 sc->sc_padbar[bar] + pad * sc->sc_padsize + 4); 680 681 gpi_ie = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 682 sc->sc_device->gpi_ie + bank * 4); 683 sc->sc_pin_cfg[pin].gpi_ie = (gpi_ie & (1 << (pin - group->gpiobase))); 684 } 685 686 void 687 pchgpio_save(struct pchgpio_softc *sc) 688 { 689 int pin; 690 691 for (pin = 0; pin < sc->sc_npins; pin++) 692 pchgpio_save_pin(sc, pin); 693 } 694 695 void 696 pchgpio_restore_pin(struct pchgpio_softc *sc, int pin) 697 { 698 const struct pchgpio_group *group; 699 int restore = 0; 700 uint32_t pad_cfg_dw0, gpi_ie; 701 uint16_t pad; 702 uint8_t bank, bar; 703 704 group = pchgpio_find_group(sc, pin); 705 if (group == NULL) 706 return; 707 708 bar = group->bar; 709 bank = group->bank; 710 pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar]; 711 712 pad_cfg_dw0 = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 713 sc->sc_padbar[bar] + pad * sc->sc_padsize); 714 715 if (sc->sc_pin_ih[pin].ih_func) 716 restore = 1; 717 718 /* 719 * The BIOS on Lenovo Thinkpads based on Intel's Tiger Lake 720 * platform have a bug where the GPIO pin that is used for the 721 * touchpad interrupt gets reset when entering S3 and isn't 722 * properly restored upon resume. We detect this issue by 723 * comparing the bits in the PAD_CFG_DW0 register PADRSTCFG 724 * field before suspend and after resume and restore the pin 725 * configuration if the bits don't match. 726 */ 727 if ((sc->sc_pin_cfg[pin].pad_cfg_dw0 & PCHGPIO_CONF_PADRSTCFG_MASK) != 728 (pad_cfg_dw0 & PCHGPIO_CONF_PADRSTCFG_MASK)) 729 restore = 1; 730 731 if (restore) { 732 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 733 sc->sc_padbar[bar] + pad * sc->sc_padsize, 734 sc->sc_pin_cfg[pin].pad_cfg_dw0); 735 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 736 sc->sc_padbar[bar] + pad * sc->sc_padsize + 4, 737 sc->sc_pin_cfg[pin].pad_cfg_dw1); 738 739 gpi_ie = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 740 sc->sc_device->gpi_ie + bank * 4); 741 if (sc->sc_pin_cfg[pin].gpi_ie) 742 gpi_ie |= (1 << (pin - group->gpiobase)); 743 else 744 gpi_ie &= ~(1 << (pin - group->gpiobase)); 745 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 746 sc->sc_device->gpi_ie + bank * 4, gpi_ie); 747 } 748 } 749 750 void 751 pchgpio_restore(struct pchgpio_softc *sc) 752 { 753 int pin; 754 755 for (pin = 0; pin < sc->sc_npins; pin++) 756 pchgpio_restore_pin(sc, pin); 757 } 758