From: patrick Date: Sun, 6 Nov 2022 15:33:58 +0000 (+0000) Subject: Add FDT-based attachment for qcgpio(4). X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=e9f702617d0761830c0e32d6cc29668da9d42c81;p=openbsd Add FDT-based attachment for qcgpio(4). ok kettenis@ --- diff --git a/sys/arch/arm64/conf/GENERIC b/sys/arch/arm64/conf/GENERIC index 3ce6e7795b1..3cfbbd95c7f 100644 --- a/sys/arch/arm64/conf/GENERIC +++ b/sys/arch/arm64/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.241 2022/11/06 12:12:45 patrick Exp $ +# $OpenBSD: GENERIC,v 1.242 2022/11/06 15:33:58 patrick Exp $ # # GENERIC machine description file # @@ -307,6 +307,7 @@ sdmmc* at dwmmc? # Qualcomm SoCs qcdwusb* at fdt? qcgpio* at acpi? +qcgpio* at fdt? qciic* at acpi? iic* at qciic? diff --git a/sys/arch/arm64/conf/RAMDISK b/sys/arch/arm64/conf/RAMDISK index e96bbb0bf99..e52656dd20a 100644 --- a/sys/arch/arm64/conf/RAMDISK +++ b/sys/arch/arm64/conf/RAMDISK @@ -1,4 +1,4 @@ -# $OpenBSD: RAMDISK,v 1.179 2022/11/06 12:12:45 patrick Exp $ +# $OpenBSD: RAMDISK,v 1.180 2022/11/06 15:33:58 patrick Exp $ machine arm64 maxusers 4 @@ -235,6 +235,7 @@ sdmmc* at dwmmc? # Qualcomm SoCs qcdwusb* at fdt? qcgpio* at acpi? +qcgpio* at fdt? qciic* at acpi? iic* at qciic? diff --git a/sys/conf/files b/sys/conf/files index 18ad40c52cb..148bdf1159d 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $OpenBSD: files,v 1.717 2022/11/05 19:29:45 cheloha Exp $ +# $OpenBSD: files,v 1.718 2022/11/06 15:33:58 patrick Exp $ # $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -530,6 +530,9 @@ file dev/ic/dwiic.c dwiic device imxiic: i2cbus file dev/ic/imxiic.c imxiic +# Qualcomm GPIO controller +device qcgpio + # legitimate pseudo-devices pseudo-device vnd: disk pseudo-device rd: disk diff --git a/sys/dev/acpi/files.acpi b/sys/dev/acpi/files.acpi index f603a136f14..8f001185abf 100644 --- a/sys/dev/acpi/files.acpi +++ b/sys/dev/acpi/files.acpi @@ -1,4 +1,4 @@ -# $OpenBSD: files.acpi,v 1.65 2022/08/31 16:10:59 kettenis Exp $ +# $OpenBSD: files.acpi,v 1.66 2022/11/06 15:33:58 patrick Exp $ # # Config file and device description for machine-independent ACPI code. # Included by ports that need it. @@ -264,9 +264,8 @@ file dev/acpi/acpihid.c acpihid attach imxiic at acpi with imxiic_acpi file dev/acpi/imxiic_acpi.c imxiic_acpi -# Qualcom GPIO controller -device qcgpio -attach qcgpio at acpi +# Qualcomm GPIO controller +attach qcgpio at acpi with qcgpio_acpi file dev/acpi/qcgpio.c qcgpio # Qualcomm I2C controller diff --git a/sys/dev/acpi/qcgpio.c b/sys/dev/acpi/qcgpio.c index 330c1c1ef52..d32005b7877 100644 --- a/sys/dev/acpi/qcgpio.c +++ b/sys/dev/acpi/qcgpio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: qcgpio.c,v 1.6 2022/09/15 18:03:52 mglocker Exp $ */ +/* $OpenBSD: qcgpio.c,v 1.7 2022/11/06 15:33:58 patrick Exp $ */ /* * Copyright (c) 2022 Mark Kettenis * @@ -79,11 +79,11 @@ struct qcgpio_softc { struct acpi_gpio sc_gpio; }; -int qcgpio_match(struct device *, void *, void *); -void qcgpio_attach(struct device *, struct device *, void *); +int qcgpio_acpi_match(struct device *, void *, void *); +void qcgpio_acpi_attach(struct device *, struct device *, void *); -const struct cfattach qcgpio_ca = { - sizeof(struct qcgpio_softc), qcgpio_match, qcgpio_attach +const struct cfattach qcgpio_acpi_ca = { + sizeof(struct qcgpio_softc), qcgpio_acpi_match, qcgpio_acpi_attach }; struct cfdriver qcgpio_cd = { @@ -108,7 +108,7 @@ int qcgpio_pin_intr(struct qcgpio_softc *, int); int qcgpio_intr(void *); int -qcgpio_match(struct device *parent, void *match, void *aux) +qcgpio_acpi_match(struct device *parent, void *match, void *aux) { struct acpi_attach_args *aaa = aux; struct cfdata *cf = match; @@ -119,7 +119,7 @@ qcgpio_match(struct device *parent, void *match, void *aux) } void -qcgpio_attach(struct device *parent, struct device *self, void *aux) +qcgpio_acpi_attach(struct device *parent, struct device *self, void *aux) { struct acpi_attach_args *aaa = aux; struct qcgpio_softc *sc = (struct qcgpio_softc *)self; diff --git a/sys/dev/fdt/files.fdt b/sys/dev/fdt/files.fdt index fb573122036..a19835ea4e1 100644 --- a/sys/dev/fdt/files.fdt +++ b/sys/dev/fdt/files.fdt @@ -1,4 +1,4 @@ -# $OpenBSD: files.fdt,v 1.165 2022/11/06 12:12:45 patrick Exp $ +# $OpenBSD: files.fdt,v 1.166 2022/11/06 15:33:58 patrick Exp $ # # Config file and device description for machine-independent FDT code. # Included by ports that need it. @@ -624,3 +624,7 @@ file dev/fdt/tascodec.c tascodec device qcdwusb: fdt attach qcdwusb at fdt file dev/fdt/qcdwusb.c qcdwusb + +# Qualcomm GPIO controller +attach qcgpio at fdt with qcgpio_fdt +file dev/fdt/qcgpio_fdt.c qcgpio diff --git a/sys/dev/fdt/qcgpio_fdt.c b/sys/dev/fdt/qcgpio_fdt.c new file mode 100644 index 00000000000..f6813d5cbeb --- /dev/null +++ b/sys/dev/fdt/qcgpio_fdt.c @@ -0,0 +1,295 @@ +/* $OpenBSD: qcgpio_fdt.c,v 1.1 2022/11/06 15:33:58 patrick Exp $ */ +/* + * Copyright (c) 2022 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include + +#include +#include +#include + +/* Registers. */ +#define TLMM_GPIO_IN_OUT(pin) (0x0004 + 0x1000 * (pin)) +#define TLMM_GPIO_IN_OUT_GPIO_IN (1 << 0) +#define TLMM_GPIO_IN_OUT_GPIO_OUT (1 << 1) +#define TLMM_GPIO_INTR_CFG(pin) (0x0008 + 0x1000 * (pin)) +#define TLMM_GPIO_INTR_CFG_TARGET_PROC_MASK (0x7 << 5) +#define TLMM_GPIO_INTR_CFG_TARGET_PROC_RPM (0x3 << 5) +#define TLMM_GPIO_INTR_CFG_INTR_RAW_STATUS_EN (1 << 4) +#define TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_MASK (0x3 << 2) +#define TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_LEVEL (0x0 << 2) +#define TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_POS (0x1 << 2) +#define TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_NEG (0x2 << 2) +#define TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_BOTH (0x3 << 2) +#define TLMM_GPIO_INTR_CFG_INTR_POL_CTL (1 << 1) +#define TLMM_GPIO_INTR_CFG_INTR_ENABLE (1 << 0) +#define TLMM_GPIO_INTR_STATUS(pin) (0x000c + 0x1000 * (pin)) +#define TLMM_GPIO_INTR_STATUS_INTR_STATUS (1 << 0) + +#define HREAD4(sc, reg) \ + (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) +#define HWRITE4(sc, reg, val) \ + bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) +#define HSET4(sc, reg, bits) \ + HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) +#define HCLR4(sc, reg, bits) \ + HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) + +struct qcgpio_intrhand { + int (*ih_func)(void *); + void *ih_arg; + void *ih_sc; + int ih_pin; +}; + +struct qcgpio_softc { + struct device sc_dev; + + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + + void *sc_ih; + + uint32_t sc_npins; + struct qcgpio_intrhand *sc_pin_ih; + + struct interrupt_controller sc_ic; +}; + +int qcgpio_fdt_match(struct device *, void *, void *); +void qcgpio_fdt_attach(struct device *, struct device *, void *); + +const struct cfattach qcgpio_fdt_ca = { + sizeof(struct qcgpio_softc), qcgpio_fdt_match, qcgpio_fdt_attach +}; + +int qcgpio_fdt_read_pin(void *, int); +void qcgpio_fdt_write_pin(void *, int, int); +void *qcgpio_fdt_intr_establish(void *, int *, int, struct cpu_info *, + int (*)(void *), void *, char *); +void qcgpio_fdt_intr_disestablish(void *); +void qcgpio_fdt_intr_enable(void *); +void qcgpio_fdt_intr_disable(void *); +void qcgpio_fdt_intr_barrier(void *); +int qcgpio_fdt_pin_intr(struct qcgpio_softc *, int); +int qcgpio_fdt_intr(void *); + +int +qcgpio_fdt_match(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *faa = aux; + + return OF_is_compatible(faa->fa_node, "qcom,sc8280xp-tlmm"); +} + +void +qcgpio_fdt_attach(struct device *parent, struct device *self, void *aux) +{ + struct fdt_attach_args *faa = aux; + struct qcgpio_softc *sc = (struct qcgpio_softc *)self; + + sc->sc_iot = faa->fa_iot; + if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, faa->fa_reg[0].size, + 0, &sc->sc_ioh)) { + printf(": can't map registers\n"); + return; + } + + sc->sc_npins = 230; + sc->sc_pin_ih = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_ih), + M_DEVBUF, M_WAITOK | M_ZERO); + + sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_BIO, qcgpio_fdt_intr, + sc, sc->sc_dev.dv_xname); + if (sc->sc_ih == NULL) { + printf(": can't establish interrupt\n"); + goto unmap; + } + + sc->sc_ic.ic_node = faa->fa_node; + sc->sc_ic.ic_cookie = sc; + sc->sc_ic.ic_establish = qcgpio_fdt_intr_establish; + sc->sc_ic.ic_disestablish = qcgpio_fdt_intr_disestablish; + sc->sc_ic.ic_enable = qcgpio_fdt_intr_enable; + sc->sc_ic.ic_disable = qcgpio_fdt_intr_disable; + sc->sc_ic.ic_barrier = qcgpio_fdt_intr_barrier; + fdt_intr_register(&sc->sc_ic); + + printf("\n"); + return; + +unmap: + if (sc->sc_ih) + fdt_intr_disestablish(sc->sc_ih); + free(sc->sc_pin_ih, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_ih)); + bus_space_unmap(sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size); +} + +int +qcgpio_fdt_read_pin(void *cookie, int pin) +{ + struct qcgpio_softc *sc = cookie; + uint32_t reg; + + if (pin < 0 || pin >= sc->sc_npins) + return 0; + + reg = HREAD4(sc, TLMM_GPIO_IN_OUT(pin)); + return !!(reg & TLMM_GPIO_IN_OUT_GPIO_IN); +} + +void +qcgpio_fdt_write_pin(void *cookie, int pin, int val) +{ + struct qcgpio_softc *sc = cookie; + + if (pin < 0 || pin >= sc->sc_npins) + return; + + if (val) { + HSET4(sc, TLMM_GPIO_IN_OUT(pin), + TLMM_GPIO_IN_OUT_GPIO_OUT); + } else { + HCLR4(sc, TLMM_GPIO_IN_OUT(pin), + TLMM_GPIO_IN_OUT_GPIO_OUT); + } +} + +void * +qcgpio_fdt_intr_establish(void *cookie, int *cells, int ipl, + struct cpu_info *ci, int (*func)(void *), void *arg, char *name) +{ + struct qcgpio_softc *sc = cookie; + uint32_t reg; + int pin = cells[0]; + int level = cells[1]; + + if (pin < 0 || pin >= sc->sc_npins) + return NULL; + + sc->sc_pin_ih[pin].ih_func = func; + sc->sc_pin_ih[pin].ih_arg = arg; + sc->sc_pin_ih[pin].ih_pin = pin; + sc->sc_pin_ih[pin].ih_sc = sc; + + reg = HREAD4(sc, TLMM_GPIO_INTR_CFG(pin)); + reg &= ~TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_MASK; + reg &= ~TLMM_GPIO_INTR_CFG_INTR_POL_CTL; + switch (level) { + case 1: + reg |= TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_POS | + TLMM_GPIO_INTR_CFG_INTR_POL_CTL; + break; + case 2: + reg |= TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_NEG | + TLMM_GPIO_INTR_CFG_INTR_POL_CTL; + break; + case 3: + reg |= TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_BOTH; + break; + case 4: + reg |= TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_LEVEL | + TLMM_GPIO_INTR_CFG_INTR_POL_CTL; + break; + case 8: + reg |= TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_LEVEL; + break; + default: + printf("%s: unsupported interrupt mode/polarity\n", + sc->sc_dev.dv_xname); + break; + } + reg &= ~TLMM_GPIO_INTR_CFG_TARGET_PROC_MASK; + reg |= TLMM_GPIO_INTR_CFG_TARGET_PROC_RPM; + reg |= TLMM_GPIO_INTR_CFG_INTR_RAW_STATUS_EN; + reg |= TLMM_GPIO_INTR_CFG_INTR_ENABLE; + HWRITE4(sc, TLMM_GPIO_INTR_CFG(pin), reg); + + return &sc->sc_pin_ih[pin]; +} + +void +qcgpio_fdt_intr_disestablish(void *cookie) +{ + struct qcgpio_intrhand *ih = cookie; + + qcgpio_fdt_intr_disable(cookie); + ih->ih_func = NULL; +} + +void +qcgpio_fdt_intr_enable(void *cookie) +{ + struct qcgpio_intrhand *ih = cookie; + struct qcgpio_softc *sc = ih->ih_sc; + int pin = ih->ih_pin; + + if (pin < 0 || pin >= sc->sc_npins) + return; + + HSET4(sc, TLMM_GPIO_INTR_CFG(pin), + TLMM_GPIO_INTR_CFG_INTR_ENABLE); +} + +void +qcgpio_fdt_intr_disable(void *cookie) +{ + struct qcgpio_intrhand *ih = cookie; + struct qcgpio_softc *sc = ih->ih_sc; + int pin = ih->ih_pin; + + if (pin < 0 || pin >= sc->sc_npins) + return; + + HCLR4(sc, TLMM_GPIO_INTR_CFG(pin), + TLMM_GPIO_INTR_CFG_INTR_ENABLE); +} + +void +qcgpio_fdt_intr_barrier(void *cookie) +{ + struct qcgpio_intrhand *ih = cookie; + struct qcgpio_softc *sc = ih->ih_sc; + + intr_barrier(sc->sc_ih); +} + +int +qcgpio_fdt_intr(void *arg) +{ + struct qcgpio_softc *sc = arg; + int pin, handled = 0; + uint32_t stat; + + for (pin = 0; pin < sc->sc_npins; pin++) { + if (sc->sc_pin_ih[pin].ih_func == NULL) + continue; + + stat = HREAD4(sc, TLMM_GPIO_INTR_STATUS(pin)); + if (stat & TLMM_GPIO_INTR_STATUS_INTR_STATUS) { + sc->sc_pin_ih[pin].ih_func(sc->sc_pin_ih[pin].ih_arg); + handled = 1; + } + HWRITE4(sc, TLMM_GPIO_INTR_STATUS(pin), + stat & ~TLMM_GPIO_INTR_STATUS_INTR_STATUS); + } + + return handled; +}