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$"); 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), 93227908Smarius DEVMETHOD_END 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[] = { 111221407Smarius MII_PHY_DESC(xxNATSEMI, DP83840), 112164827Smarius MII_PHY_END 113164827Smarius}; 114164827Smarius 115221407Smariusstatic const struct mii_phy_funcs nsphy_funcs = { 116221407Smarius nsphy_service, 117221407Smarius nsphy_status, 118221407Smarius nsphy_reset 119221407Smarius}; 120221407Smarius 121105135Salfredstatic int 122150763Simpnsphy_probe(device_t dev) 12350120Swpaul{ 12450120Swpaul 125164827Smarius return (mii_phy_dev_probe(dev, nsphys, BUS_PROBE_DEFAULT)); 12650120Swpaul} 12750120Swpaul 128105135Salfredstatic int 129150763Simpnsphy_attach(device_t dev) 13050120Swpaul{ 131164708Smarius const char *nic; 132221407Smarius u_int flags; 13350120Swpaul 134221407Smarius nic = device_get_name(device_get_parent(device_get_parent(dev))); 135221407Smarius flags = MIIF_NOMANPAUSE; 13650120Swpaul /* 137213893Smarius * Am79C971 wedge when isolating all of their external PHYs. 13850120Swpaul */ 139213893Smarius if (strcmp(nic, "pcn") == 0) 140221407Smarius flags |= MIIF_NOISOLATE; 141221407Smarius mii_phy_dev_attach(dev, flags, &nsphy_funcs, 1); 142164708Smarius return (0); 14350120Swpaul} 14450120Swpaul 14584145Sjlemonstatic int 146150763Simpnsphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 14750120Swpaul{ 14850120Swpaul int reg; 14950120Swpaul 15050120Swpaul switch (cmd) { 15150120Swpaul case MII_POLLSTAT: 15250120Swpaul break; 15350120Swpaul 15450120Swpaul case MII_MEDIACHG: 15550120Swpaul /* 15650120Swpaul * If the interface is not up, don't do anything. 15750120Swpaul */ 15850120Swpaul if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 15950120Swpaul break; 16050120Swpaul 16150120Swpaul reg = PHY_READ(sc, MII_NSPHY_PCR); 16250120Swpaul 16350120Swpaul /* 16450120Swpaul * Set up the PCR to use LED4 to indicate full-duplex 16550120Swpaul * in both 10baseT and 100baseTX modes. 16650120Swpaul */ 16750120Swpaul reg |= PCR_LED4MODE; 16850120Swpaul 16950120Swpaul /* 170129842Smarius * Make sure Carrier Integrity Monitor function is 17150120Swpaul * disabled (normal for Node operation, but sometimes 17250120Swpaul * it's not set?!) 17350120Swpaul */ 17450120Swpaul reg |= PCR_CIMDIS; 17550120Swpaul 17650120Swpaul /* 17750120Swpaul * Make sure "force link good" is set to normal mode. 17850120Swpaul * It's only intended for debugging. 17950120Swpaul */ 18050120Swpaul reg |= PCR_FLINK100; 18150120Swpaul 18250120Swpaul /* 18350120Swpaul * Mystery bits which are supposedly `reserved', 18450120Swpaul * but we seem to need to set them when the PHY 18574353Sjlemon * is connected to some interfaces: 18674353Sjlemon * 18774353Sjlemon * 0x0400 is needed for fxp 18874353Sjlemon * (Intel EtherExpress Pro 10+/100B, 82557 chip) 18974353Sjlemon * (nsphy with a DP83840 chip) 19074353Sjlemon * 0x0100 may be needed for some other card 19150120Swpaul */ 19250120Swpaul reg |= 0x0100 | 0x0400; 19374353Sjlemon 194164708Smarius if (strcmp(mii->mii_ifp->if_dname, "fxp") == 0) 19577634Sjlemon PHY_WRITE(sc, MII_NSPHY_PCR, reg); 19674353Sjlemon 197164708Smarius mii_phy_setmedia(sc); 19850120Swpaul break; 19950120Swpaul 20050120Swpaul case MII_TICK: 20184145Sjlemon if (mii_phy_tick(sc) == EJUSTRETURN) 20250120Swpaul return (0); 20350120Swpaul break; 20450120Swpaul } 20550120Swpaul 20650120Swpaul /* Update the media status. */ 207221407Smarius PHY_STATUS(sc); 20850120Swpaul 20950120Swpaul /* Callback if something changed. */ 21084145Sjlemon mii_phy_update(sc, cmd); 21150120Swpaul return (0); 21250120Swpaul} 21350120Swpaul 21484145Sjlemonstatic void 215150763Simpnsphy_status(struct mii_softc *sc) 21650120Swpaul{ 21750120Swpaul struct mii_data *mii = sc->mii_pdata; 218164708Smarius struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 21950120Swpaul int bmsr, bmcr, par, anlpar; 22050120Swpaul 22150120Swpaul mii->mii_media_status = IFM_AVALID; 22250120Swpaul mii->mii_media_active = IFM_ETHER; 22350120Swpaul 22450120Swpaul bmsr = PHY_READ(sc, MII_BMSR) | 22550120Swpaul PHY_READ(sc, MII_BMSR); 22650120Swpaul if (bmsr & BMSR_LINK) 22750120Swpaul mii->mii_media_status |= IFM_ACTIVE; 22850120Swpaul 22950120Swpaul bmcr = PHY_READ(sc, MII_BMCR); 23050120Swpaul if (bmcr & BMCR_ISO) { 23150120Swpaul mii->mii_media_active |= IFM_NONE; 23250120Swpaul mii->mii_media_status = 0; 23350120Swpaul return; 23450120Swpaul } 23550120Swpaul 23650120Swpaul if (bmcr & BMCR_LOOP) 23750120Swpaul mii->mii_media_active |= IFM_LOOP; 23850120Swpaul 23950120Swpaul if (bmcr & BMCR_AUTOEN) { 24050120Swpaul /* 241175705Smarius * The PAR status bits are only valid if autonegotiation 24250120Swpaul * has completed (or it's disabled). 24350120Swpaul */ 24450120Swpaul if ((bmsr & BMSR_ACOMP) == 0) { 24550120Swpaul /* Erg, still trying, I guess... */ 24650120Swpaul mii->mii_media_active |= IFM_NONE; 24750120Swpaul return; 24850120Swpaul } 24950120Swpaul 25050120Swpaul /* 25150120Swpaul * Argh. The PAR doesn't seem to indicate duplex mode 25250120Swpaul * properly! Determine media based on link partner's 25350120Swpaul * advertised capabilities. 25450120Swpaul */ 25550120Swpaul if (PHY_READ(sc, MII_ANER) & ANER_LPAN) { 25650120Swpaul anlpar = PHY_READ(sc, MII_ANAR) & 25750120Swpaul PHY_READ(sc, MII_ANLPAR); 258173665Syongari if (anlpar & ANLPAR_TX_FD) 259173665Syongari mii->mii_media_active |= IFM_100_TX|IFM_FDX; 260173665Syongari else if (anlpar & ANLPAR_T4) 261213384Smarius mii->mii_media_active |= IFM_100_T4|IFM_HDX; 26250120Swpaul else if (anlpar & ANLPAR_TX) 263213384Smarius mii->mii_media_active |= IFM_100_TX|IFM_HDX; 26450120Swpaul else if (anlpar & ANLPAR_10_FD) 26550120Swpaul mii->mii_media_active |= IFM_10_T|IFM_FDX; 26650120Swpaul else if (anlpar & ANLPAR_10) 267213384Smarius mii->mii_media_active |= IFM_10_T|IFM_HDX; 26850120Swpaul else 26950120Swpaul mii->mii_media_active |= IFM_NONE; 270221407Smarius if ((mii->mii_media_active & IFM_FDX) != 0) 271221407Smarius mii->mii_media_active |= 272221407Smarius mii_phy_flowstatus(sc); 27350120Swpaul return; 27450120Swpaul } 27550120Swpaul 27650120Swpaul /* 27750120Swpaul * Link partner is not capable of autonegotiation. 27850120Swpaul * We will never be in full-duplex mode if this is 27950120Swpaul * the case, so reading the PAR is OK. 28050120Swpaul */ 28150120Swpaul par = PHY_READ(sc, MII_NSPHY_PAR); 28250120Swpaul if (par & PAR_10) 28350120Swpaul mii->mii_media_active |= IFM_10_T; 28450120Swpaul else 28550120Swpaul mii->mii_media_active |= IFM_100_TX; 286213384Smarius mii->mii_media_active |= IFM_HDX; 28750120Swpaul } else 288164708Smarius mii->mii_media_active = ife->ifm_media; 28950120Swpaul} 290164708Smarius 291164708Smariusstatic void 292164708Smariusnsphy_reset(struct mii_softc *sc) 293164708Smarius{ 294164708Smarius struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur; 295164708Smarius int reg, i; 296164708Smarius 297164708Smarius if (sc->mii_flags & MIIF_NOISOLATE) 298164708Smarius reg = BMCR_RESET; 299164708Smarius else 300164708Smarius reg = BMCR_RESET | BMCR_ISO; 301164708Smarius PHY_WRITE(sc, MII_BMCR, reg); 302164708Smarius 303164708Smarius /* 304175705Smarius * It is best to allow a little time for the reset to settle 305175705Smarius * in before we start polling the BMCR again. Notably, the 306175705Smarius * DP83840A manuals state that there should be a 500us delay 307175705Smarius * between asserting software reset and attempting MII serial 308175705Smarius * operations. Be conservative. 309164708Smarius */ 310164708Smarius DELAY(1000); 311164708Smarius 312164708Smarius /* 313164708Smarius * Wait another 2s for it to complete. 314164708Smarius * This is only a little overkill as under normal circumstances 315164708Smarius * the PHY can take up to 1s to complete reset. 316164708Smarius * This is also a bit odd because after a reset, the BMCR will 317164708Smarius * clear the reset bit and simply reports 0 even though the reset 318164708Smarius * is not yet complete. 319164708Smarius */ 320164708Smarius for (i = 0; i < 1000; i++) { 321164708Smarius reg = PHY_READ(sc, MII_BMCR); 322164708Smarius if (reg != 0 && (reg & BMCR_RESET) == 0) 323164708Smarius break; 324164708Smarius DELAY(2000); 325164708Smarius } 326164708Smarius 327164708Smarius if ((sc->mii_flags & MIIF_NOISOLATE) == 0) { 328164708Smarius if ((ife == NULL && sc->mii_inst != 0) || 329164708Smarius (ife != NULL && IFM_INST(ife->ifm_media) != sc->mii_inst)) 330164708Smarius PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 331164708Smarius } 332164708Smarius} 333