pchgpio.c revision 1.5
1/* $OpenBSD: pchgpio.c,v 1.5 2021/08/30 18:40:19 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 38#define PCHGPIO_PADBAR 0x00c 39 40struct pchgpio_group { 41 uint8_t bar; 42 uint8_t bank; 43 uint16_t base; 44 uint16_t limit; 45 int16_t gpiobase; 46}; 47 48struct pchgpio_device { 49 uint16_t pad_size; 50 uint16_t gpi_is; 51 uint16_t gpi_ie; 52 const struct pchgpio_group *groups; 53 int ngroups; 54 int npins; 55}; 56 57struct pchgpio_match { 58 const char *hid; 59 const struct pchgpio_device *device; 60}; 61 62struct pchgpio_intrhand { 63 int (*ih_func)(void *); 64 void *ih_arg; 65}; 66 67struct pchgpio_softc { 68 struct device sc_dev; 69 struct acpi_softc *sc_acpi; 70 struct aml_node *sc_node; 71 72 bus_space_tag_t sc_memt[PCHGPIO_MAXCOM]; 73 bus_space_handle_t sc_memh[PCHGPIO_MAXCOM]; 74 void *sc_ih; 75 int sc_naddr; 76 77 const struct pchgpio_device *sc_device; 78 uint16_t sc_padbar[PCHGPIO_MAXCOM]; 79 uint16_t sc_padbase[PCHGPIO_MAXCOM]; 80 int sc_padsize; 81 82 int sc_npins; 83 struct pchgpio_intrhand *sc_pin_ih; 84 85 struct acpi_gpio sc_gpio; 86}; 87 88int pchgpio_match(struct device *, void *, void *); 89void pchgpio_attach(struct device *, struct device *, void *); 90 91struct cfattach pchgpio_ca = { 92 sizeof(struct pchgpio_softc), pchgpio_match, pchgpio_attach 93}; 94 95struct cfdriver pchgpio_cd = { 96 NULL, "pchgpio", DV_DULL 97}; 98 99const char *pchgpio_hids[] = { 100 "INT34BB", 101 "INT34C5", 102 NULL 103}; 104 105const struct pchgpio_group cnl_lp_groups[] = 106{ 107 /* Community 0 */ 108 { 0, 0, 0, 24, 0 }, /* GPP_A */ 109 { 0, 1, 25, 50, 32 }, /* GPP_B */ 110 { 0, 2, 51, 58, 64 }, /* GPP_G */ 111 112 /* Community 1 */ 113 { 1, 0, 68, 92, 96 }, /* GPP_D */ 114 { 1, 1, 93, 116, 128 }, /* GPP_F */ 115 { 1, 2, 117, 140, 160 }, /* GPP_H */ 116 117 /* Community 4 */ 118 { 2, 0, 181, 204, 256 }, /* GPP_C */ 119 { 2, 1, 205, 228, 288 }, /* GPP_E */ 120}; 121 122const struct pchgpio_device cnl_lp_device = 123{ 124 .pad_size = 16, 125 .gpi_is = 0x100, 126 .gpi_ie = 0x120, 127 .groups = cnl_lp_groups, 128 .ngroups = nitems(cnl_lp_groups), 129 .npins = 320, 130}; 131 132const struct pchgpio_group tgl_lp_groups[] = 133{ 134 /* Community 0 */ 135 { 0, 0, 0, 25, 0 }, /* GPP_B */ 136 { 0, 1, 26, 41, 32 }, /* GPP_T */ 137 { 0, 2, 42, 66, 64 }, /* GPP_A */ 138 139 /* Community 1 */ 140 { 1, 0, 67, 74, 96 }, /* GPP_S */ 141 { 1, 1, 75, 98, 128 }, /* GPP_H */ 142 { 1, 2, 99, 119, 160 }, /* GPP_D */ 143 { 1, 3, 120, 143, 192 }, /* GPP_U */ 144 145 /* Community 4 */ 146 { 2, 0, 171, 194, 256 }, /* GPP_C */ 147 { 2, 1, 195, 219, 288 }, /* GPP_F */ 148 { 2, 3, 226, 250, 320 }, /* GPP_E */ 149 150 /* Community 5 */ 151 { 3, 0, 260, 267, 352 }, /* GPP_R */ 152}; 153 154const struct pchgpio_device tgl_lp_device = 155{ 156 .pad_size = 16, 157 .gpi_is = 0x100, 158 .gpi_ie = 0x120, 159 .groups = tgl_lp_groups, 160 .ngroups = nitems(tgl_lp_groups), 161 .npins = 360, 162}; 163 164struct pchgpio_match pchgpio_devices[] = { 165 { "INT34BB", &cnl_lp_device }, 166 { "INT34C5", &tgl_lp_device }, 167}; 168 169int pchgpio_read_pin(void *, int); 170void pchgpio_write_pin(void *, int, int); 171void pchgpio_intr_establish(void *, int, int, int (*)(void *), void *); 172int pchgpio_intr(void *); 173 174int 175pchgpio_match(struct device *parent, void *match, void *aux) 176{ 177 struct acpi_attach_args *aaa = aux; 178 struct cfdata *cf = match; 179 180 return acpi_matchhids(aaa, pchgpio_hids, cf->cf_driver->cd_name); 181} 182 183void 184pchgpio_attach(struct device *parent, struct device *self, void *aux) 185{ 186 struct pchgpio_softc *sc = (struct pchgpio_softc *)self; 187 struct acpi_attach_args *aaa = aux; 188 uint16_t bar; 189 int i; 190 191 sc->sc_acpi = (struct acpi_softc *)parent; 192 sc->sc_node = aaa->aaa_node; 193 printf(" %s", sc->sc_node->name); 194 195 if (aaa->aaa_naddr < 1) { 196 printf(": no registers\n"); 197 return; 198 } 199 200 if (aaa->aaa_nirq < 1) { 201 printf(": no interrupt\n"); 202 return; 203 } 204 205 printf(" addr"); 206 207 for (i = 0; i < aaa->aaa_naddr; i++) { 208 printf(" 0x%llx/0x%llx", aaa->aaa_addr[i], aaa->aaa_size[i]); 209 210 sc->sc_memt[i] = aaa->aaa_bst[i]; 211 if (bus_space_map(sc->sc_memt[i], aaa->aaa_addr[i], 212 aaa->aaa_size[i], 0, &sc->sc_memh[i])) { 213 printf(": can't map registers\n"); 214 goto unmap; 215 } 216 217 sc->sc_padbar[i] = bus_space_read_4(sc->sc_memt[i], 218 sc->sc_memh[i], PCHGPIO_PADBAR); 219 sc->sc_naddr++; 220 } 221 222 printf(" irq %d", aaa->aaa_irq[0]); 223 224 for (i = 0; i < nitems(pchgpio_devices); i++) { 225 if (strcmp(pchgpio_devices[i].hid, aaa->aaa_dev) == 0) { 226 sc->sc_device = pchgpio_devices[i].device; 227 break; 228 } 229 } 230 KASSERT(sc->sc_device); 231 232 /* Figure out the first pin for each community. */ 233 bar = -1; 234 for (i = 0; i < sc->sc_device->ngroups; i++) { 235 if (sc->sc_device->groups[i].bar != bar) { 236 bar = sc->sc_device->groups[i].bar; 237 sc->sc_padbase[bar] = sc->sc_device->groups[i].base; 238 } 239 } 240 241 sc->sc_padsize = sc->sc_device->pad_size; 242 sc->sc_npins = sc->sc_device->npins; 243 sc->sc_pin_ih = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_ih), 244 M_DEVBUF, M_WAITOK | M_ZERO); 245 246 sc->sc_ih = acpi_intr_establish(aaa->aaa_irq[0], aaa->aaa_irq_flags[0], 247 IPL_BIO, pchgpio_intr, sc, sc->sc_dev.dv_xname); 248 if (sc->sc_ih == NULL) { 249 printf(": can't establish interrupt\n"); 250 goto unmap; 251 } 252 253 sc->sc_gpio.cookie = sc; 254 sc->sc_gpio.read_pin = pchgpio_read_pin; 255 sc->sc_gpio.write_pin = pchgpio_write_pin; 256 sc->sc_gpio.intr_establish = pchgpio_intr_establish; 257 sc->sc_node->gpio = &sc->sc_gpio; 258 259 printf(", %d pins\n", sc->sc_npins); 260 261 acpi_register_gpio(sc->sc_acpi, sc->sc_node); 262 return; 263 264unmap: 265 free(sc->sc_pin_ih, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_ih)); 266 for (i = 0; i < sc->sc_naddr; i++) 267 bus_space_unmap(sc->sc_memt[i], sc->sc_memh[i], 268 aaa->aaa_size[i]); 269} 270 271const struct pchgpio_group * 272pchgpio_find_group(struct pchgpio_softc *sc, int pin) 273{ 274 int i, npads; 275 276 for (i = 0; i < sc->sc_device->ngroups; i++) { 277 npads = 1 + sc->sc_device->groups[i].limit - 278 sc->sc_device->groups[i].base; 279 280 if (pin >= sc->sc_device->groups[i].gpiobase && 281 pin < sc->sc_device->groups[i].gpiobase + npads) 282 return &sc->sc_device->groups[i]; 283 } 284 return NULL; 285} 286 287int 288pchgpio_read_pin(void *cookie, int pin) 289{ 290 struct pchgpio_softc *sc = cookie; 291 const struct pchgpio_group *group; 292 uint32_t reg; 293 uint16_t pad; 294 uint8_t bar; 295 296 group = pchgpio_find_group(sc, pin); 297 bar = group->bar; 298 pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar]; 299 300 reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 301 sc->sc_padbar[bar] + pad * sc->sc_padsize); 302 303 return !!(reg & PCHGPIO_CONF_RXSTATE); 304} 305 306void 307pchgpio_write_pin(void *cookie, int pin, int value) 308{ 309 struct pchgpio_softc *sc = cookie; 310 const struct pchgpio_group *group; 311 uint32_t reg; 312 uint16_t pad; 313 uint8_t bar; 314 315 group = pchgpio_find_group(sc, pin); 316 bar = group->bar; 317 pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar]; 318 319 reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 320 sc->sc_padbar[bar] + pad * sc->sc_padsize); 321 if (value) 322 reg |= PCHGPIO_CONF_TXSTATE; 323 else 324 reg &= ~PCHGPIO_CONF_TXSTATE; 325 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 326 sc->sc_padbar[bar] + pad * sc->sc_padsize, reg); 327} 328 329void 330pchgpio_intr_establish(void *cookie, int pin, int flags, 331 int (*func)(void *), void *arg) 332{ 333 struct pchgpio_softc *sc = cookie; 334 const struct pchgpio_group *group; 335 uint32_t reg; 336 uint16_t pad; 337 uint8_t bank, bar; 338 339 KASSERT(pin >= 0); 340 341 group = pchgpio_find_group(sc, pin); 342 if (group == NULL) 343 return; 344 345 bar = group->bar; 346 bank = group->bank; 347 pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar]; 348 349 sc->sc_pin_ih[pin].ih_func = func; 350 sc->sc_pin_ih[pin].ih_arg = arg; 351 352 reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 353 sc->sc_padbar[bar] + pad * sc->sc_padsize); 354 reg &= ~(PCHGPIO_CONF_RXEV_MASK | PCHGPIO_CONF_RXINV); 355 if ((flags & LR_GPIO_MODE) == 1) 356 reg |= PCHGPIO_CONF_RXEV_EDGE; 357 if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTLO) 358 reg |= PCHGPIO_CONF_RXINV; 359 if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTBOTH) 360 reg |= PCHGPIO_CONF_RXEV_EDGE | PCHGPIO_CONF_RXEV_ZERO; 361 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 362 sc->sc_padbar[bar] + pad * sc->sc_padsize, reg); 363 364 reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 365 sc->sc_device->gpi_ie + bank * 4); 366 reg |= (1 << (pin - group->gpiobase)); 367 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 368 sc->sc_device->gpi_ie + bank * 4, reg); 369} 370 371int 372pchgpio_intr(void *arg) 373{ 374 struct pchgpio_softc *sc = arg; 375 uint32_t status, enable; 376 int gpiobase, group, bit, pin, handled = 0; 377 uint16_t base, limit; 378 uint8_t bank, bar; 379 380 for (group = 0; group < sc->sc_device->ngroups; group++) { 381 bar = sc->sc_device->groups[group].bar; 382 bank = sc->sc_device->groups[group].bank; 383 base = sc->sc_device->groups[group].base; 384 limit = sc->sc_device->groups[group].limit; 385 gpiobase = sc->sc_device->groups[group].gpiobase; 386 387 status = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 388 sc->sc_device->gpi_is + bank * 4); 389 bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar], 390 sc->sc_device->gpi_is + bank * 4, status); 391 enable = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar], 392 sc->sc_device->gpi_ie + bank * 4); 393 status &= enable; 394 if (status == 0) 395 continue; 396 397 for (bit = 0; bit <= (limit - base); bit++) { 398 pin = gpiobase + bit; 399 if (status & (1 << bit) && sc->sc_pin_ih[pin].ih_func) 400 sc->sc_pin_ih[pin].ih_func(sc->sc_pin_ih[pin].ih_arg); 401 handled = 1; 402 } 403 } 404 405 return handled; 406} 407