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