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 * 28220938Smarius * Additional Copyright (c) 2001 by Traakan Software under same licence. 2975353Smjacob * Secondary Author: Matthew Jacob 3075353Smjacob */ 3175353Smjacob 32129843Smarius#include <sys/cdefs.h> 33129843Smarius__FBSDID("$FreeBSD$"); 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#include <net/if.h> 54257184Sglebius#include <net/if_var.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 6875353Smjacobstatic device_method_t e1000phy_methods[] = { 6975353Smjacob /* device interface */ 7075353Smjacob DEVMETHOD(device_probe, e1000phy_probe), 7175353Smjacob DEVMETHOD(device_attach, e1000phy_attach), 7295722Sphk DEVMETHOD(device_detach, mii_phy_detach), 7375353Smjacob DEVMETHOD(device_shutdown, bus_generic_shutdown), 74227908Smarius DEVMETHOD_END 7575353Smjacob}; 7675353Smjacob 7775353Smjacobstatic devclass_t e1000phy_devclass; 7875353Smjacobstatic driver_t e1000phy_driver = { 79165099Syongari "e1000phy", 80165099Syongari e1000phy_methods, 81221407Smarius sizeof(struct mii_softc) 8275353Smjacob}; 83165099Syongari 8475353SmjacobDRIVER_MODULE(e1000phy, miibus, e1000phy_driver, e1000phy_devclass, 0, 0); 8575353Smjacob 8684145Sjlemonstatic int e1000phy_service(struct mii_softc *, struct mii_data *, int); 8784145Sjlemonstatic void e1000phy_status(struct mii_softc *); 8884145Sjlemonstatic void e1000phy_reset(struct mii_softc *); 89221407Smariusstatic int e1000phy_mii_phy_auto(struct mii_softc *, int); 9075353Smjacob 91165099Syongaristatic const struct mii_phydesc e1000phys[] = { 92165099Syongari MII_PHY_DESC(MARVELL, E1000), 93165099Syongari MII_PHY_DESC(MARVELL, E1011), 94165099Syongari MII_PHY_DESC(MARVELL, E1000_3), 95165099Syongari MII_PHY_DESC(MARVELL, E1000_5), 96165099Syongari MII_PHY_DESC(MARVELL, E1111), 97165099Syongari MII_PHY_DESC(xxMARVELL, E1000), 98165099Syongari MII_PHY_DESC(xxMARVELL, E1011), 99165099Syongari MII_PHY_DESC(xxMARVELL, E1000_3), 100221407Smarius MII_PHY_DESC(xxMARVELL, E1000S), 101165099Syongari MII_PHY_DESC(xxMARVELL, E1000_5), 102221407Smarius MII_PHY_DESC(xxMARVELL, E1101), 103221407Smarius MII_PHY_DESC(xxMARVELL, E3082), 104221407Smarius MII_PHY_DESC(xxMARVELL, E1112), 105221407Smarius MII_PHY_DESC(xxMARVELL, E1149), 106165099Syongari MII_PHY_DESC(xxMARVELL, E1111), 107221407Smarius MII_PHY_DESC(xxMARVELL, E1116), 108221407Smarius MII_PHY_DESC(xxMARVELL, E1116R), 109238874Shrs MII_PHY_DESC(xxMARVELL, E1116R_29), 110221407Smarius MII_PHY_DESC(xxMARVELL, E1118), 111242272Sjmallett MII_PHY_DESC(xxMARVELL, E1145), 112223688Simp MII_PHY_DESC(xxMARVELL, E1149R), 113221407Smarius MII_PHY_DESC(xxMARVELL, E3016), 114221407Smarius MII_PHY_DESC(xxMARVELL, PHYG65G), 115165099Syongari MII_PHY_END 116165099Syongari}; 11775353Smjacob 118221407Smariusstatic const struct mii_phy_funcs e1000phy_funcs = { 119221407Smarius e1000phy_service, 120221407Smarius e1000phy_status, 121221407Smarius e1000phy_reset 122221407Smarius}; 123221407Smarius 12475353Smjacobstatic int 12575353Smjacobe1000phy_probe(device_t dev) 12675353Smjacob{ 12775353Smjacob 128165099Syongari return (mii_phy_dev_probe(dev, e1000phys, BUS_PROBE_DEFAULT)); 12975353Smjacob} 13075353Smjacob 13175353Smjacobstatic int 13275353Smjacobe1000phy_attach(device_t dev) 13375353Smjacob{ 13475353Smjacob struct mii_softc *sc; 13575353Smjacob 136221407Smarius sc = device_get_softc(dev); 13775353Smjacob 138221407Smarius mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &e1000phy_funcs, 0); 13975353Smjacob 140277105Sglebius if (mii_dev_mac_match(dev, "msk") && 141277105Sglebius (sc->mii_flags & MIIF_MACPRIV0) != 0) 142213893Smarius sc->mii_flags |= MIIF_PHYPRIV0; 143197590Syongari 144221407Smarius switch (sc->mii_mpd_model) { 145221407Smarius case MII_MODEL_xxMARVELL_E1011: 146221407Smarius case MII_MODEL_xxMARVELL_E1112: 147165099Syongari if (PHY_READ(sc, E1000_ESSR) & E1000_ESSR_FIBER_LINK) 148165099Syongari sc->mii_flags |= MIIF_HAVEFIBER; 149165099Syongari break; 150221407Smarius case MII_MODEL_xxMARVELL_E1149: 151223688Simp case MII_MODEL_xxMARVELL_E1149R: 152183966Syongari /* 153183966Syongari * Some 88E1149 PHY's page select is initialized to 154183966Syongari * point to other bank instead of copper/fiber bank 155183966Syongari * which in turn resulted in wrong registers were 156183966Syongari * accessed during PHY operation. It is believed that 157183966Syongari * page 0 should be used for copper PHY so reinitialize 158183966Syongari * E1000_EADR to select default copper PHY. If parent 159183966Syongari * device know the type of PHY(either copper or fiber), 160183966Syongari * that information should be used to select default 161183966Syongari * type of PHY. 162183966Syongari */ 163183966Syongari PHY_WRITE(sc, E1000_EADR, 0); 164183966Syongari break; 165165099Syongari } 166165099Syongari 167221407Smarius PHY_RESET(sc); 16875353Smjacob 169221407Smarius sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & sc->mii_capmask; 170271073Syongari if (sc->mii_capabilities & BMSR_EXTSTAT) { 171192708Syongari sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); 172271073Syongari if ((sc->mii_extcapabilities & 173271073Syongari (EXTSR_1000TFDX | EXTSR_1000THDX)) != 0) 174271073Syongari sc->mii_flags |= MIIF_HAVE_GTCR; 175271073Syongari } 17684144Sjlemon device_printf(dev, " "); 177192708Syongari mii_phy_add_media(sc); 178192708Syongari printf("\n"); 17984144Sjlemon 18075353Smjacob MIIBUS_MEDIAINIT(sc->mii_dev); 181165095Syongari return (0); 18275353Smjacob} 18375353Smjacob 18475353Smjacobstatic void 18575353Smjacobe1000phy_reset(struct mii_softc *sc) 18675353Smjacob{ 187183493Syongari uint16_t reg, page; 18875353Smjacob 18975353Smjacob reg = PHY_READ(sc, E1000_SCR); 190165099Syongari if ((sc->mii_flags & MIIF_HAVEFIBER) != 0) { 191165099Syongari reg &= ~E1000_SCR_AUTO_X_MODE; 192165099Syongari PHY_WRITE(sc, E1000_SCR, reg); 193221407Smarius if (sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1112) { 194165099Syongari /* Select 1000BASE-X only mode. */ 195183493Syongari page = PHY_READ(sc, E1000_EADR); 196165099Syongari PHY_WRITE(sc, E1000_EADR, 2); 197165099Syongari reg = PHY_READ(sc, E1000_SCR); 198165099Syongari reg &= ~E1000_SCR_MODE_MASK; 199165099Syongari reg |= E1000_SCR_MODE_1000BX; 200165099Syongari PHY_WRITE(sc, E1000_SCR, reg); 201214566Smarius if ((sc->mii_flags & MIIF_PHYPRIV0) != 0) { 202197590Syongari /* Set SIGDET polarity low for SFP module. */ 203197590Syongari PHY_WRITE(sc, E1000_EADR, 1); 204197590Syongari reg = PHY_READ(sc, E1000_SCR); 205197590Syongari reg |= E1000_SCR_FIB_SIGDET_POLARITY; 206197590Syongari PHY_WRITE(sc, E1000_SCR, reg); 207197590Syongari } 208183493Syongari PHY_WRITE(sc, E1000_EADR, page); 209165099Syongari } 210165099Syongari } else { 211221407Smarius switch (sc->mii_mpd_model) { 212221407Smarius case MII_MODEL_xxMARVELL_E1111: 213221407Smarius case MII_MODEL_xxMARVELL_E1112: 214221407Smarius case MII_MODEL_xxMARVELL_E1116: 215238874Shrs case MII_MODEL_xxMARVELL_E1116R_29: 216221407Smarius case MII_MODEL_xxMARVELL_E1118: 217221407Smarius case MII_MODEL_xxMARVELL_E1149: 218223688Simp case MII_MODEL_xxMARVELL_E1149R: 219221407Smarius case MII_MODEL_xxMARVELL_PHYG65G: 220165099Syongari /* Disable energy detect mode. */ 221165099Syongari reg &= ~E1000_SCR_EN_DETECT_MASK; 222165099Syongari reg |= E1000_SCR_AUTO_X_MODE; 223238874Shrs if (sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1116 || 224238874Shrs sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1116R_29) 225173133Syongari reg &= ~E1000_SCR_POWER_DOWN; 226192713Syongari reg |= E1000_SCR_ASSERT_CRS_ON_TX; 227165099Syongari break; 228221407Smarius case MII_MODEL_xxMARVELL_E3082: 229165099Syongari reg |= (E1000_SCR_AUTO_X_MODE >> 1); 230192713Syongari reg |= E1000_SCR_ASSERT_CRS_ON_TX; 231165099Syongari break; 232221407Smarius case MII_MODEL_xxMARVELL_E3016: 233192713Syongari reg |= E1000_SCR_AUTO_MDIX; 234192713Syongari reg &= ~(E1000_SCR_EN_DETECT | 235192713Syongari E1000_SCR_SCRAMBLER_DISABLE); 236192713Syongari reg |= E1000_SCR_LPNP; 237192713Syongari /* XXX Enable class A driver for Yukon FE+ A0. */ 238192713Syongari PHY_WRITE(sc, 0x1C, PHY_READ(sc, 0x1C) | 0x0001); 239192713Syongari break; 240165099Syongari default: 241165099Syongari reg &= ~E1000_SCR_AUTO_X_MODE; 242192713Syongari reg |= E1000_SCR_ASSERT_CRS_ON_TX; 243165099Syongari break; 244165099Syongari } 245221407Smarius if (sc->mii_mpd_model != MII_MODEL_xxMARVELL_E3016) { 246192713Syongari /* Auto correction for reversed cable polarity. */ 247192713Syongari reg &= ~E1000_SCR_POLARITY_REVERSAL; 248192713Syongari } 249165099Syongari PHY_WRITE(sc, E1000_SCR, reg); 250173133Syongari 251221407Smarius if (sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1116 || 252238874Shrs sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1116R_29 || 253223688Simp sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1149 || 254223688Simp sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1149R) { 255173133Syongari PHY_WRITE(sc, E1000_EADR, 2); 256173133Syongari reg = PHY_READ(sc, E1000_SCR); 257173133Syongari reg |= E1000_SCR_RGMII_POWER_UP; 258173133Syongari PHY_WRITE(sc, E1000_SCR, reg); 259196366Syongari PHY_WRITE(sc, E1000_EADR, 0); 260173133Syongari } 261165099Syongari } 26275353Smjacob 263221407Smarius switch (sc->mii_mpd_model) { 264221407Smarius case MII_MODEL_xxMARVELL_E3082: 265221407Smarius case MII_MODEL_xxMARVELL_E1112: 266221407Smarius case MII_MODEL_xxMARVELL_E1118: 267193291Syongari break; 268221407Smarius case MII_MODEL_xxMARVELL_E1116: 269238874Shrs case MII_MODEL_xxMARVELL_E1116R_29: 270193291Syongari page = PHY_READ(sc, E1000_EADR); 271193291Syongari /* Select page 3, LED control register. */ 272193291Syongari PHY_WRITE(sc, E1000_EADR, 3); 273193291Syongari PHY_WRITE(sc, E1000_SCR, 274193291Syongari E1000_SCR_LED_LOS(1) | /* Link/Act */ 275193291Syongari E1000_SCR_LED_INIT(8) | /* 10Mbps */ 276193291Syongari E1000_SCR_LED_STAT1(7) | /* 100Mbps */ 277193291Syongari E1000_SCR_LED_STAT0(7)); /* 1000Mbps */ 278193291Syongari /* Set blink rate. */ 279193291Syongari PHY_WRITE(sc, E1000_IER, E1000_PULSE_DUR(E1000_PULSE_170MS) | 280193291Syongari E1000_BLINK_RATE(E1000_BLINK_84MS)); 281193291Syongari PHY_WRITE(sc, E1000_EADR, page); 282165099Syongari break; 283221407Smarius case MII_MODEL_xxMARVELL_E3016: 284192713Syongari /* LED2 -> ACT, LED1 -> LINK, LED0 -> SPEED. */ 285192713Syongari PHY_WRITE(sc, 0x16, 0x0B << 8 | 0x05 << 4 | 0x04); 286192713Syongari /* Integrated register calibration workaround. */ 287192713Syongari PHY_WRITE(sc, 0x1D, 17); 288192713Syongari PHY_WRITE(sc, 0x1E, 0x3F60); 289192713Syongari break; 290165099Syongari default: 291165099Syongari /* Force TX_CLK to 25MHz clock. */ 292165099Syongari reg = PHY_READ(sc, E1000_ESCR); 293165099Syongari reg |= E1000_ESCR_TX_CLK_25; 294165099Syongari PHY_WRITE(sc, E1000_ESCR, reg); 295165099Syongari break; 296165099Syongari } 297165099Syongari 298165099Syongari /* Reset the PHY so all changes take effect. */ 29975353Smjacob reg = PHY_READ(sc, E1000_CR); 30075353Smjacob reg |= E1000_CR_RESET; 30175353Smjacob PHY_WRITE(sc, E1000_CR, reg); 30275353Smjacob} 30375353Smjacob 30484145Sjlemonstatic int 30575353Smjacobe1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 30675353Smjacob{ 30775353Smjacob struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 308165099Syongari uint16_t speed, gig; 30975353Smjacob int reg; 31075353Smjacob 31175353Smjacob switch (cmd) { 31275353Smjacob case MII_POLLSTAT: 31375353Smjacob break; 31475353Smjacob 31575353Smjacob case MII_MEDIACHG: 316165099Syongari if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { 317221407Smarius e1000phy_mii_phy_auto(sc, ife->ifm_media); 31875353Smjacob break; 319165099Syongari } 32075353Smjacob 321165099Syongari speed = 0; 322165099Syongari switch (IFM_SUBTYPE(ife->ifm_media)) { 32395673Sphk case IFM_1000_T: 324271073Syongari if ((sc->mii_flags & MIIF_HAVE_GTCR) == 0) 325165099Syongari return (EINVAL); 326165099Syongari speed = E1000_CR_SPEED_1000; 32775353Smjacob break; 328120281Swilko case IFM_1000_SX: 329192708Syongari if ((sc->mii_extcapabilities & 330192708Syongari (EXTSR_1000XFDX | EXTSR_1000XHDX)) == 0) 331165099Syongari return (EINVAL); 332165099Syongari speed = E1000_CR_SPEED_1000; 333120281Swilko break; 33475353Smjacob case IFM_100_TX: 335165099Syongari speed = E1000_CR_SPEED_100; 33675353Smjacob break; 33775353Smjacob case IFM_10_T: 338165099Syongari speed = E1000_CR_SPEED_10; 33975353Smjacob break; 340165099Syongari case IFM_NONE: 341165099Syongari reg = PHY_READ(sc, E1000_CR); 342165099Syongari PHY_WRITE(sc, E1000_CR, 343165099Syongari reg | E1000_CR_ISOLATE | E1000_CR_POWER_DOWN); 344165099Syongari goto done; 34575353Smjacob default: 34675353Smjacob return (EINVAL); 34775353Smjacob } 34875353Smjacob 349217412Smarius if ((ife->ifm_media & IFM_FDX) != 0) { 350165099Syongari speed |= E1000_CR_FULL_DUPLEX; 351165099Syongari gig = E1000_1GCR_1000T_FD; 352165099Syongari } else 353165099Syongari gig = E1000_1GCR_1000T; 354165099Syongari 355165099Syongari reg = PHY_READ(sc, E1000_CR); 356165099Syongari reg &= ~E1000_CR_AUTO_NEG_ENABLE; 357165099Syongari PHY_WRITE(sc, E1000_CR, reg | E1000_CR_RESET); 358165099Syongari 359215297Smarius if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { 360215297Smarius gig |= E1000_1GCR_MS_ENABLE; 361271073Syongari if ((ife->ifm_media & IFM_ETH_MASTER) != 0) 362215297Smarius gig |= E1000_1GCR_MS_VALUE; 363271073Syongari } else if ((sc->mii_flags & MIIF_HAVE_GTCR) != 0) 364217412Smarius gig = 0; 365217412Smarius PHY_WRITE(sc, E1000_1GCR, gig); 366165099Syongari PHY_WRITE(sc, E1000_AR, E1000_AR_SELECTOR_FIELD); 367165099Syongari PHY_WRITE(sc, E1000_CR, speed | E1000_CR_RESET); 368165099Syongaridone: 36975353Smjacob break; 37075353Smjacob case MII_TICK: 37175353Smjacob /* 37284145Sjlemon * Only used for autonegotiation. 37375353Smjacob */ 374173667Syongari if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { 375173667Syongari sc->mii_ticks = 0; 37684145Sjlemon break; 377173667Syongari } 37875353Smjacob 37975353Smjacob /* 38084145Sjlemon * check for link. 38184145Sjlemon * Read the status register twice; BMSR_LINK is latch-low. 38275353Smjacob */ 38384145Sjlemon reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 384165099Syongari if (reg & BMSR_LINK) { 385165099Syongari sc->mii_ticks = 0; 38684145Sjlemon break; 387165099Syongari } 38875353Smjacob 389165099Syongari /* Announce link loss right after it happens. */ 390173667Syongari if (sc->mii_ticks++ == 0) 391173667Syongari break; 392165099Syongari if (sc->mii_ticks <= sc->mii_anegticks) 393192709Syongari break; 39475353Smjacob 39584145Sjlemon sc->mii_ticks = 0; 396221407Smarius PHY_RESET(sc); 397221407Smarius e1000phy_mii_phy_auto(sc, ife->ifm_media); 398165099Syongari break; 39975353Smjacob } 40075353Smjacob 40175353Smjacob /* Update the media status. */ 402221407Smarius PHY_STATUS(sc); 40375353Smjacob 40475353Smjacob /* Callback if something changed. */ 40584145Sjlemon mii_phy_update(sc, cmd); 40675353Smjacob return (0); 40775353Smjacob} 40875353Smjacob 40984145Sjlemonstatic void 41075353Smjacobe1000phy_status(struct mii_softc *sc) 41175353Smjacob{ 41275353Smjacob struct mii_data *mii = sc->mii_pdata; 413215297Smarius int bmcr, bmsr, ssr; 41475353Smjacob 41575353Smjacob mii->mii_media_status = IFM_AVALID; 41675353Smjacob mii->mii_media_active = IFM_ETHER; 41775353Smjacob 41875353Smjacob bmsr = PHY_READ(sc, E1000_SR) | PHY_READ(sc, E1000_SR); 41975353Smjacob bmcr = PHY_READ(sc, E1000_CR); 42075353Smjacob ssr = PHY_READ(sc, E1000_SSR); 42175353Smjacob 42275353Smjacob if (bmsr & E1000_SR_LINK_STATUS) 42375353Smjacob mii->mii_media_status |= IFM_ACTIVE; 42475353Smjacob 42575353Smjacob if (bmcr & E1000_CR_LOOPBACK) 42675353Smjacob mii->mii_media_active |= IFM_LOOP; 42775353Smjacob 428192710Syongari if ((bmcr & E1000_CR_AUTO_NEG_ENABLE) != 0 && 429192710Syongari (ssr & E1000_SSR_SPD_DPLX_RESOLVED) == 0) { 43075353Smjacob /* Erg, still trying, I guess... */ 43175353Smjacob mii->mii_media_active |= IFM_NONE; 43275353Smjacob return; 43375353Smjacob } 43475353Smjacob 435120281Swilko if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { 436192710Syongari switch (ssr & E1000_SSR_SPEED) { 437192710Syongari case E1000_SSR_1000MBS: 438120281Swilko mii->mii_media_active |= IFM_1000_T; 439192710Syongari break; 440192710Syongari case E1000_SSR_100MBS: 441120281Swilko mii->mii_media_active |= IFM_100_TX; 442192710Syongari break; 443192710Syongari case E1000_SSR_10MBS: 444120281Swilko mii->mii_media_active |= IFM_10_T; 445192710Syongari break; 446192710Syongari default: 447192710Syongari mii->mii_media_active |= IFM_NONE; 448192710Syongari return; 449192710Syongari } 450120281Swilko } else { 451197588Syongari /* 452197588Syongari * Some fiber PHY(88E1112) does not seem to set resolved 453197588Syongari * speed so always assume we've got IFM_1000_SX. 454197588Syongari */ 455197588Syongari mii->mii_media_active |= IFM_1000_SX; 456120281Swilko } 45775353Smjacob 458215297Smarius if (ssr & E1000_SSR_DUPLEX) { 45975353Smjacob mii->mii_media_active |= IFM_FDX; 460215297Smarius if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) 461215297Smarius mii->mii_media_active |= mii_phy_flowstatus(sc); 462215297Smarius } else 46375353Smjacob mii->mii_media_active |= IFM_HDX; 46475353Smjacob 465215297Smarius if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { 466215297Smarius if (((PHY_READ(sc, E1000_1GSR) | PHY_READ(sc, E1000_1GSR)) & 467215297Smarius E1000_1GSR_MS_CONFIG_RES) != 0) 468215297Smarius mii->mii_media_active |= IFM_ETH_MASTER; 46975353Smjacob } 47075353Smjacob} 47175353Smjacob 47275353Smjacobstatic int 473221407Smariuse1000phy_mii_phy_auto(struct mii_softc *sc, int media) 47475353Smjacob{ 475192711Syongari uint16_t reg; 47675353Smjacob 477192711Syongari if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { 478192711Syongari reg = PHY_READ(sc, E1000_AR); 479215923Smarius reg &= ~(E1000_AR_PAUSE | E1000_AR_ASM_DIR); 480192711Syongari reg |= E1000_AR_10T | E1000_AR_10T_FD | 481215297Smarius E1000_AR_100TX | E1000_AR_100TX_FD; 482215297Smarius if ((media & IFM_FLOW) != 0 || 483215297Smarius (sc->mii_flags & MIIF_FORCEPAUSE) != 0) 484215297Smarius reg |= E1000_AR_PAUSE | E1000_AR_ASM_DIR; 485192711Syongari PHY_WRITE(sc, E1000_AR, reg | E1000_AR_SELECTOR_FIELD); 486192711Syongari } else 487215297Smarius PHY_WRITE(sc, E1000_AR, E1000_FA_1000X_FD | E1000_FA_1000X); 488271073Syongari if ((sc->mii_flags & MIIF_HAVE_GTCR) != 0) { 489271073Syongari reg = 0; 490271073Syongari if ((sc->mii_extcapabilities & EXTSR_1000TFDX) != 0) 491271073Syongari reg |= E1000_1GCR_1000T_FD; 492271073Syongari if ((sc->mii_extcapabilities & EXTSR_1000THDX) != 0) 493271073Syongari reg |= E1000_1GCR_1000T; 494271073Syongari PHY_WRITE(sc, E1000_1GCR, reg); 495271073Syongari } 496165099Syongari PHY_WRITE(sc, E1000_CR, 497165099Syongari E1000_CR_AUTO_NEG_ENABLE | E1000_CR_RESTART_AUTO_NEG); 49875353Smjacob 49975353Smjacob return (EJUSTRETURN); 50075353Smjacob} 501