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