Add support for Lewisburg GPIO through P2SB

Obtained from:		Semihalf
Sponsored by:		Stormshield
Differential revision:	https://reviews.freebsd.org/D31269
This commit is contained in:
Arnaud Ysmal 2021-06-29 15:54:07 +02:00 committed by Wojciech Macek
parent 3daa8e165c
commit 3706af423f
8 changed files with 871 additions and 0 deletions

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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__ */

215
sys/dev/p2sb/p2sb.c Normal file
View File

@ -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);

11
sys/dev/p2sb/p2sb.h Normal file
View File

@ -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__ */

View File

@ -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}

View File

@ -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>