svn commit: r326109 - in head/sys: conf dev/bhnd dev/bhnd/cores/chipc mips/conf modules/bhnd

Wojciech Macek wma at semihalf.com
Fri Nov 24 09:21:39 UTC 2017


Hi,

The patch breaks the build for ppc64. Could you please add missing
ofw_bus_if.h to the Makefile?

cc -isystem
/home/wma/ppc64-freebsd/obj/home/wma/ppc64-freebsd/powerpc.powerpc64/tmp/usr/include
-L/home/wma/ppc64-freebsd/obj/home/wma/ppc64-freebsd/powerpc.powerpc64/tmp/usr/lib
-B/home/wma/ppc64-freebsd/obj/home/wma/ppc64-freebsd/powerpc.powerpc64/tmp/usr/lib
--sysroot=/home/wma/ppc64-freebsd/obj/home/wma/ppc64-freebsd/powerpc.powerpc64/tmp
-B/home/wma/ppc64-freebsd/obj/home/wma/ppc64-freebsd/powerpc.powerpc64/tmp/usr/bin
-O2 -pipe  -fno-strict-aliasing -Werror -D_KERNEL -DKLD_MODULE -nostdinc
 -DHAVE_KERNEL_OPTION_HEADERS -include
/home/wma/ppc64-freebsd/obj/home/wma/ppc64-freebsd/powerpc.powerpc64/sys/GENERIC64/opt_global.h
-I. -I/home/wma/ppc64-freebsd/sys -fno-common -g -mlongcall
-fno-omit-frame-pointer
-I/home/wma/ppc64-freebsd/obj/home/wma/ppc64-freebsd/powerpc.powerpc64/sys/GENERIC64
 -MD  -MF.depend.chipc_gpio.o -MTchipc_gpio.o -mno-altivec -ffreestanding
-fwrapv -fstack-protector -gdwarf-2 -Wall -Wredundant-decls
-Wnested-externs -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith
-Winline -Wcast-qual -Wundef -Wno-pointer-sign -fformat-extensions
-Wmissing-include-dirs -fdiagnostics-show-option -Wno-unknown-pragmas
-Wno-uninitialized  -finline-limit=15000 -fms-extensions --param
inline-unit-growth=100 --param large-function-growth=1000 -msoft-float
-mcall-aixdesc  -std=iso9899:1999 -c
/home/wma/ppc64-freebsd/sys/dev/bhnd/cores/chipc/chipc_gpio.c -o
chipc_gpio.o
In file included from /home/wma/ppc64-freebsd/sys/dev/gpio/gpiobusvar.h:40,
                 from
/home/wma/ppc64-freebsd/sys/dev/bhnd/cores/chipc/chipc_gpio.c:48:
/home/wma/ppc64-freebsd/sys/dev/ofw/ofw_bus_subr.h:40:24: error:
ofw_bus_if.h: No such file or directory
cc1: warnings being treated as errors
In file included from /home/wma/ppc64-freebsd/sys/dev/gpio/gpiobusvar.h:40,
                 from
/home/wma/ppc64-freebsd/sys/dev/bhnd/cores/chipc/chipc_gpio.c:48:
/home/wma/ppc64-freebsd/sys/dev/ofw/ofw_bus_subr.h:71: warning: 'struct
ofw_bus_devinfo' declared inside parameter list
/home/wma/ppc64-freebsd/sys/dev/ofw/ofw_bus_subr.h:71: warning: its scope
is only this definition or declaration, which is probably not what you want
/home/wma/ppc64-freebsd/sys/dev/ofw/ofw_bus_subr.h:72: warning: 'struct
ofw_bus_devinfo' declared inside parameter list
/home/wma/ppc64-freebsd/sys/dev/ofw/ofw_bus_subr.h:74: error: expected '=',
',', ';', 'asm' or '__attribute__' before 'ofw_bus_gen_get_compat'
/home/wma/ppc64-freebsd/sys/dev/ofw/ofw_bus_subr.h:75: error: expected '=',
',', ';', 'asm' or '__attribute__' before 'ofw_bus_gen_get_model'
/home/wma/ppc64-freebsd/sys/dev/ofw/ofw_bus_subr.h:76: error: expected '=',
',', ';', 'asm' or '__attribute__' before 'ofw_bus_gen_get_name'
/home/wma/ppc64-freebsd/sys/dev/ofw/ofw_bus_subr.h:77: error: expected '=',
',', ';', 'asm' or '__attribute__' before 'ofw_bus_gen_get_node'
/home/wma/ppc64-freebsd/sys/dev/ofw/ofw_bus_subr.h:78: error: expected '=',
',', ';', 'asm' or '__attribute__' before 'ofw_bus_gen_get_type'
In file included from
/home/wma/ppc64-freebsd/sys/dev/bhnd/cores/chipc/chipc_gpio.c:48:
/home/wma/ppc64-freebsd/sys/dev/gpio/gpiobusvar.h:115: error: field
'opd_obdinfo' has incomplete type
*** [chipc_gpio.o] Error code 1

make[4]: stopped in /home/wma/ppc64-freebsd/sys/modules/bhnd
--- all_subdir_cardbus ---
--- cardbus.o ---
ctfconvert -L VERSION -g cardbus.o
A failure has been detected in another branch of the parallel make


Regards,
Wojtek

2017-11-23 0:10 GMT+01:00 Landon J. Fuller <landonf at freebsd.org>:

> Author: landonf
> Date: Wed Nov 22 23:10:20 2017
> New Revision: 326109
> URL: https://svnweb.freebsd.org/changeset/base/326109
>
> Log:
>   bhnd(4): Add a basic ChipCommon GPIO driver sufficient to support bwn(4)
>
>   The driver is functional on both BHND Wi-Fi adapters and MIPS SoCs, but
>   does not currently include support for features not required by bwn(4),
>   including GPIO interrupt handling.
>
>   Approved by:  adrian (mentor, implicit)
>   Sponsored by: The FreeBSD Foundation
>   Differential Revision:        https://reviews.freebsd.org/D12708
>
> Added:
>   head/sys/dev/bhnd/cores/chipc/chipc_gpio.c   (contents, props changed)
>   head/sys/dev/bhnd/cores/chipc/chipc_gpiovar.h   (contents, props
> changed)
> Modified:
>   head/sys/conf/files
>   head/sys/dev/bhnd/bhnd_types.h
>   head/sys/dev/bhnd/cores/chipc/chipc.c
>   head/sys/dev/bhnd/cores/chipc/chipc_subr.c
>   head/sys/dev/bhnd/cores/chipc/chipcreg.h
>   head/sys/mips/conf/BCM
>   head/sys/mips/conf/SENTRY5
>   head/sys/modules/bhnd/Makefile
>
> Modified: head/sys/conf/files
> ============================================================
> ==================
> --- head/sys/conf/files Wed Nov 22 22:04:27 2017        (r326108)
> +++ head/sys/conf/files Wed Nov 22 23:10:20 2017        (r326109)
> @@ -1246,6 +1246,7 @@ dev/bhnd/cores/chipc/bhnd_sprom_chipc.c   optional
> bhnd
>  dev/bhnd/cores/chipc/bhnd_pmu_chipc.c  optional bhnd
>  dev/bhnd/cores/chipc/chipc.c           optional bhnd
>  dev/bhnd/cores/chipc/chipc_cfi.c       optional bhnd cfi
> +dev/bhnd/cores/chipc/chipc_gpio.c      optional bhnd gpio
>  dev/bhnd/cores/chipc/chipc_slicer.c    optional bhnd cfi | bhnd spibus
>  dev/bhnd/cores/chipc/chipc_spi.c       optional bhnd spibus
>  dev/bhnd/cores/chipc/chipc_subr.c      optional bhnd
>
> Modified: head/sys/dev/bhnd/bhnd_types.h
> ============================================================
> ==================
> --- head/sys/dev/bhnd/bhnd_types.h      Wed Nov 22 22:04:27 2017
> (r326108)
> +++ head/sys/dev/bhnd/bhnd_types.h      Wed Nov 22 23:10:20 2017
> (r326109)
> @@ -75,6 +75,7 @@ typedef enum {
>         BHND_SERVICE_PWRCTL,            /**< legacy pwrctl service;
> implements the bhnd_pwrctl interface */
>         BHND_SERVICE_PMU,               /**< pmu service; implements the
> bhnd_pmu interface */
>         BHND_SERVICE_NVRAM,             /**< nvram service; implements the
> bhnd_nvram interface */
> +       BHND_SERVICE_GPIO,              /**< gpio service; implements the
> standard gpio interface */
>
>         BHND_SERVICE_ANY = 1000,        /**< match on any service type */
>  } bhnd_service_t;
>
> Modified: head/sys/dev/bhnd/cores/chipc/chipc.c
> ============================================================
> ==================
> --- head/sys/dev/bhnd/cores/chipc/chipc.c       Wed Nov 22 22:04:27 2017
>       (r326108)
> +++ head/sys/dev/bhnd/cores/chipc/chipc.c       Wed Nov 22 23:10:20 2017
>       (r326109)
> @@ -306,6 +306,20 @@ chipc_add_children(struct chipc_softc *sc)
>                 }
>         }
>
> +       /* GPIO */
> +       child = BUS_ADD_CHILD(sc->dev, 0, "gpio", 0);
> +       if (child == NULL) {
> +               device_printf(sc->dev, "failed to add gpio\n");
> +               return (ENXIO);
> +       }
> +
> +       error = chipc_set_mem_resource(sc, child, 0, 0, RM_MAX_END, 0, 0);
> +       if (error) {
> +               device_printf(sc->dev, "failed to set gpio memory
> resource: "
> +                   "%d\n", error);
> +               return (error);
> +       }
> +
>         /* All remaining devices are SoC-only */
>         if (bhnd_get_attach_type(sc->dev) != BHND_ATTACH_NATIVE)
>                 return (0);
> @@ -835,6 +849,25 @@ chipc_alloc_resource(device_t dev, device_t child, int
>         if ((cr = chipc_find_region(sc, start, end)) == NULL) {
>                 /* Resource requests outside our shared port regions can be
>                  * delegated to our parent. */
> +               rv = bus_generic_rl_alloc_resource(dev, child, type, rid,
> +                   start, end, count, flags);
> +               return (rv);
> +       }
> +
> +       /*
> +        * As a special case, children that map the complete ChipCommon
> register
> +        * block are delegated to our parent.
> +        *
> +        * The rman API does not support sharing resources that are not
> +        * identical in size; since we allocate subregions to various
> children,
> +        * any children that need to map the entire register block (e.g.
> because
> +        * they require access to discontiguous register ranges) must make
> the
> +        * allocation through our parent, where we hold a compatible
> +        * RF_SHAREABLE allocation.
> +        */
> +       if (cr == sc->core_region && cr->cr_addr == start &&
> +           cr->cr_end == end && cr->cr_count == count)
> +       {
>                 rv = bus_generic_rl_alloc_resource(dev, child, type, rid,
>                     start, end, count, flags);
>                 return (rv);
>
> Added: head/sys/dev/bhnd/cores/chipc/chipc_gpio.c
> ============================================================
> ==================
> --- /dev/null   00:00:00 1970   (empty, because file is newly added)
> +++ head/sys/dev/bhnd/cores/chipc/chipc_gpio.c  Wed Nov 22 23:10:20 2017
>       (r326109)
> @@ -0,0 +1,846 @@
> +/*-
> + * Copyright (c) 2017 The FreeBSD Foundation
> + * All rights reserved.
> + *
> + * This software was developed by Landon Fuller under sponsorship from
> + * the FreeBSD Foundation.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + *     notice, this list of conditions and the following disclaimer.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + *    notice, this list of conditions and the following disclaimer in the
> + *    documentation and/or other materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
> + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> PURPOSE
> + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> CONSEQUENTIAL
> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
> STRICT
> + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
> WAY
> + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + *
> + * $FreeBSD$
> + */
> +
> +#include <sys/cdefs.h>
> +__FBSDID("$FreeBSD$");
> +
> +#include <sys/param.h>
> +#include <sys/kernel.h>
> +#include <sys/bus.h>
> +#include <sys/gpio.h>
> +#include <sys/limits.h>
> +#include <sys/module.h>
> +
> +#include <machine/_inttypes.h>
> +#include <machine/bus.h>
> +#include <sys/rman.h>
> +#include <machine/resource.h>
> +
> +#include <dev/bhnd/bhnd.h>
> +#include <dev/gpio/gpiobusvar.h>
> +
> +#include "gpio_if.h"
> +
> +#include "bhnd_nvram_map.h"
> +
> +#include "chipcreg.h"
> +#include "chipc_gpiovar.h"
> +
> +/*
> + * ChipCommon GPIO driver
> + */
> +
> +static int                     chipc_gpio_check_flags(
> +                                   struct chipc_gpio_softc *sc,
> +                                   uint32_t pin_num, uint32_t flags,
> +                                   chipc_gpio_pin_mode *mode);
> +static int                     chipc_gpio_pin_update(
> +                                   struct chipc_gpio_softc *sc,
> +                                   struct chipc_gpio_update *update,
> +                                   uint32_t pin_num, uint32_t flags);
> +static int                     chipc_gpio_commit_update(
> +                                   struct chipc_gpio_softc *sc,
> +                                   struct chipc_gpio_update *update);
> +static chipc_gpio_pin_mode     chipc_gpio_pin_get_mode(
> +                                   struct chipc_gpio_softc *sc,
> +                                   uint32_t pin_num);
> +
> +
> +/* Debugging flags */
> +static u_long chipc_gpio_debug = 0;
> +TUNABLE_ULONG("hw.bhnd_chipc.gpio_debug", &chipc_gpio_debug);
> +
> +enum {
> +       /** Allow userspace GPIO access on bridged network (e.g. wi-fi)
> +         * adapters */
> +       CC_GPIO_DEBUG_ADAPTER_GPIOC = 1 << 0,
> +};
> +
> +#define        CC_GPIO_DEBUG(_type)    (CC_GPIO_DEBUG_ ## _type &
> chipc_gpio_debug)
> +
> +static struct bhnd_device_quirk chipc_gpio_quirks[];
> +
> +/* Supported parent core device identifiers */
> +static const struct bhnd_device chipc_gpio_devices[] = {
> +       BHND_DEVICE(BCM, CC, "Broadcom ChipCommon GPIO",
> chipc_gpio_quirks),
> +       BHND_DEVICE_END
> +};
> +
> +/* Device quirks table */
> +static struct bhnd_device_quirk chipc_gpio_quirks[] = {
> +       BHND_CORE_QUIRK (HWREV_LTE(10), CC_GPIO_QUIRK_NO_EVENTS),
> +       BHND_CORE_QUIRK (HWREV_LTE(15), CC_GPIO_QUIRK_NO_DCTIMER),
> +       BHND_CORE_QUIRK (HWREV_LTE(19), CC_GPIO_QUIRK_NO_PULLUPDOWN),
> +
> +       BHND_DEVICE_QUIRK_END
> +};
> +
> +static int
> +chipc_gpio_probe(device_t dev)
> +{
> +       const struct bhnd_device        *id;
> +       device_t                         chipc;
> +
> +       /* Look for compatible chipc parent */
> +       chipc = device_get_parent(dev);
> +       id = bhnd_device_lookup(chipc, chipc_gpio_devices,
> +           sizeof(chipc_gpio_devices[0]));
> +       if (id == NULL)
> +               return (ENXIO);
> +
> +       device_set_desc(dev, id->desc);
> +       return (BUS_PROBE_NOWILDCARD);
> +}
> +
> +static int
> +chipc_gpio_attach(device_t dev)
> +{
> +       struct chipc_gpio_softc *sc;
> +       device_t                 chipc;
> +       int                      error;
> +
> +       chipc = device_get_parent(dev);
> +
> +       sc = device_get_softc(dev);
> +       sc->dev = dev;
> +       sc->quirks = bhnd_device_quirks(chipc, chipc_gpio_devices,
> +           sizeof(chipc_gpio_devices[0]));
> +
> +       /* If this is a bridged wi-fi adapter, we don't want to support
> +        * userspace requests via gpioc(4) */
> +       if (bhnd_get_attach_type(chipc) == BHND_ATTACH_ADAPTER) {
> +               if (!CC_GPIO_DEBUG(ADAPTER_GPIOC))
> +                       sc->quirks |= CC_GPIO_QUIRK_NO_GPIOC;
> +       }
> +
> +       CC_GPIO_LOCK_INIT(sc);
> +
> +       sc->mem_rid = 0;
> +       sc->mem_res = bhnd_alloc_resource_any(dev, SYS_RES_MEMORY,
> &sc->mem_rid,
> +           RF_ACTIVE|RF_SHAREABLE);
> +       if (sc->mem_res == NULL) {
> +               device_printf(dev, "failed to allocate chipcommon
> registers\n");
> +               error = ENXIO;
> +               goto failed;
> +       }
> +
> +       /*
> +        * If hardware 'pulsate' support is available, set the timer
> duty-cycle
> +        * to either the NVRAM 'leddc' value if available, or the default
> duty
> +        * cycle.
> +        */
> +       if (!CC_GPIO_QUIRK(sc, NO_DCTIMER)) {
> +               uint32_t dctimerval;
> +
> +               error = bhnd_nvram_getvar_uint32(chipc, BHND_NVAR_LEDDC,
> +                   &dctimerval);
> +               if (error == ENOENT) {
> +                       /* Fall back on default duty cycle */
> +                       dctimerval = CHIPC_GPIOTIMERVAL_DEFAULT;
> +               } else if (error) {
> +                       device_printf(dev, "error reading %s from NVRAM:
> %d\n",
> +                           BHND_NVAR_LEDDC, error);
> +                       goto failed;
> +               }
> +
> +               CC_GPIO_WR4(sc, CHIPC_GPIOTIMERVAL, dctimerval);
> +       }
> +
> +       /* Attach gpioc/gpiobus */
> +       if (CC_GPIO_QUIRK(sc, NO_GPIOC)) {
> +               sc->gpiobus = NULL;
> +       } else {
> +               if ((sc->gpiobus = gpiobus_attach_bus(dev)) == NULL) {
> +                       device_printf(dev, "failed to attach gpiobus\n");
> +                       error = ENXIO;
> +                       goto failed;
> +               }
> +       }
> +
> +       /* Register as the bus GPIO provider */
> +       if ((error = bhnd_register_provider(dev, BHND_SERVICE_GPIO))) {
> +               device_printf(dev, "failed to register gpio with bus:
> %d\n",
> +                   error);
> +               goto failed;
> +       }
> +
> +       return (0);
> +
> +failed:
> +       device_delete_children(dev);
> +
> +       if (sc->mem_res != NULL) {
> +               bhnd_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid,
> +                   sc->mem_res);
> +       }
> +
> +       CC_GPIO_LOCK_DESTROY(sc);
> +
> +       return (error);
> +}
> +
> +static int
> +chipc_gpio_detach(device_t dev)
> +{
> +       struct chipc_gpio_softc *sc;
> +       int                      error;
> +
> +       sc = device_get_softc(dev);
> +
> +       if ((error = bus_generic_detach(dev)))
> +               return (error);
> +
> +       if ((error = bhnd_deregister_provider(dev, BHND_SERVICE_ANY)))
> +               return (error);
> +
> +       bhnd_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid,
> sc->mem_res);
> +       CC_GPIO_LOCK_DESTROY(sc);
> +
> +       return (0);
> +}
> +
> +static device_t
> +chipc_gpio_get_bus(device_t dev)
> +{
> +       struct chipc_gpio_softc *sc = device_get_softc(dev);
> +
> +       return (sc->gpiobus);
> +}
> +
> +static int
> +chipc_gpio_pin_max(device_t dev, int *maxpin)
> +{
> +       *maxpin = CC_GPIO_NPINS-1;
> +       return (0);
> +}
> +
> +static int
> +chipc_gpio_pin_set(device_t dev, uint32_t pin_num, uint32_t pin_value)
> +{
> +       struct chipc_gpio_softc *sc;
> +       bool                     pin_high;
> +       int                      error;
> +
> +       sc = device_get_softc(dev);
> +       error = 0;
> +
> +       if (!CC_GPIO_VALID_PIN(pin_num))
> +               return (EINVAL);
> +
> +       switch (pin_value) {
> +       case GPIO_PIN_HIGH:
> +               pin_high = true;
> +               break;
> +       case GPIO_PIN_LOW:
> +               pin_high = false;
> +               break;
> +       default:
> +               return (EINVAL);
> +       }
> +
> +       CC_GPIO_LOCK(sc);
> +
> +       switch (chipc_gpio_pin_get_mode(sc, pin_num)) {
> +       case CC_GPIO_PIN_INPUT:
> +       case CC_GPIO_PIN_TRISTATE:
> +               error = ENODEV;
> +               break;
> +
> +       case CC_GPIO_PIN_OUTPUT:
> +               CC_GPIO_WRFLAG(sc, pin_num, GPIOOUT, pin_high);
> +               break;
> +       }
> +
> +       CC_GPIO_UNLOCK(sc);
> +
> +       return (error);
> +}
> +
> +static int
> +chipc_gpio_pin_get(device_t dev, uint32_t pin_num, uint32_t *pin_value)
> +{
> +       struct chipc_gpio_softc *sc;
> +       bool                     pin_high;
> +
> +       if (!CC_GPIO_VALID_PIN(pin_num))
> +               return (EINVAL);
> +
> +       sc = device_get_softc(dev);
> +       pin_high = false;
> +
> +       CC_GPIO_LOCK(sc);
> +
> +       switch (chipc_gpio_pin_get_mode(sc, pin_num)) {
> +       case CC_GPIO_PIN_INPUT:
> +               pin_high = CC_GPIO_RDFLAG(sc, pin_num, GPIOIN);
> +               break;
> +
> +       case CC_GPIO_PIN_OUTPUT:
> +               pin_high = CC_GPIO_RDFLAG(sc, pin_num, GPIOOUT);
> +               break;
> +
> +       case CC_GPIO_PIN_TRISTATE:
> +               pin_high = false;
> +               break;
> +       }
> +
> +       CC_GPIO_UNLOCK(sc);
> +
> +       *pin_value = pin_high ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
> +
> +       return (0);
> +}
> +
> +static int
> +chipc_gpio_pin_toggle(device_t dev, uint32_t pin_num)
> +{
> +       struct chipc_gpio_softc *sc;
> +       bool                     pin_high;
> +       int                      error;
> +
> +       if (!CC_GPIO_VALID_PIN(pin_num))
> +               return (EINVAL);
> +
> +       sc = device_get_softc(dev);
> +       error = 0;
> +
> +       CC_GPIO_LOCK(sc);
> +
> +       switch (chipc_gpio_pin_get_mode(sc, pin_num)) {
> +       case CC_GPIO_PIN_INPUT:
> +       case CC_GPIO_PIN_TRISTATE:
> +               error = ENODEV;
> +               break;
> +
> +       case CC_GPIO_PIN_OUTPUT:
> +               pin_high = CC_GPIO_RDFLAG(sc, pin_num, GPIOOUT);
> +               CC_GPIO_WRFLAG(sc, pin_num, GPIOOUT, !pin_high);
> +               break;
> +       }
> +
> +       CC_GPIO_UNLOCK(sc);
> +
> +       return (error);
> +}
> +
> +static int
> +chipc_gpio_pin_getcaps(device_t dev, uint32_t pin_num, uint32_t *caps)
> +{
> +       struct chipc_gpio_softc *sc = device_get_softc(dev);
> +
> +       if (!CC_GPIO_VALID_PIN(pin_num))
> +               return (EINVAL);
> +
> +       *caps = (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE);
> +
> +       if (!CC_GPIO_QUIRK(sc, NO_PULLUPDOWN))
> +               *caps |= (GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN);
> +
> +       if (!CC_GPIO_QUIRK(sc, NO_DCTIMER))
> +               *caps |= GPIO_PIN_PULSATE;
> +
> +       return (0);
> +}
> +
> +static int
> +chipc_gpio_pin_getflags(device_t dev, uint32_t pin_num, uint32_t *flags)
> +{
> +       struct chipc_gpio_softc *sc = device_get_softc(dev);
> +
> +       if (!CC_GPIO_VALID_PIN(pin_num))
> +               return (EINVAL);
> +
> +       CC_GPIO_LOCK(sc);
> +
> +       switch (chipc_gpio_pin_get_mode(sc, pin_num)) {
> +       case CC_GPIO_PIN_INPUT:
> +               *flags = GPIO_PIN_INPUT;
> +
> +               if (!CC_GPIO_QUIRK(sc, NO_PULLUPDOWN)) {
> +                       if (CC_GPIO_RDFLAG(sc, pin_num, GPIOPU)) {
> +                               *flags |= GPIO_PIN_PULLUP;
> +                       } else if (CC_GPIO_RDFLAG(sc, pin_num, GPIOPD)) {
> +                               *flags |= GPIO_PIN_PULLDOWN;
> +                       }
> +               }
> +               break;
> +
> +       case CC_GPIO_PIN_OUTPUT:
> +               *flags = GPIO_PIN_OUTPUT;
> +
> +               if (!CC_GPIO_QUIRK(sc, NO_DCTIMER)) {
> +                       if (CC_GPIO_RDFLAG(sc, pin_num, GPIOTIMEROUTMASK))
> +                               *flags |= GPIO_PIN_PULSATE;
> +               }
> +
> +               break;
> +
> +       case CC_GPIO_PIN_TRISTATE:
> +               *flags = GPIO_PIN_TRISTATE|GPIO_PIN_OUTPUT;
> +               break;
> +       }
> +
> +       CC_GPIO_UNLOCK(sc);
> +
> +       return (0);
> +}
> +
> +static int
> +chipc_gpio_pin_getname(device_t dev, uint32_t pin_num, char *name)
> +{
> +       int ret;
> +
> +       if (!CC_GPIO_VALID_PIN(pin_num))
> +               return (EINVAL);
> +
> +       ret = snprintf(name, GPIOMAXNAME, "bhnd_gpio%02" PRIu32, pin_num);
> +
> +       if (ret < 0)
> +               return (ENXIO);
> +
> +       if (ret >= GPIOMAXNAME)
> +               return (ENOMEM);
> +
> +       return (0);
> +}
> +
> +static int
> +chipc_gpio_pin_setflags(device_t dev, uint32_t pin_num, uint32_t flags)
> +{
> +       struct chipc_gpio_softc         *sc;
> +       struct chipc_gpio_update         upd;
> +       int                              error;
> +
> +       sc = device_get_softc(dev);
> +
> +       if (!CC_GPIO_VALID_PIN(pin_num))
> +               return (EINVAL);
> +
> +       /* Produce an update descriptor */
> +       memset(&upd, 0, sizeof(upd));
> +       if ((error = chipc_gpio_pin_update(sc, &upd, pin_num, flags)))
> +               return (error);
> +
> +       /* Commit the update */
> +       CC_GPIO_LOCK(sc);
> +       error = chipc_gpio_commit_update(sc, &upd);
> +       CC_GPIO_UNLOCK(sc);
> +
> +       return (error);
> +}
> +
> +static int
> +chipc_gpio_pin_access_32(device_t dev, uint32_t first_pin, uint32_t
> clear_pins,
> +    uint32_t change_pins, uint32_t *orig_pins)
> +{
> +       struct chipc_gpio_softc         *sc;
> +       struct chipc_gpio_update         upd;
> +       uint32_t                         out, outen, ctrl;
> +       uint32_t                         num_pins;
> +       int                              error;
> +
> +       sc = device_get_softc(dev);
> +
> +       if (first_pin >= CC_GPIO_NPINS)
> +               return (EINVAL);
> +
> +       /* Determine the actual number of referenced pins */
> +       if (clear_pins == 0 && change_pins == 0) {
> +               num_pins = CC_GPIO_NPINS - first_pin;
> +       } else {
> +               int num_clear_pins, num_change_pins;
> +
> +               num_clear_pins = flsl((u_long)clear_pins);
> +               num_change_pins = flsl((u_long)change_pins);
> +               num_pins = MAX(num_clear_pins, num_change_pins);
> +       }
> +
> +       /* Validate the full pin range */
> +       if (!CC_GPIO_VALID_PINS(first_pin, num_pins))
> +               return (EINVAL);
> +
> +       /* Produce an update descriptor for all pins, relative to the
> current
> +        * pin state */
> +       CC_GPIO_LOCK(sc);
> +       memset(&upd, 0, sizeof(upd));
> +
> +       out = CC_GPIO_RD4(sc, CHIPC_GPIOOUT);
> +       outen = CC_GPIO_RD4(sc, CHIPC_GPIOOUTEN);
> +       ctrl = CC_GPIO_RD4(sc, CHIPC_GPIOCTRL);
> +
> +       for (uint32_t i = 0; i < num_pins; i++) {
> +               uint32_t        pin;
> +               bool            pin_high;
> +
> +               pin = first_pin + i;
> +
> +               /* The pin must be configured for output */
> +               if ((outen & (1 << pin)) == 0) {
> +                       CC_GPIO_UNLOCK(sc);
> +                       return (EINVAL);
> +               }
> +
> +               /* The pin must not tristated */
> +               if ((ctrl & (1 << pin)) != 0) {
> +                       CC_GPIO_UNLOCK(sc);
> +                       return (EINVAL);
> +               }
> +
> +               /* Fetch current state */
> +               if (out & (1 << pin)) {
> +                       pin_high = true;
> +               } else {
> +                       pin_high = false;
> +               }
> +
> +               /* Apply clear/toggle request */
> +               if (clear_pins & (1 << pin))
> +                       pin_high = false;
> +
> +               if (change_pins & (1 << pin))
> +                       pin_high = !pin_high;
> +
> +               /* Add to our update descriptor */
> +               CC_GPIO_UPDATE(&upd, pin, out, pin_high);
> +       }
> +
> +       /* Commit the update */
> +       error = chipc_gpio_commit_update(sc, &upd);
> +       CC_GPIO_UNLOCK(sc);
> +
> +       return (error);
> +}
> +
> +static int
> +chipc_gpio_pin_config_32(device_t dev, uint32_t first_pin, uint32_t
> num_pins,
> +    uint32_t *pin_flags)
> +{
> +       struct chipc_gpio_softc         *sc;
> +       struct chipc_gpio_update         upd;
> +       int                              error;
> +
> +       sc = device_get_softc(dev);
> +
> +       if (!CC_GPIO_VALID_PINS(first_pin, num_pins))
> +               return (EINVAL);
> +
> +       /* Produce an update descriptor */
> +       memset(&upd, 0, sizeof(upd));
> +       for (uint32_t i = 0; i < num_pins; i++) {
> +               uint32_t pin, flags;
> +
> +               pin = first_pin + i;
> +               flags = pin_flags[i];
> +
> +               /* As per the gpio_config_32 API documentation, any pins
> for
> +                * which neither GPIO_PIN_OUTPUT or GPIO_PIN_INPUT are set
> +                * should be ignored and left unmodified */
> +               if ((flags & (GPIO_PIN_OUTPUT|GPIO_PIN_INPUT)) == 0)
> +                       continue;
> +
> +               if ((error = chipc_gpio_pin_update(sc, &upd, pin, flags)))
> +                       return (error);
> +       }
> +
> +       /* Commit the update */
> +       CC_GPIO_LOCK(sc);
> +       error = chipc_gpio_commit_update(sc, &upd);
> +       CC_GPIO_UNLOCK(sc);
> +
> +       return (error);
> +}
> +
> +
> +/**
> + * Commit a single @p reg register update.
> + */
> +static void
> +chipc_gpio_commit_reg(struct chipc_gpio_softc *sc, bus_size_t offset,
> +    struct chipc_gpio_reg *reg)
> +{
> +       uint32_t value;
> +
> +       CC_GPIO_LOCK_ASSERT(sc, MA_OWNED);
> +
> +       if (reg->mask == 0)
> +               return;
> +
> +       value = bhnd_bus_read_4(sc->mem_res, offset);
> +       value &= ~reg->mask;
> +       value |= reg->value;
> +
> +       bhnd_bus_write_4(sc->mem_res, offset, value);
> +}
> +
> +/**
> + * Commit the set of GPIO register updates described by @p update.
> + */
> +static int
> +chipc_gpio_commit_update(struct chipc_gpio_softc *sc,
> +    struct chipc_gpio_update *update)
> +{
> +       CC_GPIO_LOCK_ASSERT(sc, MA_OWNED);
> +
> +       /* Commit pulldown/pullup before potentially disabling an output
> pin */
> +       chipc_gpio_commit_reg(sc, CHIPC_GPIOPD, &update->pulldown);
> +       chipc_gpio_commit_reg(sc, CHIPC_GPIOPU, &update->pullup);
> +
> +       /* Commit output settings before potentially enabling an output
> pin */
> +       chipc_gpio_commit_reg(sc, CHIPC_GPIOTIMEROUTMASK,
> +           &update->timeroutmask);
> +       chipc_gpio_commit_reg(sc, CHIPC_GPIOOUT, &update->out);
> +
> +       /* Commit input/output/tristate modes */
> +       chipc_gpio_commit_reg(sc, CHIPC_GPIOOUTEN, &update->outen);
> +       chipc_gpio_commit_reg(sc, CHIPC_GPIOCTRL, &update->ctrl);
> +
> +       return (0);
> +}
> +
> +/**
> + * Apply the changes described by @p flags for @p pin_num to the given @p
> update
> + * descriptor.
> + */
> +static int
> +chipc_gpio_pin_update(struct chipc_gpio_softc *sc,
> +    struct chipc_gpio_update *update, uint32_t pin_num, uint32_t flags)
> +{
> +       chipc_gpio_pin_mode     mode;
> +       int                     error;
> +
> +       if (!CC_GPIO_VALID_PIN(pin_num))
> +               return (EINVAL);
> +
> +       /* Verify flag compatibility and determine the pin mode */
> +       if ((error = chipc_gpio_check_flags(sc, pin_num, flags, &mode)))
> +               return (error);
> +
> +       /* Apply the mode-specific changes */
> +       switch (mode) {
> +       case CC_GPIO_PIN_INPUT:
> +               CC_GPIO_UPDATE(update, pin_num, pullup, false);
> +               CC_GPIO_UPDATE(update, pin_num, pulldown, false);
> +               CC_GPIO_UPDATE(update, pin_num, out, false);
> +               CC_GPIO_UPDATE(update, pin_num, outen, false);
> +               CC_GPIO_UPDATE(update, pin_num, timeroutmask, false);
> +               CC_GPIO_UPDATE(update, pin_num, ctrl, false);
> +
> +               if (flags & GPIO_PIN_PULLUP) {
> +                       CC_GPIO_UPDATE(update, pin_num, pullup, true);
> +               } else if (flags & GPIO_PIN_PULLDOWN) {
> +                       CC_GPIO_UPDATE(update, pin_num, pulldown, true);
> +               }
> +
> +               return (0);
> +
> +       case CC_GPIO_PIN_OUTPUT:
> +               CC_GPIO_UPDATE(update, pin_num, pullup, false);
> +               CC_GPIO_UPDATE(update, pin_num, pulldown, false);
> +               CC_GPIO_UPDATE(update, pin_num, outen, true);
> +               CC_GPIO_UPDATE(update, pin_num, timeroutmask, false);
> +               CC_GPIO_UPDATE(update, pin_num, ctrl, false);
> +
> +               if (flags & GPIO_PIN_PRESET_HIGH) {
> +                       CC_GPIO_UPDATE(update, pin_num, out, true);
> +               } else if (flags & GPIO_PIN_PRESET_LOW) {
> +                       CC_GPIO_UPDATE(update, pin_num, out, false);
> +               }
> +
> +               if (flags & GPIO_PIN_PULSATE)
> +                       CC_GPIO_UPDATE(update, pin_num, timeroutmask,
> true);
> +
> +               return (0);
> +
> +       case CC_GPIO_PIN_TRISTATE:
> +               CC_GPIO_UPDATE(update, pin_num, pullup, false);
> +               CC_GPIO_UPDATE(update, pin_num, pulldown, false);
> +               CC_GPIO_UPDATE(update, pin_num, out, false);
> +               CC_GPIO_UPDATE(update, pin_num, outen, false);
> +               CC_GPIO_UPDATE(update, pin_num, timeroutmask, false);
> +               CC_GPIO_UPDATE(update, pin_num, ctrl, true);
> +
> +               if (flags & GPIO_PIN_OUTPUT)
> +                       CC_GPIO_UPDATE(update, pin_num, outen, true);
> +
> +               return (0);
> +       }
> +
> +       device_printf(sc->dev, "unknown pin mode %d\n", mode);
> +       return (EINVAL);
> +}
> +
> +/**
> + * Verify that @p flags are valid for use with @p pin_num, and on success,
> + * return the pin mode described by @p flags in @p mode.
> + *
> + * @param      sc      GPIO driver instance state.
> + * @param      pin_num The pin number to configure.
> + * @param      flags   The pin flags to be validated.
> + * @param[out] mode    On success, will be populated with the GPIO pin
> mode
> + *                     defined by @p flags.
> + *
> + * @retval 0           success
> + * @retval EINVAL      if @p flags are invalid.
> + */
> +static int
> +chipc_gpio_check_flags(struct chipc_gpio_softc *sc, uint32_t pin_num,
> +    uint32_t flags, chipc_gpio_pin_mode *mode)
> +{
> +       uint32_t mode_flag, input_flag, output_flag;
> +
> +       CC_GPIO_ASSERT_VALID_PIN(sc, pin_num);
> +
> +       mode_flag = flags & (GPIO_PIN_OUTPUT | GPIO_PIN_INPUT |
> +           GPIO_PIN_TRISTATE);
> +       output_flag = flags & (GPIO_PIN_PRESET_HIGH | GPIO_PIN_PRESET_LOW
> +           | GPIO_PIN_PULSATE);
> +       input_flag = flags & (GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN);
> +
> +       switch (mode_flag) {
> +       case GPIO_PIN_OUTPUT:
> +               /* No input flag(s) should be set */
> +               if (input_flag != 0)
> +                       return (EINVAL);
> +
> +               /* Validate our output flag(s) */
> +               switch (output_flag) {
> +               case GPIO_PIN_PRESET_HIGH:
> +               case GPIO_PIN_PRESET_LOW:
> +               case (GPIO_PIN_PRESET_HIGH|GPIO_PIN_PULSATE):
> +               case (GPIO_PIN_PRESET_LOW|GPIO_PIN_PULSATE):
> +               case 0:
> +                       /* Check for unhandled flags */
> +                       if ((flags & ~(mode_flag | output_flag)) != 0)
> +                               return (EINVAL);
> +
> +                       *mode = CC_GPIO_PIN_OUTPUT;
> +                       return (0);
> +
> +               default:
> +                       /* Incompatible output flags */
> +                       return (EINVAL);
> +               }
> +
> +       case GPIO_PIN_INPUT:
> +               /* No output flag(s) should be set */
> +               if (output_flag != 0)
> +                       return (EINVAL);
> +
> +               /* Validate our input flag(s) */
> +               switch (input_flag) {
> +               case GPIO_PIN_PULLUP:
> +               case GPIO_PIN_PULLDOWN:
> +               case 0:
> +                       /* Check for unhandled flags */
> +                       if ((flags & ~(mode_flag | input_flag)) != 0)
> +                               return (EINVAL);
> +
> +                       *mode = CC_GPIO_PIN_INPUT;
> +                       return (0);
> +
> +               default:
> +                       /* Incompatible input flags */
> +                       return (EINVAL);
> +               }
> +
> +               break;
> +
> +       case (GPIO_PIN_TRISTATE|GPIO_PIN_OUTPUT):
> +       case GPIO_PIN_TRISTATE:
> +               /* No input or output flag(s) should be set */
> +               if (input_flag != 0 || output_flag != 0)
> +                       return (EINVAL);
> +
> +               /* Check for unhandled flags */
> +               if ((flags & ~mode_flag) != 0)
> +                       return (EINVAL);
> +
> +               *mode = CC_GPIO_PIN_TRISTATE;
> +               return (0);
> +
> +       default:
> +               /* Incompatible mode flags */
> +               return (EINVAL);
> +       }
> +}
> +
> +/**
> + * Return the current pin mode for @p pin_num.
> + *
> + * @param sc           GPIO driver instance state.
> + * @param pin_num      The pin number to query.
> + */
> +static chipc_gpio_pin_mode
> +chipc_gpio_pin_get_mode(struct chipc_gpio_softc *sc, uint32_t pin_num)
> +{
> +       CC_GPIO_LOCK_ASSERT(sc, MA_OWNED);
> +       CC_GPIO_ASSERT_VALID_PIN(sc, pin_num);
> +
> +       if (CC_GPIO_RDFLAG(sc, pin_num, GPIOCTRL)) {
> +               return (CC_GPIO_PIN_TRISTATE);
> +       } else if (CC_GPIO_RDFLAG(sc, pin_num, GPIOOUTEN)) {
> +               return (CC_GPIO_PIN_OUTPUT);
> +       } else {
> +               return (CC_GPIO_PIN_INPUT);
> +       }
> +}
> +
> +static device_method_t chipc_gpio_methods[] = {
> +       /* Device interface */
> +       DEVMETHOD(device_probe,         chipc_gpio_probe),
> +       DEVMETHOD(device_attach,        chipc_gpio_attach),
> +       DEVMETHOD(device_detach,        chipc_gpio_detach),
> +
> +       /* GPIO interface */
> +       DEVMETHOD(gpio_get_bus,         chipc_gpio_get_bus),
> +       DEVMETHOD(gpio_pin_max,         chipc_gpio_pin_max),
> +       DEVMETHOD(gpio_pin_getname,     chipc_gpio_pin_getname),
> +       DEVMETHOD(gpio_pin_getflags,    chipc_gpio_pin_getflags),
> +       DEVMETHOD(gpio_pin_getcaps,     chipc_gpio_pin_getcaps),
> +       DEVMETHOD(gpio_pin_setflags,    chipc_gpio_pin_setflags),
> +       DEVMETHOD(gpio_pin_get,         chipc_gpio_pin_get),
> +       DEVMETHOD(gpio_pin_set,         chipc_gpio_pin_set),
> +       DEVMETHOD(gpio_pin_toggle,      chipc_gpio_pin_toggle),
> +       DEVMETHOD(gpio_pin_access_32,   chipc_gpio_pin_access_32),
> +       DEVMETHOD(gpio_pin_config_32,   chipc_gpio_pin_config_32),
> +
> +       DEVMETHOD_END
> +};
> +
> +static devclass_t gpio_devclass;
> +
> +DEFINE_CLASS_0(gpio, chipc_gpio_driver, chipc_gpio_methods, sizeof(struct
> chipc_gpio_softc));
> +EARLY_DRIVER_MODULE(chipc_gpio, bhnd_chipc, chipc_gpio_driver,
> +    gpio_devclass, NULL, NULL, BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE);
> +
> +MODULE_DEPEND(chipc_gpio, bhnd, 1, 1, 1);
> +MODULE_DEPEND(chipc_gpio, gpiobus, 1, 1, 1);
> +MODULE_VERSION(chipc_gpio, 1);
>
> Added: head/sys/dev/bhnd/cores/chipc/chipc_gpiovar.h
> ============================================================
> ==================
> --- /dev/null   00:00:00 1970   (empty, because file is newly added)
> +++ head/sys/dev/bhnd/cores/chipc/chipc_gpiovar.h       Wed Nov 22
> 23:10:20 2017        (r326109)
> @@ -0,0 +1,161 @@
> +/*-
> + * Copyright (c) 2017 The FreeBSD Foundation
> + * All rights reserved.
> + *
> + * This software was developed by Landon Fuller under sponsorship from
> + * the FreeBSD Foundation.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + *     notice, this list of conditions and the following disclaimer.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + *    notice, this list of conditions and the following disclaimer in the
> + *    documentation and/or other materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
> + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> PURPOSE
> + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> CONSEQUENTIAL
> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
> STRICT
> + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
> WAY
> + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + *
> + * $FreeBSD$
> + */
> +
> +#ifndef _BHND_CORES_CHIPC_CHIPC_GPIOVAR_H_
> +#define _BHND_CORES_CHIPC_CHIPC_GPIOVAR_H_
> +
> +#include <sys/param.h>
> +#include <sys/bus.h>
> +
> +#include <sys/lock.h>
> +#include <sys/mutex.h>
> +
> +#include <dev/bhnd/bhnd.h>
> +
> +/**
> + * ChipCommon GPIO device quirks.
> + */
> +enum {
> +       /**
> +        * No GPIO event support.
> +        *
> +        * The CHIPC_GPIOEVENT, CHIPC_GPIOEVENT_INTM, and
> +        * CHIPC_GPIOEVENT_INTPOLARITY registers are not available.
> +        */
> +       CC_GPIO_QUIRK_NO_EVENTS         = (1<<0),
> +
> +       /**
> +        * No GPIO duty-cycle timer support.
> +        *
> +        * The CHIPC_GPIOTIMERVAL and CHIPC_GPIOTIMEROUTMASK registers are
> not
> +        * available.
> +        */
> +       CC_GPIO_QUIRK_NO_DCTIMER        = (1<<1),
> +
> +       /**
> +        * No GPIO pull-up/pull-down configuration support.
> +        *
> +        * The CHIPC_GPIOPU and CHIPC_GPIOPD registers are not available.
> +        */
> +       CC_GPIO_QUIRK_NO_PULLUPDOWN     = (1<<2),
> +
> +       /**
> +        * Do not attach a child gpioc(4) device.
> +        *
> +        * This is primarily intended for use on bridged Wi-Fi adapters,
> where
> +        * userspace modification of GPIO pin configuration could introduce
> +        * significant undesirable behavior.
> +        */
> +       CC_GPIO_QUIRK_NO_GPIOC          = (1<<3),
> +};
> +
>
> *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
>
>


More information about the svn-src-all mailing list