Diff below adds GPIO support to bcmgpio(4). It also adds the bits to
attach gpio(4) such that GPIO pins can be controlled from userland.
This makes sense on boards like the Raspberry Pi and the
implementation makes sure that pins used by kernel drivers can't be
touched.
ok?
Index: arch/arm64/conf/GENERIC
===
RCS file: /cvs/src/sys/arch/arm64/conf/GENERIC,v
retrieving revision 1.161
diff -u -p -r1.161 GENERIC
--- arch/arm64/conf/GENERIC 25 Apr 2020 22:28:12 - 1.161
+++ arch/arm64/conf/GENERIC 26 Apr 2020 10:51:19 -
@@ -148,6 +148,7 @@ bcmclock* at fdt? early 1
bcmdmac* at fdt? early 1
bcmdog*at fdt?
bcmgpio* at fdt? early 1
+gpio* at bcmgpio?
bcmintc* at fdt? early 1
bcmirng* at fdt?
bcmmbox* at fdt? early 1
Index: dev/fdt/bcm2835_gpio.c
===
RCS file: /cvs/src/sys/dev/fdt/bcm2835_gpio.c,v
retrieving revision 1.2
diff -u -p -r1.2 bcm2835_gpio.c
--- dev/fdt/bcm2835_gpio.c 25 Apr 2020 22:15:00 - 1.2
+++ dev/fdt/bcm2835_gpio.c 26 Apr 2020 10:51:20 -
@@ -17,16 +17,21 @@
#include
#include
+#include
#include
#include
#include
#include
+#include
#include
+#include
#include
#include
+#include "gpio.h"
+
/* Registers */
#define GPFSEL(n) (0x00 + ((n) * 4))
#define GPFSEL_MASK 0x7
@@ -38,6 +43,9 @@
#define GPFSEL_ALT3 0x7
#define GPFSEL_ALT4 0x3
#define GPFSEL_ALT5 0x2
+#define GPSET(n) (0x1c + ((n) * 4))
+#define GPCLR(n) (0x28 + ((n) * 4))
+#define GPLEV(n) (0x34 + ((n) * 4))
#define GPPUD 0x94
#define GPPUD_PUD 0x3
#define GPPUD_PUD_OFF 0x0
@@ -47,6 +55,8 @@
#define GPPULL(n) (0xe4 + ((n) * 4))
#define GPPULL_MASK 0x3
+#define BCMGPIO_MAX_PINS 58
+
#define HREAD4(sc, reg)
\
(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
#define HWRITE4(sc, reg, val) \
@@ -58,6 +68,13 @@ struct bcmgpio_softc {
bus_space_handle_t sc_ioh;
void(*sc_config_pull)(struct bcmgpio_softc *, int, int);
+ int sc_num_pins;
+
+ struct gpio_controller sc_gc;
+
+ struct gpio_chipset_tag sc_gpio_tag;
+ gpio_pin_t sc_gpio_pins[BCMGPIO_MAX_PINS];
+ int sc_gpio_claimed[BCMGPIO_MAX_PINS];
};
intbcmgpio_match(struct device *, void *, void *);
@@ -74,6 +91,10 @@ struct cfdriver bcmgpio_cd = {
void bcm2711_config_pull(struct bcmgpio_softc *, int, int);
void bcm2835_config_pull(struct bcmgpio_softc *, int, int);
intbcmgpio_pinctrl(uint32_t, void *);
+void bcmgpio_config_pin(void *, uint32_t *, int);
+intbcmgpio_get_pin(void *, uint32_t *);
+void bcmgpio_set_pin(void *, uint32_t *, int);
+void bcmgpio_attach_gpio(struct device *);
int
bcmgpio_match(struct device *parent, void *match, void *aux)
@@ -104,12 +125,24 @@ bcmgpio_attach(struct device *parent, st
printf("\n");
- if (OF_is_compatible(faa->fa_node, "brcm,bcm2711-gpio"))
+ if (OF_is_compatible(faa->fa_node, "brcm,bcm2711-gpio")) {
sc->sc_config_pull = bcm2711_config_pull;
- else
+ sc->sc_num_pins = 58;
+ } else {
sc->sc_config_pull = bcm2835_config_pull;
+ sc->sc_num_pins = 54;
+ }
pinctrl_register(faa->fa_node, bcmgpio_pinctrl, sc);
+
+ sc->sc_gc.gc_node = faa->fa_node;
+ sc->sc_gc.gc_cookie = sc;
+ sc->sc_gc.gc_config_pin = bcmgpio_config_pin;
+ sc->sc_gc.gc_get_pin = bcmgpio_get_pin;
+ sc->sc_gc.gc_set_pin = bcmgpio_set_pin;
+ gpio_controller_register(&sc->sc_gc);
+
+ config_mountroot(self, bcmgpio_attach_gpio);
}
void
@@ -186,6 +219,7 @@ bcmgpio_pinctrl(uint32_t phandle, void *
bcmgpio_config_func(sc, pins[i], func);
if (plen > 0 && i < plen / sizeof(uint32_t))
sc->sc_config_pull(sc, pins[i], pull[i]);
+ sc->sc_gpio_claimed[pins[i]] = 1;
}
free(pull, M_TEMP, plen);
@@ -196,4 +230,176 @@ fail:
free(pull, M_TEMP, plen);
free(pins, M_TEMP, len);
return -1;
+}
+
+void
+bcmgpio_config_pin(void *cookie, uint32_t *cells, int config)
+{
+ struct bcmgpio_softc *sc = cookie;
+ uint32_t pin = cells[0];
+
+ if (pin >= sc->sc_num_pins)
+ return;
+
+ if (config & GPIO_CONFIG_OUTPUT)
+ bcmgpio_config_func(sc, pin, GPFSEL_GPIO_OUT);
+ else
+ bcmgpio_config_func(sc, pin, GPFSEL_GPIO_OUT);
+ if (config & GPIO_CONFIG_PULL_UP)
+ sc->sc_config_pull(sc, pin, GPPUD_PUD_UP);
+ else