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