nsphy.c revision 213893
150120Swpaul/* $NetBSD: nsphy.c,v 1.18 1999/07/14 23:57:36 thorpej Exp $ */ 250120Swpaul 350120Swpaul/*- 450120Swpaul * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. 550120Swpaul * All rights reserved. 650120Swpaul * 750120Swpaul * This code is derived from software contributed to The NetBSD Foundation 850120Swpaul * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 950120Swpaul * NASA Ames Research Center. 1050120Swpaul * 1150120Swpaul * Redistribution and use in source and binary forms, with or without 1250120Swpaul * modification, are permitted provided that the following conditions 1350120Swpaul * are met: 1450120Swpaul * 1. Redistributions of source code must retain the above copyright 1550120Swpaul * notice, this list of conditions and the following disclaimer. 1650120Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1750120Swpaul * notice, this list of conditions and the following disclaimer in the 1850120Swpaul * documentation and/or other materials provided with the distribution. 1950120Swpaul * 2050120Swpaul * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2150120Swpaul * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2250120Swpaul * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2350120Swpaul * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2450120Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2550120Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2650120Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2750120Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2850120Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2950120Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3050120Swpaul * POSSIBILITY OF SUCH DAMAGE. 3150120Swpaul */ 3250120Swpaul 33139749Simp/*- 3450120Swpaul * Copyright (c) 1997 Manuel Bouyer. All rights reserved. 3550120Swpaul * 3650120Swpaul * Redistribution and use in source and binary forms, with or without 3750120Swpaul * modification, are permitted provided that the following conditions 3850120Swpaul * are met: 3950120Swpaul * 1. Redistributions of source code must retain the above copyright 4050120Swpaul * notice, this list of conditions and the following disclaimer. 4150120Swpaul * 2. Redistributions in binary form must reproduce the above copyright 4250120Swpaul * notice, this list of conditions and the following disclaimer in the 4350120Swpaul * documentation and/or other materials provided with the distribution. 4450120Swpaul * 4550120Swpaul * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 4650120Swpaul * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 4750120Swpaul * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 4850120Swpaul * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 4950120Swpaul * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 5050120Swpaul * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 5150120Swpaul * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 5250120Swpaul * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 5350120Swpaul * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 5450120Swpaul * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 5550120Swpaul */ 5650120Swpaul 57129844Smarius#include <sys/cdefs.h> 58129844Smarius__FBSDID("$FreeBSD: head/sys/dev/mii/nsphy.c 213893 2010-10-15 14:52:11Z marius $"); 59129844Smarius 6050120Swpaul/* 6150120Swpaul * driver for National Semiconductor's DP83840A ethernet 10/100 PHY 6250120Swpaul * Data Sheet available from www.national.com 6350120Swpaul */ 6450120Swpaul 6550120Swpaul#include <sys/param.h> 6650120Swpaul#include <sys/systm.h> 6750120Swpaul#include <sys/kernel.h> 6850120Swpaul#include <sys/socket.h> 6950120Swpaul#include <sys/errno.h> 7050120Swpaul#include <sys/module.h> 7150120Swpaul#include <sys/bus.h> 7250120Swpaul 7350120Swpaul#include <net/if.h> 7450120Swpaul#include <net/if_media.h> 7550120Swpaul 7650120Swpaul#include <dev/mii/mii.h> 7750120Swpaul#include <dev/mii/miivar.h> 78109514Sobrien#include "miidevs.h" 7950120Swpaul 8050120Swpaul#include <dev/mii/nsphyreg.h> 8150120Swpaul 8250120Swpaul#include "miibus_if.h" 8350120Swpaul 84105135Salfredstatic int nsphy_probe(device_t); 85105135Salfredstatic int nsphy_attach(device_t); 8650120Swpaul 8750120Swpaulstatic device_method_t nsphy_methods[] = { 8850120Swpaul /* device interface */ 8950120Swpaul DEVMETHOD(device_probe, nsphy_probe), 9050120Swpaul DEVMETHOD(device_attach, nsphy_attach), 9195722Sphk DEVMETHOD(device_detach, mii_phy_detach), 9250120Swpaul DEVMETHOD(device_shutdown, bus_generic_shutdown), 9350120Swpaul { 0, 0 } 9450120Swpaul}; 9550120Swpaul 9650120Swpaulstatic devclass_t nsphy_devclass; 9750120Swpaul 9850120Swpaulstatic driver_t nsphy_driver = { 9950120Swpaul "nsphy", 10050120Swpaul nsphy_methods, 10150120Swpaul sizeof(struct mii_softc) 10250120Swpaul}; 10350120Swpaul 10450120SwpaulDRIVER_MODULE(nsphy, miibus, nsphy_driver, nsphy_devclass, 0, 0); 10550120Swpaul 10692739Salfredstatic int nsphy_service(struct mii_softc *, struct mii_data *, int); 10792739Salfredstatic void nsphy_status(struct mii_softc *); 108164708Smariusstatic void nsphy_reset(struct mii_softc *); 10950120Swpaul 110164827Smariusstatic const struct mii_phydesc nsphys[] = { 111164827Smarius MII_PHY_DESC(NATSEMI, DP83840), 112164827Smarius MII_PHY_END 113164827Smarius}; 114164827Smarius 115105135Salfredstatic int 116150763Simpnsphy_probe(device_t dev) 11750120Swpaul{ 11850120Swpaul 119164827Smarius return (mii_phy_dev_probe(dev, nsphys, BUS_PROBE_DEFAULT)); 12050120Swpaul} 12150120Swpaul 122105135Salfredstatic int 123150763Simpnsphy_attach(device_t dev) 12450120Swpaul{ 12550120Swpaul struct mii_softc *sc; 12650120Swpaul struct mii_attach_args *ma; 12750120Swpaul struct mii_data *mii; 128164708Smarius const char *nic; 12950120Swpaul 13050120Swpaul sc = device_get_softc(dev); 13150120Swpaul ma = device_get_ivars(dev); 13250120Swpaul sc->mii_dev = device_get_parent(dev); 133213229Smarius mii = ma->mii_data; 13450120Swpaul LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 13550120Swpaul 136213893Smarius sc->mii_flags = miibus_get_flags(dev); 137213364Smarius sc->mii_inst = mii->mii_instance++; 13850120Swpaul sc->mii_phy = ma->mii_phyno; 13950120Swpaul sc->mii_service = nsphy_service; 14050120Swpaul sc->mii_pdata = mii; 14150120Swpaul 142164708Smarius nic = device_get_name(device_get_parent(sc->mii_dev)); 14350120Swpaul /* 144213893Smarius * Am79C971 wedge when isolating all of their external PHYs. 14550120Swpaul */ 146213893Smarius if (strcmp(nic, "pcn") == 0) 147164708Smarius sc->mii_flags |= MIIF_NOISOLATE; 14850120Swpaul 149213893Smarius#if 1 15050120Swpaul 15150120Swpaul#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) 15250120Swpaul 153175705Smarius /* 154213893Smarius * XXX IFM_LOOP should be handled by mii_phy_add_media() based 155213893Smarius * on MIIF_NOLOOP. 156175705Smarius */ 157213893Smarius if ((sc->mii_flags & MIIF_NOLOOP) == 0) 158164708Smarius ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, 159165985Smarius sc->mii_inst), MII_MEDIA_100_TX); 160213893Smarius 16150120Swpaul#endif 16250120Swpaul 163164708Smarius nsphy_reset(sc); 16450120Swpaul 165213364Smarius sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 16650120Swpaul device_printf(dev, " "); 167164708Smarius mii_phy_add_media(sc); 16850120Swpaul printf("\n"); 16950120Swpaul 17050120Swpaul MIIBUS_MEDIAINIT(sc->mii_dev); 171164708Smarius return (0); 17250120Swpaul} 17350120Swpaul 17484145Sjlemonstatic int 175150763Simpnsphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 17650120Swpaul{ 17750120Swpaul int reg; 17850120Swpaul 17950120Swpaul switch (cmd) { 18050120Swpaul case MII_POLLSTAT: 18150120Swpaul break; 18250120Swpaul 18350120Swpaul case MII_MEDIACHG: 18450120Swpaul /* 18550120Swpaul * If the interface is not up, don't do anything. 18650120Swpaul */ 18750120Swpaul if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 18850120Swpaul break; 18950120Swpaul 19050120Swpaul reg = PHY_READ(sc, MII_NSPHY_PCR); 19150120Swpaul 19250120Swpaul /* 19350120Swpaul * Set up the PCR to use LED4 to indicate full-duplex 19450120Swpaul * in both 10baseT and 100baseTX modes. 19550120Swpaul */ 19650120Swpaul reg |= PCR_LED4MODE; 19750120Swpaul 19850120Swpaul /* 199129842Smarius * Make sure Carrier Integrity Monitor function is 20050120Swpaul * disabled (normal for Node operation, but sometimes 20150120Swpaul * it's not set?!) 20250120Swpaul */ 20350120Swpaul reg |= PCR_CIMDIS; 20450120Swpaul 20550120Swpaul /* 20650120Swpaul * Make sure "force link good" is set to normal mode. 20750120Swpaul * It's only intended for debugging. 20850120Swpaul */ 20950120Swpaul reg |= PCR_FLINK100; 21050120Swpaul 21150120Swpaul /* 21250120Swpaul * Mystery bits which are supposedly `reserved', 21350120Swpaul * but we seem to need to set them when the PHY 21474353Sjlemon * is connected to some interfaces: 21574353Sjlemon * 21674353Sjlemon * 0x0400 is needed for fxp 21774353Sjlemon * (Intel EtherExpress Pro 10+/100B, 82557 chip) 21874353Sjlemon * (nsphy with a DP83840 chip) 21974353Sjlemon * 0x0100 may be needed for some other card 22050120Swpaul */ 22150120Swpaul reg |= 0x0100 | 0x0400; 22274353Sjlemon 223164708Smarius if (strcmp(mii->mii_ifp->if_dname, "fxp") == 0) 22477634Sjlemon PHY_WRITE(sc, MII_NSPHY_PCR, reg); 22574353Sjlemon 226164708Smarius mii_phy_setmedia(sc); 22750120Swpaul break; 22850120Swpaul 22950120Swpaul case MII_TICK: 23084145Sjlemon if (mii_phy_tick(sc) == EJUSTRETURN) 23150120Swpaul return (0); 23250120Swpaul break; 23350120Swpaul } 23450120Swpaul 23550120Swpaul /* Update the media status. */ 23650120Swpaul nsphy_status(sc); 23750120Swpaul 23850120Swpaul /* Callback if something changed. */ 23984145Sjlemon mii_phy_update(sc, cmd); 24050120Swpaul return (0); 24150120Swpaul} 24250120Swpaul 24384145Sjlemonstatic void 244150763Simpnsphy_status(struct mii_softc *sc) 24550120Swpaul{ 24650120Swpaul struct mii_data *mii = sc->mii_pdata; 247164708Smarius struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 24850120Swpaul int bmsr, bmcr, par, anlpar; 24950120Swpaul 25050120Swpaul mii->mii_media_status = IFM_AVALID; 25150120Swpaul mii->mii_media_active = IFM_ETHER; 25250120Swpaul 25350120Swpaul bmsr = PHY_READ(sc, MII_BMSR) | 25450120Swpaul PHY_READ(sc, MII_BMSR); 25550120Swpaul if (bmsr & BMSR_LINK) 25650120Swpaul mii->mii_media_status |= IFM_ACTIVE; 25750120Swpaul 25850120Swpaul bmcr = PHY_READ(sc, MII_BMCR); 25950120Swpaul if (bmcr & BMCR_ISO) { 26050120Swpaul mii->mii_media_active |= IFM_NONE; 26150120Swpaul mii->mii_media_status = 0; 26250120Swpaul return; 26350120Swpaul } 26450120Swpaul 26550120Swpaul if (bmcr & BMCR_LOOP) 26650120Swpaul mii->mii_media_active |= IFM_LOOP; 26750120Swpaul 26850120Swpaul if (bmcr & BMCR_AUTOEN) { 26950120Swpaul /* 270175705Smarius * The PAR status bits are only valid if autonegotiation 27150120Swpaul * has completed (or it's disabled). 27250120Swpaul */ 27350120Swpaul if ((bmsr & BMSR_ACOMP) == 0) { 27450120Swpaul /* Erg, still trying, I guess... */ 27550120Swpaul mii->mii_media_active |= IFM_NONE; 27650120Swpaul return; 27750120Swpaul } 27850120Swpaul 27950120Swpaul /* 28050120Swpaul * Argh. The PAR doesn't seem to indicate duplex mode 28150120Swpaul * properly! Determine media based on link partner's 28250120Swpaul * advertised capabilities. 28350120Swpaul */ 28450120Swpaul if (PHY_READ(sc, MII_ANER) & ANER_LPAN) { 28550120Swpaul anlpar = PHY_READ(sc, MII_ANAR) & 28650120Swpaul PHY_READ(sc, MII_ANLPAR); 287173665Syongari if (anlpar & ANLPAR_TX_FD) 288173665Syongari mii->mii_media_active |= IFM_100_TX|IFM_FDX; 289173665Syongari else if (anlpar & ANLPAR_T4) 290213384Smarius mii->mii_media_active |= IFM_100_T4|IFM_HDX; 29150120Swpaul else if (anlpar & ANLPAR_TX) 292213384Smarius mii->mii_media_active |= IFM_100_TX|IFM_HDX; 29350120Swpaul else if (anlpar & ANLPAR_10_FD) 29450120Swpaul mii->mii_media_active |= IFM_10_T|IFM_FDX; 29550120Swpaul else if (anlpar & ANLPAR_10) 296213384Smarius mii->mii_media_active |= IFM_10_T|IFM_HDX; 29750120Swpaul else 29850120Swpaul mii->mii_media_active |= IFM_NONE; 29950120Swpaul return; 30050120Swpaul } 30150120Swpaul 30250120Swpaul /* 30350120Swpaul * Link partner is not capable of autonegotiation. 30450120Swpaul * We will never be in full-duplex mode if this is 30550120Swpaul * the case, so reading the PAR is OK. 30650120Swpaul */ 30750120Swpaul par = PHY_READ(sc, MII_NSPHY_PAR); 30850120Swpaul if (par & PAR_10) 30950120Swpaul mii->mii_media_active |= IFM_10_T; 31050120Swpaul else 31150120Swpaul mii->mii_media_active |= IFM_100_TX; 312213384Smarius mii->mii_media_active |= IFM_HDX; 31350120Swpaul } else 314164708Smarius mii->mii_media_active = ife->ifm_media; 31550120Swpaul} 316164708Smarius 317164708Smariusstatic void 318164708Smariusnsphy_reset(struct mii_softc *sc) 319164708Smarius{ 320164708Smarius struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur; 321164708Smarius int reg, i; 322164708Smarius 323164708Smarius if (sc->mii_flags & MIIF_NOISOLATE) 324164708Smarius reg = BMCR_RESET; 325164708Smarius else 326164708Smarius reg = BMCR_RESET | BMCR_ISO; 327164708Smarius PHY_WRITE(sc, MII_BMCR, reg); 328164708Smarius 329164708Smarius /* 330175705Smarius * It is best to allow a little time for the reset to settle 331175705Smarius * in before we start polling the BMCR again. Notably, the 332175705Smarius * DP83840A manuals state that there should be a 500us delay 333175705Smarius * between asserting software reset and attempting MII serial 334175705Smarius * operations. Be conservative. 335164708Smarius */ 336164708Smarius DELAY(1000); 337164708Smarius 338164708Smarius /* 339164708Smarius * Wait another 2s for it to complete. 340164708Smarius * This is only a little overkill as under normal circumstances 341164708Smarius * the PHY can take up to 1s to complete reset. 342164708Smarius * This is also a bit odd because after a reset, the BMCR will 343164708Smarius * clear the reset bit and simply reports 0 even though the reset 344164708Smarius * is not yet complete. 345164708Smarius */ 346164708Smarius for (i = 0; i < 1000; i++) { 347164708Smarius reg = PHY_READ(sc, MII_BMCR); 348164708Smarius if (reg != 0 && (reg & BMCR_RESET) == 0) 349164708Smarius break; 350164708Smarius DELAY(2000); 351164708Smarius } 352164708Smarius 353164708Smarius if ((sc->mii_flags & MIIF_NOISOLATE) == 0) { 354164708Smarius if ((ife == NULL && sc->mii_inst != 0) || 355164708Smarius (ife != NULL && IFM_INST(ife->ifm_media) != sc->mii_inst)) 356164708Smarius PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 357164708Smarius } 358164708Smarius} 359