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