mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
[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:
parent
32f8bbf8cd
commit
8ef24a0d4b
26 changed files with 1745 additions and 201 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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_ */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
289
sys/dev/bhnd/cores/pcie2/bhnd_pcie2.c
Normal file
289
sys/dev/bhnd/cores/pcie2/bhnd_pcie2.c
Normal 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);
|
||||
254
sys/dev/bhnd/cores/pcie2/bhnd_pcie2_hostb.c
Normal file
254
sys/dev/bhnd/cores/pcie2/bhnd_pcie2_hostb.c
Normal 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);
|
||||
72
sys/dev/bhnd/cores/pcie2/bhnd_pcie2_hostbvar.h
Normal file
72
sys/dev/bhnd/cores/pcie2/bhnd_pcie2_hostbvar.h
Normal 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_ */
|
||||
228
sys/dev/bhnd/cores/pcie2/bhnd_pcie2_reg.h
Normal file
228
sys/dev/bhnd/cores/pcie2/bhnd_pcie2_reg.h
Normal 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_ */
|
||||
98
sys/dev/bhnd/cores/pcie2/bhnd_pcie2_var.h
Normal file
98
sys/dev/bhnd/cores/pcie2/bhnd_pcie2_var.h
Normal 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_ */
|
||||
98
sys/dev/bhnd/cores/pcie2/bhnd_pcie2b.c
Normal file
98
sys/dev/bhnd/cores/pcie2/bhnd_pcie2b.c
Normal 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);
|
||||
42
sys/dev/bhnd/cores/pcie2/bhnd_pcie2b_var.h
Normal file
42
sys/dev/bhnd/cores/pcie2/bhnd_pcie2b_var.h
Normal 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_ */
|
||||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in a new issue