1139749Simp/*- 299440Sbenno * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc. 399440Sbenno * All rights reserved. 499440Sbenno * 599440Sbenno * This code is derived from software contributed to The NetBSD Foundation 699440Sbenno * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 799440Sbenno * NASA Ames Research Center. 899440Sbenno * 999440Sbenno * Redistribution and use in source and binary forms, with or without 1099440Sbenno * modification, are permitted provided that the following conditions 1199440Sbenno * are met: 1299440Sbenno * 1. Redistributions of source code must retain the above copyright 1399440Sbenno * notice, this list of conditions and the following disclaimer. 1499440Sbenno * 2. Redistributions in binary form must reproduce the above copyright 1599440Sbenno * notice, this list of conditions and the following disclaimer in the 1699440Sbenno * documentation and/or other materials provided with the distribution. 1799440Sbenno * 1899440Sbenno * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 1999440Sbenno * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2099440Sbenno * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2199440Sbenno * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2299440Sbenno * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2399440Sbenno * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2499440Sbenno * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2599440Sbenno * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2699440Sbenno * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2799440Sbenno * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2899440Sbenno * POSSIBILITY OF SUCH DAMAGE. 2999440Sbenno */ 3099440Sbenno 3199440Sbenno/* 3299440Sbenno * Copyright (c) 1997 Manuel Bouyer. All rights reserved. 3399440Sbenno * 3499440Sbenno * Redistribution and use in source and binary forms, with or without 3599440Sbenno * modification, are permitted provided that the following conditions 3699440Sbenno * are met: 3799440Sbenno * 1. Redistributions of source code must retain the above copyright 3899440Sbenno * notice, this list of conditions and the following disclaimer. 3999440Sbenno * 2. Redistributions in binary form must reproduce the above copyright 4099440Sbenno * notice, this list of conditions and the following disclaimer in the 4199440Sbenno * documentation and/or other materials provided with the distribution. 4299440Sbenno * 4399440Sbenno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 4499440Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 4599440Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 4699440Sbenno * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 4799440Sbenno * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 4899440Sbenno * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 4999440Sbenno * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 5099440Sbenno * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 5199440Sbenno * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 5299440Sbenno * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 5399440Sbenno * 5499440Sbenno * from: NetBSD: bmtphy.c,v 1.8 2002/07/03 06:25:50 simonb Exp 5599440Sbenno * 5699440Sbenno */ 5799440Sbenno 58129844Smarius#include <sys/cdefs.h> 59129844Smarius__FBSDID("$FreeBSD: releng/11.0/sys/dev/mii/bmtphy.c 257184 2013-10-26 18:40:17Z glebius $"); 60129844Smarius 6199440Sbenno/* 6299440Sbenno * Driver for the Broadcom BCM5201/BCM5202 "Mini-Theta" PHYs. This also 6399440Sbenno * drives the PHY on the 3Com 3c905C. The 3c905C's PHY is described in 6499440Sbenno * the 3c905C data sheet. 6599440Sbenno */ 6699440Sbenno 6799440Sbenno#include <sys/param.h> 6899440Sbenno#include <sys/systm.h> 6999440Sbenno#include <sys/kernel.h> 70129876Sphk#include <sys/module.h> 7199440Sbenno#include <sys/socket.h> 7299440Sbenno#include <sys/bus.h> 7399440Sbenno 7499440Sbenno#include <net/if.h> 7599440Sbenno#include <net/if_media.h> 7699440Sbenno 7799440Sbenno#include <dev/mii/mii.h> 7899440Sbenno#include <dev/mii/miivar.h> 79109514Sobrien#include "miidevs.h" 8099440Sbenno 8199440Sbenno#include <dev/mii/bmtphyreg.h> 8299440Sbenno 8399440Sbenno#include "miibus_if.h" 8499440Sbenno 8599440Sbennostatic int bmtphy_probe(device_t); 8699440Sbennostatic int bmtphy_attach(device_t); 8799440Sbenno 8899440Sbennostatic device_method_t bmtphy_methods[] = { 8999440Sbenno /* Device interface */ 9099440Sbenno DEVMETHOD(device_probe, bmtphy_probe), 9199440Sbenno DEVMETHOD(device_attach, bmtphy_attach), 9299440Sbenno DEVMETHOD(device_detach, mii_phy_detach), 9399440Sbenno DEVMETHOD(device_shutdown, bus_generic_shutdown), 94227908Smarius DEVMETHOD_END 9599440Sbenno}; 9699440Sbenno 9799440Sbennostatic devclass_t bmtphy_devclass; 9899440Sbenno 9999440Sbennostatic driver_t bmtphy_driver = { 10099440Sbenno "bmtphy", 10199440Sbenno bmtphy_methods, 102221407Smarius sizeof(struct mii_softc) 10399440Sbenno}; 10499440Sbenno 10599440SbennoDRIVER_MODULE(bmtphy, miibus, bmtphy_driver, bmtphy_devclass, 0, 0); 10699440Sbenno 10799440Sbennostatic int bmtphy_service(struct mii_softc *, struct mii_data *, int); 10899440Sbennostatic void bmtphy_status(struct mii_softc *); 109215720Smariusstatic void bmtphy_reset(struct mii_softc *); 11099440Sbenno 111164827Smariusstatic const struct mii_phydesc bmtphys_dp[] = { 112221407Smarius MII_PHY_DESC(xxBROADCOM, BCM4401), 113221407Smarius MII_PHY_DESC(xxBROADCOM, BCM5201), 114221407Smarius MII_PHY_DESC(xxBROADCOM, BCM5214), 115221407Smarius MII_PHY_DESC(xxBROADCOM, BCM5221), 116221407Smarius MII_PHY_DESC(xxBROADCOM, BCM5222), 117164827Smarius MII_PHY_END 118164827Smarius}; 119164827Smarius 120164827Smariusstatic const struct mii_phydesc bmtphys_lp[] = { 121221407Smarius MII_PHY_DESC(xxBROADCOM, 3C905B), 122221407Smarius MII_PHY_DESC(xxBROADCOM, 3C905C), 123164827Smarius MII_PHY_END 124164827Smarius}; 125164827Smarius 126221407Smariusstatic const struct mii_phy_funcs bmtphy_funcs = { 127221407Smarius bmtphy_service, 128221407Smarius bmtphy_status, 129221407Smarius bmtphy_reset 130221407Smarius}; 131221407Smarius 13299440Sbennostatic int 13399440Sbennobmtphy_probe(device_t dev) 13499440Sbenno{ 13599440Sbenno int rval; 13699440Sbenno 137164827Smarius /* Let exphy(4) take precedence for these. */ 138164827Smarius rval = mii_phy_dev_probe(dev, bmtphys_lp, BUS_PROBE_LOW_PRIORITY); 139164827Smarius if (rval <= 0) 140164827Smarius return (rval); 14199440Sbenno 142164827Smarius return (mii_phy_dev_probe(dev, bmtphys_dp, BUS_PROBE_DEFAULT)); 14399440Sbenno} 14499440Sbenno 14599440Sbennostatic int 14699440Sbennobmtphy_attach(device_t dev) 14799440Sbenno{ 14899440Sbenno 149221407Smarius mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &bmtphy_funcs, 1); 15099440Sbenno return (0); 15199440Sbenno} 15299440Sbenno 15399440Sbennostatic int 15499440Sbennobmtphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 15599440Sbenno{ 15699440Sbenno 15799440Sbenno switch (cmd) { 15899440Sbenno case MII_POLLSTAT: 15999440Sbenno break; 16099440Sbenno 16199440Sbenno case MII_MEDIACHG: 16299440Sbenno mii_phy_setmedia(sc); 16399440Sbenno break; 16499440Sbenno 16599440Sbenno case MII_TICK: 16699440Sbenno if (mii_phy_tick(sc) == EJUSTRETURN) 16799440Sbenno return (0); 16899440Sbenno break; 16999440Sbenno } 17099440Sbenno 17199440Sbenno /* Update the media status. */ 172221407Smarius PHY_STATUS(sc); 17399440Sbenno 17499440Sbenno /* Callback if something changed. */ 17599440Sbenno mii_phy_update(sc, cmd); 17699440Sbenno return (0); 17799440Sbenno} 17899440Sbenno 17999440Sbennostatic void 18099440Sbennobmtphy_status(struct mii_softc *sc) 18199440Sbenno{ 182215720Smarius struct mii_data *mii; 183215720Smarius struct ifmedia_entry *ife; 184215720Smarius int bmsr, bmcr, aux_csr; 18599440Sbenno 18699440Sbenno mii = sc->mii_pdata; 18799440Sbenno ife = mii->mii_media.ifm_cur; 18899440Sbenno 18999440Sbenno mii->mii_media_status = IFM_AVALID; 19099440Sbenno mii->mii_media_active = IFM_ETHER; 19199440Sbenno 19299440Sbenno bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 19399440Sbenno 19499440Sbenno if (bmsr & BMSR_LINK) 19599440Sbenno mii->mii_media_status |= IFM_ACTIVE; 19699440Sbenno 19799440Sbenno bmcr = PHY_READ(sc, MII_BMCR); 19899440Sbenno if (bmcr & BMCR_ISO) { 19999440Sbenno mii->mii_media_active |= IFM_NONE; 20099440Sbenno mii->mii_media_status = 0; 20199440Sbenno return; 20299440Sbenno } 20399440Sbenno 20499440Sbenno if (bmcr & BMCR_LOOP) 20599440Sbenno mii->mii_media_active |= IFM_LOOP; 20699440Sbenno 20799440Sbenno if (bmcr & BMCR_AUTOEN) { 20899440Sbenno /* 20999440Sbenno * The media status bits are only valid if autonegotiation 21099440Sbenno * has completed (or it's disabled). 21199440Sbenno */ 21299440Sbenno if ((bmsr & BMSR_ACOMP) == 0) { 21399440Sbenno /* Erg, still trying, I guess... */ 21499440Sbenno mii->mii_media_active |= IFM_NONE; 21599440Sbenno return; 21699440Sbenno } 21799440Sbenno 218215720Smarius aux_csr = PHY_READ(sc, MII_BMTPHY_AUX_CSR); 21999440Sbenno if (aux_csr & AUX_CSR_SPEED) 22099440Sbenno mii->mii_media_active |= IFM_100_TX; 22199440Sbenno else 22299440Sbenno mii->mii_media_active |= IFM_10_T; 22399440Sbenno if (aux_csr & AUX_CSR_FDX) 224215716Smarius mii->mii_media_active |= 225215716Smarius IFM_FDX | mii_phy_flowstatus(sc); 226213384Smarius else 227213384Smarius mii->mii_media_active |= IFM_HDX; 22899440Sbenno } else 22999440Sbenno mii->mii_media_active = ife->ifm_media; 23099440Sbenno} 231215720Smarius 232215720Smariusstatic void 233215720Smariusbmtphy_reset(struct mii_softc *sc) 234215720Smarius{ 235215720Smarius u_int16_t data; 236215720Smarius 237215720Smarius mii_phy_reset(sc); 238215720Smarius 239221407Smarius if (sc->mii_mpd_model == MII_MODEL_xxBROADCOM_BCM5221) { 240215720Smarius /* Enable shadow register mode. */ 241215720Smarius data = PHY_READ(sc, 0x1f); 242215720Smarius PHY_WRITE(sc, 0x1f, data | 0x0080); 243215720Smarius 244215720Smarius /* Enable APD (Auto PowerDetect). */ 245215720Smarius data = PHY_READ(sc, MII_BMTPHY_AUX2); 246215720Smarius PHY_WRITE(sc, MII_BMTPHY_AUX2, data | 0x0020); 247215720Smarius 248215720Smarius /* Enable clocks across APD for Auto-MDIX functionality. */ 249215720Smarius data = PHY_READ(sc, MII_BMTPHY_INTR); 250215720Smarius PHY_WRITE(sc, MII_BMTPHY_INTR, data | 0x0004); 251215720Smarius 252215720Smarius /* Disable shadow register mode. */ 253215720Smarius data = PHY_READ(sc, 0x1f); 254215720Smarius PHY_WRITE(sc, 0x1f, data & ~0x0080); 255215720Smarius } 256215720Smarius} 257