root/dev/mii/xmphy.c

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

DEFINITIONS

This source file includes following definitions.
  1. xmphy_probe
  2. xmphy_attach
  3. xmphy_service
  4. xmphy_status
  5. xmphy_mii_phy_auto

    1 /*      $OpenBSD: xmphy.c,v 1.17 2006/12/31 15:04:33 krw Exp $  */
    2 
    3 /*
    4  * Copyright (c) 2000
    5  *      Bill Paul <wpaul@ee.columbia.edu>.  All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *      This product includes software developed by Bill Paul.
   18  * 4. Neither the name of the author nor the names of any co-contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
   26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   32  * THE POSSIBILITY OF SUCH DAMAGE.
   33  *
   34  * $FreeBSD: src/sys/dev/mii/xmphy.c,v 1.1 2000/04/22 01:58:18 wpaul Exp $
   35  */
   36 
   37 /*
   38  * driver for the XaQti XMAC II's internal PHY. This is sort of
   39  * like a 10/100 PHY, except the only thing we're really autoselecting
   40  * here is full/half duplex. Speed is always 1000mbps.
   41  */
   42 
   43 #include <sys/param.h>
   44 #include <sys/systm.h>
   45 #include <sys/kernel.h>
   46 #include <sys/device.h>
   47 #include <sys/socket.h>
   48 #include <sys/errno.h>
   49 
   50 #include <net/if.h>
   51 #include <net/if_media.h>
   52 
   53 #include <dev/mii/mii.h>
   54 #include <dev/mii/miivar.h>
   55 #include <dev/mii/miidevs.h>
   56 
   57 #include <dev/mii/xmphyreg.h>
   58 
   59 int xmphy_probe(struct device *, void *, void *);
   60 void xmphy_attach(struct device *, struct device *, void *);
   61 
   62 struct cfattach xmphy_ca = {
   63         sizeof(struct mii_softc), xmphy_probe, xmphy_attach, mii_phy_detach,
   64             mii_phy_activate
   65 };
   66 
   67 struct cfdriver xmphy_cd = {
   68         NULL, "xmphy", DV_DULL
   69 };
   70 
   71 int     xmphy_service(struct mii_softc *, struct mii_data *, int);
   72 void    xmphy_status(struct mii_softc *);
   73 
   74 int     xmphy_mii_phy_auto(struct mii_softc *);
   75 
   76 const struct mii_phy_funcs xmphy_funcs = {
   77         xmphy_service, xmphy_status, mii_phy_reset,
   78 };
   79 
   80 static const struct mii_phydesc xmphys[] = {
   81         { MII_OUI_xxXAQTI,      MII_MODEL_XAQTI_XMACII,
   82           MII_STR_XAQTI_XMACII },
   83 
   84         { MII_OUI_JATO,         MII_MODEL_JATO_BASEX,
   85           MII_STR_JATO_BASEX },
   86 
   87         { 0,                    0,
   88           NULL },
   89 };
   90 
   91 int xmphy_probe(struct device *parent, void *match, void *aux)
   92 {
   93         struct mii_attach_args *ma = aux;
   94 
   95         if (mii_phy_match(ma, xmphys) != NULL)
   96                 return (10);
   97 
   98         return (0);
   99 }
  100 
  101 void
  102 xmphy_attach(struct device *parent, struct device *self, void *aux)
  103 {
  104         struct mii_softc *sc = (struct mii_softc *)self;
  105         struct mii_attach_args *ma = aux;
  106         struct mii_data *mii = ma->mii_data;
  107         const struct mii_phydesc *mpd;
  108 
  109         mpd = mii_phy_match(ma, xmphys);
  110         printf(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
  111 
  112         sc->mii_inst = mii->mii_instance;
  113         sc->mii_phy = ma->mii_phyno;
  114         sc->mii_funcs = &xmphy_funcs;
  115         sc->mii_pdata = mii;
  116         sc->mii_flags = ma->mii_flags;
  117         sc->mii_anegticks = MII_ANEGTICKS;
  118 
  119         sc->mii_flags |= MIIF_NOISOLATE;
  120 
  121 #define ADD(m, c)       ifmedia_add(&mii->mii_media, (m), (c), NULL)
  122 
  123         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
  124             BMCR_ISO);
  125 
  126         PHY_RESET(sc);
  127 
  128         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, sc->mii_inst),
  129             XMPHY_BMCR_FDX);
  130         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst), 0);
  131         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0);
  132 
  133 #undef ADD
  134 }
  135 
  136 int
  137 xmphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
  138 {
  139         struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
  140         int reg;
  141 
  142         if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0)
  143                 return (ENXIO);
  144 
  145         switch (cmd) {
  146         case MII_POLLSTAT:
  147                 /*
  148                  * If we're not polling our PHY instance, just return.
  149                  */
  150                 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
  151                         return (0);
  152                 break;
  153 
  154         case MII_MEDIACHG:
  155                 /*
  156                  * If the media indicates a different PHY instance,
  157                  * isolate ourselves.
  158                  */
  159                 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
  160                         reg = PHY_READ(sc, MII_BMCR);
  161                         PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
  162                         return (0);
  163                 }
  164 
  165                 /*
  166                  * If the interface is not up, don't do anything.
  167                  */
  168                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
  169                         break;
  170 
  171                 switch (IFM_SUBTYPE(ife->ifm_media)) {
  172                 case IFM_AUTO:
  173                         (void) xmphy_mii_phy_auto(sc);
  174                         break;
  175                 case IFM_1000_SX:
  176                         PHY_RESET(sc);
  177                         if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
  178                                 PHY_WRITE(sc, XMPHY_MII_ANAR, XMPHY_ANAR_FDX);
  179                                 PHY_WRITE(sc, XMPHY_MII_BMCR, XMPHY_BMCR_FDX);
  180                         } else {
  181                                 PHY_WRITE(sc, XMPHY_MII_ANAR, XMPHY_ANAR_HDX);
  182                                 PHY_WRITE(sc, XMPHY_MII_BMCR, 0);
  183                         }
  184                         break;
  185                 case IFM_100_T4:
  186                 case IFM_100_TX:
  187                 case IFM_10_T:
  188                 default:
  189                         return (EINVAL);
  190                 }
  191                 break;
  192 
  193         case MII_TICK:
  194                 /*
  195                  * If we're not currently selected, just return.
  196                  */
  197                 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
  198                         return (0);
  199 
  200                 /*
  201                  * Is the interface even up?
  202                  */
  203                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
  204                         return (0);
  205 
  206                 /*
  207                  * Only used for autonegotiation.
  208                  */
  209                 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
  210                         break;
  211 
  212                 /*
  213                  * Check to see if we have link.  If we do, we don't
  214                  * need to restart the autonegotiation process.  Read
  215                  * the BMSR twice in case it's latched.
  216                  */
  217                 reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
  218                 if (reg & BMSR_LINK)
  219                         break;
  220 
  221                 /*
  222                  * Only retry autonegotiation every mii_anegticks seconds.
  223                  */
  224                 if (++sc->mii_ticks <= sc->mii_anegticks)
  225                         break;
  226 
  227                 sc->mii_ticks = 0;
  228                 PHY_RESET(sc);
  229 
  230                 xmphy_mii_phy_auto(sc);
  231                 break;
  232         }
  233 
  234         /* Update the media status. */
  235         mii_phy_status(sc);
  236 
  237         /* Callback if something changed. */
  238         mii_phy_update(sc, cmd);
  239         return (0);
  240 }
  241 
  242 void
  243 xmphy_status(struct mii_softc *sc)
  244 {
  245         struct mii_data *mii = sc->mii_pdata;
  246         int bmsr, bmcr, anlpar;
  247 
  248         mii->mii_media_status = IFM_AVALID;
  249         mii->mii_media_active = IFM_ETHER;
  250 
  251         bmsr = PHY_READ(sc, XMPHY_MII_BMSR) |
  252             PHY_READ(sc, XMPHY_MII_BMSR);
  253         if (bmsr & XMPHY_BMSR_LINK)
  254                 mii->mii_media_status |= IFM_ACTIVE;
  255 
  256         /* Do dummy read of extended status register. */
  257         bmcr = PHY_READ(sc, XMPHY_MII_EXTSTS);
  258 
  259         bmcr = PHY_READ(sc, XMPHY_MII_BMCR);
  260 
  261         if (bmcr & XMPHY_BMCR_LOOP)
  262                 mii->mii_media_active |= IFM_LOOP;
  263 
  264 
  265         if (bmcr & XMPHY_BMCR_AUTOEN) {
  266                 if ((bmsr & XMPHY_BMSR_ACOMP) == 0) {
  267                         if (bmsr & XMPHY_BMSR_LINK) {
  268                                 mii->mii_media_active |= IFM_1000_SX|IFM_HDX;
  269                                 return;
  270                         }
  271                         /* Erg, still trying, I guess... */
  272                         mii->mii_media_active |= IFM_NONE;
  273                         return;
  274                 }
  275 
  276                 mii->mii_media_active |= IFM_1000_SX;
  277                 anlpar = PHY_READ(sc, XMPHY_MII_ANAR) &
  278                     PHY_READ(sc, XMPHY_MII_ANLPAR);
  279                 if (anlpar & XMPHY_ANLPAR_FDX)
  280                         mii->mii_media_active |= IFM_FDX;
  281                 else
  282                         mii->mii_media_active |= IFM_HDX;
  283                 return;
  284         }
  285 
  286         mii->mii_media_active |= IFM_1000_SX;
  287         if (bmcr & XMPHY_BMCR_FDX)
  288                 mii->mii_media_active |= IFM_FDX;
  289         else
  290                 mii->mii_media_active |= IFM_HDX;
  291 
  292         return;
  293 }
  294 
  295 
  296 int
  297 xmphy_mii_phy_auto(struct mii_softc *sc)
  298 {
  299         int anar = 0;
  300 
  301         anar = PHY_READ(sc, XMPHY_MII_ANAR);
  302         anar |= XMPHY_ANAR_FDX|XMPHY_ANAR_HDX;
  303         PHY_WRITE(sc, XMPHY_MII_ANAR, anar);
  304         DELAY(1000);
  305         PHY_WRITE(sc, XMPHY_MII_BMCR,
  306             XMPHY_BMCR_AUTOEN | XMPHY_BMCR_STARTNEG);
  307 
  308         return (EJUSTRETURN);
  309 }

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