Author: loos Date: Tue Nov 18 01:38:39 2014 New Revision: 274638 URL: https://svnweb.freebsd.org/changeset/base/274638
Log: Add basic interrupt management code to gpiobus and ofw_gpiobus. This is the general support to allow the use of GPIO pins as interrupt sources for direct gpiobus children. The use of GPIO pins as generic interrupt sources (for an ethernet driver for example) will only be possible when arm/intrng is complete. Then, most of this code will need to be rewritten, but it works for now, is better than what we have and will allow further developments. Tested on: ar71xx (RSPRO), am335x (BBB), bcm2835 (Raspberry pi) Differential Revision: https://reviews.freebsd.org/D999 Reviewed by: rpaulo Modified: head/sys/dev/gpio/gpiobus.c head/sys/dev/gpio/gpiobusvar.h head/sys/dev/gpio/ofw_gpiobus.c Modified: head/sys/dev/gpio/gpiobus.c ============================================================================== --- head/sys/dev/gpio/gpiobus.c Mon Nov 17 22:22:16 2014 (r274637) +++ head/sys/dev/gpio/gpiobus.c Tue Nov 18 01:38:39 2014 (r274638) @@ -38,6 +38,13 @@ __FBSDID("$FreeBSD$"); #include "gpiobus_if.h" +#undef GPIOBUS_DEBUG +#ifdef GPIOBUS_DEBUG +#define dprintf printf +#else +#define dprintf(x, arg...) +#endif + static int gpiobus_parse_pins(struct gpiobus_softc *, device_t, int); static int gpiobus_probe(device_t); static int gpiobus_attach(device_t); @@ -105,6 +112,11 @@ gpiobus_init_softc(device_t dev) sc = GPIOBUS_SOFTC(dev); sc->sc_busdev = dev; sc->sc_dev = device_get_parent(dev); + sc->sc_intr_rman.rm_type = RMAN_ARRAY; + sc->sc_intr_rman.rm_descr = "GPIO Interrupts"; + if (rman_init(&sc->sc_intr_rman) != 0 || + rman_manage_region(&sc->sc_intr_rman, 0, ~0) != 0) + panic("%s: failed to set up rman.", __func__); if (GPIO_PIN_MAX(sc->sc_dev, &sc->sc_npins) != 0) return (ENXIO); @@ -267,6 +279,7 @@ gpiobus_print_child(device_t dev, device retval += bus_print_child_header(dev, child); retval += printf(" at pin(s) "); gpiobus_print_pins(devi); + resource_list_print_type(&devi->rl, "irq", SYS_RES_IRQ, "%ld"); retval += bus_print_child_footer(dev, child); return (retval); @@ -304,7 +317,9 @@ gpiobus_add_child(device_t dev, u_int or device_delete_child(dev, child); return (0); } + resource_list_init(&devi->rl); device_set_ivars(child, devi); + return (child); } @@ -314,14 +329,103 @@ gpiobus_hinted_child(device_t bus, const struct gpiobus_softc *sc = GPIOBUS_SOFTC(bus); struct gpiobus_ivar *devi; device_t child; - int pins; - + int irq, pins; child = BUS_ADD_CHILD(bus, 0, dname, dunit); devi = GPIOBUS_IVAR(child); resource_int_value(dname, dunit, "pins", &pins); if (gpiobus_parse_pins(sc, child, pins)) device_delete_child(bus, child); + if (resource_int_value(dname, dunit, "irq", &irq) == 0) { + if (bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1) != 0) + device_printf(bus, + "warning: bus_set_resource() failed\n"); + } +} + +static int +gpiobus_set_resource(device_t dev, device_t child, int type, int rid, + u_long start, u_long count) +{ + struct gpiobus_ivar *devi; + struct resource_list_entry *rle; + + dprintf("%s: entry (%p, %p, %d, %d, %p, %ld)\n", + __func__, dev, child, type, rid, (void *)(intptr_t)start, count); + devi = GPIOBUS_IVAR(child); + rle = resource_list_add(&devi->rl, type, rid, start, + start + count - 1, count); + if (rle == NULL) + return (ENXIO); + + return (0); +} + +static struct resource * +gpiobus_alloc_resource(device_t bus, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + struct gpiobus_softc *sc; + struct resource *rv; + struct resource_list *rl; + struct resource_list_entry *rle; + int isdefault; + + if (type != SYS_RES_IRQ) + return (NULL); + isdefault = (start == 0UL && end == ~0UL && count == 1); + rle = NULL; + if (isdefault) { + rl = BUS_GET_RESOURCE_LIST(bus, child); + if (rl == NULL) + return (NULL); + rle = resource_list_find(rl, type, *rid); + if (rle == NULL) + return (NULL); + if (rle->res != NULL) + panic("%s: resource entry is busy", __func__); + start = rle->start; + count = rle->count; + end = rle->end; + } + sc = device_get_softc(bus); + rv = rman_reserve_resource(&sc->sc_intr_rman, start, end, count, flags, + child); + if (rv == NULL) + return (NULL); + rman_set_rid(rv, *rid); + if ((flags & RF_ACTIVE) != 0 && + bus_activate_resource(child, type, *rid, rv) != 0) { + rman_release_resource(rv); + return (NULL); + } + + return (rv); +} + +static int +gpiobus_release_resource(device_t bus __unused, device_t child, int type, + int rid, struct resource *r) +{ + int error; + + if (rman_get_flags(r) & RF_ACTIVE) { + error = bus_deactivate_resource(child, type, rid, r); + if (error) + return (error); + } + + return (rman_release_resource(r)); +} + +static struct resource_list * +gpiobus_get_resource_list(device_t bus __unused, device_t child) +{ + struct gpiobus_ivar *ivar; + + ivar = GPIOBUS_IVAR(child); + + return (&ivar->rl); } static int @@ -450,6 +554,15 @@ static device_method_t gpiobus_methods[] DEVMETHOD(device_resume, gpiobus_resume), /* Bus interface */ + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_config_intr, bus_generic_config_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + DEVMETHOD(bus_set_resource, gpiobus_set_resource), + DEVMETHOD(bus_alloc_resource, gpiobus_alloc_resource), + DEVMETHOD(bus_release_resource, gpiobus_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_get_resource_list, gpiobus_get_resource_list), DEVMETHOD(bus_add_child, gpiobus_add_child), DEVMETHOD(bus_print_child, gpiobus_print_child), DEVMETHOD(bus_child_pnpinfo_str, gpiobus_child_pnpinfo_str), Modified: head/sys/dev/gpio/gpiobusvar.h ============================================================================== --- head/sys/dev/gpio/gpiobusvar.h Mon Nov 17 22:22:16 2014 (r274637) +++ head/sys/dev/gpio/gpiobusvar.h Tue Nov 18 01:38:39 2014 (r274638) @@ -34,6 +34,7 @@ #include <sys/lock.h> #include <sys/mutex.h> +#include <sys/rman.h> #ifdef FDT #include <dev/ofw/ofw_bus_subr.h> @@ -62,6 +63,7 @@ struct gpiobus_softc { struct mtx sc_mtx; /* bus mutex */ + struct rman sc_intr_rman; /* isr resources */ device_t sc_busdev; /* bus device */ device_t sc_owner; /* bus owner */ device_t sc_dev; /* driver device */ @@ -71,6 +73,7 @@ struct gpiobus_softc struct gpiobus_ivar { + struct resource_list rl; /* isr resource list */ uint32_t npins; /* pins total */ uint32_t *flags; /* pins flags */ uint32_t *pins; /* pins map */ Modified: head/sys/dev/gpio/ofw_gpiobus.c ============================================================================== --- head/sys/dev/gpio/ofw_gpiobus.c Mon Nov 17 22:22:16 2014 (r274637) +++ head/sys/dev/gpio/ofw_gpiobus.c Tue Nov 18 01:38:39 2014 (r274638) @@ -238,6 +238,13 @@ ofw_gpiobus_setup_devinfo(device_t dev, free(dinfo, M_DEVBUF); return (NULL); } + /* And now the interrupt resources. */ + resource_list_init(&dinfo->opd_dinfo.rl); + if (ofw_bus_intr_to_rl(dev, node, &dinfo->opd_dinfo.rl) != 0) { + ofw_bus_gen_destroy_devinfo(&dinfo->opd_obdinfo); + free(dinfo, M_DEVBUF); + return (NULL); + } return (dinfo); } @@ -246,6 +253,7 @@ static void ofw_gpiobus_destroy_devinfo(struct ofw_gpiobus_devinfo *dinfo) { + resource_list_free(&dinfo->opd_dinfo.rl); ofw_bus_gen_destroy_devinfo(&dinfo->opd_obdinfo); free(dinfo, M_DEVBUF); } @@ -326,6 +334,8 @@ ofw_gpiobus_print_child(device_t dev, de retval += bus_print_child_header(dev, child); retval += printf(" at pin(s) "); gpiobus_print_pins(&devi->opd_dinfo); + resource_list_print_type(&devi->opd_dinfo.rl, "irq", SYS_RES_IRQ, + "%ld"); retval += bus_print_child_footer(dev, child); return (retval); _______________________________________________ svn-src-head@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-head To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"