Date: Fri, 22 Apr 2016 16:26:53 +0000 (UTC) From: Adrian Chadd <adrian@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r298479 - in head/sys: dev/bhnd/bhndb dev/bhnd/cores/chipc dev/bhnd/cores/pci dev/bhnd/siba modules/bhnd/cores/bhnd_pci Message-ID: <201604221626.u3MGQr1w091608@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: adrian Date: Fri Apr 22 16:26:53 2016 New Revision: 298479 URL: https://svnweb.freebsd.org/changeset/base/298479 Log: [bhnd] Add a common bhnd_pci driver shared by both bhnd_pcib and bhnd_pci_hostb This extracts common code from bhndb_pci, bhnd_pcib, and bhnd_pci_hostb into a simpler shared bhnd_pci base driver, and should enable SoC-side implementation of bhnd_pcib root complex support. Submitted by: Landon Fuller <landonf@landonf.org> Differential Revision: https://reviews.freebsd.org/D5763 Added: head/sys/dev/bhnd/cores/pci/bhnd_pci_hostbvar.h (contents, props changed) Deleted: head/sys/dev/bhnd/cores/pci/mdio_pcie.c head/sys/dev/bhnd/cores/pci/mdio_pciereg.h head/sys/dev/bhnd/cores/pci/mdio_pcievar.h Modified: head/sys/dev/bhnd/bhndb/bhndb_pci.c head/sys/dev/bhnd/bhndb/bhndb_pcivar.h head/sys/dev/bhnd/cores/chipc/chipc.c head/sys/dev/bhnd/cores/pci/bhnd_pci.c head/sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c head/sys/dev/bhnd/cores/pci/bhnd_pcib.c head/sys/dev/bhnd/cores/pci/bhnd_pcibvar.h head/sys/dev/bhnd/cores/pci/bhnd_pcireg.h head/sys/dev/bhnd/cores/pci/bhnd_pcivar.h head/sys/dev/bhnd/siba/siba_bhndb.c head/sys/modules/bhnd/cores/bhnd_pci/Makefile Modified: head/sys/dev/bhnd/bhndb/bhndb_pci.c ============================================================================== --- head/sys/dev/bhnd/bhndb/bhndb_pci.c Fri Apr 22 16:20:58 2016 (r298478) +++ head/sys/dev/bhnd/bhndb/bhndb_pci.c Fri Apr 22 16:26:53 2016 (r298479) @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2015 Landon Fuller <landon@landonf.org> + * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,27 +37,11 @@ __FBSDID("$FreeBSD$"); * bus (e.g. bcma or siba) via a Broadcom PCI core configured in end-point * mode. * - * This driver handles all interactions with the PCI bridge core. On the - * bridged bhnd bus, the PCI core device will be claimed by a simple - * bhnd_hostb driver. + * 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. */ -// Quirk TODO -// WARs for the following are not yet implemented: -// - BHND_PCI_QUIRK_SBINTVEC -// - BHND_PCIE_QUIRK_ASPM_OVR -// - 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) - #include <sys/param.h> #include <sys/kernel.h> #include <sys/bus.h> @@ -72,7 +56,6 @@ __FBSDID("$FreeBSD$"); #include <dev/bhnd/bhnd.h> #include <dev/bhnd/cores/pci/bhnd_pcireg.h> -#include <dev/bhnd/cores/pci/mdio_pcievar.h> #include "bhndb_pcireg.h" #include "bhndb_pcivar.h" @@ -86,128 +69,8 @@ static int bhndb_pci_compat_setregwin(st static int bhndb_pci_fast_setregwin(struct bhndb_pci_softc *, const struct bhndb_regwin *, bhnd_addr_t); -static uint32_t bhndb_pcie_read_proto_reg(struct bhndb_pci_softc *sc, - uint32_t addr); -static void bhndb_pcie_write_proto_reg(struct bhndb_pci_softc *sc, - uint32_t addr, uint32_t val); - static void bhndb_init_sromless_pci_config(struct bhndb_pci_softc *sc); -static int bhndb_pci_wars_register_access(struct bhndb_pci_softc *sc); -static int bhndb_pci_wars_early_once(struct bhndb_pci_softc *sc); -static int bhndb_pci_wars_hwup(struct bhndb_pci_softc *sc); -static int bhndb_pci_wars_hwdown(struct bhndb_pci_softc *sc); - -static uint32_t bhndb_pci_discover_quirks(struct bhndb_pci_softc *, - const struct bhndb_pci_id *); - -static const struct bhndb_pci_id *bhndb_pci_find_core_id( - struct bhnd_core_info *core); -/* - * Supported PCI bridge cores. - * - * This table defines quirks specific to core hwrev ranges; see also - * bhndb_pci_discover_quirks() for additional quirk detection. - */ -static const struct bhndb_pci_id bhndb_pci_ids[] = { - /* PCI */ - { BHND_COREID_PCI, BHND_PCI_REGFMT_PCI, - (struct bhnd_device_quirk[]) { - { BHND_HWREV_GTE (0), - BHNDB_PCI_QUIRK_EXT_CLOCK_GATING | - BHNDB_PCI_QUIRK_SBTOPCI2_PREF_BURST }, - - { BHND_HWREV_RANGE (0, 5), - BHNDB_PCI_QUIRK_SBINTVEC }, - - { BHND_HWREV_GTE (11), - BHNDB_PCI_QUIRK_SBTOPCI2_READMULTI | - BHNDB_PCI_QUIRK_CLKRUN_DSBL }, - - BHND_DEVICE_QUIRK_END - } - }, - - /* PCI Gen 1 */ - { BHND_COREID_PCIE, BHND_PCI_REGFMT_PCIE, - (struct bhnd_device_quirk[]) { - { BHND_HWREV_EQ (0), - BHNDB_PCIE_QUIRK_SDR9_L0s_HANG }, - - { BHND_HWREV_RANGE (0, 1), - BHNDB_PCIE_QUIRK_UR_STATUS_FIX }, - - { BHND_HWREV_EQ (1), - BHNDB_PCIE_QUIRK_PCIPM_REQEN }, - - { BHND_HWREV_RANGE (3, 5), - BHNDB_PCIE_QUIRK_ASPM_OVR | - BHNDB_PCIE_QUIRK_SDR9_POLARITY | - BHNDB_PCIE_QUIRK_SDR9_NO_FREQRETRY }, - - { BHND_HWREV_LTE (6), - BHNDB_PCIE_QUIRK_L1_IDLE_THRESH }, - - { BHND_HWREV_GTE (6), - BHNDB_PCIE_QUIRK_SPROM_L23_PCI_RESET }, - - { BHND_HWREV_EQ (7), - BHNDB_PCIE_QUIRK_SERDES_NOPLLDOWN }, - - { BHND_HWREV_GTE (8), - BHNDB_PCIE_QUIRK_L1_TIMER_PERF }, - - { BHND_HWREV_GTE (10), - BHNDB_PCIE_QUIRK_SD_C22_EXTADDR }, - - BHND_DEVICE_QUIRK_END - } - }, - - { BHND_COREID_INVALID, BHND_PCI_REGFMT_PCI } -}; - - -/* quirk flag convenience macros */ -#define BHNDB_PCI_QUIRK(_sc, _name) \ - ((_sc)->quirks & BHNDB_PCI_QUIRK_ ## _name) -#define BHNDB_PCIE_QUIRK(_sc, _name) \ - ((_sc)->quirks & BHNDB_PCIE_QUIRK_ ## _name) - -#define BHNDB_PCI_ASSERT_QUIRK(_sc, name) \ - KASSERT(BHNDB_PCI_QUIRK((_sc), name), ("quirk " __STRING(_name) " not set")) -#define BHNDB_PCIE_ASSERT_QUIRK(_sc, name) \ - KASSERT(BHNDB_PCIE_QUIRK((_sc), name), ("quirk " __STRING(_name) " not set")) - - -/* bus_(read|write)_* convenience macros */ -#define BHNDB_PCI_READ_2(_sc, _reg) \ - bus_read_2((_sc)->mem_res, (_sc)->mem_off + (_reg)) -#define BHNDB_PCI_READ_4(_sc, _reg) \ - bus_read_4((_sc)->mem_res, (_sc)->mem_off + (_reg)) - -#define BHNDB_PCI_WRITE_2(_sc, _reg, _val) \ - bus_write_2((_sc)->mem_res, (_sc)->mem_off + (_reg), (_val)) -#define BHNDB_PCI_WRITE_4(_sc, _reg, _val) \ - bus_write_4((_sc)->mem_res, (_sc)->mem_off + (_reg), (_val)) - - -/* BHNDB_PCI_REG_* convenience macros */ -#define BPCI_REG_EXTRACT(_rv, _a) BHND_PCI_REG_EXTRACT(_rv, BHND_ ## _a) -#define BPCI_REG_INSERT(_rv, _a, _v) BHND_PCI_REG_INSERT(_rv, BHND_ ## _a, _v) - -#define BPCI_COMMON_REG_EXTRACT(_r, _a) \ - BHND_PCI_COMMON_REG_EXTRACT(sc->regfmt, _r, _a) - -#define BPCI_COMMON_REG_INSERT(_r, _a, _v) \ - BHND_PCI_COMMON_REG_INSERT(sc->regfmt, _r, _a, _v) - -#define BPCI_COMMON_REG(_name) \ - BHND_PCI_COMMON_REG(sc->regfmt, _name) - -#define BPCI_COMMON_REG_OFFSET(_base, _offset) \ - (BPCI_COMMON_REG(_base) + BPCI_COMMON_REG(_offset)) - /** * Default bhndb_pci implementation of device_probe(). * @@ -250,14 +113,8 @@ bhndb_pci_attach(device_t dev) if (pci_find_cap(device_get_parent(dev), PCIY_EXPRESS, ®) == 0) sc->pci_devclass = BHND_DEVCLASS_PCIE; - /* Determine the basic set of applicable quirks. This will be updated - * in bhndb_pci_init_full_config() once the PCI device core has - * been enumerated. */ - sc->quirks = bhndb_pci_discover_quirks(sc, NULL); - - /* Using the discovered quirks, apply any WARs required for basic - * register access. */ - if ((error = bhndb_pci_wars_register_access(sc))) + /* Enable clocks (if supported by this hardware) */ + if ((error = bhndb_enable_pci_clocks(sc))) return (error); /* Use siba(4)-compatible regwin handling until we know @@ -280,438 +137,108 @@ bhndb_pci_attach(device_t dev) return (0); } -/** - * Initialize the full bridge configuration. - * - * This is called during the DEVICE_ATTACH() process by the bridged bhndb(4) - * bus, prior to probe/attachment of child cores. - * - * At this point, we can introspect the enumerated cores, find our host - * bridge device, and apply any bridge-level hardware workarounds required - * for proper operation of the bridged device cores. - */ static int bhndb_pci_init_full_config(device_t dev, device_t child, - const struct bhndb_hw_priority *prio_table) + const struct bhndb_hw_priority *hw_prio_table) { - struct bhnd_core_info core; - const struct bhndb_pci_id *id; - struct bhndb_pci_softc *sc; - struct bhndb_region *pcir; - bhnd_addr_t pcir_addr; - bhnd_size_t pcir_size; - int error; + struct bhndb_pci_softc *sc; + int error; sc = device_get_softc(dev); - /* Let bhndb perform full discovery and initialization of the - * available register windows and bridge resources. */ - if ((error = bhndb_generic_init_full_config(dev, child, prio_table))) + /* Let our parent perform standard initialization first */ + if ((error = bhndb_generic_init_full_config(dev, child, hw_prio_table))) return (error); - /* - * Identify our PCI bridge core, its register family, and any - * applicable hardware quirks. - */ - KASSERT(sc->bhndb.hostb_dev, - ("missing hostb device\n")); - - core = bhnd_get_core_info(sc->bhndb.hostb_dev); - id = bhndb_pci_find_core_id(&core); - if (id == NULL) { - device_printf(dev, "%s %s hostb core is not recognized\n", - bhnd_vendor_name(core.vendor), bhnd_core_name(&core)); - } - - sc->regfmt = id->regfmt; - - /* Now that we've identified the PCI bridge core, we can determine the - * full set of device quirks */ - sc->quirks = bhndb_pci_discover_quirks(sc, id); - - /* - * Determine and save a reference to the bhndb resource and offset - * at which the bridge core's device registers are mapped. - * - * All known bhnd(4) hardware provides a fixed static mapping of - * the PCI core's registers. If this changes in the future -- which - * is unlikely -- this driver will need to be adjusted to use - * dynamic register windows. - */ - - /* Find base address and size of the PCI core's register block. */ - error = bhnd_get_region_addr(sc->bhndb.hostb_dev, BHND_PORT_DEVICE, 0, - 0, &pcir_addr, &pcir_size); - if (error) { - device_printf(dev, - "failed to locate PCI core registers\n"); - return (error); - } - - /* Find the bhndb_region that statically maps this block */ - pcir = bhndb_find_resource_region(sc->bhndb.bus_res, pcir_addr, - pcir_size); - if (pcir == NULL || pcir->static_regwin == NULL) { - device_printf(dev, - "missing static PCI core register window\n"); - return (ENXIO); - } - - /* Save borrowed reference to the mapped PCI core registers */ - sc->mem_off = pcir->static_regwin->win_offset; - sc->mem_res = bhndb_find_regwin_resource(sc->bhndb.bus_res, - pcir->static_regwin); - if (sc->mem_res == NULL || !(rman_get_flags(sc->mem_res) & RF_ACTIVE)) { - device_printf(dev, - "no active resource maps the PCI core register window\n"); - return (ENXIO); - } - - /* Configure a direct bhnd_resource wrapper that we can pass to - * bhnd_resource APIs */ - sc->bhnd_mem_res = (struct bhnd_resource) { - .res = sc->mem_res, - .direct = true - }; - - /* - * Attach MMIO device (if this is a PCIe device), which is used for - * access to the PCIe SerDes required by the quirk workarounds. - */ - if (sc->pci_devclass == BHND_DEVCLASS_PCIE) { - sc->mdio = BUS_ADD_CHILD(dev, 0, - devclass_get_name(bhnd_mdio_pci_devclass), 0); - if (sc->mdio == NULL) - return (ENXIO); - - error = bus_set_resource(sc->mdio, SYS_RES_MEMORY, 0, - rman_get_start(sc->mem_res) + sc->mem_off + - BHND_PCIE_MDIO_CTL, sizeof(uint32_t)*2); - if (error) { - device_printf(dev, "failed to set MDIO resource\n"); - return (error); - } - - if ((error = device_probe_and_attach(sc->mdio))) { - device_printf(dev, "failed to attach MDIO device\n"); - return (error); - } - } - - /* Apply any early one-time quirk workarounds */ - if ((error = bhndb_pci_wars_early_once(sc))) - return (error); - - /* Apply attach-time quirk workarounds, required before the bridged - * bhnd(4) bus itself performs a full attach(). */ - if ((error = bhndb_pci_wars_hwup(sc))) - return (error); - - return (0); -} - -/** - * Apply any hardware workarounds that must be executed prior to attempting - * register access on the bridged chipset. - * - * This must be called very early in attach() or resume(), after the basic - * set of applicable device quirks has been determined. - */ -static int -bhndb_pci_wars_register_access(struct bhndb_pci_softc *sc) -{ - int error; - - if (BHNDB_PCI_QUIRK(sc, EXT_CLOCK_GATING)) { - if ((error = bhndb_enable_pci_clocks(sc))) { - device_printf(sc->dev, "failed to enable clocks\n"); - 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 -bhndb_pci_wars_early_once(struct bhndb_pci_softc *sc) -{ - /* Determine correct polarity by observing the attach-time PCIe PHY - * link status. This is used later to reset/force the SerDes - * polarity */ - if (BHNDB_PCIE_QUIRK(sc, SDR9_POLARITY)) { - uint32_t st; - bool inv; - - - st = bhndb_pcie_read_proto_reg(sc, BHND_PCIE_PLP_STATUSREG); - inv = ((st & BHND_PCIE_PLP_POLARITY_INV) != 0); - sc->sdr9_quirk_polarity.inv = inv; - } - - return (0); -} - -/** - * Apply any hardware workarounds that are required upon attach or resume - * of the bridge device. - */ -static int -bhndb_pci_wars_hwup(struct bhndb_pci_softc *sc) -{ - /* Note that the order here matters; these work-arounds - * should not be re-ordered without careful review of their - * interdependencies */ - - /* Fix up any PoR defaults on SROMless devices */ + /* Fix-up power on defaults for SROM-less devices. */ bhndb_init_sromless_pci_config(sc); - /* Enable PCI prefetch/burst/readmulti flags */ - if (BHNDB_PCI_QUIRK(sc, SBTOPCI2_PREF_BURST) || - BHNDB_PCI_QUIRK(sc, SBTOPCI2_READMULTI)) - { - uint32_t sbp2; - sbp2 = BHNDB_PCI_READ_4(sc, BHND_PCI_SBTOPCI2); - - if (BHNDB_PCI_QUIRK(sc, SBTOPCI2_PREF_BURST)) - sbp2 |= (BHND_PCI_SBTOPCI_PREF|BHND_PCI_SBTOPCI_BURST); - - if (BHNDB_PCI_QUIRK(sc, SBTOPCI2_READMULTI)) - sbp2 |= BHND_PCI_SBTOPCI_RC_READMULTI; - - BHNDB_PCI_WRITE_4(sc, BHND_PCI_SBTOPCI2, sbp2); - } - - /* Disable PCI CLKRUN# */ - if (BHNDB_PCI_QUIRK(sc, CLKRUN_DSBL)) { - uint32_t ctl; - - ctl = BHNDB_PCI_READ_4(sc, BHND_PCI_CLKRUN_CTL); - ctl |= BHND_PCI_CLKRUN_DSBL; - BHNDB_PCI_WRITE_4(sc, BHND_PCI_CLKRUN_CTL, ctl); - } - - /* Enable TLP unmatched address handling work-around */ - if (BHNDB_PCIE_QUIRK(sc, UR_STATUS_FIX)) { - uint32_t wrs; - wrs = bhndb_pcie_read_proto_reg(sc, BHND_PCIE_TLP_WORKAROUNDSREG); - wrs |= BHND_PCIE_TLP_WORKAROUND_URBIT; - bhndb_pcie_write_proto_reg(sc, BHND_PCIE_TLP_WORKAROUNDSREG, wrs); - } - - /* Adjust SerDes CDR tuning to ensure that CDR is stable before sending - * data during L0s to L0 exit transitions. */ - if (BHNDB_PCIE_QUIRK(sc, SDR9_L0s_HANG)) { - uint16_t sdv; - - /* Set RX track/acquire timers to 2.064us/40.96us */ - sdv = BPCI_REG_INSERT(0, PCIE_SDR9_RX_TIMER1_LKTRK, (2064/16)); - sdv = BPCI_REG_INSERT(sdv, PCIE_SDR9_RX_TIMER1_LKACQ, - (40960/1024)); - MDIO_WRITEREG(sc->mdio, BHND_PCIE_PHY_SDR9_TXRX, - BHND_PCIE_SDR9_RX_TIMER1, sdv); - - /* Apply CDR frequency workaround */ - sdv = BHND_PCIE_SDR9_RX_CDR_FREQ_OVR_EN; - sdv = BPCI_REG_INSERT(sdv, PCIE_SDR9_RX_CDR_FREQ_OVR, 0x0); - MDIO_WRITEREG(sc->mdio, BHND_PCIE_PHY_SDR9_TXRX, - BHND_PCIE_SDR9_RX_CDR, sdv); - - /* Apply CDR BW tunings */ - sdv = 0; - sdv = BPCI_REG_INSERT(sdv, PCIE_SDR9_RX_CDRBW_INTGTRK, 0x2); - sdv = BPCI_REG_INSERT(sdv, PCIE_SDR9_RX_CDRBW_INTGACQ, 0x4); - sdv = BPCI_REG_INSERT(sdv, PCIE_SDR9_RX_CDRBW_PROPTRK, 0x6); - sdv = BPCI_REG_INSERT(sdv, PCIE_SDR9_RX_CDRBW_PROPACQ, 0x6); - MDIO_WRITEREG(sc->mdio, BHND_PCIE_PHY_SDR9_TXRX, - BHND_PCIE_SDR9_RX_CDRBW, sdv); - } - - /* Force correct SerDes polarity */ - if (BHNDB_PCIE_QUIRK(sc, SDR9_POLARITY)) { - uint16_t rxctl; - - rxctl = MDIO_READREG(sc->mdio, BHND_PCIE_PHY_SDR9_TXRX, - BHND_PCIE_SDR9_RX_CTRL); - - rxctl |= BHND_PCIE_SDR9_RX_CTRL_FORCE; - if (sc->sdr9_quirk_polarity.inv) - rxctl |= BHND_PCIE_SDR9_RX_CTRL_POLARITY_INV; - else - rxctl &= ~BHND_PCIE_SDR9_RX_CTRL_POLARITY_INV; - - MDIO_WRITEREG(sc->mdio, BHND_PCIE_PHY_SDR9_TXRX, - BHND_PCIE_SDR9_RX_CTRL, rxctl); - } - - /* Disable startup retry on PLL frequency detection failure */ - if (BHNDB_PCIE_QUIRK(sc, SDR9_NO_FREQRETRY)) { - uint16_t pctl; - - pctl = MDIO_READREG(sc->mdio, BHND_PCIE_PHY_SDR9_PLL, - BHND_PCIE_SDR9_PLL_CTRL); - - pctl &= ~BHND_PCIE_SDR9_PLL_CTRL_FREQDET_EN; - MDIO_WRITEREG(sc->mdio, BHND_PCIE_PHY_SDR9_PLL, - BHND_PCIE_SDR9_PLL_CTRL, pctl); - } - - /* Explicitly enable PCI-PM */ - if (BHNDB_PCIE_QUIRK(sc, PCIPM_REQEN)) { - uint32_t lcreg; - lcreg = bhndb_pcie_read_proto_reg(sc, BHND_PCIE_DLLP_LCREG); - lcreg |= BHND_PCIE_DLLP_LCREG_PCIPM_EN; - bhndb_pcie_write_proto_reg(sc, BHND_PCIE_DLLP_LCREG, lcreg); - } - - /* Adjust L1 timer to fix slow L1->L0 transitions */ - if (BHNDB_PCIE_QUIRK(sc, L1_IDLE_THRESH)) { - uint32_t pmt; - pmt = bhndb_pcie_read_proto_reg(sc, BHND_PCIE_DLLP_PMTHRESHREG); - pmt = BPCI_REG_INSERT(pmt, PCIE_L1THRESHOLDTIME, - BHND_PCIE_L1THRESHOLD_WARVAL); - bhndb_pcie_write_proto_reg(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt); - } - - /* Extend L1 timer for better performance. - * TODO: We could enable/disable this on demand for better power - * savings if we tie this to HT clock request handling */ - if (BHNDB_PCIE_QUIRK(sc, L1_TIMER_PERF)) { - uint32_t pmt; - pmt = bhndb_pcie_read_proto_reg(sc, BHND_PCIE_DLLP_PMTHRESHREG); - pmt |= BHND_PCIE_ASPMTIMER_EXTEND; - bhndb_pcie_write_proto_reg(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt); - } - - /* Enable L23READY_EXIT_NOPRST if not already set in SPROM. */ - if (BHNDB_PCIE_QUIRK(sc, SPROM_L23_PCI_RESET)) { - bus_size_t reg; - uint16_t cfg; - - /* Fetch the misc cfg flags from SPROM */ - reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_PCIE_MISC_CONFIG; - cfg = BHNDB_PCI_READ_2(sc, reg); - - /* Write EXIT_NOPRST flag if not already set in SPROM */ - if (!(cfg & BHND_PCIE_SRSH_L23READY_EXIT_NOPRST)) { - cfg |= BHND_PCIE_SRSH_L23READY_EXIT_NOPRST; - BHNDB_PCI_WRITE_2(sc, reg, cfg); - } - } - - return (0); -} - -/** - * Apply any hardware workarounds that are required upon resume of the - * bridge device. - * - * This must be called before any bridged bhnd(4) cores have been resumed. - */ -static int -bhndb_pci_wars_hwresume(struct bhndb_pci_softc *sc) -{ - int error; - - /* Nothing is possible without register access */ - if ((error = bhndb_pci_wars_register_access(sc))) - return (error); - - /* Apply the general hwup workarounds */ - return (bhndb_pci_wars_hwup(sc)); -} - -/** - * Apply any hardware workarounds that are required upon detach or suspend - * of the bridge device. - */ -static int -bhndb_pci_wars_hwdown(struct bhndb_pci_softc *sc) -{ - int error; - - /* 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 */ - if (BHNDB_PCIE_QUIRK(sc, L1_TIMER_PERF)) { - uint32_t pmt; - pmt = bhndb_pcie_read_proto_reg(sc, BHND_PCIE_DLLP_PMTHRESHREG); - pmt &= ~BHND_PCIE_ASPMTIMER_EXTEND; - bhndb_pcie_write_proto_reg(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt); - } - - /* Disable clocks */ - if (BHNDB_PCI_QUIRK(sc, EXT_CLOCK_GATING)) { - if ((error = bhndb_disable_pci_clocks(sc))) { - device_printf(sc->dev, "failed to disable clocks\n"); - return (error); - } - } - return (0); } /* * On devices without a SROM, the PCI(e) cores will be initialized with - * their Power-on-Reset defaults; this can leave the the BAR0 PCI windows - * potentially mapped to the wrong core index. + * their Power-on-Reset defaults; this can leave two of the BAR0 PCI windows + * mapped to the wrong core. * - * This function updates the PCI core's BAR0 PCI configuration to point at the + * This function updates the SROM shadow to point the BAR0 windows at the * current PCI core. * - * Applies to all PCI/PCIe revisions. Must be applied before bus devices - * are probed/attached or the SPROM is parsed. + * Applies to all PCI/PCIe revisions. */ static void bhndb_init_sromless_pci_config(struct bhndb_pci_softc *sc) { - bus_size_t sprom_addr; - u_int sprom_core_idx; - u_int pci_core_idx; - uint16_t val; + struct bhndb_resources *bres; + const struct bhndb_hwcfg *cfg; + const struct bhndb_regwin *win; + struct resource *core_regs; + bus_size_t srom_offset; + u_int pci_cidx, sprom_cidx; + uint16_t val; + + bres = sc->bhndb.bus_res; + cfg = bres->cfg; + + if (bhnd_get_vendor(sc->bhndb.hostb_dev) != BHND_MFGID_BCM) + return; + + switch (bhnd_get_device(sc->bhndb.hostb_dev)) { + case BHND_COREID_PCI: + srom_offset = BHND_PCI_SRSH_PI_OFFSET; + break; + case BHND_COREID_PCIE: + srom_offset = BHND_PCIE_SRSH_PI_OFFSET; + break; + default: + device_printf(sc->dev, "unsupported PCI host bridge device\n"); + return; + } + + /* Locate the static register window mapping the PCI core */ + win = bhndb_regwin_find_core(cfg->register_windows, sc->pci_devclass, + 0, BHND_PORT_DEVICE, 0, 0); + if (win == NULL) { + device_printf(sc->dev, "missing PCI core register window\n"); + return; + } + + /* Fetch the resource containing the register window */ + core_regs = bhndb_find_regwin_resource(bres, win); + if (core_regs == NULL) { + device_printf(sc->dev, "missing PCI core register resource\n"); + return; + } /* Fetch the SPROM's configured core index */ - sprom_addr = BPCI_COMMON_REG_OFFSET(SPROM_SHADOW, SRSH_PI_OFFSET); - val = BHNDB_PCI_READ_2(sc, sprom_addr); + val = bus_read_2(core_regs, win->win_offset + srom_offset); + sprom_cidx = (val & BHND_PCI_SRSH_PI_MASK) >> BHND_PCI_SRSH_PI_SHIFT; /* If it doesn't match host bridge's core index, update the index * value */ - sprom_core_idx = BPCI_COMMON_REG_EXTRACT(val, SRSH_PI); - pci_core_idx = bhnd_get_core_index(sc->bhndb.hostb_dev); - - if (sprom_core_idx != pci_core_idx) { - val = BPCI_COMMON_REG_INSERT(val, SRSH_PI, pci_core_idx); - BHNDB_PCI_WRITE_2(sc, sprom_addr, val); + pci_cidx = bhnd_get_core_index(sc->bhndb.hostb_dev); + if (sprom_cidx != pci_cidx) { + val &= ~BHND_PCI_SRSH_PI_MASK; + val |= (pci_cidx << BHND_PCI_SRSH_PI_SHIFT); + bus_write_2(core_regs, + win->win_offset + srom_offset, val); } } static int -bhndb_pci_detach(device_t dev) +bhndb_pci_resume(device_t dev) { struct bhndb_pci_softc *sc; int error; sc = device_get_softc(dev); - - if ((error = bhndb_generic_detach(dev))) - return (error); - - /* Apply any hardware workarounds. This may disable the clock, and - * thus must be called *after* any children have been detached. */ - if ((error = bhndb_pci_wars_hwdown(sc))) + + /* Enable clocks (if supported by this hardware) */ + if ((error = bhndb_enable_pci_clocks(sc))) return (error); - /* Disable PCI bus mastering */ - pci_disable_busmaster(device_get_parent(dev)); - - return (0); + /* Perform resume */ + return (bhndb_generic_resume(dev)); } static int @@ -721,35 +248,34 @@ bhndb_pci_suspend(device_t dev) int error; sc = device_get_softc(dev); - - if ((error = bhndb_generic_suspend(dev))) - return (error); - - /* Apply any hardware workarounds. This may disable the clock, and - * thus must be called *after* any children have been suspended. */ - if ((error = bhndb_pci_wars_hwdown(sc))) + + /* Disable clocks (if supported by this hardware) */ + if ((error = bhndb_disable_pci_clocks(sc))) return (error); - return (0); + /* Perform suspend */ + return (bhndb_generic_suspend(dev)); } static int -bhndb_pci_resume(device_t dev) +bhndb_pci_detach(device_t dev) { struct bhndb_pci_softc *sc; int error; sc = device_get_softc(dev); - /* Apply any resume workarounds; these may be required for bridged - * device access, and thus must be called *before* any children are - * resumed. */ - if ((error = bhndb_pci_wars_hwresume(sc))) + /* Disable clocks (if supported by this hardware) */ + if ((error = bhndb_disable_pci_clocks(sc))) return (error); - if ((error = bhndb_generic_resume(dev))) + /* Perform detach */ + if ((error = bhndb_generic_detach(dev))) return (error); + /* Disable PCI bus mastering */ + pci_disable_busmaster(device_get_parent(dev)); + return (0); } @@ -826,54 +352,14 @@ bhndb_pci_fast_setregwin(struct bhndb_pc return (0); } - /** - * Read a 32-bit PCIe TLP/DLLP/PLP protocol register. + * Enable externally managed clocks, if required. * - * @param sc The bhndb_pci driver state. - * @param addr The protocol register offset. - */ -static uint32_t -bhndb_pcie_read_proto_reg(struct bhndb_pci_softc *sc, uint32_t addr) -{ - uint32_t val; - - KASSERT(bhnd_get_class(sc->bhndb.hostb_dev) == BHND_DEVCLASS_PCIE, - ("not a pcie device!")); - - BHNDB_LOCK(&sc->bhndb); - BHNDB_PCI_WRITE_4(sc, BHND_PCIE_IND_ADDR, addr); - val = BHNDB_PCI_READ_4(sc, BHND_PCIE_IND_DATA); - BHNDB_UNLOCK(&sc->bhndb); - - return (val); -} - -/** - * 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. - */ -static void -bhndb_pcie_write_proto_reg(struct bhndb_pci_softc *sc, uint32_t addr, - uint32_t val) -{ - KASSERT(bhnd_get_class(sc->bhndb.hostb_dev) == BHND_DEVCLASS_PCIE, - ("not a pcie device!")); - - BHNDB_LOCK(&sc->bhndb); - BHNDB_PCI_WRITE_4(sc, BHND_PCIE_IND_ADDR, addr); - BHNDB_PCI_WRITE_4(sc, BHND_PCIE_IND_DATA, val); - BHNDB_UNLOCK(&sc->bhndb); -} - - -/** - * Enable externally managed clocks. - * - * Quirk Required: EXT_CLOCK_GATING + * Some PCI chipsets (BCM4306, possibly others) chips do not support + * the idle low-power clock. Clocking must be bootstrapped at + * attach/resume by directly adjusting GPIO registers exposed in the + * PCI config space, and correspondingly, explicitly shutdown at + * detach/suspend. * * @param sc Bridge driver state. */ @@ -885,7 +371,9 @@ bhndb_enable_pci_clocks(struct bhndb_pci uint32_t gpio_flags; uint16_t pci_status; - BHNDB_PCI_ASSERT_QUIRK(sc, EXT_CLOCK_GATING); + /* Only supported and required on PCI devices */ + if (sc->pci_devclass != BHND_DEVCLASS_PCI) + return (0); pci_parent = device_get_parent(sc->dev); @@ -921,9 +409,7 @@ bhndb_enable_pci_clocks(struct bhndb_pci } /** - * Disable externally managed clocks. - * - * Quirk Required: EXT_CLOCK_GATING + * Disable externally managed clocks, if required. * * @param sc Bridge driver state. */ @@ -933,7 +419,9 @@ bhndb_disable_pci_clocks(struct bhndb_pc device_t parent_dev; uint32_t gpio_out, gpio_en; - BHNDB_PCI_ASSERT_QUIRK(sc, EXT_CLOCK_GATING); + /* Only supported and required on PCI devices */ + if (sc->pci_devclass != BHND_DEVCLASS_PCI) + return (0); parent_dev = device_get_parent(sc->dev); @@ -957,111 +445,13 @@ bhndb_disable_pci_clocks(struct bhndb_pc return (0); } - -/** - * Find the identification table entry for a core descriptor. - * - * @param sc bhndb PCI driver state. - */ -static const struct bhndb_pci_id * -bhndb_pci_find_core_id(struct bhnd_core_info *core) -{ - const struct bhndb_pci_id *id; - - for (id = bhndb_pci_ids; id->device != BHND_COREID_INVALID; id++) { - if (core->vendor == BHND_MFGID_BCM && - core->device == id->device) - return (id); - } - - return (NULL); -} - -/** - * Return all quirks known to be applicable to the host bridge. - * - * If the PCI bridge core has not yet been identified, no core-specific - * quirk flags will be returned. This function may be called again to - * rediscover applicable quirks after the host bridge core has been - * identified. - * - * @param sc bhndb PCI driver state. - * @param id The host bridge core's identification table entry, or NULL - * if the host bridge core has not yet been identified. - * - * @return Returns the set of quirks applicable to the current hardware. - */ -static uint32_t -bhndb_pci_discover_quirks(struct bhndb_pci_softc *sc, - const struct bhndb_pci_id *id) -{ - struct bhnd_device_quirk *qt; - uint32_t quirks; - uint8_t hwrev; - - quirks = BHNDB_PCI_QUIRK_NONE; - - /* Determine any device class-specific quirks */ - switch (sc->pci_devclass) { - case BHND_DEVCLASS_PCI: - /* All PCI devices require external clock gating */ - sc->quirks |= BHNDB_PCI_QUIRK_EXT_CLOCK_GATING; - break; - default: - break; - } - - // TODO: Additional quirk matching - - /* Determine any PCI core hwrev-specific device quirks */ - if (id != NULL) { - hwrev = bhnd_get_hwrev(sc->bhndb.hostb_dev); - for (qt = id->quirks; qt->quirks != 0; qt++) { - if (bhnd_hwrev_matches(hwrev, &qt->hwrev)) - quirks |= qt->quirks; - } - } - - - return (quirks); -} - -/* - * Support for attaching the PCIe-Gen1 MDIO driver to a parent bhndb PCIe - * bridge device. - */ -static int -bhndb_mdio_pcie_probe(device_t dev) -{ - device_quiet(dev); - return (BUS_PROBE_NOWILDCARD); -} - -static int -bhndb_mdio_pcie_attach(device_t dev) -{ - struct bhndb_pci_softc *psc; - psc = device_get_softc(device_get_parent(dev)); - return (bhnd_mdio_pcie_attach(dev, - &psc->bhnd_mem_res, -1, - psc->mem_off + BHND_PCIE_MDIO_CTL, - (psc->quirks & BHNDB_PCIE_QUIRK_SD_C22_EXTADDR) != 0)); -} - -static device_method_t bhnd_mdio_pcie_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, bhndb_mdio_pcie_probe), - DEVMETHOD(device_attach, bhndb_mdio_pcie_attach), - DEVMETHOD_END -}; - static device_method_t bhndb_pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, bhndb_pci_probe), DEVMETHOD(device_attach, bhndb_pci_attach), - DEVMETHOD(device_detach, bhndb_pci_detach), - DEVMETHOD(device_suspend, bhndb_pci_suspend), DEVMETHOD(device_resume, bhndb_pci_resume), + DEVMETHOD(device_suspend, bhndb_pci_suspend), + DEVMETHOD(device_detach, bhndb_pci_detach), /* BHNDB interface */ DEVMETHOD(bhndb_init_full_config, bhndb_pci_init_full_config), @@ -1073,12 +463,6 @@ static device_method_t bhndb_pci_methods DEFINE_CLASS_1(bhndb, bhndb_pci_driver, bhndb_pci_methods, sizeof(struct bhndb_pci_softc), bhndb_driver); -DEFINE_CLASS_1(bhnd_mdio_pci, bhndb_mdio_pcie_driver, bhnd_mdio_pcie_methods, - sizeof(struct bhnd_mdio_pcie_softc), bhnd_mdio_pcie_driver); - -DRIVER_MODULE(bhnd_mdio_pcie, bhndb, bhndb_mdio_pcie_driver, - bhnd_mdio_pci_devclass, NULL, NULL); - MODULE_VERSION(bhndb_pci, 1); MODULE_DEPEND(bhndb_pci, bhnd_pci, 1, 1, 1); MODULE_DEPEND(bhndb_pci, pci, 1, 1, 1); Modified: head/sys/dev/bhnd/bhndb/bhndb_pcivar.h ============================================================================== --- head/sys/dev/bhnd/bhndb/bhndb_pcivar.h Fri Apr 22 16:20:58 2016 (r298478) +++ head/sys/dev/bhnd/bhndb/bhndb_pcivar.h Fri Apr 22 16:26:53 2016 (r298479) @@ -32,10 +32,6 @@ #ifndef _BHND_BHNDB_PCIVAR_H_ #define _BHND_BHNDB_PCIVAR_H_ -#include <sys/stdint.h> - -#include <dev/bhnd/cores/pci/bhnd_pcivar.h> - #include "bhndbvar.h" /* @@ -52,191 +48,11 @@ struct bhndb_pci_softc; typedef int (*bhndb_pci_set_regwin_t)(struct bhndb_pci_softc *sc, const struct bhndb_regwin *rw, bhnd_addr_t addr); - -/** - * PCI bridge core identification table. - */ -struct bhndb_pci_id { - uint16_t device; /**< bhnd device ID */ - bhnd_pci_regfmt_t regfmt; /**< register format */ - struct bhnd_device_quirk *quirks; /**< quirks table */ -}; - struct bhndb_pci_softc { struct bhndb_softc bhndb; /**< parent softc */ device_t dev; /**< bridge device */ bhnd_devclass_t pci_devclass; /**< PCI core's devclass */ bhndb_pci_set_regwin_t set_regwin; /**< regwin handler */ - *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201604221626.u3MGQr1w091608>