lxtphy.c revision 213229
11556Srgrimes/* OpenBSD: lxtphy.c,v 1.5 2000/08/26 20:04:17 nate Exp */ 21556Srgrimes/* NetBSD: lxtphy.c,v 1.19 2000/02/02 23:34:57 thorpej Exp */ 31556Srgrimes 41556Srgrimes/*- 51556Srgrimes * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. 61556Srgrimes * All rights reserved. 71556Srgrimes * 81556Srgrimes * This code is derived from software contributed to The NetBSD Foundation 91556Srgrimes * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 101556Srgrimes * NASA Ames Research Center. 111556Srgrimes * 121556Srgrimes * Redistribution and use in source and binary forms, with or without 131556Srgrimes * modification, are permitted provided that the following conditions 141556Srgrimes * are met: 151556Srgrimes * 1. Redistributions of source code must retain the above copyright 161556Srgrimes * notice, this list of conditions and the following disclaimer. 171556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 181556Srgrimes * notice, this list of conditions and the following disclaimer in the 191556Srgrimes * documentation and/or other materials provided with the distribution. 201556Srgrimes * 211556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 221556Srgrimes * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 231556Srgrimes * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 241556Srgrimes * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 251556Srgrimes * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 261556Srgrimes * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 271556Srgrimes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 281556Srgrimes * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 291556Srgrimes * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30110390Scharnier * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 311556Srgrimes * POSSIBILITY OF SUCH DAMAGE. 3236006Scharnier */ 33110390Scharnier 3435773Scharnier/*- 35110390Scharnier * Copyright (c) 1997 Manuel Bouyer. All rights reserved. 3699109Sobrien * 3799109Sobrien * Redistribution and use in source and binary forms, with or without 381556Srgrimes * modification, are permitted provided that the following conditions 391556Srgrimes * are met: 401556Srgrimes * 1. Redistributions of source code must retain the above copyright 411556Srgrimes * notice, this list of conditions and the following disclaimer. 421556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 431556Srgrimes * notice, this list of conditions and the following disclaimer in the 441556Srgrimes * documentation and/or other materials provided with the distribution. 451556Srgrimes * 461556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 471556Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 481556Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 491556Srgrimes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 501556Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 511556Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 521556Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 531556Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 541556Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 551556Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 561556Srgrimes */ 571556Srgrimes 581556Srgrimes#include <sys/cdefs.h> 591556Srgrimes__FBSDID("$FreeBSD: head/sys/dev/mii/lxtphy.c 213229 2010-09-27 20:31:03Z marius $"); 601556Srgrimes 611556Srgrimes/* 621556Srgrimes * driver for Level One's LXT-970 ethernet 10/100 PHY 631556Srgrimes * datasheet from www.level1.com 641556Srgrimes */ 651556Srgrimes 6690108Simp#include <sys/param.h> 671556Srgrimes#include <sys/systm.h> 681556Srgrimes#include <sys/kernel.h> 691556Srgrimes#include <sys/socket.h> 701556Srgrimes#include <sys/errno.h> 7191079Smarkm#include <sys/module.h> 721556Srgrimes#include <sys/bus.h> 731556Srgrimes 7498062Skeramida#include <net/if.h> 7598062Skeramida#include <net/if_media.h> 761556Srgrimes 771556Srgrimes#include <dev/mii/mii.h> 781556Srgrimes#include <dev/mii/miivar.h> 79110390Scharnier#include "miidevs.h" 801556Srgrimes 811556Srgrimes#include <dev/mii/lxtphyreg.h> 821556Srgrimes 831556Srgrimes#include "miibus_if.h" 841556Srgrimes 851556Srgrimesstatic int lxtphy_probe(device_t); 861556Srgrimesstatic int lxtphy_attach(device_t); 871556Srgrimes 88244538Skevlostatic device_method_t lxtphy_methods[] = { 891556Srgrimes /* device interface */ 901556Srgrimes DEVMETHOD(device_probe, lxtphy_probe), 911556Srgrimes DEVMETHOD(device_attach, lxtphy_attach), 921556Srgrimes DEVMETHOD(device_detach, mii_phy_detach), 9391079Smarkm DEVMETHOD(device_shutdown, bus_generic_shutdown), 9491079Smarkm { 0, 0 } 951556Srgrimes}; 9691079Smarkm 9791079Smarkmstatic devclass_t lxtphy_devclass; 981556Srgrimes 991556Srgrimesstatic driver_t lxtphy_driver = { 1001556Srgrimes "lxtphy", 1011556Srgrimes lxtphy_methods, 1021556Srgrimes sizeof(struct mii_softc) 1031556Srgrimes}; 1041556Srgrimes 1051556SrgrimesDRIVER_MODULE(lxtphy, miibus, lxtphy_driver, lxtphy_devclass, 0, 0); 1061556Srgrimes 1071556Srgrimesstatic int lxtphy_service(struct mii_softc *, struct mii_data *, int); 1081556Srgrimesstatic void lxtphy_status(struct mii_softc *); 109161469Simpstatic void lxtphy_set_tp(struct mii_softc *); 1101556Srgrimesstatic void lxtphy_set_fx(struct mii_softc *); 1111556Srgrimes 1121556Srgrimesstatic const struct mii_phydesc lxtphys[] = { 1131556Srgrimes MII_PHY_DESC(xxLEVEL1, LXT970), 1141556Srgrimes MII_PHY_END 1151556Srgrimes}; 116161469Simp 1171556Srgrimesstatic int 1181556Srgrimeslxtphy_probe(device_t dev) 1191556Srgrimes{ 1201556Srgrimes 1211556Srgrimes return (mii_phy_dev_probe(dev, lxtphys, BUS_PROBE_DEFAULT)); 1221556Srgrimes} 1231556Srgrimes 1241556Srgrimesstatic int 1251556Srgrimeslxtphy_attach(device_t dev) 1261556Srgrimes{ 1271556Srgrimes struct mii_softc *sc; 1281556Srgrimes struct mii_attach_args *ma; 1291556Srgrimes struct mii_data *mii; 1301556Srgrimes const char *nic; 1311556Srgrimes 1321556Srgrimes sc = device_get_softc(dev); 1331556Srgrimes ma = device_get_ivars(dev); 1341556Srgrimes sc->mii_dev = device_get_parent(dev); 1351556Srgrimes mii = ma->mii_data; 1361556Srgrimes LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 1371556Srgrimes 1381556Srgrimes sc->mii_inst = mii->mii_instance; 1391556Srgrimes sc->mii_phy = ma->mii_phyno; 1401556Srgrimes sc->mii_service = lxtphy_service; 14191079Smarkm sc->mii_pdata = mii; 1421556Srgrimes 14391079Smarkm mii->mii_instance++; 14491079Smarkm 14591079Smarkm mii_phy_reset(sc); 1461556Srgrimes 1471556Srgrimes sc->mii_capabilities = 1481556Srgrimes PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 1491556Srgrimes device_printf(dev, " "); 1501556Srgrimes 1511556Srgrimes /* 1521556Srgrimes * On Apple BMAC controllers, we end up in a weird state 1531556Srgrimes * of partially-completed autonegotiation on boot. So 1541556Srgrimes * force autonegotation to try again. 1551556Srgrimes */ 1561556Srgrimes nic = device_get_name(device_get_parent(sc->mii_dev)); 1571556Srgrimes if (strcmp(nic, "bm") == 0) 1581556Srgrimes sc->mii_flags |= MIIF_FORCEANEG | MIIF_NOISOLATE; 1591556Srgrimes 1601556Srgrimes#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) 1611556Srgrimes ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, 0, sc->mii_inst), 1621556Srgrimes MII_MEDIA_100_TX); 1631556Srgrimes printf("100baseFX, "); 1641556Srgrimes ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, IFM_FDX, sc->mii_inst), 1651556Srgrimes MII_MEDIA_100_TX_FDX); 1661556Srgrimes printf("100baseFX-FDX, "); 1671556Srgrimes#undef ADD 1681556Srgrimes 1698855Srgrimes mii_phy_add_media(sc); 1701556Srgrimes printf("\n"); 1711556Srgrimes 1721556Srgrimes MIIBUS_MEDIAINIT(sc->mii_dev); 1731556Srgrimes return (0); 1741556Srgrimes} 1751556Srgrimes 1761556Srgrimesstatic int 1771556Srgrimeslxtphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 1781556Srgrimes{ 1791556Srgrimes struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 1801556Srgrimes int reg; 1811556Srgrimes 182 switch (cmd) { 183 case MII_POLLSTAT: 184 /* 185 * If we're not polling our PHY instance, just return. 186 */ 187 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 188 return (0); 189 break; 190 191 case MII_MEDIACHG: 192 /* 193 * If the media indicates a different PHY instance, 194 * isolate ourselves. 195 */ 196 if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 197 reg = PHY_READ(sc, MII_BMCR); 198 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 199 return (0); 200 } 201 202 /* 203 * If the interface is not up, don't do anything. 204 */ 205 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 206 break; 207 208 if (IFM_SUBTYPE(ife->ifm_media) == IFM_100_FX) 209 lxtphy_set_fx(sc); 210 else 211 lxtphy_set_tp(sc); 212 213 mii_phy_setmedia(sc); 214 break; 215 216 case MII_TICK: 217 /* 218 * If we're not currently selected, just return. 219 */ 220 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 221 return (0); 222 if (mii_phy_tick(sc) == EJUSTRETURN) 223 return (0); 224 break; 225 } 226 227 /* Update the media status. */ 228 lxtphy_status(sc); 229 230 /* Callback if something changed. */ 231 mii_phy_update(sc, cmd); 232 return (0); 233} 234 235static void 236lxtphy_status(struct mii_softc *sc) 237{ 238 struct mii_data *mii = sc->mii_pdata; 239 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 240 int bmcr, bmsr, csr; 241 242 mii->mii_media_status = IFM_AVALID; 243 mii->mii_media_active = IFM_ETHER; 244 245 /* 246 * Get link status from the CSR; we need to read the CSR 247 * for media type anyhow, and the link status in the CSR 248 * doens't latch, so fewer register reads are required. 249 */ 250 csr = PHY_READ(sc, MII_LXTPHY_CSR); 251 if (csr & CSR_LINK) 252 mii->mii_media_status |= IFM_ACTIVE; 253 254 bmcr = PHY_READ(sc, MII_BMCR); 255 if (bmcr & BMCR_ISO) { 256 mii->mii_media_active |= IFM_NONE; 257 mii->mii_media_status = 0; 258 return; 259 } 260 261 if (bmcr & BMCR_LOOP) 262 mii->mii_media_active |= IFM_LOOP; 263 264 if (bmcr & BMCR_AUTOEN) { 265 bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 266 if ((bmsr & BMSR_ACOMP) == 0) { 267 /* Erg, still trying, I guess... */ 268 mii->mii_media_active |= IFM_NONE; 269 return; 270 } 271 if (csr & CSR_SPEED) 272 mii->mii_media_active |= IFM_100_TX; 273 else 274 mii->mii_media_active |= IFM_10_T; 275 if (csr & CSR_DUPLEX) 276 mii->mii_media_active |= IFM_FDX; 277 } else 278 mii->mii_media_active = ife->ifm_media; 279} 280 281static void 282lxtphy_set_tp(struct mii_softc *sc) 283{ 284 int cfg; 285 286 cfg = PHY_READ(sc, MII_LXTPHY_CONFIG); 287 cfg &= ~CONFIG_100BASEFX; 288 PHY_WRITE(sc, MII_LXTPHY_CONFIG, cfg); 289} 290 291static void 292lxtphy_set_fx(struct mii_softc *sc) 293{ 294 int cfg; 295 296 cfg = PHY_READ(sc, MII_LXTPHY_CONFIG); 297 cfg |= CONFIG_100BASEFX; 298 PHY_WRITE(sc, MII_LXTPHY_CONFIG, cfg); 299} 300