e1000phy.c revision 183493
1139749Simp/*- 275353Smjacob * Principal Author: Parag Patel 375353Smjacob * Copyright (c) 2001 475353Smjacob * All rights reserved. 575353Smjacob * 675353Smjacob * Redistribution and use in source and binary forms, with or without 775353Smjacob * modification, are permitted provided that the following conditions 875353Smjacob * are met: 975353Smjacob * 1. Redistributions of source code must retain the above copyright 1075353Smjacob * notice unmodified, this list of conditions, and the following 1175353Smjacob * disclaimer. 1275353Smjacob * 2. Redistributions in binary form must reproduce the above copyright 1375353Smjacob * notice, this list of conditions and the following disclaimer in the 1475353Smjacob * documentation and/or other materials provided with the distribution. 1575353Smjacob * 1675353Smjacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1775353Smjacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1875353Smjacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1975353Smjacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2075353Smjacob * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2175353Smjacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2275353Smjacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2375353Smjacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2475353Smjacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2575353Smjacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2675353Smjacob * SUCH DAMAGE. 2775353Smjacob * 2875353Smjacob * Additonal Copyright (c) 2001 by Traakan Software under same licence. 2975353Smjacob * Secondary Author: Matthew Jacob 3075353Smjacob */ 3175353Smjacob 32129843Smarius#include <sys/cdefs.h> 33129843Smarius__FBSDID("$FreeBSD: head/sys/dev/mii/e1000phy.c 183493 2008-09-30 08:18:38Z yongari $"); 34129843Smarius 3575353Smjacob/* 3675353Smjacob * driver for the Marvell 88E1000 series external 1000/100/10-BT PHY. 3775353Smjacob */ 3875353Smjacob 39120281Swilko/* 40120281Swilko * Support added for the Marvell 88E1011 (Alaska) 1000/100/10baseTX and 41120281Swilko * 1000baseSX PHY. 42120281Swilko * Nathan Binkert <nate@openbsd.org> 43120281Swilko * Jung-uk Kim <jkim@niksun.com> 44120281Swilko */ 45120281Swilko 4675353Smjacob#include <sys/param.h> 4775353Smjacob#include <sys/systm.h> 4875353Smjacob#include <sys/kernel.h> 49129876Sphk#include <sys/module.h> 5075353Smjacob#include <sys/socket.h> 5175353Smjacob#include <sys/bus.h> 5275353Smjacob 5375353Smjacob 5475353Smjacob#include <net/if.h> 5575353Smjacob#include <net/if_media.h> 5675353Smjacob 5775353Smjacob#include <dev/mii/mii.h> 5875353Smjacob#include <dev/mii/miivar.h> 59109514Sobrien#include "miidevs.h" 6075353Smjacob 6175353Smjacob#include <dev/mii/e1000phyreg.h> 6275353Smjacob 6375353Smjacob#include "miibus_if.h" 6475353Smjacob 65165095Syongaristatic int e1000phy_probe(device_t); 66165095Syongaristatic int e1000phy_attach(device_t); 6775353Smjacob 68165099Syongaristruct e1000phy_softc { 69165099Syongari struct mii_softc mii_sc; 70165099Syongari int mii_model; 71165099Syongari}; 72165099Syongari 7375353Smjacobstatic device_method_t e1000phy_methods[] = { 7475353Smjacob /* device interface */ 7575353Smjacob DEVMETHOD(device_probe, e1000phy_probe), 7675353Smjacob DEVMETHOD(device_attach, e1000phy_attach), 7795722Sphk DEVMETHOD(device_detach, mii_phy_detach), 7875353Smjacob DEVMETHOD(device_shutdown, bus_generic_shutdown), 7975353Smjacob { 0, 0 } 8075353Smjacob}; 8175353Smjacob 8275353Smjacobstatic devclass_t e1000phy_devclass; 8375353Smjacobstatic driver_t e1000phy_driver = { 84165099Syongari "e1000phy", 85165099Syongari e1000phy_methods, 86165099Syongari sizeof(struct e1000phy_softc) 8775353Smjacob}; 88165099Syongari 8975353SmjacobDRIVER_MODULE(e1000phy, miibus, e1000phy_driver, e1000phy_devclass, 0, 0); 9075353Smjacob 9184145Sjlemonstatic int e1000phy_service(struct mii_softc *, struct mii_data *, int); 9284145Sjlemonstatic void e1000phy_status(struct mii_softc *); 9384145Sjlemonstatic void e1000phy_reset(struct mii_softc *); 94165099Syongaristatic int e1000phy_mii_phy_auto(struct e1000phy_softc *); 9575353Smjacob 96165099Syongaristatic const struct mii_phydesc e1000phys[] = { 97165099Syongari MII_PHY_DESC(MARVELL, E1000), 98165099Syongari MII_PHY_DESC(MARVELL, E1011), 99165099Syongari MII_PHY_DESC(MARVELL, E1000_3), 100165099Syongari MII_PHY_DESC(MARVELL, E1000S), 101165099Syongari MII_PHY_DESC(MARVELL, E1000_5), 102165099Syongari MII_PHY_DESC(MARVELL, E1000_6), 103165099Syongari MII_PHY_DESC(MARVELL, E3082), 104165099Syongari MII_PHY_DESC(MARVELL, E1112), 105165099Syongari MII_PHY_DESC(MARVELL, E1149), 106165099Syongari MII_PHY_DESC(MARVELL, E1111), 107165099Syongari MII_PHY_DESC(MARVELL, E1116), 108182751Sraj MII_PHY_DESC(MARVELL, E1116R), 109165099Syongari MII_PHY_DESC(MARVELL, E1118), 110165099Syongari MII_PHY_DESC(xxMARVELL, E1000), 111165099Syongari MII_PHY_DESC(xxMARVELL, E1011), 112165099Syongari MII_PHY_DESC(xxMARVELL, E1000_3), 113165099Syongari MII_PHY_DESC(xxMARVELL, E1000_5), 114165099Syongari MII_PHY_DESC(xxMARVELL, E1111), 115165099Syongari MII_PHY_END 116165099Syongari}; 11775353Smjacob 11875353Smjacobstatic int 11975353Smjacobe1000phy_probe(device_t dev) 12075353Smjacob{ 12175353Smjacob 122165099Syongari return (mii_phy_dev_probe(dev, e1000phys, BUS_PROBE_DEFAULT)); 12375353Smjacob} 12475353Smjacob 12575353Smjacobstatic int 12675353Smjacobe1000phy_attach(device_t dev) 12775353Smjacob{ 128165099Syongari struct e1000phy_softc *esc; 12975353Smjacob struct mii_softc *sc; 13075353Smjacob struct mii_attach_args *ma; 13175353Smjacob struct mii_data *mii; 132165099Syongari int fast_ether; 13375353Smjacob 134165099Syongari esc = device_get_softc(dev); 135165099Syongari sc = &esc->mii_sc; 13675353Smjacob ma = device_get_ivars(dev); 13775353Smjacob sc->mii_dev = device_get_parent(dev); 13875353Smjacob mii = device_get_softc(sc->mii_dev); 13975353Smjacob LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 14075353Smjacob 14175353Smjacob sc->mii_inst = mii->mii_instance; 14275353Smjacob sc->mii_phy = ma->mii_phyno; 14375353Smjacob sc->mii_service = e1000phy_service; 14475353Smjacob sc->mii_pdata = mii; 145165099Syongari sc->mii_anegticks = MII_ANEGTICKS_GIGE; 146165099Syongari mii->mii_instance++; 14775353Smjacob 148165099Syongari fast_ether = 0; 149165099Syongari esc->mii_model = MII_MODEL(ma->mii_id2); 150165099Syongari switch (esc->mii_model) { 151165099Syongari case MII_MODEL_MARVELL_E1011: 152165099Syongari case MII_MODEL_MARVELL_E1112: 153165099Syongari if (PHY_READ(sc, E1000_ESSR) & E1000_ESSR_FIBER_LINK) 154165099Syongari sc->mii_flags |= MIIF_HAVEFIBER; 155165099Syongari break; 156165099Syongari case MII_MODEL_MARVELL_E3082: 157165099Syongari /* 88E3082 10/100 Fast Ethernet PHY. */ 158165099Syongari sc->mii_anegticks = MII_ANEGTICKS; 159165099Syongari fast_ether = 1; 160165099Syongari break; 161165099Syongari } 162165099Syongari 16375353Smjacob e1000phy_reset(sc); 16475353Smjacob 16584144Sjlemon device_printf(dev, " "); 16684144Sjlemon 16775353Smjacob#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) 168165099Syongari ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), 169165099Syongari E1000_CR_ISOLATE); 170120281Swilko if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { 171120281Swilko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst), 172120281Swilko E1000_CR_SPEED_10); 173120281Swilko printf("10baseT, "); 174120281Swilko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst), 175120281Swilko E1000_CR_SPEED_10 | E1000_CR_FULL_DUPLEX); 176120281Swilko printf("10baseT-FDX, "); 177120281Swilko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst), 178120281Swilko E1000_CR_SPEED_100); 179120281Swilko printf("100baseTX, "); 180120281Swilko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst), 181120281Swilko E1000_CR_SPEED_100 | E1000_CR_FULL_DUPLEX); 182120281Swilko printf("100baseTX-FDX, "); 183165099Syongari if (fast_ether == 0) { 184165099Syongari /* 185165099Syongari * 1000BT-simplex not supported; driver must ignore 186165099Syongari * this entry, but it must be present in order to 187165099Syongari * manually set full-duplex. 188165099Syongari */ 189165099Syongari ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, 190165099Syongari sc->mii_inst), E1000_CR_SPEED_1000); 191165099Syongari ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX, 192165099Syongari sc->mii_inst), 193165099Syongari E1000_CR_SPEED_1000 | E1000_CR_FULL_DUPLEX); 194165099Syongari printf("1000baseTX-FDX, "); 195165099Syongari } 196120281Swilko } else { 197120281Swilko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst), 198120281Swilko E1000_CR_SPEED_1000 | E1000_CR_FULL_DUPLEX); 199120281Swilko printf("1000baseSX-FDX, "); 200120281Swilko } 20175353Smjacob ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0); 20284144Sjlemon printf("auto\n"); 20375353Smjacob#undef ADD 20475353Smjacob 20575353Smjacob MIIBUS_MEDIAINIT(sc->mii_dev); 206165095Syongari return (0); 20775353Smjacob} 20875353Smjacob 20975353Smjacobstatic void 21075353Smjacobe1000phy_reset(struct mii_softc *sc) 21175353Smjacob{ 212165099Syongari struct e1000phy_softc *esc; 213183493Syongari uint16_t reg, page; 21475353Smjacob 215165099Syongari esc = (struct e1000phy_softc *)sc; 21675353Smjacob reg = PHY_READ(sc, E1000_SCR); 217165099Syongari if ((sc->mii_flags & MIIF_HAVEFIBER) != 0) { 218165099Syongari reg &= ~E1000_SCR_AUTO_X_MODE; 219165099Syongari PHY_WRITE(sc, E1000_SCR, reg); 220165099Syongari if (esc->mii_model == MII_MODEL_MARVELL_E1112) { 221165099Syongari /* Select 1000BASE-X only mode. */ 222183493Syongari page = PHY_READ(sc, E1000_EADR); 223165099Syongari PHY_WRITE(sc, E1000_EADR, 2); 224165099Syongari reg = PHY_READ(sc, E1000_SCR); 225165099Syongari reg &= ~E1000_SCR_MODE_MASK; 226165099Syongari reg |= E1000_SCR_MODE_1000BX; 227165099Syongari PHY_WRITE(sc, E1000_SCR, reg); 228183493Syongari PHY_WRITE(sc, E1000_EADR, page); 229165099Syongari } 230165099Syongari } else { 231165099Syongari switch (esc->mii_model) { 232165099Syongari case MII_MODEL_MARVELL_E1111: 233165099Syongari case MII_MODEL_MARVELL_E1112: 234165099Syongari case MII_MODEL_MARVELL_E1116: 235165099Syongari case MII_MODEL_MARVELL_E1118: 236165099Syongari case MII_MODEL_MARVELL_E1149: 237165099Syongari /* Disable energy detect mode. */ 238165099Syongari reg &= ~E1000_SCR_EN_DETECT_MASK; 239165099Syongari reg |= E1000_SCR_AUTO_X_MODE; 240173133Syongari if (esc->mii_model == MII_MODEL_MARVELL_E1116) 241173133Syongari reg &= ~E1000_SCR_POWER_DOWN; 242165099Syongari break; 243165099Syongari case MII_MODEL_MARVELL_E3082: 244165099Syongari reg |= (E1000_SCR_AUTO_X_MODE >> 1); 245165099Syongari break; 246165099Syongari default: 247165099Syongari reg &= ~E1000_SCR_AUTO_X_MODE; 248165099Syongari break; 249165099Syongari } 250165099Syongari /* Enable CRS on TX. */ 251165099Syongari reg |= E1000_SCR_ASSERT_CRS_ON_TX; 252165099Syongari /* Auto correction for reversed cable polarity. */ 253165099Syongari reg &= ~E1000_SCR_POLARITY_REVERSAL; 254165099Syongari PHY_WRITE(sc, E1000_SCR, reg); 255173133Syongari 256173133Syongari if (esc->mii_model == MII_MODEL_MARVELL_E1116) { 257173133Syongari PHY_WRITE(sc, E1000_EADR, 2); 258173133Syongari reg = PHY_READ(sc, E1000_SCR); 259173133Syongari reg |= E1000_SCR_RGMII_POWER_UP; 260173133Syongari PHY_WRITE(sc, E1000_SCR, reg); 261173133Syongari PHY_WRITE(sc, E1000_EADR, 0); 262173133Syongari } 263165099Syongari } 26475353Smjacob 265165099Syongari switch (MII_MODEL(esc->mii_model)) { 266165099Syongari case MII_MODEL_MARVELL_E3082: 267165099Syongari case MII_MODEL_MARVELL_E1112: 268165099Syongari case MII_MODEL_MARVELL_E1116: 269165099Syongari case MII_MODEL_MARVELL_E1118: 270165099Syongari case MII_MODEL_MARVELL_E1149: 271165099Syongari break; 272165099Syongari default: 273165099Syongari /* Force TX_CLK to 25MHz clock. */ 274165099Syongari reg = PHY_READ(sc, E1000_ESCR); 275165099Syongari reg |= E1000_ESCR_TX_CLK_25; 276165099Syongari PHY_WRITE(sc, E1000_ESCR, reg); 277165099Syongari break; 278165099Syongari } 279165099Syongari 280165099Syongari /* Reset the PHY so all changes take effect. */ 28175353Smjacob reg = PHY_READ(sc, E1000_CR); 28275353Smjacob reg |= E1000_CR_RESET; 28375353Smjacob PHY_WRITE(sc, E1000_CR, reg); 28475353Smjacob} 28575353Smjacob 28684145Sjlemonstatic int 28775353Smjacobe1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 28875353Smjacob{ 28975353Smjacob struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 290165099Syongari struct e1000phy_softc *esc = (struct e1000phy_softc *)sc; 291165099Syongari uint16_t speed, gig; 29275353Smjacob int reg; 29375353Smjacob 29475353Smjacob switch (cmd) { 29575353Smjacob case MII_POLLSTAT: 29675353Smjacob /* 29775353Smjacob * If we're not polling our PHY instance, just return. 29875353Smjacob */ 29975353Smjacob if (IFM_INST(ife->ifm_media) != sc->mii_inst) 30075353Smjacob return (0); 30175353Smjacob break; 30275353Smjacob 30375353Smjacob case MII_MEDIACHG: 30475353Smjacob /* 30575353Smjacob * If the media indicates a different PHY instance, 30675353Smjacob * isolate ourselves. 30775353Smjacob */ 30875353Smjacob if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 30975353Smjacob reg = PHY_READ(sc, E1000_CR); 31075353Smjacob PHY_WRITE(sc, E1000_CR, reg | E1000_CR_ISOLATE); 31175353Smjacob return (0); 31275353Smjacob } 31375353Smjacob 31475353Smjacob /* 31575353Smjacob * If the interface is not up, don't do anything. 31675353Smjacob */ 317165095Syongari if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 31875353Smjacob break; 31975353Smjacob 320165099Syongari if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { 321165099Syongari e1000phy_mii_phy_auto(esc); 32275353Smjacob break; 323165099Syongari } 32475353Smjacob 325165099Syongari speed = 0; 326165099Syongari switch (IFM_SUBTYPE(ife->ifm_media)) { 32795673Sphk case IFM_1000_T: 328165099Syongari if (esc->mii_model == MII_MODEL_MARVELL_E3082) 329165099Syongari return (EINVAL); 330165099Syongari speed = E1000_CR_SPEED_1000; 33175353Smjacob break; 332120281Swilko case IFM_1000_SX: 333165099Syongari if (esc->mii_model == MII_MODEL_MARVELL_E3082) 334165099Syongari return (EINVAL); 335165099Syongari speed = E1000_CR_SPEED_1000; 336120281Swilko break; 33775353Smjacob case IFM_100_TX: 338165099Syongari speed = E1000_CR_SPEED_100; 33975353Smjacob break; 34075353Smjacob case IFM_10_T: 341165099Syongari speed = E1000_CR_SPEED_10; 34275353Smjacob break; 343165099Syongari case IFM_NONE: 344165099Syongari reg = PHY_READ(sc, E1000_CR); 345165099Syongari PHY_WRITE(sc, E1000_CR, 346165099Syongari reg | E1000_CR_ISOLATE | E1000_CR_POWER_DOWN); 347165099Syongari goto done; 34875353Smjacob default: 34975353Smjacob return (EINVAL); 35075353Smjacob } 35175353Smjacob 352165099Syongari if (((ife->ifm_media & IFM_GMASK) & IFM_FDX) != 0) { 353165099Syongari speed |= E1000_CR_FULL_DUPLEX; 354165099Syongari gig = E1000_1GCR_1000T_FD; 355165099Syongari } else 356165099Syongari gig = E1000_1GCR_1000T; 357165099Syongari 358165099Syongari reg = PHY_READ(sc, E1000_CR); 359165099Syongari reg &= ~E1000_CR_AUTO_NEG_ENABLE; 360165099Syongari PHY_WRITE(sc, E1000_CR, reg | E1000_CR_RESET); 361165099Syongari 362165099Syongari /* 363165099Syongari * When setting the link manually, one side must 364165099Syongari * be the master and the other the slave. However 365165099Syongari * ifmedia doesn't give us a good way to specify 366165099Syongari * this, so we fake it by using one of the LINK 367165099Syongari * flags. If LINK0 is set, we program the PHY to 368165099Syongari * be a master, otherwise it's a slave. 369165099Syongari */ 370165099Syongari if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T || 371165099Syongari (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_SX)) { 372165099Syongari if ((mii->mii_ifp->if_flags & IFF_LINK0)) 373165099Syongari PHY_WRITE(sc, E1000_1GCR, gig | 374165099Syongari E1000_1GCR_MS_ENABLE | E1000_1GCR_MS_VALUE); 375165099Syongari else 376165099Syongari PHY_WRITE(sc, E1000_1GCR, gig | 377165099Syongari E1000_1GCR_MS_ENABLE); 378165099Syongari } else { 379165099Syongari if (esc->mii_model != MII_MODEL_MARVELL_E3082) 380165099Syongari PHY_WRITE(sc, E1000_1GCR, 0); 381165099Syongari } 382165099Syongari PHY_WRITE(sc, E1000_AR, E1000_AR_SELECTOR_FIELD); 383165099Syongari PHY_WRITE(sc, E1000_CR, speed | E1000_CR_RESET); 384165099Syongaridone: 38575353Smjacob break; 38675353Smjacob case MII_TICK: 38775353Smjacob /* 38875353Smjacob * If we're not currently selected, just return. 38975353Smjacob */ 390165099Syongari if (IFM_INST(ife->ifm_media) != sc->mii_inst) 39175353Smjacob return (0); 39275353Smjacob 39375353Smjacob /* 39484145Sjlemon * Is the interface even up? 39575353Smjacob */ 39684145Sjlemon if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 39775353Smjacob return (0); 39875353Smjacob 39975353Smjacob /* 40084145Sjlemon * Only used for autonegotiation. 40175353Smjacob */ 402173667Syongari if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { 403173667Syongari sc->mii_ticks = 0; 40484145Sjlemon break; 405173667Syongari } 40675353Smjacob 40775353Smjacob /* 40884145Sjlemon * check for link. 40984145Sjlemon * Read the status register twice; BMSR_LINK is latch-low. 41075353Smjacob */ 41184145Sjlemon reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 412165099Syongari if (reg & BMSR_LINK) { 413165099Syongari sc->mii_ticks = 0; 41484145Sjlemon break; 415165099Syongari } 41675353Smjacob 417165099Syongari /* Announce link loss right after it happens. */ 418173667Syongari if (sc->mii_ticks++ == 0) 419173667Syongari break; 420165099Syongari if (sc->mii_ticks <= sc->mii_anegticks) 421165099Syongari return (0); 42275353Smjacob 42384145Sjlemon sc->mii_ticks = 0; 42475353Smjacob e1000phy_reset(sc); 425165099Syongari e1000phy_mii_phy_auto(esc); 426165099Syongari break; 42775353Smjacob } 42875353Smjacob 42975353Smjacob /* Update the media status. */ 43075353Smjacob e1000phy_status(sc); 43175353Smjacob 43275353Smjacob /* Callback if something changed. */ 43384145Sjlemon mii_phy_update(sc, cmd); 43475353Smjacob return (0); 43575353Smjacob} 43675353Smjacob 43784145Sjlemonstatic void 43875353Smjacobe1000phy_status(struct mii_softc *sc) 43975353Smjacob{ 44075353Smjacob struct mii_data *mii = sc->mii_pdata; 441165099Syongari int bmsr, bmcr, esr, gsr, ssr, isr, ar, lpar; 44275353Smjacob 44375353Smjacob mii->mii_media_status = IFM_AVALID; 44475353Smjacob mii->mii_media_active = IFM_ETHER; 44575353Smjacob 44675353Smjacob bmsr = PHY_READ(sc, E1000_SR) | PHY_READ(sc, E1000_SR); 44775353Smjacob esr = PHY_READ(sc, E1000_ESR); 44875353Smjacob bmcr = PHY_READ(sc, E1000_CR); 44975353Smjacob ssr = PHY_READ(sc, E1000_SSR); 45075353Smjacob isr = PHY_READ(sc, E1000_ISR); 45175353Smjacob ar = PHY_READ(sc, E1000_AR); 45275353Smjacob lpar = PHY_READ(sc, E1000_LPAR); 45375353Smjacob 45475353Smjacob if (bmsr & E1000_SR_LINK_STATUS) 45575353Smjacob mii->mii_media_status |= IFM_ACTIVE; 45675353Smjacob 45775353Smjacob if (bmcr & E1000_CR_LOOPBACK) 45875353Smjacob mii->mii_media_active |= IFM_LOOP; 45975353Smjacob 460165099Syongari if ((((bmcr & E1000_CR_AUTO_NEG_ENABLE) != 0) && 461165099Syongari ((bmsr & E1000_SR_AUTO_NEG_COMPLETE) == 0)) || 462165099Syongari ((ssr & E1000_SSR_LINK) == 0) || 463165099Syongari ((ssr & E1000_SSR_SPD_DPLX_RESOLVED) == 0)) { 46475353Smjacob /* Erg, still trying, I guess... */ 46575353Smjacob mii->mii_media_active |= IFM_NONE; 46675353Smjacob return; 46775353Smjacob } 46875353Smjacob 469120281Swilko if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { 470120281Swilko if (ssr & E1000_SSR_1000MBS) 471120281Swilko mii->mii_media_active |= IFM_1000_T; 472120281Swilko else if (ssr & E1000_SSR_100MBS) 473120281Swilko mii->mii_media_active |= IFM_100_TX; 474120281Swilko else 475120281Swilko mii->mii_media_active |= IFM_10_T; 476120281Swilko } else { 477120281Swilko if (ssr & E1000_SSR_1000MBS) 478120281Swilko mii->mii_media_active |= IFM_1000_SX; 479120281Swilko } 48075353Smjacob 48175353Smjacob if (ssr & E1000_SSR_DUPLEX) 48275353Smjacob mii->mii_media_active |= IFM_FDX; 48375353Smjacob else 48475353Smjacob mii->mii_media_active |= IFM_HDX; 48575353Smjacob 486120281Swilko if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { 487120281Swilko /* FLAG0==rx-flow-control FLAG1==tx-flow-control */ 488120281Swilko if ((ar & E1000_AR_PAUSE) && (lpar & E1000_LPAR_PAUSE)) { 489120281Swilko mii->mii_media_active |= IFM_FLAG0 | IFM_FLAG1; 490120281Swilko } else if (!(ar & E1000_AR_PAUSE) && (ar & E1000_AR_ASM_DIR) && 491120281Swilko (lpar & E1000_LPAR_PAUSE) && (lpar & E1000_LPAR_ASM_DIR)) { 492120281Swilko mii->mii_media_active |= IFM_FLAG1; 493120281Swilko } else if ((ar & E1000_AR_PAUSE) && (ar & E1000_AR_ASM_DIR) && 494120281Swilko !(lpar & E1000_LPAR_PAUSE) && (lpar & E1000_LPAR_ASM_DIR)) { 495120281Swilko mii->mii_media_active |= IFM_FLAG0; 496120281Swilko } 49775353Smjacob } 498165099Syongari 499165099Syongari /* FLAG2 : local PHY resolved to MASTER */ 500165099Syongari if ((IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) || 501165099Syongari (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX)) { 502165099Syongari PHY_READ(sc, E1000_1GSR); 503165099Syongari gsr = PHY_READ(sc, E1000_1GSR); 504165099Syongari if ((gsr & E1000_1GSR_MS_CONFIG_RES) != 0) 505165099Syongari mii->mii_media_active |= IFM_FLAG2; 506165099Syongari } 50775353Smjacob} 50875353Smjacob 50975353Smjacobstatic int 510165099Syongarie1000phy_mii_phy_auto(struct e1000phy_softc *esc) 51175353Smjacob{ 512165099Syongari struct mii_softc *sc; 51375353Smjacob 514165099Syongari sc = &esc->mii_sc; 515165099Syongari if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) 516165099Syongari PHY_WRITE(sc, E1000_AR, E1000_AR_10T | E1000_AR_10T_FD | 517165099Syongari E1000_AR_100TX | E1000_AR_100TX_FD | 518120281Swilko E1000_AR_PAUSE | E1000_AR_ASM_DIR); 519165099Syongari else 520165099Syongari PHY_WRITE(sc, E1000_AR, E1000_FA_1000X_FD | E1000_FA_1000X | 521165099Syongari E1000_FA_SYM_PAUSE | E1000_FA_ASYM_PAUSE); 522165099Syongari if (esc->mii_model != MII_MODEL_MARVELL_E3082) 523165099Syongari PHY_WRITE(sc, E1000_1GCR, 524165099Syongari E1000_1GCR_1000T_FD | E1000_1GCR_1000T); 525165099Syongari PHY_WRITE(sc, E1000_CR, 526165099Syongari E1000_CR_AUTO_NEG_ENABLE | E1000_CR_RESTART_AUTO_NEG); 52775353Smjacob 52875353Smjacob return (EJUSTRETURN); 52975353Smjacob} 530