Index: head/sys/conf/files =================================================================== --- head/sys/conf/files +++ head/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: head/sys/dev/bhnd/bhnd.h =================================================================== --- head/sys/dev/bhnd/bhnd.h +++ head/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: head/sys/dev/bhnd/bhnd_ids.h =================================================================== --- head/sys/dev/bhnd/bhnd_ids.h +++ head/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: head/sys/dev/bhnd/bhnd_subr.c =================================================================== --- head/sys/dev/bhnd/bhnd_subr.c +++ head/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: head/sys/dev/bhnd/bhndb/bhndb_pci.c =================================================================== --- head/sys/dev/bhnd/bhndb/bhndb_pci.c +++ head/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 @@ -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: head/sys/dev/bhnd/bhndb/bhndb_pcireg.h =================================================================== --- head/sys/dev/bhnd/bhndb/bhndb_pcireg.h +++ head/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: head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m =================================================================== --- head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m +++ head/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: head/sys/dev/bhnd/cores/chipc/chipc.c =================================================================== --- head/sys/dev/bhnd/cores/chipc/chipc.c +++ head/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: head/sys/dev/bhnd/cores/pci/bhnd_pci.c =================================================================== --- head/sys/dev/bhnd/cores/pci/bhnd_pci.c +++ head/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: head/sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c =================================================================== --- head/sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c +++ head/sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c @@ -56,28 +56,43 @@ #include -#include "bhnd_pcireg.h" -#include "bhnd_pci_hostbvar.h" +#include +#include -#define BHND_PCI_ASSERT_QUIRK(_sc, _name) \ - KASSERT((_sc)->quirks & (_name), ("quirk " __STRING(_name) " not set")) +#include +#include -#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: head/sys/dev/bhnd/cores/pci/bhnd_pci_hostbvar.h =================================================================== --- head/sys/dev/bhnd/cores/pci/bhnd_pci_hostbvar.h +++ head/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. - * - * Detach/Suspend: - * - - * - When the device enters D3 state, or system enters S3/S4 state, - * clear ASPM L1 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: + * - 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: head/sys/dev/bhnd/cores/pci/bhnd_pcib.c =================================================================== --- head/sys/dev/bhnd/cores/pci/bhnd_pcib.c +++ head/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: head/sys/dev/bhnd/cores/pci/bhnd_pcireg.h =================================================================== --- head/sys/dev/bhnd/cores/pci/bhnd_pcireg.h +++ head/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: head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2.c =================================================================== --- head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2.c +++ head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2.c @@ -0,0 +1,289 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * 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 +__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 +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#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: head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2_hostb.c =================================================================== --- head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2_hostb.c +++ head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2_hostb.c @@ -0,0 +1,254 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * 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 +__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 +#include + +#include + +#include +#include + +#include + +#include +#include +#include + +#include + +#include +#include + +#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: head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2_hostbvar.h =================================================================== --- head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2_hostbvar.h +++ head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2_hostbvar.h @@ -0,0 +1,72 @@ +/*- + * Copyright (c) 2015-2016 Landon Fuller + * 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 +#include + +#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: head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2_reg.h =================================================================== --- head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2_reg.h +++ head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2_reg.h @@ -0,0 +1,228 @@ +/*- + * Copyright (c) 2016 Landon Fuller + * 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: head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2_var.h =================================================================== --- head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2_var.h +++ head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2_var.h @@ -0,0 +1,98 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * 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 +#include + +/* + * 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: head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2b.c =================================================================== --- head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2b.c +++ head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2b.c @@ -0,0 +1,98 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * 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 +__FBSDID("$FreeBSD$"); + +/* + * Broadcom PCI/PCIe-Gen1 Host-PCI bridge. + * + * This driver handles all interactions with PCI bridge cores operating in + * root complex mode. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#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: head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2b_var.h =================================================================== --- head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2b_var.h +++ head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2b_var.h @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2015-2016 Landon Fuller + * 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: head/sys/dev/bhnd/siba/siba.c =================================================================== --- head/sys/dev/bhnd/siba/siba.c +++ head/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: head/sys/dev/bhnd/siba/siba_bhndb.c =================================================================== --- head/sys/dev/bhnd/siba/siba_bhndb.c +++ head/sys/dev/bhnd/siba/siba_bhndb.c @@ -34,11 +34,13 @@ #include #include #include +#include #include #include #include +#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: head/sys/dev/bhnd/siba/sibavar.h =================================================================== --- head/sys/dev/bhnd/siba/sibavar.h +++ head/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: head/sys/modules/bhnd/cores/bhnd_pci/Makefile =================================================================== --- head/sys/modules/bhnd/cores/bhnd_pci/Makefile +++ head/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 Index: head/sys/modules/bhnd/cores/bhnd_pci_hostb/Makefile =================================================================== --- head/sys/modules/bhnd/cores/bhnd_pci_hostb/Makefile +++ head/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 Index: head/sys/modules/bhnd/cores/bhnd_pcib/Makefile =================================================================== --- head/sys/modules/bhnd/cores/bhnd_pcib/Makefile +++ head/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