1 /* $NetBSD: nsphy.c,v 1.39 2003/04/29 01:49:34 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * Copyright (c) 1997 Manuel Bouyer. All rights reserved. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. All advertising materials mentioning features or use of this software 52 * must display the following acknowledgement: 53 * This product includes software developed by Manuel Bouyer. 54 * 4. The name of the author may not be used to endorse or promote products 55 * derived from this software without specific prior written permission. 56 * 57 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 58 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 59 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 60 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 61 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 62 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 63 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 64 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 65 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 66 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 67 */ 68 69 /* 70 * driver for National Semiconductor's DP83840A ethernet 10/100 PHY 71 * Data Sheet available from www.national.com 72 */ 73 74 #include <sys/cdefs.h> 75 __KERNEL_RCSID(0, "$NetBSD: nsphy.c,v 1.39 2003/04/29 01:49:34 thorpej Exp $"); 76 77 #include <sys/param.h> 78 #include <sys/systm.h> 79 #include <sys/kernel.h> 80 #include <sys/device.h> 81 #include <sys/socket.h> 82 #include <sys/errno.h> 83 84 #include <net/if.h> 85 #include <net/if_media.h> 86 87 #include <dev/mii/mii.h> 88 #include <dev/mii/miivar.h> 89 #include <dev/mii/miidevs.h> 90 91 #include <dev/mii/nsphyreg.h> 92 93 int nsphymatch(struct device *, struct cfdata *, void *); 94 void nsphyattach(struct device *, struct device *, void *); 95 96 CFATTACH_DECL(nsphy, sizeof(struct mii_softc), 97 nsphymatch, nsphyattach, mii_phy_detach, mii_phy_activate); 98 99 int nsphy_service(struct mii_softc *, struct mii_data *, int); 100 void nsphy_status(struct mii_softc *); 101 102 const struct mii_phy_funcs nsphy_funcs = { 103 nsphy_service, nsphy_status, mii_phy_reset, 104 }; 105 106 const struct mii_phydesc nsphys[] = { 107 { MII_OUI_xxNATSEMI, MII_MODEL_xxNATSEMI_DP83840, 108 MII_STR_xxNATSEMI_DP83840 }, 109 110 { 0, 0, 111 NULL }, 112 }; 113 114 int 115 nsphymatch(struct device *parent, struct cfdata *match, void *aux) 116 { 117 struct mii_attach_args *ma = aux; 118 119 if (mii_phy_match(ma, nsphys) != NULL) 120 return (10); 121 122 return (0); 123 } 124 125 void 126 nsphyattach(struct device *parent, struct device *self, void *aux) 127 { 128 struct mii_softc *sc = (struct mii_softc *)self; 129 struct mii_attach_args *ma = aux; 130 struct mii_data *mii = ma->mii_data; 131 const struct mii_phydesc *mpd; 132 133 mpd = mii_phy_match(ma, nsphys); 134 aprint_naive(": Media interface\n"); 135 aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2)); 136 137 sc->mii_inst = mii->mii_instance; 138 sc->mii_phy = ma->mii_phyno; 139 sc->mii_funcs = &nsphy_funcs; 140 sc->mii_pdata = mii; 141 sc->mii_flags = ma->mii_flags; 142 sc->mii_anegticks = 5; 143 144 PHY_RESET(sc); 145 146 sc->mii_capabilities = 147 PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 148 aprint_normal("%s: ", sc->mii_dev.dv_xname); 149 if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0) 150 aprint_error("no media present"); 151 else 152 mii_phy_add_media(sc); 153 aprint_normal("\n"); 154 } 155 156 int 157 nsphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 158 { 159 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 160 int reg; 161 162 if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0) 163 return (ENXIO); 164 165 switch (cmd) { 166 case MII_POLLSTAT: 167 /* 168 * If we're not polling our PHY instance, just return. 169 */ 170 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 171 return (0); 172 break; 173 174 case MII_MEDIACHG: 175 /* 176 * If the media indicates a different PHY instance, 177 * isolate ourselves. 178 */ 179 if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 180 reg = PHY_READ(sc, MII_BMCR); 181 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 182 return (0); 183 } 184 185 /* 186 * If the interface is not up, don't do anything. 187 */ 188 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 189 break; 190 191 reg = PHY_READ(sc, MII_NSPHY_PCR); 192 193 /* 194 * Set up the PCR to use LED4 to indicate full-duplex 195 * in both 10baseT and 100baseTX modes. 196 */ 197 reg |= PCR_LED4MODE; 198 199 /* 200 * Make sure Carrier Intgrity Monitor function is 201 * disabled (normal for Node operation, but sometimes 202 * it's not set?!) 203 */ 204 reg |= PCR_CIMDIS; 205 206 /* 207 * Make sure "force link good" is set to normal mode. 208 * It's only intended for debugging. 209 */ 210 reg |= PCR_FLINK100; 211 212 /* 213 * Mystery bits which are supposedly `reserved', 214 * but we seem to need to set them when the PHY 215 * is connected to some interfaces: 216 * 217 * 0x0400 is needed for fxp 218 * (Intel EtherExpress Pro 10+/100B, 82557 chip) 219 * (nsphy with a DP83840 chip) 220 * 0x0100 may be needed for some other card 221 */ 222 reg |= 0x0100 | 0x0400; 223 224 PHY_WRITE(sc, MII_NSPHY_PCR, reg); 225 226 mii_phy_setmedia(sc); 227 break; 228 229 case MII_TICK: 230 /* 231 * If we're not currently selected, just return. 232 */ 233 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 234 return (0); 235 236 if (mii_phy_tick(sc) == EJUSTRETURN) 237 return (0); 238 break; 239 240 case MII_DOWN: 241 mii_phy_down(sc); 242 return (0); 243 } 244 245 /* Update the media status. */ 246 mii_phy_status(sc); 247 248 /* Callback if something changed. */ 249 mii_phy_update(sc, cmd); 250 return (0); 251 } 252 253 void 254 nsphy_status(struct mii_softc *sc) 255 { 256 struct mii_data *mii = sc->mii_pdata; 257 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 258 int bmsr, bmcr, par, anlpar; 259 260 mii->mii_media_status = IFM_AVALID; 261 mii->mii_media_active = IFM_ETHER; 262 263 bmsr = PHY_READ(sc, MII_BMSR) | 264 PHY_READ(sc, MII_BMSR); 265 if (bmsr & BMSR_LINK) 266 mii->mii_media_status |= IFM_ACTIVE; 267 268 bmcr = PHY_READ(sc, MII_BMCR); 269 if (bmcr & BMCR_ISO) { 270 mii->mii_media_active |= IFM_NONE; 271 mii->mii_media_status = 0; 272 return; 273 } 274 275 if (bmcr & BMCR_LOOP) 276 mii->mii_media_active |= IFM_LOOP; 277 278 if (bmcr & BMCR_AUTOEN) { 279 /* 280 * The PAR status bits are only valid of autonegotiation 281 * has completed (or it's disabled). 282 */ 283 if ((bmsr & BMSR_ACOMP) == 0) { 284 /* Erg, still trying, I guess... */ 285 mii->mii_media_active |= IFM_NONE; 286 return; 287 } 288 289 /* 290 * Argh. The PAR doesn't seem to indicate duplex mode 291 * properly! Determine media based on link partner's 292 * advertised capabilities. 293 */ 294 if (PHY_READ(sc, MII_ANER) & ANER_LPAN) { 295 anlpar = PHY_READ(sc, MII_ANAR) & 296 PHY_READ(sc, MII_ANLPAR); 297 if (anlpar & ANLPAR_T4) 298 mii->mii_media_active |= IFM_100_T4; 299 else if (anlpar & ANLPAR_TX_FD) 300 mii->mii_media_active |= IFM_100_TX|IFM_FDX; 301 else if (anlpar & ANLPAR_TX) 302 mii->mii_media_active |= IFM_100_TX; 303 else if (anlpar & ANLPAR_10_FD) 304 mii->mii_media_active |= IFM_10_T|IFM_FDX; 305 else if (anlpar & ANLPAR_10) 306 mii->mii_media_active |= IFM_10_T; 307 else 308 mii->mii_media_active |= IFM_NONE; 309 return; 310 } 311 312 /* 313 * Link partner is not capable of autonegotiation. 314 * We will never be in full-duplex mode if this is 315 * the case, so reading the PAR is OK. 316 */ 317 par = PHY_READ(sc, MII_NSPHY_PAR); 318 if (par & PAR_10) 319 mii->mii_media_active |= IFM_10_T; 320 else 321 mii->mii_media_active |= IFM_100_TX; 322 #if 0 323 if (par & PAR_FDX) 324 mii->mii_media_active |= IFM_FDX; 325 #endif 326 } else 327 mii->mii_media_active = ife->ifm_media; 328 } 329