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/mii/brgphy.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  * Copyright (c) 2000
    3  *      Bill Paul <wpaul@ee.columbia.edu>.  All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *      This product includes software developed by Bill Paul.
   16  * 4. Neither the name of the author nor the names of any co-contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
   24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   30  * THE POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD$");
   35 
   36 /*
   37  * Driver for the Broadcom BCM54xx/57xx 1000baseTX PHY.
   38  */
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/kernel.h>
   43 #include <sys/module.h>
   44 #include <sys/socket.h>
   45 #include <sys/bus.h>
   46 
   47 #include <net/if.h>
   48 #include <net/ethernet.h>
   49 #include <net/if_media.h>
   50 
   51 #include <dev/mii/mii.h>
   52 #include <dev/mii/miivar.h>
   53 #include "miidevs.h"
   54 
   55 #include <dev/mii/brgphyreg.h>
   56 #include <net/if_arp.h>
   57 #include <machine/bus.h>
   58 #include <dev/bge/if_bgereg.h>
   59 #include <dev/bce/if_bcereg.h>
   60 
   61 #include <dev/pci/pcireg.h>
   62 #include <dev/pci/pcivar.h>
   63 
   64 #include "miibus_if.h"
   65 
   66 static int brgphy_probe(device_t);
   67 static int brgphy_attach(device_t);
   68 
   69 struct brgphy_softc {
   70         struct mii_softc mii_sc;
   71         int serdes_flags;       /* Keeps track of the serdes type used */
   72 #define BRGPHY_5706S            0x0001
   73 #define BRGPHY_5708S            0x0002
   74 #define BRGPHY_NOANWAIT         0x0004
   75 #define BRGPHY_5709S            0x0008
   76         int bce_phy_flags;      /* PHY flags transferred from the MAC driver */
   77 };
   78 
   79 static device_method_t brgphy_methods[] = {
   80         /* device interface */
   81         DEVMETHOD(device_probe,         brgphy_probe),
   82         DEVMETHOD(device_attach,        brgphy_attach),
   83         DEVMETHOD(device_detach,        mii_phy_detach),
   84         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
   85         DEVMETHOD_END
   86 };
   87 
   88 static devclass_t brgphy_devclass;
   89 
   90 static driver_t brgphy_driver = {
   91         "brgphy",
   92         brgphy_methods,
   93         sizeof(struct brgphy_softc)
   94 };
   95 
   96 DRIVER_MODULE(brgphy, miibus, brgphy_driver, brgphy_devclass, 0, 0);
   97 
   98 static int      brgphy_service(struct mii_softc *, struct mii_data *, int);
   99 static void     brgphy_setmedia(struct mii_softc *, int);
  100 static void     brgphy_status(struct mii_softc *);
  101 static void     brgphy_mii_phy_auto(struct mii_softc *, int);
  102 static void     brgphy_reset(struct mii_softc *);
  103 static void     brgphy_enable_loopback(struct mii_softc *);
  104 static void     bcm5401_load_dspcode(struct mii_softc *);
  105 static void     bcm5411_load_dspcode(struct mii_softc *);
  106 static void     bcm54k2_load_dspcode(struct mii_softc *);
  107 static void     brgphy_fixup_5704_a0_bug(struct mii_softc *);
  108 static void     brgphy_fixup_adc_bug(struct mii_softc *);
  109 static void     brgphy_fixup_adjust_trim(struct mii_softc *);
  110 static void     brgphy_fixup_ber_bug(struct mii_softc *);
  111 static void     brgphy_fixup_crc_bug(struct mii_softc *);
  112 static void     brgphy_fixup_jitter_bug(struct mii_softc *);
  113 static void     brgphy_ethernet_wirespeed(struct mii_softc *);
  114 static void     brgphy_jumbo_settings(struct mii_softc *, u_long);
  115 
  116 static const struct mii_phydesc brgphys[] = {
  117         MII_PHY_DESC(BROADCOM, BCM5400),
  118         MII_PHY_DESC(BROADCOM, BCM5401),
  119         MII_PHY_DESC(BROADCOM, BCM5411),
  120         MII_PHY_DESC(BROADCOM, BCM54K2),
  121         MII_PHY_DESC(BROADCOM, BCM5701),
  122         MII_PHY_DESC(BROADCOM, BCM5703),
  123         MII_PHY_DESC(BROADCOM, BCM5704),
  124         MII_PHY_DESC(BROADCOM, BCM5705),
  125         MII_PHY_DESC(BROADCOM, BCM5706),
  126         MII_PHY_DESC(BROADCOM, BCM5714),
  127         MII_PHY_DESC(BROADCOM, BCM5421),
  128         MII_PHY_DESC(BROADCOM, BCM5750),
  129         MII_PHY_DESC(BROADCOM, BCM5752),
  130         MII_PHY_DESC(BROADCOM, BCM5780),
  131         MII_PHY_DESC(BROADCOM, BCM5708C),
  132         MII_PHY_DESC(BROADCOM2, BCM5482),
  133         MII_PHY_DESC(BROADCOM2, BCM5708S),
  134         MII_PHY_DESC(BROADCOM2, BCM5709C),
  135         MII_PHY_DESC(BROADCOM2, BCM5709S),
  136         MII_PHY_DESC(BROADCOM2, BCM5709CAX),
  137         MII_PHY_DESC(BROADCOM2, BCM5722),
  138         MII_PHY_DESC(BROADCOM2, BCM5755),
  139         MII_PHY_DESC(BROADCOM2, BCM5754),
  140         MII_PHY_DESC(BROADCOM2, BCM5761),
  141         MII_PHY_DESC(BROADCOM2, BCM5784),
  142 #ifdef notyet   /* better handled by ukphy(4) until WARs are implemented */
  143         MII_PHY_DESC(BROADCOM2, BCM5785),
  144 #endif
  145         MII_PHY_DESC(BROADCOM3, BCM5717C),
  146         MII_PHY_DESC(BROADCOM3, BCM5719C),
  147         MII_PHY_DESC(BROADCOM3, BCM5720C),
  148         MII_PHY_DESC(BROADCOM3, BCM57765),
  149         MII_PHY_DESC(BROADCOM3, BCM57780),
  150         MII_PHY_DESC(BROADCOM4, BCM5725C),
  151         MII_PHY_DESC(xxBROADCOM_ALT1, BCM5906),
  152         MII_PHY_END
  153 };
  154 
  155 static const struct mii_phy_funcs brgphy_funcs = {
  156         brgphy_service,
  157         brgphy_status,
  158         brgphy_reset
  159 };
  160 
  161 static const struct hs21_type {
  162         const uint32_t id;
  163         const char *prod;
  164 } hs21_type_lists[] = {
  165         { 0x57081021, "IBM eServer BladeCenter HS21" },
  166         { 0x57081011, "IBM eServer BladeCenter HS21 -[8853PAU]-" },
  167 };
  168 
  169 static int
  170 detect_hs21(struct bce_softc *bce_sc)
  171 {
  172         char *sysenv;
  173         int found, i;
  174 
  175         found = 0;
  176         sysenv = getenv("smbios.system.product");
  177         if (sysenv == NULL)
  178                 return (found);
  179         for (i = 0; i < nitems(hs21_type_lists); i++) {
  180                 if (bce_sc->bce_chipid == hs21_type_lists[i].id &&
  181                     strncmp(sysenv, hs21_type_lists[i].prod,
  182                     strlen(hs21_type_lists[i].prod)) == 0) {
  183                         found++;
  184                         break;
  185                 }
  186         }
  187         freeenv(sysenv);
  188         return (found);
  189 }
  190 
  191 /* Search for our PHY in the list of known PHYs */
  192 static int
  193 brgphy_probe(device_t dev)
  194 {
  195 
  196         return (mii_phy_dev_probe(dev, brgphys, BUS_PROBE_DEFAULT));
  197 }
  198 
  199 /* Attach the PHY to the MII bus */
  200 static int
  201 brgphy_attach(device_t dev)
  202 {
  203         struct brgphy_softc *bsc;
  204         struct bge_softc *bge_sc = NULL;
  205         struct bce_softc *bce_sc = NULL;
  206         struct mii_softc *sc;
  207         struct ifnet *ifp;
  208 
  209         bsc = device_get_softc(dev);
  210         sc = &bsc->mii_sc;
  211 
  212         mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE,
  213             &brgphy_funcs, 0);
  214 
  215         bsc->serdes_flags = 0;
  216         ifp = sc->mii_pdata->mii_ifp;
  217 
  218         /* Find the MAC driver associated with this PHY. */
  219         if (strcmp(ifp->if_dname, "bge") == 0)
  220                 bge_sc = ifp->if_softc;
  221         else if (strcmp(ifp->if_dname, "bce") == 0)
  222                 bce_sc = ifp->if_softc;
  223 
  224         /* Handle any special cases based on the PHY ID */
  225         switch (sc->mii_mpd_oui) {
  226         case MII_OUI_BROADCOM:
  227                 switch (sc->mii_mpd_model) {
  228                 case MII_MODEL_BROADCOM_BCM5706:
  229                 case MII_MODEL_BROADCOM_BCM5714:
  230                         /*
  231                          * The 5464 PHY used in the 5706 supports both copper
  232                          * and fiber interfaces over GMII.  Need to check the
  233                          * shadow registers to see which mode is actually
  234                          * in effect, and therefore whether we have 5706C or
  235                          * 5706S.
  236                          */
  237                         PHY_WRITE(sc, BRGPHY_MII_SHADOW_1C,
  238                                 BRGPHY_SHADOW_1C_MODE_CTRL);
  239                         if (PHY_READ(sc, BRGPHY_MII_SHADOW_1C) &
  240                                 BRGPHY_SHADOW_1C_ENA_1000X) {
  241                                 bsc->serdes_flags |= BRGPHY_5706S;
  242                                 sc->mii_flags |= MIIF_HAVEFIBER;
  243                         }
  244                         break;
  245                 }
  246                 break;
  247         case MII_OUI_BROADCOM2:
  248                 switch (sc->mii_mpd_model) {
  249                 case MII_MODEL_BROADCOM2_BCM5708S:
  250                         bsc->serdes_flags |= BRGPHY_5708S;
  251                         sc->mii_flags |= MIIF_HAVEFIBER;
  252                         break;
  253                 case MII_MODEL_BROADCOM2_BCM5709S:
  254                         /*
  255                          * XXX
  256                          * 5720S and 5709S shares the same PHY id.
  257                          * Assume 5720S PHY if parent device is bge(4).
  258                          */
  259                         if (bge_sc != NULL)
  260                                 bsc->serdes_flags |= BRGPHY_5708S;
  261                         else
  262                                 bsc->serdes_flags |= BRGPHY_5709S;
  263                         sc->mii_flags |= MIIF_HAVEFIBER;
  264                         break;
  265                 }
  266                 break;
  267         }
  268 
  269         PHY_RESET(sc);
  270 
  271         /* Read the PHY's capabilities. */
  272         sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & sc->mii_capmask;
  273         if (sc->mii_capabilities & BMSR_EXTSTAT)
  274                 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
  275         device_printf(dev, " ");
  276 
  277 #define ADD(m, c)       ifmedia_add(&sc->mii_pdata->mii_media, (m), (c), NULL)
  278 
  279         /* Add the supported media types */
  280         if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) {
  281                 mii_phy_add_media(sc);
  282                 printf("\n");
  283         } else {
  284                 sc->mii_anegticks = MII_ANEGTICKS_GIGE;
  285                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst),
  286                         BRGPHY_S1000 | BRGPHY_BMCR_FDX);
  287                 printf("1000baseSX-FDX, ");
  288                 /* 2.5G support is a software enabled feature on the 5708S and 5709S. */
  289                 if (bce_sc && (bce_sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG)) {
  290                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_2500_SX, IFM_FDX, sc->mii_inst), 0);
  291                         printf("2500baseSX-FDX, ");
  292                 } else if ((bsc->serdes_flags & BRGPHY_5708S) && bce_sc &&
  293                     (detect_hs21(bce_sc) != 0)) {
  294                         /*
  295                          * There appears to be certain silicon revision
  296                          * in IBM HS21 blades that is having issues with
  297                          * this driver wating for the auto-negotiation to
  298                          * complete. This happens with a specific chip id
  299                          * only and when the 1000baseSX-FDX is the only
  300                          * mode. Workaround this issue since it's unlikely
  301                          * to be ever addressed.
  302                          */
  303                         printf("auto-neg workaround, ");
  304                         bsc->serdes_flags |= BRGPHY_NOANWAIT;
  305                 }
  306                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0);
  307                 printf("auto\n");
  308         }
  309 
  310 #undef ADD
  311         MIIBUS_MEDIAINIT(sc->mii_dev);
  312         return (0);
  313 }
  314 
  315 static int
  316 brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
  317 {
  318         struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
  319         int val;
  320 
  321         switch (cmd) {
  322         case MII_POLLSTAT:
  323                 break;
  324         case MII_MEDIACHG:
  325                 /* If the interface is not up, don't do anything. */
  326                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
  327                         break;
  328 
  329                 /* Todo: Why is this here?  Is it really needed? */
  330                 PHY_RESET(sc);  /* XXX hardware bug work-around */
  331 
  332                 switch (IFM_SUBTYPE(ife->ifm_media)) {
  333                 case IFM_AUTO:
  334                         brgphy_mii_phy_auto(sc, ife->ifm_media);
  335                         break;
  336                 case IFM_2500_SX:
  337                 case IFM_1000_SX:
  338                 case IFM_1000_T:
  339                 case IFM_100_TX:
  340                 case IFM_10_T:
  341                         brgphy_setmedia(sc, ife->ifm_media);
  342                         break;
  343                 default:
  344                         return (EINVAL);
  345                 }
  346                 break;
  347         case MII_TICK:
  348                 /* Bail if the interface isn't up. */
  349                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
  350                         return (0);
  351 
  352 
  353                 /* Bail if autoneg isn't in process. */
  354                 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
  355                         sc->mii_ticks = 0;
  356                         break;
  357                 }
  358 
  359                 /*
  360                  * Check to see if we have link.  If we do, we don't
  361                  * need to restart the autonegotiation process.
  362                  */
  363                 val = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
  364                 if (val & BMSR_LINK) {
  365                         sc->mii_ticks = 0;      /* Reset autoneg timer. */
  366                         break;
  367                 }
  368 
  369                 /* Announce link loss right after it happens. */
  370                 if (sc->mii_ticks++ == 0)
  371                         break;
  372 
  373                 /* Only retry autonegotiation every mii_anegticks seconds. */
  374                 if (sc->mii_ticks <= sc->mii_anegticks)
  375                         break;
  376 
  377 
  378                 /* Retry autonegotiation */
  379                 sc->mii_ticks = 0;
  380                 brgphy_mii_phy_auto(sc, ife->ifm_media);
  381                 break;
  382         }
  383 
  384         /* Update the media status. */
  385         PHY_STATUS(sc);
  386 
  387         /*
  388          * Callback if something changed. Note that we need to poke
  389          * the DSP on the Broadcom PHYs if the media changes.
  390          */
  391         if (sc->mii_media_active != mii->mii_media_active ||
  392             sc->mii_media_status != mii->mii_media_status ||
  393             cmd == MII_MEDIACHG) {
  394                 switch (sc->mii_mpd_oui) {
  395                 case MII_OUI_BROADCOM:
  396                         switch (sc->mii_mpd_model) {
  397                         case MII_MODEL_BROADCOM_BCM5400:
  398                                 bcm5401_load_dspcode(sc);
  399                                 break;
  400                         case MII_MODEL_BROADCOM_BCM5401:
  401                                 if (sc->mii_mpd_rev == 1 || sc->mii_mpd_rev == 3)
  402                                         bcm5401_load_dspcode(sc);
  403                                 break;
  404                         case MII_MODEL_BROADCOM_BCM5411:
  405                                 bcm5411_load_dspcode(sc);
  406                                 break;
  407                         case MII_MODEL_BROADCOM_BCM54K2:
  408                                 bcm54k2_load_dspcode(sc);
  409                                 break;
  410                         }
  411                         break;
  412                 }
  413         }
  414         mii_phy_update(sc, cmd);
  415         return (0);
  416 }
  417 
  418 /****************************************************************************/
  419 /* Sets the PHY link speed.                                                 */
  420 /*                                                                          */
  421 /* Returns:                                                                 */
  422 /*   None                                                                   */
  423 /****************************************************************************/
  424 static void
  425 brgphy_setmedia(struct mii_softc *sc, int media)
  426 {
  427         int bmcr = 0, gig;
  428 
  429         switch (IFM_SUBTYPE(media)) {
  430         case IFM_2500_SX:
  431                 break;
  432         case IFM_1000_SX:
  433         case IFM_1000_T:
  434                 bmcr = BRGPHY_S1000;
  435                 break;
  436         case IFM_100_TX:
  437                 bmcr = BRGPHY_S100;
  438                 break;
  439         case IFM_10_T:
  440         default:
  441                 bmcr = BRGPHY_S10;
  442                 break;
  443         }
  444 
  445         if ((media & IFM_FDX) != 0) {
  446                 bmcr |= BRGPHY_BMCR_FDX;
  447                 gig = BRGPHY_1000CTL_AFD;
  448         } else {
  449                 gig = BRGPHY_1000CTL_AHD;
  450         }
  451 
  452         /* Force loopback to disconnect PHY from Ethernet medium. */
  453         brgphy_enable_loopback(sc);
  454 
  455         PHY_WRITE(sc, BRGPHY_MII_1000CTL, 0);
  456         PHY_WRITE(sc, BRGPHY_MII_ANAR, BRGPHY_SEL_TYPE);
  457 
  458         if (IFM_SUBTYPE(media) != IFM_1000_T &&
  459             IFM_SUBTYPE(media) != IFM_1000_SX) {
  460                 PHY_WRITE(sc, BRGPHY_MII_BMCR, bmcr);
  461                 return;
  462         }
  463 
  464         if (IFM_SUBTYPE(media) == IFM_1000_T) {
  465                 gig |= BRGPHY_1000CTL_MSE;
  466                 if ((media & IFM_ETH_MASTER) != 0)
  467                         gig |= BRGPHY_1000CTL_MSC;
  468         }
  469         PHY_WRITE(sc, BRGPHY_MII_1000CTL, gig);
  470         PHY_WRITE(sc, BRGPHY_MII_BMCR,
  471             bmcr | BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG);
  472 }
  473 
  474 /****************************************************************************/
  475 /* Set the media status based on the PHY settings.                          */
  476 /*                                                                          */
  477 /* Returns:                                                                 */
  478 /*   None                                                                   */
  479 /****************************************************************************/
  480 static void
  481 brgphy_status(struct mii_softc *sc)
  482 {
  483         struct brgphy_softc *bsc = (struct brgphy_softc *)sc;
  484         struct mii_data *mii = sc->mii_pdata;
  485         int aux, bmcr, bmsr, val, xstat;
  486         u_int flowstat;
  487 
  488         mii->mii_media_status = IFM_AVALID;
  489         mii->mii_media_active = IFM_ETHER;
  490 
  491         bmsr = PHY_READ(sc, BRGPHY_MII_BMSR) | PHY_READ(sc, BRGPHY_MII_BMSR);
  492         bmcr = PHY_READ(sc, BRGPHY_MII_BMCR);
  493 
  494         if (bmcr & BRGPHY_BMCR_LOOP) {
  495                 mii->mii_media_active |= IFM_LOOP;
  496         }
  497 
  498         if ((bmcr & BRGPHY_BMCR_AUTOEN) &&
  499             (bmsr & BRGPHY_BMSR_ACOMP) == 0 &&
  500             (bsc->serdes_flags & BRGPHY_NOANWAIT) == 0) {
  501                 /* Erg, still trying, I guess... */
  502                 mii->mii_media_active |= IFM_NONE;
  503                 return;
  504         }
  505 
  506         if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) {
  507                 /*
  508                  * NB: reading the ANAR, ANLPAR or 1000STS after the AUXSTS
  509                  * wedges at least the PHY of BCM5704 (but not others).
  510                  */
  511                 flowstat = mii_phy_flowstatus(sc);
  512                 xstat = PHY_READ(sc, BRGPHY_MII_1000STS);
  513                 aux = PHY_READ(sc, BRGPHY_MII_AUXSTS);
  514 
  515                 /* If copper link is up, get the negotiated speed/duplex. */
  516                 if (aux & BRGPHY_AUXSTS_LINK) {
  517                         mii->mii_media_status |= IFM_ACTIVE;
  518                         switch (aux & BRGPHY_AUXSTS_AN_RES) {
  519                         case BRGPHY_RES_1000FD:
  520                                 mii->mii_media_active |= IFM_1000_T | IFM_FDX;  break;
  521                         case BRGPHY_RES_1000HD:
  522                                 mii->mii_media_active |= IFM_1000_T | IFM_HDX;  break;
  523                         case BRGPHY_RES_100FD:
  524                                 mii->mii_media_active |= IFM_100_TX | IFM_FDX; break;
  525                         case BRGPHY_RES_100T4:
  526                                 mii->mii_media_active |= IFM_100_T4; break;
  527                         case BRGPHY_RES_100HD:
  528                                 mii->mii_media_active |= IFM_100_TX | IFM_HDX;  break;
  529                         case BRGPHY_RES_10FD:
  530                                 mii->mii_media_active |= IFM_10_T | IFM_FDX; break;
  531                         case BRGPHY_RES_10HD:
  532                                 mii->mii_media_active |= IFM_10_T | IFM_HDX; break;
  533                         default:
  534                                 mii->mii_media_active |= IFM_NONE; break;
  535                         }
  536 
  537                         if ((mii->mii_media_active & IFM_FDX) != 0)
  538                                 mii->mii_media_active |= flowstat;
  539 
  540                         if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T &&
  541                             (xstat & BRGPHY_1000STS_MSR) != 0)
  542                                 mii->mii_media_active |= IFM_ETH_MASTER;
  543                 }
  544         } else {
  545                 /* Todo: Add support for flow control. */
  546                 /* If serdes link is up, get the negotiated speed/duplex. */
  547                 if (bmsr & BRGPHY_BMSR_LINK) {
  548                         mii->mii_media_status |= IFM_ACTIVE;
  549                 }
  550 
  551                 /* Check the link speed/duplex based on the PHY type. */
  552                 if (bsc->serdes_flags & BRGPHY_5706S) {
  553                         mii->mii_media_active |= IFM_1000_SX;
  554 
  555                         /* If autoneg enabled, read negotiated duplex settings */
  556                         if (bmcr & BRGPHY_BMCR_AUTOEN) {
  557                                 val = PHY_READ(sc, BRGPHY_SERDES_ANAR) & PHY_READ(sc, BRGPHY_SERDES_ANLPAR);
  558                                 if (val & BRGPHY_SERDES_ANAR_FDX)
  559                                         mii->mii_media_active |= IFM_FDX;
  560                                 else
  561                                         mii->mii_media_active |= IFM_HDX;
  562                         }
  563                 } else if (bsc->serdes_flags & BRGPHY_5708S) {
  564                         PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0);
  565                         xstat = PHY_READ(sc, BRGPHY_5708S_PG0_1000X_STAT1);
  566 
  567                         /* Check for MRBE auto-negotiated speed results. */
  568                         switch (xstat & BRGPHY_5708S_PG0_1000X_STAT1_SPEED_MASK) {
  569                         case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_10:
  570                                 mii->mii_media_active |= IFM_10_FL; break;
  571                         case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_100:
  572                                 mii->mii_media_active |= IFM_100_FX; break;
  573                         case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_1G:
  574                                 mii->mii_media_active |= IFM_1000_SX; break;
  575                         case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_25G:
  576                                 mii->mii_media_active |= IFM_2500_SX; break;
  577                         }
  578 
  579                         /* Check for MRBE auto-negotiated duplex results. */
  580                         if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_FDX)
  581                                 mii->mii_media_active |= IFM_FDX;
  582                         else
  583                                 mii->mii_media_active |= IFM_HDX;
  584                 } else if (bsc->serdes_flags & BRGPHY_5709S) {
  585                         /* Select GP Status Block of the AN MMD, get autoneg results. */
  586                         PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_GP_STATUS);
  587                         xstat = PHY_READ(sc, BRGPHY_GP_STATUS_TOP_ANEG_STATUS);
  588 
  589                         /* Restore IEEE0 block (assumed in all brgphy(4) code). */
  590                         PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_COMBO_IEEE0);
  591 
  592                         /* Check for MRBE auto-negotiated speed results. */
  593                         switch (xstat & BRGPHY_GP_STATUS_TOP_ANEG_SPEED_MASK) {
  594                                 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_10:
  595                                         mii->mii_media_active |= IFM_10_FL; break;
  596                                 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_100:
  597                                         mii->mii_media_active |= IFM_100_FX; break;
  598                                 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1G:
  599                                         mii->mii_media_active |= IFM_1000_SX; break;
  600                                 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_25G:
  601                                         mii->mii_media_active |= IFM_2500_SX; break;
  602                         }
  603 
  604                         /* Check for MRBE auto-negotiated duplex results. */
  605                         if (xstat & BRGPHY_GP_STATUS_TOP_ANEG_FDX)
  606                                 mii->mii_media_active |= IFM_FDX;
  607                         else
  608                                 mii->mii_media_active |= IFM_HDX;
  609                 }
  610         }
  611 }
  612 
  613 static void
  614 brgphy_mii_phy_auto(struct mii_softc *sc, int media)
  615 {
  616         int anar, ktcr = 0;
  617 
  618         PHY_RESET(sc);
  619 
  620         if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) {
  621                 anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA;
  622                 if ((media & IFM_FLOW) != 0 ||
  623                     (sc->mii_flags & MIIF_FORCEPAUSE) != 0)
  624                         anar |= BRGPHY_ANAR_PC | BRGPHY_ANAR_ASP;
  625                 PHY_WRITE(sc, BRGPHY_MII_ANAR, anar);
  626                 ktcr = BRGPHY_1000CTL_AFD | BRGPHY_1000CTL_AHD;
  627                 if (sc->mii_mpd_model == MII_MODEL_BROADCOM_BCM5701)
  628                         ktcr |= BRGPHY_1000CTL_MSE | BRGPHY_1000CTL_MSC;
  629                 PHY_WRITE(sc, BRGPHY_MII_1000CTL, ktcr);
  630                 PHY_READ(sc, BRGPHY_MII_1000CTL);
  631         } else {
  632                 anar = BRGPHY_SERDES_ANAR_FDX | BRGPHY_SERDES_ANAR_HDX;
  633                 if ((media & IFM_FLOW) != 0 ||
  634                     (sc->mii_flags & MIIF_FORCEPAUSE) != 0)
  635                         anar |= BRGPHY_SERDES_ANAR_BOTH_PAUSE;
  636                 PHY_WRITE(sc, BRGPHY_SERDES_ANAR, anar);
  637         }
  638 
  639         PHY_WRITE(sc, BRGPHY_MII_BMCR, BRGPHY_BMCR_AUTOEN |
  640             BRGPHY_BMCR_STARTNEG);
  641         PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00);
  642 }
  643 
  644 /* Enable loopback to force the link down. */
  645 static void
  646 brgphy_enable_loopback(struct mii_softc *sc)
  647 {
  648         int i;
  649 
  650         PHY_WRITE(sc, BRGPHY_MII_BMCR, BRGPHY_BMCR_LOOP);
  651         for (i = 0; i < 15000; i++) {
  652                 if (!(PHY_READ(sc, BRGPHY_MII_BMSR) & BRGPHY_BMSR_LINK))
  653                         break;
  654                 DELAY(10);
  655         }
  656 }
  657 
  658 /* Turn off tap power management on 5401. */
  659 static void
  660 bcm5401_load_dspcode(struct mii_softc *sc)
  661 {
  662         static const struct {
  663                 int             reg;
  664                 uint16_t        val;
  665         } dspcode[] = {
  666                 { BRGPHY_MII_AUXCTL,            0x0c20 },
  667                 { BRGPHY_MII_DSP_ADDR_REG,      0x0012 },
  668                 { BRGPHY_MII_DSP_RW_PORT,       0x1804 },
  669                 { BRGPHY_MII_DSP_ADDR_REG,      0x0013 },
  670                 { BRGPHY_MII_DSP_RW_PORT,       0x1204 },
  671                 { BRGPHY_MII_DSP_ADDR_REG,      0x8006 },
  672                 { BRGPHY_MII_DSP_RW_PORT,       0x0132 },
  673                 { BRGPHY_MII_DSP_ADDR_REG,      0x8006 },
  674                 { BRGPHY_MII_DSP_RW_PORT,       0x0232 },
  675                 { BRGPHY_MII_DSP_ADDR_REG,      0x201f },
  676                 { BRGPHY_MII_DSP_RW_PORT,       0x0a20 },
  677                 { 0,                            0 },
  678         };
  679         int i;
  680 
  681         for (i = 0; dspcode[i].reg != 0; i++)
  682                 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
  683         DELAY(40);
  684 }
  685 
  686 static void
  687 bcm5411_load_dspcode(struct mii_softc *sc)
  688 {
  689         static const struct {
  690                 int             reg;
  691                 uint16_t        val;
  692         } dspcode[] = {
  693                 { 0x1c,                         0x8c23 },
  694                 { 0x1c,                         0x8ca3 },
  695                 { 0x1c,                         0x8c23 },
  696                 { 0,                            0 },
  697         };
  698         int i;
  699 
  700         for (i = 0; dspcode[i].reg != 0; i++)
  701                 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
  702 }
  703 
  704 void
  705 bcm54k2_load_dspcode(struct mii_softc *sc)
  706 {
  707         static const struct {
  708                 int             reg;
  709                 uint16_t        val;
  710         } dspcode[] = {
  711                 { 4,                            0x01e1 },
  712                 { 9,                            0x0300 },
  713                 { 0,                            0 },
  714         };
  715         int i;
  716 
  717         for (i = 0; dspcode[i].reg != 0; i++)
  718                 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
  719 
  720 }
  721 
  722 static void
  723 brgphy_fixup_5704_a0_bug(struct mii_softc *sc)
  724 {
  725         static const struct {
  726                 int             reg;
  727                 uint16_t        val;
  728         } dspcode[] = {
  729                 { 0x1c,                         0x8d68 },
  730                 { 0x1c,                         0x8d68 },
  731                 { 0,                            0 },
  732         };
  733         int i;
  734 
  735         for (i = 0; dspcode[i].reg != 0; i++)
  736                 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
  737 }
  738 
  739 static void
  740 brgphy_fixup_adc_bug(struct mii_softc *sc)
  741 {
  742         static const struct {
  743                 int             reg;
  744                 uint16_t        val;
  745         } dspcode[] = {
  746                 { BRGPHY_MII_AUXCTL,            0x0c00 },
  747                 { BRGPHY_MII_DSP_ADDR_REG,      0x201f },
  748                 { BRGPHY_MII_DSP_RW_PORT,       0x2aaa },
  749                 { 0,                            0 },
  750         };
  751         int i;
  752 
  753         for (i = 0; dspcode[i].reg != 0; i++)
  754                 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
  755 }
  756 
  757 static void
  758 brgphy_fixup_adjust_trim(struct mii_softc *sc)
  759 {
  760         static const struct {
  761                 int             reg;
  762                 uint16_t        val;
  763         } dspcode[] = {
  764                 { BRGPHY_MII_AUXCTL,            0x0c00 },
  765                 { BRGPHY_MII_DSP_ADDR_REG,      0x000a },
  766                 { BRGPHY_MII_DSP_RW_PORT,       0x110b },
  767                 { BRGPHY_MII_TEST1,                     0x0014 },
  768                 { BRGPHY_MII_AUXCTL,            0x0400 },
  769                 { 0,                            0 },
  770         };
  771         int i;
  772 
  773         for (i = 0; dspcode[i].reg != 0; i++)
  774                 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
  775 }
  776 
  777 static void
  778 brgphy_fixup_ber_bug(struct mii_softc *sc)
  779 {
  780         static const struct {
  781                 int             reg;
  782                 uint16_t        val;
  783         } dspcode[] = {
  784                 { BRGPHY_MII_AUXCTL,            0x0c00 },
  785                 { BRGPHY_MII_DSP_ADDR_REG,      0x000a },
  786                 { BRGPHY_MII_DSP_RW_PORT,       0x310b },
  787                 { BRGPHY_MII_DSP_ADDR_REG,      0x201f },
  788                 { BRGPHY_MII_DSP_RW_PORT,       0x9506 },
  789                 { BRGPHY_MII_DSP_ADDR_REG,      0x401f },
  790                 { BRGPHY_MII_DSP_RW_PORT,       0x14e2 },
  791                 { BRGPHY_MII_AUXCTL,            0x0400 },
  792                 { 0,                            0 },
  793         };
  794         int i;
  795 
  796         for (i = 0; dspcode[i].reg != 0; i++)
  797                 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
  798 }
  799 
  800 static void
  801 brgphy_fixup_crc_bug(struct mii_softc *sc)
  802 {
  803         static const struct {
  804                 int             reg;
  805                 uint16_t        val;
  806         } dspcode[] = {
  807                 { BRGPHY_MII_DSP_RW_PORT,       0x0a75 },
  808                 { 0x1c,                         0x8c68 },
  809                 { 0x1c,                         0x8d68 },
  810                 { 0x1c,                         0x8c68 },
  811                 { 0,                            0 },
  812         };
  813         int i;
  814 
  815         for (i = 0; dspcode[i].reg != 0; i++)
  816                 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
  817 }
  818 
  819 static void
  820 brgphy_fixup_jitter_bug(struct mii_softc *sc)
  821 {
  822         static const struct {
  823                 int             reg;
  824                 uint16_t        val;
  825         } dspcode[] = {
  826                 { BRGPHY_MII_AUXCTL,            0x0c00 },
  827                 { BRGPHY_MII_DSP_ADDR_REG,      0x000a },
  828                 { BRGPHY_MII_DSP_RW_PORT,       0x010b },
  829                 { BRGPHY_MII_AUXCTL,            0x0400 },
  830                 { 0,                            0 },
  831         };
  832         int i;
  833 
  834         for (i = 0; dspcode[i].reg != 0; i++)
  835                 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
  836 }
  837 
  838 static void
  839 brgphy_fixup_disable_early_dac(struct mii_softc *sc)
  840 {
  841         uint32_t val;
  842 
  843         PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x0f08);
  844         val = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT);
  845         val &= ~(1 << 8);
  846         PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, val);
  847 
  848 }
  849 
  850 static void
  851 brgphy_ethernet_wirespeed(struct mii_softc *sc)
  852 {
  853         uint32_t        val;
  854 
  855         /* Enable Ethernet@WireSpeed. */
  856         PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007);
  857         val = PHY_READ(sc, BRGPHY_MII_AUXCTL);
  858         PHY_WRITE(sc, BRGPHY_MII_AUXCTL, val | (1 << 15) | (1 << 4));
  859 }
  860 
  861 static void
  862 brgphy_jumbo_settings(struct mii_softc *sc, u_long mtu)
  863 {
  864         uint32_t        val;
  865 
  866         /* Set or clear jumbo frame settings in the PHY. */
  867         if (mtu > ETHER_MAX_LEN) {
  868                 if (sc->mii_mpd_model == MII_MODEL_BROADCOM_BCM5401) {
  869                         /* BCM5401 PHY cannot read-modify-write. */
  870                         PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x4c20);
  871                 } else {
  872                         PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7);
  873                         val = PHY_READ(sc, BRGPHY_MII_AUXCTL);
  874                         PHY_WRITE(sc, BRGPHY_MII_AUXCTL,
  875                             val | BRGPHY_AUXCTL_LONG_PKT);
  876                 }
  877 
  878                 val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL);
  879                 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL,
  880                     val | BRGPHY_PHY_EXTCTL_HIGH_LA);
  881         } else {
  882                 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7);
  883                 val = PHY_READ(sc, BRGPHY_MII_AUXCTL);
  884                 PHY_WRITE(sc, BRGPHY_MII_AUXCTL,
  885                     val & ~(BRGPHY_AUXCTL_LONG_PKT | 0x7));
  886 
  887                 val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL);
  888                 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL,
  889                         val & ~BRGPHY_PHY_EXTCTL_HIGH_LA);
  890         }
  891 }
  892 
  893 static void
  894 brgphy_reset(struct mii_softc *sc)
  895 {
  896         struct bge_softc *bge_sc = NULL;
  897         struct bce_softc *bce_sc = NULL;
  898         struct ifnet *ifp;
  899         int i, val;
  900 
  901         /*
  902          * Perform a reset.  Note that at least some Broadcom PHYs default to
  903          * being powered down as well as isolated after a reset but don't work
  904          * if one or both of these bits are cleared.  However, they just work
  905          * fine if both bits remain set, so we don't use mii_phy_reset() here.
  906          */
  907         PHY_WRITE(sc, BRGPHY_MII_BMCR, BRGPHY_BMCR_RESET);
  908 
  909         /* Wait 100ms for it to complete. */
  910         for (i = 0; i < 100; i++) {
  911                 if ((PHY_READ(sc, BRGPHY_MII_BMCR) & BRGPHY_BMCR_RESET) == 0)
  912                         break;
  913                 DELAY(1000);
  914         }
  915 
  916         /* Handle any PHY specific procedures following the reset. */
  917         switch (sc->mii_mpd_oui) {
  918         case MII_OUI_BROADCOM:
  919                 switch (sc->mii_mpd_model) {
  920                 case MII_MODEL_BROADCOM_BCM5400:
  921                         bcm5401_load_dspcode(sc);
  922                         break;
  923                 case MII_MODEL_BROADCOM_BCM5401:
  924                         if (sc->mii_mpd_rev == 1 || sc->mii_mpd_rev == 3)
  925                                 bcm5401_load_dspcode(sc);
  926                         break;
  927                 case MII_MODEL_BROADCOM_BCM5411:
  928                         bcm5411_load_dspcode(sc);
  929                         break;
  930                 case MII_MODEL_BROADCOM_BCM54K2:
  931                         bcm54k2_load_dspcode(sc);
  932                         break;
  933                 }
  934                 break;
  935         case MII_OUI_BROADCOM3:
  936                 switch (sc->mii_mpd_model) {
  937                 case MII_MODEL_BROADCOM3_BCM5717C:
  938                 case MII_MODEL_BROADCOM3_BCM5719C:
  939                 case MII_MODEL_BROADCOM3_BCM5720C:
  940                 case MII_MODEL_BROADCOM3_BCM57765:
  941                         return;
  942                 }
  943                 break;
  944         case MII_OUI_BROADCOM4:
  945                 return;
  946         }
  947 
  948         ifp = sc->mii_pdata->mii_ifp;
  949 
  950         /* Find the driver associated with this PHY. */
  951         if (strcmp(ifp->if_dname, "bge") == 0)  {
  952                 bge_sc = ifp->if_softc;
  953         } else if (strcmp(ifp->if_dname, "bce") == 0) {
  954                 bce_sc = ifp->if_softc;
  955         }
  956 
  957         if (bge_sc) {
  958                 /* Fix up various bugs */
  959                 if (bge_sc->bge_phy_flags & BGE_PHY_5704_A0_BUG)
  960                         brgphy_fixup_5704_a0_bug(sc);
  961                 if (bge_sc->bge_phy_flags & BGE_PHY_ADC_BUG)
  962                         brgphy_fixup_adc_bug(sc);
  963                 if (bge_sc->bge_phy_flags & BGE_PHY_ADJUST_TRIM)
  964                         brgphy_fixup_adjust_trim(sc);
  965                 if (bge_sc->bge_phy_flags & BGE_PHY_BER_BUG)
  966                         brgphy_fixup_ber_bug(sc);
  967                 if (bge_sc->bge_phy_flags & BGE_PHY_CRC_BUG)
  968                         brgphy_fixup_crc_bug(sc);
  969                 if (bge_sc->bge_phy_flags & BGE_PHY_JITTER_BUG)
  970                         brgphy_fixup_jitter_bug(sc);
  971 
  972                 if (bge_sc->bge_flags & BGE_FLAG_JUMBO)
  973                         brgphy_jumbo_settings(sc, ifp->if_mtu);
  974 
  975                 if ((bge_sc->bge_phy_flags & BGE_PHY_NO_WIRESPEED) == 0)
  976                         brgphy_ethernet_wirespeed(sc);
  977 
  978                 /* Enable Link LED on Dell boxes */
  979                 if (bge_sc->bge_phy_flags & BGE_PHY_NO_3LED) {
  980                         PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL,
  981                             PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL) &
  982                             ~BRGPHY_PHY_EXTCTL_3_LED);
  983                 }
  984 
  985                 /* Adjust output voltage (From Linux driver) */
  986                 if (bge_sc->bge_asicrev == BGE_ASICREV_BCM5906)
  987                         PHY_WRITE(sc, BRGPHY_MII_EPHY_PTEST, 0x12);
  988         } else if (bce_sc) {
  989                 if (BCE_CHIP_NUM(bce_sc) == BCE_CHIP_NUM_5708 &&
  990                         (bce_sc->bce_phy_flags & BCE_PHY_SERDES_FLAG)) {
  991 
  992                         /* Store autoneg capabilities/results in digital block (Page 0) */
  993                         PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG3_PG2);
  994                         PHY_WRITE(sc, BRGPHY_5708S_PG2_DIGCTL_3_0,
  995                                 BRGPHY_5708S_PG2_DIGCTL_3_0_USE_IEEE);
  996                         PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0);
  997 
  998                         /* Enable fiber mode and autodetection */
  999                         PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL1,
 1000                                 PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL1) |
 1001                                 BRGPHY_5708S_PG0_1000X_CTL1_AUTODET_EN |
 1002                                 BRGPHY_5708S_PG0_1000X_CTL1_FIBER_MODE);
 1003 
 1004                         /* Enable parallel detection */
 1005                         PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL2,
 1006                                 PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL2) |
 1007                                 BRGPHY_5708S_PG0_1000X_CTL2_PAR_DET_EN);
 1008 
 1009                         /* Advertise 2.5G support through next page during autoneg */
 1010                         if (bce_sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG)
 1011                                 PHY_WRITE(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1,
 1012                                         PHY_READ(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1) |
 1013                                         BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G);
 1014 
 1015                         /* Increase TX signal amplitude */
 1016                         if ((BCE_CHIP_ID(bce_sc) == BCE_CHIP_ID_5708_A0) ||
 1017                             (BCE_CHIP_ID(bce_sc) == BCE_CHIP_ID_5708_B0) ||
 1018                             (BCE_CHIP_ID(bce_sc) == BCE_CHIP_ID_5708_B1)) {
 1019                                 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
 1020                                         BRGPHY_5708S_TX_MISC_PG5);
 1021                                 PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL1,
 1022                                         PHY_READ(sc, BRGPHY_5708S_PG5_TXACTL1) & ~0x30);
 1023                                 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
 1024                                         BRGPHY_5708S_DIG_PG0);
 1025                         }
 1026 
 1027                         /* Backplanes use special driver/pre-driver/pre-emphasis values. */
 1028                         if ((bce_sc->bce_shared_hw_cfg & BCE_SHARED_HW_CFG_PHY_BACKPLANE) &&
 1029                                 (bce_sc->bce_port_hw_cfg & BCE_PORT_HW_CFG_CFG_TXCTL3_MASK)) {
 1030                                         PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
 1031                                                 BRGPHY_5708S_TX_MISC_PG5);
 1032                                         PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL3,
 1033                                                 bce_sc->bce_port_hw_cfg &
 1034                                                 BCE_PORT_HW_CFG_CFG_TXCTL3_MASK);
 1035                                         PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
 1036                                                 BRGPHY_5708S_DIG_PG0);
 1037                         }
 1038                 } else if (BCE_CHIP_NUM(bce_sc) == BCE_CHIP_NUM_5709 &&
 1039                         (bce_sc->bce_phy_flags & BCE_PHY_SERDES_FLAG)) {
 1040 
 1041                         /* Select the SerDes Digital block of the AN MMD. */
 1042                         PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_SERDES_DIG);
 1043                         val = PHY_READ(sc, BRGPHY_SERDES_DIG_1000X_CTL1);
 1044                         val &= ~BRGPHY_SD_DIG_1000X_CTL1_AUTODET;
 1045                         val |= BRGPHY_SD_DIG_1000X_CTL1_FIBER;
 1046                         PHY_WRITE(sc, BRGPHY_SERDES_DIG_1000X_CTL1, val);
 1047 
 1048                         /* Select the Over 1G block of the AN MMD. */
 1049                         PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_OVER_1G);
 1050 
 1051                         /* Enable autoneg "Next Page" to advertise 2.5G support. */
 1052                         val = PHY_READ(sc, BRGPHY_OVER_1G_UNFORMAT_PG1);
 1053                         if (bce_sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG)
 1054                                 val |= BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G;
 1055                         else
 1056                                 val &= ~BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G;
 1057                         PHY_WRITE(sc, BRGPHY_OVER_1G_UNFORMAT_PG1, val);
 1058 
 1059                         /* Select the Multi-Rate Backplane Ethernet block of the AN MMD. */
 1060                         PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_MRBE);
 1061 
 1062                         /* Enable MRBE speed autoneg. */
 1063                         val = PHY_READ(sc, BRGPHY_MRBE_MSG_PG5_NP);
 1064                         val |= BRGPHY_MRBE_MSG_PG5_NP_MBRE |
 1065                             BRGPHY_MRBE_MSG_PG5_NP_T2;
 1066                         PHY_WRITE(sc, BRGPHY_MRBE_MSG_PG5_NP, val);
 1067 
 1068                         /* Select the Clause 73 User B0 block of the AN MMD. */
 1069                         PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_CL73_USER_B0);
 1070 
 1071                         /* Enable MRBE speed autoneg. */
 1072                         PHY_WRITE(sc, BRGPHY_CL73_USER_B0_MBRE_CTL1,
 1073                             BRGPHY_CL73_USER_B0_MBRE_CTL1_NP_AFT_BP |
 1074                             BRGPHY_CL73_USER_B0_MBRE_CTL1_STA_MGR |
 1075                             BRGPHY_CL73_USER_B0_MBRE_CTL1_ANEG);
 1076 
 1077                         /* Restore IEEE0 block (assumed in all brgphy(4) code). */
 1078                         PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_COMBO_IEEE0);
 1079         } else if (BCE_CHIP_NUM(bce_sc) == BCE_CHIP_NUM_5709) {
 1080                         if ((BCE_CHIP_REV(bce_sc) == BCE_CHIP_REV_Ax) ||
 1081                                 (BCE_CHIP_REV(bce_sc) == BCE_CHIP_REV_Bx))
 1082                                 brgphy_fixup_disable_early_dac(sc);
 1083 
 1084                         brgphy_jumbo_settings(sc, ifp->if_mtu);
 1085                         brgphy_ethernet_wirespeed(sc);
 1086                 } else {
 1087                         brgphy_fixup_ber_bug(sc);
 1088                         brgphy_jumbo_settings(sc, ifp->if_mtu);
 1089                         brgphy_ethernet_wirespeed(sc);
 1090                 }
 1091         }
 1092 }

Cache object: 26662a86d301634c05e8369c190a8f32


[ 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.