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