Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F115233455
D31269.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
23 KB
Referenced Files
None
Subscribers
None
D31269.diff
View Options
diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64
--- a/sys/conf/files.amd64
+++ b/sys/conf/files.amd64
@@ -363,6 +363,9 @@
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
--- /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.h b/sys/dev/p2sb/lewisburg_gpiocm.h
new file mode 100644
--- /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/lewisburg_gpiocm.c b/sys/dev/p2sb/lewisburg_gpiocm.c
new file mode 100644
--- /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/p2sb.h b/sys/dev/p2sb/p2sb.h
new file mode 100644
--- /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/dev/p2sb/p2sb.c b/sys/dev/p2sb/p2sb.c
new file mode 100644
--- /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/modules/Makefile b/sys/modules/Makefile
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -358,6 +358,7 @@
stge \
${_sume} \
${_superio} \
+ ${_p2sb} \
${_sym} \
${_syscons} \
sysvipc \
@@ -662,6 +663,7 @@
_speaker= speaker
_splash= splash
_sppp= sppp
+_p2sb= p2sb
_wbwd= wbwd
_aac= aac
@@ -755,6 +757,7 @@
_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
--- /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>
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Apr 22, 4:41 PM (10 h, 53 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17711040
Default Alt Text
D31269.diff (23 KB)
Attached To
Mode
D31269: Add support for Lewisburg GPIO through P2SB
Attached
Detach File
Event Timeline
Log In to Comment