aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmmanuel Vadot <manu@FreeBSD.org>2022-09-29 08:05:19 +0000
committerEmmanuel Vadot <manu@FreeBSD.org>2023-08-10 07:21:55 +0000
commitb07fed8180a6b97f44c7d900d17b94fa3f1974cf (patch)
treec523c15adf78188e627c277888a0475921ded9b6
parent9da33e8d10736c255bf63d408837c6942bd28e04 (diff)
downloadsrc-b07fed8180a6b97f44c7d900d17b94fa3f1974cf.tar.gz
src-b07fed8180a6b97f44c7d900d17b94fa3f1974cf.zip
arm: xilinx: gpio: Make the driver more generic
All other Zynq SoCs have the same GPIO controller, the only difference is the number of banks/pins so make this driver more generic to add other SoCs more easily. No functional changes intended. Sponsored by: Beckhoff Automation GmbH & Co. KG MFC after: 2 weeks
-rw-r--r--sys/arm/xilinx/zy7_gpio.c120
1 files changed, 93 insertions, 27 deletions
diff --git a/sys/arm/xilinx/zy7_gpio.c b/sys/arm/xilinx/zy7_gpio.c
index 9e9cf2b7f86a..d487fc8e79d1 100644
--- a/sys/arm/xilinx/zy7_gpio.c
+++ b/sys/arm/xilinx/zy7_gpio.c
@@ -70,16 +70,30 @@ __FBSDID("$FreeBSD$");
#include "gpio_if.h"
-#define NUMBANKS 4
-#define MAXPIN (32*NUMBANKS)
-
-#define MIO_PIN 0 /* pins 0-53 go to MIO */
-#define NUM_MIO_PINS 54
-#define EMIO_PIN 64 /* pins 64-127 go to PL */
-#define NUM_EMIO_PINS 64
-
-#define VALID_PIN(u) (((u) >= MIO_PIN && (u) < MIO_PIN + NUM_MIO_PINS) || \
- ((u) >= EMIO_PIN && (u) < EMIO_PIN + NUM_EMIO_PINS))
+#define ZYNQ_MAX_BANK 4
+
+/* Zynq 7000 */
+#define ZYNQ_BANK0_PIN_MIN 0
+#define ZYNQ_BANK0_NPIN 32
+#define ZYNQ_BANK1_PIN_MIN 32
+#define ZYNQ_BANK1_NPIN 22
+#define ZYNQ_BANK2_PIN_MIN 64
+#define ZYNQ_BANK2_NPIN 32
+#define ZYNQ_BANK3_PIN_MIN 96
+#define ZYNQ_BANK3_NPIN 32
+#define ZYNQ_PIN_MIO_MIN 0
+#define ZYNQ_PIN_MIO_MAX 54
+#define ZYNQ_PIN_EMIO_MIN 64
+#define ZYNQ_PIN_EMIO_MAX 118
+
+#define ZYNQ_BANK_NPIN(bank) (ZYNQ_BANK##bank##_NPIN)
+#define ZYNQ_BANK_PIN_MIN(bank) (ZYNQ_BANK##bank##_PIN_MIN)
+#define ZYNQ_BANK_PIN_MAX(bank) (ZYNQ_BANK##bank##_PIN_MIN + ZYNQ_BANK##bank##_NPIN - 1)
+
+#define ZYNQ_PIN_IS_MIO(pin) (pin >= ZYNQ_PIN_MIO_MIN && \
+ pin <= ZYNQ_PIN_MIO_MAX)
+#define ZYNQ_PIN_IS_EMIO(pin) (pin >= ZYNQ_PIN_EMIO_MIN && \
+ pin <= ZYNQ_PIN_EMIO_MAX)
#define ZGPIO_LOCK(sc) mtx_lock(&(sc)->sc_mtx)
#define ZGPIO_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx)
@@ -88,11 +102,39 @@ __FBSDID("$FreeBSD$");
"gpio", MTX_DEF)
#define ZGPIO_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
+struct zynq_gpio_conf {
+ char *name;
+ uint32_t nbanks;
+ uint32_t maxpin;
+ uint32_t bank_min[ZYNQ_MAX_BANK];
+ uint32_t bank_max[ZYNQ_MAX_BANK];
+};
+
struct zy7_gpio_softc {
- device_t dev;
- device_t busdev;
- struct mtx sc_mtx;
- struct resource *mem_res; /* Memory resource */
+ device_t dev;
+ device_t busdev;
+ struct mtx sc_mtx;
+ struct resource *mem_res; /* Memory resource */
+ struct zynq_gpio_conf *conf;
+};
+
+static struct zynq_gpio_conf z7_gpio_conf = {
+ .name = "Zynq-7000 GPIO Controller",
+ .nbanks = ZYNQ_MAX_BANK,
+ .maxpin = ZYNQ_PIN_EMIO_MAX,
+ .bank_min[0] = ZYNQ_BANK_PIN_MIN(0),
+ .bank_max[0] = ZYNQ_BANK_PIN_MAX(0),
+ .bank_min[1] = ZYNQ_BANK_PIN_MIN(1),
+ .bank_max[1] = ZYNQ_BANK_PIN_MAX(1),
+ .bank_min[2] = ZYNQ_BANK_PIN_MIN(2),
+ .bank_max[2] = ZYNQ_BANK_PIN_MAX(2),
+ .bank_min[3] = ZYNQ_BANK_PIN_MIN(3),
+ .bank_max[3] = ZYNQ_BANK_PIN_MAX(3),
+};
+
+static struct ofw_compat_data compat_data[] = {
+ {"xlnx,zy7_gpio", (uintptr_t)&z7_gpio_conf},
+ {NULL, 0},
};
#define WR4(sc, off, val) bus_write_4((sc)->mem_res, (off), (val))
@@ -128,17 +170,37 @@ zy7_gpio_get_bus(device_t dev)
static int
zy7_gpio_pin_max(device_t dev, int *maxpin)
{
+ struct zy7_gpio_softc *sc;
- *maxpin = MAXPIN;
+ sc = device_get_softc(dev);
+ *maxpin = sc->conf->maxpin;
return (0);
}
+static inline bool
+zy7_pin_valid(device_t dev, uint32_t pin)
+{
+ struct zy7_gpio_softc *sc;
+ int i;
+ bool found = false;
+
+ sc = device_get_softc(dev);
+ for (i = 0; i < sc->conf->nbanks; i++) {
+ if (pin >= sc->conf->bank_min[i] && pin <= sc->conf->bank_max[i]) {
+ found = true;
+ break;
+ }
+ }
+
+ return (found);
+}
+
/* Get a specific pin's capabilities. */
static int
zy7_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
{
- if (!VALID_PIN(pin))
+ if (!zy7_pin_valid(dev, pin))
return (EINVAL);
*caps = (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE);
@@ -151,14 +213,14 @@ static int
zy7_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
{
- if (!VALID_PIN(pin))
+ if (!zy7_pin_valid(dev, pin))
return (EINVAL);
- if (pin < NUM_MIO_PINS) {
+ if (ZYNQ_PIN_IS_MIO(pin)) {
snprintf(name, GPIOMAXNAME, "MIO_%d", pin);
name[GPIOMAXNAME - 1] = '\0';
} else {
- snprintf(name, GPIOMAXNAME, "EMIO_%d", pin - EMIO_PIN);
+ snprintf(name, GPIOMAXNAME, "EMIO_%d", pin - ZYNQ_PIN_EMIO_MIN);
name[GPIOMAXNAME - 1] = '\0';
}
@@ -171,7 +233,7 @@ zy7_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
{
struct zy7_gpio_softc *sc = device_get_softc(dev);
- if (!VALID_PIN(pin))
+ if (!zy7_pin_valid(dev, pin))
return (EINVAL);
ZGPIO_LOCK(sc);
@@ -197,7 +259,7 @@ zy7_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
{
struct zy7_gpio_softc *sc = device_get_softc(dev);
- if (!VALID_PIN(pin))
+ if (!zy7_pin_valid(dev, pin))
return (EINVAL);
ZGPIO_LOCK(sc);
@@ -234,7 +296,7 @@ zy7_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
{
struct zy7_gpio_softc *sc = device_get_softc(dev);
- if (!VALID_PIN(pin) || value > 1)
+ if (!zy7_pin_valid(dev, pin) || value > 1)
return (EINVAL);
/* Fancy register tricks allow atomic set or reset. */
@@ -256,7 +318,7 @@ zy7_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value)
{
struct zy7_gpio_softc *sc = device_get_softc(dev);
- if (!VALID_PIN(pin))
+ if (!zy7_pin_valid(dev, pin))
return (EINVAL);
*value = (RD4(sc, ZY7_GPIO_DATA_RO(pin >> 5)) >> (pin & 31)) & 1;
@@ -270,7 +332,7 @@ zy7_gpio_pin_toggle(device_t dev, uint32_t pin)
{
struct zy7_gpio_softc *sc = device_get_softc(dev);
- if (!VALID_PIN(pin))
+ if (!zy7_pin_valid(dev, pin))
return (EINVAL);
ZGPIO_LOCK(sc);
@@ -286,14 +348,16 @@ zy7_gpio_pin_toggle(device_t dev, uint32_t pin)
static int
zy7_gpio_probe(device_t dev)
{
+ struct zynq_gpio_conf *conf;
if (!ofw_bus_status_okay(dev))
return (ENXIO);
- if (!ofw_bus_is_compatible(dev, "xlnx,zy7_gpio"))
+ conf = (struct zynq_gpio_conf *)ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+ if (conf == 0)
return (ENXIO);
- device_set_desc(dev, "Zynq-7000 GPIO driver");
+ device_set_desc(dev, conf->name);
return (0);
}
@@ -306,6 +370,7 @@ zy7_gpio_attach(device_t dev)
int rid;
sc->dev = dev;
+ sc->conf = (struct zynq_gpio_conf *)ofw_bus_search_compatible(dev, compat_data)->ocd_data;
ZGPIO_LOCK_INIT(sc);
@@ -372,4 +437,5 @@ static driver_t zy7_gpio_driver = {
sizeof(struct zy7_gpio_softc),
};
-DRIVER_MODULE(zy7_gpio, simplebus, zy7_gpio_driver, NULL, NULL);
+EARLY_DRIVER_MODULE(zy7_gpio, simplebus, zy7_gpio_driver, 0, 0,
+ BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);