1112a855dSMarius Strobl /*- 2*7282444bSPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 3*7282444bSPedro F. Giffuni * 4112a855dSMarius Strobl * Copyright (c) 2001 Jonathan Lemon 5112a855dSMarius Strobl * All rights reserved. 6112a855dSMarius Strobl * 7112a855dSMarius Strobl * Redistribution and use in source and binary forms, with or without 8112a855dSMarius Strobl * modification, are permitted provided that the following conditions 9112a855dSMarius Strobl * are met: 10112a855dSMarius Strobl * 1. Redistributions of source code must retain the above copyright 11112a855dSMarius Strobl * notice, this list of conditions and the following disclaimer. 12112a855dSMarius Strobl * 2. Redistributions in binary form must reproduce the above copyright 13112a855dSMarius Strobl * notice, this list of conditions and the following disclaimer in the 14112a855dSMarius Strobl * documentation and/or other materials provided with the distribution. 15112a855dSMarius Strobl * 3. Neither the name of the author nor the names of any co-contributors 16112a855dSMarius Strobl * may be used to endorse or promote products derived from this software 17112a855dSMarius Strobl * without specific prior written permission. 18112a855dSMarius Strobl * 19112a855dSMarius Strobl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20112a855dSMarius Strobl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21112a855dSMarius Strobl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22112a855dSMarius Strobl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23112a855dSMarius Strobl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24112a855dSMarius Strobl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25112a855dSMarius Strobl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26112a855dSMarius Strobl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27112a855dSMarius Strobl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28112a855dSMarius Strobl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29112a855dSMarius Strobl * SUCH DAMAGE. 30112a855dSMarius Strobl * 31112a855dSMarius Strobl */ 32112a855dSMarius Strobl 33112a855dSMarius Strobl #include <sys/cdefs.h> 34112a855dSMarius Strobl __FBSDID("$FreeBSD$"); 35112a855dSMarius Strobl 36112a855dSMarius Strobl /* 37112a855dSMarius Strobl * driver for Intel 82553 and 82555 PHYs 38112a855dSMarius Strobl */ 39112a855dSMarius Strobl 40112a855dSMarius Strobl #include <sys/param.h> 41112a855dSMarius Strobl #include <sys/systm.h> 42112a855dSMarius Strobl #include <sys/kernel.h> 43112a855dSMarius Strobl #include <sys/module.h> 44112a855dSMarius Strobl #include <sys/socket.h> 45112a855dSMarius Strobl #include <sys/bus.h> 46112a855dSMarius Strobl 47112a855dSMarius Strobl #include <net/if.h> 4876039bc8SGleb Smirnoff #include <net/if_var.h> 49112a855dSMarius Strobl #include <net/if_media.h> 50112a855dSMarius Strobl 51112a855dSMarius Strobl #include <dev/mii/mii.h> 52112a855dSMarius Strobl #include <dev/mii/miivar.h> 53112a855dSMarius Strobl #include "miidevs.h" 54112a855dSMarius Strobl 55112a855dSMarius Strobl #include <dev/fxp/inphyreg.h> 56112a855dSMarius Strobl 57112a855dSMarius Strobl #include "miibus_if.h" 58112a855dSMarius Strobl 59112a855dSMarius Strobl static int inphy_probe(device_t dev); 60112a855dSMarius Strobl static int inphy_attach(device_t dev); 61112a855dSMarius Strobl 62112a855dSMarius Strobl static device_method_t inphy_methods[] = { 63112a855dSMarius Strobl /* device interface */ 64112a855dSMarius Strobl DEVMETHOD(device_probe, inphy_probe), 65112a855dSMarius Strobl DEVMETHOD(device_attach, inphy_attach), 66112a855dSMarius Strobl DEVMETHOD(device_detach, mii_phy_detach), 67112a855dSMarius Strobl DEVMETHOD(device_shutdown, bus_generic_shutdown), 68112a855dSMarius Strobl { 0, 0 } 69112a855dSMarius Strobl }; 70112a855dSMarius Strobl 71112a855dSMarius Strobl static devclass_t inphy_devclass; 72112a855dSMarius Strobl 73112a855dSMarius Strobl static driver_t inphy_driver = { 74112a855dSMarius Strobl "inphy", 75112a855dSMarius Strobl inphy_methods, 76112a855dSMarius Strobl sizeof(struct mii_softc) 77112a855dSMarius Strobl }; 78112a855dSMarius Strobl 79112a855dSMarius Strobl DRIVER_MODULE(inphy, miibus, inphy_driver, inphy_devclass, 0, 0); 80112a855dSMarius Strobl 81112a855dSMarius Strobl static int inphy_service(struct mii_softc *, struct mii_data *, int); 82112a855dSMarius Strobl static void inphy_status(struct mii_softc *); 83112a855dSMarius Strobl static void inphy_reset(struct mii_softc *); 84112a855dSMarius Strobl 85112a855dSMarius Strobl static const struct mii_phydesc inphys[] = { 86112a855dSMarius Strobl MII_PHY_DESC(xxINTEL, I82553), 87112a855dSMarius Strobl MII_PHY_DESC(yyINTEL, I82553), 88112a855dSMarius Strobl MII_PHY_DESC(yyINTEL, I82555), 89112a855dSMarius Strobl MII_PHY_DESC(yyINTEL, I82562EM), 90112a855dSMarius Strobl MII_PHY_DESC(yyINTEL, I82562ET), 91112a855dSMarius Strobl MII_PHY_END 92112a855dSMarius Strobl }; 93112a855dSMarius Strobl 94112a855dSMarius Strobl static const struct mii_phy_funcs inphy_funcs = { 95112a855dSMarius Strobl inphy_service, 96112a855dSMarius Strobl inphy_status, 97112a855dSMarius Strobl inphy_reset 98112a855dSMarius Strobl }; 99112a855dSMarius Strobl 100112a855dSMarius Strobl static int 101112a855dSMarius Strobl inphy_probe(device_t dev) 102112a855dSMarius Strobl { 103112a855dSMarius Strobl 104112a855dSMarius Strobl return (mii_phy_dev_probe(dev, inphys, BUS_PROBE_DEFAULT)); 105112a855dSMarius Strobl } 106112a855dSMarius Strobl 107112a855dSMarius Strobl static int 108112a855dSMarius Strobl inphy_attach(device_t dev) 109112a855dSMarius Strobl { 110112a855dSMarius Strobl 111112a855dSMarius Strobl mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &inphy_funcs, 1); 112112a855dSMarius Strobl return (0); 113112a855dSMarius Strobl } 114112a855dSMarius Strobl 115112a855dSMarius Strobl static int 116112a855dSMarius Strobl inphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 117112a855dSMarius Strobl { 118112a855dSMarius Strobl 119112a855dSMarius Strobl switch (cmd) { 120112a855dSMarius Strobl case MII_POLLSTAT: 121112a855dSMarius Strobl break; 122112a855dSMarius Strobl 123112a855dSMarius Strobl case MII_MEDIACHG: 124112a855dSMarius Strobl /* 125112a855dSMarius Strobl * If the interface is not up, don't do anything. 126112a855dSMarius Strobl */ 12762d76917SMarcel Moolenaar if ((if_getflags(mii->mii_ifp) & IFF_UP) == 0) 128112a855dSMarius Strobl break; 129112a855dSMarius Strobl 130112a855dSMarius Strobl mii_phy_setmedia(sc); 131112a855dSMarius Strobl break; 132112a855dSMarius Strobl 133112a855dSMarius Strobl case MII_TICK: 134112a855dSMarius Strobl if (mii_phy_tick(sc) == EJUSTRETURN) 135112a855dSMarius Strobl return (0); 136112a855dSMarius Strobl break; 137112a855dSMarius Strobl } 138112a855dSMarius Strobl 139112a855dSMarius Strobl /* Update the media status. */ 140112a855dSMarius Strobl PHY_STATUS(sc); 141112a855dSMarius Strobl 142112a855dSMarius Strobl /* Callback if something changed. */ 143112a855dSMarius Strobl mii_phy_update(sc, cmd); 144112a855dSMarius Strobl return (0); 145112a855dSMarius Strobl } 146112a855dSMarius Strobl 147112a855dSMarius Strobl static void 148112a855dSMarius Strobl inphy_status(struct mii_softc *sc) 149112a855dSMarius Strobl { 150112a855dSMarius Strobl struct mii_data *mii = sc->mii_pdata; 151112a855dSMarius Strobl struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 152112a855dSMarius Strobl int bmsr, bmcr, scr; 153112a855dSMarius Strobl 154112a855dSMarius Strobl mii->mii_media_status = IFM_AVALID; 155112a855dSMarius Strobl mii->mii_media_active = IFM_ETHER; 156112a855dSMarius Strobl 157112a855dSMarius Strobl bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 158112a855dSMarius Strobl if (bmsr & BMSR_LINK) 159112a855dSMarius Strobl mii->mii_media_status |= IFM_ACTIVE; 160112a855dSMarius Strobl 161112a855dSMarius Strobl bmcr = PHY_READ(sc, MII_BMCR); 162112a855dSMarius Strobl if (bmcr & BMCR_ISO) { 163112a855dSMarius Strobl mii->mii_media_active |= IFM_NONE; 164112a855dSMarius Strobl mii->mii_media_status = 0; 165112a855dSMarius Strobl return; 166112a855dSMarius Strobl } 167112a855dSMarius Strobl 168112a855dSMarius Strobl if (bmcr & BMCR_LOOP) 169112a855dSMarius Strobl mii->mii_media_active |= IFM_LOOP; 170112a855dSMarius Strobl 171112a855dSMarius Strobl if (bmcr & BMCR_AUTOEN) { 172112a855dSMarius Strobl if ((bmsr & BMSR_ACOMP) == 0) { 173112a855dSMarius Strobl mii->mii_media_active |= IFM_NONE; 174112a855dSMarius Strobl return; 175112a855dSMarius Strobl } 176112a855dSMarius Strobl 177112a855dSMarius Strobl scr = PHY_READ(sc, MII_INPHY_SCR); 178112a855dSMarius Strobl if (scr & SCR_S100) 179112a855dSMarius Strobl mii->mii_media_active |= IFM_100_TX; 180112a855dSMarius Strobl else 181112a855dSMarius Strobl mii->mii_media_active |= IFM_10_T; 182112a855dSMarius Strobl if (scr & SCR_FDX) 183112a855dSMarius Strobl mii->mii_media_active |= 184112a855dSMarius Strobl IFM_FDX | mii_phy_flowstatus(sc); 185112a855dSMarius Strobl else 186112a855dSMarius Strobl mii->mii_media_active |= IFM_HDX; 187112a855dSMarius Strobl } else 188112a855dSMarius Strobl mii->mii_media_active = ife->ifm_media; 189112a855dSMarius Strobl } 190112a855dSMarius Strobl 191112a855dSMarius Strobl static void 192112a855dSMarius Strobl inphy_reset(struct mii_softc *sc) 193112a855dSMarius Strobl { 194112a855dSMarius Strobl 195112a855dSMarius Strobl mii_phy_reset(sc); 196112a855dSMarius Strobl 197112a855dSMarius Strobl /* Ensure Bay flow control is disabled. */ 198112a855dSMarius Strobl PHY_WRITE(sc, MII_INPHY_SCR, 199112a855dSMarius Strobl PHY_READ(sc, MII_INPHY_SCR) & ~SCR_FLOWCTL); 200112a855dSMarius Strobl } 201