[BACK]Return to eephy.c CVS log [TXT][DIR] Up to [local] / sys / dev / mii

Annotation of sys/dev/mii/eephy.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: eephy.c,v 1.40 2007/02/11 21:29:24 kettenis Exp $     */
        !             2: /*
        !             3:  * Principal Author: Parag Patel
        !             4:  * Copyright (c) 2001
        !             5:  * 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 unmodified, this list of conditions, and the following
        !            12:  *    disclaimer.
        !            13:  * 2. Redistributions in binary form must reproduce the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer in the
        !            15:  *    documentation and/or other materials provided with the distribution.
        !            16:  *
        !            17:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
        !            18:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            19:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            20:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
        !            21:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            22:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            23:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            24:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            25:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            26:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            27:  * SUCH DAMAGE.
        !            28:  *
        !            29:  * Additonal Copyright (c) 2001 by Traakan Software under same licence.
        !            30:  * Secondary Author: Matthew Jacob
        !            31:  */
        !            32:
        !            33: /*
        !            34:  * driver for the Marvell 88E1000 series external 1000/100/10-BT PHY.
        !            35:  */
        !            36:
        !            37: /*
        !            38:  * Support added for the Marvell 88E1011 (Alaska) 1000/100/10baseTX and
        !            39:  * 1000baseSX PHY.
        !            40:  * Nathan Binkert <nate@openbsd.org>
        !            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/proc.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/eephyreg.h>
        !            58:
        !            59: int    eephy_service(struct mii_softc *, struct mii_data *, int);
        !            60: void   eephy_status(struct mii_softc *);
        !            61: int    eephymatch(struct device *, void *, void *);
        !            62: void   eephyattach(struct device *, struct device *, void *);
        !            63:
        !            64: struct cfattach eephy_ca = {
        !            65:        sizeof (struct mii_softc), eephymatch, eephyattach,
        !            66:        mii_phy_detach, mii_phy_activate
        !            67: };
        !            68:
        !            69: struct cfdriver eephy_cd = {
        !            70:        NULL, "eephy", DV_DULL
        !            71: };
        !            72:
        !            73: int    eephy_mii_phy_auto(struct mii_softc *);
        !            74: void   eephy_reset(struct mii_softc *);
        !            75:
        !            76: const struct mii_phy_funcs eephy_funcs = {
        !            77:        eephy_service, eephy_status, eephy_reset,
        !            78: };
        !            79:
        !            80: static const struct mii_phydesc eephys[] = {
        !            81:        { MII_OUI_MARVELL,              MII_MODEL_MARVELL_E1000_1,
        !            82:          MII_STR_MARVELL_E1000_1 },
        !            83:        { MII_OUI_MARVELL,              MII_MODEL_MARVELL_E1000_2,
        !            84:          MII_STR_MARVELL_E1000_2 },
        !            85:        { MII_OUI_MARVELL,              MII_MODEL_MARVELL_E1000_3,
        !            86:          MII_STR_MARVELL_E1000_3 },
        !            87:        { MII_OUI_MARVELL,              MII_MODEL_MARVELL_E1000_4,
        !            88:          MII_STR_MARVELL_E1000_4 },
        !            89:        { MII_OUI_MARVELL,              MII_MODEL_MARVELL_E1000S,
        !            90:          MII_STR_MARVELL_E1000S },
        !            91:        { MII_OUI_MARVELL,              MII_MODEL_MARVELL_E1011,
        !            92:          MII_STR_MARVELL_E1011 },
        !            93:        { MII_OUI_MARVELL,              MII_MODEL_MARVELL_E1111,
        !            94:          MII_STR_MARVELL_E1111 },
        !            95:        { MII_OUI_MARVELL,              MII_MODEL_MARVELL_E1112,
        !            96:          MII_STR_MARVELL_E1112 },
        !            97:        { MII_OUI_MARVELL,              MII_MODEL_MARVELL_E1116,
        !            98:          MII_STR_MARVELL_E1116 },
        !            99:        { MII_OUI_MARVELL,              MII_MODEL_MARVELL_E1118,
        !           100:          MII_STR_MARVELL_E1118 },
        !           101:        { MII_OUI_MARVELL,              MII_MODEL_MARVELL_E1149,
        !           102:          MII_STR_MARVELL_E1149 },
        !           103:        { MII_OUI_MARVELL,              MII_MODEL_MARVELL_E3082,
        !           104:          MII_STR_MARVELL_E3082 },
        !           105:        { MII_OUI_xxMARVELL,            MII_MODEL_xxMARVELL_E1000_5,
        !           106:          MII_STR_xxMARVELL_E1000_5 },
        !           107:        { MII_OUI_xxMARVELL,            MII_MODEL_xxMARVELL_E1000_6,
        !           108:          MII_STR_xxMARVELL_E1000_6 },
        !           109:        { MII_OUI_xxMARVELL,            MII_MODEL_xxMARVELL_E1000_7,
        !           110:          MII_STR_xxMARVELL_E1000_7 },
        !           111:        { MII_OUI_xxMARVELL,            MII_MODEL_xxMARVELL_E1111,
        !           112:          MII_STR_xxMARVELL_E1111 },
        !           113:
        !           114:        { 0,                            0,
        !           115:          NULL },
        !           116: };
        !           117:
        !           118: int
        !           119: eephymatch(struct device *parent, void *match, void *aux)
        !           120: {
        !           121:        struct mii_attach_args *ma = aux;
        !           122:
        !           123:        if (mii_phy_match(ma, eephys) != NULL)
        !           124:                return (10);
        !           125:
        !           126:        return (0);
        !           127: }
        !           128:
        !           129: void
        !           130: eephyattach(struct device *parent, struct device *self, void *aux)
        !           131: {
        !           132:        struct mii_softc *sc = (struct mii_softc *)self;
        !           133:        struct mii_attach_args *ma = aux;
        !           134:        struct mii_data *mii = ma->mii_data;
        !           135:        const struct mii_phydesc *mpd;
        !           136:        int reg, page;
        !           137:
        !           138:        mpd = mii_phy_match(ma, eephys);
        !           139:        printf(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
        !           140:
        !           141:        sc->mii_inst = mii->mii_instance;
        !           142:        sc->mii_phy = ma->mii_phyno;
        !           143:        sc->mii_funcs = &eephy_funcs;
        !           144:        sc->mii_model = MII_MODEL(ma->mii_id2);
        !           145:        sc->mii_pdata = mii;
        !           146:        sc->mii_flags = ma->mii_flags;
        !           147:
        !           148:        /* XXX No loopback support yet, although the hardware can do it. */
        !           149:        sc->mii_flags |= MIIF_NOLOOP;
        !           150:
        !           151:        /* Switch to fiber-only mode if necessary. */
        !           152:        if (sc->mii_model == MII_MODEL_MARVELL_E1112 &&
        !           153:            sc->mii_flags & MIIF_HAVEFIBER) {
        !           154:                page = PHY_READ(sc, E1000_EADR);
        !           155:                PHY_WRITE(sc, E1000_EADR, 2);
        !           156:                reg = PHY_READ(sc, E1000_SCR);
        !           157:                reg &= ~E1000_SCR_MODE_MASK;
        !           158:                reg |= E1000_SCR_MODE_1000BX;
        !           159:                PHY_WRITE(sc, E1000_SCR, reg);
        !           160:                PHY_WRITE(sc, E1000_EADR, page);
        !           161:
        !           162:                PHY_RESET(sc);
        !           163:        }
        !           164:
        !           165:        sc->mii_capabilities = PHY_READ(sc, E1000_SR) & ma->mii_capmask;
        !           166:        if (sc->mii_capabilities & BMSR_EXTSTAT)
        !           167:                sc->mii_extcapabilities = PHY_READ(sc, E1000_ESR);
        !           168:
        !           169:        mii_phy_add_media(sc);
        !           170:
        !           171:        /*
        !           172:         * Initialize PHY Specific Control Register.
        !           173:         */
        !           174:
        !           175:        reg = PHY_READ(sc, E1000_SCR);
        !           176:
        !           177:        /* Assert CRS on transmit. */
        !           178:        reg |= E1000_SCR_ASSERT_CRS_ON_TX;
        !           179:
        !           180:        /* Enable auto crossover. */
        !           181:        switch (sc->mii_model) {
        !           182:        case MII_MODEL_MARVELL_E3082:
        !           183:                /* Bits are in a different position.  */
        !           184:                reg |= (E1000_SCR_AUTO_X_MODE >> 1);
        !           185:                break;
        !           186:        default:
        !           187:                /* Automatic crossover causes problems for 1000baseX. */
        !           188:                if (sc->mii_flags & MIIF_IS_1000X)
        !           189:                        reg &= ~E1000_SCR_AUTO_X_MODE;
        !           190:                else
        !           191:                        reg |= E1000_SCR_AUTO_X_MODE;
        !           192:        }
        !           193:
        !           194:        /* Disable energy detect; only available on some models. */
        !           195:        switch(sc->mii_model) {
        !           196:        case MII_MODEL_MARVELL_E1011:
        !           197:        case MII_MODEL_MARVELL_E1111:
        !           198:        case MII_MODEL_MARVELL_E1112:
        !           199:                /* Disable energy detect. */
        !           200:                reg &= ~E1000_SCR_EN_DETECT_MASK;
        !           201:                break;
        !           202:        }
        !           203:
        !           204:        PHY_WRITE(sc, E1000_SCR, reg);
        !           205:
        !           206:        /* 25 MHz TX_CLK should always work. */
        !           207:        reg = PHY_READ(sc, E1000_ESCR);
        !           208:        reg |= E1000_ESCR_TX_CLK_25;
        !           209:        PHY_WRITE(sc, E1000_ESCR, reg);
        !           210:
        !           211:        /*
        !           212:         * Do a software reset for these settings to take effect.
        !           213:         * Disable autonegotiation, such that all capabilities get
        !           214:         * advertised when it is switched back on.
        !           215:         */
        !           216:        reg = PHY_READ(sc, E1000_CR);
        !           217:        reg &= ~E1000_CR_AUTO_NEG_ENABLE;
        !           218:        PHY_WRITE(sc, E1000_CR, reg | E1000_CR_RESET);
        !           219: }
        !           220:
        !           221: void
        !           222: eephy_reset(struct mii_softc *sc)
        !           223: {
        !           224:        int reg, i;
        !           225:
        !           226:        reg = PHY_READ(sc, E1000_CR);
        !           227:        reg |= E1000_CR_RESET;
        !           228:        PHY_WRITE(sc, E1000_CR, reg);
        !           229:
        !           230:        for (i = 0; i < 500; i++) {
        !           231:                DELAY(1);
        !           232:                reg = PHY_READ(sc, E1000_CR);
        !           233:                if (!(reg & E1000_CR_RESET))
        !           234:                        break;
        !           235:        }
        !           236: }
        !           237:
        !           238: int
        !           239: eephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
        !           240: {
        !           241:        struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
        !           242:        int bmcr;
        !           243:
        !           244:        if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0)
        !           245:                return (ENXIO);
        !           246:
        !           247:        switch (cmd) {
        !           248:        case MII_POLLSTAT:
        !           249:                /*
        !           250:                 * If we're not polling our PHY instance, just return.
        !           251:                 */
        !           252:                if (IFM_INST(ife->ifm_media) != sc->mii_inst)
        !           253:                        return (0);
        !           254:                break;
        !           255:
        !           256:        case MII_MEDIACHG:
        !           257:                /*
        !           258:                 * If the media indicates a different PHY instance,
        !           259:                 * isolate ourselves.
        !           260:                 */
        !           261:                if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
        !           262:                        bmcr = PHY_READ(sc, E1000_CR);
        !           263:                        PHY_WRITE(sc, E1000_CR, bmcr | E1000_CR_ISOLATE);
        !           264:                        return (0);
        !           265:                }
        !           266:
        !           267:                /*
        !           268:                 * If the interface is not up, don't do anything.
        !           269:                 */
        !           270:                if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
        !           271:                        break;
        !           272:
        !           273:                mii_phy_setmedia(sc);
        !           274:
        !           275:                /*
        !           276:                 * If autonegitation is not enabled, we need a
        !           277:                 * software reset for the settings to take effect.
        !           278:                 */
        !           279:                if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
        !           280:                        bmcr = PHY_READ(sc, E1000_CR);
        !           281:                        PHY_WRITE(sc, E1000_CR, bmcr | E1000_CR_RESET);
        !           282:                }
        !           283:                break;
        !           284:
        !           285:        case MII_TICK:
        !           286:                /*
        !           287:                 * If we're not currently selected, just return.
        !           288:                 */
        !           289:                if (IFM_INST(ife->ifm_media) != sc->mii_inst)
        !           290:                        return (0);
        !           291:
        !           292:                if (mii_phy_tick(sc) == EJUSTRETURN)
        !           293:                         return (0);
        !           294:                break;
        !           295:
        !           296:        case MII_DOWN:
        !           297:                mii_phy_down(sc);
        !           298:                 return (0);
        !           299:        }
        !           300:
        !           301:        /* Update the media status. */
        !           302:        mii_phy_status(sc);
        !           303:
        !           304:        /* Callback if something changed. */
        !           305:        mii_phy_update(sc, cmd);
        !           306:        return (0);
        !           307: }
        !           308:
        !           309: void
        !           310: eephy_status(struct mii_softc *sc)
        !           311: {
        !           312:        struct mii_data *mii = sc->mii_pdata;
        !           313:        int bmcr, gsr, ssr;
        !           314:
        !           315:        mii->mii_media_status = IFM_AVALID;
        !           316:        mii->mii_media_active = IFM_ETHER;
        !           317:
        !           318:        bmcr = PHY_READ(sc, E1000_CR);
        !           319:        ssr = PHY_READ(sc, E1000_SSR);
        !           320:
        !           321:        if (ssr & E1000_SSR_LINK)
        !           322:                mii->mii_media_status |= IFM_ACTIVE;
        !           323:
        !           324:        if (bmcr & E1000_CR_LOOPBACK)
        !           325:                mii->mii_media_active |= IFM_LOOP;
        !           326:
        !           327:        if (!(ssr & E1000_SSR_SPD_DPLX_RESOLVED)) {
        !           328:                /* Erg, still trying, I guess... */
        !           329:                mii->mii_media_active |= IFM_NONE;
        !           330:                return;
        !           331:        }
        !           332:
        !           333:        if (sc->mii_flags & MIIF_IS_1000X) {
        !           334:                mii->mii_media_active |= IFM_1000_SX;
        !           335:        } else {
        !           336:                if (ssr & E1000_SSR_1000MBS)
        !           337:                        mii->mii_media_active |= IFM_1000_T;
        !           338:                else if (ssr & E1000_SSR_100MBS)
        !           339:                        mii->mii_media_active |= IFM_100_TX;
        !           340:                else
        !           341:                        mii->mii_media_active |= IFM_10_T;
        !           342:        }
        !           343:
        !           344:        if (ssr & E1000_SSR_DUPLEX)
        !           345:                mii->mii_media_active |= mii_phy_flowstatus(sc) | IFM_FDX;
        !           346:        else
        !           347:                mii->mii_media_active |= IFM_HDX;
        !           348:
        !           349:        if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) {
        !           350:                gsr = PHY_READ(sc, E1000_1GSR) | PHY_READ(sc, E1000_1GSR);
        !           351:                if (gsr & E1000_1GSR_MS_CONFIG_RES)
        !           352:                        mii->mii_media_active |= IFM_ETH_MASTER;
        !           353:        }
        !           354: }

CVSweb