root/dev/mii/tlphy.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tlphymatch
  2. tlphyattach
  3. tlphy_service
  4. tlphy_status
  5. tlphy_mii_phy_auto
  6. tlphy_acomp

    1 /*      $OpenBSD: tlphy.c,v 1.18 2006/12/27 19:11:09 kettenis Exp $     */
    2 /*      $NetBSD: tlphy.c,v 1.26 2000/07/04 03:29:00 thorpej Exp $       */
    3 
    4 /*-
    5  * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
    6  * All rights reserved.
    7  *
    8  * This code is derived from software contributed to The NetBSD Foundation
    9  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
   10  * NASA Ames Research Center.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. All advertising materials mentioning features or use of this software
   21  *    must display the following acknowledgement:
   22  *      This product includes software developed by the NetBSD
   23  *      Foundation, Inc. and its contributors.
   24  * 4. Neither the name of The NetBSD Foundation nor the names of its
   25  *    contributors may be used to endorse or promote products derived
   26  *    from this software without specific prior written permission.
   27  *
   28  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   29  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   31  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   32  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   33  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   34  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   35  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   36  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   37  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   38  * POSSIBILITY OF SUCH DAMAGE.
   39  */
   40 
   41 /*
   42  * Copyright (c) 1997 Manuel Bouyer.  All rights reserved.
   43  *
   44  * Redistribution and use in source and binary forms, with or without
   45  * modification, are permitted provided that the following conditions
   46  * are met:
   47  * 1. Redistributions of source code must retain the above copyright
   48  *    notice, this list of conditions and the following disclaimer.
   49  * 2. Redistributions in binary form must reproduce the above copyright
   50  *    notice, this list of conditions and the following disclaimer in the
   51  *    documentation and/or other materials provided with the distribution.
   52  * 3. All advertising materials mentioning features or use of this software
   53  *    must display the following acknowledgement:
   54  *      This product includes software developed by Manuel Bouyer.
   55  * 4. The name of the author may not be used to endorse or promote products
   56  *    derived from this software without specific prior written permission.
   57  *
   58  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   59  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   60  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   61  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   62  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   63  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   64  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   65  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   66  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   67  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   68  */
   69 
   70 /*
   71  * Driver for Texas Instruments's ThunderLAN PHYs
   72  */
   73 
   74 #include <sys/param.h>
   75 #include <sys/systm.h>
   76 #include <sys/kernel.h>
   77 #include <sys/device.h>
   78 #include <sys/socket.h>
   79 #include <sys/errno.h>
   80 
   81 #include <machine/bus.h>
   82 
   83 #include <net/if.h>
   84 #include <net/if_media.h>
   85 
   86 #include <netinet/in.h>
   87 #include <netinet/if_ether.h>
   88 
   89 #include <dev/mii/mii.h>
   90 #include <dev/mii/miivar.h>
   91 #include <dev/mii/miidevs.h>
   92 
   93 #include <dev/mii/tlphyreg.h>
   94 #include <dev/mii/tlphyvar.h>
   95 
   96 /* ThunderLAN PHY can only be on a ThunderLAN */
   97 #include <dev/pci/if_tlreg.h>
   98 
   99 struct tlphy_softc {
  100         struct mii_softc sc_mii;                /* generic PHY */
  101         int sc_tlphycap;
  102         int sc_need_acomp;
  103 };
  104 
  105 struct cfdriver tlphy_cd = {
  106         NULL, "tlphy", DV_DULL
  107 };
  108 
  109 int     tlphymatch(struct device *, void *, void *);
  110 void    tlphyattach(struct device *, struct device *, void *);
  111 
  112 struct cfattach tlphy_ca = {
  113         sizeof(struct tlphy_softc), tlphymatch, tlphyattach, mii_phy_detach,
  114             mii_phy_activate
  115 };
  116 
  117 int     tlphy_service(struct mii_softc *, struct mii_data *, int);
  118 int     tlphy_mii_phy_auto(struct tlphy_softc *, int);
  119 void    tlphy_acomp(struct tlphy_softc *);
  120 void    tlphy_status(struct mii_softc *);
  121 
  122 const struct mii_phy_funcs tlphy_funcs = {
  123         tlphy_service, tlphy_status, mii_phy_reset,
  124 };
  125 
  126 static const struct mii_phydesc tlphys[] = {
  127         { MII_OUI_xxTI,                 MII_MODEL_xxTI_TLAN10T,
  128           MII_STR_xxTI_TLAN10T },
  129 
  130         { 0,                    0,
  131           NULL },
  132 };
  133 
  134 int
  135 tlphymatch(struct device *parent, void *match, void *aux)
  136 {
  137         struct mii_attach_args *ma = aux;
  138 
  139         if (mii_phy_match(ma, tlphys) != NULL)
  140                 return (10);
  141 
  142         return (0);
  143 }
  144 
  145 void
  146 tlphyattach(struct device *parent, struct device *self, void *aux)
  147 {
  148         struct tlphy_softc *sc = (struct tlphy_softc *)self;
  149         struct tl_softc *tlsc = (struct tl_softc *)self->dv_parent;
  150         struct mii_attach_args *ma = aux;
  151         struct mii_data *mii = ma->mii_data;
  152         const struct mii_phydesc *mpd;
  153 
  154         mpd = mii_phy_match(ma, tlphys);
  155         printf(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
  156 
  157         sc->sc_mii.mii_inst = mii->mii_instance;
  158         sc->sc_mii.mii_phy = ma->mii_phyno;
  159         sc->sc_mii.mii_funcs = &tlphy_funcs;
  160         sc->sc_mii.mii_pdata = mii;
  161         sc->sc_mii.mii_flags = ma->mii_flags;
  162 
  163         sc->sc_mii.mii_flags &= ~MIIF_NOISOLATE;
  164         PHY_RESET(&sc->sc_mii);
  165         sc->sc_mii.mii_flags |= MIIF_NOISOLATE;
  166 
  167         /*
  168          * Note that if we're on a device that also supports 100baseTX,
  169          * we are not going to want to use the built-in 10baseT port,
  170          * since there will be another PHY on the MII wired up to the
  171          * UTP connector.  The parent indicates this to us by specifying
  172          * the TLPHY_MEDIA_NO_10_T bit.
  173          */
  174         sc->sc_tlphycap = tlsc->tl_product->tp_tlphymedia;
  175         if ((sc->sc_tlphycap & TLPHY_MEDIA_NO_10_T) == 0)
  176                 sc->sc_mii.mii_capabilities =
  177                     PHY_READ(&sc->sc_mii, MII_BMSR) & ma->mii_capmask;
  178         else
  179                 sc->sc_mii.mii_capabilities = 0;
  180 
  181 
  182         if (sc->sc_tlphycap & TLPHY_MEDIA_10_2)
  183                 ifmedia_add(&mii->mii_media, IFM_MAKEWORD(IFM_ETHER,
  184                     IFM_10_2, 0, sc->sc_mii.mii_inst), 0, NULL);
  185         if (sc->sc_tlphycap & TLPHY_MEDIA_10_5)
  186                 ifmedia_add(&mii->mii_media, IFM_MAKEWORD(IFM_ETHER,
  187                     IFM_10_5, 0, sc->sc_mii.mii_inst), 0, NULL);
  188         if (sc->sc_mii.mii_capabilities & BMSR_MEDIAMASK)
  189                 mii_phy_add_media(&sc->sc_mii);
  190 }
  191 
  192 int
  193 tlphy_service(struct mii_softc *self, struct mii_data *mii, int cmd)
  194 {
  195         struct tlphy_softc *sc = (struct tlphy_softc *)self;
  196         struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
  197         int reg;
  198 
  199         if ((sc->sc_mii.mii_dev.dv_flags & DVF_ACTIVE) == 0)
  200                 return (ENXIO);
  201 
  202         if ((sc->sc_mii.mii_flags & MIIF_DOINGAUTO) == 0 && sc->sc_need_acomp)
  203                 tlphy_acomp(sc);
  204 
  205         switch (cmd) {
  206         case MII_POLLSTAT:
  207                 /*
  208                  * If we're not polling our PHY instance, just return.
  209                  */
  210                 if (IFM_INST(ife->ifm_media) != sc->sc_mii.mii_inst)
  211                         return (0);
  212                 break;
  213 
  214         case MII_MEDIACHG:
  215                 /*
  216                  * If the media indicates a different PHY instance,
  217                  * isolate ourselves.
  218                  */
  219                 if (IFM_INST(ife->ifm_media) != sc->sc_mii.mii_inst) {
  220                         reg = PHY_READ(&sc->sc_mii, MII_BMCR);
  221                         PHY_WRITE(&sc->sc_mii, MII_BMCR, reg | BMCR_ISO);
  222                         return (0);
  223                 }
  224 
  225                 /*
  226                  * If the interface is not up, don't do anything.
  227                  */
  228                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
  229                         break;
  230 
  231                 switch (IFM_SUBTYPE(ife->ifm_media)) {
  232                 case IFM_AUTO:
  233                         /*
  234                          * The ThunderLAN PHY doesn't self-configure after
  235                          * an autonegotiation cycle, so there's no such
  236                          * thing as "already in auto mode".
  237                          */
  238                         (void) tlphy_mii_phy_auto(sc, 1);
  239                         break;
  240                 case IFM_10_2:
  241                 case IFM_10_5:
  242                         PHY_WRITE(&sc->sc_mii, MII_BMCR, 0);
  243                         PHY_WRITE(&sc->sc_mii, MII_TLPHY_CTRL, CTRL_AUISEL);
  244                         delay(100000);
  245                         break;
  246                 default:
  247                         PHY_WRITE(&sc->sc_mii, MII_TLPHY_CTRL, 0);
  248                         delay(100000);
  249                         mii_phy_setmedia(&sc->sc_mii);
  250                 }
  251                 break;
  252 
  253         case MII_TICK:
  254                 /*
  255                  * XXX WHAT ABOUT CHECKING LINK ON THE BNC/AUI?!
  256                  */
  257 
  258                 /*
  259                  * If we're not currently selected, just return.
  260                  */
  261                 if (IFM_INST(ife->ifm_media) != sc->sc_mii.mii_inst)
  262                         return (0);
  263 
  264                 if (mii_phy_tick(&sc->sc_mii) == EJUSTRETURN)
  265                         return (0);
  266                 break;
  267 
  268         case MII_DOWN:
  269                 mii_phy_down(&sc->sc_mii);
  270                 return (0);
  271         }
  272 
  273         /* Update the media status. */
  274         mii_phy_status(&sc->sc_mii);
  275 
  276         /* Callback if something changed. */
  277         mii_phy_update(&sc->sc_mii, cmd);
  278         return (0);
  279 }
  280 
  281 void
  282 tlphy_status(struct mii_softc *physc)
  283 {
  284         struct tlphy_softc *sc = (void *) physc;
  285         struct mii_data *mii = sc->sc_mii.mii_pdata;
  286         int bmsr, bmcr, tlctrl;
  287 
  288         mii->mii_media_status = IFM_AVALID;
  289         mii->mii_media_active = IFM_ETHER;
  290 
  291         bmcr = PHY_READ(&sc->sc_mii, MII_BMCR);
  292         if (bmcr & BMCR_ISO) {
  293                 mii->mii_media_active |= IFM_NONE;
  294                 mii->mii_media_status = 0;
  295                 return;
  296         }
  297 
  298         tlctrl = PHY_READ(&sc->sc_mii, MII_TLPHY_CTRL);
  299         if (tlctrl & CTRL_AUISEL) {
  300                 mii->mii_media_status = 0;
  301                 mii->mii_media_active = mii->mii_media.ifm_cur->ifm_media;
  302                 return;
  303         }
  304 
  305         bmsr = PHY_READ(&sc->sc_mii, MII_BMSR) |
  306             PHY_READ(&sc->sc_mii, MII_BMSR);
  307         if (bmsr & BMSR_LINK)
  308                 mii->mii_media_status |= IFM_ACTIVE;
  309 
  310         if (bmcr & BMCR_LOOP)
  311                 mii->mii_media_active |= IFM_LOOP;
  312 
  313         /*
  314          * Grr, braindead ThunderLAN PHY doesn't have any way to
  315          * tell which media is actually active.  (Note it also
  316          * doesn't self-configure after autonegotiation.)  We
  317          * just have to report what's in the BMCR.
  318          */
  319         if (bmcr & BMCR_FDX)
  320                 mii->mii_media_active |= IFM_FDX;
  321         else
  322                 mii->mii_media_active |= IFM_HDX;
  323         mii->mii_media_active |= IFM_10_T;
  324 }
  325 
  326 int
  327 tlphy_mii_phy_auto(struct tlphy_softc *sc, int waitfor)
  328 {
  329         int error;
  330 
  331         switch ((error = mii_phy_auto(&sc->sc_mii, waitfor))) {
  332         case EIO:
  333                 /*
  334                  * Just assume we're not in full-duplex mode.
  335                  * XXX Check link and try AUI/BNC?
  336                  */
  337                 PHY_WRITE(&sc->sc_mii, MII_BMCR, 0);
  338                 break;
  339 
  340         case EJUSTRETURN:
  341                 /* Flag that we need to program when it completes. */
  342                 sc->sc_need_acomp = 1;
  343                 break;
  344 
  345         default:
  346                 tlphy_acomp(sc);
  347         }
  348 
  349         return (error);
  350 }
  351 
  352 void
  353 tlphy_acomp(struct tlphy_softc *sc)
  354 {
  355         int aner, anlpar;
  356 
  357         sc->sc_need_acomp = 0;
  358 
  359         /*
  360          * Grr, braindead ThunderLAN PHY doesn't self-configure
  361          * after autonegotiation.  We have to do it ourselves
  362          * based on the link partner status.
  363          */
  364 
  365         aner = PHY_READ(&sc->sc_mii, MII_ANER);
  366         if (aner & ANER_LPAN) {
  367                 anlpar = PHY_READ(&sc->sc_mii, MII_ANLPAR) &
  368                     PHY_READ(&sc->sc_mii, MII_ANAR);
  369                 if (anlpar & ANAR_10_FD) {
  370                         PHY_WRITE(&sc->sc_mii, MII_BMCR, BMCR_FDX);
  371                         return;
  372                 }
  373         }
  374         PHY_WRITE(&sc->sc_mii, MII_BMCR, 0);
  375 }

/* [<][>][^][v][top][bottom][index][help] */