1 /* $OpenBSD: chvgpio.c,v 1.8 2017/11/29 22:51:01 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2016 Mark Kettenis 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/malloc.h> 20 #include <sys/systm.h> 21 22 #include <dev/acpi/acpireg.h> 23 #include <dev/acpi/acpivar.h> 24 #include <dev/acpi/acpidev.h> 25 #include <dev/acpi/amltypes.h> 26 #include <dev/acpi/dsdt.h> 27 28 #define CHVGPIO_INTERRUPT_STATUS 0x0300 29 #define CHVGPIO_INTERRUPT_MASK 0x0380 30 #define CHVGPIO_PAD_CFG0 0x4400 31 #define CHVGPIO_PAD_CFG1 0x4404 32 33 #define CHVGPIO_PAD_CFG0_GPIORXSTATE 0x00000001 34 #define CHVGPIO_PAD_CFG0_GPIOTXSTATE 0x00000002 35 #define CHVGPIO_PAD_CFG0_INTSEL_MASK 0xf0000000 36 #define CHVGPIO_PAD_CFG0_INTSEL_SHIFT 28 37 38 #define CHVGPIO_PAD_CFG1_INTWAKECFG_MASK 0x00000007 39 #define CHVGPIO_PAD_CFG1_INTWAKECFG_FALLING 0x00000001 40 #define CHVGPIO_PAD_CFG1_INTWAKECFG_RISING 0x00000002 41 #define CHVGPIO_PAD_CFG1_INTWAKECFG_BOTH 0x00000003 42 #define CHVGPIO_PAD_CFG1_INTWAKECFG_LEVEL 0x00000004 43 #define CHVGPIO_PAD_CFG1_INVRXTX_MASK 0x000000f0 44 #define CHVGPIO_PAD_CFG1_INVRXTX_RXDATA 0x00000040 45 46 /* OEM defined RegionSpace. */ 47 #define CHVGPIO_REGIONSPACE_BASE 0x90 48 49 struct chvgpio_intrhand { 50 int (*ih_func)(void *); 51 void *ih_arg; 52 }; 53 54 struct chvgpio_softc { 55 struct device sc_dev; 56 struct acpi_softc *sc_acpi; 57 struct aml_node *sc_node; 58 59 bus_space_tag_t sc_memt; 60 bus_space_handle_t sc_memh; 61 bus_addr_t sc_addr; 62 bus_size_t sc_size; 63 64 int sc_irq; 65 int sc_irq_flags; 66 void *sc_ih; 67 68 const int *sc_pins; 69 int sc_npins; 70 int sc_ngroups; 71 72 struct chvgpio_intrhand sc_pin_ih[16]; 73 74 struct acpi_gpio sc_gpio; 75 }; 76 77 static inline int 78 chvgpio_pad_cfg0_offset(int pin) 79 { 80 return (CHVGPIO_PAD_CFG0 + 1024 * (pin / 15) + 8 * (pin % 15)); 81 } 82 83 static inline int 84 chvgpio_read_pad_cfg0(struct chvgpio_softc *sc, int pin) 85 { 86 return bus_space_read_4(sc->sc_memt, sc->sc_memh, 87 chvgpio_pad_cfg0_offset(pin)); 88 } 89 90 static inline void 91 chvgpio_write_pad_cfg0(struct chvgpio_softc *sc, int pin, uint32_t val) 92 { 93 bus_space_write_4(sc->sc_memt, sc->sc_memh, 94 chvgpio_pad_cfg0_offset(pin), val); 95 } 96 97 static inline int 98 chvgpio_read_pad_cfg1(struct chvgpio_softc *sc, int pin) 99 { 100 return bus_space_read_4(sc->sc_memt, sc->sc_memh, 101 chvgpio_pad_cfg0_offset(pin) + 4); 102 } 103 104 static inline void 105 chvgpio_write_pad_cfg1(struct chvgpio_softc *sc, int pin, uint32_t val) 106 { 107 bus_space_write_4(sc->sc_memt, sc->sc_memh, 108 chvgpio_pad_cfg0_offset(pin) + 4, val); 109 } 110 111 int chvgpio_match(struct device *, void *, void *); 112 void chvgpio_attach(struct device *, struct device *, void *); 113 114 struct cfattach chvgpio_ca = { 115 sizeof(struct chvgpio_softc), chvgpio_match, chvgpio_attach 116 }; 117 118 struct cfdriver chvgpio_cd = { 119 NULL, "chvgpio", DV_DULL 120 }; 121 122 const char *chvgpio_hids[] = { 123 "INT33FF", 124 NULL 125 }; 126 127 /* 128 * The pads for the pins are arranged in groups of maximal 15 pins. 129 * The arrays below give the number of pins per group, such that we 130 * can validate the (untrusted) pin numbers from ACPI. 131 */ 132 133 const int chv_southwest_pins[] = { 134 8, 8, 8, 8, 8, 8, 8, -1 135 }; 136 137 const int chv_north_pins[] = { 138 9, 13, 12, 12, 13, -1 139 }; 140 141 const int chv_east_pins[] = { 142 12, 12, -1 143 }; 144 145 const int chv_southeast_pins[] = { 146 8, 12, 6, 8, 10, 11, -1 147 }; 148 149 int chvgpio_parse_resources(int, union acpi_resource *, void *); 150 int chvgpio_check_pin(struct chvgpio_softc *, int); 151 int chvgpio_read_pin(void *, int); 152 void chvgpio_write_pin(void *, int, int); 153 void chvgpio_intr_establish(void *, int, int, int (*)(), void *); 154 int chvgpio_intr(void *); 155 int chvgpio_opreg_handler(void *, int, uint64_t, int, uint64_t *); 156 157 int 158 chvgpio_match(struct device *parent, void *match, void *aux) 159 { 160 struct acpi_attach_args *aaa = aux; 161 struct cfdata *cf = match; 162 163 return acpi_matchhids(aaa, chvgpio_hids, cf->cf_driver->cd_name); 164 } 165 166 void 167 chvgpio_attach(struct device *parent, struct device *self, void *aux) 168 { 169 struct acpi_attach_args *aaa = aux; 170 struct chvgpio_softc *sc = (struct chvgpio_softc *)self; 171 struct aml_value res; 172 int64_t uid; 173 int i; 174 175 sc->sc_acpi = (struct acpi_softc *)parent; 176 sc->sc_node = aaa->aaa_node; 177 printf(": %s", sc->sc_node->name); 178 179 if (aml_evalinteger(sc->sc_acpi, sc->sc_node, "_UID", 0, NULL, &uid)) { 180 printf(", can't find uid\n"); 181 return; 182 } 183 184 printf(" uid %lld", uid); 185 186 switch (uid) { 187 case 1: 188 sc->sc_pins = chv_southwest_pins; 189 break; 190 case 2: 191 sc->sc_pins = chv_north_pins; 192 break; 193 case 3: 194 sc->sc_pins = chv_east_pins; 195 break; 196 case 4: 197 sc->sc_pins = chv_southeast_pins; 198 break; 199 default: 200 printf("\n"); 201 return; 202 } 203 204 for (i = 0; sc->sc_pins[i] >= 0; i++) { 205 sc->sc_npins += sc->sc_pins[i]; 206 sc->sc_ngroups++; 207 } 208 209 if (aml_evalname(sc->sc_acpi, sc->sc_node, "_CRS", 0, NULL, &res)) { 210 printf(", can't find registers\n"); 211 return; 212 } 213 214 aml_parse_resource(&res, chvgpio_parse_resources, sc); 215 printf(" addr 0x%lx/0x%lx", sc->sc_addr, sc->sc_size); 216 if (sc->sc_addr == 0 || sc->sc_size == 0) { 217 printf("\n"); 218 return; 219 } 220 aml_freevalue(&res); 221 222 printf(" irq %d", sc->sc_irq); 223 224 sc->sc_memt = aaa->aaa_memt; 225 if (bus_space_map(sc->sc_memt, sc->sc_addr, sc->sc_size, 0, 226 &sc->sc_memh)) { 227 printf(", can't map registers\n"); 228 return; 229 } 230 231 sc->sc_ih = acpi_intr_establish(sc->sc_irq, sc->sc_irq_flags, IPL_BIO, 232 chvgpio_intr, sc, sc->sc_dev.dv_xname); 233 if (sc->sc_ih == NULL) { 234 printf(", can't establish interrupt\n"); 235 goto unmap; 236 } 237 238 sc->sc_gpio.cookie = sc; 239 sc->sc_gpio.read_pin = chvgpio_read_pin; 240 sc->sc_gpio.write_pin = chvgpio_write_pin; 241 sc->sc_gpio.intr_establish = chvgpio_intr_establish; 242 sc->sc_node->gpio = &sc->sc_gpio; 243 244 /* Mask and ack all interrupts. */ 245 bus_space_write_4(sc->sc_memt, sc->sc_memh, 246 CHVGPIO_INTERRUPT_MASK, 0); 247 bus_space_write_4(sc->sc_memt, sc->sc_memh, 248 CHVGPIO_INTERRUPT_STATUS, 0xffff); 249 250 printf(", %d pins\n", sc->sc_npins); 251 252 /* Register OEM defined address space. */ 253 aml_register_regionspace(sc->sc_node, CHVGPIO_REGIONSPACE_BASE + uid, 254 sc, chvgpio_opreg_handler); 255 256 acpi_register_gpio(sc->sc_acpi, sc->sc_node); 257 return; 258 259 unmap: 260 bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_size); 261 } 262 263 int 264 chvgpio_parse_resources(int crsidx, union acpi_resource *crs, void *arg) 265 { 266 struct chvgpio_softc *sc = arg; 267 int type = AML_CRSTYPE(crs); 268 269 switch (type) { 270 case LR_MEM32FIXED: 271 sc->sc_addr = crs->lr_m32fixed._bas; 272 sc->sc_size = crs->lr_m32fixed._len; 273 break; 274 case LR_EXTIRQ: 275 sc->sc_irq = crs->lr_extirq.irq[0]; 276 sc->sc_irq_flags = crs->lr_extirq.flags; 277 break; 278 default: 279 printf(" type 0x%x\n", type); 280 break; 281 } 282 283 return 0; 284 } 285 286 int 287 chvgpio_check_pin(struct chvgpio_softc *sc, int pin) 288 { 289 if (pin < 0) 290 return EINVAL; 291 if ((pin / 15) >= sc->sc_ngroups) 292 return EINVAL; 293 if ((pin % 15) >= sc->sc_pins[pin / 15]) 294 return EINVAL; 295 296 return 0; 297 } 298 299 int 300 chvgpio_read_pin(void *cookie, int pin) 301 { 302 struct chvgpio_softc *sc = cookie; 303 uint32_t reg; 304 305 KASSERT(chvgpio_check_pin(sc, pin) == 0); 306 307 reg = chvgpio_read_pad_cfg0(sc, pin); 308 return (reg & CHVGPIO_PAD_CFG0_GPIORXSTATE); 309 } 310 311 void 312 chvgpio_write_pin(void *cookie, int pin, int value) 313 { 314 struct chvgpio_softc *sc = cookie; 315 uint32_t reg; 316 317 KASSERT(chvgpio_check_pin(sc, pin) == 0); 318 319 reg = chvgpio_read_pad_cfg0(sc, pin); 320 if (value) 321 reg |= CHVGPIO_PAD_CFG0_GPIOTXSTATE; 322 else 323 reg &= ~CHVGPIO_PAD_CFG0_GPIOTXSTATE; 324 chvgpio_write_pad_cfg0(sc, pin, reg); 325 } 326 327 void 328 chvgpio_intr_establish(void *cookie, int pin, int flags, 329 int (*func)(void *), void *arg) 330 { 331 struct chvgpio_softc *sc = cookie; 332 uint32_t reg; 333 int line; 334 335 KASSERT(chvgpio_check_pin(sc, pin) == 0); 336 337 reg = chvgpio_read_pad_cfg0(sc, pin); 338 reg &= CHVGPIO_PAD_CFG0_INTSEL_MASK; 339 line = reg >> CHVGPIO_PAD_CFG0_INTSEL_SHIFT; 340 341 sc->sc_pin_ih[line].ih_func = func; 342 sc->sc_pin_ih[line].ih_arg = arg; 343 344 reg = chvgpio_read_pad_cfg1(sc, pin); 345 reg &= ~CHVGPIO_PAD_CFG1_INTWAKECFG_MASK; 346 reg &= ~CHVGPIO_PAD_CFG1_INVRXTX_MASK; 347 switch (flags & (LR_GPIO_MODE | LR_GPIO_POLARITY)) { 348 case LR_GPIO_LEVEL | LR_GPIO_ACTLO: 349 reg |= CHVGPIO_PAD_CFG1_INVRXTX_RXDATA; 350 /* FALLTHROUGH */ 351 case LR_GPIO_LEVEL | LR_GPIO_ACTHI: 352 reg |= CHVGPIO_PAD_CFG1_INTWAKECFG_LEVEL; 353 break; 354 case LR_GPIO_EDGE | LR_GPIO_ACTLO: 355 reg |= CHVGPIO_PAD_CFG1_INTWAKECFG_FALLING; 356 break; 357 case LR_GPIO_EDGE | LR_GPIO_ACTHI: 358 reg |= CHVGPIO_PAD_CFG1_INTWAKECFG_RISING; 359 break; 360 case LR_GPIO_EDGE | LR_GPIO_ACTBOTH: 361 reg |= CHVGPIO_PAD_CFG1_INTWAKECFG_BOTH; 362 break; 363 default: 364 printf("%s: unsupported interrupt mode/polarity\n", 365 sc->sc_dev.dv_xname); 366 break; 367 } 368 chvgpio_write_pad_cfg1(sc, pin, reg); 369 370 reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, 371 CHVGPIO_INTERRUPT_MASK); 372 bus_space_write_4(sc->sc_memt, sc->sc_memh, 373 CHVGPIO_INTERRUPT_MASK, reg | (1 << line)); 374 } 375 376 int 377 chvgpio_intr(void *arg) 378 { 379 struct chvgpio_softc *sc = arg; 380 uint32_t reg; 381 int rc = 0; 382 int line; 383 384 reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, 385 CHVGPIO_INTERRUPT_STATUS); 386 for (line = 0; line < 16; line++) { 387 if ((reg & (1 << line)) == 0) 388 continue; 389 390 bus_space_write_4(sc->sc_memt,sc->sc_memh, 391 CHVGPIO_INTERRUPT_STATUS, 1 << line); 392 if (sc->sc_pin_ih[line].ih_func) 393 sc->sc_pin_ih[line].ih_func(sc->sc_pin_ih[line].ih_arg); 394 rc = 1; 395 } 396 397 return rc; 398 } 399 400 int 401 chvgpio_opreg_handler(void *cookie, int iodir, uint64_t address, int size, 402 uint64_t *value) 403 { 404 struct chvgpio_softc *sc = cookie; 405 406 /* Only allow 32-bit access. */ 407 if (size != 4 || address > sc->sc_size - size) 408 return -1; 409 410 if (iodir == ACPI_IOREAD) 411 *value = bus_space_read_4(sc->sc_memt, sc->sc_memh, address); 412 else 413 bus_space_write_4(sc->sc_memt, sc->sc_memh, address, *value); 414 415 return 0; 416 } 417