1 /* $OpenBSD: chvgpio.c,v 1.5 2016/05/08 18:18:42 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 struct chvgpio_intrhand { 47 int (*ih_func)(void *); 48 void *ih_arg; 49 }; 50 51 struct chvgpio_softc { 52 struct device sc_dev; 53 struct acpi_softc *sc_acpi; 54 struct aml_node *sc_node; 55 56 bus_space_tag_t sc_memt; 57 bus_space_handle_t sc_memh; 58 bus_addr_t sc_addr; 59 bus_size_t sc_size; 60 61 int sc_irq; 62 int sc_irq_flags; 63 void *sc_ih; 64 65 const int *sc_pins; 66 int sc_npins; 67 int sc_ngroups; 68 69 struct chvgpio_intrhand sc_pin_ih[16]; 70 71 struct acpi_gpio sc_gpio; 72 }; 73 74 static inline int 75 chvgpio_pad_cfg0_offset(int pin) 76 { 77 return (CHVGPIO_PAD_CFG0 + 1024 * (pin / 15) + 8 * (pin % 15)); 78 } 79 80 static inline int 81 chvgpio_read_pad_cfg0(struct chvgpio_softc *sc, int pin) 82 { 83 return bus_space_read_4(sc->sc_memt, sc->sc_memh, 84 chvgpio_pad_cfg0_offset(pin)); 85 } 86 87 static inline void 88 chvgpio_write_pad_cfg0(struct chvgpio_softc *sc, int pin, uint32_t val) 89 { 90 bus_space_write_4(sc->sc_memt, sc->sc_memh, 91 chvgpio_pad_cfg0_offset(pin), val); 92 } 93 94 static inline int 95 chvgpio_read_pad_cfg1(struct chvgpio_softc *sc, int pin) 96 { 97 return bus_space_read_4(sc->sc_memt, sc->sc_memh, 98 chvgpio_pad_cfg0_offset(pin) + 4); 99 } 100 101 static inline void 102 chvgpio_write_pad_cfg1(struct chvgpio_softc *sc, int pin, uint32_t val) 103 { 104 bus_space_write_4(sc->sc_memt, sc->sc_memh, 105 chvgpio_pad_cfg0_offset(pin) + 4, val); 106 } 107 108 int chvgpio_match(struct device *, void *, void *); 109 void chvgpio_attach(struct device *, struct device *, void *); 110 111 struct cfattach chvgpio_ca = { 112 sizeof(struct chvgpio_softc), chvgpio_match, chvgpio_attach 113 }; 114 115 struct cfdriver chvgpio_cd = { 116 NULL, "chvgpio", DV_DULL 117 }; 118 119 const char *chvgpio_hids[] = { 120 "INT33FF", 121 NULL 122 }; 123 124 /* 125 * The pads for the pins are arranged in groups of maximal 15 pins. 126 * The arrays below give the number of pins per group, such that we 127 * can validate the (untrusted) pin numbers from ACPI. 128 */ 129 130 const int chv_southwest_pins[] = { 131 8, 8, 8, 8, 8, 8, 8, -1 132 }; 133 134 const int chv_north_pins[] = { 135 9, 13, 12, 12, 13, -1 136 }; 137 138 const int chv_east_pins[] = { 139 12, 12, -1 140 }; 141 142 const int chv_southeast_pins[] = { 143 8, 12, 6, 8, 10, 11, -1 144 }; 145 146 int chvgpio_parse_resources(union acpi_resource *, void *); 147 int chvgpio_check_pin(struct chvgpio_softc *, int); 148 int chvgpio_read_pin(void *, int); 149 void chvgpio_write_pin(void *, int, int); 150 void chvgpio_intr_establish(void *, int, int, int (*)(), void *); 151 int chvgpio_intr(void *); 152 153 int 154 chvgpio_match(struct device *parent, void *match, void *aux) 155 { 156 struct acpi_attach_args *aaa = aux; 157 struct cfdata *cf = match; 158 159 return acpi_matchhids(aaa, chvgpio_hids, cf->cf_driver->cd_name); 160 } 161 162 void 163 chvgpio_attach(struct device *parent, struct device *self, void *aux) 164 { 165 struct acpi_attach_args *aaa = aux; 166 struct chvgpio_softc *sc = (struct chvgpio_softc *)self; 167 struct aml_value res; 168 struct aml_value arg[2]; 169 struct aml_node *node; 170 int64_t uid; 171 int i; 172 173 sc->sc_acpi = (struct acpi_softc *)parent; 174 sc->sc_node = aaa->aaa_node; 175 printf(": %s", sc->sc_node->name); 176 177 if (aml_evalinteger(sc->sc_acpi, sc->sc_node, "_UID", 0, NULL, &uid)) { 178 printf(", can't find uid\n"); 179 return; 180 } 181 182 printf(" uid %lld", uid); 183 184 switch (uid) { 185 case 1: 186 sc->sc_pins = chv_southwest_pins; 187 break; 188 case 2: 189 sc->sc_pins = chv_north_pins; 190 break; 191 case 3: 192 sc->sc_pins = chv_east_pins; 193 break; 194 case 4: 195 sc->sc_pins = chv_southeast_pins; 196 break; 197 default: 198 printf("\n"); 199 return; 200 } 201 202 for (i = 0; sc->sc_pins[i] >= 0; i++) { 203 sc->sc_npins += sc->sc_pins[i]; 204 sc->sc_ngroups++; 205 } 206 207 if (aml_evalname(sc->sc_acpi, sc->sc_node, "_CRS", 0, NULL, &res)) { 208 printf(", can't find registers\n"); 209 return; 210 } 211 212 aml_parse_resource(&res, chvgpio_parse_resources, sc); 213 printf(" addr 0x%lx/0x%lx", sc->sc_addr, sc->sc_size); 214 if (sc->sc_addr == 0 || sc->sc_size == 0) { 215 printf("\n"); 216 return; 217 } 218 aml_freevalue(&res); 219 220 printf(" irq %d", sc->sc_irq); 221 222 sc->sc_memt = aaa->aaa_memt; 223 if (bus_space_map(sc->sc_memt, sc->sc_addr, sc->sc_size, 0, 224 &sc->sc_memh)) { 225 printf(", can't map registers\n"); 226 return; 227 } 228 229 sc->sc_ih = acpi_intr_establish(sc->sc_irq, sc->sc_irq_flags, IPL_BIO, 230 chvgpio_intr, sc, sc->sc_dev.dv_xname); 231 if (sc->sc_ih == NULL) { 232 printf(", can't establish interrupt\n"); 233 goto unmap; 234 } 235 236 sc->sc_gpio.cookie = sc; 237 sc->sc_gpio.read_pin = chvgpio_read_pin; 238 sc->sc_gpio.write_pin = chvgpio_write_pin; 239 sc->sc_gpio.intr_establish = chvgpio_intr_establish; 240 sc->sc_node->gpio = &sc->sc_gpio; 241 242 /* Mask and ack all interrupts. */ 243 bus_space_write_4(sc->sc_memt, sc->sc_memh, 244 CHVGPIO_INTERRUPT_MASK, 0); 245 bus_space_write_4(sc->sc_memt, sc->sc_memh, 246 CHVGPIO_INTERRUPT_STATUS, 0xffff); 247 248 printf(", %d pins\n", sc->sc_npins); 249 250 /* Register address space. */ 251 memset(&arg, 0, sizeof(arg)); 252 arg[0].type = AML_OBJTYPE_INTEGER; 253 arg[0].v_integer = ACPI_OPREG_GPIO; 254 arg[1].type = AML_OBJTYPE_INTEGER; 255 arg[1].v_integer = 1; 256 node = aml_searchname(sc->sc_node, "_REG"); 257 if (node && aml_evalnode(sc->sc_acpi, node, 2, arg, NULL)) 258 printf("%s: _REG failed\n", sc->sc_dev.dv_xname); 259 260 return; 261 262 unmap: 263 bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_size); 264 } 265 266 int 267 chvgpio_parse_resources(union acpi_resource *crs, void *arg) 268 { 269 struct chvgpio_softc *sc = arg; 270 int type = AML_CRSTYPE(crs); 271 272 switch (type) { 273 case LR_MEM32FIXED: 274 sc->sc_addr = crs->lr_m32fixed._bas; 275 sc->sc_size = crs->lr_m32fixed._len; 276 break; 277 case LR_EXTIRQ: 278 sc->sc_irq = crs->lr_extirq.irq[0]; 279 sc->sc_irq_flags = crs->lr_extirq.flags; 280 break; 281 default: 282 printf(" type 0x%x\n", type); 283 break; 284 } 285 286 return 0; 287 } 288 289 int 290 chvgpio_check_pin(struct chvgpio_softc *sc, int pin) 291 { 292 if (pin < 0) 293 return EINVAL; 294 if ((pin / 15) >= sc->sc_ngroups) 295 return EINVAL; 296 if ((pin % 15) >= sc->sc_pins[pin / 15]) 297 return EINVAL; 298 299 return 0; 300 } 301 302 int 303 chvgpio_read_pin(void *cookie, int pin) 304 { 305 struct chvgpio_softc *sc = cookie; 306 uint32_t reg; 307 308 KASSERT(chvgpio_check_pin(sc, pin) == 0); 309 310 reg = chvgpio_read_pad_cfg0(sc, pin); 311 return (reg & CHVGPIO_PAD_CFG0_GPIORXSTATE); 312 } 313 314 void 315 chvgpio_write_pin(void *cookie, int pin, int value) 316 { 317 struct chvgpio_softc *sc = cookie; 318 uint32_t reg; 319 320 KASSERT(chvgpio_check_pin(sc, pin) == 0); 321 322 reg = chvgpio_read_pad_cfg0(sc, pin); 323 if (value) 324 reg |= CHVGPIO_PAD_CFG0_GPIOTXSTATE; 325 else 326 reg &= ~CHVGPIO_PAD_CFG0_GPIOTXSTATE; 327 chvgpio_write_pad_cfg0(sc, pin, reg); 328 } 329 330 void 331 chvgpio_intr_establish(void *cookie, int pin, int flags, 332 int (*func)(void *), void *arg) 333 { 334 struct chvgpio_softc *sc = cookie; 335 uint32_t reg; 336 int line; 337 338 KASSERT(chvgpio_check_pin(sc, pin) == 0); 339 340 reg = chvgpio_read_pad_cfg0(sc, pin); 341 reg &= CHVGPIO_PAD_CFG0_INTSEL_MASK; 342 line = reg >> CHVGPIO_PAD_CFG0_INTSEL_SHIFT; 343 344 sc->sc_pin_ih[line].ih_func = func; 345 sc->sc_pin_ih[line].ih_arg = arg; 346 347 reg = chvgpio_read_pad_cfg1(sc, pin); 348 reg &= ~CHVGPIO_PAD_CFG1_INTWAKECFG_MASK; 349 reg &= ~CHVGPIO_PAD_CFG1_INVRXTX_MASK; 350 switch (flags & (LR_GPIO_MODE | LR_GPIO_POLARITY)) { 351 case LR_GPIO_LEVEL | LR_GPIO_ACTLO: 352 reg |= CHVGPIO_PAD_CFG1_INVRXTX_RXDATA; 353 /* FALLTHROUGH */ 354 case LR_GPIO_LEVEL | LR_GPIO_ACTHI: 355 reg |= CHVGPIO_PAD_CFG1_INTWAKECFG_LEVEL; 356 break; 357 case LR_GPIO_EDGE | LR_GPIO_ACTLO: 358 reg |= CHVGPIO_PAD_CFG1_INTWAKECFG_FALLING; 359 break; 360 case LR_GPIO_EDGE | LR_GPIO_ACTHI: 361 reg |= CHVGPIO_PAD_CFG1_INTWAKECFG_RISING; 362 break; 363 case LR_GPIO_EDGE | LR_GPIO_ACTBOTH: 364 reg |= CHVGPIO_PAD_CFG1_INTWAKECFG_BOTH; 365 break; 366 default: 367 printf("%s: unsupported interrupt mode/polarity\n", 368 sc->sc_dev.dv_xname); 369 break; 370 } 371 chvgpio_write_pad_cfg1(sc, pin, reg); 372 373 reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, 374 CHVGPIO_INTERRUPT_MASK); 375 bus_space_write_4(sc->sc_memt, sc->sc_memh, 376 CHVGPIO_INTERRUPT_MASK, reg | (1 << line)); 377 } 378 379 int 380 chvgpio_intr(void *arg) 381 { 382 struct chvgpio_softc *sc = arg; 383 uint32_t reg; 384 int rc = 0; 385 int line; 386 387 reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, 388 CHVGPIO_INTERRUPT_STATUS); 389 for (line = 0; line < 16; line++) { 390 if ((reg & (1 << line)) == 0) 391 continue; 392 393 bus_space_write_4(sc->sc_memt,sc->sc_memh, 394 CHVGPIO_INTERRUPT_STATUS, 1 << line); 395 if (sc->sc_pin_ih[line].ih_func) 396 sc->sc_pin_ih[line].ih_func(sc->sc_pin_ih[line].ih_arg); 397 rc = 1; 398 } 399 400 return rc; 401 } 402