The branch main has been updated by wma:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=3706af423ff257540dfe88bcb91fb0ab54e60946

commit 3706af423ff257540dfe88bcb91fb0ab54e60946
Author:     Arnaud Ysmal <arnaud.ys...@stormshield.eu>
AuthorDate: 2021-06-29 13:54:07 +0000
Commit:     Wojciech Macek <w...@freebsd.org>
CommitDate: 2021-08-26 09:00:39 +0000

    Add support for Lewisburg GPIO through P2SB
    
    Obtained from:          Semihalf
    Sponsored by:           Stormshield
    Differential revision:  https://reviews.freebsd.org/D31269
---
 sys/conf/files.amd64            |   3 +
 sys/dev/p2sb/lewisburg_gpio.c   | 269 ++++++++++++++++++++++++++++++
 sys/dev/p2sb/lewisburg_gpiocm.c | 351 ++++++++++++++++++++++++++++++++++++++++
 sys/dev/p2sb/lewisburg_gpiocm.h |  12 ++
 sys/dev/p2sb/p2sb.c             | 215 ++++++++++++++++++++++++
 sys/dev/p2sb/p2sb.h             |  11 ++
 sys/modules/Makefile            |   3 +
 sys/modules/p2sb/Makefile       |   7 +
 8 files changed, 871 insertions(+)

diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64
index d58cf7927206..1bcfaa05d0ba 100644
--- a/sys/conf/files.amd64
+++ b/sys/conf/files.amd64
@@ -363,6 +363,9 @@ dev/viawd/viawd.c           optional        viawd
 dev/vmd/vmd.c                  optional        vmd
 dev/vmd/vmd_bus.c              optional        vmd_bus
 dev/wbwd/wbwd.c                        optional        wbwd
+dev/p2sb/p2sb.c                        optional        p2sb pci
+dev/p2sb/lewisburg_gpiocm.c    optional        lbggpiocm p2sb
+dev/p2sb/lewisburg_gpio.c      optional        lbggpio lbggpiocm
 isa/syscons_isa.c              optional        sc
 isa/vga_isa.c                  optional        vga
 kern/imgact_aout.c             optional compat_aout
diff --git a/sys/dev/p2sb/lewisburg_gpio.c b/sys/dev/p2sb/lewisburg_gpio.c
new file mode 100644
index 000000000000..d0b08520eb87
--- /dev/null
+++ b/sys/dev/p2sb/lewisburg_gpio.c
@@ -0,0 +1,269 @@
+/*-
+ * Copyright (c) 2018 Stormshield
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+#include <sys/param.h>         /* defines used in kernel.h */
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>                /* types used in module initialization 
*/
+#include <sys/conf.h>          /* cdevsw struct */
+#include <sys/uio.h>           /* uio struct */
+#include <sys/malloc.h>
+#include <sys/bus.h>           /* structs, prototypes for pci bus stuff and 
DEVMETHOD macros! */
+#include <sys/gpio.h>
+
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <dev/gpio/gpiobusvar.h>
+
+#include "gpio_if.h"
+
+#include "lewisburg_gpiocm.h"
+
+#define P2SB_GROUP_GPIO_MAX_PINS 24
+struct lbggpio_softc
+{
+       device_t                sc_busdev;
+       int groupid;
+       int pins_off;
+       int npins;
+       char grpname;
+       struct gpio_pin gpio_setup[P2SB_GROUP_GPIO_MAX_PINS];
+};
+
+static device_t
+lbggpio_get_bus(device_t dev)
+{
+       struct lbggpio_softc *sc;
+
+       sc = device_get_softc(dev);
+
+       return (sc->sc_busdev);
+}
+
+static int
+lbggpio_pin_max(device_t dev, int *maxpin)
+{
+       struct lbggpio_softc *sc;
+
+       if (maxpin == NULL)
+               return (EINVAL);
+
+       sc = device_get_softc(dev);
+
+       *maxpin = sc->npins - 1;
+
+       return (0);
+}
+
+static int
+lbggpio_pin_getname(device_t dev, uint32_t pin, char *name)
+{
+       struct lbggpio_softc *sc = device_get_softc(dev);
+
+       if (name == NULL)
+               return (EINVAL);
+
+       if (pin >= sc->npins)
+               return (EINVAL);
+
+       strlcpy(name, sc->gpio_setup[pin].gp_name, GPIOMAXNAME);
+
+       return (0);
+}
+
+static int
+lbggpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
+{
+       struct lbggpio_softc *sc = device_get_softc(dev);
+
+       if (flags == NULL)
+               return (EINVAL);
+
+       if (pin >= sc->npins)
+               return (EINVAL);
+
+       *flags = sc->gpio_setup[pin].gp_flags;
+
+       return (0);
+}
+
+static int
+lbggpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
+{
+       struct lbggpio_softc *sc = device_get_softc(dev);
+
+       if (caps == NULL)
+               return (EINVAL);
+
+       if (pin >= sc->npins)
+               return (EINVAL);
+
+       *caps = sc->gpio_setup[pin].gp_caps;
+
+       return (0);
+}
+
+static int
+lbggpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
+{
+       struct lbggpio_softc *sc = device_get_softc(dev);
+
+       if (pin >= sc->npins)
+               return (EINVAL);
+
+       /* Check for unwanted flags. */
+       if ((flags & sc->gpio_setup[pin].gp_caps) != flags)
+               return (EINVAL);
+
+       lbggpiocm_pin_setflags(device_get_parent(dev), dev, pin, flags);
+       sc->gpio_setup[pin].gp_flags = flags;
+
+       return (0);
+}
+
+static int
+lbggpio_pin_get(device_t dev, uint32_t pin, uint32_t *value)
+{
+       struct lbggpio_softc *sc = device_get_softc(dev);
+
+       if (value == NULL)
+               return (EINVAL);
+
+       if (pin >= sc->npins)
+               return (EINVAL);
+
+       return (lbggpiocm_pin_get(device_get_parent(dev), dev, pin, value));
+}
+
+static int
+lbggpio_pin_set(device_t dev, uint32_t pin, uint32_t value)
+{
+       struct lbggpio_softc *sc = device_get_softc(dev);
+
+       if (pin >= sc->npins)
+               return (EINVAL);
+
+       return (lbggpiocm_pin_set(device_get_parent(dev), dev, pin, value));
+}
+
+static int
+lbggpio_pin_toggle(device_t dev, uint32_t pin)
+{
+       struct lbggpio_softc *sc = device_get_softc(dev);
+
+       if (pin >= sc->npins)
+               return (EINVAL);
+
+       return (lbggpiocm_pin_toggle(device_get_parent(dev), dev, pin));
+}
+
+static int
+lbggpio_probe(device_t dev)
+{
+       struct lbggpio_softc *sc = device_get_softc(dev);
+       /* X is a placeholder for the actual one letter group name. */
+       static char desc[] = "LewisBurg GPIO Group X";
+
+       sc->npins = lbggpiocm_get_group_npins(device_get_parent(dev), dev);
+       sc->grpname = lbggpiocm_get_group_name(device_get_parent(dev), dev);
+       if (sc->npins <= 0)
+               return (ENXIO);
+
+       desc[sizeof(desc)-2] = sc->grpname;
+       device_set_desc_copy(dev, desc);
+       return (BUS_PROBE_DEFAULT);
+}
+
+static int
+lbggpio_attach(device_t dev)
+{
+       uint32_t i;
+       struct lbggpio_softc *sc;
+
+       sc = device_get_softc(dev);
+       /* GPIO config */
+       for (i = 0; i < sc->npins; ++i) {
+               sc->gpio_setup[i].gp_pin = i;
+               snprintf(sc->gpio_setup[i].gp_name,
+                   sizeof(sc->gpio_setup[i].gp_name),
+                   "GPIO %c%u", sc->grpname, i);
+               sc->gpio_setup[i].gp_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
+       }
+
+       /* support gpio */
+       sc->sc_busdev = gpiobus_attach_bus(dev);
+       if (sc->sc_busdev == NULL)
+               return (ENXIO);
+
+       return (0);
+}
+
+static int
+lbggpio_detach(device_t dev)
+{
+       struct lbggpio_softc *sc;
+
+       sc = device_get_softc(dev);
+
+       if (sc->sc_busdev)
+               gpiobus_detach_bus(dev);
+
+       return (0);
+}
+
+static device_method_t lbggpio_methods[] = {
+       /* Device interface */
+       DEVMETHOD(device_probe,         lbggpio_probe),
+       DEVMETHOD(device_attach,        lbggpio_attach),
+       DEVMETHOD(device_detach,        lbggpio_detach),
+
+       /* GPIO protocol */
+       DEVMETHOD(gpio_get_bus,         lbggpio_get_bus),
+       DEVMETHOD(gpio_pin_max,         lbggpio_pin_max),
+       DEVMETHOD(gpio_pin_getcaps,     lbggpio_pin_getcaps),
+       DEVMETHOD(gpio_pin_getflags,    lbggpio_pin_getflags),
+       DEVMETHOD(gpio_pin_setflags,    lbggpio_pin_setflags),
+       DEVMETHOD(gpio_pin_getname,     lbggpio_pin_getname),
+       DEVMETHOD(gpio_pin_set,         lbggpio_pin_set),
+       DEVMETHOD(gpio_pin_get,         lbggpio_pin_get),
+       DEVMETHOD(gpio_pin_toggle,      lbggpio_pin_toggle),
+
+       DEVMETHOD_END
+};
+
+static driver_t lbggpio_driver = {
+       "gpio",
+       lbggpio_methods,
+       sizeof(struct lbggpio_softc)
+};
+
+static devclass_t lbggpio_devclass;
+
+DRIVER_MODULE(lbggpio, lbggpiocm, lbggpio_driver, lbggpio_devclass, NULL, 
NULL);
+MODULE_DEPEND(lbggpio, gpiobus, 1, 1, 1);
diff --git a/sys/dev/p2sb/lewisburg_gpiocm.c b/sys/dev/p2sb/lewisburg_gpiocm.c
new file mode 100644
index 000000000000..4a046a50aed4
--- /dev/null
+++ b/sys/dev/p2sb/lewisburg_gpiocm.c
@@ -0,0 +1,351 @@
+/*-
+ * Copyright (c) 2018 Stormshield
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/bus.h>
+#include <sys/gpio.h>
+
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include "gpio_if.h"
+
+#include "lewisburg_gpiocm.h"
+#include "p2sb.h"
+
+#define PADBAR 0x00c
+
+#define PADCFG0_GPIORXDIS      (1<<9)
+#define PADCFG0_GPIOTXDIS      (1<<8)
+#define PADCFG0_GPIORXSTATE    (1<<1)
+#define PADCFG0_GPIOTXSTATE    (1<<0)
+
+#define MAX_PAD_PER_GROUP      24
+
+#define LBGGPIOCM_READ(sc, reg) p2sb_port_read_4(sc->p2sb, sc->port, reg)
+#define LBGGPIOCM_WRITE(sc, reg, val) \
+       p2sb_port_write_4(sc->p2sb, sc->port, reg, val)
+#define LBGGPIOCM_LOCK(sc) p2sb_lock(sc->p2sb)
+#define LBGGPIOCM_UNLOCK(sc) p2sb_unlock(sc->p2sb)
+
+struct lbggroup {
+       int groupid;
+       int npins;
+       int pins_off;
+       device_t dev;
+       char grpname;
+};
+
+struct lbgcommunity {
+       uint8_t npins;
+       const char *name;
+       uint32_t pad_off;
+       struct lbggroup groups[3];
+       int ngroups;
+       const char *grpnames;
+};
+#define LBG_COMMUNITY(n, np, g) \
+{ \
+       .name = n, \
+       .npins = np, \
+       .grpnames = g, \
+}
+
+static struct lbgcommunity lbg_communities[] = {
+       LBG_COMMUNITY("LewisBurg GPIO Community 0", 72, "ABF"),
+       LBG_COMMUNITY("LewisBurg GPIO Community 1", 61, "CDE"),
+       LBG_COMMUNITY("LewisBurg GPIO Community 2", 0, ""),
+       LBG_COMMUNITY("LewisBurg GPIO Community 3", 12, "I"),
+       LBG_COMMUNITY("LewisBurg GPIO Community 4", 36, "JK"),
+       LBG_COMMUNITY("LewisBurg GPIO Community 5", 66, "GHL"),
+};
+
+struct lbggpiocm_softc
+{
+       int port;
+       device_t p2sb;
+       struct lbgcommunity *community;
+};
+
+static struct lbggroup *lbggpiocm_get_group(struct lbggpiocm_softc *sc,
+    device_t child);
+
+static __inline struct lbggroup *
+lbggpiocm_get_group(struct lbggpiocm_softc *sc, device_t child)
+{
+       int i;
+
+       for (i = 0; i < sc->community->ngroups; ++i)
+               if (sc->community->groups[i].dev == child)
+                       return (&sc->community->groups[i]);
+       return (NULL);
+}
+
+
+static __inline uint32_t
+lbggpiocm_getpad(struct lbggpiocm_softc *sc, uint32_t pin)
+{
+
+       if (pin >= sc->community->npins)
+               return (0);
+
+       return (sc->community->pad_off + 2 * 4 * pin);
+}
+
+int
+lbggpiocm_get_group_npins(device_t dev, device_t child)
+{
+       struct lbggpiocm_softc *sc = device_get_softc(dev);
+       struct lbggroup *group;
+
+       group = lbggpiocm_get_group(sc, child);
+       if (group != NULL)
+               return (group->npins);
+       return (-1);
+}
+
+char
+lbggpiocm_get_group_name(device_t dev, device_t child)
+{
+       struct lbggpiocm_softc *sc = device_get_softc(dev);
+       struct lbggroup *group;
+
+       group = lbggpiocm_get_group(sc, child);
+       if (group != NULL)
+               return (group->grpname);
+       return ('\0');
+}
+
+static int
+lbggpiocm_pin2cpin(struct lbggpiocm_softc *sc, device_t child, uint32_t pin)
+{
+       struct lbggroup *group;
+
+       group = lbggpiocm_get_group(sc, child);
+       if (group != NULL)
+               return (pin + group->pins_off);
+       return (-1);
+}
+
+int
+lbggpiocm_pin_setflags(device_t dev, device_t child, uint32_t pin, uint32_t 
flags)
+{
+       struct lbggpiocm_softc *sc = device_get_softc(dev);
+       uint32_t padreg, padval;
+       int rpin;
+
+       if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) ==
+           (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT))
+               return (EINVAL);
+
+       if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) == 0)
+               return (EINVAL);
+
+       rpin = lbggpiocm_pin2cpin(sc, child, pin);
+       if (rpin < 0)
+               return (EINVAL);
+
+       padreg = lbggpiocm_getpad(sc, rpin);
+
+       LBGGPIOCM_LOCK(sc);
+       padval = LBGGPIOCM_READ(sc, padreg);
+
+       if (flags & GPIO_PIN_INPUT) {
+               padval &= ~PADCFG0_GPIORXDIS;
+               padval |= PADCFG0_GPIOTXDIS;
+       } else if (flags & GPIO_PIN_OUTPUT) {
+               padval &= ~PADCFG0_GPIOTXDIS;
+               padval |= PADCFG0_GPIORXDIS;
+       }
+
+       LBGGPIOCM_WRITE(sc, padreg, padval);
+       LBGGPIOCM_UNLOCK(sc);
+
+       return (0);
+}
+
+int
+lbggpiocm_pin_get(device_t dev, device_t child, uint32_t pin, uint32_t *value)
+{
+       struct lbggpiocm_softc *sc = device_get_softc(dev);
+       uint32_t padreg, val;
+       int rpin;
+
+       if (value == NULL)
+               return (EINVAL);
+
+       rpin = lbggpiocm_pin2cpin(sc, child, pin);
+       if (rpin < 0)
+               return (EINVAL);
+
+       padreg = lbggpiocm_getpad(sc, rpin);
+
+       LBGGPIOCM_LOCK(sc);
+       val = LBGGPIOCM_READ(sc, padreg);
+       LBGGPIOCM_UNLOCK(sc);
+
+       if (!(val & PADCFG0_GPIOTXDIS))
+               *value = !!(val & PADCFG0_GPIOTXSTATE);
+       else
+               *value = !!(val & PADCFG0_GPIORXSTATE);
+
+       return (0);
+}
+
+int
+lbggpiocm_pin_set(device_t dev, device_t child, uint32_t pin, uint32_t value)
+{
+       struct lbggpiocm_softc *sc = device_get_softc(dev);
+       uint32_t padreg, padcfg;
+       int rpin;
+
+       rpin = lbggpiocm_pin2cpin(sc, child, pin);
+       if (rpin < 0)
+               return (EINVAL);
+
+       padreg = lbggpiocm_getpad(sc, rpin);
+
+       LBGGPIOCM_LOCK(sc);
+
+       padcfg = LBGGPIOCM_READ(sc, padreg);
+       if (value)
+               padcfg |= PADCFG0_GPIOTXSTATE;
+       else
+               padcfg &= ~PADCFG0_GPIOTXSTATE;
+       LBGGPIOCM_WRITE(sc, padreg, padcfg);
+
+       LBGGPIOCM_UNLOCK(sc);
+
+       return (0);
+}
+
+int
+lbggpiocm_pin_toggle(device_t dev, device_t child, uint32_t pin)
+{
+       struct lbggpiocm_softc *sc = device_get_softc(dev);
+       uint32_t padreg, padcfg;
+       int rpin;
+
+       rpin = lbggpiocm_pin2cpin(sc, child, pin);
+       if (rpin < 0)
+               return (EINVAL);
+
+       padreg = lbggpiocm_getpad(sc, rpin);
+
+       LBGGPIOCM_LOCK(sc);
+       padcfg = LBGGPIOCM_READ(sc, padreg);
+       padcfg ^= PADCFG0_GPIOTXSTATE;
+       LBGGPIOCM_WRITE(sc, padreg, padcfg);
+
+       LBGGPIOCM_UNLOCK(sc);
+
+       return (0);
+}
+
+static int
+lbggpiocm_probe(device_t dev)
+{
+       struct lbggpiocm_softc *sc = device_get_softc(dev);
+       int unit;
+
+       sc->p2sb = device_get_parent(dev);
+       unit = device_get_unit(dev);
+       KASSERT(unit < nitems(lbg_communities), ("Wrong number of devices or 
communities"));
+       sc->port = p2sb_get_port(sc->p2sb, unit);
+       sc->community = &lbg_communities[unit];
+       if (sc->port < 0)
+               return (ENXIO);
+
+       device_set_desc(dev, sc->community->name);
+       return (BUS_PROBE_DEFAULT);
+}
+
+static int
+lbggpiocm_attach(device_t dev)
+{
+       uint32_t npins;
+       struct lbggpiocm_softc *sc;
+       struct lbggroup *group;
+       int i;
+
+       sc = device_get_softc(dev);
+       if (sc->community->npins == 0)
+               return (ENXIO);
+
+       LBGGPIOCM_LOCK(sc);
+       sc->community->pad_off = LBGGPIOCM_READ(sc, PADBAR);
+       LBGGPIOCM_UNLOCK(sc);
+
+       npins = sc->community->npins;
+       for (i = 0; i < nitems(sc->community->groups) && npins > 0; ++i) {
+               group = &sc->community->groups[i];
+
+               group->groupid = i;
+               group->grpname = sc->community->grpnames[i];
+               group->pins_off = i * MAX_PAD_PER_GROUP;
+               group->npins = npins < MAX_PAD_PER_GROUP ? npins :
+                       MAX_PAD_PER_GROUP;
+               npins -= group->npins;
+               group->dev = device_add_child(dev, "gpio", -1);
+       }
+       sc->community->ngroups = i;
+       return (bus_generic_attach(dev));
+}
+
+static int
+lbggpiocm_detach(device_t dev)
+{
+       int error;
+
+       error = device_delete_children(dev);
+       if (error)
+               return (error);
+
+       return (bus_generic_detach(dev));
+}
+
+static device_method_t lbggpiocm_methods[] = {
+       /* Device interface */
+       DEVMETHOD(device_probe,         lbggpiocm_probe),
+       DEVMETHOD(device_attach,        lbggpiocm_attach),
+       DEVMETHOD(device_detach,        lbggpiocm_detach),
+
+       DEVMETHOD_END
+};
+
+static driver_t lbggpiocm_driver = {
+       "lbggpiocm",
+       lbggpiocm_methods,
+       sizeof(struct lbggpiocm_softc)
+};
+static devclass_t lbggpiocm_devclass;
+DRIVER_MODULE(lbggpiocm, p2sb, lbggpiocm_driver, lbggpiocm_devclass, NULL, 
NULL);
diff --git a/sys/dev/p2sb/lewisburg_gpiocm.h b/sys/dev/p2sb/lewisburg_gpiocm.h
new file mode 100644
index 000000000000..7fcbf919949b
--- /dev/null
+++ b/sys/dev/p2sb/lewisburg_gpiocm.h
@@ -0,0 +1,12 @@
+#ifndef __LEWISBURG_GPIOCM_H__
+#define __LEWISBURG_GPIOCM_H__
+
+int lbggpiocm_get_group_npins(device_t dev, device_t child);
+char lbggpiocm_get_group_name(device_t dev, device_t child);
+
+int lbggpiocm_pin_setflags(device_t, device_t, uint32_t, uint32_t);
+int lbggpiocm_pin_get(device_t, device_t, uint32_t, uint32_t *);
+int lbggpiocm_pin_set(device_t, device_t, uint32_t, uint32_t);
+int lbggpiocm_pin_toggle(device_t, device_t, uint32_t);
+
+#endif /* __LEWISBURG_GPIOCM_H__ */
diff --git a/sys/dev/p2sb/p2sb.c b/sys/dev/p2sb/p2sb.c
new file mode 100644
index 000000000000..80836cbb2f59
--- /dev/null
+++ b/sys/dev/p2sb/p2sb.c
@@ -0,0 +1,215 @@
+/*-
+ * Copyright (c) 2018 Stormshield
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+/*
+ * Implementation of Primary to Sideband bridge (P2SB), the documentation is 
available here :
+ * 
https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/c620-series-chipset-datasheet.pdf
+ * section 36.9 P2SB Bridge.
+ * This device exposes a 16MB memory block, this block is composed of 256 64KB 
blocks called ports.
+ * The indexes of this array (target port ID) can be found on the Table 36-10 
of the documentation.
+ */
+
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/bus.h>
+
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+
+#include "p2sb.h"
+
+#define PCI_PRODUCT_LEWISBURG_P2SB 0xa1a08086
+
+#define P2SB_PORT2ADDRESS_SHIFT 16
+#define P2SB_PORT_ADDRESS(port) ((uint32_t)port << P2SB_PORT2ADDRESS_SHIFT)
+
+static const uint8_t lbg_communities[] = {
+       0xAF, 0xAE, 0xAD, 0xAC, 0xAB, 0x11
+};
+
+/* The softc holds our per-instance data. */
+struct p2sb_softc {
+       device_t        dev;
+       int rid;
+       struct resource *res;
+       struct intel_community *communities;
+       int ncommunities;
+       struct mtx mutex;
+};
+
+int
+p2sb_get_port(device_t dev, int unit)
+{
+
+       if (unit >= nitems(lbg_communities))
+               return (EINVAL);
+       return (lbg_communities[unit]);
+}
+
+uint32_t
+p2sb_port_read_4(device_t dev, uint8_t port, uint32_t reg)
+{
+       struct p2sb_softc *sc;
+
+       KASSERT(reg < (1<<P2SB_PORT2ADDRESS_SHIFT), ("register out of port"));
+       sc = device_get_softc(dev);
+       return (bus_read_4(sc->res, P2SB_PORT_ADDRESS(port) + reg));
+}
+
+void
+p2sb_port_write_4(device_t dev, uint8_t port, uint32_t reg, uint32_t val)
+{
+       struct p2sb_softc *sc;
+
+       KASSERT(reg < (1<<P2SB_PORT2ADDRESS_SHIFT), ("register out of port"));
+       sc = device_get_softc(dev);
+       bus_write_4(sc->res, P2SB_PORT_ADDRESS(port) + reg, val);
+}
+
+void
+p2sb_lock(device_t dev)
+{
+       struct p2sb_softc *sc;
+
+       sc = device_get_softc(dev);
+       mtx_lock_spin(&sc->mutex);
+}
+
+void
+p2sb_unlock(device_t dev)
+{
+       struct p2sb_softc *sc;
+
+       sc = device_get_softc(dev);
+       mtx_unlock_spin(&sc->mutex);
+}
+
+
+static int
+p2sb_probe(device_t dev)
+{
+
+       if (pci_get_devid(dev) == PCI_PRODUCT_LEWISBURG_P2SB) {
+               device_set_desc(dev, "Lewisburg P2SB");
+               return (BUS_PROBE_DEFAULT);
+       }
+       return (ENXIO);
+}
+
+/* Attach function is only called if the probe is successful. */
+
+static int
+p2sb_attach(device_t dev)
+{
+       struct p2sb_softc *sc;
+       int i;
+
+       sc = device_get_softc(dev);
+       sc->dev = dev;
+       sc->rid = PCIR_BAR(0);
+       sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid, 
RF_ACTIVE);
+       if (sc->res == NULL) {
+               device_printf(dev, "Could not allocate memory.\n");
+               return (ENXIO);
+       }
+       mtx_init(&sc->mutex, device_get_nameunit(dev), NULL, MTX_SPIN);
+       for (i = 0; i < nitems(lbg_communities); ++i)
+               device_add_child(dev, "lbggpiocm", i);
+
+       return (bus_generic_attach(dev));
+}
+
+/* Detach device. */
+
+static int
+p2sb_detach(device_t dev)
+{
+       struct p2sb_softc *sc;
+
+       /* Teardown the state in our softc created in our attach routine. */
+       device_delete_children(dev);
+       sc = device_get_softc(dev);
+       mtx_destroy(&sc->mutex);
+       if (sc->res != NULL)
+               bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res);
+       return (0);
+}
+
+/* Called during system shutdown after sync. */
+
+static int
+p2sb_shutdown(device_t dev)
+{
+
+       return (0);
+}
+
+/*
+ * Device suspend routine.
+ */
+static int
+p2sb_suspend(device_t dev)
+{
+
+       return (0);
+}
+
+/*
+ * Device resume routine.
+ */
+static int
+p2sb_resume(device_t dev)
+{
+
+       return (0);
+}
+
+static device_method_t p2sb_methods[] = {
+       /* Device interface */
+       DEVMETHOD(device_probe,         p2sb_probe),
+       DEVMETHOD(device_attach,        p2sb_attach),
+       DEVMETHOD(device_detach,        p2sb_detach),
+       DEVMETHOD(device_shutdown,      p2sb_shutdown),
+       DEVMETHOD(device_suspend,       p2sb_suspend),
+       DEVMETHOD(device_resume,        p2sb_resume),
+
+       DEVMETHOD_END
+};
+
+static devclass_t p2sb_devclass;
+
+DEFINE_CLASS_0(p2sb, p2sb_driver, p2sb_methods, sizeof(struct p2sb_softc));
+DRIVER_MODULE(p2sb, pci, p2sb_driver, p2sb_devclass, 0, 0);
diff --git a/sys/dev/p2sb/p2sb.h b/sys/dev/p2sb/p2sb.h
new file mode 100644
index 000000000000..7c060a02fcf9
--- /dev/null
+++ b/sys/dev/p2sb/p2sb.h
@@ -0,0 +1,11 @@
+#ifndef __P2SB_H__
+#define __P2SB_H__
+
+void p2sb_lock(device_t dev);
+void p2sb_unlock(device_t dev);
+
+uint32_t p2sb_port_read_4(device_t dev, uint8_t port, uint32_t reg);
+void p2sb_port_write_4(device_t dev, uint8_t port, uint32_t reg, uint32_t val);
+int p2sb_get_port(device_t dev, int unit);
+
+#endif /* __P2SB_H__ */
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index 7ef3c5a477ce..585e2bdc80ca 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -358,6 +358,7 @@ SUBDIR=     \
        stge \
        ${_sume} \
        ${_superio} \
+       ${_p2sb} \
        ${_sym} \
        ${_syscons} \
        sysvipc \
@@ -662,6 +663,7 @@ _safe=              safe
 _speaker=      speaker
 _splash=       splash
 _sppp=         sppp
+_p2sb=         p2sb
 _wbwd=         wbwd
 
 _aac=          aac
@@ -755,6 +757,7 @@ _sfxge=             sfxge
 _sgx=          sgx
 _sgx_linux=    sgx_linux
 _smartpqi=     smartpqi
+_p2sb=         p2sb
 
 .if ${MK_BHYVE} != "no" || defined(ALL_MODULES)
 .if ${KERN_OPTS:MSMP}
diff --git a/sys/modules/p2sb/Makefile b/sys/modules/p2sb/Makefile
new file mode 100644
index 000000000000..8f4d604f73d5
--- /dev/null
+++ b/sys/modules/p2sb/Makefile
@@ -0,0 +1,7 @@
+.PATH: ${.CURDIR}/../../dev/p2sb
+
+KMOD= p2sb
+SRCS= p2sb.c lewisburg_gpio.c lewisburg_gpiocm.c
+SRCS+= device_if.h bus_if.h pci_if.h gpio_if.h
+
+.include <bsd.kmod.mk>
_______________________________________________
dev-commits-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-all
To unsubscribe, send any mail to "dev-commits-src-all-unsubscr...@freebsd.org"

Reply via email to