172132Ssemenu/* OpenBSD: qsphy.c,v 1.6 2000/08/26 20:04:18 nate Exp */ 272132Ssemenu/* NetBSD: qsphy.c,v 1.19 2000/02/02 23:34:57 thorpej Exp */ 372132Ssemenu 472132Ssemenu/*- 572132Ssemenu * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. 672132Ssemenu * All rights reserved. 772132Ssemenu * 872132Ssemenu * This code is derived from software contributed to The NetBSD Foundation 972132Ssemenu * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 1072132Ssemenu * NASA Ames Research Center. 1172132Ssemenu * 1272132Ssemenu * Redistribution and use in source and binary forms, with or without 1372132Ssemenu * modification, are permitted provided that the following conditions 1472132Ssemenu * are met: 1572132Ssemenu * 1. Redistributions of source code must retain the above copyright 1672132Ssemenu * notice, this list of conditions and the following disclaimer. 1772132Ssemenu * 2. Redistributions in binary form must reproduce the above copyright 1872132Ssemenu * notice, this list of conditions and the following disclaimer in the 1972132Ssemenu * documentation and/or other materials provided with the distribution. 2072132Ssemenu * 2172132Ssemenu * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2272132Ssemenu * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2372132Ssemenu * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2472132Ssemenu * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2572132Ssemenu * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2672132Ssemenu * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2772132Ssemenu * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2872132Ssemenu * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2972132Ssemenu * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3072132Ssemenu * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3172132Ssemenu * POSSIBILITY OF SUCH DAMAGE. 3272132Ssemenu */ 3372132Ssemenu 34139749Simp/*- 3572132Ssemenu * Copyright (c) 1997 Manuel Bouyer. All rights reserved. 3672132Ssemenu * 3772132Ssemenu * Redistribution and use in source and binary forms, with or without 3872132Ssemenu * modification, are permitted provided that the following conditions 3972132Ssemenu * are met: 4072132Ssemenu * 1. Redistributions of source code must retain the above copyright 4172132Ssemenu * notice, this list of conditions and the following disclaimer. 4272132Ssemenu * 2. Redistributions in binary form must reproduce the above copyright 4372132Ssemenu * notice, this list of conditions and the following disclaimer in the 4472132Ssemenu * documentation and/or other materials provided with the distribution. 4572132Ssemenu * 4672132Ssemenu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 4772132Ssemenu * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 4872132Ssemenu * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 4972132Ssemenu * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 5072132Ssemenu * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 5172132Ssemenu * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 5272132Ssemenu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 5372132Ssemenu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 5472132Ssemenu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 5572132Ssemenu * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 5672132Ssemenu */ 5772132Ssemenu 58129844Smarius#include <sys/cdefs.h> 59129844Smarius__FBSDID("$FreeBSD$"); 60129844Smarius 6172132Ssemenu/* 6272132Ssemenu * driver for Quality Semiconductor's QS6612 ethernet 10/100 PHY 6372132Ssemenu * datasheet from www.qualitysemi.com 6472132Ssemenu */ 6572132Ssemenu 6672132Ssemenu#include <sys/param.h> 6772132Ssemenu#include <sys/systm.h> 6872132Ssemenu#include <sys/kernel.h> 6972132Ssemenu#include <sys/socket.h> 7072132Ssemenu#include <sys/errno.h> 7172132Ssemenu#include <sys/module.h> 7272132Ssemenu#include <sys/bus.h> 7372132Ssemenu 7472132Ssemenu#include <net/if.h> 7572132Ssemenu#include <net/if_media.h> 7672132Ssemenu 7772132Ssemenu#include <dev/mii/mii.h> 7872132Ssemenu#include <dev/mii/miivar.h> 79109514Sobrien#include "miidevs.h" 8072132Ssemenu 8172132Ssemenu#include <dev/mii/qsphyreg.h> 8272132Ssemenu 8372132Ssemenu#include "miibus_if.h" 8472132Ssemenu 85105135Salfredstatic int qsphy_probe(device_t); 86105135Salfredstatic int qsphy_attach(device_t); 8772132Ssemenu 8872132Ssemenustatic device_method_t qsphy_methods[] = { 8972132Ssemenu /* device interface */ 9072132Ssemenu DEVMETHOD(device_probe, qsphy_probe), 9172132Ssemenu DEVMETHOD(device_attach, qsphy_attach), 9295722Sphk DEVMETHOD(device_detach, mii_phy_detach), 9372132Ssemenu DEVMETHOD(device_shutdown, bus_generic_shutdown), 94227908Smarius DEVMETHOD_END 9572132Ssemenu}; 9672132Ssemenu 9772132Ssemenustatic devclass_t qsphy_devclass; 9872132Ssemenu 9972132Ssemenustatic driver_t qsphy_driver = { 10072132Ssemenu "qsphy", 10172132Ssemenu qsphy_methods, 10272132Ssemenu sizeof(struct mii_softc) 10372132Ssemenu}; 10472132Ssemenu 10572132SsemenuDRIVER_MODULE(qsphy, miibus, qsphy_driver, qsphy_devclass, 0, 0); 10672132Ssemenu 10792739Salfredstatic int qsphy_service(struct mii_softc *, struct mii_data *, int); 10892739Salfredstatic void qsphy_reset(struct mii_softc *); 10992739Salfredstatic void qsphy_status(struct mii_softc *); 11072132Ssemenu 111164827Smariusstatic const struct mii_phydesc qsphys[] = { 112221407Smarius MII_PHY_DESC(xxQUALSEMI, QS6612), 113164827Smarius MII_PHY_END 114164827Smarius}; 115164827Smarius 116221407Smariusstatic const struct mii_phy_funcs qsphy_funcs = { 117221407Smarius qsphy_service, 118221407Smarius qsphy_status, 119221407Smarius qsphy_reset 120221407Smarius}; 121221407Smarius 122105135Salfredstatic int 123150763Simpqsphy_probe(device_t dev) 12472132Ssemenu{ 12572132Ssemenu 126164827Smarius return (mii_phy_dev_probe(dev, qsphys, BUS_PROBE_DEFAULT)); 12772132Ssemenu} 12872132Ssemenu 129105135Salfredstatic int 130150763Simpqsphy_attach(device_t dev) 13172132Ssemenu{ 13272132Ssemenu 133221407Smarius mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &qsphy_funcs, 1); 13472132Ssemenu return (0); 13572132Ssemenu} 13672132Ssemenu 13784145Sjlemonstatic int 138150763Simpqsphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 13972132Ssemenu{ 14072132Ssemenu 14172132Ssemenu switch (cmd) { 14272132Ssemenu case MII_POLLSTAT: 14372132Ssemenu break; 14472132Ssemenu 14572132Ssemenu case MII_MEDIACHG: 14672132Ssemenu /* 14772132Ssemenu * If the interface is not up, don't do anything. 14872132Ssemenu */ 14972132Ssemenu if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 15072132Ssemenu break; 15172132Ssemenu 152164710Smarius mii_phy_setmedia(sc); 15372132Ssemenu break; 15472132Ssemenu 15572132Ssemenu case MII_TICK: 15672132Ssemenu /* 15784145Sjlemon * Is the interface even up? 15872132Ssemenu */ 15984145Sjlemon if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 16072132Ssemenu return (0); 16172132Ssemenu 16272132Ssemenu /* 16395877Ssemenu * This PHY's autonegotiation doesn't need to be kicked. 16472132Ssemenu */ 16572132Ssemenu break; 16672132Ssemenu } 16772132Ssemenu 16872132Ssemenu /* Update the media status. */ 169221407Smarius PHY_STATUS(sc); 17072132Ssemenu 17172132Ssemenu /* Callback if something changed. */ 17284145Sjlemon mii_phy_update(sc, cmd); 17372132Ssemenu return (0); 17472132Ssemenu} 17572132Ssemenu 17684145Sjlemonstatic void 177150763Simpqsphy_status(struct mii_softc *sc) 17872132Ssemenu{ 17972132Ssemenu struct mii_data *mii = sc->mii_pdata; 18072132Ssemenu int bmsr, bmcr, pctl; 18172132Ssemenu 18272132Ssemenu mii->mii_media_status = IFM_AVALID; 18372132Ssemenu mii->mii_media_active = IFM_ETHER; 18472132Ssemenu 18572132Ssemenu bmsr = PHY_READ(sc, MII_BMSR) | 18672132Ssemenu PHY_READ(sc, MII_BMSR); 18772132Ssemenu if (bmsr & BMSR_LINK) 18872132Ssemenu mii->mii_media_status |= IFM_ACTIVE; 18972132Ssemenu 19072132Ssemenu bmcr = PHY_READ(sc, MII_BMCR); 19172132Ssemenu if (bmcr & BMCR_ISO) { 19272132Ssemenu mii->mii_media_active |= IFM_NONE; 19372132Ssemenu mii->mii_media_status = 0; 19472132Ssemenu return; 19572132Ssemenu } 19672132Ssemenu 19772132Ssemenu if (bmcr & BMCR_LOOP) 19872132Ssemenu mii->mii_media_active |= IFM_LOOP; 19972132Ssemenu 20095877Ssemenu pctl = PHY_READ(sc, MII_QSPHY_PCTL); 20195877Ssemenu switch (pctl & PCTL_OPMASK) { 20295877Ssemenu case PCTL_10_T: 203213384Smarius mii->mii_media_active |= IFM_10_T|IFM_HDX; 20495877Ssemenu break; 20595877Ssemenu case PCTL_10_T_FDX: 20695877Ssemenu mii->mii_media_active |= IFM_10_T|IFM_FDX; 20795877Ssemenu break; 20895877Ssemenu case PCTL_100_TX: 209213384Smarius mii->mii_media_active |= IFM_100_TX|IFM_HDX; 21095877Ssemenu break; 21195877Ssemenu case PCTL_100_TX_FDX: 21295877Ssemenu mii->mii_media_active |= IFM_100_TX|IFM_FDX; 21395877Ssemenu break; 21495877Ssemenu case PCTL_100_T4: 215213384Smarius mii->mii_media_active |= IFM_100_T4|IFM_HDX; 21695877Ssemenu break; 21795877Ssemenu case PCTL_AN: 21895877Ssemenu mii->mii_media_active |= IFM_NONE; 21995877Ssemenu break; 22095877Ssemenu default: 22195877Ssemenu /* Erg... this shouldn't happen. */ 22295877Ssemenu mii->mii_media_active |= IFM_NONE; 22395877Ssemenu break; 22495877Ssemenu } 225221407Smarius if ((mii->mii_media_active & IFM_FDX) != 0) 226221407Smarius mii->mii_media_active |= mii_phy_flowstatus(sc); 22772132Ssemenu} 22872132Ssemenu 22984145Sjlemonstatic void 230150763Simpqsphy_reset(struct mii_softc *sc) 23172132Ssemenu{ 23272132Ssemenu 23372132Ssemenu mii_phy_reset(sc); 23472132Ssemenu PHY_WRITE(sc, MII_QSPHY_IMASK, 0); 23572132Ssemenu} 236