1 /* $OpenBSD: qcgpio.c,v 1.9 2023/04/11 04:45:11 mglocker Exp $ */ 2 /* 3 * Copyright (c) 2022 Mark Kettenis <kettenis@openbsd.org> 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 /* Registers. */ 29 #define TLMM_GPIO_IN_OUT(pin) (0x0004 + 0x1000 * (pin)) 30 #define TLMM_GPIO_IN_OUT_GPIO_IN (1 << 0) 31 #define TLMM_GPIO_IN_OUT_GPIO_OUT (1 << 1) 32 #define TLMM_GPIO_INTR_CFG(pin) (0x0008 + 0x1000 * (pin)) 33 #define TLMM_GPIO_INTR_CFG_TARGET_PROC_MASK (0x7 << 5) 34 #define TLMM_GPIO_INTR_CFG_TARGET_PROC_RPM (0x3 << 5) 35 #define TLMM_GPIO_INTR_CFG_INTR_RAW_STATUS_EN (1 << 4) 36 #define TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_MASK (0x3 << 2) 37 #define TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_LEVEL (0x0 << 2) 38 #define TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_POS (0x1 << 2) 39 #define TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_NEG (0x2 << 2) 40 #define TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_BOTH (0x3 << 2) 41 #define TLMM_GPIO_INTR_CFG_INTR_POL_CTL (1 << 1) 42 #define TLMM_GPIO_INTR_CFG_INTR_ENABLE (1 << 0) 43 #define TLMM_GPIO_INTR_STATUS(pin) (0x000c + 0x1000 * (pin)) 44 #define TLMM_GPIO_INTR_STATUS_INTR_STATUS (1 << 0) 45 46 /* SC7180 has multiple tiles */ 47 #define QCGPIO_SC7180_WEST 0x00100000 48 #define QCGPIO_SC7180_NORTH 0x00500000 49 #define QCGPIO_SC7180_SOUTH 0x00900000 50 51 #define HREAD4(sc, reg) \ 52 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 53 #define HWRITE4(sc, reg, val) \ 54 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 55 #define HSET4(sc, reg, bits) \ 56 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 57 #define HCLR4(sc, reg, bits) \ 58 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 59 60 struct qcgpio_intrhand { 61 int (*ih_func)(void *); 62 void *ih_arg; 63 }; 64 65 struct qcgpio_softc { 66 struct device sc_dev; 67 struct acpi_softc *sc_acpi; 68 struct aml_node *sc_node; 69 70 bus_space_tag_t sc_iot; 71 bus_space_handle_t sc_ioh; 72 73 void *sc_ih; 74 75 uint32_t sc_npins; 76 int (*sc_pin_map)(int, bus_size_t *); 77 struct qcgpio_intrhand *sc_pin_ih; 78 79 struct acpi_gpio sc_gpio; 80 }; 81 82 int qcgpio_acpi_match(struct device *, void *, void *); 83 void qcgpio_acpi_attach(struct device *, struct device *, void *); 84 85 const struct cfattach qcgpio_acpi_ca = { 86 sizeof(struct qcgpio_softc), qcgpio_acpi_match, qcgpio_acpi_attach 87 }; 88 89 struct cfdriver qcgpio_cd = { 90 NULL, "qcgpio", DV_DULL 91 }; 92 93 const char *qcgpio_hids[] = { 94 "QCOM060C", 95 "QCOM080D", 96 NULL 97 }; 98 99 int qcgpio_sc7180_pin_map(int, bus_size_t *); 100 int qcgpio_sc8280xp_pin_map(int, bus_size_t *); 101 102 int qcgpio_read_pin(void *, int); 103 void qcgpio_write_pin(void *, int, int); 104 void qcgpio_intr_establish(void *, int, int, int (*)(void *), void *); 105 void qcgpio_intr_enable(void *, int); 106 void qcgpio_intr_disable(void *, int); 107 int qcgpio_intr(void *); 108 109 int 110 qcgpio_acpi_match(struct device *parent, void *match, void *aux) 111 { 112 struct acpi_attach_args *aaa = aux; 113 struct cfdata *cf = match; 114 115 if (aaa->aaa_naddr < 1 || aaa->aaa_nirq < 1) 116 return 0; 117 return acpi_matchhids(aaa, qcgpio_hids, cf->cf_driver->cd_name); 118 } 119 120 void 121 qcgpio_acpi_attach(struct device *parent, struct device *self, void *aux) 122 { 123 struct acpi_attach_args *aaa = aux; 124 struct qcgpio_softc *sc = (struct qcgpio_softc *)self; 125 126 sc->sc_acpi = (struct acpi_softc *)parent; 127 sc->sc_node = aaa->aaa_node; 128 printf(" %s", sc->sc_node->name); 129 130 printf(" addr 0x%llx/0x%llx", aaa->aaa_addr[0], aaa->aaa_size[0]); 131 132 sc->sc_iot = aaa->aaa_bst[0]; 133 if (bus_space_map(sc->sc_iot, aaa->aaa_addr[0], aaa->aaa_size[0], 134 0, &sc->sc_ioh)) { 135 printf(": can't map registers\n"); 136 return; 137 } 138 139 if (strcmp(aaa->aaa_dev, "QCOM080D") == 0) { 140 sc->sc_npins = 119; 141 sc->sc_pin_map = qcgpio_sc7180_pin_map; 142 } else if (strcmp(aaa->aaa_dev, "QCOM060C") == 0) { 143 sc->sc_npins = 228; 144 sc->sc_pin_map = qcgpio_sc8280xp_pin_map; 145 } 146 KASSERT(sc->sc_npins != 0); 147 148 sc->sc_pin_ih = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_ih), 149 M_DEVBUF, M_WAITOK | M_ZERO); 150 151 printf(" irq %d", aaa->aaa_irq[0]); 152 153 sc->sc_ih = acpi_intr_establish(aaa->aaa_irq[0], 154 aaa->aaa_irq_flags[0], IPL_BIO, qcgpio_intr, 155 sc, sc->sc_dev.dv_xname); 156 if (sc->sc_ih == NULL) { 157 printf(": can't establish interrupt\n"); 158 goto unmap; 159 } 160 161 sc->sc_gpio.cookie = sc; 162 sc->sc_gpio.read_pin = qcgpio_read_pin; 163 sc->sc_gpio.write_pin = qcgpio_write_pin; 164 sc->sc_gpio.intr_establish = qcgpio_intr_establish; 165 sc->sc_gpio.intr_enable = qcgpio_intr_enable; 166 sc->sc_gpio.intr_disable = qcgpio_intr_disable; 167 sc->sc_node->gpio = &sc->sc_gpio; 168 169 printf("\n"); 170 171 acpi_register_gpio(sc->sc_acpi, sc->sc_node); 172 return; 173 174 unmap: 175 if (sc->sc_ih) 176 acpi_intr_disestablish(sc->sc_ih); 177 free(sc->sc_pin_ih, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_ih)); 178 bus_space_unmap(sc->sc_iot, sc->sc_ioh, aaa->aaa_size[0]); 179 } 180 181 int 182 qcgpio_sc7180_pin_map(int pin, bus_size_t *off) 183 { 184 switch (pin) { 185 case 30: 186 *off = QCGPIO_SC7180_SOUTH; 187 return 30; 188 #if 0 189 /* XXX: Disable until we can fix the interrupt storm. */ 190 case 32: 191 case 0x140: 192 *off = QCGPIO_SC7180_NORTH; 193 return 32; 194 #endif 195 case 33: 196 case 0x180: 197 *off = QCGPIO_SC7180_NORTH; 198 return 33; 199 case 94: 200 case 0x1c0: 201 *off = QCGPIO_SC7180_SOUTH; 202 return 94; 203 default: 204 return -1; 205 } 206 } 207 208 int 209 qcgpio_sc8280xp_pin_map(int pin, bus_size_t *off) 210 { 211 switch (pin) { 212 case 107: 213 case 175: 214 return pin; 215 case 0x2c0: 216 return 107; 217 case 0x340: 218 return 104; 219 case 0x380: 220 return 182; 221 default: 222 return -1; 223 } 224 } 225 226 int 227 qcgpio_read_pin(void *cookie, int pin) 228 { 229 struct qcgpio_softc *sc = cookie; 230 bus_size_t off = 0; 231 uint32_t reg; 232 233 pin = sc->sc_pin_map(pin, &off); 234 if (pin < 0 || pin >= sc->sc_npins) 235 return 0; 236 237 reg = HREAD4(sc, off + TLMM_GPIO_IN_OUT(pin)); 238 return !!(reg & TLMM_GPIO_IN_OUT_GPIO_IN); 239 } 240 241 void 242 qcgpio_write_pin(void *cookie, int pin, int val) 243 { 244 struct qcgpio_softc *sc = cookie; 245 bus_size_t off = 0; 246 247 pin = sc->sc_pin_map(pin, &off); 248 if (pin < 0 || pin >= sc->sc_npins) 249 return; 250 251 if (val) { 252 HSET4(sc, off + TLMM_GPIO_IN_OUT(pin), 253 TLMM_GPIO_IN_OUT_GPIO_OUT); 254 } else { 255 HCLR4(sc, off + TLMM_GPIO_IN_OUT(pin), 256 TLMM_GPIO_IN_OUT_GPIO_OUT); 257 } 258 } 259 260 void 261 qcgpio_intr_establish(void *cookie, int pin, int flags, 262 int (*func)(void *), void *arg) 263 { 264 struct qcgpio_softc *sc = cookie; 265 bus_size_t off = 0; 266 uint32_t reg; 267 268 pin = sc->sc_pin_map(pin, &off); 269 if (pin < 0 || pin >= sc->sc_npins) 270 return; 271 272 sc->sc_pin_ih[pin].ih_func = func; 273 sc->sc_pin_ih[pin].ih_arg = arg; 274 275 reg = HREAD4(sc, off + TLMM_GPIO_INTR_CFG(pin)); 276 reg &= ~TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_MASK; 277 reg &= ~TLMM_GPIO_INTR_CFG_INTR_POL_CTL; 278 switch (flags & (LR_GPIO_MODE | LR_GPIO_POLARITY)) { 279 case LR_GPIO_LEVEL | LR_GPIO_ACTLO: 280 reg |= TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_LEVEL; 281 break; 282 case LR_GPIO_LEVEL | LR_GPIO_ACTHI: 283 reg |= TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_LEVEL | 284 TLMM_GPIO_INTR_CFG_INTR_POL_CTL; 285 break; 286 case LR_GPIO_EDGE | LR_GPIO_ACTLO: 287 reg |= TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_NEG | 288 TLMM_GPIO_INTR_CFG_INTR_POL_CTL; 289 break; 290 case LR_GPIO_EDGE | LR_GPIO_ACTHI: 291 reg |= TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_POS | 292 TLMM_GPIO_INTR_CFG_INTR_POL_CTL; 293 break; 294 case LR_GPIO_EDGE | LR_GPIO_ACTBOTH: 295 reg |= TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_BOTH; 296 break; 297 default: 298 printf("%s: unsupported interrupt mode/polarity\n", 299 sc->sc_dev.dv_xname); 300 break; 301 } 302 reg &= ~TLMM_GPIO_INTR_CFG_TARGET_PROC_MASK; 303 reg |= TLMM_GPIO_INTR_CFG_TARGET_PROC_RPM; 304 reg |= TLMM_GPIO_INTR_CFG_INTR_RAW_STATUS_EN; 305 reg |= TLMM_GPIO_INTR_CFG_INTR_ENABLE; 306 HWRITE4(sc, off + TLMM_GPIO_INTR_CFG(pin), reg); 307 } 308 309 void 310 qcgpio_intr_enable(void *cookie, int pin) 311 { 312 struct qcgpio_softc *sc = cookie; 313 bus_size_t off = 0; 314 315 pin = sc->sc_pin_map(pin, &off); 316 if (pin < 0 || pin >= sc->sc_npins) 317 return; 318 319 HSET4(sc, off + TLMM_GPIO_INTR_CFG(pin), 320 TLMM_GPIO_INTR_CFG_INTR_ENABLE); 321 } 322 323 void 324 qcgpio_intr_disable(void *cookie, int pin) 325 { 326 struct qcgpio_softc *sc = cookie; 327 bus_size_t off = 0; 328 329 pin = sc->sc_pin_map(pin, &off); 330 if (pin < 0 || pin >= sc->sc_npins) 331 return; 332 333 HCLR4(sc, off + TLMM_GPIO_INTR_CFG(pin), 334 TLMM_GPIO_INTR_CFG_INTR_ENABLE); 335 } 336 337 int 338 qcgpio_intr(void *arg) 339 { 340 struct qcgpio_softc *sc = arg; 341 int pin, handled = 0; 342 bus_size_t off = 0; 343 uint32_t stat; 344 345 for (pin = 0; pin < sc->sc_npins; pin++) { 346 if (sc->sc_pin_ih[pin].ih_func == NULL) 347 continue; 348 349 sc->sc_pin_map(pin, &off); 350 351 stat = HREAD4(sc, off + TLMM_GPIO_INTR_STATUS(pin)); 352 if (stat & TLMM_GPIO_INTR_STATUS_INTR_STATUS) { 353 sc->sc_pin_ih[pin].ih_func(sc->sc_pin_ih[pin].ih_arg); 354 HWRITE4(sc, off + TLMM_GPIO_INTR_STATUS(pin), 355 stat & ~TLMM_GPIO_INTR_STATUS_INTR_STATUS); 356 handled = 1; 357 } 358 } 359 360 return handled; 361 } 362