Module Name:    src
Committed By:   mlelstv
Date:           Sat Sep 28 07:24:52 UTC 2019

Modified Files:
        src/sys/arch/arm/broadcom: bcm2835_gpio.c bcm2835_gpioreg.h

Log Message:
Handle BCM2838 (bcm2711) SoC pecularities.


To generate a diff of this commit:
cvs rdiff -u -r1.12 -r1.13 src/sys/arch/arm/broadcom/bcm2835_gpio.c
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/arm/broadcom/bcm2835_gpioreg.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/arm/broadcom/bcm2835_gpio.c
diff -u src/sys/arch/arm/broadcom/bcm2835_gpio.c:1.12 src/sys/arch/arm/broadcom/bcm2835_gpio.c:1.13
--- src/sys/arch/arm/broadcom/bcm2835_gpio.c:1.12	Fri May 10 08:28:50 2019
+++ src/sys/arch/arm/broadcom/bcm2835_gpio.c	Sat Sep 28 07:24:52 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: bcm2835_gpio.c,v 1.12 2019/05/10 08:28:50 skrll Exp $	*/
+/*	$NetBSD: bcm2835_gpio.c,v 1.13 2019/09/28 07:24:52 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 2013, 2014, 2017 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bcm2835_gpio.c,v 1.12 2019/05/10 08:28:50 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bcm2835_gpio.c,v 1.13 2019/09/28 07:24:52 mlelstv Exp $");
 
 /*
  * Driver for BCM2835 GPIO
@@ -65,7 +65,9 @@ int bcm2835gpiodebug = 3;
 #define DPRINTF(l, x)
 #endif
 
-#define	BCMGPIO_MAXPINS	54
+#define BCM2835_GPIO_MAXPINS 54
+#define BCM2838_GPIO_MAXPINS 58
+#define	BCMGPIO_MAXPINS	BCM2838_GPIO_MAXPINS
 
 struct bcmgpio_eint {
 	 int			(*eint_func)(void *);
@@ -101,6 +103,9 @@ struct bcmgpio_softc {
 
 	/* For interrupt support. */
 	struct bcmgpio_bank	sc_banks[BCMGPIO_NBANKS];
+
+	bool			sc_is2835;	/* for pullup on 2711 */
+	u_int			sc_maxpins;
 };
 
 struct bcmgpio_pin {
@@ -216,7 +221,7 @@ bcm283x_pinctrl_set_config(device_t dev,
 	for (int i = 0; i < npins; i++) {
 		const u_int pin = be32toh(pins[i]);
 
-		if (pin > BCMGPIO_MAXPINS)
+		if (pin > sc->sc_maxpins)
 			continue;
 		if (pull) {
 			const int value = be32toh(pull[npull == 1 ? 0 : i]);
@@ -254,6 +259,7 @@ bcmgpio_attach(device_t parent, device_t
 	int error;
 	int pin;
 	int bank;
+	uint32_t reg;
 
 	const int phandle = faa->faa_phandle;
 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
@@ -263,19 +269,25 @@ bcmgpio_attach(device_t parent, device_t
 
 	sc->sc_dev = self;
 
-	aprint_naive("\n");
-	aprint_normal(": GPIO controller\n");
-
 	sc->sc_iot = faa->faa_bst;
 	error = bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh);
 	if (error) {
-		aprint_error_dev(self, "couldn't map registers\n");
+		aprint_error_dev(self, ": couldn't map registers\n");
 		return;
 	}
 
 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
 
-	for (pin = 0; pin < BCMGPIO_MAXPINS; pin++) {
+	/* BCM2835, BCM2836, BCM2837 return 'gpio' in this unused register */
+	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BCM2838_GPIO_GPPUPPDN(3));
+	sc->sc_is2835 = reg == 0x6770696f;
+	sc->sc_maxpins = sc->sc_is2835 ? BCM2835_GPIO_MAXPINS
+	                               : BCM2838_GPIO_MAXPINS;
+
+	aprint_naive("\n");
+	aprint_normal(": GPIO controller %s\n", sc->sc_is2835 ? "2835" : "2838");
+
+	for (pin = 0; pin < sc->sc_maxpins; pin++) {
 		sc->sc_gpio_pins[pin].pin_num = pin;
 		/*
 		 * find out pins still available for GPIO
@@ -329,13 +341,13 @@ bcmgpio_attach(device_t parent, device_t
 			aprint_normal_dev(self,
 			    "pins %d..%d interrupting on %s\n",
 			    bank * 32,
-			    MIN((bank * 32) + 31, BCMGPIO_MAXPINS),
+			    MIN((bank * 32) + 31, sc->sc_maxpins),
 			    intrstr);
 		} else {
 			aprint_error_dev(self,
 			    "failed to establish interrupt for pins %d..%d\n",
 			    bank * 32,
-			    MIN((bank * 32) + 31, BCMGPIO_MAXPINS));
+			    MIN((bank * 32) + 31, sc->sc_maxpins));
 		}
 	}
 
@@ -364,7 +376,7 @@ bcmgpio_attach(device_t parent, device_t
 
 	gba.gba_gc = &sc->sc_gpio_gc;
 	gba.gba_pins = &sc->sc_gpio_pins[0];
-	gba.gba_npins = BCMGPIO_MAXPINS;
+	gba.gba_npins = sc->sc_maxpins;
 	(void) config_found_ia(self, "gpiobus", &gba, gpiobus_print);
 }
 
@@ -657,8 +669,9 @@ bcmgpio_gpio_intr_disestablish(void *vsc
 static bool
 bcmgpio_gpio_intrstr(void *vsc, int pin, int irqmode, char *buf, size_t buflen)
 {
+	struct bcmgpio_softc * const sc = vsc;
 
-	if (pin < 0 || pin >= BCMGPIO_MAXPINS)
+	if (pin < 0 || pin >= sc->sc_maxpins)
 		return (false);
 
 	snprintf(buf, buflen, "GPIO %d", pin);
@@ -797,15 +810,48 @@ bcm283x_pin_setpull(const struct bcmgpio
 
 	KASSERT(mutex_owned(&sc->sc_lock));
 
-	const u_int mask = 1 << (pin % BCM2835_GPIO_GPPUD_PINS_PER_REGISTER);
-	const u_int regid = (pin / BCM2835_GPIO_GPPUD_PINS_PER_REGISTER);
+	u_int mask, regid;
+	uint32_t reg;
 
-	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BCM2835_GPIO_GPPUD, pud);
-	delay(1);
-	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BCM2835_GPIO_GPPUDCLK(regid), mask);
-	delay(1);
-	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BCM2835_GPIO_GPPUD, 0);
-	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BCM2835_GPIO_GPPUDCLK(regid), 0);
+	if (sc->sc_is2835) {
+		mask = 1 << (pin % BCM2835_GPIO_GPPUD_PINS_PER_REGISTER);
+		regid = (pin / BCM2835_GPIO_GPPUD_PINS_PER_REGISTER);
+
+printf("2835: pin=%u, pud=%u, regid=%u, mask=%08x\n",pin,pud,regid,mask);
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+		    BCM2835_GPIO_GPPUD, pud);
+		delay(1);
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+		    BCM2835_GPIO_GPPUDCLK(regid), mask);
+		delay(1);
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+		    BCM2835_GPIO_GPPUD, 0);
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+		    BCM2835_GPIO_GPPUDCLK(regid), 0);
+	} else {
+		mask = BCM2838_GPIO_GPPUD_MASK(pin);
+		regid = BCM2838_GPIO_GPPUD_REGID(pin);
+
+		switch (pud) {
+		case BCM2835_GPIO_GPPUD_PULLUP:
+			pud = BCM2838_GPIO_GPPUD_PULLUP;
+			break;
+		case BCM2835_GPIO_GPPUD_PULLDOWN:
+			pud = BCM2838_GPIO_GPPUD_PULLDOWN;
+			break;
+		default:
+			pud = BCM2838_GPIO_GPPUD_PULLOFF;
+			break;
+		}
+printf("2838: pin=%u, pud=%u, regid=%u, mask=%08x\n",pin,pud,regid,mask);
+
+		reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+		    BCM2838_GPIO_GPPUPPDN(regid));
+		reg &= ~mask;
+		reg |= __SHIFTIN(pud, mask);
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+		    BCM2838_GPIO_GPPUPPDN(regid), reg);
+	}
 }
 
 
@@ -866,20 +912,7 @@ bcm2835gpio_gpio_pin_ctl(void *arg, int 
 		cmd = BCM2835_GPIO_GPPUD_PULLOFF;
 	}
 
-	/* set up control signal */
-	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BCM2835_GPIO_GPPUD, cmd);
-	delay(1); /* wait 150 cycles */
-	/* set clock signal */
-	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
-	    BCM2835_GPIO_GPPUDCLK(pin / BCM2835_GPIO_GPLEV_PINS_PER_REGISTER),
-	    1 << (pin % BCM2835_GPIO_GPPUD_PINS_PER_REGISTER));
-	delay(1); /* wait 150 cycles */
-	/* reset control signal and clock */
-	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
-	    BCM2835_GPIO_GPPUD, BCM2835_GPIO_GPPUD_PULLOFF);
-	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
-	    BCM2835_GPIO_GPPUDCLK(pin / BCM2835_GPIO_GPLEV_PINS_PER_REGISTER),
-	    0);
+	bcm283x_pin_setpull(sc, pin, cmd);
 	mutex_exit(&sc->sc_lock);
 }
 
@@ -896,7 +929,7 @@ bcmgpio_fdt_acquire(device_t dev, const 
 	const u_int pin = be32toh(gpio[1]);
 	const bool actlo = be32toh(gpio[2]) & 1;
 
-	if (pin >= BCMGPIO_MAXPINS)
+	if (pin >= sc->sc_maxpins)
 		return NULL;
 
 	gpin = kmem_alloc(sizeof(*gpin), KM_SLEEP);

Index: src/sys/arch/arm/broadcom/bcm2835_gpioreg.h
diff -u src/sys/arch/arm/broadcom/bcm2835_gpioreg.h:1.4 src/sys/arch/arm/broadcom/bcm2835_gpioreg.h:1.5
--- src/sys/arch/arm/broadcom/bcm2835_gpioreg.h:1.4	Sun Dec 10 21:38:26 2017
+++ src/sys/arch/arm/broadcom/bcm2835_gpioreg.h	Sat Sep 28 07:24:52 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: bcm2835_gpioreg.h,v 1.4 2017/12/10 21:38:26 skrll Exp $	*/
+/*	$NetBSD: bcm2835_gpioreg.h,v 1.5 2019/09/28 07:24:52 mlelstv Exp $	*/
 
 /*
  * Copyright (c) 2013 Jonathan A. Kollasch
@@ -48,6 +48,7 @@
 #define BCM2835_GPIO_GPAFEN(x)	(0x088 + (x) * sizeof(uint32_t))
 
 #define BCM2835_GPIO_GPPUD	(0x094)
+
 /* brcm,pull property */
 #define  BCM2835_GPIO_GPPUD_PULLOFF	0x0
 #define  BCM2835_GPIO_GPPUD_PULLDOWN	0x1
@@ -55,6 +56,13 @@
 #define BCM2835_GPIO_GPPUDCLK(x)	(0x098 + (x) * sizeof(uint32_t))
 #define BCM2835_GPIO_GPPUD_PINS_PER_REGISTER 32
 
+#define  BCM2838_GPIO_GPPUD_PULLOFF	0x0
+#define  BCM2838_GPIO_GPPUD_PULLDOWN	0x2
+#define  BCM2838_GPIO_GPPUD_PULLUP	0x1
+#define BCM2838_GPIO_GPPUPPDN(x)	(0x0e4 + (x) * sizeof(uint32_t))
+#define BCM2838_GPIO_GPPUD_REGID(n)	((n) / 16)
+#define BCM2838_GPIO_GPPUD_MASK(n)	(0x3 << ((n) % 16)*2)
+
 /* brcm,function property */
 #define BCM2835_GPIO_IN		0
 #define BCM2835_GPIO_OUT	1

Reply via email to