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