174131Sjlemon/*- 274131Sjlemon * Copyright (c) 2001 Jonathan Lemon 374131Sjlemon * All rights reserved. 474131Sjlemon * 574131Sjlemon * Redistribution and use in source and binary forms, with or without 674131Sjlemon * modification, are permitted provided that the following conditions 774131Sjlemon * are met: 874131Sjlemon * 1. Redistributions of source code must retain the above copyright 974131Sjlemon * notice, this list of conditions and the following disclaimer. 1074131Sjlemon * 2. Redistributions in binary form must reproduce the above copyright 1174131Sjlemon * notice, this list of conditions and the following disclaimer in the 1274131Sjlemon * documentation and/or other materials provided with the distribution. 1374131Sjlemon * 3. Neither the name of the author nor the names of any co-contributors 1474131Sjlemon * may be used to endorse or promote products derived from this software 1574131Sjlemon * without specific prior written permission. 1674131Sjlemon * 1774131Sjlemon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1874131Sjlemon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1974131Sjlemon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2074131Sjlemon * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2174131Sjlemon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2274131Sjlemon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2374131Sjlemon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2474131Sjlemon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2574131Sjlemon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2674131Sjlemon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2774131Sjlemon * SUCH DAMAGE. 2874131Sjlemon * 2974131Sjlemon */ 3074131Sjlemon 31119418Sobrien#include <sys/cdefs.h> 32119418Sobrien__FBSDID("$FreeBSD$"); 33119418Sobrien 3474131Sjlemon/* 3574131Sjlemon * driver for Intel 82553 and 82555 PHYs 3674131Sjlemon */ 3774131Sjlemon 3874131Sjlemon#include <sys/param.h> 3974131Sjlemon#include <sys/systm.h> 4074131Sjlemon#include <sys/kernel.h> 41129876Sphk#include <sys/module.h> 4274131Sjlemon#include <sys/socket.h> 4374131Sjlemon#include <sys/bus.h> 4474131Sjlemon 4574131Sjlemon#include <net/if.h> 4674131Sjlemon#include <net/if_media.h> 4774131Sjlemon 4874131Sjlemon#include <dev/mii/mii.h> 4974131Sjlemon#include <dev/mii/miivar.h> 50109514Sobrien#include "miidevs.h" 5174131Sjlemon 52226154Smarius#include <dev/fxp/inphyreg.h> 5374131Sjlemon 5474131Sjlemon#include "miibus_if.h" 5574131Sjlemon 5674131Sjlemonstatic int inphy_probe(device_t dev); 5774131Sjlemonstatic int inphy_attach(device_t dev); 5874131Sjlemon 5974131Sjlemonstatic device_method_t inphy_methods[] = { 6074131Sjlemon /* device interface */ 6174131Sjlemon DEVMETHOD(device_probe, inphy_probe), 6274131Sjlemon DEVMETHOD(device_attach, inphy_attach), 6395722Sphk DEVMETHOD(device_detach, mii_phy_detach), 6474131Sjlemon DEVMETHOD(device_shutdown, bus_generic_shutdown), 6574131Sjlemon { 0, 0 } 6674131Sjlemon}; 6774131Sjlemon 6874131Sjlemonstatic devclass_t inphy_devclass; 6974131Sjlemon 7074131Sjlemonstatic driver_t inphy_driver = { 7174131Sjlemon "inphy", 7274131Sjlemon inphy_methods, 7374131Sjlemon sizeof(struct mii_softc) 7474131Sjlemon}; 7574131Sjlemon 7674131SjlemonDRIVER_MODULE(inphy, miibus, inphy_driver, inphy_devclass, 0, 0); 7774131Sjlemon 7884145Sjlemonstatic int inphy_service(struct mii_softc *, struct mii_data *, int); 7984145Sjlemonstatic void inphy_status(struct mii_softc *); 80215905Smariusstatic void inphy_reset(struct mii_softc *); 8174131Sjlemon 82164827Smariusstatic const struct mii_phydesc inphys[] = { 83221407Smarius MII_PHY_DESC(xxINTEL, I82553), 84221407Smarius MII_PHY_DESC(yyINTEL, I82553), 85221407Smarius MII_PHY_DESC(yyINTEL, I82555), 86221407Smarius MII_PHY_DESC(yyINTEL, I82562EM), 87221407Smarius MII_PHY_DESC(yyINTEL, I82562ET), 88164827Smarius MII_PHY_END 89164827Smarius}; 90164827Smarius 91221407Smariusstatic const struct mii_phy_funcs inphy_funcs = { 92221407Smarius inphy_service, 93221407Smarius inphy_status, 94221407Smarius inphy_reset 95221407Smarius}; 96221407Smarius 9774131Sjlemonstatic int 9874131Sjlemoninphy_probe(device_t dev) 9974131Sjlemon{ 10074131Sjlemon 101164827Smarius return (mii_phy_dev_probe(dev, inphys, BUS_PROBE_DEFAULT)); 10274131Sjlemon} 10374131Sjlemon 10474131Sjlemonstatic int 10574131Sjlemoninphy_attach(device_t dev) 10674131Sjlemon{ 10774131Sjlemon 108221407Smarius mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &inphy_funcs, 1); 10974131Sjlemon return (0); 11074131Sjlemon} 11174131Sjlemon 11274131Sjlemonstatic int 11374131Sjlemoninphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 11474131Sjlemon{ 11574131Sjlemon 11674131Sjlemon switch (cmd) { 11774131Sjlemon case MII_POLLSTAT: 11874131Sjlemon break; 11974131Sjlemon 12074131Sjlemon case MII_MEDIACHG: 12174131Sjlemon /* 12274131Sjlemon * If the interface is not up, don't do anything. 12374131Sjlemon */ 12474131Sjlemon if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 12574131Sjlemon break; 12674131Sjlemon 12795718Sphk mii_phy_setmedia(sc); 12874131Sjlemon break; 12974131Sjlemon 13074131Sjlemon case MII_TICK: 13184145Sjlemon if (mii_phy_tick(sc) == EJUSTRETURN) 13274131Sjlemon return (0); 13374131Sjlemon break; 13474131Sjlemon } 13574131Sjlemon 13674131Sjlemon /* Update the media status. */ 137221407Smarius PHY_STATUS(sc); 13874131Sjlemon 13974131Sjlemon /* Callback if something changed. */ 14084145Sjlemon mii_phy_update(sc, cmd); 14174131Sjlemon return (0); 14274131Sjlemon} 14374131Sjlemon 14484145Sjlemonstatic void 14574131Sjlemoninphy_status(struct mii_softc *sc) 14674131Sjlemon{ 14774131Sjlemon struct mii_data *mii = sc->mii_pdata; 14895718Sphk struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 14974131Sjlemon int bmsr, bmcr, scr; 15074131Sjlemon 15174131Sjlemon mii->mii_media_status = IFM_AVALID; 15274131Sjlemon mii->mii_media_active = IFM_ETHER; 15374131Sjlemon 15474131Sjlemon bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 15574131Sjlemon if (bmsr & BMSR_LINK) 15674131Sjlemon mii->mii_media_status |= IFM_ACTIVE; 15774131Sjlemon 15874131Sjlemon bmcr = PHY_READ(sc, MII_BMCR); 15974131Sjlemon if (bmcr & BMCR_ISO) { 16074131Sjlemon mii->mii_media_active |= IFM_NONE; 16174131Sjlemon mii->mii_media_status = 0; 16274131Sjlemon return; 16374131Sjlemon } 16474131Sjlemon 16574131Sjlemon if (bmcr & BMCR_LOOP) 16674131Sjlemon mii->mii_media_active |= IFM_LOOP; 16774131Sjlemon 16874131Sjlemon if (bmcr & BMCR_AUTOEN) { 16974131Sjlemon if ((bmsr & BMSR_ACOMP) == 0) { 17074131Sjlemon mii->mii_media_active |= IFM_NONE; 17174131Sjlemon return; 17274131Sjlemon } 17374131Sjlemon 17474131Sjlemon scr = PHY_READ(sc, MII_INPHY_SCR); 17574131Sjlemon if (scr & SCR_S100) 17674131Sjlemon mii->mii_media_active |= IFM_100_TX; 17774131Sjlemon else 17874131Sjlemon mii->mii_media_active |= IFM_10_T; 17974131Sjlemon if (scr & SCR_FDX) 180215716Smarius mii->mii_media_active |= 181215716Smarius IFM_FDX | mii_phy_flowstatus(sc); 182213384Smarius else 183213384Smarius mii->mii_media_active |= IFM_HDX; 18474131Sjlemon } else 18595718Sphk mii->mii_media_active = ife->ifm_media; 18674131Sjlemon} 187215905Smarius 188215905Smariusstatic void 189215905Smariusinphy_reset(struct mii_softc *sc) 190215905Smarius{ 191215905Smarius 192215905Smarius mii_phy_reset(sc); 193215905Smarius 194215905Smarius /* Ensure Bay flow control is disabled. */ 195215905Smarius PHY_WRITE(sc, MII_INPHY_SCR, 196215905Smarius PHY_READ(sc, MII_INPHY_SCR) & ~SCR_FLOWCTL); 197215905Smarius} 198