1 /* $OpenBSD: pchgpio.c,v 1.16 2024/08/18 11:10:10 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 "INTC1056", 119 "INTC1057", 120 "INTC1082", 121 "INTC1083", 122 "INTC1085", 123 NULL 124 }; 125 126 /* Sunrisepoint-LP */ 127 128 const struct pchgpio_group spt_lp_groups[] = 129 { 130 /* Community 0 */ 131 { 0, 0, 0, 23, 0 }, /* GPP_A */ 132 { 0, 1, 24, 47, 24 }, /* GPP_B */ 133 134 /* Community 1 */ 135 { 1, 0, 48, 71, 48 }, /* GPP_C */ 136 { 1, 1, 72, 95, 72 }, /* GPP_D */ 137 { 1, 2, 96, 119, 96 }, /* GPP_E */ 138 139 /* Community 3 */ 140 { 2, 0, 120, 143, 120 }, /* GPP_F */ 141 { 2, 1, 144, 151, 144 }, /* GPP_G */ 142 }; 143 144 const struct pchgpio_device spt_lp_device = 145 { 146 .pad_size = 8, 147 .gpi_is = 0x100, 148 .gpi_ie = 0x120, 149 .groups = spt_lp_groups, 150 .ngroups = nitems(spt_lp_groups), 151 .npins = 176, 152 }; 153 154 /* Sunrisepoint-H */ 155 156 const struct pchgpio_group spt_h_groups[] = 157 { 158 /* Community 0 */ 159 { 0, 0, 0, 23, 0 }, /* GPP_A */ 160 { 0, 1, 24, 47, 24 }, /* GPP_B */ 161 162 /* Community 1 */ 163 { 1, 0, 48, 71, 48 }, /* GPP_C */ 164 { 1, 1, 72, 95, 72 }, /* GPP_D */ 165 { 1, 2, 96, 108, 96 }, /* GPP_E */ 166 { 1, 3, 109, 132, 120 }, /* GPP_F */ 167 { 1, 4, 133, 156, 144 }, /* GPP_G */ 168 { 1, 5, 157, 180, 168 }, /* GPP_H */ 169 170 /* Community 3 */ 171 { 2, 0, 181, 191, 192 }, /* GPP_I */ 172 }; 173 174 const struct pchgpio_device spt_h_device = 175 { 176 .pad_size = 8, 177 .gpi_is = 0x100, 178 .gpi_ie = 0x120, 179 .groups = spt_h_groups, 180 .ngroups = nitems(spt_h_groups), 181 .npins = 224, 182 }; 183 184 /* Cannon Lake-H */ 185 186 const struct pchgpio_group cnl_h_groups[] = 187 { 188 /* Community 0 */ 189 { 0, 0, 0, 24, 0 }, /* GPP_A */ 190 { 0, 1, 25, 50, 32 }, /* GPP_B */ 191 192 /* Community 1 */ 193 { 1, 0, 51, 74, 64 }, /* GPP_C */ 194 { 1, 1, 75, 98, 96 }, /* GPP_D */ 195 { 1, 2, 99, 106, 128 }, /* GPP_G */ 196 197 /* Community 3 */ 198 { 2, 0, 155, 178, 192 }, /* GPP_K */ 199 { 2, 1, 179, 202, 224 }, /* GPP_H */ 200 { 2, 2, 203, 215, 256 }, /* GPP_E */ 201 { 2, 3, 216, 239, 288 }, /* GPP_F */ 202 203 /* Community 4 */ 204 { 3, 2, 269, 286, 320 }, /* GPP_I */ 205 { 3, 3, 287, 298, 352 }, /* GPP_J */ 206 }; 207 208 const struct pchgpio_device cnl_h_device = 209 { 210 .pad_size = 16, 211 .gpi_is = 0x100, 212 .gpi_ie = 0x120, 213 .groups = cnl_h_groups, 214 .ngroups = nitems(cnl_h_groups), 215 .npins = 384, 216 }; 217 218 /* Cannon Lake-LP */ 219 220 const struct pchgpio_group cnl_lp_groups[] = 221 { 222 /* Community 0 */ 223 { 0, 0, 0, 24, 0 }, /* GPP_A */ 224 { 0, 1, 25, 50, 32 }, /* GPP_B */ 225 { 0, 2, 51, 58, 64 }, /* GPP_G */ 226 227 /* Community 1 */ 228 { 1, 0, 68, 92, 96 }, /* GPP_D */ 229 { 1, 1, 93, 116, 128 }, /* GPP_F */ 230 { 1, 2, 117, 140, 160 }, /* GPP_H */ 231 232 /* Community 4 */ 233 { 2, 0, 181, 204, 256 }, /* GPP_C */ 234 { 2, 1, 205, 228, 288 }, /* GPP_E */ 235 }; 236 237 const struct pchgpio_device cnl_lp_device = 238 { 239 .pad_size = 16, 240 .gpi_is = 0x100, 241 .gpi_ie = 0x120, 242 .groups = cnl_lp_groups, 243 .ngroups = nitems(cnl_lp_groups), 244 .npins = 320, 245 }; 246 247 /* Tiger Lake-LP */ 248 249 const struct pchgpio_group tgl_lp_groups[] = 250 { 251 /* Community 0 */ 252 { 0, 0, 0, 25, 0 }, /* GPP_B */ 253 { 0, 1, 26, 41, 32 }, /* GPP_T */ 254 { 0, 2, 42, 66, 64 }, /* GPP_A */ 255 256 /* Community 1 */ 257 { 1, 0, 67, 74, 96 }, /* GPP_S */ 258 { 1, 1, 75, 98, 128 }, /* GPP_H */ 259 { 1, 2, 99, 119, 160 }, /* GPP_D */ 260 { 1, 3, 120, 143, 192 }, /* GPP_U */ 261 262 /* Community 4 */ 263 { 2, 0, 171, 194, 256 }, /* GPP_C */ 264 { 2, 1, 195, 219, 288 }, /* GPP_F */ 265 { 2, 3, 226, 250, 320 }, /* GPP_E */ 266 267 /* Community 5 */ 268 { 3, 0, 260, 267, 352 }, /* GPP_R */ 269 }; 270 271 const struct pchgpio_device tgl_lp_device = 272 { 273 .pad_size = 16, 274 .gpi_is = 0x100, 275 .gpi_ie = 0x120, 276 .groups = tgl_lp_groups, 277 .ngroups = nitems(tgl_lp_groups), 278 .npins = 360, 279 }; 280 281 /* Tiger Lake-H */ 282 283 const struct pchgpio_group tgl_h_groups[] = 284 { 285 /* Community 0 */ 286 { 0, 0, 0, 24, 0 }, /* GPP_A */ 287 { 0, 1, 25, 44, 32 }, /* GPP_R */ 288 { 0, 2, 45, 70, 64 }, /* GPP_B */ 289 290 /* Community 1 */ 291 { 1, 0, 79, 104, 128 }, /* GPP_D */ 292 { 1, 1, 105, 128, 160 }, /* GPP_C */ 293 { 1, 2, 129, 136, 192 }, /* GPP_S */ 294 { 1, 3, 137, 153, 224 }, /* GPP_G */ 295 296 /* Community 3 */ 297 { 2, 0, 181, 193, 288 }, /* GPP_E */ 298 { 2, 1, 194, 217, 320 }, /* GPP_F */ 299 300 /* Community 4 */ 301 { 2, 0, 218, 241, 352 }, /* GPP_H */ 302 { 2, 1, 242, 251, 384 }, /* GPP_J */ 303 { 2, 2, 252, 266, 416 }, /* GPP_K */ 304 305 /* Community 5 */ 306 { 3, 0, 267, 281, 448 }, /* GPP_I */ 307 }; 308 309 const struct pchgpio_device tgl_h_device = 310 { 311 .pad_size = 16, 312 .gpi_is = 0x100, 313 .gpi_ie = 0x120, 314 .groups = tgl_h_groups, 315 .ngroups = nitems(tgl_h_groups), 316 .npins = 480, 317 }; 318 319 /* Alder Lake-S */ 320 321 const struct pchgpio_group adl_s_groups[] = 322 { 323 /* Community 0 */ 324 { 0, 0, 0, 24, 0 }, /* GPP_I */ 325 { 0, 1, 25, 47, 32 }, /* GPP_R */ 326 { 0, 2, 48, 59, 64 }, /* GPP_J */ 327 328 /* Community 1 */ 329 { 1, 0, 95, 118, 160 }, /* GPP_B */ 330 { 1, 1, 119, 126, 192 }, /* GPP_G */ 331 { 1, 2, 127, 150, 224 }, /* GPP_H */ 332 333 /* Community 3 */ 334 { 2, 1, 160, 175, 256 }, /* GPP_A */ 335 { 2, 2, 176, 199, 288 }, /* GPP_C */ 336 337 /* Community 4 */ 338 { 3, 0, 200, 207, 320 }, /* GPP_S */ 339 { 3, 1, 208, 230, 352 }, /* GPP_E */ 340 { 3, 2, 231, 245, 384 }, /* GPP_K */ 341 { 3, 3, 246, 269, 416 }, /* GPP_F */ 342 343 /* Community 5 */ 344 { 4, 0, 270, 294, 448 }, /* GPP_D */ 345 }; 346 347 const struct pchgpio_device adl_s_device = 348 { 349 .pad_size = 16, 350 .gpi_is = 0x200, 351 .gpi_ie = 0x220, 352 .groups = adl_s_groups, 353 .ngroups = nitems(adl_s_groups), 354 .npins = 480, 355 }; 356 357 /* Alder Lake-N */ 358 359 const struct pchgpio_group adl_n_groups[] = 360 { 361 /* Community 0 */ 362 { 0, 0, 0, 25, 0 }, /* GPP_B */ 363 { 0, 1, 26, 41, 32 }, /* GPP_T */ 364 { 0, 2, 42, 66, 64 }, /* GPP_A */ 365 366 /* Community 1 */ 367 { 1, 0, 67, 74, 96 }, /* GPP_S */ 368 { 1, 1, 75, 94, 128 }, /* GPP_I */ 369 { 1, 2, 95, 118, 160 }, /* GPP_H */ 370 { 1, 3, 119, 139, 192 }, /* GPP_D */ 371 372 /* Community 4 */ 373 { 2, 0, 169, 192, 256 }, /* GPP_C */ 374 { 2, 1, 193, 217, 288 }, /* GPP_F */ 375 { 2, 3, 224, 248, 320 }, /* GPP_E */ 376 377 /* Community 5 */ 378 { 3, 0, 249, 256, 352 }, /* GPP_R */ 379 }; 380 381 const struct pchgpio_device adl_n_device = 382 { 383 .pad_size = 16, 384 .gpi_is = 0x100, 385 .gpi_ie = 0x120, 386 .groups = adl_n_groups, 387 .ngroups = nitems(adl_n_groups), 388 .npins = 384, 389 }; 390 391 /* Meteor Lake-P */ 392 393 const struct pchgpio_group mtl_p_groups[] = 394 { 395 /* Community 0 */ 396 { 0, 1, 5, 28, 32 }, /* GPP_V */ 397 { 0, 2, 29, 52, 64 }, /* GPP_C */ 398 399 /* Community 1 */ 400 { 1, 0, 53, 77, 96 }, /* GPP_A */ 401 { 1, 1, 78, 102, 128 }, /* GPP_E */ 402 403 /* Community 3 */ 404 { 2, 0, 103, 128, 160 }, /* GPP_H */ 405 { 2, 1, 129, 154, 192 }, /* GPP_F */ 406 407 /* Community 4 */ 408 { 3, 0, 184, 191, 288 }, /* GPP_S */ 409 410 /* Community 5 */ 411 { 4, 0, 204, 228, 352 }, /* GPP_B */ 412 { 4, 1, 229, 253, 384 }, /* GPP_D */ 413 }; 414 415 const struct pchgpio_device mtl_p_device = 416 { 417 .pad_size = 16, 418 .gpi_is = 0x200, 419 .gpi_ie = 0x210, 420 .groups = mtl_p_groups, 421 .ngroups = nitems(mtl_p_groups), 422 .npins = 416, 423 }; 424 425 /* Meteor Lake-S */ 426 427 const struct pchgpio_group mtl_s_groups[] = 428 { 429 /* Community 0 */ 430 { 0, 0, 0, 27, 0 }, /* GPP_A */ 431 { 0, 2, 47, 73, 64 }, /* GPP_C */ 432 433 /* Community 1 */ 434 { 1, 0, 74, 93, 96 }, /* GPP_B */ 435 { 1, 2, 96, 119, 160 }, /* GPP_D */ 436 }; 437 438 const struct pchgpio_device mtl_s_device = 439 { 440 .pad_size = 16, 441 .gpi_is = 0x200, 442 .gpi_ie = 0x210, 443 .groups = mtl_s_groups, 444 .ngroups = nitems(mtl_s_groups), 445 .npins = 192, 446 }; 447 448 struct pchgpio_match pchgpio_devices[] = { 449 { "INT344B", &spt_lp_device }, 450 { "INT3450", &cnl_h_device }, 451 { "INT3451", &spt_h_device }, 452 { "INT345D", &spt_h_device }, 453 { "INT34BB", &cnl_lp_device }, 454 { "INT34C5", &tgl_lp_device }, 455 { "INT34C6", &tgl_h_device }, 456 { "INTC1055", &tgl_lp_device }, 457 { "INTC1056", &adl_s_device }, 458 { "INTC1057", &adl_n_device }, 459 { "INTC1085", &adl_s_device }, 460 { "INTC1082", &mtl_s_device }, 461 { "INTC1083", &mtl_p_device }, 462 }; 463 464 int pchgpio_read_pin(void *, int); 465 void pchgpio_write_pin(void *, int, int); 466 void pchgpio_intr_establish(void *, int, int, int (*)(void *), void *); 467 void pchgpio_intr_enable(void *, int); 468 void pchgpio_intr_disable(void *, int); 469 int pchgpio_intr(void *); 470 void pchgpio_save(struct pchgpio_softc *); 471 void pchgpio_restore(struct pchgpio_softc *); 472 473 int 474 pchgpio_match(struct device *parent, void *match, void *aux) 475 { 476 struct acpi_attach_args *aaa = aux; 477 struct cfdata *cf = match; 478 479 if (aaa->aaa_naddr < 1 || aaa->aaa_nirq < 1) 480 return 0; 481 return acpi_matchhids(aaa, pchgpio_hids, cf->cf_driver->cd_name); 482 } 483 484 void 485 pchgpio_attach(struct device *parent, struct device *self, void *aux) 486 { 487 struct pchgpio_softc *sc = (struct pchgpio_softc *)self; 488 struct acpi_attach_args *aaa = aux; 489 uint16_t bar; 490 int i; 491 492 sc->sc_acpi = (struct acpi_softc *)parent; 493 sc->sc_node = aaa->aaa_node; 494 printf(" %s", sc->sc_node->name); 495 496 printf(" addr"); 497 498 for (i = 0; i < aaa->aaa_naddr; i++) { 499 printf(" 0x%llx/0x%llx", aaa->aaa_addr[i], aaa->aaa_size[i]); 500 501 sc->sc_memt[i] = aaa->aaa_bst[i]; 502 if (bus_space_map(sc->sc_memt[i], aaa->aaa_addr[i], 503 aaa->aaa_size[i], 0, &sc->sc_memh[i])) { 504 printf(": can't map registers\n"); 505 goto unmap; 506 } 507 508 sc->sc_padbar[i] = bus_space_read_4(sc->sc_memt[i], 509 sc->sc_memh[i], PCHGPIO_PADBAR); 510 sc->sc_naddr++; 511 } 512 513 printf(" irq %d", aaa->aaa_irq[0]); 514 515 for (i = 0; i < nitems(pchgpio_devices); i++) { 516 if (strcmp(pchgpio_devices[i].hid, aaa->aaa_dev) == 0) { 517 sc->sc_device = pchgpio_devices[i].device; 518 break; 519 } 520 } 521 KASSERT(sc->sc_device); 522 523 /* Figure out the first pin for each community. */ 524 bar = -1; 525 for (i = 0; i < sc->sc_device->ngroups; i++) { 526 if (sc->sc_device->groups[i].bar != bar) { 527 bar = sc->sc_device->groups[i].bar; 528 sc->sc_padbase[bar] = sc->sc_device->groups[i].base; 529 } 530 } 531 532 sc->sc_padsize = sc->sc_device->pad_size; 533 sc->sc_npins = sc->sc_device->npins; 534 sc->sc_pin_cfg = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_cfg), 535 M_DEVBUF, M_WAITOK); 536 sc->sc_pin_ih = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_ih), 537 M_DEVBUF, M_WAITOK | M_ZERO); 538 539 sc->sc_ih = acpi_intr_establish(aaa->aaa_irq[0], aaa->aaa_irq_flags[0], 540 IPL_BIO, pchgpio_intr, sc, sc->sc_dev.dv_xname); 541 if (sc->sc_ih == NULL) { 542 printf(": can't establish interrupt\n"); 543 goto unmap; 544 } 545 546 sc->sc_gpio.cookie = sc; 547 sc->sc_gpio.read_pin = pchgpio_read_pin; 548 sc->sc_gpio.write_pin = pchgpio_write_pin; 549 sc->sc_gpio.intr_establish = pchgpio_intr_establish; 550 sc->sc_gpio.intr_enable = pchgpio_intr_enable; 551 sc->sc_gpio.intr_disable = pchgpio_intr_disable; 552 sc->sc_node->gpio = &sc->sc_gpio; 553 554 printf(", %d pins\n", sc->sc_npins); 555 556 acpi_register_gpio(sc->sc_acpi, sc->sc_node); 557 return; 558 559 unmap: 560 free(sc->sc_pin_ih, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_ih)); 561 free(sc->sc_pin_cfg, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_cfg)); 562 for (i = 0; i < sc->sc_naddr; i++) 563 bus_space_unmap(sc->sc_memt[i], sc->sc_memh[i], 564 aaa->aaa_size[i]); 565 } 566 567 int 568 pchgpio_activate(struct device *self, int act) 569 { 570 struct pchgpio_softc *sc = (struct pchgpio_softc *)self; 571 572 switch (act) { 573 case DVACT_SUSPEND: 574 pchgpio_save(sc); 575 break; 576 case DVACT_RESUME: 577 pchgpio_restore(sc); 578 break; 579 } 580 581 return 0; 582 } 583 584 const struct pchgpio_group * 585 pchgpio_find_group(struct pchgpio_softc *sc, int pin) 586 { 587 int i, npads; 588 589 for (i = 0; i < sc->sc_device->ngroups; i++) { 590 npads = 1 + sc->sc_device->groups[i].limit - 591 sc->sc_device->groups[i].base; 592 593 if (pin >= sc->sc_device->groups[i].gpiobase && 594 pin < sc->sc_device->groups[i].gpiobase + npads) 595 return &sc->sc_device->groups[i]; 596 } 597 return NULL; 598 } 599 600 int 601 pchgpio_read_pin(void *cookie, int pin) 602 { 603 struct pchgpio_softc *sc = cookie; 604 const struct pchgpio_group *group; 605 uint32_t reg; 606 uint16_t pad; 607 uint8_t bar; 608 609 group = pchgpio_find_group(sc, pin); 610 bar = group->bar; 611 pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar]; 612 613 reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 614 sc->sc_padbar[bar] + pad * sc->sc_padsize); 615 616 return !!(reg & PCHGPIO_CONF_RXSTATE); 617 } 618 619 void 620 pchgpio_write_pin(void *cookie, int pin, int value) 621 { 622 struct pchgpio_softc *sc = cookie; 623 const struct pchgpio_group *group; 624 uint32_t reg; 625 uint16_t pad; 626 uint8_t bar; 627 628 group = pchgpio_find_group(sc, pin); 629 bar = group->bar; 630 pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar]; 631 632 reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 633 sc->sc_padbar[bar] + pad * sc->sc_padsize); 634 if (value) 635 reg |= PCHGPIO_CONF_TXSTATE; 636 else 637 reg &= ~PCHGPIO_CONF_TXSTATE; 638 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 639 sc->sc_padbar[bar] + pad * sc->sc_padsize, reg); 640 } 641 642 void 643 pchgpio_intr_establish(void *cookie, int pin, int flags, 644 int (*func)(void *), void *arg) 645 { 646 struct pchgpio_softc *sc = cookie; 647 const struct pchgpio_group *group; 648 uint32_t reg; 649 uint16_t pad; 650 uint8_t bank, bar; 651 652 KASSERT(pin >= 0); 653 654 group = pchgpio_find_group(sc, pin); 655 if (group == NULL) 656 return; 657 658 bar = group->bar; 659 bank = group->bank; 660 pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar]; 661 662 sc->sc_pin_ih[pin].ih_func = func; 663 sc->sc_pin_ih[pin].ih_arg = arg; 664 665 reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 666 sc->sc_padbar[bar] + pad * sc->sc_padsize); 667 reg &= ~(PCHGPIO_CONF_RXEV_MASK | PCHGPIO_CONF_RXINV); 668 if ((flags & LR_GPIO_MODE) == 1) 669 reg |= PCHGPIO_CONF_RXEV_EDGE; 670 if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTLO) 671 reg |= PCHGPIO_CONF_RXINV; 672 if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTBOTH) 673 reg |= PCHGPIO_CONF_RXEV_EDGE | PCHGPIO_CONF_RXEV_ZERO; 674 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 675 sc->sc_padbar[bar] + pad * sc->sc_padsize, reg); 676 677 reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 678 sc->sc_device->gpi_ie + bank * 4); 679 reg |= (1 << (pin - group->gpiobase)); 680 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 681 sc->sc_device->gpi_ie + bank * 4, reg); 682 } 683 684 void 685 pchgpio_intr_enable(void *cookie, int pin) 686 { 687 struct pchgpio_softc *sc = cookie; 688 const struct pchgpio_group *group; 689 uint32_t reg; 690 uint16_t pad; 691 uint8_t bank, bar; 692 693 KASSERT(pin >= 0); 694 695 group = pchgpio_find_group(sc, pin); 696 if (group == NULL) 697 return; 698 699 bar = group->bar; 700 bank = group->bank; 701 pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar]; 702 703 reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 704 sc->sc_device->gpi_ie + bank * 4); 705 reg |= (1 << (pin - group->gpiobase)); 706 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 707 sc->sc_device->gpi_ie + bank * 4, reg); 708 } 709 710 void 711 pchgpio_intr_disable(void *cookie, int pin) 712 { 713 struct pchgpio_softc *sc = cookie; 714 const struct pchgpio_group *group; 715 uint32_t reg; 716 uint16_t pad; 717 uint8_t bank, bar; 718 719 KASSERT(pin >= 0); 720 721 group = pchgpio_find_group(sc, pin); 722 if (group == NULL) 723 return; 724 725 bar = group->bar; 726 bank = group->bank; 727 pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar]; 728 729 reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 730 sc->sc_device->gpi_ie + bank * 4); 731 reg &= ~(1 << (pin - group->gpiobase)); 732 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 733 sc->sc_device->gpi_ie + bank * 4, reg); 734 } 735 736 int 737 pchgpio_intr_handle(struct pchgpio_softc *sc, int group, int bit) 738 { 739 uint32_t enable; 740 int gpiobase, pin, handled = 0; 741 uint8_t bank, bar; 742 743 bar = sc->sc_device->groups[group].bar; 744 bank = sc->sc_device->groups[group].bank; 745 gpiobase = sc->sc_device->groups[group].gpiobase; 746 747 pin = gpiobase + bit; 748 if (sc->sc_pin_ih[pin].ih_func) { 749 sc->sc_pin_ih[pin].ih_func(sc->sc_pin_ih[pin].ih_arg); 750 handled = 1; 751 } else { 752 /* Mask unhandled interrupt */ 753 enable = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 754 sc->sc_device->gpi_ie + bank * 4); 755 enable &= ~(1 << bit); 756 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 757 sc->sc_device->gpi_ie + bank * 4, enable); 758 } 759 760 return handled; 761 } 762 763 int 764 pchgpio_intr(void *arg) 765 { 766 struct pchgpio_softc *sc = arg; 767 uint32_t status, enable; 768 int group, bit, handled = 0; 769 uint16_t base, limit; 770 uint8_t bank, bar; 771 772 for (group = 0; group < sc->sc_device->ngroups; group++) { 773 bar = sc->sc_device->groups[group].bar; 774 bank = sc->sc_device->groups[group].bank; 775 base = sc->sc_device->groups[group].base; 776 limit = sc->sc_device->groups[group].limit; 777 778 status = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 779 sc->sc_device->gpi_is + bank * 4); 780 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 781 sc->sc_device->gpi_is + bank * 4, status); 782 enable = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 783 sc->sc_device->gpi_ie + bank * 4); 784 status &= enable; 785 if (status == 0) 786 continue; 787 788 for (bit = 0; bit <= (limit - base); bit++) { 789 if (status & (1 << bit)) 790 handled |= pchgpio_intr_handle(sc, group, bit); 791 } 792 } 793 794 return handled; 795 } 796 797 void 798 pchgpio_save_pin(struct pchgpio_softc *sc, int pin) 799 { 800 const struct pchgpio_group *group; 801 uint32_t gpi_ie; 802 uint16_t pad; 803 uint8_t bank, bar; 804 805 group = pchgpio_find_group(sc, pin); 806 if (group == NULL) 807 return; 808 809 bar = group->bar; 810 bank = group->bank; 811 pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar]; 812 813 sc->sc_pin_cfg[pin].pad_cfg_dw0 = 814 bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 815 sc->sc_padbar[bar] + pad * sc->sc_padsize); 816 sc->sc_pin_cfg[pin].pad_cfg_dw1 = 817 bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 818 sc->sc_padbar[bar] + pad * sc->sc_padsize + 4); 819 820 gpi_ie = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 821 sc->sc_device->gpi_ie + bank * 4); 822 sc->sc_pin_cfg[pin].gpi_ie = (gpi_ie & (1 << (pin - group->gpiobase))); 823 } 824 825 void 826 pchgpio_save(struct pchgpio_softc *sc) 827 { 828 int pin; 829 830 for (pin = 0; pin < sc->sc_npins; pin++) 831 pchgpio_save_pin(sc, pin); 832 } 833 834 void 835 pchgpio_restore_pin(struct pchgpio_softc *sc, int pin) 836 { 837 const struct pchgpio_group *group; 838 int restore = 0; 839 uint32_t pad_cfg_dw0, gpi_ie; 840 uint16_t pad; 841 uint8_t bank, bar; 842 843 group = pchgpio_find_group(sc, pin); 844 if (group == NULL) 845 return; 846 847 bar = group->bar; 848 bank = group->bank; 849 pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar]; 850 851 pad_cfg_dw0 = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 852 sc->sc_padbar[bar] + pad * sc->sc_padsize); 853 854 if (sc->sc_pin_ih[pin].ih_func) 855 restore = 1; 856 857 /* 858 * The BIOS on Lenovo Thinkpads based on Intel's Tiger Lake 859 * platform have a bug where the GPIO pin that is used for the 860 * touchpad interrupt gets reset when entering S3 and isn't 861 * properly restored upon resume. We detect this issue by 862 * comparing the bits in the PAD_CFG_DW0 register PADRSTCFG 863 * field before suspend and after resume and restore the pin 864 * configuration if the bits don't match. 865 */ 866 if ((sc->sc_pin_cfg[pin].pad_cfg_dw0 & PCHGPIO_CONF_PADRSTCFG_MASK) != 867 (pad_cfg_dw0 & PCHGPIO_CONF_PADRSTCFG_MASK)) 868 restore = 1; 869 870 if (restore) { 871 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 872 sc->sc_padbar[bar] + pad * sc->sc_padsize, 873 sc->sc_pin_cfg[pin].pad_cfg_dw0); 874 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 875 sc->sc_padbar[bar] + pad * sc->sc_padsize + 4, 876 sc->sc_pin_cfg[pin].pad_cfg_dw1); 877 878 gpi_ie = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 879 sc->sc_device->gpi_ie + bank * 4); 880 if (sc->sc_pin_cfg[pin].gpi_ie) 881 gpi_ie |= (1 << (pin - group->gpiobase)); 882 else 883 gpi_ie &= ~(1 << (pin - group->gpiobase)); 884 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 885 sc->sc_device->gpi_ie + bank * 4, gpi_ie); 886 } 887 } 888 889 void 890 pchgpio_restore(struct pchgpio_softc *sc) 891 { 892 int pin; 893 894 for (pin = 0; pin < sc->sc_npins; pin++) 895 pchgpio_restore_pin(sc, pin); 896 } 897