diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2020-04-24 09:52:44 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2020-04-24 09:52:44 +0000 |
commit | c86de870a67df4b3a22ff5e0ba1b20f857171872 (patch) | |
tree | a56fd4d40abbe8195ff80f4eb566b286968a7110 /sys/dev/fdt | |
parent | 7b055ff1456b6d8c629d2f73f4e45d828777e55d (diff) |
Add bcmgpio(4). For now this driver only provides pinctrl functionality.
Actual gpio support (possibly including gpio(4) support) will come later.
ok jsg@
Diffstat (limited to 'sys/dev/fdt')
-rw-r--r-- | sys/dev/fdt/bcm2835_gpio.c | 199 | ||||
-rw-r--r-- | sys/dev/fdt/files.fdt | 6 |
2 files changed, 204 insertions, 1 deletions
diff --git a/sys/dev/fdt/bcm2835_gpio.c b/sys/dev/fdt/bcm2835_gpio.c new file mode 100644 index 00000000000..4d9d0ab3426 --- /dev/null +++ b/sys/dev/fdt/bcm2835_gpio.c @@ -0,0 +1,199 @@ +/* $OpenBSD: bcm2835_gpio.c,v 1.1 2020/04/24 09:52:43 kettenis Exp $ */ +/* + * Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org> + * + * 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 <sys/param.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/systm.h> + +#include <machine/bus.h> +#include <machine/fdt.h> + +#include <dev/ofw/openfirm.h> +#include <dev/ofw/ofw_pinctrl.h> +#include <dev/ofw/fdt.h> + +/* Registers */ +#define GPFSEL(n) (0x00 + ((n) * 4)) +#define GPFSEL_MASK 0x7 +#define GPFSEL_GPIO_IN 0x0 +#define GPFSEL_GPIO_OUT 0x1 +#define GPFSEL_ALT0 0x4 +#define GPFSEL_ALT1 0x5 +#define GPFSEL_ALT2 0x6 +#define GPFSEL_ALT3 0x7 +#define GPFSEL_ALT4 0x3 +#define GPFSEL_ALT5 0x2 +#define GPPUD 0x94 +#define GPPUD_PUD 0x3 +#define GPPUD_PUD_OFF 0x0 +#define GPPUD_PUD_DOWN 0x1 +#define GPPUD_PUD_UP 0x2 +#define GPPUDCLK(n) (0x98 + ((n) * 4)) +#define GPPULL(n) (0xe4 + ((n) * 4)) +#define GPPULL_MASK 0x3 + +#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)) + +struct bcmgpio_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + + void (*sc_config_pull)(struct bcmgpio_softc *, int, int); +}; + +int bcmgpio_match(struct device *, void *, void *); +void bcmgpio_attach(struct device *, struct device *, void *); + +struct cfattach bcmgpio_ca = { + sizeof (struct bcmgpio_softc), bcmgpio_match, bcmgpio_attach +}; + +struct cfdriver bcmgpio_cd = { + NULL, "bcmgpio", DV_DULL +}; + +void bcm2711_config_pull(struct bcmgpio_softc *, int, int); +void bcm2835_config_pull(struct bcmgpio_softc *, int, int); +int bcmgpio_pinctrl(uint32_t, void *); + +int +bcmgpio_match(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *faa = aux; + + return (OF_is_compatible(faa->fa_node, "brcm,bcm2711-gpio") || + OF_is_compatible(faa->fa_node, "brcm,bcm2835-gpio")); +} + +void +bcmgpio_attach(struct device *parent, struct device *self, void *aux) +{ + struct bcmgpio_softc *sc = (struct bcmgpio_softc *)self; + struct fdt_attach_args *faa = aux; + + if (faa->fa_nreg < 1) { + printf(": no registers\n"); + return; + } + + 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; + } + + printf("\n"); + + if (OF_is_compatible(faa->fa_node, "brcm,bcm2711-gpio")) + sc->sc_config_pull = bcm2711_config_pull; + else + sc->sc_config_pull = bcm2835_config_pull; + + pinctrl_register(faa->fa_node, bcmgpio_pinctrl, sc); +} + +void +bcmgpio_config_func(struct bcmgpio_softc *sc, int pin, int func) +{ + int reg = (pin / 10); + int shift = (pin % 10) * 3; + uint32_t val; + + val = HREAD4(sc, GPFSEL(reg)); + val &= ~(GPFSEL_MASK << shift); + HWRITE4(sc, GPFSEL(reg), val); + val |= ((func & GPFSEL_MASK) << shift); + HWRITE4(sc, GPFSEL(reg), val); +} + +void +bcm2711_config_pull(struct bcmgpio_softc *sc, int pin, int pull) +{ + int reg = (pin / 16); + int shift = (pin % 16) * 2; + uint32_t val; + + val = HREAD4(sc, GPPULL(reg)); + val &= ~(GPPULL_MASK << shift); + pull = ((pull & 1) << 1) | ((pull & 2) >> 1); + val |= (pull << shift); + HWRITE4(sc, GPPULL(reg), val); +} + +void +bcm2835_config_pull(struct bcmgpio_softc *sc, int pin, int pull) +{ + int reg = (pin / 32); + int shift = (pin % 32); + + HWRITE4(sc, GPPUD, pull & GPPUD_PUD); + delay(1); + HWRITE4(sc, GPPUDCLK(reg), 1 << shift); + delay(1); + HWRITE4(sc, GPPUDCLK(reg), 0); +} + +int +bcmgpio_pinctrl(uint32_t phandle, void *cookie) +{ + struct bcmgpio_softc *sc = cookie; + uint32_t *pins, *pull = NULL; + int len, plen = 0; + int node, i; + int func; + + node = OF_getnodebyphandle(phandle); + if (node == 0) + return -1; + + len = OF_getproplen(node, "brcm,pins"); + if (len <= 0) + return -1; + + pins = malloc(len, M_TEMP, M_WAITOK); + if (OF_getpropintarray(node, "brcm,pins", pins, len) != len) + goto fail; + func = OF_getpropint(node, "brcm,function", -1); + + plen = OF_getproplen(node, "brcm,pull"); + if (plen > 0) { + pull = malloc(len, M_TEMP, M_WAITOK); + if (OF_getpropintarray(node, "brcm,pull", pull, plen) != plen) + goto fail; + } + + for (i = 0; i < len / sizeof(uint32_t); i++) { + bcmgpio_config_func(sc, pins[i], func); + if (i < plen / sizeof(uint32_t)) + sc->sc_config_pull(sc, pins[i], pull[i]); + } + + free(pull, M_TEMP, plen); + free(pins, M_TEMP, len); + return 0; + +fail: + free(pull, M_TEMP, plen); + free(pins, M_TEMP, len); + return -1; +} diff --git a/sys/dev/fdt/files.fdt b/sys/dev/fdt/files.fdt index a9b4082a944..f0b41a72c5e 100644 --- a/sys/dev/fdt/files.fdt +++ b/sys/dev/fdt/files.fdt @@ -1,4 +1,4 @@ -# $OpenBSD: files.fdt,v 1.125 2020/04/23 22:14:49 patrick Exp $ +# $OpenBSD: files.fdt,v 1.126 2020/04/24 09:52:43 kettenis Exp $ # # Config file and device description for machine-independent FDT code. # Included by ports that need it. @@ -93,6 +93,10 @@ device bcmdog attach bcmdog at fdt file dev/fdt/bcm2835_dog.c bcmdog +device bcmgpio +attach bcmgpio at fdt +file dev/fdt/bcm2835_gpio.c bcmgpio + device bcmirng attach bcmirng at fdt file dev/fdt/bcm2711_rng.c bcmirng |