nsgphy.c revision 194134
1139749Simp/*- 276479Swpaul * Copyright (c) 2001 Wind River Systems 376479Swpaul * Copyright (c) 2001 476479Swpaul * Bill Paul <wpaul@bsdi.com>. All rights reserved. 595718Sphk * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc. 695718Sphk * All rights reserved. 776479Swpaul * 895718Sphk * This code is derived from software contributed to The NetBSD Foundation 995718Sphk * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 1095718Sphk * NASA Ames Research Center. 1195718Sphk * 1276479Swpaul * Redistribution and use in source and binary forms, with or without 1376479Swpaul * modification, are permitted provided that the following conditions 1476479Swpaul * are met: 1576479Swpaul * 1. Redistributions of source code must retain the above copyright 1676479Swpaul * notice, this list of conditions and the following disclaimer. 1776479Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1876479Swpaul * notice, this list of conditions and the following disclaimer in the 1976479Swpaul * documentation and/or other materials provided with the distribution. 2076479Swpaul * 3. All advertising materials mentioning features or use of this software 2176479Swpaul * must display the following acknowledgement: 2276479Swpaul * This product includes software developed by Bill Paul. 2376479Swpaul * 4. Neither the name of the author nor the names of any co-contributors 2476479Swpaul * may be used to endorse or promote products derived from this software 2576479Swpaul * without specific prior written permission. 2676479Swpaul * 2776479Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 2876479Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2976479Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3076479Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 3176479Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 3276479Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3376479Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 3476479Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3576479Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3676479Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3776479Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 3876479Swpaul */ 3976479Swpaul 40119418Sobrien#include <sys/cdefs.h> 41119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/mii/nsgphy.c 194134 2009-06-13 23:27:04Z marius $"); 42119418Sobrien 4376479Swpaul/* 44194134Smarius * Driver for the National Semiconductor DP83861, DP83865 and DP83891 4576479Swpaul * 10/100/1000 PHYs. 4676479Swpaul * Datasheet available at: http://www.national.com/ds/DP/DP83861.pdf 47194134Smarius * and at: http://www.national.com/ds/DP/DP83865.pdf 4876479Swpaul * 49194134Smarius * The DP83891 is the older NS GigE PHY which isn't being sold 50194134Smarius * anymore. The DP83861 is its replacement, which is an 'enhanced' 51194134Smarius * firmware driven component. The major difference between the 52194134Smarius * two is that the DP83891 can't generate interrupts, while the 53194134Smarius * 83861 can (probably it wasn't originally designed to do this, but 54194134Smarius * it can now thanks to firmware updates). The DP83861 also allows 55194134Smarius * access to its internal RAM via indirect register access. The 56194134Smarius * DP83865 is an ultra low power version of the DP83861 and DP83891. 5776479Swpaul */ 5876479Swpaul 5976479Swpaul#include <sys/param.h> 6076479Swpaul#include <sys/systm.h> 6176479Swpaul#include <sys/kernel.h> 62129876Sphk#include <sys/module.h> 6376479Swpaul#include <sys/socket.h> 6476479Swpaul#include <sys/bus.h> 6576479Swpaul 6676479Swpaul#include <net/if.h> 6776479Swpaul#include <net/if_media.h> 6876479Swpaul 6976479Swpaul#include <dev/mii/mii.h> 7076479Swpaul#include <dev/mii/miivar.h> 71109514Sobrien#include "miidevs.h" 7276479Swpaul 7376479Swpaul#include <dev/mii/nsgphyreg.h> 7476479Swpaul 7576479Swpaul#include "miibus_if.h" 7676479Swpaul 77105135Salfredstatic int nsgphy_probe(device_t); 78105135Salfredstatic int nsgphy_attach(device_t); 7976479Swpaul 8076479Swpaulstatic device_method_t nsgphy_methods[] = { 8176479Swpaul /* device interface */ 8276479Swpaul DEVMETHOD(device_probe, nsgphy_probe), 8376479Swpaul DEVMETHOD(device_attach, nsgphy_attach), 8495722Sphk DEVMETHOD(device_detach, mii_phy_detach), 8576479Swpaul DEVMETHOD(device_shutdown, bus_generic_shutdown), 8676479Swpaul { 0, 0 } 8776479Swpaul}; 8876479Swpaul 8976479Swpaulstatic devclass_t nsgphy_devclass; 9076479Swpaul 9176479Swpaulstatic driver_t nsgphy_driver = { 9276479Swpaul "nsgphy", 9376479Swpaul nsgphy_methods, 9476479Swpaul sizeof(struct mii_softc) 9576479Swpaul}; 9676479Swpaul 9776479SwpaulDRIVER_MODULE(nsgphy, miibus, nsgphy_driver, nsgphy_devclass, 0, 0); 9876479Swpaul 9992739Salfredstatic int nsgphy_service(struct mii_softc *, struct mii_data *,int); 10092739Salfredstatic void nsgphy_status(struct mii_softc *); 10176479Swpaul 102164827Smariusstatic const struct mii_phydesc nsgphys[] = { 103150755Simp MII_PHY_DESC(NATSEMI, DP83861), 104194134Smarius MII_PHY_DESC(NATSEMI, DP83865), 105150755Simp MII_PHY_DESC(NATSEMI, DP83891), 106150755Simp MII_PHY_END 10795724Sphk}; 10895724Sphk 10995664Sphkstatic int 11095664Sphknsgphy_probe(device_t dev) 11176479Swpaul{ 11276479Swpaul 113164827Smarius return (mii_phy_dev_probe(dev, nsgphys, BUS_PROBE_DEFAULT)); 11476479Swpaul} 11576479Swpaul 11695664Sphkstatic int 11795664Sphknsgphy_attach(device_t dev) 11876479Swpaul{ 11976479Swpaul struct mii_softc *sc; 12076479Swpaul struct mii_attach_args *ma; 12176479Swpaul struct mii_data *mii; 12276479Swpaul 12376479Swpaul sc = device_get_softc(dev); 12476479Swpaul ma = device_get_ivars(dev); 12595724Sphk if (bootverbose) 12695724Sphk device_printf(dev, "<rev. %d>\n", MII_REV(ma->mii_id2)); 12795724Sphk device_printf(dev, " "); 12876479Swpaul sc->mii_dev = device_get_parent(dev); 12976479Swpaul mii = device_get_softc(sc->mii_dev); 13076479Swpaul LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 13176479Swpaul 13276479Swpaul sc->mii_inst = mii->mii_instance; 13376479Swpaul sc->mii_phy = ma->mii_phyno; 13476479Swpaul sc->mii_service = nsgphy_service; 13576479Swpaul sc->mii_pdata = mii; 13676479Swpaul 13776479Swpaul mii->mii_instance++; 13876479Swpaul 139194134Smarius mii_phy_reset(sc); 140194134Smarius 141194134Smarius /* 142194134Smarius * NB: the PHY has the 10baseT BMSR bits hard-wired to 0, 143194134Smarius * even though it supports 10baseT. 144194134Smarius */ 14595707Sphk sc->mii_capabilities = (PHY_READ(sc, MII_BMSR) | 146194134Smarius (BMSR_10TFDX | BMSR_10THDX)) & ma->mii_capmask; 14795707Sphk if (sc->mii_capabilities & BMSR_EXTSTAT) 14895707Sphk sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); 14995718Sphk 15095718Sphk mii_phy_add_media(sc); 15176479Swpaul printf("\n"); 15276479Swpaul 15376479Swpaul MIIBUS_MEDIAINIT(sc->mii_dev); 154164707Smarius return (0); 15576479Swpaul} 15676479Swpaul 15795664Sphkstatic int 15895664Sphknsgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 15976479Swpaul{ 16076479Swpaul struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 16176479Swpaul int reg; 16276479Swpaul 16376479Swpaul switch (cmd) { 16476479Swpaul case MII_POLLSTAT: 16576479Swpaul /* 16676479Swpaul * If we're not polling our PHY instance, just return. 16776479Swpaul */ 16876479Swpaul if (IFM_INST(ife->ifm_media) != sc->mii_inst) 16976479Swpaul return (0); 17076479Swpaul break; 17176479Swpaul 17276479Swpaul case MII_MEDIACHG: 17376479Swpaul /* 17476479Swpaul * If the media indicates a different PHY instance, 17576479Swpaul * isolate ourselves. 17676479Swpaul */ 17776479Swpaul if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 17876479Swpaul reg = PHY_READ(sc, MII_BMCR); 17976479Swpaul PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 18076479Swpaul return (0); 18176479Swpaul } 18276479Swpaul 18376479Swpaul /* 18476479Swpaul * If the interface is not up, don't do anything. 18576479Swpaul */ 18676479Swpaul if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 18776479Swpaul break; 18876479Swpaul 18995718Sphk mii_phy_setmedia(sc); 19076479Swpaul break; 19176479Swpaul 19276479Swpaul case MII_TICK: 19376479Swpaul /* 19476479Swpaul * If we're not currently selected, just return. 19576479Swpaul */ 19676479Swpaul if (IFM_INST(ife->ifm_media) != sc->mii_inst) 19776479Swpaul return (0); 19876479Swpaul 19995718Sphk if (mii_phy_tick(sc) == EJUSTRETURN) 20084145Sjlemon return (0); 20176479Swpaul break; 20276479Swpaul } 20376479Swpaul 20476479Swpaul /* Update the media status. */ 20576479Swpaul nsgphy_status(sc); 20676479Swpaul 20776479Swpaul /* Callback if something changed. */ 20884145Sjlemon mii_phy_update(sc, cmd); 20976479Swpaul return (0); 21076479Swpaul} 21176479Swpaul 21284145Sjlemonstatic void 21395664Sphknsgphy_status(struct mii_softc *sc) 21476479Swpaul{ 21576479Swpaul struct mii_data *mii = sc->mii_pdata; 21695718Sphk struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 21795718Sphk int bmsr, bmcr, physup, gtsr; 21876479Swpaul 21976479Swpaul mii->mii_media_status = IFM_AVALID; 22076479Swpaul mii->mii_media_active = IFM_ETHER; 22176479Swpaul 22295718Sphk bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 22395664Sphk 22476479Swpaul physup = PHY_READ(sc, NSGPHY_MII_PHYSUP); 22595664Sphk 22695718Sphk if (physup & PHY_SUP_LINK) 22776479Swpaul mii->mii_media_status |= IFM_ACTIVE; 22876479Swpaul 22995664Sphk bmcr = PHY_READ(sc, MII_BMCR); 23095718Sphk if (bmcr & BMCR_ISO) { 23195718Sphk mii->mii_media_active |= IFM_NONE; 23295718Sphk mii->mii_media_status = 0; 23395718Sphk return; 23495718Sphk } 23576479Swpaul 23695664Sphk if (bmcr & BMCR_LOOP) 23776479Swpaul mii->mii_media_active |= IFM_LOOP; 23876479Swpaul 23995664Sphk if (bmcr & BMCR_AUTOEN) { 24095664Sphk /* 24195664Sphk * The media status bits are only valid if autonegotiation 24295664Sphk * has completed (or it's disabled). 24395664Sphk */ 24495664Sphk if ((bmsr & BMSR_ACOMP) == 0) { 24576479Swpaul /* Erg, still trying, I guess... */ 24676479Swpaul mii->mii_media_active |= IFM_NONE; 24776479Swpaul return; 24876479Swpaul } 24976479Swpaul 250194134Smarius switch (physup & (PHY_SUP_SPEED1 | PHY_SUP_SPEED0)) { 25195718Sphk case PHY_SUP_SPEED1: 25295718Sphk mii->mii_media_active |= IFM_1000_T; 25395718Sphk gtsr = PHY_READ(sc, MII_100T2SR); 25495718Sphk if (gtsr & GTSR_MS_RES) 25595718Sphk mii->mii_media_active |= IFM_ETH_MASTER; 25695718Sphk break; 25776479Swpaul 25895718Sphk case PHY_SUP_SPEED0: 25995718Sphk mii->mii_media_active |= IFM_100_TX; 26095718Sphk break; 26176479Swpaul 26295718Sphk case 0: 26395718Sphk mii->mii_media_active |= IFM_10_T; 26495718Sphk break; 26576479Swpaul 26695718Sphk default: 26795718Sphk mii->mii_media_active |= IFM_NONE; 26895718Sphk mii->mii_media_status = 0; 269194134Smarius return; 27076479Swpaul } 271194134Smarius 27295718Sphk if (physup & PHY_SUP_DUPLEX) 27395718Sphk mii->mii_media_active |= IFM_FDX; 274194134Smarius else 275194134Smarius mii->mii_media_active |= IFM_HDX; 27695718Sphk } else 27795718Sphk mii->mii_media_active = ife->ifm_media; 27876479Swpaul} 279