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 /* defines used in kernel.h */ +#include +#include +#include +#include /* types used in module initialization */ +#include /* cdevsw struct */ +#include /* uio struct */ +#include +#include /* structs, prototypes for pci bus stuff and DEVMETHOD macros! */ +#include + +#include +#include +#include + +#include + +#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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#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<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<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