Page MenuHomeFreeBSD

D6377.id16435.diff
No OneTemporary

D6377.id16435.diff

Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -1142,6 +1142,9 @@
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
Index: sys/dev/bhnd/bhnd.h
===================================================================
--- sys/dev/bhnd/bhnd.h
+++ sys/dev/bhnd/bhnd.h
@@ -318,8 +318,8 @@
.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 @@
/** 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_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,
Index: sys/dev/bhnd/bhnd_ids.h
===================================================================
--- sys/dev/bhnd/bhnd_ids.h
+++ sys/dev/bhnd/bhnd_ids.h
@@ -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
Index: sys/dev/bhnd/bhnd_subr.c
===================================================================
--- sys/dev/bhnd/bhnd_subr.c
+++ sys/dev/bhnd/bhnd_subr.c
@@ -350,6 +350,56 @@
}
/**
+ * 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.
*
* @param cores The table to search.
Index: sys/dev/bhnd/bhndb/bhndb_pci.c
===================================================================
--- sys/dev/bhnd/bhndb/bhndb_pci.c
+++ sys/dev/bhnd/bhndb/bhndb_pci.c
@@ -37,9 +37,10 @@
* 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 @@
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 @@
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 @@
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);
Index: sys/dev/bhnd/bhndb/bhndb_pcireg.h
===================================================================
--- sys/dev/bhnd/bhndb/bhndb_pcireg.h
+++ sys/dev/bhnd/bhndb/bhndb_pcireg.h
@@ -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 */
Index: sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m
===================================================================
--- sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m
+++ sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m
@@ -43,4 +43,23 @@
*/
METHOD bhnd_nvram_src_t nvram_src {
device_t dev;
-}
\ No newline at end of file
+}
+
+/**
+ * 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;
+}
Index: sys/dev/bhnd/cores/chipc/chipc.c
===================================================================
--- sys/dev/bhnd/cores/chipc/chipc.c
+++ sys/dev/bhnd/cores/chipc/chipc.c
@@ -489,20 +489,38 @@
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
};
Index: sys/dev/bhnd/cores/pci/bhnd_pci.c
===================================================================
--- sys/dev/bhnd/cores/pci/bhnd_pci.c
+++ sys/dev/bhnd/cores/pci/bhnd_pci.c
@@ -429,8 +429,7 @@
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 @@
/* 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 @@
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 @@
/* 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);
Index: sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c
===================================================================
--- sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c
+++ sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c
@@ -56,28 +56,43 @@
#include <dev/bhnd/bhnd.h>
-#include "bhnd_pcireg.h"
-#include "bhnd_pci_hostbvar.h"
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
-#define BHND_PCI_ASSERT_QUIRK(_sc, _name) \
- KASSERT((_sc)->quirks & (_name), ("quirk " __STRING(_name) " not set"))
+#include <dev/bhnd/cores/chipc/chipc.h>
+#include <dev/bhnd/cores/chipc/chipcreg.h>
-#define BHND_PCI_DEV(_core, _quirks, _chip_quirks) \
- BHND_DEVICE(_core, "", _quirks, _chip_quirks, BHND_DF_HOSTB)
+#include "bhnd_pcireg.h"
+#include "bhnd_pci_hostbvar.h"
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 @@
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 @@
{ 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 @@
#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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
* 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_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 @@
}
}
+ /* 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 @@
* 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_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 @@
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);
Index: sys/dev/bhnd/cores/pci/bhnd_pci_hostbvar.h
===================================================================
--- sys/dev/bhnd/cores/pci/bhnd_pci_hostbvar.h
+++ sys/dev/bhnd/cores/pci/bhnd_pci_hostbvar.h
@@ -43,7 +43,7 @@
DECLARE_CLASS(bhnd_pci_hostb_driver);
-/*
+/**
* PCI/PCIe-Gen1 endpoint-mode device quirks
*/
enum {
@@ -56,7 +56,6 @@
*/
BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST = (1<<1),
-
/**
* SBTOPCI_RC_READMULTI must be set on the SSB_PCICORE_SBTOPCI2
* register.
@@ -74,18 +73,24 @@
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 @@
* 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.
+ *
+ * Suspend:
+ * - Clear ASPM L1 flag in the PCIER_LINK_CTL register.
+ * - Set CLKREQ (ECPM) flag in the 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.
+ * 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 @@
* 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 @@
*
* 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 @@
};
-#endif /* _BHND_CORES_PCI_BHND_PCI_HOSTBVAR_H_ */
\ No newline at end of file
+#endif /* _BHND_CORES_PCI_BHND_PCI_HOSTBVAR_H_ */
Index: sys/dev/bhnd/cores/pci/bhnd_pcib.c
===================================================================
--- sys/dev/bhnd/cores/pci/bhnd_pcib.c
+++ sys/dev/bhnd/cores/pci/bhnd_pcib.c
@@ -86,8 +86,10 @@
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);
Index: sys/dev/bhnd/cores/pci/bhnd_pcireg.h
===================================================================
--- sys/dev/bhnd/cores/pci/bhnd_pcireg.h
+++ sys/dev/bhnd/cores/pci/bhnd_pcireg.h
@@ -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 */
Index: sys/dev/bhnd/cores/pcie2/bhnd_pcie2.c
===================================================================
--- /dev/null
+++ sys/dev/bhnd/cores/pcie2/bhnd_pcie2.c
@@ -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);
Index: sys/dev/bhnd/cores/pcie2/bhnd_pcie2_hostb.c
===================================================================
--- /dev/null
+++ sys/dev/bhnd/cores/pcie2/bhnd_pcie2_hostb.c
@@ -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);
Index: sys/dev/bhnd/cores/pcie2/bhnd_pcie2_hostbvar.h
===================================================================
--- /dev/null
+++ sys/dev/bhnd/cores/pcie2/bhnd_pcie2_hostbvar.h
@@ -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_ */
\ No newline at end of file
Index: sys/dev/bhnd/cores/pcie2/bhnd_pcie2_reg.h
===================================================================
--- /dev/null
+++ sys/dev/bhnd/cores/pcie2/bhnd_pcie2_reg.h
@@ -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_ */
Index: sys/dev/bhnd/cores/pcie2/bhnd_pcie2_var.h
===================================================================
--- /dev/null
+++ sys/dev/bhnd/cores/pcie2/bhnd_pcie2_var.h
@@ -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_ */
\ No newline at end of file
Index: sys/dev/bhnd/cores/pcie2/bhnd_pcie2b.c
===================================================================
--- /dev/null
+++ sys/dev/bhnd/cores/pcie2/bhnd_pcie2b.c
@@ -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);
Index: sys/dev/bhnd/cores/pcie2/bhnd_pcie2b_var.h
===================================================================
--- /dev/null
+++ sys/dev/bhnd/cores/pcie2/bhnd_pcie2b_var.h
@@ -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_ */
\ No newline at end of file
Index: sys/dev/bhnd/siba/siba.c
===================================================================
--- sys/dev/bhnd/siba/siba.c
+++ sys/dev/bhnd/siba/siba.c
@@ -55,15 +55,13 @@
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 @@
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 @@
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),
Index: sys/dev/bhnd/siba/siba_bhndb.c
===================================================================
--- sys/dev/bhnd/siba/siba_bhndb.c
+++ sys/dev/bhnd/siba/siba_bhndb.c
@@ -34,11 +34,13 @@
#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 @@
// 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 @@
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 @@
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),
Index: sys/dev/bhnd/siba/sibavar.h
===================================================================
--- sys/dev/bhnd/siba/sibavar.h
+++ sys/dev/bhnd/siba/sibavar.h
@@ -53,6 +53,8 @@
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 @@
/** 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 */
};
Index: sys/modules/bhnd/cores/bhnd_pci/Makefile
===================================================================
--- sys/modules/bhnd/cores/bhnd_pci/Makefile
+++ sys/modules/bhnd/cores/bhnd_pci/Makefile
@@ -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>
Index: sys/modules/bhnd/cores/bhnd_pci_hostb/Makefile
===================================================================
--- sys/modules/bhnd/cores/bhnd_pci_hostb/Makefile
+++ sys/modules/bhnd/cores/bhnd_pci_hostb/Makefile
@@ -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>
Index: sys/modules/bhnd/cores/bhnd_pcib/Makefile
===================================================================
--- sys/modules/bhnd/cores/bhnd_pcib/Makefile
+++ sys/modules/bhnd/cores/bhnd_pcib/Makefile
@@ -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>

File Metadata

Mime Type
text/plain
Expires
Sat, Oct 11, 4:18 PM (19 h, 50 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
23583742
Default Alt Text
D6377.id16435.diff (84 KB)

Event Timeline