e1000phy.c revision 193291
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 193291 2009-06-02 00:30:30Z 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), 110192713Syongari MII_PHY_DESC(MARVELL, E3016), 111165099Syongari MII_PHY_DESC(xxMARVELL, E1000), 112165099Syongari MII_PHY_DESC(xxMARVELL, E1011), 113165099Syongari MII_PHY_DESC(xxMARVELL, E1000_3), 114165099Syongari MII_PHY_DESC(xxMARVELL, E1000_5), 115165099Syongari MII_PHY_DESC(xxMARVELL, E1111), 116165099Syongari MII_PHY_END 117165099Syongari}; 11875353Smjacob 11975353Smjacobstatic int 12075353Smjacobe1000phy_probe(device_t dev) 12175353Smjacob{ 12275353Smjacob 123165099Syongari return (mii_phy_dev_probe(dev, e1000phys, BUS_PROBE_DEFAULT)); 12475353Smjacob} 12575353Smjacob 12675353Smjacobstatic int 12775353Smjacobe1000phy_attach(device_t dev) 12875353Smjacob{ 129165099Syongari struct e1000phy_softc *esc; 13075353Smjacob struct mii_softc *sc; 13175353Smjacob struct mii_attach_args *ma; 13275353Smjacob struct mii_data *mii; 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 mii->mii_instance++; 14675353Smjacob 147165099Syongari esc->mii_model = MII_MODEL(ma->mii_id2); 148165099Syongari switch (esc->mii_model) { 149165099Syongari case MII_MODEL_MARVELL_E1011: 150165099Syongari case MII_MODEL_MARVELL_E1112: 151165099Syongari if (PHY_READ(sc, E1000_ESSR) & E1000_ESSR_FIBER_LINK) 152165099Syongari sc->mii_flags |= MIIF_HAVEFIBER; 153165099Syongari break; 154183966Syongari case MII_MODEL_MARVELL_E1149: 155183966Syongari /* 156183966Syongari * Some 88E1149 PHY's page select is initialized to 157183966Syongari * point to other bank instead of copper/fiber bank 158183966Syongari * which in turn resulted in wrong registers were 159183966Syongari * accessed during PHY operation. It is believed that 160183966Syongari * page 0 should be used for copper PHY so reinitialize 161183966Syongari * E1000_EADR to select default copper PHY. If parent 162183966Syongari * device know the type of PHY(either copper or fiber), 163183966Syongari * that information should be used to select default 164183966Syongari * type of PHY. 165183966Syongari */ 166183966Syongari PHY_WRITE(sc, E1000_EADR, 0); 167183966Syongari break; 168165099Syongari } 169165099Syongari 17075353Smjacob e1000phy_reset(sc); 17175353Smjacob 172192708Syongari sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 173192708Syongari if (sc->mii_capabilities & BMSR_EXTSTAT) 174192708Syongari sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); 17584144Sjlemon device_printf(dev, " "); 176192708Syongari mii_phy_add_media(sc); 177192708Syongari printf("\n"); 17884144Sjlemon 17975353Smjacob MIIBUS_MEDIAINIT(sc->mii_dev); 180165095Syongari return (0); 18175353Smjacob} 18275353Smjacob 18375353Smjacobstatic void 18475353Smjacobe1000phy_reset(struct mii_softc *sc) 18575353Smjacob{ 186165099Syongari struct e1000phy_softc *esc; 187183493Syongari uint16_t reg, page; 18875353Smjacob 189165099Syongari esc = (struct e1000phy_softc *)sc; 19075353Smjacob reg = PHY_READ(sc, E1000_SCR); 191165099Syongari if ((sc->mii_flags & MIIF_HAVEFIBER) != 0) { 192165099Syongari reg &= ~E1000_SCR_AUTO_X_MODE; 193165099Syongari PHY_WRITE(sc, E1000_SCR, reg); 194165099Syongari if (esc->mii_model == MII_MODEL_MARVELL_E1112) { 195165099Syongari /* Select 1000BASE-X only mode. */ 196183493Syongari page = PHY_READ(sc, E1000_EADR); 197165099Syongari PHY_WRITE(sc, E1000_EADR, 2); 198165099Syongari reg = PHY_READ(sc, E1000_SCR); 199165099Syongari reg &= ~E1000_SCR_MODE_MASK; 200165099Syongari reg |= E1000_SCR_MODE_1000BX; 201165099Syongari PHY_WRITE(sc, E1000_SCR, reg); 202183493Syongari PHY_WRITE(sc, E1000_EADR, page); 203165099Syongari } 204165099Syongari } else { 205165099Syongari switch (esc->mii_model) { 206165099Syongari case MII_MODEL_MARVELL_E1111: 207165099Syongari case MII_MODEL_MARVELL_E1112: 208165099Syongari case MII_MODEL_MARVELL_E1116: 209165099Syongari case MII_MODEL_MARVELL_E1118: 210165099Syongari case MII_MODEL_MARVELL_E1149: 211165099Syongari /* Disable energy detect mode. */ 212165099Syongari reg &= ~E1000_SCR_EN_DETECT_MASK; 213165099Syongari reg |= E1000_SCR_AUTO_X_MODE; 214173133Syongari if (esc->mii_model == MII_MODEL_MARVELL_E1116) 215173133Syongari reg &= ~E1000_SCR_POWER_DOWN; 216192713Syongari reg |= E1000_SCR_ASSERT_CRS_ON_TX; 217165099Syongari break; 218165099Syongari case MII_MODEL_MARVELL_E3082: 219165099Syongari reg |= (E1000_SCR_AUTO_X_MODE >> 1); 220192713Syongari reg |= E1000_SCR_ASSERT_CRS_ON_TX; 221165099Syongari break; 222192713Syongari case MII_MODEL_MARVELL_E3016: 223192713Syongari reg |= E1000_SCR_AUTO_MDIX; 224192713Syongari reg &= ~(E1000_SCR_EN_DETECT | 225192713Syongari E1000_SCR_SCRAMBLER_DISABLE); 226192713Syongari reg |= E1000_SCR_LPNP; 227192713Syongari /* XXX Enable class A driver for Yukon FE+ A0. */ 228192713Syongari PHY_WRITE(sc, 0x1C, PHY_READ(sc, 0x1C) | 0x0001); 229192713Syongari break; 230165099Syongari default: 231165099Syongari reg &= ~E1000_SCR_AUTO_X_MODE; 232192713Syongari reg |= E1000_SCR_ASSERT_CRS_ON_TX; 233165099Syongari break; 234165099Syongari } 235192713Syongari if (esc->mii_model != MII_MODEL_MARVELL_E3016) { 236192713Syongari /* Auto correction for reversed cable polarity. */ 237192713Syongari reg &= ~E1000_SCR_POLARITY_REVERSAL; 238192713Syongari } 239165099Syongari PHY_WRITE(sc, E1000_SCR, reg); 240173133Syongari 241193291Syongari if (esc->mii_model == MII_MODEL_MARVELL_E1116 || 242193291Syongari esc->mii_model == MII_MODEL_MARVELL_E1149) { 243193289Syongari page = PHY_READ(sc, E1000_EADR); 244193289Syongari /* Select page 2, MAC specific control register. */ 245173133Syongari PHY_WRITE(sc, E1000_EADR, 2); 246173133Syongari reg = PHY_READ(sc, E1000_SCR); 247173133Syongari reg |= E1000_SCR_RGMII_POWER_UP; 248173133Syongari PHY_WRITE(sc, E1000_SCR, reg); 249193289Syongari PHY_WRITE(sc, E1000_EADR, page); 250173133Syongari } 251165099Syongari } 25275353Smjacob 253165099Syongari switch (MII_MODEL(esc->mii_model)) { 254165099Syongari case MII_MODEL_MARVELL_E3082: 255165099Syongari case MII_MODEL_MARVELL_E1112: 256193291Syongari case MII_MODEL_MARVELL_E1118: 257193291Syongari break; 258165099Syongari case MII_MODEL_MARVELL_E1116: 259165099Syongari case MII_MODEL_MARVELL_E1149: 260193291Syongari page = PHY_READ(sc, E1000_EADR); 261193291Syongari /* Select page 3, LED control register. */ 262193291Syongari PHY_WRITE(sc, E1000_EADR, 3); 263193291Syongari PHY_WRITE(sc, E1000_SCR, 264193291Syongari E1000_SCR_LED_LOS(1) | /* Link/Act */ 265193291Syongari E1000_SCR_LED_INIT(8) | /* 10Mbps */ 266193291Syongari E1000_SCR_LED_STAT1(7) | /* 100Mbps */ 267193291Syongari E1000_SCR_LED_STAT0(7)); /* 1000Mbps */ 268193291Syongari /* Set blink rate. */ 269193291Syongari PHY_WRITE(sc, E1000_IER, E1000_PULSE_DUR(E1000_PULSE_170MS) | 270193291Syongari E1000_BLINK_RATE(E1000_BLINK_84MS)); 271193291Syongari PHY_WRITE(sc, E1000_EADR, page); 272165099Syongari break; 273192713Syongari case MII_MODEL_MARVELL_E3016: 274192713Syongari /* LED2 -> ACT, LED1 -> LINK, LED0 -> SPEED. */ 275192713Syongari PHY_WRITE(sc, 0x16, 0x0B << 8 | 0x05 << 4 | 0x04); 276192713Syongari /* Integrated register calibration workaround. */ 277192713Syongari PHY_WRITE(sc, 0x1D, 17); 278192713Syongari PHY_WRITE(sc, 0x1E, 0x3F60); 279192713Syongari break; 280165099Syongari default: 281165099Syongari /* Force TX_CLK to 25MHz clock. */ 282165099Syongari reg = PHY_READ(sc, E1000_ESCR); 283165099Syongari reg |= E1000_ESCR_TX_CLK_25; 284165099Syongari PHY_WRITE(sc, E1000_ESCR, reg); 285165099Syongari break; 286165099Syongari } 287165099Syongari 288165099Syongari /* Reset the PHY so all changes take effect. */ 28975353Smjacob reg = PHY_READ(sc, E1000_CR); 29075353Smjacob reg |= E1000_CR_RESET; 29175353Smjacob PHY_WRITE(sc, E1000_CR, reg); 29275353Smjacob} 29375353Smjacob 29484145Sjlemonstatic int 29575353Smjacobe1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 29675353Smjacob{ 29775353Smjacob struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 298165099Syongari struct e1000phy_softc *esc = (struct e1000phy_softc *)sc; 299165099Syongari uint16_t speed, gig; 30075353Smjacob int reg; 30175353Smjacob 30275353Smjacob switch (cmd) { 30375353Smjacob case MII_POLLSTAT: 30475353Smjacob /* 30575353Smjacob * If we're not polling our PHY instance, just return. 30675353Smjacob */ 30775353Smjacob if (IFM_INST(ife->ifm_media) != sc->mii_inst) 30875353Smjacob return (0); 30975353Smjacob break; 31075353Smjacob 31175353Smjacob case MII_MEDIACHG: 31275353Smjacob /* 31375353Smjacob * If the media indicates a different PHY instance, 31475353Smjacob * isolate ourselves. 31575353Smjacob */ 31675353Smjacob if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 31775353Smjacob reg = PHY_READ(sc, E1000_CR); 31875353Smjacob PHY_WRITE(sc, E1000_CR, reg | E1000_CR_ISOLATE); 31975353Smjacob return (0); 32075353Smjacob } 32175353Smjacob 32275353Smjacob /* 32375353Smjacob * If the interface is not up, don't do anything. 32475353Smjacob */ 325165095Syongari if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 32675353Smjacob break; 32775353Smjacob 328165099Syongari if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { 329165099Syongari e1000phy_mii_phy_auto(esc); 33075353Smjacob break; 331165099Syongari } 33275353Smjacob 333165099Syongari speed = 0; 334165099Syongari switch (IFM_SUBTYPE(ife->ifm_media)) { 33595673Sphk case IFM_1000_T: 336192708Syongari if ((sc->mii_extcapabilities & 337192708Syongari (EXTSR_1000TFDX | EXTSR_1000THDX)) == 0) 338165099Syongari return (EINVAL); 339165099Syongari speed = E1000_CR_SPEED_1000; 34075353Smjacob break; 341120281Swilko case IFM_1000_SX: 342192708Syongari if ((sc->mii_extcapabilities & 343192708Syongari (EXTSR_1000XFDX | EXTSR_1000XHDX)) == 0) 344165099Syongari return (EINVAL); 345165099Syongari speed = E1000_CR_SPEED_1000; 346120281Swilko break; 34775353Smjacob case IFM_100_TX: 348165099Syongari speed = E1000_CR_SPEED_100; 34975353Smjacob break; 35075353Smjacob case IFM_10_T: 351165099Syongari speed = E1000_CR_SPEED_10; 35275353Smjacob break; 353165099Syongari case IFM_NONE: 354165099Syongari reg = PHY_READ(sc, E1000_CR); 355165099Syongari PHY_WRITE(sc, E1000_CR, 356165099Syongari reg | E1000_CR_ISOLATE | E1000_CR_POWER_DOWN); 357165099Syongari goto done; 35875353Smjacob default: 35975353Smjacob return (EINVAL); 36075353Smjacob } 36175353Smjacob 362165099Syongari if (((ife->ifm_media & IFM_GMASK) & IFM_FDX) != 0) { 363165099Syongari speed |= E1000_CR_FULL_DUPLEX; 364165099Syongari gig = E1000_1GCR_1000T_FD; 365165099Syongari } else 366165099Syongari gig = E1000_1GCR_1000T; 367165099Syongari 368165099Syongari reg = PHY_READ(sc, E1000_CR); 369165099Syongari reg &= ~E1000_CR_AUTO_NEG_ENABLE; 370165099Syongari PHY_WRITE(sc, E1000_CR, reg | E1000_CR_RESET); 371165099Syongari 372165099Syongari /* 373165099Syongari * When setting the link manually, one side must 374165099Syongari * be the master and the other the slave. However 375165099Syongari * ifmedia doesn't give us a good way to specify 376165099Syongari * this, so we fake it by using one of the LINK 377165099Syongari * flags. If LINK0 is set, we program the PHY to 378165099Syongari * be a master, otherwise it's a slave. 379165099Syongari */ 380165099Syongari if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T || 381165099Syongari (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_SX)) { 382165099Syongari if ((mii->mii_ifp->if_flags & IFF_LINK0)) 383165099Syongari PHY_WRITE(sc, E1000_1GCR, gig | 384165099Syongari E1000_1GCR_MS_ENABLE | E1000_1GCR_MS_VALUE); 385165099Syongari else 386165099Syongari PHY_WRITE(sc, E1000_1GCR, gig | 387165099Syongari E1000_1GCR_MS_ENABLE); 388165099Syongari } else { 389192708Syongari if ((sc->mii_extcapabilities & 390192708Syongari (EXTSR_1000TFDX | EXTSR_1000THDX)) != 0) 391165099Syongari PHY_WRITE(sc, E1000_1GCR, 0); 392165099Syongari } 393165099Syongari PHY_WRITE(sc, E1000_AR, E1000_AR_SELECTOR_FIELD); 394165099Syongari PHY_WRITE(sc, E1000_CR, speed | E1000_CR_RESET); 395165099Syongaridone: 39675353Smjacob break; 39775353Smjacob case MII_TICK: 39875353Smjacob /* 39975353Smjacob * If we're not currently selected, just return. 40075353Smjacob */ 401165099Syongari if (IFM_INST(ife->ifm_media) != sc->mii_inst) 40275353Smjacob return (0); 40375353Smjacob 40475353Smjacob /* 40584145Sjlemon * Is the interface even up? 40675353Smjacob */ 40784145Sjlemon if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 40875353Smjacob return (0); 40975353Smjacob 41075353Smjacob /* 41184145Sjlemon * Only used for autonegotiation. 41275353Smjacob */ 413173667Syongari if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { 414173667Syongari sc->mii_ticks = 0; 41584145Sjlemon break; 416173667Syongari } 41775353Smjacob 41875353Smjacob /* 41984145Sjlemon * check for link. 42084145Sjlemon * Read the status register twice; BMSR_LINK is latch-low. 42175353Smjacob */ 42284145Sjlemon reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 423165099Syongari if (reg & BMSR_LINK) { 424165099Syongari sc->mii_ticks = 0; 42584145Sjlemon break; 426165099Syongari } 42775353Smjacob 428165099Syongari /* Announce link loss right after it happens. */ 429173667Syongari if (sc->mii_ticks++ == 0) 430173667Syongari break; 431165099Syongari if (sc->mii_ticks <= sc->mii_anegticks) 432192709Syongari break; 43375353Smjacob 43484145Sjlemon sc->mii_ticks = 0; 43575353Smjacob e1000phy_reset(sc); 436165099Syongari e1000phy_mii_phy_auto(esc); 437165099Syongari break; 43875353Smjacob } 43975353Smjacob 44075353Smjacob /* Update the media status. */ 44175353Smjacob e1000phy_status(sc); 44275353Smjacob 44375353Smjacob /* Callback if something changed. */ 44484145Sjlemon mii_phy_update(sc, cmd); 44575353Smjacob return (0); 44675353Smjacob} 44775353Smjacob 44884145Sjlemonstatic void 44975353Smjacobe1000phy_status(struct mii_softc *sc) 45075353Smjacob{ 45175353Smjacob struct mii_data *mii = sc->mii_pdata; 452192710Syongari int bmcr, bmsr, gsr, ssr, ar, lpar; 45375353Smjacob 45475353Smjacob mii->mii_media_status = IFM_AVALID; 45575353Smjacob mii->mii_media_active = IFM_ETHER; 45675353Smjacob 45775353Smjacob bmsr = PHY_READ(sc, E1000_SR) | PHY_READ(sc, E1000_SR); 45875353Smjacob bmcr = PHY_READ(sc, E1000_CR); 45975353Smjacob ssr = PHY_READ(sc, E1000_SSR); 46075353Smjacob 46175353Smjacob if (bmsr & E1000_SR_LINK_STATUS) 46275353Smjacob mii->mii_media_status |= IFM_ACTIVE; 46375353Smjacob 46475353Smjacob if (bmcr & E1000_CR_LOOPBACK) 46575353Smjacob mii->mii_media_active |= IFM_LOOP; 46675353Smjacob 467192710Syongari if ((bmcr & E1000_CR_AUTO_NEG_ENABLE) != 0 && 468192710Syongari (ssr & E1000_SSR_SPD_DPLX_RESOLVED) == 0) { 46975353Smjacob /* Erg, still trying, I guess... */ 47075353Smjacob mii->mii_media_active |= IFM_NONE; 47175353Smjacob return; 47275353Smjacob } 47375353Smjacob 474120281Swilko if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { 475192710Syongari switch (ssr & E1000_SSR_SPEED) { 476192710Syongari case E1000_SSR_1000MBS: 477120281Swilko mii->mii_media_active |= IFM_1000_T; 478192710Syongari break; 479192710Syongari case E1000_SSR_100MBS: 480120281Swilko mii->mii_media_active |= IFM_100_TX; 481192710Syongari break; 482192710Syongari case E1000_SSR_10MBS: 483120281Swilko mii->mii_media_active |= IFM_10_T; 484192710Syongari break; 485192710Syongari default: 486192710Syongari mii->mii_media_active |= IFM_NONE; 487192710Syongari return; 488192710Syongari } 489120281Swilko } else { 490120281Swilko if (ssr & E1000_SSR_1000MBS) 491120281Swilko mii->mii_media_active |= IFM_1000_SX; 492120281Swilko } 49375353Smjacob 49475353Smjacob if (ssr & E1000_SSR_DUPLEX) 49575353Smjacob mii->mii_media_active |= IFM_FDX; 49675353Smjacob else 49775353Smjacob mii->mii_media_active |= IFM_HDX; 49875353Smjacob 499120281Swilko if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { 500192710Syongari ar = PHY_READ(sc, E1000_AR); 501192710Syongari lpar = PHY_READ(sc, E1000_LPAR); 502120281Swilko /* FLAG0==rx-flow-control FLAG1==tx-flow-control */ 503120281Swilko if ((ar & E1000_AR_PAUSE) && (lpar & E1000_LPAR_PAUSE)) { 504120281Swilko mii->mii_media_active |= IFM_FLAG0 | IFM_FLAG1; 505120281Swilko } else if (!(ar & E1000_AR_PAUSE) && (ar & E1000_AR_ASM_DIR) && 506120281Swilko (lpar & E1000_LPAR_PAUSE) && (lpar & E1000_LPAR_ASM_DIR)) { 507120281Swilko mii->mii_media_active |= IFM_FLAG1; 508120281Swilko } else if ((ar & E1000_AR_PAUSE) && (ar & E1000_AR_ASM_DIR) && 509120281Swilko !(lpar & E1000_LPAR_PAUSE) && (lpar & E1000_LPAR_ASM_DIR)) { 510120281Swilko mii->mii_media_active |= IFM_FLAG0; 511120281Swilko } 51275353Smjacob } 513165099Syongari 514165099Syongari /* FLAG2 : local PHY resolved to MASTER */ 515165099Syongari if ((IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) || 516165099Syongari (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX)) { 517165099Syongari PHY_READ(sc, E1000_1GSR); 518165099Syongari gsr = PHY_READ(sc, E1000_1GSR); 519165099Syongari if ((gsr & E1000_1GSR_MS_CONFIG_RES) != 0) 520165099Syongari mii->mii_media_active |= IFM_FLAG2; 521165099Syongari } 52275353Smjacob} 52375353Smjacob 52475353Smjacobstatic int 525165099Syongarie1000phy_mii_phy_auto(struct e1000phy_softc *esc) 52675353Smjacob{ 527165099Syongari struct mii_softc *sc; 528192711Syongari uint16_t reg; 52975353Smjacob 530165099Syongari sc = &esc->mii_sc; 531192711Syongari if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { 532192711Syongari reg = PHY_READ(sc, E1000_AR); 533192711Syongari reg |= E1000_AR_10T | E1000_AR_10T_FD | 534165099Syongari E1000_AR_100TX | E1000_AR_100TX_FD | 535192711Syongari E1000_AR_PAUSE | E1000_AR_ASM_DIR; 536192711Syongari PHY_WRITE(sc, E1000_AR, reg | E1000_AR_SELECTOR_FIELD); 537192711Syongari } else 538165099Syongari PHY_WRITE(sc, E1000_AR, E1000_FA_1000X_FD | E1000_FA_1000X | 539165099Syongari E1000_FA_SYM_PAUSE | E1000_FA_ASYM_PAUSE); 540192708Syongari if ((sc->mii_extcapabilities & (EXTSR_1000TFDX | EXTSR_1000THDX)) != 0) 541165099Syongari PHY_WRITE(sc, E1000_1GCR, 542165099Syongari E1000_1GCR_1000T_FD | E1000_1GCR_1000T); 543165099Syongari PHY_WRITE(sc, E1000_CR, 544165099Syongari E1000_CR_AUTO_NEG_ENABLE | E1000_CR_RESTART_AUTO_NEG); 54575353Smjacob 54675353Smjacob return (EJUSTRETURN); 54775353Smjacob} 548