[bhnd] Finish bhnd(4) PCI/PCIe-G1 hostb support.

Now that we've got access to SPROM and can access board identification,
this implements all known remaining hardware work-arounds for the bhnd(4)
PCI and PCIe-G1 cores operating endpoint mode.

Additionally, this adds an initial set of skeleton PCIe-G2 hostb and pcib
drivers, required by fullmac and newer softmac devices.

Submitted by:	Landon Fuller <landonf@landonf.org>
Differential Revision:	https://reviews.freebsd.org/D6377
This commit is contained in:
Adrian Chadd 2016-05-17 06:52:53 +00:00
parent 32f8bbf8cd
commit 8ef24a0d4b
26 changed files with 1745 additions and 201 deletions

View file

@ -1142,6 +1142,9 @@ dev/bhnd/cores/chipc/bhnd_chipc_if.m optional bhndbus | bhnd
dev/bhnd/cores/pci/bhnd_pci.c optional bhndbus pci | bhnd pci
dev/bhnd/cores/pci/bhnd_pci_hostb.c optional bhndbus pci | bhndb pci
dev/bhnd/cores/pci/bhnd_pcib.c optional bhnd_pcib bhnd pci
dev/bhnd/cores/pcie2/bhnd_pcie2.c optional bhndbus pci | bhnd pci
dev/bhnd/cores/pcie2/bhnd_pcie2_hostb.c optional bhndbus pci | bhndb pci
dev/bhnd/cores/pcie2/bhnd_pcie2b.c optional bhnd_pcie2b bhnd pci
dev/bhnd/nvram/bhnd_nvram_if.m optional bhndbus | bhnd
dev/bhnd/nvram/bhnd_sprom.c optional bhndbus | bhnd
dev/bhnd/nvram/nvram_subr.c optional bhndbus | bhnd

View file

@ -318,8 +318,8 @@ struct bhnd_chip_match {
.match_bvendor = 1, .board_vendor = _vend
/** Set the required board type within a bhnd_chip_match instance */
#define BHND_CHIP_BT(_btype) \
.match_btype = 1, .board_type = BHND_BOARD_BCM ## _btype
#define BHND_CHIP_BTYPE(_btype) \
.match_btype = 1, .board_type = BHND_BOARD_ ## _btype
/** Set the required SROM revision range within a bhnd_chip_match instance */
#define BHND_CHIP_SROMREV(_rev) \
@ -331,7 +331,7 @@ struct bhnd_chip_match {
/** Set the required board vendor and type within a bhnd_chip_match instance */
#define BHND_CHIP_BVT(_vend, _type) \
BHND_CHIP_BVEND(_vend), BHND_CHIP_BTYPE(_type)
BHND_CHIP_BVENDOR(_vend), BHND_CHIP_BTYPE(_type)
/** Set the required board vendor, type, and revision within a bhnd_chip_match
* instance */
@ -429,6 +429,9 @@ device_t bhnd_match_child(device_t dev,
device_t bhnd_find_child(device_t dev,
bhnd_devclass_t class, int unit);
device_t bhnd_find_bridge_root(device_t dev,
devclass_t bus_class);
const struct bhnd_core_info *bhnd_match_core(
const struct bhnd_core_info *cores,
u_int num_cores,

View file

@ -26,8 +26,6 @@
#ifndef _BHND_BHND_IDS_H_
#define _BHND_BHND_IDS_H_
/*
* JEDEC JEP-106 Core Vendor IDs
*
@ -851,12 +849,12 @@
#define BHND_BOARD_BU4785 0x0478
/* 4321 boards */
#define BHND_BOARD_BU4321 0x046b
#define BHND_BOARD_BU4321E 0x047c
#define BHND_BOARD_MP4321 0x046c
#define BHND_BOARD_CB2_4321 0x046d
#define BHND_BOARD_CB2_4321_AG 0x0066
#define BHND_BOARD_MC4321 0x046e
#define BHND_BOARD_BCM4321BU 0x046b
#define BHND_BOARD_BCM4321BUE 0x047c
#define BHND_BOARD_BCM4321MP 0x046c
#define BHND_BOARD_BCM4321CB2 0x046d
#define BHND_BOARD_BCM4321CB2_AG 0x0066
#define BHND_BOARD_BCM4321MC 0x046e
/* 4328 boards */
#define BHND_BOARD_BU4328 0x0481

View file

@ -349,6 +349,56 @@ done:
return match;
}
/**
* Walk up the bhnd device hierarchy to locate the root device
* to which the bhndb bridge is attached.
*
* This can be used from within bhnd host bridge drivers to locate the
* actual upstream host device.
*
* @param dev A bhnd device.
* @param bus_class The expected bus (e.g. "pci") to which the bridge root
* should be attached.
*
* @retval device_t if a matching parent device is found.
* @retval NULL @p dev is not attached via a bhndb bus
* @retval NULL no parent device is attached via @p bus_class.
*/
device_t
bhnd_find_bridge_root(device_t dev, devclass_t bus_class)
{
devclass_t bhndb_class;
device_t parent;
KASSERT(device_get_devclass(device_get_parent(dev)) == bhnd_devclass,
("%s not a bhnd device", device_get_nameunit(dev)));
bhndb_class = devclass_find("bhndb");
/* Walk the device tree until we hit a bridge */
parent = dev;
while ((parent = device_get_parent(parent)) != NULL) {
if (device_get_devclass(parent) == bhndb_class)
break;
}
/* No bridge? */
if (parent == NULL)
return (NULL);
/* Search for a parent attached to the expected bus class */
while ((parent = device_get_parent(parent)) != NULL) {
device_t bus;
bus = device_get_parent(parent);
if (bus != NULL && device_get_devclass(bus) == bus_class)
return (parent);
}
/* Not found */
return (NULL);
}
/**
* Find the first core in @p cores that matches @p desc.
*

View file

@ -37,9 +37,10 @@ __FBSDID("$FreeBSD$");
* bus (e.g. bcma or siba) via a Broadcom PCI core configured in end-point
* mode.
*
* This driver handles all host-level PCI interactions with a PCI/PCIe bridge
* core operating in endpoint mode. On the bridged bhnd bus, the PCI core
* device will be managed by a bhnd_pci_hostb driver.
* This driver handles all initial generic host-level PCI interactions with a
* PCI/PCIe bridge core operating in endpoint mode. Once the bridged bhnd(4)
* bus has been enumerated, this driver works in tandem with a core-specific
* bhnd_pci_hostb driver to manage the PCI core.
*/
#include <sys/param.h>
@ -482,6 +483,35 @@ bhndb_pci_populate_board_info(device_t dev, device_t child,
sc = device_get_softc(dev);
/*
* On a subset of Apple BCM4360 modules, always prefer the
* PCI subdevice to the SPROM-supplied boardtype.
*
* TODO:
*
* Broadcom's own drivers implement this override, and then later use
* the remapped BCM4360 board type to determine the required
* board-specific workarounds.
*
* Without access to this hardware, it's unclear why this mapping
* is done, and we must do the same. If we can survey the hardware
* in question, it may be possible to replace this behavior with
* explicit references to the SPROM-supplied boardtype(s) in our
* quirk definitions.
*/
if (pci_get_subvendor(sc->parent) == PCI_VENDOR_APPLE) {
switch (info->board_type) {
case BHND_BOARD_BCM94360X29C:
case BHND_BOARD_BCM94360X29CP2:
case BHND_BOARD_BCM94360X51:
case BHND_BOARD_BCM94360X51P2:
info->board_type = 0; /* allow override below */
break;
default:
break;
}
}
/* If NVRAM did not supply vendor/type info, provide the PCI
* subvendor/subdevice values. */
if (info->board_vendor == 0)
@ -560,10 +590,6 @@ bhndb_disable_pci_clocks(struct bhndb_pci_softc *sc)
if (sc->pci_devclass != BHND_DEVCLASS_PCI)
return (0);
// TODO: Check board flags for BFL2_XTALBUFOUTEN?
// TODO: Check PCI core revision?
// TODO: Switch to 'slow' clock?
/* Fetch current config */
gpio_out = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUT, 4);
gpio_en = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, 4);
@ -601,6 +627,7 @@ DEFINE_CLASS_1(bhndb, bhndb_pci_driver, bhndb_pci_methods,
MODULE_VERSION(bhndb_pci, 1);
MODULE_DEPEND(bhndb_pci, bhnd_pci_hostb, 1, 1, 1);
MODULE_DEPEND(bhndb_pci, bhnd_pcie2_hostb, 1, 1, 1);
MODULE_DEPEND(bhndb_pci, pci, 1, 1, 1);
MODULE_DEPEND(bhndb_pci, bhndb, 1, 1, 1);
MODULE_DEPEND(bhndb_pci, bhnd, 1, 1, 1);

View file

@ -29,13 +29,13 @@
*
* = MAJOR CORE REVISIONS =
*
* There have been four revisions to the BAR0/BAR1 memory mappings used
* There have been four revisions to the BAR0 memory mappings used
* in BHND PCI/PCIE bridge cores:
*
* == PCI_V0 ==
* Applies to:
* - PCI (cid=0x804, revision <= 12)
* BAR size: 8KB
* BAR0 size: 8KB
* Address Map:
* [offset+ size] type description
* [0x0000+0x1000] dynamic mapped backplane address space (window 0).
@ -46,7 +46,7 @@
* Applies to:
* - PCI (cid=0x804, revision >= 13)
* - PCIE (cid=0x820) with ChipCommon (revision <= 31)
* BAR size: 16KB
* BAR0 size: 16KB
* Address Map:
* [offset+ size] type description
* [0x0000+0x1000] dynamic mapped backplane address space (window 0).
@ -57,7 +57,7 @@
* == PCI_V2 ==
* Applies to:
* - PCIE (cid=0x820) with ChipCommon (revision >= 32)
* BAR size: 16KB
* BAR0 size: 16KB
* Address Map:
* [offset+ size] type description
* [0x0000+0x1000] dynamic mapped backplane address space (window 0).
@ -68,7 +68,7 @@
* == PCI_V3 ==
* Applies to:
* - PCIE Gen 2 (cid=0x83c)
* BAR size: 32KB?
* BAR0 size: 32KB
* Address Map:
* [offset+ size] type description
* [0x0000+0x1000] dynamic mapped backplane address space (window 0).
@ -76,6 +76,12 @@
* [0x2000+0x1000] fixed pci/pcie core registers
* [0x3000+0x1000] fixed chipcommon core registers
* [???]
* BAR1 size: varies
* Address Map:
* [offset+ size] type description
* [0x0000+0x????] fixed ARM tightly-coupled memory (TCM).
* While fullmac chipsets provided a fixed
* 4KB mapping, newer devices will vary.
*
* = MINOR CORE REVISIONS =
*
@ -86,28 +92,6 @@
* == PCI/PCIE Cores Revision >= 14 ==
* - Mapped the clock CSR into the PCI config space. Refer to
* BHND_PCI_CLK_CTL_ST
*
* = Hardware Bugs =
* == BAR1 ==
*
* The BHND PCI(e) cores hypothetically support an additional memory mapping
* of the backplane address space via BAR1, but this appears to be subject
* to a hardware bug in which BAR1 is initially configured with a 4 byte
* length.
*
* A work-around for this bug may be possible by writing to the PCI core's
* BAR1 config register (0x4e0), but this requires further research -- I've
* found three sources for information on the BAR1 PCI core configuration that
* may be relevant:
* - The QLogix NetXTreme 10GB PCIe NIC seems to use the same PCIE
* core IP block as is used in other BHND devices. The bxe(4) driver
* contains example initialization code and register constants
* that may apply (e.g. GRC_BAR2_CONFIG/PCI_CONFIG_2_BAR2_SIZE).
* - The publicly available Broadcom BCM440X data sheet (440X-PG02-R)
* appears to (partially) document a Broadcom PCI(e) core that has a
* seemingly compatible programming model.
* - The Android bcmdhd driver sources include a possible work-around
* implementation (writing to 0x4e0) in dhd_pcie.c
*/
/* Common PCI/PCIE Config Registers */
@ -181,12 +165,11 @@
#define BHNDB_PCI_V2_BAR0_CCREGS_OFFSET 0x3000 /* bar0 + 12K accesses chipc core registers */
#define BHNDB_PCI_V2_BAR0_CCREGS_SIZE 0x1000
/* PCI_V3 */
/* PCI_V3 (PCIe-G2) */
#define BHNDB_PCI_V3_BAR0_WIN0_CONTROL 0x80 /* backplane address space accessed by BAR0/WIN0 */
#define BHNDB_PCI_V3_BAR1_WIN0_CONTROL 0x84 /* backplane address space accessed by BAR1/WIN0. */
#define BHNDB_PCI_V3_BAR0_WIN1_CONTROL 0x70 /* backplane address space accessed by BAR0/WIN1 */
#define BHNDB_PCI_V3_BAR0_SIZE 0x8000 /* 32KB BAR0 (?) */
#define BHNDB_PCI_V3_BAR0_SIZE 0x8000 /* 32KB BAR0 */
#define BHNDB_PCI_V3_BAR0_WIN0_OFFSET 0x0 /* bar0 + 0x0 accesses configurable 4K region of backplane address space */
#define BHNDB_PCI_V3_BAR0_WIN0_SIZE 0x1000
#define BHNDB_PCI_V3_BAR0_WIN1_OFFSET 0x1000 /* bar0 + 4K accesses second 4K window */

View file

@ -43,4 +43,23 @@ INTERFACE bhnd_chipc;
*/
METHOD bhnd_nvram_src_t nvram_src {
device_t dev;
}
}
/**
* Write @p value with @p mask directly to the chipctrl register.
*
* @param dev A bhnd(4) ChipCommon device.
* @param value The value to write.
* @param mask The mask of bits to be written from @p value.
*
* Drivers should only use function for functionality that is not
* available via another bhnd_chipc() function.
*
* Currently, the only known valid use-case is in implementing a hardware
* work-around for the BCM4321 PCIe rev7 core revision.
*/
METHOD void write_chipctrl {
device_t dev;
uint32_t value;
uint32_t mask;
}

View file

@ -489,20 +489,38 @@ chipc_nvram_setvar(device_t dev, const char *name, const void *buf,
return (ENODEV);
}
static void
chipc_write_chipctrl(device_t dev, uint32_t value, uint32_t mask)
{
struct chipc_softc *sc;
uint32_t cctrl;
sc = device_get_softc(dev);
CHIPC_LOCK(sc);
cctrl = bhnd_bus_read_4(sc->core, CHIPC_CHIPCTRL);
cctrl = (cctrl & ~mask) | (value | mask);
bhnd_bus_write_4(sc->core, CHIPC_CHIPCTRL, cctrl);
CHIPC_UNLOCK(sc);
}
static device_method_t chipc_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, chipc_probe),
DEVMETHOD(device_attach, chipc_attach),
DEVMETHOD(device_detach, chipc_detach),
DEVMETHOD(device_suspend, chipc_suspend),
DEVMETHOD(device_resume, chipc_resume),
DEVMETHOD(device_probe, chipc_probe),
DEVMETHOD(device_attach, chipc_attach),
DEVMETHOD(device_detach, chipc_detach),
DEVMETHOD(device_suspend, chipc_suspend),
DEVMETHOD(device_resume, chipc_resume),
/* ChipCommon interface */
DEVMETHOD(bhnd_chipc_nvram_src, chipc_nvram_src),
DEVMETHOD(bhnd_chipc_nvram_src, chipc_nvram_src),
DEVMETHOD(bhnd_chipc_write_chipctrl, chipc_write_chipctrl),
/* NVRAM interface */
DEVMETHOD(bhnd_nvram_getvar, chipc_nvram_getvar),
DEVMETHOD(bhnd_nvram_setvar, chipc_nvram_setvar),
DEVMETHOD(bhnd_nvram_getvar, chipc_nvram_getvar),
DEVMETHOD(bhnd_nvram_setvar, chipc_nvram_setvar),
DEVMETHOD_END
};

View file

@ -429,8 +429,7 @@ bhnd_pcie_mdio_read_ext(struct bhnd_pci_softc *sc, int phy, int devaddr,
int reg)
{
uint32_t cmd;
uint16_t blk, val;
uint8_t blk_reg;
uint16_t val;
int error;
if (devaddr == MDIO_DEVADDR_NONE)
@ -438,27 +437,23 @@ bhnd_pcie_mdio_read_ext(struct bhnd_pci_softc *sc, int phy, int devaddr,
/* Extended register access is only supported for the SerDes device,
* using the non-standard C22 extended address mechanism */
if (!(sc->quirks & BHND_PCI_QUIRK_SD_C22_EXTADDR))
if (!(sc->quirks & BHND_PCI_QUIRK_SD_C22_EXTADDR) ||
phy != BHND_PCIE_PHYADDR_SD)
{
return (~0U);
if (phy != BHND_PCIE_PHYADDR_SD || devaddr != BHND_PCIE_DEVAD_SD)
return (~0U);
}
/* Enable MDIO access */
BHND_PCI_LOCK(sc);
bhnd_pcie_mdio_enable(sc);
/* Determine the block and register values */
blk = (reg & BHND_PCIE_SD_ADDREXT_BLK_MASK);
blk_reg = (reg & BHND_PCIE_SD_ADDREXT_REG_MASK);
/* Write the block address to the address extension register */
cmd = BHND_PCIE_MDIODATA_ADDR(phy, BHND_PCIE_SD_ADDREXT) |
(blk & BHND_PCIE_MDIODATA_DATA_MASK);
cmd = BHND_PCIE_MDIODATA_ADDR(phy, BHND_PCIE_SD_ADDREXT) | devaddr;
if ((error = bhnd_pcie_mdio_cmd_write(sc, cmd)))
goto cleanup;
/* Issue the read */
cmd = BHND_PCIE_MDIODATA_ADDR(phy, blk_reg);
cmd = BHND_PCIE_MDIODATA_ADDR(phy, reg);
error = bhnd_pcie_mdio_cmd_read(sc, cmd, &val);
cleanup:
@ -476,8 +471,6 @@ bhnd_pcie_mdio_write_ext(struct bhnd_pci_softc *sc, int phy, int devaddr,
int reg, int val)
{
uint32_t cmd;
uint16_t blk;
uint8_t blk_reg;
int error;
if (devaddr == MDIO_DEVADDR_NONE)
@ -485,27 +478,23 @@ bhnd_pcie_mdio_write_ext(struct bhnd_pci_softc *sc, int phy, int devaddr,
/* Extended register access is only supported for the SerDes device,
* using the non-standard C22 extended address mechanism */
if (!(sc->quirks & BHND_PCI_QUIRK_SD_C22_EXTADDR))
if (!(sc->quirks & BHND_PCI_QUIRK_SD_C22_EXTADDR) ||
phy != BHND_PCIE_PHYADDR_SD)
{
return (~0U);
if (phy != BHND_PCIE_PHYADDR_SD || devaddr != BHND_PCIE_DEVAD_SD)
return (~0U);
}
/* Enable MDIO access */
BHND_PCI_LOCK(sc);
bhnd_pcie_mdio_enable(sc);
/* Determine the block and register values */
blk = (reg & BHND_PCIE_SD_ADDREXT_BLK_MASK);
blk_reg = (reg & BHND_PCIE_SD_ADDREXT_REG_MASK);
/* Write the block address to the address extension register */
cmd = BHND_PCIE_MDIODATA_ADDR(phy, BHND_PCIE_SD_ADDREXT) |
(blk & BHND_PCIE_MDIODATA_DATA_MASK);
cmd = BHND_PCIE_MDIODATA_ADDR(phy, BHND_PCIE_SD_ADDREXT) | devaddr;
if ((error = bhnd_pcie_mdio_cmd_write(sc, cmd)))
goto cleanup;
/* Issue the write */
cmd = BHND_PCIE_MDIODATA_ADDR(phy, blk_reg) |
cmd = BHND_PCIE_MDIODATA_ADDR(phy, reg) |
(val & BHND_PCIE_MDIODATA_DATA_MASK);
error = bhnd_pcie_mdio_cmd_write(sc, cmd);

View file

@ -56,28 +56,43 @@ __FBSDID("$FreeBSD$");
#include <dev/bhnd/bhnd.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/bhnd/cores/chipc/chipc.h>
#include <dev/bhnd/cores/chipc/chipcreg.h>
#include "bhnd_pcireg.h"
#include "bhnd_pci_hostbvar.h"
#define BHND_PCI_ASSERT_QUIRK(_sc, _name) \
KASSERT((_sc)->quirks & (_name), ("quirk " __STRING(_name) " not set"))
#define BHND_PCI_DEV(_core, _quirks, _chip_quirks) \
BHND_DEVICE(_core, "", _quirks, _chip_quirks, BHND_DF_HOSTB)
static const struct bhnd_device_quirk bhnd_pci_quirks[];
static const struct bhnd_device_quirk bhnd_pcie_quirks[];
static const struct bhnd_chip_quirk bhnd_pci_chip_quirks[];
static const struct bhnd_chip_quirk bhnd_pcie_chip_quirks[];
/* Device driver work-around variations */
typedef enum {
BHND_PCI_WAR_ATTACH, /**< apply attach workarounds */
BHND_PCI_WAR_RESUME, /**< apply resume workarounds */
BHND_PCI_WAR_SUSPEND, /**< apply suspend workarounds */
BHND_PCI_WAR_DETACH /**< apply detach workarounds */
} bhnd_pci_war_state;
static int bhnd_pci_wars_early_once(struct bhnd_pcihb_softc *sc);
static int bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc);
static int bhnd_pci_wars_hwdown(struct bhnd_pcihb_softc *sc);
static int bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc,
bhnd_pci_war_state state);
static int bhnd_pci_wars_hwdown(struct bhnd_pcihb_softc *sc,
bhnd_pci_war_state state);
/*
* device/quirk tables
*/
#define BHND_PCI_DEV(_core, _quirks, _chip_quirks) \
BHND_DEVICE(_core, "", _quirks, _chip_quirks, BHND_DF_HOSTB)
static const struct bhnd_device bhnd_pci_devs[] = {
BHND_PCI_DEV(PCI, bhnd_pci_quirks, NULL),
BHND_PCI_DEV(PCI, bhnd_pci_quirks, bhnd_pci_chip_quirks),
BHND_PCI_DEV(PCIE, bhnd_pcie_quirks, bhnd_pcie_chip_quirks),
BHND_DEVICE_END
};
@ -89,12 +104,22 @@ static const struct bhnd_device_quirk bhnd_pci_quirks[] = {
BHND_DEVICE_QUIRK_END
};
static const struct bhnd_chip_quirk bhnd_pci_chip_quirks[] = {
/* BCM4321CB2 boards that require 960ns latency timer override */
{{ BHND_CHIP_BTYPE(BCM4321CB2) },
BHND_PCI_QUIRK_960NS_LATTIM_OVR },
{{ BHND_CHIP_BTYPE(BCM4321CB2_AG) },
BHND_PCI_QUIRK_960NS_LATTIM_OVR },
BHND_CHIP_QUIRK_END
};
static const struct bhnd_device_quirk bhnd_pcie_quirks[] = {
{ BHND_HWREV_EQ (0), BHND_PCIE_QUIRK_SDR9_L0s_HANG },
{ BHND_HWREV_RANGE (0, 1), BHND_PCIE_QUIRK_UR_STATUS_FIX },
{ BHND_HWREV_RANGE (0,1), BHND_PCIE_QUIRK_UR_STATUS_FIX },
{ BHND_HWREV_EQ (1), BHND_PCIE_QUIRK_PCIPM_REQEN },
{ BHND_HWREV_RANGE (3, 5), BHND_PCIE_QUIRK_ASPM_OVR |
{ BHND_HWREV_RANGE (3,5), BHND_PCIE_QUIRK_ASPM_OVR |
BHND_PCIE_QUIRK_SDR9_POLARITY |
BHND_PCIE_QUIRK_SDR9_NO_FREQRETRY },
@ -102,37 +127,50 @@ static const struct bhnd_device_quirk bhnd_pcie_quirks[] = {
{ BHND_HWREV_GTE (6), BHND_PCIE_QUIRK_SPROM_L23_PCI_RESET },
{ BHND_HWREV_EQ (7), BHND_PCIE_QUIRK_SERDES_NOPLLDOWN },
{ BHND_HWREV_GTE (8), BHND_PCIE_QUIRK_L1_TIMER_PERF },
{ BHND_HWREV_GTE (10), BHND_PCIE_QUIRK_SD_C22_EXTADDR },
{ BHND_HWREV_LTE (17), BHND_PCIE_QUIRK_MAX_MRRS_128 },
BHND_DEVICE_QUIRK_END
};
static const struct bhnd_chip_quirk bhnd_pcie_chip_quirks[] = {
/* Apple boards on which BHND_BFL2_PCIEWAR_OVR should be assumed
* to be set. */
{{ BHND_CHIP_BVENDOR (PCI_VENDOR_APPLE),
BHND_CHIP_SROMREV (HWREV_EQ(4)),
BHND_CHIP_BREV (HWREV_LTE(0x71)) },
BHND_PCIE_QUIRK_BFL2_PCIEWAR_EN },
{{ BHND_CHIP_BVENDOR (PCI_VENDOR_APPLE),
BHND_CHIP_SROMREV (HWREV_EQ(4)),
BHND_CHIP_BREV (HWREV_LTE(0x71)) },
BHND_PCIE_QUIRK_BFL2_PCIEWAR_EN },
/* Apple BCM4322 boards that require 700mV SerDes TX drive strength. */
{{ BHND_CHIP_BVT (PCI_VENDOR_APPLE, BCM94322X9) },
BHND_PCIE_QUIRK_SERDES_TXDRV_700MV },
/* Apple BCM4331 board-specific quirks */
#define BHND_APPLE_4331_QUIRK(_board, ...) \
{{ BHND_CHIP_ID (4331), \
BHND_CHIP_BVT (PCI_VENDOR_APPLE, _board), }, \
__VA_ARGS__ }
BHND_APPLE_4331_QUIRK(BCM94331X19,
BHND_PCIE_QUIRK_SERDES_TXDRV_MAX|BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
BHND_APPLE_4331_QUIRK(BCM94331X28,
BHND_PCIE_QUIRK_SERDES_TXDRV_MAX|BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
BHND_APPLE_4331_QUIRK(BCM94331X28B, BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
BHND_APPLE_4331_QUIRK(BCM94331X29B,
BHND_PCIE_QUIRK_SERDES_TXDRV_MAX|BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
BHND_APPLE_4331_QUIRK(BCM94331X19C,
BHND_PCIE_QUIRK_SERDES_TXDRV_MAX|BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
BHND_APPLE_4331_QUIRK(BCM94331X29D, BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
BHND_APPLE_4331_QUIRK(BCM94331X33, BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
#undef BHND_APPLE_4331_QUIRK
BHND_CHIP_QUIRK_END
};
// Quirk handling TODO
// WARs for the following are not yet implemented:
// - BHND_PCIE_QUIRK_ASPM_OVR
// - BHND_PCIE_QUIRK_BFL2_PCIEWAR_EN
// - BHND_PCIE_QUIRK_SERDES_NOPLLDOWN
// Quirks (and WARs) for the following are not yet defined:
// - Power savings via MDIO BLK1/PWR_MGMT3 on PCIe hwrev 15-20, 21-22
// - WOWL PME enable/disable
// - 4360 PCIe SerDes Tx amplitude/deemphasis (vendor Apple, boards
// BCM94360X51P2, BCM94360X51A).
// - PCI latency timer (boards CB2_4321_BOARD, CB2_4321_AG_BOARD)
// - Max SerDes TX drive strength (vendor Apple, pcie >= rev10,
// board BCM94322X9)
// - 700mV SerDes TX drive strength (chipid BCM4331, boards BCM94331X19,
// BCM94331X28, BCM94331X29B, BCM94331X19C)
#define BHND_PCI_SOFTC(_sc) (&((_sc)->common))
#define BHND_PCI_READ_2(_sc, _reg) \
@ -159,6 +197,13 @@ static const struct bhnd_chip_quirk bhnd_pcie_chip_quirks[] = {
#define BHND_PCI_MDIO_WRITE(_sc, _phy, _reg, _val) \
bhnd_pcie_mdio_write(BHND_PCI_SOFTC(_sc), (_phy), (_reg), (_val))
#define BHND_PCI_MDIO_READ_EXT(_sc, _phy, _devaddr, _reg) \
bhnd_pcie_mdio_read_ext(BHND_PCI_SOFTC(_sc), (_phy), (_devaddr), (_reg))
#define BHND_PCI_MDIO_WRITE_EXT(_sc, _phy, _devaddr, _reg, _val) \
bhnd_pcie_mdio_write_ext(BHND_PCI_SOFTC(_sc), (_phy), \
(_devaddr), (_reg), (_val))
#define BPCI_REG_SET(_regv, _attr, _val) \
BHND_PCI_REG_SET((_regv), BHND_ ## _attr, (_val))
@ -180,26 +225,34 @@ bhnd_pci_hostb_attach(device_t dev)
int error;
sc = device_get_softc(dev);
sc->dev = dev;
sc->quirks = bhnd_device_quirks(dev, bhnd_pci_devs,
sizeof(bhnd_pci_devs[0]));
/* Find the host PCI bridge device */
sc->pci_dev = bhnd_find_bridge_root(dev, devclass_find("pci"));
if (sc->pci_dev == NULL) {
device_printf(dev, "parent pci bridge device not found\n");
return (ENXIO);
}
/* Common setup */
if ((error = bhnd_pci_generic_attach(dev)))
return (error);
/* Apply early single-shot work-arounds */
if ((error = bhnd_pci_wars_early_once(sc))) {
bhnd_pci_generic_detach(dev);
return (error);
}
if ((error = bhnd_pci_wars_early_once(sc)))
goto failed;
/* Apply attach/resume work-arounds */
if ((error = bhnd_pci_wars_hwup(sc))) {
bhnd_pci_generic_detach(dev);
return (error);
}
if ((error = bhnd_pci_wars_hwup(sc, BHND_PCI_WAR_ATTACH)))
goto failed;
return (0);
failed:
bhnd_pci_generic_detach(dev);
return (error);
}
static int
@ -211,7 +264,7 @@ bhnd_pci_hostb_detach(device_t dev)
sc = device_get_softc(dev);
/* Apply suspend/detach work-arounds */
if ((error = bhnd_pci_wars_hwdown(sc)))
if ((error = bhnd_pci_wars_hwdown(sc, BHND_PCI_WAR_DETACH)))
return (error);
return (bhnd_pci_generic_detach(dev));
@ -226,7 +279,7 @@ bhnd_pci_hostb_suspend(device_t dev)
sc = device_get_softc(dev);
/* Apply suspend/detach work-arounds */
if ((error = bhnd_pci_wars_hwdown(sc)))
if ((error = bhnd_pci_wars_hwdown(sc, BHND_PCI_WAR_SUSPEND)))
return (error);
return (bhnd_pci_generic_suspend(dev));
@ -244,7 +297,7 @@ bhnd_pci_hostb_resume(device_t dev)
return (error);
/* Apply attach/resume work-arounds */
if ((error = bhnd_pci_wars_hwup(sc))) {
if ((error = bhnd_pci_wars_hwup(sc, BHND_PCI_WAR_RESUME))) {
bhnd_pci_generic_detach(dev);
return (error);
}
@ -263,6 +316,36 @@ bhnd_pci_hostb_resume(device_t dev)
static int
bhnd_pci_wars_early_once(struct bhnd_pcihb_softc *sc)
{
int error;
/* Set PCI latency timer */
if (sc->quirks & BHND_PCI_QUIRK_960NS_LATTIM_OVR) {
pci_write_config(sc->pci_dev, PCIR_LATTIMER, 0x20 /* 960ns */,
1);
}
/* Determine whether ASPM/CLKREQ should be forced on, or forced off. */
if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
struct bhnd_board_info board;
bool aspm_en;
/* Fetch board info */
if ((error = bhnd_read_board_info(sc->dev, &board)))
return (error);
/* Check board flags */
aspm_en = true;
if (board.board_flags2 & BHND_BFL2_PCIEWAR_OVR)
aspm_en = false;
/* Early Apple devices did not (but should have) set
* BHND_BFL2_PCIEWAR_OVR in SPROM. */
if (sc->quirks & BHND_PCIE_QUIRK_BFL2_PCIEWAR_EN)
aspm_en = false;
sc->aspm_quirk_override.aspm_en = aspm_en;
}
/* Determine correct polarity by observing the attach-time PCIe PHY
* link status. This is used later to reset/force the SerDes
* polarity */
@ -270,12 +353,23 @@ bhnd_pci_wars_early_once(struct bhnd_pcihb_softc *sc)
uint32_t st;
bool inv;
st = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_PLP_STATUSREG);
inv = ((st & BHND_PCIE_PLP_POLARITY_INV) != 0);
sc->sdr9_quirk_polarity.inv = inv;
}
/* Override maximum read request size */
if (bhnd_get_class(sc->dev) == BHND_DEVCLASS_PCIE) {
int msize;
msize = 128; /* compatible with all PCIe-G1 core revisions */
if (sc->quirks & BHND_PCIE_QUIRK_DEFAULT_MRRS_512)
msize = 512;
if (pci_set_max_read_req(sc->pci_dev, msize) == 0)
panic("set mrrs on non-PCIe device");
}
return (0);
}
@ -284,7 +378,7 @@ bhnd_pci_wars_early_once(struct bhnd_pcihb_softc *sc)
* of the bridge device.
*/
static int
bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc)
bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc, bhnd_pci_war_state state)
{
/* Note that the order here matters; these work-arounds
* should not be re-ordered without careful review of their
@ -407,6 +501,47 @@ bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc)
BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt);
}
/* Override ASPM/ECPM settings in SPROM shadow and PCIER_LINK_CTL */
if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
bus_size_t reg;
uint16_t cfg;
/* Set ASPM L1/L0s flags in SPROM shadow */
reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_ASPM_OFFSET;
cfg = BHND_PCI_READ_2(sc, reg);
if (sc->aspm_quirk_override.aspm_en)
cfg |= BHND_PCIE_SRSH_ASPM_ENB;
else
cfg &= ~BHND_PCIE_SRSH_ASPM_ENB;
BHND_PCI_WRITE_2(sc, reg, cfg);
/* Set ASPM/ECPM (CLKREQ) flags in PCIe link control register */
cfg = pcie_read_config(sc->pci_dev, PCIER_LINK_CTL, 2);
if (sc->aspm_quirk_override.aspm_en)
cfg |= PCIEM_LINK_CTL_ASPMC;
else
cfg &= ~PCIEM_LINK_CTL_ASPMC;
cfg &= ~PCIEM_LINK_CTL_ECPM; /* CLKREQ# */
pcie_write_config(sc->pci_dev, PCIER_LINK_CTL, cfg, 2);
/* Set CLKREQ (ECPM) flags in SPROM shadow */
reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_CLKREQ_OFFSET_R5;
cfg = BHND_PCI_READ_2(sc, reg);
if (sc->aspm_quirk_override.aspm_en)
cfg |= BHND_PCIE_SRSH_CLKREQ_ENB;
else
cfg &= ~BHND_PCIE_SRSH_CLKREQ_ENB;
BHND_PCI_WRITE_2(sc, reg, cfg);
}
/* Enable L23READY_EXIT_NOPRST if not already set in SPROM. */
if (sc->quirks & BHND_PCIE_QUIRK_SPROM_L23_PCI_RESET) {
bus_size_t reg;
@ -423,6 +558,54 @@ bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc)
}
}
/* Disable SerDes PLL down */
if (sc->quirks & BHND_PCIE_QUIRK_SERDES_NOPLLDOWN) {
device_t bhnd, chipc;
bus_size_t reg;
bhnd = device_get_parent(sc->dev);
chipc = bhnd_find_child(bhnd, BHND_DEVCLASS_CC, 0);
KASSERT(chipc != NULL, ("missing chipcommon device"));
/* Write SerDes PLL disable flag to the ChipCommon core */
BHND_CHIPC_WRITE_CHIPCTRL(chipc, CHIPCTRL_4321_PLL_DOWN,
CHIPCTRL_4321_PLL_DOWN);
/* Clear SPROM shadow backdoor register */
reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_BD_OFFSET;
BHND_PCI_WRITE_2(sc, reg, 0);
}
/* Adjust TX drive strength and pre-emphasis coefficient */
if (sc->quirks & BHND_PCIE_QUIRK_SERDES_TXDRV_ADJUST) {
uint16_t txdrv;
/* Fetch current TX driver parameters */
txdrv = BHND_PCI_MDIO_READ_EXT(sc, BHND_PCIE_PHYADDR_SD,
BHND_PCIE_SD_REGS_TX0, BHND_PCIE_SD_TX_DRIVER);
/* Set 700mV drive strength */
if (sc->quirks & BHND_PCIE_QUIRK_SERDES_TXDRV_700MV) {
txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_P2_COEFF,
BHND_PCIE_APPLE_TX_P2_COEFF_700MV);
txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_IDRIVER,
BHND_PCIE_APPLE_TX_IDRIVER_700MV);
}
/* ... or, set max drive strength */
if (sc->quirks & BHND_PCIE_QUIRK_SERDES_TXDRV_MAX) {
txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_P2_COEFF,
BHND_PCIE_APPLE_TX_P2_COEFF_MAX);
txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_IDRIVER,
BHND_PCIE_APPLE_TX_IDRIVER_MAX);
}
BHND_PCI_MDIO_WRITE_EXT(sc, BHND_PCIE_PHYADDR_SD,
BHND_PCIE_SD_REGS_TX0, BHND_PCIE_SD_TX_DRIVER, txdrv);
}
return (0);
}
@ -431,8 +614,8 @@ bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc)
* of the bridge device.
*/
static int
bhnd_pci_wars_hwdown(struct bhnd_pcihb_softc *sc)
{
bhnd_pci_wars_hwdown(struct bhnd_pcihb_softc *sc, bhnd_pci_war_state state)
{
/* Reduce L1 timer for better power savings.
* TODO: We could enable/disable this on demand for better power
* savings if we tie this to HT clock request handling */
@ -443,6 +626,19 @@ bhnd_pci_wars_hwdown(struct bhnd_pcihb_softc *sc)
BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt);
}
/* Enable CLKREQ (ECPM). If suspending, also disable ASPM L1 entry */
if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
uint16_t lcreg;
lcreg = pcie_read_config(sc->pci_dev, PCIER_LINK_CTL, 2);
lcreg |= PCIEM_LINK_CTL_ECPM; /* CLKREQ# */
if (state == BHND_PCI_WAR_SUSPEND)
lcreg &= ~PCIEM_LINK_CTL_ASPMC_L1;
pcie_write_config(sc->pci_dev, PCIER_LINK_CTL, lcreg, 2);
}
return (0);
}
@ -456,10 +652,9 @@ static device_method_t bhnd_pci_hostb_methods[] = {
DEVMETHOD_END
};
DEFINE_CLASS_1(bhnd_pci_hostb, bhnd_pci_hostb_driver, bhnd_pci_hostb_methods,
DEFINE_CLASS_1(bhnd_hostb, bhnd_pci_hostb_driver, bhnd_pci_hostb_methods,
sizeof(struct bhnd_pcihb_softc), bhnd_pci_driver);
DRIVER_MODULE(bhnd_hostb, bhnd, bhnd_pci_hostb_driver, bhnd_hostb_devclass, 0, 0);
DRIVER_MODULE(bhnd_pci_hostb, bhnd, bhnd_pci_hostb_driver, bhnd_hostb_devclass, 0, 0);
MODULE_VERSION(bhnd_pci_hostb, 1);
MODULE_DEPEND(bhnd_pci_hostb, bhnd, 1, 1, 1);

View file

@ -43,7 +43,7 @@
DECLARE_CLASS(bhnd_pci_hostb_driver);
/*
/**
* PCI/PCIe-Gen1 endpoint-mode device quirks
*/
enum {
@ -56,7 +56,6 @@ enum {
*/
BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST = (1<<1),
/**
* SBTOPCI_RC_READMULTI must be set on the SSB_PCICORE_SBTOPCI2
* register.
@ -73,19 +72,25 @@ enum {
*/
BHND_PCI_QUIRK_CLKRUN_DSBL = (1<<3),
/**
* On PCI-attached BCM4321CB* boards, the PCI latency timer must be set
* to 960ns on initial attach.
*/
BHND_PCI_QUIRK_960NS_LATTIM_OVR = (1<<4),
/**
* TLP workaround for unmatched address handling is required.
*
* This TLP workaround will enable setting of the PCIe UR status bit
* on memory access to an unmatched address.
*/
BHND_PCIE_QUIRK_UR_STATUS_FIX = (1<<4),
BHND_PCIE_QUIRK_UR_STATUS_FIX = (1<<5),
/**
* PCI-PM power management must be explicitly enabled via
* the data link control register.
*/
BHND_PCIE_QUIRK_PCIPM_REQEN = (1<<5),
BHND_PCIE_QUIRK_PCIPM_REQEN = (1<<6),
/**
* Fix L0s to L0 exit transition on SerDes <= rev9 devices.
@ -98,46 +103,50 @@ enum {
* filters must be tweaked to ensure the CDR has fully stabilized
* before asserting receive sequencer completion.
*/
BHND_PCIE_QUIRK_SDR9_L0s_HANG = (1<<6),
BHND_PCIE_QUIRK_SDR9_L0s_HANG = (1<<7),
/**
* The idle time for entering L1 low-power state must be
* explicitly set (to 114ns) to fix slow L1->L0 transition issues.
*/
BHND_PCIE_QUIRK_L1_IDLE_THRESH = (1<<7),
BHND_PCIE_QUIRK_L1_IDLE_THRESH = (1<<8),
/**
* The ASPM L1 entry timer should be extended for better performance,
* and restored for better power savings.
*/
BHND_PCIE_QUIRK_L1_TIMER_PERF = (1<<8),
BHND_PCIE_QUIRK_L1_TIMER_PERF = (1<<9),
/**
* ASPM and ECPM settings must be overridden manually.
* Applies to 4311B0/4321B1 chipset revisions.
*
* The override behavior is controlled by the BHND_BFL2_PCIEWAR_OVR
* flag. If this flag is set, ASPM/CLKREQ should be overridden as
* enabled; otherwise, they should be overridden as disabled.
* flag; if set, ASPM and CLKREQ should be explicitly disabled. If not
* set, they should be explicitly enabled.
*
* Attach/Resume:
* - Set SRSH_ASPM_ENB flag in the SPROM ASPM register.
* - Set ASPM L0S/L1 in the PCIER_LINK_CTL register.
* - Set SRSH_CLKREQ_ENB flag in the SPROM CLKREQ_REV5 register.
* - Clear ECPM in the PCIER_LINK_CTL register.
* - Update SRSH_ASPM_ENB flag in the SPROM ASPM register.
* - Update SRSH_CLKREQ_ENB flag in the SPROM CLKREQ_REV5
* register.
* - Update ASPM L0S/L1 flags in PCIER_LINK_CTL register.
* - Clear CLKREQ (ECPM) flag in PCIER_LINK_CTL register.
*
* Detach/Suspend:
* -
* - When the device enters D3 state, or system enters S3/S4 state,
* clear ASPM L1 in the PCIER_LINK_CTL register.
* Suspend:
* - Clear ASPM L1 flag in the PCIER_LINK_CTL register.
* - Set CLKREQ (ECPM) flag in the PCIER_LINK_CTL register.
*
* Detach:
* - Set CLKREQ (ECPM) flag in the PCIER_LINK_CTL register.
*/
BHND_PCIE_QUIRK_ASPM_OVR = (1<<9),
BHND_PCIE_QUIRK_ASPM_OVR = (1<<10),
/**
* A subset of Apple devices did not set the BHND_BFL2_PCIEWAR_OVR
* flag in SPROM; on these devices, the BHND_BFL2_PCIEWAR_OVR flag
* should always be treated as if set.
*/
BHND_PCIE_QUIRK_BFL2_PCIEWAR_EN = (1<<10),
BHND_PCIE_QUIRK_BFL2_PCIEWAR_EN = (1<<11),
/**
* Fix SerDes polarity on SerDes <= rev9 devices.
@ -145,13 +154,13 @@ enum {
* The SerDes polarity must be saved at device attachment, and
* restored on suspend/resume.
*/
BHND_PCIE_QUIRK_SDR9_POLARITY = (1<<11),
BHND_PCIE_QUIRK_SDR9_POLARITY = (1<<12),
/**
* SerDes PLL down flag must be manually disabled (by ChipCommon) on
* resume.
*/
BHND_PCIE_QUIRK_SERDES_NOPLLDOWN = (1<<12),
BHND_PCIE_QUIRK_SERDES_NOPLLDOWN = (1<<13),
/**
* On attach and resume, consult the SPROM to determine whether
@ -159,31 +168,77 @@ enum {
*
* If L23READY_EXIT_NOPRST is not already set in the SPROM, set it
*/
BHND_PCIE_QUIRK_SPROM_L23_PCI_RESET = (1<<13),
/**
* The PCIe SerDes supports non-standard extended MDIO register access.
*
* The PCIe SerDes supports access to extended MDIO registers via
* a non-standard Clause 22 address extension mechanism.
*/
BHND_PCIE_QUIRK_SD_C22_EXTADDR = (1<<14),
BHND_PCIE_QUIRK_SPROM_L23_PCI_RESET = (1<<14),
/**
* The PCIe SerDes PLL must be configured to not retry the startup
* sequence upon frequency detection failure on SerDes <= rev9 devices
*
* The issue this workaround resolves has not be determined.
* The issue this workaround resolves is unknown.
*/
BHND_PCIE_QUIRK_SDR9_NO_FREQRETRY = (1<<15),
/**
* Common flag for quirks that require PCIe SerDes TX
* drive strength adjustment.
*
* Only applies to PCIe >= rev10 devices.
*/
BHND_PCIE_QUIRK_SERDES_TXDRV_ADJUST = (1<<16),
/**
* On Apple BCM94322X9 devices, the PCIe SerDes TX drive strength
* should be set to 700mV.
*
* The exact issue is unknown, but presumably this workaround
* resolves signal integrity issues with these devices.
*
* Only applies to PCIe >= rev10 devices.
*/
BHND_PCIE_QUIRK_SERDES_TXDRV_700MV = (1<<17) |
BHND_PCIE_QUIRK_SERDES_TXDRV_ADJUST,
/**
* On some Apple BCM4331-based devices, the PCIe SerDes TX drive
* strength should be set to its maximum.
*
* The exact issue is unknown, but presumably this workaround
* resolves signal integrity issues with these devices.
*/
BHND_PCIE_QUIRK_SERDES_TXDRV_MAX = (1<<18) |
BHND_PCIE_QUIRK_SERDES_TXDRV_ADJUST,
/**
* PCIe cores prior to rev18 do not support an MRRS larger than
* 128 bytes.
*/
BHND_PCIE_QUIRK_MAX_MRRS_128 = (1<<19),
/**
* The PCIe core should be configured with an MRRS of 512 bytes.
*/
BHND_PCIE_QUIRK_DEFAULT_MRRS_512 = (1<<20),
};
/**
* bhnd_pci_hostb driver instance state.
*/
struct bhnd_pcihb_softc {
struct bhnd_pci_softc common; /**< common bhnd_pci state */
uint32_t quirks; /**< hostb device quirks */
struct bhnd_pci_softc common; /**< common bhnd_pci state */
device_t dev;
device_t pci_dev; /**< host PCI device */
uint32_t quirks; /**< hostb device quirks */
/** BHND_PCIE_QUIRK_ASPM_OVR state. */
struct {
/**
* ASPM/CLKREQ override setting.
*
* If true, ASPM/CLKREQ should be overridden as enabled.
* If false, ASPM/CLKREQ should be overridden as disabled.
*/
bool aspm_en;
} aspm_quirk_override;
/** BHND_PCIE_QUIRK_SDR9_POLARITY state. */
struct {
@ -198,4 +253,4 @@ struct bhnd_pcihb_softc {
};
#endif /* _BHND_CORES_PCI_BHND_PCI_HOSTBVAR_H_ */
#endif /* _BHND_CORES_PCI_BHND_PCI_HOSTBVAR_H_ */

View file

@ -86,8 +86,10 @@ static device_method_t bhnd_pcib_methods[] = {
DEVMETHOD_END
};
DEFINE_CLASS_1(bhnd_pcib, bhnd_pcib_driver, bhnd_pcib_methods, sizeof(struct bhnd_pcib_softc), bhnd_pci_driver);
DRIVER_MODULE(bhnd_pcib, bhnd, bhnd_pcib_driver, bhnd_hostb_devclass, 0, 0);
DEFINE_CLASS_1(pcib, bhnd_pcib_driver, bhnd_pcib_methods, sizeof(struct bhnd_pcib_softc), bhnd_pci_driver);
static devclass_t pcib_devclass;
DRIVER_MODULE(bhnd_pcib, bhnd, bhnd_pcib_driver, pcib_devclass, 0, 0);
MODULE_VERSION(bhnd_pcib, 1);
MODULE_DEPEND(bhnd_pcib, bhnd, 1, 1, 1);

View file

@ -321,12 +321,8 @@
* PCIe-G1 SerDes MDIO Registers (>= rev10)
*/
#define BHND_PCIE_PHYADDR_SD 0x0 /* serdes PHY address */
#define BHND_PCIE_DEVAD_SD 0x1 /* serdes pseudo-devad (PMA) recognized by
the bhnd_mdio_pcie driver */
#define BHND_PCIE_SD_ADDREXT 0x1F /* serdes address extension register */
#define BHND_PCIE_SD_ADDREXT_BLK_MASK 0xFFF0 /* register block mask */
#define BHND_PCIE_SD_ADDREXT_REG_MASK 0x000F /* register address mask */
#define BHND_PCIE_SD_REGS_IEEE0 0x0000 /* IEEE0 AN CTRL block */
#define BHND_PCIE_SD_REGS_IEEE1 0x0010 /* IEEE1 AN ADV block */
@ -335,10 +331,30 @@
#define BHND_PCIE_SD_REGS_BLK2 0x8020 /* ??? */
#define BHND_PCIE_SD_REGS_BLK3 0x8030 /* ??? */
#define BHND_PCIE_SD_REGS_BLK4 0x8040 /* ??? */
#define BHND_PCIE_SD_REGS_TXPLL 0x8080 /* TXPLL register block */
#define BHND_PCIE_SD_REGS_TXCTRL0 0x8200 /* ??? */
#define BHND_PCIE_SD_REGS_SERDESID 0x8310 /* ??? */
#define BHND_PCIE_SD_REGS_RXCTRL0 0x8400 /* ??? */
#define BHND_PCIE_SD_REGS_PLL 0x8080 /* (?) PLL register block */
#define BHND_PCIE_SD_REGS_TX0 0x8200 /* (?) Transmit 0 block */
#define BHND_PCIE_SD_REGS_SERDESID 0x8310 /* ??? */
#define BHND_PCIE_SD_REGS_RX0 0x8400 /* (?) Receive 0 register block */
/* The interpretation of these registers and values are just guesses based on
* the limited available documentation from other (likely similar) Broadcom
* SerDes IP. */
#define BHND_PCIE_SD_TX_DRIVER 0x17 /* TX transmit driver register */
#define BHND_PCIE_SD_TX_DRIVER_IFIR_MASK 0x000E /* unconfirmed */
#define BHND_PCIE_SD_TX_DRIVER_IFIR_SHIFT 1 /* unconfirmed */
#define BHND_PCIE_SD_TX_DRIVER_IPRE_MASK 0x00F0 /* unconfirmed */
#define BHND_PCIE_SD_TX_DRIVER_IPRE_SHIFT 4 /* unconfirmed */
#define BHND_PCIE_SD_TX_DRIVER_IDRIVER_MASK 0x0F00 /* unconfirmed */
#define BHND_PCIE_SD_TX_DRIVER_IDRIVER_SHIFT 8 /* unconfirmed */
#define BHND_PCIE_SD_TX_DRIVER_P2_COEFF_SHIFT 12 /* unconfirmed */
#define BHND_PCIE_SD_TX_DRIVER_P2_COEFF_MASK 0xF000 /* unconfirmed */
/* Constants used with host bridge quirk handling */
#define BHND_PCIE_APPLE_TX_P2_COEFF_MAX 0x7 /* 9.6dB pre-emphassis coeff (???) */
#define BHND_PCIE_APPLE_TX_IDRIVER_MAX 0xF /* 1400mV voltage range (???) */
#define BHND_PCIE_APPLE_TX_P2_COEFF_700MV 0x7 /* 2.3dB pre-emphassis coeff (???) */
#define BHND_PCIE_APPLE_TX_IDRIVER_700MV 0x0 /* 670mV voltage range (???) */
/*
* PCIe-G1 SerDes-R9 MDIO Registers (<= rev9)
@ -389,23 +405,12 @@
#define BHND_PCIE_SRSH_ASPM_L0s_ENB 0x8 /* bit 3 */
#define BHND_PCIE_SRSH_PCIE_MISC_CONFIG 10 /* word 5 */
#define BHND_PCIE_SRSH_L23READY_EXIT_NOPRST 0x8000 /* bit 15 */
#define BHND_PCIE_SRSH_CLKREQ_OFFSET_REV5 40 /* word 20 for srom rev <= 5 */
#define BHND_PCIE_SRSH_CLKREQ_OFFSET_REV8 104 /* word 52 for srom rev 8 */
#define BHND_PCIE_SRSH_CLKREQ_OFFSET_R5 40 /* word 20 for srom rev <= 5 */
#define BHND_PCIE_SRSH_CLKREQ_OFFSET_R8 104 /* word 52 for srom rev 8 */
#define BHND_PCIE_SRSH_CLKREQ_ENB 0x0800 /* bit 11 */
#define BHND_PCIE_SRSH_BD_OFFSET 12 /* word 6 */
#define BHND_PCIE_SRSH_AUTOINIT_OFFSET 36 /* auto initialization enable */
/* Linkcontrol reg offset in PCIE Cap */
#define BHND_PCIE_CAP_LINKCTRL_OFFSET 16 /* linkctrl offset in pcie cap */
#define BHND_PCIE_CAP_LCREG_ASPML0s 0x01 /* ASPM L0s in linkctrl */
#define BHND_PCIE_CAP_LCREG_ASPML1 0x02 /* ASPM L1 in linkctrl */
#define BHND_PCIE_CLKREQ_ENAB 0x100 /* CLKREQ Enab in linkctrl */
#define BHND_PCIE_ASPM_ENAB 3 /* ASPM L0s & L1 in linkctrl */
#define BHND_PCIE_ASPM_L1_ENAB 2 /* ASPM L0s & L1 in linkctrl */
#define BHND_PCIE_ASPM_L0s_ENAB 1 /* ASPM L0s & L1 in linkctrl */
#define BHND_PCIE_ASPM_DISAB 0 /* ASPM L0s & L1 in linkctrl */
/* Status reg PCIE_PLP_STATUSREG */
#define BHND_PCIE_PLP_POLARITY_INV 0x10 /* lane polarity is inverted */

View file

@ -0,0 +1,289 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* 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,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* Broadcom Common PCIe-G2 Support.
*
* This base driver implementation is shared by the bhnd_pcib_g2 (root complex)
* and bhnd_pci_hostb_g2 (host bridge) drivers.
*/
#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
#include <dev/bhnd/bhnd.h>
#include <dev/mdio/mdio.h>
#include "bhnd_pcie2_reg.h"
#include "bhnd_pcie2_var.h"
static struct bhnd_device_quirk bhnd_pcie2_quirks[];
#define BHND_PCIE_DEV(_core, _desc, ...) \
BHND_DEVICE(_core, _desc, bhnd_pcie2_quirks, NULL, ## __VA_ARGS__)
static const struct bhnd_device bhnd_pcie2_devs[] = {
BHND_PCIE_DEV(PCIE2, "PCIe-G2 Host-PCI bridge", BHND_DF_HOSTB),
BHND_PCIE_DEV(PCIE2, "PCIe-G2 PCI-BHND bridge"),
BHND_DEVICE_END
};
/* Device quirks tables */
static struct bhnd_device_quirk bhnd_pcie2_quirks[] = {
BHND_DEVICE_QUIRK_END
};
int
bhnd_pcie2_generic_probe(device_t dev)
{
const struct bhnd_device *id;
id = bhnd_device_lookup(dev, bhnd_pcie2_devs,
sizeof(bhnd_pcie2_devs[0]));
if (id == NULL)
return (ENXIO);
bhnd_set_custom_core_desc(dev, id->desc);
return (BUS_PROBE_DEFAULT);
}
int
bhnd_pcie2_generic_attach(device_t dev)
{
struct bhnd_pcie2_softc *sc;
int error;
sc = device_get_softc(dev);
sc->dev = dev;
sc->quirks = bhnd_device_quirks(dev, bhnd_pcie2_devs,
sizeof(bhnd_pcie2_devs[0]));
/* Allocate bus resources */
sc->mem_res = bhnd_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid,
RF_ACTIVE);
if (sc->mem_res == NULL)
return (ENXIO);
BHND_PCIE2_LOCK_INIT(sc);
/* Probe and attach children */
if ((error = bus_generic_attach(dev)))
goto cleanup;
return (0);
cleanup:
bhnd_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res);
BHND_PCIE2_LOCK_DESTROY(sc);
return (error);
}
int
bhnd_pcie2_generic_detach(device_t dev)
{
struct bhnd_pcie2_softc *sc;
int error;
sc = device_get_softc(dev);
if ((error = bus_generic_detach(dev)))
return (error);
bhnd_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res);
BHND_PCIE2_LOCK_DESTROY(sc);
return (0);
}
static struct resource_list *
bhnd_pcie2_get_resource_list(device_t dev, device_t child)
{
struct bhnd_pcie2_devinfo *dinfo;
if (device_get_parent(child) != dev)
return (NULL);
dinfo = device_get_ivars(child);
return (&dinfo->resources);
}
static device_t
bhnd_pcie2_add_child(device_t dev, u_int order, const char *name, int unit)
{
struct bhnd_pcie2_devinfo *dinfo;
device_t child;
child = device_add_child_ordered(dev, order, name, unit);
if (child == NULL)
return (NULL);
dinfo = malloc(sizeof(struct bhnd_pcie2_devinfo), M_DEVBUF, M_NOWAIT);
if (dinfo == NULL) {
device_delete_child(dev, child);
return (NULL);
}
resource_list_init(&dinfo->resources);
device_set_ivars(child, dinfo);
return (child);
}
static void
bhnd_pcie2_child_deleted(device_t dev, device_t child)
{
struct bhnd_pcie2_devinfo *dinfo;
if (device_get_parent(child) != dev)
return;
dinfo = device_get_ivars(child);
if (dinfo != NULL) {
resource_list_free(&dinfo->resources);
free(dinfo, M_DEVBUF);
}
device_set_ivars(child, NULL);
}
int
bhnd_pcie2_generic_suspend(device_t dev)
{
return (bus_generic_suspend(dev));
}
int
bhnd_pcie2_generic_resume(device_t dev)
{
return (bus_generic_resume(dev));
}
/**
* Read a 32-bit PCIe TLP/DLLP/PLP protocol register.
*
* @param sc The bhndb_pci driver state.
* @param addr The protocol register offset.
*/
uint32_t
bhnd_pcie2_read_proto_reg(struct bhnd_pcie2_softc *sc, uint32_t addr)
{
// TODO
return (ENXIO);
}
/**
* Write a 32-bit PCIe TLP/DLLP/PLP protocol register value.
*
* @param sc The bhndb_pci driver state.
* @param addr The protocol register offset.
* @param val The value to write to @p addr.
*/
void
bhnd_pcie2_write_proto_reg(struct bhnd_pcie2_softc *sc, uint32_t addr,
uint32_t val)
{
// TODO
panic("unimplemented");
}
int
bhnd_pcie2_mdio_read(struct bhnd_pcie2_softc *sc, int phy, int reg)
{
// TODO
return (ENXIO);
}
int
bhnd_pcie2_mdio_write(struct bhnd_pcie2_softc *sc, int phy, int reg, int val)
{
// TODO
return (ENXIO);
}
int
bhnd_pcie2_mdio_read_ext(struct bhnd_pcie2_softc *sc, int phy, int devaddr,
int reg)
{
// TODO
return (ENXIO);
}
int
bhnd_pcie2_mdio_write_ext(struct bhnd_pcie2_softc *sc, int phy, int devaddr,
int reg, int val)
{
// TODO
return (ENXIO);
}
static device_method_t bhnd_pcie2_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, bhnd_pcie2_generic_probe),
DEVMETHOD(device_attach, bhnd_pcie2_generic_attach),
DEVMETHOD(device_detach, bhnd_pcie2_generic_detach),
DEVMETHOD(device_suspend, bhnd_pcie2_generic_suspend),
DEVMETHOD(device_resume, bhnd_pcie2_generic_resume),
/* Bus interface */
DEVMETHOD(bus_add_child, bhnd_pcie2_add_child),
DEVMETHOD(bus_child_deleted, bhnd_pcie2_child_deleted),
DEVMETHOD(bus_print_child, bus_generic_print_child),
DEVMETHOD(bus_get_resource_list, bhnd_pcie2_get_resource_list),
DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource),
DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource),
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource),
DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource),
DEVMETHOD_END
};
DEFINE_CLASS_0(bhnd_pcie2, bhnd_pcie2_driver, bhnd_pcie2_methods,
sizeof(struct bhnd_pcie2_softc));
MODULE_DEPEND(bhnd_pcie2, bhnd, 1, 1, 1);
MODULE_DEPEND(bhnd_pcie2, pci, 1, 1, 1);
MODULE_VERSION(bhnd_pcie2, 1);

View file

@ -0,0 +1,254 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* 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,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* Broadcom BHND PCIe-Gen2 PCI-Host Bridge.
*
* This driver handles all interactions with PCIe-G2 bridge cores operating in
* endpoint mode.
*
* Host-level PCI operations are handled at the bhndb bridge level by the
* bhndb_pci driver.
*/
// TODO
//
// A full survey of known quirks/work-arounds has not been completed.
//
// Work-arounds for the following are not yet implemented:
// - BHND_PCIE2_QUIRK_SERDES_TXDRV_DEEMPH
// 4360 PCIe SerDes Tx amplitude/deemphasis (vendor Apple, boards
// BCM94360X51P2, BCM94360X51A)
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/bus.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
#include <dev/bhnd/bhnd.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include "bhnd_pcie2_reg.h"
#include "bhnd_pcie2_hostbvar.h"
static const struct bhnd_device_quirk bhnd_pcie2_quirks[];
static const struct bhnd_chip_quirk bhnd_pcie2_chip_quirks[];
static int bhnd_pcie2_wars_early_once(struct bhnd_pcie2hb_softc *sc);
static int bhnd_pcie2_wars_hwup(struct bhnd_pcie2hb_softc *sc);
static int bhnd_pcie2_wars_hwdown(struct bhnd_pcie2hb_softc *sc);
/*
* device/quirk tables
*/
#define BHND_PCI_DEV(_core, _quirks, _chip_quirks) \
BHND_DEVICE(_core, "", _quirks, _chip_quirks, BHND_DF_HOSTB)
static const struct bhnd_device bhnd_pcie2_devs[] = {
BHND_PCI_DEV(PCIE2, bhnd_pcie2_quirks, bhnd_pcie2_chip_quirks),
BHND_DEVICE_END
};
static const struct bhnd_device_quirk bhnd_pcie2_quirks[] = {
BHND_DEVICE_QUIRK_END
};
static const struct bhnd_chip_quirk bhnd_pcie2_chip_quirks[] = {
/* Apple BCM4360 boards that require adjusting TX amplitude and
* differential output de-emphasis of the PCIe SerDes */
{{ BHND_CHIP_BVT (PCI_VENDOR_APPLE, BCM94360X51P2) },
BHND_PCIE2_QUIRK_SERDES_TXDRV_DEEMPH },
{{ BHND_CHIP_BVT (PCI_VENDOR_APPLE, BCM94360X51A) },
BHND_PCIE2_QUIRK_SERDES_TXDRV_DEEMPH },
BHND_CHIP_QUIRK_END
};
static int
bhnd_pcie2_hostb_attach(device_t dev)
{
struct bhnd_pcie2hb_softc *sc;
int error;
sc = device_get_softc(dev);
sc->dev = dev;
sc->quirks = bhnd_device_quirks(dev, bhnd_pcie2_devs,
sizeof(bhnd_pcie2_devs[0]));
/* Find the host PCI bridge device */
sc->pci_dev = bhnd_find_bridge_root(dev, devclass_find("pci"));
if (sc->pci_dev == NULL) {
device_printf(dev, "parent pci bridge device not found\n");
return (ENXIO);
}
/* Common setup */
if ((error = bhnd_pcie2_generic_attach(dev)))
return (error);
/* Apply early single-shot work-arounds */
if ((error = bhnd_pcie2_wars_early_once(sc)))
goto failed;
/* Apply attach/resume work-arounds */
if ((error = bhnd_pcie2_wars_hwup(sc)))
goto failed;
return (0);
failed:
bhnd_pcie2_generic_detach(dev);
return (error);
}
static int
bhnd_pcie2_hostb_detach(device_t dev)
{
struct bhnd_pcie2hb_softc *sc;
int error;
sc = device_get_softc(dev);
/* Apply suspend/detach work-arounds */
if ((error = bhnd_pcie2_wars_hwdown(sc)))
return (error);
return (bhnd_pcie2_generic_detach(dev));
}
static int
bhnd_pcie2_hostb_suspend(device_t dev)
{
struct bhnd_pcie2hb_softc *sc;
int error;
sc = device_get_softc(dev);
/* Apply suspend/detach work-arounds */
if ((error = bhnd_pcie2_wars_hwdown(sc)))
return (error);
return (bhnd_pcie2_generic_suspend(dev));
}
static int
bhnd_pcie2_hostb_resume(device_t dev)
{
struct bhnd_pcie2hb_softc *sc;
int error;
sc = device_get_softc(dev);
if ((error = bhnd_pcie2_generic_resume(dev)))
return (error);
/* Apply attach/resume work-arounds */
if ((error = bhnd_pcie2_wars_hwup(sc))) {
bhnd_pcie2_generic_detach(dev);
return (error);
}
return (0);
}
/**
* Apply any hardware work-arounds that must be executed exactly once, early in
* the attach process.
*
* This must be called after core enumeration and discovery of all applicable
* quirks, but prior to probe/attach of any cores, parsing of
* SPROM, etc.
*/
static int
bhnd_pcie2_wars_early_once(struct bhnd_pcie2hb_softc *sc)
{
// TODO
return (ENXIO);
}
/**
* Apply any hardware workarounds that are required upon attach or resume
* of the bridge device.
*/
static int
bhnd_pcie2_wars_hwup(struct bhnd_pcie2hb_softc *sc)
{
// TODO
return (ENXIO);
}
/**
* Apply any hardware workarounds that are required upon detach or suspend
* of the bridge device.
*/
static int
bhnd_pcie2_wars_hwdown(struct bhnd_pcie2hb_softc *sc)
{
// TODO
return (ENXIO);
}
static device_method_t bhnd_pcie2_hostb_methods[] = {
/* Device interface */
DEVMETHOD(device_attach, bhnd_pcie2_hostb_attach),
DEVMETHOD(device_detach, bhnd_pcie2_hostb_detach),
DEVMETHOD(device_suspend, bhnd_pcie2_hostb_suspend),
DEVMETHOD(device_resume, bhnd_pcie2_hostb_resume),
DEVMETHOD_END
};
DEFINE_CLASS_1(bhnd_hostb, bhnd_pcie2_hostb_driver,
bhnd_pcie2_hostb_methods, sizeof(struct bhnd_pcie2hb_softc),
bhnd_pcie2_driver);
DRIVER_MODULE(bhnd_pcie2_hostb, bhnd, bhnd_pcie2_hostb_driver, bhnd_hostb_devclass, 0, 0);
MODULE_VERSION(bhnd_pcie2_hostb, 1);
MODULE_DEPEND(bhnd_pcie2_hostb, bhnd, 1, 1, 1);
MODULE_DEPEND(bhnd_pcie2_hostb, bhnd_pcie2, 1, 1, 1);

View file

@ -0,0 +1,72 @@
/*-
* Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
* 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,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
*
* $FreeBSD$
*/
#ifndef _BHND_CORES_PCIE2_BHND_PCI_HOSTBVAR_H_
#define _BHND_CORES_PCIE2_BHND_PCI_HOSTBVAR_H_
/*
* PCIe-Gen2 Host Bridge definitions.
*/
#include <sys/param.h>
#include <sys/bus.h>
#include "bhnd_pcie2_var.h"
DECLARE_CLASS(bhnd_pcie2_hostb_driver);
/*
* PCIe-Gen2 endpoint-mode device quirks
*/
enum {
/**
* The PCIe SerDes output should be configured with an amplitude of
* 1214mVpp and a differential output de-emphasis of -8.46dB.
*
* The exact issue this workaround resolves is unknown.
*/
BHND_PCIE2_QUIRK_SERDES_TXDRV_DEEMPH = (1<<0),
};
/**
* bhnd_pci_hostb driver instance state.
*/
struct bhnd_pcie2hb_softc {
struct bhnd_pcie2_softc common; /**< common bhnd_pcie2 state */
device_t dev;
device_t pci_dev; /**< host PCI device */
uint32_t quirks; /**< hostb device quirks */
};
#endif /* _BHND_CORES_PCIE2_BHND_PCI_HOSTBVAR_H_ */

View file

@ -0,0 +1,228 @@
/*-
* Copyright (c) 2016 Landon Fuller <landon@landonf.org>
* Copyright (c) 2015 Broadcom Corporation
* All rights reserved.
*
* This file is derived from the pcie_core.h and pcie2_core.h headers
* from Broadcom's Linux driver sources as distributed by dd-wrt.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $FreeBSD$
*/
#ifndef _BHND_CORES_PCIE2_BHND_PCIE2_REG_H_
#define _BHND_CORES_PCIE2_BHND_PCIE2_REG_H_
#define BHND_PCIE2_CLK_CONTROL 0x000
#define BHND_PCIE2_RC_PM_CONTROL 0x004
#define BHND_PCIE2_RC_PM_STATUS 0x008
#define BHND_PCIE2_EP_PM_CONTROL 0x00C
#define BHND_PCIE2_EP_PM_STATUS 0x010
#define BHND_PCIE2_EP_LTR_CONTROL 0x014
#define BHND_PCIE2_EP_LTR_STATUS 0x018
#define BHND_PCIE2_EP_OBFF_STATUS 0x01C
#define BHND_PCIE2_PCIE_ERR_STATUS 0x020
#define BHND_PCIE2_RC_AXI_CONFIG 0x100
#define BHND_PCIE2_EP_AXI_CONFIG 0x104
#define BHND_PCIE2_RXDEBUG_STATUS0 0x108
#define BHND_PCIE2_RXDEBUG_CONTROL0 0x10C
#define BHND_PCIE2_CONFIGINDADDR 0x120
#define BHND_PCIE2_CONFIGINDDATA 0x124
#define BHND_PCIE2_CFG_ADDR 0x1F8
#define BHND_PCIE2_CFG_DATA 0x1FC
#define BHND_PCIE2_SYS_EQ_PAGE 0x200
#define BHND_PCIE2_SYS_MSI_PAGE 0x204
#define BHND_PCIE2_SYS_MSI_INTREN 0x208
#define BHND_PCIE2_SYS_MSI_CTRL0 0x210
#define BHND_PCIE2_SYS_MSI_CTRL1 0x214
#define BHND_PCIE2_SYS_MSI_CTRL2 0x218
#define BHND_PCIE2_SYS_MSI_CTRL3 0x21C
#define BHND_PCIE2_SYS_MSI_CTRL4 0x220
#define BHND_PCIE2_SYS_MSI_CTRL5 0x224
#define BHND_PCIE2_SYS_EQ_HEAD0 0x250
#define BHND_PCIE2_SYS_EQ_TAIL0 0x254
#define BHND_PCIE2_SYS_EQ_HEAD1 0x258
#define BHND_PCIE2_SYS_EQ_TAIL1 0x25C
#define BHND_PCIE2_SYS_EQ_HEAD2 0x260
#define BHND_PCIE2_SYS_EQ_TAIL2 0x264
#define BHND_PCIE2_SYS_EQ_HEAD3 0x268
#define BHND_PCIE2_SYS_EQ_TAIL3 0x26C
#define BHND_PCIE2_SYS_EQ_HEAD4 0x270
#define BHND_PCIE2_SYS_EQ_TAIL4 0x274
#define BHND_PCIE2_SYS_EQ_HEAD5 0x278
#define BHND_PCIE2_SYS_EQ_TAIL5 0x27C
#define BHND_PCIE2_SYS_RC_INTX_EN 0x330
#define BHND_PCIE2_SYS_RC_INTX_CSR 0x334
#define BHND_PCIE2_SYS_MSI_REQ 0x340
#define BHND_PCIE2_SYS_HOST_INTR_EN 0x344
#define BHND_PCIE2_SYS_HOST_INTR_CSR 0x348
#define BHND_PCIE2_SYS_HOST_INTR0 0x350
#define BHND_PCIE2_SYS_HOST_INTR1 0x354
#define BHND_PCIE2_SYS_HOST_INTR2 0x358
#define BHND_PCIE2_SYS_HOST_INTR3 0x35C
#define BHND_PCIE2_SYS_EP_INT_EN0 0x360
#define BHND_PCIE2_SYS_EP_INT_EN1 0x364
#define BHND_PCIE2_SYS_EP_INT_CSR0 0x370
#define BHND_PCIE2_SYS_EP_INT_CSR1 0x374
#define BHND_PCIE2_MDIO_CTL 0x128 /**< mdio control */
#define BHND_PCIE2_MDIO_WRDATA 0x12C /**< mdio data write */
#define BHND_PCIE2_MDIO_RDDATA 0x130 /**< mdio data read */
/* DMA doorbell registers (>= rev5) */
#define BHND_PCIE2_DB0_HOST2DEV0 0x140
#define BHND_PCIE2_DB0_HOST2DEV1 0x144
#define BHND_PCIE2_DB0_DEV2HOST0 0x148
#define BHND_PCIE2_DB0_DEV2HOST1 0x14C
#define BHND_PCIE2_DB1_HOST2DEV0 0x150
#define BHND_PCIE2_DB1_HOST2DEV1 0x154
#define BHND_PCIE2_DB1_DEV2HOST0 0x158
#define BHND_PCIE2_DB1_DEV2HOST1 0x15C
#define BHND_PCIE2_DB2_HOST2DEV0 0x160
#define BHND_PCIE2_DB2_HOST2DEV1 0x164
#define BHND_PCIE2_DB2_DEV2HOST0 0x168
#define BHND_PCIE2_DB2_DEV2HOST1 0x16C
#define BHND_PCIE2_DB3_HOST2DEV0 0x170
#define BHND_PCIE2_DB3_HOST2DEV1 0x174
#define BHND_PCIE2_DB3_DEV2HOST0 0x178
#define BHND_PCIE2_DB3_DEV2HOST1 0x17C
#define BHND_PCIE2_DATAINTF 0x180
#define BHND_PCIE2_INTRLAZY0_DEV2HOST 0x188
#define BHND_PCIE2_INTRLAZY0_HOST2DEV 0x18c
#define BHND_PCIE2_INTSTAT0_HOST2DEV 0x190
#define BHND_PCIE2_INTMASK0_HOST2DEV 0x194
#define BHND_PCIE2_INTSTAT0_DEV2HOST 0x198
#define BHND_PCIE2_INTMASK0_DEV2HOST 0x19c
#define BHND_PCIE2_LTR_STATE 0x1A0
#define BHND_PCIE2_PWR_INT_STATUS 0x1A4
#define BHND_PCIE2_PWR_INT_MASK 0x1A8
/* DMA channel registers */
#define BHND_PCIE2_DMA0_HOST2DEV_TX 0x200
#define BHND_PCIE2_DMA0_HOST2DEV_RX 0x220
#define BHND_PCIE2_DMA0_DEV2HOST_TX 0x240
#define BHND_PCIE2_DMA0_DEV2HOST_RX 0x260
#define BHND_PCIE2_DMA1_HOST2DEV_TX 0x280
#define BHND_PCIE2_DMA1_HOST2DEV_RX 0x2A0
#define BHND_PCIE2_DMA1_DEV2HOST_TX 0x2C0
#define BHND_PCIE2_DMA1_DEV2HOST_RX 0x2E0
#define BHND_PCIE2_DMA2_HOST2DEV_TX 0x300
#define BHND_PCIE2_DMA2_HOST2DEV_RX 0x320
#define BHND_PCIE2_DMA2_DEV2HOST_TX 0x340
#define BHND_PCIE2_DMA2_DEV2HOST_RX 0x360
#define BHND_PCIE2_DMA3_HOST2DEV_TX 0x380
#define BHND_PCIE2_DMA3_HOST2DEV_RX 0x3A0
#define BHND_PCIE2_DMA3_DEV2HOST_TX 0x3C0
#define BHND_PCIE2_DMA3_DEV2HOST_RX 0x3E0
#define BHND_PCIE2_PCIE_FUNC0_CFG 0x400 /**< PCIe function 0 config space */
#define BHND_PCIE2_PCIE_FUNC1_CFG 0x500 /**< PCIe function 1 config space */
#define BHND_PCIE2_PCIE_FUNC2_CFG 0x600 /**< PCIe function 2 config space */
#define BHND_PCIE2_PCIE_FUNC3_CFG 0x700 /**< PCIe function 3 config space */
#define BHND_PCIE2_SPROM 0x800 /**< SPROM shadow */
#define BHND_PCIE2_FUNC0_IMAP0_0 0xC00
#define BHND_PCIE2_FUNC0_IMAP0_1 0xC04
#define BHND_PCIE2_FUNC0_IMAP0_2 0xC08
#define BHND_PCIE2_FUNC0_IMAP0_3 0xC0C
#define BHND_PCIE2_FUNC0_IMAP0_4 0xC10
#define BHND_PCIE2_FUNC0_IMAP0_5 0xC14
#define BHND_PCIE2_FUNC0_IMAP0_6 0xC18
#define BHND_PCIE2_FUNC0_IMAP0_7 0xC1C
#define BHND_PCIE2_FUNC1_IMAP0_0 0xC20
#define BHND_PCIE2_FUNC1_IMAP0_1 0xC24
#define BHND_PCIE2_FUNC1_IMAP0_2 0xC28
#define BHND_PCIE2_FUNC1_IMAP0_3 0xC2C
#define BHND_PCIE2_FUNC1_IMAP0_4 0xC30
#define BHND_PCIE2_FUNC1_IMAP0_5 0xC34
#define BHND_PCIE2_FUNC1_IMAP0_6 0xC38
#define BHND_PCIE2_FUNC1_IMAP0_7 0xC3C
#define BHND_PCIE2_FUNC0_IMAP1 0xC80
#define BHND_PCIE2_FUNC1_IMAP1 0xC88
#define BHND_PCIE2_FUNC0_IMAP2 0xCC0
#define BHND_PCIE2_FUNC1_IMAP2 0xCC8
#define BHND_PCIE2_IARR0_LOWER 0xD00
#define BHND_PCIE2_IARR0_UPPER 0xD04
#define BHND_PCIE2_IARR1_LOWER 0xD08
#define BHND_PCIE2_IARR1_UPPER 0xD0C
#define BHND_PCIE2_IARR2_LOWER 0xD10
#define BHND_PCIE2_IARR2_UPPER 0xD14
#define BHND_PCIE2_OARR0 0xD20
#define BHND_PCIE2_OARR1 0xD28
#define BHND_PCIE2_OARR2 0xD30
#define BHND_PCIE2_OMAP0_LOWER 0xD40
#define BHND_PCIE2_OMAP0_UPPER 0xD44
#define BHND_PCIE2_OMAP1_LOWER 0xD48
#define BHND_PCIE2_OMAP1_UPPER 0xD4C
#define BHND_PCIE2_OMAP2_LOWER 0xD50
#define BHND_PCIE2_OMAP2_UPPER 0xD54
#define BHND_PCIE2_FUNC1_IARR1_SIZE 0xD58
#define BHND_PCIE2_FUNC1_IARR2_SIZE 0xD5C
#define BHND_PCIE2_MEM_CONTROL 0xF00
#define BHND_PCIE2_MEM_ECC_ERRLOG0 0xF04
#define BHND_PCIE2_MEM_ECC_ERRLOG1 0xF08
#define BHND_PCIE2_LINK_STATUS 0xF0C
#define BHND_PCIE2_STRAP_STATUS 0xF10
#define BHND_PCIE2_RESET_STATUS 0xF14
#define BHND_PCIE2_RESETEN_IN_LINKDOWN 0xF18
#define BHND_PCIE2_MISC_INTR_EN 0xF1C
#define BHND_PCIE2_TX_DEBUG_CFG 0xF20
#define BHND_PCIE2_MISC_CONFIG 0xF24
#define BHND_PCIE2_MISC_STATUS 0xF28
#define BHND_PCIE2_INTR_EN 0xF30
#define BHND_PCIE2_INTR_CLEAR 0xF34
#define BHND_PCIE2_INTR_STATUS 0xF38
/* BHND_PCIE2_MDIO_CTL */
#define BHND_PCIE2_MDIOCTL_DIVISOR_MASK 0x7f /* clock to be used on MDIO */
#define BHND_PCIE2_MDIOCTL_DIVISOR_VAL 0x2
#define BHND_PCIE2_MDIOCTL_REGADDR_SHIFT 8 /* Regaddr shift */
#define BHND_PCIE2_MDIOCTL_REGADDR_MASK 0x00FFFF00 /* Regaddr Mask */
#define BHND_PCIE2_MDIOCTL_DEVADDR_SHIFT 24 /* Physmedia devaddr shift */
#define BHND_PCIE2_MDIOCTL_DEVADDR_MASK 0x0f000000 /* Physmedia devaddr Mask */
#define BHND_PCIE2_MDIOCTL_SLAVE_BYPASS 0x10000000 /* IP slave bypass */
#define BHND_PCIE2_MDIOCTL_READ 0x20000000 /* IP slave bypass */
/* BHND_PCIE2_MDIO_DATA */
#define BHND_PCIE2_MDIODATA_DONE 0x80000000 /* rd/wr transaction done */
#define BHND_PCIE2_MDIODATA_MASK 0x7FFFFFFF /* rd/wr transaction data */
#define BHND_PCIE2_MDIODATA_DEVADDR_SHIFT 4 /* Physmedia devaddr shift */
/* BHND_PCIE2_DMA[0-4]_HOST2DEV_(TX|RX) per-channel register offsets */
#define BHND_PCIE2_DMA_CTRL 0x0 /**< enable, et al */
#define BHND_PCIE2_DMA_PTR 0x4 /**< last descriptor posted to chip */
#define BHND_PCIE2_DMA_ADDRL 0x8 /**< descriptor ring base address low 32-bits (8K aligned) */
#define BHND_PCIE2_DMA_ADDRH 0xC /**< descriptor ring base address bits 63:32 (8K aligned) */
#define BHND_PCIE2_DMA_STATUS0 0x10 /**< current descriptor, xmt state */
#define BHND_PCIE2_DMA_STATUS1 0x10 /**< active descriptor, xmt error */
#endif /* _BHND_CORES_PCIE2_BHND_PCIE2_REG_H_ */

View file

@ -0,0 +1,98 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* 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,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
*
* $FreeBSD$
*/
#ifndef _BHND_CORES_PCIE2_BHND_PCIE2_VAR_H_
#define _BHND_CORES_PCIE2_BHND_PCIE2_VAR_H_
#include <sys/param.h>
#include <sys/bus.h>
/*
* Shared PCIe-G2 Bridge/Host Bridge definitions.
*/
DECLARE_CLASS(bhnd_pcie2_driver);
struct bhnd_pcie2_softc;
int bhnd_pcie2_generic_probe(device_t dev);
int bhnd_pcie2_generic_attach(device_t dev);
int bhnd_pcie2_generic_detach(device_t dev);
int bhnd_pcie2_generic_suspend(device_t dev);
int bhnd_pcie2_generic_resume(device_t dev);
uint32_t bhnd_pcie2_read_proto_reg(struct bhnd_pcie2_softc *sc,
uint32_t addr);
void bhnd_pcie2_write_proto_reg(struct bhnd_pcie2_softc *sc,
uint32_t addr, uint32_t val);
int bhnd_pcie2_mdio_read(struct bhnd_pcie2_softc *sc, int phy,
int reg);
int bhnd_pcie2_mdio_write(struct bhnd_pcie2_softc *sc, int phy,
int reg, int val);
int bhnd_pcie2_mdio_read_ext(struct bhnd_pcie2_softc *sc, int phy,
int devaddr, int reg);
int bhnd_pcie2_mdio_write_ext(struct bhnd_pcie2_softc *sc,
int phy, int devaddr, int reg, int val);
/**
* bhnd_pcie2 child device info
*/
struct bhnd_pcie2_devinfo {
struct resource_list resources;
};
/*
* Generic PCIe-G2 bridge/end-point driver state.
*
* Must be first member of all subclass softc structures.
*/
struct bhnd_pcie2_softc {
device_t dev; /**< pci device */
uint32_t quirks; /**< quirk flags */
struct mtx mtx; /**< state mutex used to protect
interdependent register
accesses. */
struct bhnd_resource *mem_res; /**< device register block. */
int mem_rid; /**< register block RID */
};
#define BHND_PCIE2_LOCK_INIT(sc) \
mtx_init(&(sc)->mtx, device_get_nameunit((sc)->dev), \
"BHND PCIe-G2 driver lock", MTX_DEF)
#define BHND_PCIE2_LOCK(sc) mtx_lock(&(sc)->mtx)
#define BHND_PCIE2_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
#define BHND_PCIE2_LOCK_ASSERT(sc, what) mtx_assert(&(sc)->mtx, what)
#define BHND_PCIE2_LOCK_DESTROY(sc) mtx_destroy(&(sc)->mtx)
#endif /* _BHND_CORES_PCIE2_BHND_PCIE2_VAR_H_ */

View file

@ -0,0 +1,98 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* 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,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* Broadcom PCI/PCIe-Gen1 Host-PCI bridge.
*
* This driver handles all interactions with PCI bridge cores operating in
* root complex mode.
*/
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/module.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
#include <dev/bhnd/bhnd.h>
#include "bhnd_pcie2_reg.h"
#include "bhnd_pcie2b_var.h"
static int
bhnd_pcie2b_attach(device_t dev)
{
// TODO
return (bhnd_pcie2_generic_attach(dev));
}
static int
bhnd_pcie2b_detach(device_t dev)
{
// TODO
return (bhnd_pcie2_generic_detach(dev));
}
static int
bhnd_pcie2b_suspend(device_t dev)
{
return (bhnd_pcie2_generic_suspend(dev));
}
static int
bhnd_pcie2b_resume(device_t dev)
{
return (bhnd_pcie2_generic_resume(dev));
}
static device_method_t bhnd_pcie2b_methods[] = {
/* Device interface */
DEVMETHOD(device_attach, bhnd_pcie2b_attach),
DEVMETHOD(device_detach, bhnd_pcie2b_detach),
DEVMETHOD(device_suspend, bhnd_pcie2b_suspend),
DEVMETHOD(device_resume, bhnd_pcie2b_resume),
DEVMETHOD_END
};
DEFINE_CLASS_1(pcib, bhnd_pcie2b_driver, bhnd_pcie2b_methods,
sizeof(struct bhnd_pcie2b_softc), bhnd_pcie2_driver);
static devclass_t pcib_devclass;
DRIVER_MODULE(bhnd_pcie2b, bhnd, bhnd_pcie2b_driver, pcib_devclass, 0, 0);
MODULE_VERSION(bhnd_pcie2b, 1);
MODULE_DEPEND(bhnd_pcie2b, bhnd, 1, 1, 1);
MODULE_DEPEND(bhnd_pcie2b, bhnd_pcie2, 1, 1, 1);
MODULE_DEPEND(bhnd_pcie2b, pci, 1, 1, 1);

View file

@ -0,0 +1,42 @@
/*-
* Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
* 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,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
*
* $FreeBSD$
*/
#ifndef _BHND_CORES_PCIE2_BHND_PCIE2BVAR_H_
#define _BHND_CORES_PCIE2_BHND_PCIE2BVAR_H_
#include "bhnd_pcie2_var.h"
/* PCIe-G2 bridge driver-specific state */
struct bhnd_pcie2b_softc {
struct bhnd_pcie2_softc sc_common;
};
#endif /* _BHND_CORES_PCIE2_BHND_PCIE2BVAR_H_ */

View file

@ -55,15 +55,13 @@ int
siba_attach(device_t dev)
{
struct siba_devinfo *dinfo;
struct siba_softc *sc;
device_t *devs;
int ndevs;
int error;
// TODO: We need to set the initiator timeout for the
// core that will be issuing requests to non-memory locations.
//
// In the case of a bridged device, this is the hostb core.
// On a non-bridged device, this will be the CPU.
sc = device_get_softc(dev);
sc->dev = dev;
/* Fetch references to the siba SIBA_CFG* blocks for all
* registered devices */
@ -144,6 +142,18 @@ siba_detach(device_t dev)
return (bhnd_generic_detach(dev));
}
int
siba_resume(device_t dev)
{
return (bhnd_generic_resume(dev));
}
int
siba_suspend(device_t dev)
{
return (bhnd_generic_suspend(dev));
}
static int
siba_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
{
@ -663,6 +673,8 @@ static device_method_t siba_methods[] = {
DEVMETHOD(device_probe, siba_probe),
DEVMETHOD(device_attach, siba_attach),
DEVMETHOD(device_detach, siba_detach),
DEVMETHOD(device_resume, siba_resume),
DEVMETHOD(device_suspend, siba_suspend),
/* Bus interface */
DEVMETHOD(bus_child_deleted, siba_child_deleted),

View file

@ -34,11 +34,13 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <dev/bhnd/bhnd_ids.h>
#include <dev/bhnd/bhndb/bhndbvar.h>
#include <dev/bhnd/bhndb/bhndb_hwdata.h>
#include "sibareg.h"
#include "sibavar.h"
/*
@ -56,6 +58,20 @@ __FBSDID("$FreeBSD$");
// than delegating to our parent bhndb device.
//
static int siba_bhndb_wars_hwup(struct siba_softc *sc);
enum {
/** When PCIe-bridged, the D11 core's initiator request
* timeout must be disabled to prevent D11 from entering a
* RESP_TIMEOUT error state. */
SIBA_QUIRK_PCIE_D11_SB_TIMEOUT = (1<<0)
};
static struct bhnd_chip_quirk chip_quirks[] = {
{{ BHND_CHIP_IR(4311, HWREV_EQ(2)) }, SIBA_QUIRK_PCIE_D11_SB_TIMEOUT },
{{ BHND_CHIP_IR(4312, HWREV_EQ(0)) }, SIBA_QUIRK_PCIE_D11_SB_TIMEOUT },
};
static int
siba_bhndb_probe(device_t dev)
{
@ -94,7 +110,30 @@ siba_bhndb_attach(device_t dev)
sc->hostb_dev = BHNDB_FIND_HOSTB_DEVICE(device_get_parent(dev), dev);
/* Call our superclass' implementation */
return (siba_attach(dev));
if ((error = siba_attach(dev)))
return (error);
/* Apply attach/resume work-arounds */
if ((error = siba_bhndb_wars_hwup(sc)))
return (error);
return (0);
}
static int
siba_bhndb_resume(device_t dev)
{
struct siba_softc *sc;
int error;
sc = device_get_softc(dev);
/* Apply attach/resume work-arounds */
if ((error = siba_bhndb_wars_hwup(sc)))
return (error);
/* Call our superclass' implementation */
return (siba_resume(dev));
}
/* Suspend all references to the device's cfg register blocks */
@ -180,10 +219,67 @@ siba_bhndb_read_board_info(device_t dev, device_t child,
return (BHNDB_POPULATE_BOARD_INFO(device_get_parent(dev), dev, info));
}
/* Work-around implementation for SIBA_QUIRK_PCIE_D11_SB_TIMEOUT */
static int
siba_bhndb_wars_pcie_clear_d11_timeout(struct siba_softc *sc)
{
struct siba_devinfo *dinfo;
device_t d11;
uint32_t imcfg;
/* Only applies when bridged by PCIe */
if (bhnd_get_class(sc->hostb_dev) != BHND_DEVCLASS_PCIE)
return (0);
/* Only applies if there's a D11 core */
d11 = bhnd_match_child(sc->dev, &(struct bhnd_core_match){
.vendor = BHND_MFGID_BCM,
.device = BHND_COREID_D11,
.hwrev = BHND_HWREV_ANY,
.class = BHND_DEVCLASS_INVALID,
.unit = 0
});
if (d11 == NULL)
return (0);
/* Clear initiator timeout in D11's CFG0 block */
dinfo = device_get_ivars(d11);
KASSERT(dinfo->cfg[0] != NULL, ("missing core config mapping"));
imcfg = bhnd_bus_read_4(dinfo->cfg[0], SIBA_CFG0_IMCONFIGLOW);
imcfg &= ~SIBA_IMCL_RTO_MASK;
bhnd_bus_write_4(dinfo->cfg[0], SIBA_CFG0_IMCONFIGLOW, imcfg);
return (0);
}
/**
* Apply any hardware workarounds that are required upon attach or resume
* of the bus.
*/
static int
siba_bhndb_wars_hwup(struct siba_softc *sc)
{
uint32_t quirks;
int error;
quirks = bhnd_chip_quirks(sc->hostb_dev, chip_quirks);
if (quirks & SIBA_QUIRK_PCIE_D11_SB_TIMEOUT) {
if ((error = siba_bhndb_wars_pcie_clear_d11_timeout(sc)))
return (error);
}
return (0);
}
static device_method_t siba_bhndb_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, siba_bhndb_probe),
DEVMETHOD(device_attach, siba_bhndb_attach),
DEVMETHOD(device_resume, siba_bhndb_resume),
/* Bus interface */
DEVMETHOD(bus_suspend_child, siba_bhndb_suspend_child),

View file

@ -53,6 +53,8 @@ struct siba_core_id;
int siba_probe(device_t dev);
int siba_attach(device_t dev);
int siba_detach(device_t dev);
int siba_resume(device_t dev);
int siba_suspend(device_t dev);
uint16_t siba_get_bhnd_mfgid(uint16_t ocp_vendor);
@ -145,6 +147,7 @@ struct siba_devinfo {
/** siba(4) per-instance state */
struct siba_softc {
struct bhnd_softc bhnd_sc; /**< bhnd state */
device_t dev; /**< siba device */
device_t hostb_dev; /**< host bridge core, or NULL */
};

View file

@ -1,9 +1,10 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../../../dev/bhnd/cores/pci
.PATH: ${.CURDIR}/../../../../dev/bhnd/cores/pcie2
KMOD= bhnd_pci
SRCS= bhnd_pci.c
SRCS= bhnd_pci.c bhnd_pcie2.c
SRCS+= device_if.h bus_if.h bhnd_bus_if.h
.include <bsd.kmod.mk>

View file

@ -1,9 +1,11 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../../../dev/bhnd/cores/pci
.PATH: ${.CURDIR}/../../../../dev/bhnd/cores/pcie2
KMOD= bhnd_pci_hostb
SRCS= bhnd_pci_hostb.c
SRCS+= device_if.h bus_if.h bhnd_bus_if.h
SRCS= bhnd_pci_hostb.c bhnd_pcie2_hostb.c
SRCS+= device_if.h bus_if.h pci_if.h \
bhnd_bus_if.h bhnd_chipc_if.h
.include <bsd.kmod.mk>

View file

@ -1,9 +1,11 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../../../dev/bhnd/cores/pci
.PATH: ${.CURDIR}/../../../../dev/bhnd/cores/pcie2
KMOD= bhnd_pcib
SRCS= bhnd_pcib.c
SRCS+= device_if.h bus_if.h bhnd_bus_if.h
SRCS= bhnd_pcib.c bhnd_pcie2b.c
SRCS+= device_if.h bus_if.h pci_if.h \
bhnd_bus_if.h
.include <bsd.kmod.mk>