The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
    5  * Copyright (c) 2017 The FreeBSD Foundation
    6  * All rights reserved.
    7  *
    8  * Portions of this software were developed by Landon Fuller
    9  * under sponsorship from the FreeBSD Foundation.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer,
   16  *    without modification.
   17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
   18  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
   19  *    redistribution must be conditioned upon including a substantially
   20  *    similar Disclaimer requirement for further binary redistribution.
   21  *
   22  * NO WARRANTY
   23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   24  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   25  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
   26  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
   27  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
   28  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
   31  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   33  * THE POSSIBILITY OF SUCH DAMAGES.
   34  */
   35 
   36 #include <sys/cdefs.h>
   37 __FBSDID("$FreeBSD$");
   38 
   39 /*
   40  * Broadcom BHND PCI/PCIe-Gen1 PCI-Host Bridge.
   41  * 
   42  * This driver handles all interactions with PCI bridge cores operating in
   43  * endpoint mode.
   44  * 
   45  * Host-level PCI operations are handled at the bhndb bridge level by the
   46  * bhndb_pci driver.
   47  */
   48 
   49 #include <sys/param.h>
   50 #include <sys/kernel.h>
   51 
   52 #include <sys/malloc.h>
   53 
   54 #include <sys/bus.h>
   55 #include <sys/module.h>
   56 
   57 #include <sys/systm.h>
   58 
   59 #include <machine/bus.h>
   60 #include <sys/rman.h>
   61 #include <machine/resource.h>
   62 
   63 #include <dev/bhnd/bhnd.h>
   64 
   65 #include <dev/pci/pcireg.h>
   66 #include <dev/pci/pcivar.h>
   67 
   68 #include <dev/bhnd/cores/chipc/chipc.h>
   69 #include <dev/bhnd/cores/chipc/chipcreg.h>
   70 
   71 #include "bhnd_pcireg.h"
   72 #include "bhnd_pci_hostbvar.h"
   73 
   74 static const struct bhnd_device_quirk bhnd_pci_quirks[];
   75 static const struct bhnd_device_quirk bhnd_pcie_quirks[];
   76 
   77 /* Device driver work-around variations */
   78 typedef enum {
   79         BHND_PCI_WAR_ATTACH,    /**< apply attach workarounds */
   80         BHND_PCI_WAR_RESUME,    /**< apply resume workarounds */
   81         BHND_PCI_WAR_SUSPEND,   /**< apply suspend workarounds */
   82         BHND_PCI_WAR_DETACH     /**< apply detach workarounds */
   83 } bhnd_pci_war_state;
   84 
   85 static int      bhnd_pci_wars_early_once(struct bhnd_pcihb_softc *sc);
   86 static int      bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc,
   87                     bhnd_pci_war_state state);
   88 static int      bhnd_pci_wars_hwdown(struct bhnd_pcihb_softc *sc,
   89                     bhnd_pci_war_state state);
   90 
   91 /*
   92  * device/quirk tables
   93  */
   94 
   95 #define BHND_PCI_DEV(_core, _quirks)            \
   96         BHND_DEVICE(BCM, _core, NULL, _quirks, BHND_DF_HOSTB)
   97 
   98 static const struct bhnd_device bhnd_pci_devs[] = {
   99         BHND_PCI_DEV(PCI,       bhnd_pci_quirks),
  100         BHND_PCI_DEV(PCIE,      bhnd_pcie_quirks),
  101         BHND_DEVICE_END
  102 };
  103 
  104 static const struct bhnd_device_quirk bhnd_pci_quirks[] = {
  105         /* core revision quirks */
  106         BHND_CORE_QUIRK (HWREV_ANY,     BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST),
  107         BHND_CORE_QUIRK (HWREV_GTE(11), BHND_PCI_QUIRK_SBTOPCI2_READMULTI |
  108                                         BHND_PCI_QUIRK_CLKRUN_DSBL),
  109 
  110         /* BCM4321CB2 boards that require 960ns latency timer override */
  111         BHND_BOARD_QUIRK(BCM4321CB2,    BHND_PCI_QUIRK_960NS_LATTIM_OVR),
  112         BHND_BOARD_QUIRK(BCM4321CB2_AG, BHND_PCI_QUIRK_960NS_LATTIM_OVR),
  113 
  114         BHND_DEVICE_QUIRK_END
  115 };
  116 
  117 static const struct bhnd_device_quirk bhnd_pcie_quirks[] = {
  118         /* core revision quirks */
  119         BHND_CORE_QUIRK (HWREV_EQ (0),  BHND_PCIE_QUIRK_SDR9_L0s_HANG),
  120         BHND_CORE_QUIRK (HWREV_RANGE(0,1),
  121             BHND_PCIE_QUIRK_UR_STATUS_FIX),
  122 
  123         BHND_CORE_QUIRK (HWREV_EQ (1),  BHND_PCIE_QUIRK_PCIPM_REQEN),
  124 
  125         BHND_CORE_QUIRK (HWREV_RANGE(3,5),
  126             BHND_PCIE_QUIRK_ASPM_OVR | BHND_PCIE_QUIRK_SDR9_POLARITY |
  127             BHND_PCIE_QUIRK_SDR9_NO_FREQRETRY),
  128 
  129         BHND_CORE_QUIRK (HWREV_LTE(6),  BHND_PCIE_QUIRK_L1_IDLE_THRESH),
  130         BHND_CORE_QUIRK (HWREV_GTE(6),  BHND_PCIE_QUIRK_SPROM_L23_PCI_RESET),
  131         BHND_CORE_QUIRK (HWREV_EQ (7),  BHND_PCIE_QUIRK_SERDES_NOPLLDOWN),
  132         BHND_CORE_QUIRK (HWREV_GTE(8),  BHND_PCIE_QUIRK_L1_TIMER_PERF),
  133 
  134         BHND_CORE_QUIRK (HWREV_LTE(17), BHND_PCIE_QUIRK_MAX_MRRS_128),
  135 
  136         /* Apple boards on which BHND_BFL2_PCIEWAR_OVR should be assumed
  137          * to be set. */
  138         {{ BHND_MATCH_BOARD_VENDOR      (PCI_VENDOR_APPLE),
  139            BHND_MATCH_BOARD_REV         (HWREV_LTE(0x71)),
  140            BHND_MATCH_SROMREV           (EQ(4)) },
  141                 BHND_PCIE_QUIRK_BFL2_PCIEWAR_EN },
  142 
  143         /* Apple BCM4322 boards that require 700mV SerDes TX drive strength. */
  144         {{ BHND_MATCH_CHIP_ID(BCM4322),
  145            BHND_MATCH_BOARD(PCI_VENDOR_APPLE, BCM94322X9), },
  146                 BHND_PCIE_QUIRK_SERDES_TXDRV_700MV },
  147 
  148         /* Apple BCM4331 board-specific quirks */
  149 #define BHND_A4331_QUIRK(_board, ...)   \
  150         {{ BHND_MATCH_CHIP_ID(BCM4331),         \
  151             BHND_MATCH_BOARD(PCI_VENDOR_APPLE, _board) }, __VA_ARGS__ }
  152 
  153         BHND_A4331_QUIRK(BCM94331X19,   BHND_PCIE_QUIRK_SERDES_TXDRV_MAX |
  154                                         BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
  155 
  156         BHND_A4331_QUIRK(BCM94331X28,   BHND_PCIE_QUIRK_SERDES_TXDRV_MAX | 
  157                                         BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
  158 
  159         BHND_A4331_QUIRK(BCM94331X28B,  BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
  160 
  161         BHND_A4331_QUIRK(BCM94331X29B,  BHND_PCIE_QUIRK_SERDES_TXDRV_MAX | 
  162                                         BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
  163 
  164         BHND_A4331_QUIRK(BCM94331X19C,  BHND_PCIE_QUIRK_SERDES_TXDRV_MAX |
  165                                         BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
  166             
  167         BHND_A4331_QUIRK(BCM94331X29D,  BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
  168 
  169         BHND_A4331_QUIRK(BCM94331X33,   BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
  170                          
  171 #undef BHND_A4331_QUIRK
  172 
  173         BHND_DEVICE_QUIRK_END
  174 };
  175 
  176 #define BHND_PCI_SOFTC(_sc)     (&((_sc)->common))
  177 
  178 #define BHND_PCI_READ_2(_sc, _reg)              \
  179         bhnd_bus_read_2(BHND_PCI_SOFTC(_sc)->mem_res, (_reg))
  180 
  181 #define BHND_PCI_READ_4(_sc, _reg)              \
  182         bhnd_bus_read_4(BHND_PCI_SOFTC(_sc)->mem_res, (_reg))
  183 
  184 #define BHND_PCI_WRITE_2(_sc, _reg, _val)       \
  185         bhnd_bus_write_2(BHND_PCI_SOFTC(_sc)->mem_res, (_reg), (_val))
  186 
  187 #define BHND_PCI_WRITE_4(_sc, _reg, _val)       \
  188         bhnd_bus_write_4(BHND_PCI_SOFTC(_sc)->mem_res, (_reg), (_val))
  189 
  190 #define BHND_PCI_PROTO_READ_4(_sc, _reg)        \
  191         bhnd_pcie_read_proto_reg(BHND_PCI_SOFTC(_sc), (_reg))
  192 
  193 #define BHND_PCI_PROTO_WRITE_4(_sc, _reg, _val) \
  194         bhnd_pcie_write_proto_reg(BHND_PCI_SOFTC(_sc), (_reg), (_val))
  195 
  196 #define BHND_PCI_MDIO_READ(_sc, _phy, _reg)     \
  197         bhnd_pcie_mdio_read(BHND_PCI_SOFTC(_sc), (_phy), (_reg))
  198 
  199 #define BHND_PCI_MDIO_WRITE(_sc, _phy, _reg, _val)              \
  200         bhnd_pcie_mdio_write(BHND_PCI_SOFTC(_sc), (_phy), (_reg), (_val))
  201 
  202 #define BHND_PCI_MDIO_READ_EXT(_sc, _phy, _devaddr, _reg)               \
  203         bhnd_pcie_mdio_read_ext(BHND_PCI_SOFTC(_sc), (_phy), (_devaddr), (_reg))
  204 
  205 #define BHND_PCI_MDIO_WRITE_EXT(_sc, _phy, _devaddr, _reg, _val)        \
  206         bhnd_pcie_mdio_write_ext(BHND_PCI_SOFTC(_sc), (_phy),           \
  207             (_devaddr), (_reg), (_val))
  208 
  209 #define BPCI_REG_SET(_regv, _attr, _val)        \
  210         BHND_PCI_REG_SET((_regv), BHND_ ## _attr, (_val))
  211 
  212 #define BPCI_REG_GET(_regv, _attr)      \
  213         BHND_PCI_REG_GET((_regv), BHND_ ## _attr)
  214 
  215 #define BPCI_CMN_REG_SET(_regv, _attr, _val)                    \
  216         BHND_PCI_CMN_REG_SET(BHND_PCI_SOFTC(_sc)->regfmt, (_regv),      \
  217             BHND_ ## _attr, (_val))
  218 
  219 #define BPCI_CMN_REG_GET(_regv, _attr)                          \
  220         BHND_PCI_CMN_REG_GET(BHND_PCI_SOFTC(_sc)->regfmt, (_regv),      \
  221             BHND_ ## _attr)
  222 
  223 static int
  224 bhnd_pci_hostb_attach(device_t dev)
  225 {
  226         struct bhnd_pcihb_softc *sc;
  227         int                      error;
  228 
  229         sc = device_get_softc(dev);
  230         sc->dev = dev;
  231         sc->quirks = bhnd_device_quirks(dev, bhnd_pci_devs,
  232             sizeof(bhnd_pci_devs[0]));
  233 
  234         /* Find the host PCI bridge device */
  235         sc->pci_dev = bhnd_find_bridge_root(dev, devclass_find("pci"));
  236         if (sc->pci_dev == NULL) {
  237                 device_printf(dev, "parent pci bridge device not found\n");
  238                 return (ENXIO);
  239         }
  240 
  241         /* Common setup */
  242         if ((error = bhnd_pci_generic_attach(dev)))
  243                 return (error);
  244 
  245         /* Apply early single-shot work-arounds */
  246         if ((error = bhnd_pci_wars_early_once(sc)))
  247                 goto failed;
  248 
  249         /* Apply attach/resume work-arounds */
  250         if ((error = bhnd_pci_wars_hwup(sc, BHND_PCI_WAR_ATTACH)))
  251                 goto failed;
  252 
  253         return (0);
  254 
  255 failed:
  256         bhnd_pci_generic_detach(dev);
  257         return (error);
  258 }
  259 
  260 static int
  261 bhnd_pci_hostb_detach(device_t dev)
  262 {
  263         struct bhnd_pcihb_softc *sc;
  264         int                      error;
  265 
  266         sc = device_get_softc(dev);
  267 
  268         /* Apply suspend/detach work-arounds */
  269         if ((error = bhnd_pci_wars_hwdown(sc, BHND_PCI_WAR_DETACH)))
  270                 return (error);
  271 
  272         return (bhnd_pci_generic_detach(dev));
  273 }
  274 
  275 static int
  276 bhnd_pci_hostb_suspend(device_t dev)
  277 {
  278         struct bhnd_pcihb_softc *sc;
  279         int                      error;
  280 
  281         sc = device_get_softc(dev);
  282 
  283         /* Apply suspend/detach work-arounds */
  284         if ((error = bhnd_pci_wars_hwdown(sc, BHND_PCI_WAR_SUSPEND)))
  285                 return (error);
  286 
  287         return (bhnd_pci_generic_suspend(dev));
  288 }
  289 
  290 static int
  291 bhnd_pci_hostb_resume(device_t dev)
  292 {
  293         struct bhnd_pcihb_softc *sc;
  294         int                      error;
  295 
  296         sc = device_get_softc(dev);
  297 
  298         if ((error = bhnd_pci_generic_resume(dev)))
  299                 return (error);
  300 
  301         /* Apply attach/resume work-arounds */
  302         if ((error = bhnd_pci_wars_hwup(sc, BHND_PCI_WAR_RESUME))) {
  303                 bhnd_pci_generic_detach(dev);
  304                 return (error);
  305         }
  306 
  307         return (0);
  308 }
  309 
  310 /**
  311  * Apply any hardware work-arounds that must be executed exactly once, early in
  312  * the attach process.
  313  * 
  314  * This must be called after core enumeration and discovery of all applicable
  315  * quirks, but prior to probe/attach of any cores, parsing of
  316  * SPROM, etc.
  317  */
  318 static int
  319 bhnd_pci_wars_early_once(struct bhnd_pcihb_softc *sc)
  320 {
  321         int error;
  322 
  323         /* Set PCI latency timer */
  324         if (sc->quirks & BHND_PCI_QUIRK_960NS_LATTIM_OVR) {
  325                 pci_write_config(sc->pci_dev, PCIR_LATTIMER, 0x20 /* 960ns */,
  326                     1); 
  327         }
  328 
  329         /* Determine whether ASPM/CLKREQ should be forced on, or forced off. */
  330         if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
  331                 struct bhnd_board_info  board;
  332                 bool                    aspm_en;
  333 
  334                 /* Fetch board info */
  335                 if ((error = bhnd_read_board_info(sc->dev, &board)))
  336                         return (error);
  337                 
  338                 /* Check board flags */
  339                 aspm_en = true;
  340                 if (board.board_flags2 & BHND_BFL2_PCIEWAR_OVR)
  341                         aspm_en = false;
  342 
  343                 /* Early Apple devices did not (but should have) set
  344                  * BHND_BFL2_PCIEWAR_OVR in SPROM. */
  345                 if (sc->quirks & BHND_PCIE_QUIRK_BFL2_PCIEWAR_EN)
  346                         aspm_en = false;
  347 
  348                 sc->aspm_quirk_override.aspm_en = aspm_en;
  349         }
  350 
  351         /* Determine correct polarity by observing the attach-time PCIe PHY
  352          * link status. This is used later to reset/force the SerDes
  353          * polarity */
  354         if (sc->quirks & BHND_PCIE_QUIRK_SDR9_POLARITY) {
  355                 uint32_t st;
  356                 bool inv;
  357 
  358                 st = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_PLP_STATUSREG);
  359                 inv = ((st & BHND_PCIE_PLP_POLARITY_INV) != 0);
  360                 sc->sdr9_quirk_polarity.inv = inv;
  361         }
  362 
  363         /* Override maximum read request size */
  364         if (bhnd_get_class(sc->dev) == BHND_DEVCLASS_PCIE) {
  365                 int     msize;
  366 
  367                 msize = 128; /* compatible with all PCIe-G1 core revisions */
  368                 if (sc->quirks & BHND_PCIE_QUIRK_DEFAULT_MRRS_512)
  369                         msize = 512;
  370 
  371                 if (pci_set_max_read_req(sc->pci_dev, msize) == 0)
  372                         panic("set mrrs on non-PCIe device");
  373         }
  374 
  375         return (0);
  376 }
  377 
  378 /**
  379  * Apply any hardware workarounds that are required upon attach or resume
  380  * of the bridge device.
  381  */
  382 static int
  383 bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc, bhnd_pci_war_state state)
  384 {
  385         /* Note that the order here matters; these work-arounds
  386          * should not be re-ordered without careful review of their
  387          * interdependencies */
  388 
  389         /* Enable PCI prefetch/burst/readmulti flags */
  390         if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST ||
  391             sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_READMULTI)
  392         {
  393                 uint32_t sbp2;
  394                 sbp2 = BHND_PCI_READ_4(sc, BHND_PCI_SBTOPCI2);
  395 
  396                 if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST)
  397                         sbp2 |= (BHND_PCI_SBTOPCI_PREF|BHND_PCI_SBTOPCI_BURST);
  398 
  399                 if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_READMULTI)
  400                         sbp2 |= BHND_PCI_SBTOPCI_RC_READMULTI;
  401 
  402                 BHND_PCI_WRITE_4(sc, BHND_PCI_SBTOPCI2, sbp2);
  403         }
  404 
  405         /* Disable PCI CLKRUN# */
  406         if (sc->quirks & BHND_PCI_QUIRK_CLKRUN_DSBL) {
  407                 uint32_t ctl;
  408 
  409                 ctl = BHND_PCI_READ_4(sc, BHND_PCI_CLKRUN_CTL);
  410                 ctl |= BHND_PCI_CLKRUN_DSBL;
  411                 BHND_PCI_WRITE_4(sc, BHND_PCI_CLKRUN_CTL, ctl);
  412         }
  413 
  414         /* Enable TLP unmatched address handling work-around */
  415         if (sc->quirks & BHND_PCIE_QUIRK_UR_STATUS_FIX) {
  416                 uint32_t wrs;
  417                 wrs = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_TLP_WORKAROUNDSREG);
  418                 wrs |= BHND_PCIE_TLP_WORKAROUND_URBIT;
  419                 BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_TLP_WORKAROUNDSREG, wrs);
  420         }
  421 
  422         /* Adjust SerDes CDR tuning to ensure that CDR is stable before sending
  423          * data during L0s to L0 exit transitions. */
  424         if (sc->quirks & BHND_PCIE_QUIRK_SDR9_L0s_HANG) {
  425                 uint16_t sdv;
  426 
  427                 /* Set RX track/acquire timers to 2.064us/40.96us */
  428                 sdv = BPCI_REG_SET(0, PCIE_SDR9_RX_TIMER1_LKTRK, (2064/16));
  429                 sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_TIMER1_LKACQ,
  430                     (40960/1024));
  431                 BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
  432                     BHND_PCIE_SDR9_RX_TIMER1, sdv);
  433 
  434                 /* Apply CDR frequency workaround */
  435                 sdv = BHND_PCIE_SDR9_RX_CDR_FREQ_OVR_EN;
  436                 sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDR_FREQ_OVR, 0x0);
  437                 BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
  438                     BHND_PCIE_SDR9_RX_CDR, sdv);
  439 
  440                 /* Apply CDR BW tunings */
  441                 sdv = 0;
  442                 sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_INTGTRK, 0x2);
  443                 sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_INTGACQ, 0x4);
  444                 sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_PROPTRK, 0x6);
  445                 sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_PROPACQ, 0x6);
  446                 BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
  447                     BHND_PCIE_SDR9_RX_CDRBW, sdv);
  448         }
  449 
  450         /* Force correct SerDes polarity */
  451         if (sc->quirks & BHND_PCIE_QUIRK_SDR9_POLARITY) {
  452                 uint16_t        rxctl;
  453 
  454                 rxctl = BHND_PCI_MDIO_READ(sc, BHND_PCIE_PHY_SDR9_TXRX,
  455                     BHND_PCIE_SDR9_RX_CTRL);
  456 
  457                 rxctl |= BHND_PCIE_SDR9_RX_CTRL_FORCE;
  458                 if (sc->sdr9_quirk_polarity.inv)
  459                         rxctl |= BHND_PCIE_SDR9_RX_CTRL_POLARITY_INV;
  460                 else
  461                         rxctl &= ~BHND_PCIE_SDR9_RX_CTRL_POLARITY_INV;
  462 
  463                 BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
  464                     BHND_PCIE_SDR9_RX_CTRL, rxctl);
  465         }
  466 
  467         /* Disable startup retry on PLL frequency detection failure */
  468         if (sc->quirks & BHND_PCIE_QUIRK_SDR9_NO_FREQRETRY) {
  469                 uint16_t        pctl;
  470 
  471                 pctl = BHND_PCI_MDIO_READ(sc, BHND_PCIE_PHY_SDR9_PLL,
  472                     BHND_PCIE_SDR9_PLL_CTRL);
  473 
  474                 pctl &= ~BHND_PCIE_SDR9_PLL_CTRL_FREQDET_EN;
  475                 BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_PLL,
  476                     BHND_PCIE_SDR9_PLL_CTRL, pctl);
  477         }
  478 
  479         /* Explicitly enable PCI-PM */
  480         if (sc->quirks & BHND_PCIE_QUIRK_PCIPM_REQEN) {
  481                 uint32_t lcreg;
  482                 lcreg = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_LCREG);
  483                 lcreg |= BHND_PCIE_DLLP_LCREG_PCIPM_EN;
  484                 BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_LCREG, lcreg);
  485         }
  486 
  487         /* Adjust L1 timer to fix slow L1->L0 transitions */
  488         if (sc->quirks & BHND_PCIE_QUIRK_L1_IDLE_THRESH) {
  489                 uint32_t pmt;
  490                 pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG);
  491                 pmt = BPCI_REG_SET(pmt, PCIE_L1THRESHOLDTIME,
  492                     BHND_PCIE_L1THRESHOLD_WARVAL);
  493                 BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt);
  494         }
  495 
  496         /* Extend L1 timer for better performance.
  497          * TODO: We could enable/disable this on demand for better power
  498          * savings if we tie this to HT clock request handling */
  499         if (sc->quirks & BHND_PCIE_QUIRK_L1_TIMER_PERF) {
  500                 uint32_t pmt;
  501                 pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG);
  502                 pmt |= BHND_PCIE_ASPMTIMER_EXTEND;
  503                 BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt);
  504         }
  505 
  506         /* Override ASPM/ECPM settings in SPROM shadow and PCIER_LINK_CTL */
  507         if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
  508                 bus_size_t      reg;
  509                 uint16_t        cfg;
  510 
  511                 /* Set ASPM L1/L0s flags in SPROM shadow */
  512                 reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_ASPM_OFFSET;
  513                 cfg = BHND_PCI_READ_2(sc, reg);
  514 
  515                 if (sc->aspm_quirk_override.aspm_en)
  516                         cfg |= BHND_PCIE_SRSH_ASPM_ENB;
  517                 else
  518                         cfg &= ~BHND_PCIE_SRSH_ASPM_ENB;
  519                 
  520                 BHND_PCI_WRITE_2(sc, reg, cfg);
  521 
  522                 /* Set ASPM/ECPM (CLKREQ) flags in PCIe link control register */
  523                 cfg = pcie_read_config(sc->pci_dev, PCIER_LINK_CTL, 2);
  524 
  525                 if (sc->aspm_quirk_override.aspm_en)
  526                         cfg |= PCIEM_LINK_CTL_ASPMC;
  527                 else
  528                         cfg &= ~PCIEM_LINK_CTL_ASPMC;
  529 
  530                 cfg &= ~PCIEM_LINK_CTL_ECPM;            /* CLKREQ# */
  531 
  532                 pcie_write_config(sc->pci_dev, PCIER_LINK_CTL, cfg, 2); 
  533 
  534                 /* Set CLKREQ (ECPM) flags in SPROM shadow */
  535                 reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_CLKREQ_OFFSET_R5;
  536                 cfg = BHND_PCI_READ_2(sc, reg);
  537                 
  538                 if (sc->aspm_quirk_override.aspm_en)
  539                         cfg |= BHND_PCIE_SRSH_CLKREQ_ENB;
  540                 else
  541                         cfg &= ~BHND_PCIE_SRSH_CLKREQ_ENB;
  542 
  543                 BHND_PCI_WRITE_2(sc, reg, cfg);
  544         }
  545 
  546         /* Enable L23READY_EXIT_NOPRST if not already set in SPROM. */
  547         if (sc->quirks & BHND_PCIE_QUIRK_SPROM_L23_PCI_RESET) {
  548                 bus_size_t      reg;
  549                 uint16_t        cfg;
  550 
  551                 /* Fetch the misc cfg flags from SPROM */
  552                 reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_PCIE_MISC_CONFIG;
  553                 cfg = BHND_PCI_READ_2(sc, reg);
  554 
  555                 /* Write EXIT_NOPRST flag if not already set in SPROM */
  556                 if (!(cfg & BHND_PCIE_SRSH_L23READY_EXIT_NOPRST)) {
  557                         cfg |= BHND_PCIE_SRSH_L23READY_EXIT_NOPRST;
  558                         BHND_PCI_WRITE_2(sc, reg, cfg);
  559                 }
  560         }
  561 
  562         /* Disable SerDes PLL down */
  563         if (sc->quirks & BHND_PCIE_QUIRK_SERDES_NOPLLDOWN) {
  564                 device_t        bhnd, chipc;
  565                 bus_size_t      reg;
  566                 
  567                 bhnd = device_get_parent(sc->dev);
  568                 chipc = bhnd_bus_find_child(bhnd, BHND_DEVCLASS_CC, 0);
  569                 KASSERT(chipc != NULL, ("missing chipcommon device"));
  570 
  571                 /* Write SerDes PLL disable flag to the ChipCommon core */
  572                 BHND_CHIPC_WRITE_CHIPCTRL(chipc, CHIPCTRL_4321_PLL_DOWN,
  573                     CHIPCTRL_4321_PLL_DOWN);
  574 
  575                 /* Clear SPROM shadow backdoor register */
  576                 reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_BD_OFFSET;
  577                 BHND_PCI_WRITE_2(sc, reg, 0);
  578         }
  579 
  580         /* Adjust TX drive strength and pre-emphasis coefficient */
  581         if (sc->quirks & BHND_PCIE_QUIRK_SERDES_TXDRV_ADJUST) {
  582                 uint16_t txdrv;
  583 
  584                 /* Fetch current TX driver parameters */
  585                 txdrv = BHND_PCI_MDIO_READ_EXT(sc, BHND_PCIE_PHYADDR_SD,
  586                     BHND_PCIE_SD_REGS_TX0, BHND_PCIE_SD_TX_DRIVER);
  587 
  588                 /* Set 700mV drive strength */
  589                 if (sc->quirks & BHND_PCIE_QUIRK_SERDES_TXDRV_700MV) {
  590                         txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_P2_COEFF,
  591                             BHND_PCIE_APPLE_TX_P2_COEFF_700MV);
  592 
  593                         txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_IDRIVER,
  594                             BHND_PCIE_APPLE_TX_IDRIVER_700MV);
  595                 }
  596 
  597                 /* ... or, set max drive strength */
  598                 if (sc->quirks & BHND_PCIE_QUIRK_SERDES_TXDRV_MAX) {
  599                         txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_P2_COEFF,
  600                             BHND_PCIE_APPLE_TX_P2_COEFF_MAX);
  601                         
  602                         txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_IDRIVER,
  603                             BHND_PCIE_APPLE_TX_IDRIVER_MAX);
  604                 }
  605 
  606                 BHND_PCI_MDIO_WRITE_EXT(sc, BHND_PCIE_PHYADDR_SD,
  607                     BHND_PCIE_SD_REGS_TX0, BHND_PCIE_SD_TX_DRIVER, txdrv);
  608         }
  609 
  610         return (0);
  611 }
  612 
  613 /**
  614  * Apply any hardware workarounds that are required upon detach or suspend
  615  * of the bridge device.
  616  */
  617 static int
  618 bhnd_pci_wars_hwdown(struct bhnd_pcihb_softc *sc, bhnd_pci_war_state state)
  619 {
  620         /* Reduce L1 timer for better power savings.
  621          * TODO: We could enable/disable this on demand for better power
  622          * savings if we tie this to HT clock request handling */
  623         if (sc->quirks & BHND_PCIE_QUIRK_L1_TIMER_PERF) {
  624                 uint32_t pmt;
  625                 pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG);
  626                 pmt &= ~BHND_PCIE_ASPMTIMER_EXTEND;
  627                 BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt);
  628         }
  629 
  630         /* Enable CLKREQ (ECPM). If suspending, also disable ASPM L1 entry */
  631         if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
  632                 uint16_t        lcreg;
  633 
  634                 lcreg = pcie_read_config(sc->pci_dev, PCIER_LINK_CTL, 2);
  635 
  636                 lcreg |= PCIEM_LINK_CTL_ECPM;   /* CLKREQ# */
  637                 if (state == BHND_PCI_WAR_SUSPEND)
  638                         lcreg &= ~PCIEM_LINK_CTL_ASPMC_L1;
  639 
  640                 pcie_write_config(sc->pci_dev, PCIER_LINK_CTL, lcreg, 2);
  641         }
  642 
  643         return (0);
  644 }
  645 
  646 static device_method_t bhnd_pci_hostb_methods[] = {
  647         /* Device interface */
  648         DEVMETHOD(device_attach,                bhnd_pci_hostb_attach),
  649         DEVMETHOD(device_detach,                bhnd_pci_hostb_detach),
  650         DEVMETHOD(device_suspend,               bhnd_pci_hostb_suspend),
  651         DEVMETHOD(device_resume,                bhnd_pci_hostb_resume), 
  652 
  653         DEVMETHOD_END
  654 };
  655 
  656 DEFINE_CLASS_1(bhnd_hostb, bhnd_pci_hostb_driver, bhnd_pci_hostb_methods, 
  657     sizeof(struct bhnd_pcihb_softc), bhnd_pci_driver);
  658 DRIVER_MODULE(bhnd_pci_hostb, bhnd, bhnd_pci_hostb_driver, 0, 0);
  659 
  660 MODULE_VERSION(bhnd_pci_hostb, 1);
  661 MODULE_DEPEND(bhnd_pci_hostb, bhnd, 1, 1, 1);
  662 MODULE_DEPEND(bhnd_pci_hostb, bhnd_pci, 1, 1, 1);

Cache object: f45f64b0be35d1d8f2cc3ae1cb085225


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.