Date: Tue, 4 Dec 2012 17:19:06 -0200 From: Luiz Otavio O Souza <loos.br@gmail.com> To: freebsd-arch@freebsd.org Subject: FDT Support for GPIO (gpiobus and friends) Message-ID: <BEB9A0F8-560B-4937-8707-653988A26D85@gmail.com>
next in thread | raw e-mail | index | archive | help
--Apple-Mail-16-531908476
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain;
charset=us-ascii
Hi,
I've been playing with GPIO on RPi and found the missing support of FDT =
on gpiobus very annoying.
The following patch (gpio-fdt.diff) adds FDT support to GPIO (gpiobus, =
gpioc, gpioled).
The bcm2835_gpio.c.fdt.diff will add (a better) support of FDT on RPi =
GPIO controller and the bcm2835.dts.diff has my changes on the RPi dts =
for adding support of gpioled on 'ok' led (pin 16).
Comments ?
Thanks,
Luiz
--Apple-Mail-16-531908476
Content-Disposition: attachment;
filename=gpio-fdt.diff
Content-Type: application/octet-stream;
name="gpio-fdt.diff"
Content-Transfer-Encoding: 7bit
Index: dev/gpio/gpiobus.c
===================================================================
--- dev/gpio/gpiobus.c (revision 243614)
+++ dev/gpio/gpiobus.c (working copy)
@@ -46,6 +46,12 @@
#include "gpio_if.h"
#include "gpiobus_if.h"
+#ifdef FDT
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/fdt/fdt_common.h>
+#endif
+
static void gpiobus_print_pins(struct gpiobus_ivar *);
static int gpiobus_parse_pins(struct gpiobus_softc *, device_t, int);
static int gpiobus_probe(device_t);
@@ -169,9 +175,64 @@
return (0);
}
+#ifdef FDT
static int
+gpiobus_fdt_parse_pins(struct gpiobus_softc *sc, struct gpiobus_ivar *devi,
+ device_t child, phandle_t pchild)
+{
+ int i, len;
+ pcell_t *pins;
+
+ if ((len = OF_getproplen(pchild, "pins")) == -1)
+ return (-1);
+
+ pins = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (pins == NULL)
+ return (-1);
+
+ if (OF_getprop(pchild, "pins", pins, len) == -1) {
+ free(pins, M_DEVBUF);
+ return (-1);
+ }
+
+ devi->npins = len / sizeof(pcell_t);
+ devi->pins = malloc(sizeof(uint32_t) * devi->npins, M_DEVBUF,
+ M_NOWAIT | M_ZERO);
+ if (devi->pins == NULL) {
+ free(pins, M_DEVBUF);
+ return (-1);
+ }
+
+ for (i = 0; i < devi->npins; i++) {
+ devi->pins[i] = fdt32_to_cpu(pins[i]);
+
+ /*
+ * Mark pin as mapped and give warning if it's already mapped
+ */
+ if (sc->sc_pins_mapped[devi->pins[i]]) {
+ device_printf(child,
+ "warning: pin %d is already mapped\n",
+ devi->pins[i]);
+ free(pins, M_DEVBUF);
+ return (-1);
+ }
+ sc->sc_pins_mapped[devi->pins[i]] = 1;
+ }
+
+ free(pins, M_DEVBUF);
+ return (0);
+}
+#endif
+
+static int
gpiobus_probe(device_t dev)
{
+
+#ifdef FDT
+ if (!ofw_bus_is_compatible(dev, "gpiobus"))
+ return (ENXIO);
+#endif
+
device_set_desc(dev, "GPIO bus");
return (0);
}
@@ -179,6 +240,11 @@
static int
gpiobus_attach(device_t dev)
{
+#ifdef FDT
+ device_t dev_child;
+ phandle_t dt_node, dt_child;
+ struct gpiobus_ivar *devi;
+#endif
struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
int res;
@@ -208,6 +274,53 @@
* Get parent's pins and mark them as unmapped
*/
bus_enumerate_hinted_children(dev);
+
+#ifdef FDT
+ /*
+ * Walk gpiobus and add direct subordinates as our children.
+ */
+ dt_node = ofw_bus_get_node(dev);
+ for (dt_child = OF_child(dt_node); dt_child != 0;
+ dt_child = OF_peer(dt_child)) {
+
+ /* Check and process 'status' property. */
+ if (!(fdt_is_enabled(dt_child)))
+ continue;
+
+ /* The GPIO pins are mandatory. */
+ if (!OF_hasprop(dt_child, "pins"))
+ continue;
+
+ devi = malloc(sizeof(*devi), M_DEVBUF, M_WAITOK | M_ZERO);
+
+ if (ofw_bus_gen_setup_devinfo(&devi->ofw, dt_child) != 0) {
+ free(devi, M_DEVBUF);
+ device_printf(dev, "could not set up devinfo\n");
+ continue;
+ }
+
+ /* Add newbus device for this FDT node */
+ dev_child = device_add_child(dev, NULL, -1);
+ if (dev_child == NULL) {
+ device_printf(dev, "could not add child: %s\n",
+ devi->ofw.obd_name);
+ /* XXX should unmap */
+ ofw_bus_gen_destroy_devinfo(&devi->ofw);
+ free(devi, M_DEVBUF);
+ continue;
+ }
+ device_set_ivars(dev_child, devi);
+
+ if (gpiobus_fdt_parse_pins(sc,
+ devi, dev_child, dt_child) != 0) {
+ device_delete_child(dev, dev_child);
+ ofw_bus_gen_destroy_devinfo(&devi->ofw);
+ free(devi, M_DEVBUF);
+ continue;
+ }
+ }
+#endif
+
return (bus_generic_attach(dev));
}
@@ -445,6 +558,17 @@
return GPIO_PIN_TOGGLE(sc->sc_dev, devi->pins[pin]);
}
+#ifdef FDT
+static const struct ofw_bus_devinfo *
+gpiobus_get_devinfo(device_t bus, device_t child)
+{
+ struct gpiobus_ivar *devi;
+
+ devi = device_get_ivars(child);
+ return (&devi->ofw);
+}
+#endif
+
static device_method_t gpiobus_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, gpiobus_probe),
@@ -473,6 +597,16 @@
DEVMETHOD(gpiobus_pin_set, gpiobus_pin_set),
DEVMETHOD(gpiobus_pin_toggle, gpiobus_pin_toggle),
+#ifdef FDT
+ /* OFW bus interface */
+ DEVMETHOD(ofw_bus_get_devinfo, gpiobus_get_devinfo),
+ DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat),
+ DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model),
+ DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name),
+ DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node),
+ DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type),
+#endif
+
DEVMETHOD_END
};
Index: dev/gpio/gpiobusvar.h
===================================================================
--- dev/gpio/gpiobusvar.h (revision 243614)
+++ dev/gpio/gpiobusvar.h (working copy)
@@ -34,6 +34,12 @@
#include <sys/lock.h>
#include <sys/mutex.h>
+#include "opt_platform.h"
+
+#ifdef FDT
+#include <dev/ofw/ofw_bus_subr.h>
+#endif
+
#define GPIOBUS_IVAR(d) (struct gpiobus_ivar *) device_get_ivars(d)
#define GPIOBUS_SOFTC(d) (struct gpiobus_softc *) device_get_softc(d)
@@ -50,6 +56,9 @@
struct gpiobus_ivar
{
+#ifdef FDT
+ struct ofw_bus_devinfo ofw; /* FDT device info */
+#endif
uint32_t npins; /* pins total */
uint32_t *pins; /* pins map */
};
Index: dev/gpio/gpioc.c
===================================================================
--- dev/gpio/gpioc.c (revision 243614)
+++ dev/gpio/gpioc.c (working copy)
@@ -44,6 +44,13 @@
#include <sys/gpio.h>
#include "gpio_if.h"
+#include "opt_platform.h"
+
+#ifdef FDT
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#endif
+
#undef GPIOC_DEBUG
#ifdef GPIOC_DEBUG
#define dprintf printf
@@ -73,6 +80,11 @@
static int
gpioc_probe(device_t dev)
{
+
+#ifdef FDT
+ if (!ofw_bus_is_compatible(dev, "gpio-controller"))
+ return (ENXIO);
+#endif
device_set_desc(dev, "GPIO controller");
return (0);
}
Index: dev/gpio/gpioled.c
===================================================================
--- dev/gpio/gpioled.c (revision 243614)
+++ dev/gpio/gpioled.c (working copy)
@@ -43,11 +43,20 @@
#include <sys/gpio.h>
#include "gpiobus_if.h"
+#include "opt_platform.h"
+
+#ifdef FDT
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#endif
+
/*
* Only one pin for led
*/
#define GPIOLED_PIN 0
+#define GPIOLED_MAXBUF 32
+
#define GPIOLED_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
#define GPIOLED_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
#define GPIOLED_LOCK_INIT(_sc) \
@@ -85,6 +94,11 @@
static int
gpioled_probe(device_t dev)
{
+
+#ifdef FDT
+ if (!ofw_bus_is_compatible(dev, "gpioled"))
+ return (ENXIO);
+#endif
device_set_desc(dev, "GPIO led");
return (0);
}
@@ -92,16 +106,27 @@
static int
gpioled_attach(device_t dev)
{
+#ifdef FDT
+ phandle_t node;
+#endif
struct gpioled_softc *sc;
- const char *name;
+ char *name;
sc = device_get_softc(dev);
sc->sc_dev = dev;
sc->sc_busdev = device_get_parent(dev);
GPIOLED_LOCK_INIT(sc);
+
+#ifdef FDT
+ node = ofw_bus_get_node(dev);
+ name = malloc(GPIOLED_MAXBUF + 1, M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (OF_getprop(node, "label", name, GPIOLED_MAXBUF) == -1)
+ OF_getprop(node, "name", name, GPIOLED_MAXBUF);
+#else
if (resource_string_value(device_get_name(dev),
device_get_unit(dev), "name", &name))
name = NULL;
+#endif
GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, GPIOLED_PIN,
GPIO_PIN_OUTPUT);
@@ -109,6 +134,9 @@
sc->sc_leddev = led_create(gpioled_control, sc, name ? name :
device_get_nameunit(dev));
+#ifdef FDT
+ free(name, M_DEVBUF);
+#endif
return (0);
}
--Apple-Mail-16-531908476
Content-Disposition: attachment;
filename=bcm2835_gpio.c.fdt.diff
Content-Type: application/octet-stream;
name="bcm2835_gpio.c.fdt.diff"
Content-Transfer-Encoding: 7bit
--- arm/broadcom/bcm2835/bcm2835_gpio.c.orig 2012-12-03 15:39:23.762869715 -0200
+++ arm/broadcom/bcm2835/bcm2835_gpio.c 2012-12-04 16:22:40.133869246 -0200
@@ -689,9 +689,11 @@
bcm_gpio_attach(device_t dev)
{
struct bcm_gpio_softc *sc = device_get_softc(dev);
+ struct ofw_bus_devinfo *di_ofw;
+ device_t dev_child;
uint32_t func;
int i, j, rid;
- phandle_t gpio;
+ phandle_t child, gpio;
sc->sc_dev = dev;
@@ -747,8 +749,39 @@
bcm_gpio_sysctl_init(sc);
- device_add_child(dev, "gpioc", device_get_unit(dev));
- device_add_child(dev, "gpiobus", device_get_unit(dev));
+ /*
+ * Walkthrough our node and add direct subordinates as our children.
+ */
+ for (child = OF_child(gpio); child != 0; child = OF_peer(child)) {
+
+ /* Check and process 'status' property. */
+ if (!(fdt_is_enabled(child)))
+ continue;
+
+ if (!OF_hasprop(child, "compatible"))
+ continue;
+
+ di_ofw = malloc(sizeof(*di_ofw), M_DEVBUF, M_WAITOK | M_ZERO);
+
+ if (ofw_bus_gen_setup_devinfo(di_ofw, child) != 0) {
+ free(di_ofw, M_DEVBUF);
+ device_printf(dev, "could not set up devinfo\n");
+ continue;
+ }
+
+ /* Add newbus device for this FDT node */
+ dev_child = device_add_child(dev, NULL, -1);
+ if (dev_child == NULL) {
+ device_printf(dev, "could not add child: %s\n",
+ di_ofw->obd_name);
+ /* XXX should unmap */
+ ofw_bus_gen_destroy_devinfo(di_ofw);
+ free(di_ofw, M_DEVBUF);
+ continue;
+ }
+ device_set_ivars(dev_child, di_ofw);
+ }
+
return (bus_generic_attach(dev));
fail:
@@ -766,6 +799,13 @@
return (EBUSY);
}
+static const struct ofw_bus_devinfo *
+bcm_gpio_get_devinfo(device_t bus, device_t child)
+{
+
+ return (device_get_ivars(child));
+}
+
static device_method_t bcm_gpio_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, bcm_gpio_probe),
@@ -782,6 +822,14 @@
DEVMETHOD(gpio_pin_set, bcm_gpio_pin_set),
DEVMETHOD(gpio_pin_toggle, bcm_gpio_pin_toggle),
+ /* OFW bus interface */
+ DEVMETHOD(ofw_bus_get_devinfo, bcm_gpio_get_devinfo),
+ DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat),
+ DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model),
+ DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name),
+ DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node),
+ DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type),
+
DEVMETHOD_END
};
--Apple-Mail-16-531908476
Content-Disposition: attachment;
filename=bcm2835.dts.diff
Content-Type: application/octet-stream;
name="bcm2835.dts.diff"
Content-Transfer-Encoding: 7bit
Index: boot/fdt/dts/bcm2835-rpi-b.dts
===================================================================
--- boot/fdt/dts/bcm2835-rpi-b.dts (revision 243614)
+++ boot/fdt/dts/bcm2835-rpi-b.dts (working copy)
@@ -173,6 +173,21 @@
*/
broadcom,read-only = <46>, <47>, <48>, <49>, <50>, <51>, <52>, <53>;
+ gpioc {
+ compatible = "gpio-controller";
+ };
+
+ gpiobus {
+ compatible = "gpiobus";
+
+ /* Ok led */
+ led {
+ compatible = "gpioled";
+ label = "ok";
+ pins = <16>;
+ };
+ };
+
/* BSC0 */
pins_bsc0_a: bsc0_a {
broadcom,pins = <0>, <1>;
--Apple-Mail-16-531908476--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?BEB9A0F8-560B-4937-8707-653988A26D85>
