pchgpio.c revision 1.7
1/* $OpenBSD: pchgpio.c,v 1.7 2021/09/21 14:59:13 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 4 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 100struct 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 "INT34BB", 111 "INT34C5", 112 NULL 113}; 114 115const struct pchgpio_group cnl_lp_groups[] = 116{ 117 /* Community 0 */ 118 { 0, 0, 0, 24, 0 }, /* GPP_A */ 119 { 0, 1, 25, 50, 32 }, /* GPP_B */ 120 { 0, 2, 51, 58, 64 }, /* GPP_G */ 121 122 /* Community 1 */ 123 { 1, 0, 68, 92, 96 }, /* GPP_D */ 124 { 1, 1, 93, 116, 128 }, /* GPP_F */ 125 { 1, 2, 117, 140, 160 }, /* GPP_H */ 126 127 /* Community 4 */ 128 { 2, 0, 181, 204, 256 }, /* GPP_C */ 129 { 2, 1, 205, 228, 288 }, /* GPP_E */ 130}; 131 132const struct pchgpio_device cnl_lp_device = 133{ 134 .pad_size = 16, 135 .gpi_is = 0x100, 136 .gpi_ie = 0x120, 137 .groups = cnl_lp_groups, 138 .ngroups = nitems(cnl_lp_groups), 139 .npins = 320, 140}; 141 142const struct pchgpio_group tgl_lp_groups[] = 143{ 144 /* Community 0 */ 145 { 0, 0, 0, 25, 0 }, /* GPP_B */ 146 { 0, 1, 26, 41, 32 }, /* GPP_T */ 147 { 0, 2, 42, 66, 64 }, /* GPP_A */ 148 149 /* Community 1 */ 150 { 1, 0, 67, 74, 96 }, /* GPP_S */ 151 { 1, 1, 75, 98, 128 }, /* GPP_H */ 152 { 1, 2, 99, 119, 160 }, /* GPP_D */ 153 { 1, 3, 120, 143, 192 }, /* GPP_U */ 154 155 /* Community 4 */ 156 { 2, 0, 171, 194, 256 }, /* GPP_C */ 157 { 2, 1, 195, 219, 288 }, /* GPP_F */ 158 { 2, 3, 226, 250, 320 }, /* GPP_E */ 159 160 /* Community 5 */ 161 { 3, 0, 260, 267, 352 }, /* GPP_R */ 162}; 163 164const struct pchgpio_device tgl_lp_device = 165{ 166 .pad_size = 16, 167 .gpi_is = 0x100, 168 .gpi_ie = 0x120, 169 .groups = tgl_lp_groups, 170 .ngroups = nitems(tgl_lp_groups), 171 .npins = 360, 172}; 173 174struct pchgpio_match pchgpio_devices[] = { 175 { "INT34BB", &cnl_lp_device }, 176 { "INT34C5", &tgl_lp_device }, 177}; 178 179int pchgpio_read_pin(void *, int); 180void pchgpio_write_pin(void *, int, int); 181void pchgpio_intr_establish(void *, int, int, int (*)(void *), void *); 182int pchgpio_intr(void *); 183void pchgpio_save(struct pchgpio_softc *); 184void pchgpio_restore(struct pchgpio_softc *); 185 186int 187pchgpio_match(struct device *parent, void *match, void *aux) 188{ 189 struct acpi_attach_args *aaa = aux; 190 struct cfdata *cf = match; 191 192 return acpi_matchhids(aaa, pchgpio_hids, cf->cf_driver->cd_name); 193} 194 195void 196pchgpio_attach(struct device *parent, struct device *self, void *aux) 197{ 198 struct pchgpio_softc *sc = (struct pchgpio_softc *)self; 199 struct acpi_attach_args *aaa = aux; 200 uint16_t bar; 201 int i; 202 203 sc->sc_acpi = (struct acpi_softc *)parent; 204 sc->sc_node = aaa->aaa_node; 205 printf(" %s", sc->sc_node->name); 206 207 if (aaa->aaa_naddr < 1) { 208 printf(": no registers\n"); 209 return; 210 } 211 212 if (aaa->aaa_nirq < 1) { 213 printf(": no interrupt\n"); 214 return; 215 } 216 217 printf(" addr"); 218 219 for (i = 0; i < aaa->aaa_naddr; i++) { 220 printf(" 0x%llx/0x%llx", aaa->aaa_addr[i], aaa->aaa_size[i]); 221 222 sc->sc_memt[i] = aaa->aaa_bst[i]; 223 if (bus_space_map(sc->sc_memt[i], aaa->aaa_addr[i], 224 aaa->aaa_size[i], 0, &sc->sc_memh[i])) { 225 printf(": can't map registers\n"); 226 goto unmap; 227 } 228 229 sc->sc_padbar[i] = bus_space_read_4(sc->sc_memt[i], 230 sc->sc_memh[i], PCHGPIO_PADBAR); 231 sc->sc_naddr++; 232 } 233 234 printf(" irq %d", aaa->aaa_irq[0]); 235 236 for (i = 0; i < nitems(pchgpio_devices); i++) { 237 if (strcmp(pchgpio_devices[i].hid, aaa->aaa_dev) == 0) { 238 sc->sc_device = pchgpio_devices[i].device; 239 break; 240 } 241 } 242 KASSERT(sc->sc_device); 243 244 /* Figure out the first pin for each community. */ 245 bar = -1; 246 for (i = 0; i < sc->sc_device->ngroups; i++) { 247 if (sc->sc_device->groups[i].bar != bar) { 248 bar = sc->sc_device->groups[i].bar; 249 sc->sc_padbase[bar] = sc->sc_device->groups[i].base; 250 } 251 } 252 253 sc->sc_padsize = sc->sc_device->pad_size; 254 sc->sc_npins = sc->sc_device->npins; 255 sc->sc_pin_cfg = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_cfg), 256 M_DEVBUF, M_WAITOK); 257 sc->sc_pin_ih = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_ih), 258 M_DEVBUF, M_WAITOK | M_ZERO); 259 260 sc->sc_ih = acpi_intr_establish(aaa->aaa_irq[0], aaa->aaa_irq_flags[0], 261 IPL_BIO, pchgpio_intr, sc, sc->sc_dev.dv_xname); 262 if (sc->sc_ih == NULL) { 263 printf(": can't establish interrupt\n"); 264 goto unmap; 265 } 266 267 sc->sc_gpio.cookie = sc; 268 sc->sc_gpio.read_pin = pchgpio_read_pin; 269 sc->sc_gpio.write_pin = pchgpio_write_pin; 270 sc->sc_gpio.intr_establish = pchgpio_intr_establish; 271 sc->sc_node->gpio = &sc->sc_gpio; 272 273 printf(", %d pins\n", sc->sc_npins); 274 275 acpi_register_gpio(sc->sc_acpi, sc->sc_node); 276 return; 277 278unmap: 279 free(sc->sc_pin_ih, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_ih)); 280 free(sc->sc_pin_cfg, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_cfg)); 281 for (i = 0; i < sc->sc_naddr; i++) 282 bus_space_unmap(sc->sc_memt[i], sc->sc_memh[i], 283 aaa->aaa_size[i]); 284} 285 286int 287pchgpio_activate(struct device *self, int act) 288{ 289 struct pchgpio_softc *sc = (struct pchgpio_softc *)self; 290 291 switch (act) { 292 case DVACT_SUSPEND: 293 pchgpio_save(sc); 294 break; 295 case DVACT_RESUME: 296 pchgpio_restore(sc); 297 break; 298 } 299 300 return 0; 301} 302 303const struct pchgpio_group * 304pchgpio_find_group(struct pchgpio_softc *sc, int pin) 305{ 306 int i, npads; 307 308 for (i = 0; i < sc->sc_device->ngroups; i++) { 309 npads = 1 + sc->sc_device->groups[i].limit - 310 sc->sc_device->groups[i].base; 311 312 if (pin >= sc->sc_device->groups[i].gpiobase && 313 pin < sc->sc_device->groups[i].gpiobase + npads) 314 return &sc->sc_device->groups[i]; 315 } 316 return NULL; 317} 318 319int 320pchgpio_read_pin(void *cookie, int pin) 321{ 322 struct pchgpio_softc *sc = cookie; 323 const struct pchgpio_group *group; 324 uint32_t reg; 325 uint16_t pad; 326 uint8_t bar; 327 328 group = pchgpio_find_group(sc, pin); 329 bar = group->bar; 330 pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar]; 331 332 reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 333 sc->sc_padbar[bar] + pad * sc->sc_padsize); 334 335 return !!(reg & PCHGPIO_CONF_RXSTATE); 336} 337 338void 339pchgpio_write_pin(void *cookie, int pin, int value) 340{ 341 struct pchgpio_softc *sc = cookie; 342 const struct pchgpio_group *group; 343 uint32_t reg; 344 uint16_t pad; 345 uint8_t bar; 346 347 group = pchgpio_find_group(sc, pin); 348 bar = group->bar; 349 pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar]; 350 351 reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 352 sc->sc_padbar[bar] + pad * sc->sc_padsize); 353 if (value) 354 reg |= PCHGPIO_CONF_TXSTATE; 355 else 356 reg &= ~PCHGPIO_CONF_TXSTATE; 357 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 358 sc->sc_padbar[bar] + pad * sc->sc_padsize, reg); 359} 360 361void 362pchgpio_intr_establish(void *cookie, int pin, int flags, 363 int (*func)(void *), void *arg) 364{ 365 struct pchgpio_softc *sc = cookie; 366 const struct pchgpio_group *group; 367 uint32_t reg; 368 uint16_t pad; 369 uint8_t bank, bar; 370 371 KASSERT(pin >= 0); 372 373 group = pchgpio_find_group(sc, pin); 374 if (group == NULL) 375 return; 376 377 bar = group->bar; 378 bank = group->bank; 379 pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar]; 380 381 sc->sc_pin_ih[pin].ih_func = func; 382 sc->sc_pin_ih[pin].ih_arg = arg; 383 384 reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 385 sc->sc_padbar[bar] + pad * sc->sc_padsize); 386 reg &= ~(PCHGPIO_CONF_RXEV_MASK | PCHGPIO_CONF_RXINV); 387 if ((flags & LR_GPIO_MODE) == 1) 388 reg |= PCHGPIO_CONF_RXEV_EDGE; 389 if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTLO) 390 reg |= PCHGPIO_CONF_RXINV; 391 if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTBOTH) 392 reg |= PCHGPIO_CONF_RXEV_EDGE | PCHGPIO_CONF_RXEV_ZERO; 393 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 394 sc->sc_padbar[bar] + pad * sc->sc_padsize, reg); 395 396 reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 397 sc->sc_device->gpi_ie + bank * 4); 398 reg |= (1 << (pin - group->gpiobase)); 399 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 400 sc->sc_device->gpi_ie + bank * 4, reg); 401} 402 403int 404pchgpio_intr(void *arg) 405{ 406 struct pchgpio_softc *sc = arg; 407 uint32_t status, enable; 408 int gpiobase, group, bit, pin, handled = 0; 409 uint16_t base, limit; 410 uint8_t bank, bar; 411 412 for (group = 0; group < sc->sc_device->ngroups; group++) { 413 bar = sc->sc_device->groups[group].bar; 414 bank = sc->sc_device->groups[group].bank; 415 base = sc->sc_device->groups[group].base; 416 limit = sc->sc_device->groups[group].limit; 417 gpiobase = sc->sc_device->groups[group].gpiobase; 418 419 status = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 420 sc->sc_device->gpi_is + bank * 4); 421 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 422 sc->sc_device->gpi_is + bank * 4, status); 423 enable = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 424 sc->sc_device->gpi_ie + bank * 4); 425 status &= enable; 426 if (status == 0) 427 continue; 428 429 for (bit = 0; bit <= (limit - base); bit++) { 430 pin = gpiobase + bit; 431 if (status & (1 << bit) && sc->sc_pin_ih[pin].ih_func) 432 sc->sc_pin_ih[pin].ih_func(sc->sc_pin_ih[pin].ih_arg); 433 handled = 1; 434 } 435 } 436 437 return handled; 438} 439 440void 441pchgpio_save_pin(struct pchgpio_softc *sc, int pin) 442{ 443 const struct pchgpio_group *group; 444 uint32_t gpi_ie; 445 uint16_t pad; 446 uint8_t bank, bar; 447 448 group = pchgpio_find_group(sc, pin); 449 if (group == NULL) 450 return; 451 452 bar = group->bar; 453 bank = group->bank; 454 pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar]; 455 456 sc->sc_pin_cfg[pin].pad_cfg_dw0 = 457 bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 458 sc->sc_padbar[bar] + pad * sc->sc_padsize); 459 sc->sc_pin_cfg[pin].pad_cfg_dw1 = 460 bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 461 sc->sc_padbar[bar] + pad * sc->sc_padsize + 4); 462 463 gpi_ie = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 464 sc->sc_device->gpi_ie + bank * 4); 465 sc->sc_pin_cfg[pin].gpi_ie = (gpi_ie & (1 << (pin - group->gpiobase))); 466} 467 468void 469pchgpio_save(struct pchgpio_softc *sc) 470{ 471 int pin; 472 473 for (pin = 0; pin < sc->sc_npins; pin++) 474 pchgpio_save_pin(sc, pin); 475} 476 477void 478pchgpio_restore_pin(struct pchgpio_softc *sc, int pin) 479{ 480 const struct pchgpio_group *group; 481 int restore = 0; 482 uint32_t pad_cfg_dw0, gpi_ie; 483 uint16_t pad; 484 uint8_t bank, bar; 485 486 group = pchgpio_find_group(sc, pin); 487 if (group == NULL) 488 return; 489 490 bar = group->bar; 491 bank = group->bank; 492 pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar]; 493 494 pad_cfg_dw0 = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 495 sc->sc_padbar[bar] + pad * sc->sc_padsize); 496 497 if (sc->sc_pin_ih[pin].ih_func) 498 restore = 1; 499 500 /* 501 * The BIOS on Lenovo Thinkpads based on Intel's Tiger Lake 502 * platform have a bug where the GPIO pin that is used for the 503 * touchpad interrupt gets reset when entering S3 and isn't 504 * properly restored upon resume. We detect this issue by 505 * comparing the bits in the PAD_CFG_DW0 register PADRSTCFG 506 * field before suspend and after resume and restore the pin 507 * configuration if the bits don't match. 508 */ 509 if ((sc->sc_pin_cfg[pin].pad_cfg_dw0 & PCHGPIO_CONF_PADRSTCFG_MASK) != 510 (pad_cfg_dw0 & PCHGPIO_CONF_PADRSTCFG_MASK)) 511 restore = 1; 512 513 if (restore) { 514 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 515 sc->sc_padbar[bar] + pad * sc->sc_padsize, 516 sc->sc_pin_cfg[pin].pad_cfg_dw0); 517 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 518 sc->sc_padbar[bar] + pad * sc->sc_padsize + 4, 519 sc->sc_pin_cfg[pin].pad_cfg_dw1); 520 521 gpi_ie = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 522 sc->sc_device->gpi_ie + bank * 4); 523 if (sc->sc_pin_cfg[pin].gpi_ie) 524 gpi_ie |= (1 << (pin - group->gpiobase)); 525 else 526 gpi_ie &= ~(1 << (pin - group->gpiobase)); 527 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 528 sc->sc_device->gpi_ie + bank * 4, gpi_ie); 529 } 530} 531 532void 533pchgpio_restore(struct pchgpio_softc *sc) 534{ 535 int pin; 536 537 for (pin = 0; pin < sc->sc_npins; pin++) 538 pchgpio_restore_pin(sc, pin); 539} 540