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