xmphy.c revision 267654
112891Swpaul/*- 212891Swpaul * Copyright (c) 2000 312891Swpaul * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. 412891Swpaul * 512891Swpaul * Redistribution and use in source and binary forms, with or without 612891Swpaul * modification, are permitted provided that the following conditions 712891Swpaul * are met: 812891Swpaul * 1. Redistributions of source code must retain the above copyright 912891Swpaul * notice, this list of conditions and the following disclaimer. 1012891Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1112891Swpaul * notice, this list of conditions and the following disclaimer in the 1212891Swpaul * documentation and/or other materials provided with the distribution. 1312891Swpaul * 3. All advertising materials mentioning features or use of this software 1412891Swpaul * must display the following acknowledgement: 1512891Swpaul * This product includes software developed by Bill Paul. 1612891Swpaul * 4. Neither the name of the author nor the names of any co-contributors 1712891Swpaul * may be used to endorse or promote products derived from this software 1812891Swpaul * without specific prior written permission. 1912891Swpaul * 2012891Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 2112891Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2212891Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2312891Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 2412891Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2512891Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2612891Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2712891Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2812891Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2912891Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3012891Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 3112891Swpaul */ 3212891Swpaul 3312891Swpaul#include <sys/cdefs.h> 3430827Scharnier__FBSDID("$FreeBSD: releng/9.3/sys/dev/mii/xmphy.c 229093 2011-12-31 14:12:12Z hselasky $"); 3530827Scharnier 3650479Speter/* 3730827Scharnier * driver for the XaQti XMAC II's internal PHY. This is sort of 3830827Scharnier * like a 10/100 PHY, except the only thing we're really autoselecting 3920818Swpaul * here is full/half duplex. Speed is always 1000mbps. 4012891Swpaul */ 4130827Scharnier 4230827Scharnier#include <sys/param.h> 4312891Swpaul#include <sys/systm.h> 4412891Swpaul#include <sys/kernel.h> 4512891Swpaul#include <sys/module.h> 4612891Swpaul#include <sys/socket.h> 4712891Swpaul#include <sys/bus.h> 4812891Swpaul 4912891Swpaul#include <net/if.h> 5012997Swpaul#include <net/if_media.h> 5112891Swpaul 5212891Swpaul#include <dev/mii/mii.h> 5312891Swpaul#include <dev/mii/miivar.h> 5428042Swpaul#include "miidevs.h" 5528042Swpaul 5628042Swpaul#include <dev/mii/xmphyreg.h> 5728042Swpaul 5828042Swpaul#include "miibus_if.h" 5946186Swpaul 6046186Swpaulstatic int xmphy_probe(device_t); 6146186Swpaulstatic int xmphy_attach(device_t); 6246186Swpaul 6346186Swpaulstatic device_method_t xmphy_methods[] = { 6446186Swpaul /* device interface */ 6546186Swpaul DEVMETHOD(device_probe, xmphy_probe), 6646186Swpaul DEVMETHOD(device_attach, xmphy_attach), 6746186Swpaul DEVMETHOD(device_detach, mii_phy_detach), 6846186Swpaul DEVMETHOD(device_shutdown, bus_generic_shutdown), 6946186Swpaul DEVMETHOD_END 7014262Swpaul}; 7114262Swpaul 7214262Swpaulstatic devclass_t xmphy_devclass; 7314262Swpaul 7412891Swpaulstatic driver_t xmphy_driver = { 7512891Swpaul "xmphy", 7612891Swpaul xmphy_methods, 7712891Swpaul sizeof(struct mii_softc) 7812891Swpaul}; 7912891Swpaul 8019161SwpaulDRIVER_MODULE(xmphy, miibus, xmphy_driver, xmphy_devclass, 0, 0); 8119161Swpaul 8219161Swpaulstatic int xmphy_service(struct mii_softc *, struct mii_data *, int); 8312891Swpaulstatic void xmphy_status(struct mii_softc *); 8419161Swpaulstatic int xmphy_mii_phy_auto(struct mii_softc *); 8512891Swpaul 8612891Swpaulstatic const struct mii_phydesc xmphys[] = { 8712891Swpaul MII_PHY_DESC(xxJATO, BASEX), 8812891Swpaul MII_PHY_DESC(xxXAQTI, XMACII), 8912891Swpaul MII_PHY_END 9012891Swpaul}; 9112891Swpaul 9212891Swpaulstatic const struct mii_phy_funcs xmphy_funcs = { 9312891Swpaul xmphy_service, 9412891Swpaul xmphy_status, 9512891Swpaul mii_phy_reset 9612891Swpaul}; 9719161Swpaul 9819161Swpaulstatic int 9919161Swpaulxmphy_probe(device_t dev) 10012891Swpaul{ 10119161Swpaul 10212891Swpaul return (mii_phy_dev_probe(dev, xmphys, BUS_PROBE_DEFAULT)); 10312891Swpaul} 10412891Swpaul 10512891Swpaulstatic int 10612891Swpaulxmphy_attach(device_t dev) 10712891Swpaul{ 10812891Swpaul struct mii_softc *sc; 10912891Swpaul const char *sep = ""; 11012891Swpaul 11112891Swpaul sc = device_get_softc(dev); 11212891Swpaul 11312891Swpaul mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, 11412891Swpaul &xmphy_funcs, 0); 11512891Swpaul sc->mii_anegticks = MII_ANEGTICKS; 11612891Swpaul 11712891Swpaul PHY_RESET(sc); 11812891Swpaul 11919161Swpaul#define ADD(m, c) ifmedia_add(&sc->mii_pdata->mii_media, (m), (c), NULL) 12019161Swpaul#define PRINT(s) printf("%s%s", sep, s); sep = ", " 12119161Swpaul 12212891Swpaul device_printf(dev, " "); 12319161Swpaul ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, sc->mii_inst), 12412891Swpaul XMPHY_BMCR_FDX); 12512891Swpaul PRINT("1000baseSX"); 12612891Swpaul ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst), 0); 12712891Swpaul PRINT("1000baseSX-FDX"); 12812891Swpaul ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0); 12912891Swpaul PRINT("auto"); 13012891Swpaul 13112891Swpaul printf("\n"); 13212891Swpaul 13312891Swpaul#undef ADD 13412891Swpaul#undef PRINT 13512891Swpaul 13612891Swpaul MIIBUS_MEDIAINIT(sc->mii_dev); 13712891Swpaul return (0); 13812891Swpaul} 13914304Swpaul 14014304Swpaulstatic int 14119161Swpaulxmphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 14219161Swpaul{ 14319161Swpaul struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 14419161Swpaul int reg; 14512891Swpaul 14619161Swpaul switch (cmd) { 14712891Swpaul case MII_POLLSTAT: 14812891Swpaul break; 14912891Swpaul 15012891Swpaul case MII_MEDIACHG: 15112891Swpaul /* 15212891Swpaul * If the interface is not up, don't do anything. 15312891Swpaul */ 15412891Swpaul if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 15512891Swpaul break; 15633250Swpaul 15720818Swpaul switch (IFM_SUBTYPE(ife->ifm_media)) { 15820818Swpaul case IFM_AUTO: 15912891Swpaul#ifdef foo 16012891Swpaul /* 16120818Swpaul * If we're already in auto mode, just return. 16220818Swpaul */ 16312891Swpaul if (PHY_READ(sc, XMPHY_MII_BMCR) & XMPHY_BMCR_AUTOEN) 16412891Swpaul return (0); 16512891Swpaul#endif 16612891Swpaul (void)xmphy_mii_phy_auto(sc); 16719161Swpaul break; 16819161Swpaul case IFM_1000_SX: 16919161Swpaul PHY_RESET(sc); 17019161Swpaul if ((ife->ifm_media & IFM_FDX) != 0) { 17119161Swpaul PHY_WRITE(sc, XMPHY_MII_ANAR, XMPHY_ANAR_FDX); 17212891Swpaul PHY_WRITE(sc, XMPHY_MII_BMCR, XMPHY_BMCR_FDX); 17319161Swpaul } else { 17427589Swpaul PHY_WRITE(sc, XMPHY_MII_ANAR, XMPHY_ANAR_HDX); 17520818Swpaul PHY_WRITE(sc, XMPHY_MII_BMCR, 0); 17620818Swpaul } 17727589Swpaul break; 17827589Swpaul default: 17912891Swpaul return (EINVAL); 18012891Swpaul } 18130827Scharnier break; 18212891Swpaul 18312891Swpaul case MII_TICK: 18427589Swpaul /* 18512891Swpaul * Is the interface even up? 18627589Swpaul */ 18712891Swpaul if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 18820818Swpaul return (0); 18920818Swpaul 19012891Swpaul /* 19112891Swpaul * Only used for autonegotiation. 19212891Swpaul */ 19312891Swpaul if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 19412891Swpaul break; 19512891Swpaul 19612891Swpaul /* 19712891Swpaul * Check to see if we have link. If we do, we don't 19812891Swpaul * need to restart the autonegotiation process. Read 19912891Swpaul * the BMSR twice in case it's latched. 20014304Swpaul */ 20114304Swpaul reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 20219161Swpaul if (reg & BMSR_LINK) 20319161Swpaul break; 20419161Swpaul 20519161Swpaul /* Only retry autonegotiation every mii_anegticks seconds. */ 20612891Swpaul if (sc->mii_ticks <= sc->mii_anegticks) 20719161Swpaul break; 20812891Swpaul 20912891Swpaul sc->mii_ticks = 0; 21012891Swpaul 21112891Swpaul PHY_RESET(sc); 21212891Swpaul xmphy_mii_phy_auto(sc); 21312891Swpaul return (0); 21412891Swpaul } 21512891Swpaul 21612891Swpaul /* Update the media status. */ 21733250Swpaul xmphy_status(sc); 21812891Swpaul 21912891Swpaul /* Callback if something changed. */ 22012891Swpaul mii_phy_update(sc, cmd); 22112891Swpaul return (0); 22220818Swpaul} 22312891Swpaul 22412891Swpaulstatic void 22512891Swpaulxmphy_status(struct mii_softc *sc) 22612891Swpaul{ 22712891Swpaul struct mii_data *mii = sc->mii_pdata; 22812891Swpaul int bmsr, bmcr, anlpar; 22912891Swpaul 23012891Swpaul mii->mii_media_status = IFM_AVALID; 23112891Swpaul mii->mii_media_active = IFM_ETHER; 23214304Swpaul 23314304Swpaul bmsr = PHY_READ(sc, XMPHY_MII_BMSR) | 23415426Swpaul PHY_READ(sc, XMPHY_MII_BMSR); 23519161Swpaul if (bmsr & XMPHY_BMSR_LINK) 23619161Swpaul mii->mii_media_status |= IFM_ACTIVE; 23719161Swpaul 23812891Swpaul /* Do dummy read of extended status register. */ 23919161Swpaul bmcr = PHY_READ(sc, XMPHY_MII_EXTSTS); 24012891Swpaul 24112891Swpaul bmcr = PHY_READ(sc, XMPHY_MII_BMCR); 24212891Swpaul 24312891Swpaul if (bmcr & XMPHY_BMCR_LOOP) 24412891Swpaul mii->mii_media_active |= IFM_LOOP; 24512891Swpaul 24612891Swpaul if (bmcr & XMPHY_BMCR_AUTOEN) { 24712891Swpaul if ((bmsr & XMPHY_BMSR_ACOMP) == 0) { 24812891Swpaul if (bmsr & XMPHY_BMSR_LINK) { 24920818Swpaul mii->mii_media_active |= IFM_1000_SX|IFM_HDX; 25012891Swpaul return; 25112891Swpaul } 25212891Swpaul /* Erg, still trying, I guess... */ 25312891Swpaul mii->mii_media_active |= IFM_NONE; 25420818Swpaul return; 25520818Swpaul } 25612891Swpaul 25720818Swpaul mii->mii_media_active |= IFM_1000_SX; 25820818Swpaul anlpar = PHY_READ(sc, XMPHY_MII_ANAR) & 25912891Swpaul PHY_READ(sc, XMPHY_MII_ANLPAR); 26012891Swpaul if (anlpar & XMPHY_ANLPAR_FDX) 26112891Swpaul mii->mii_media_active |= IFM_FDX; 26212997Swpaul else 26312997Swpaul mii->mii_media_active |= IFM_HDX; 26412997Swpaul return; 26512997Swpaul } 26612997Swpaul 26712997Swpaul mii->mii_media_active |= IFM_1000_SX; 26812997Swpaul if (bmcr & XMPHY_BMCR_FDX) 26912997Swpaul mii->mii_media_active |= IFM_FDX; 27012997Swpaul else 27112997Swpaul mii->mii_media_active |= IFM_HDX; 27212997Swpaul} 27313375Swpaul 27412997Swpaulstatic int 27513375Swpaulxmphy_mii_phy_auto(struct mii_softc *mii) 27612997Swpaul{ 27712997Swpaul int anar = 0; 27812997Swpaul 27919131Swpaul anar = PHY_READ(mii, XMPHY_MII_ANAR); 28019131Swpaul anar |= XMPHY_ANAR_FDX|XMPHY_ANAR_HDX; 28119161Swpaul PHY_WRITE(mii, XMPHY_MII_ANAR, anar); 28219131Swpaul DELAY(1000); 28319131Swpaul PHY_WRITE(mii, XMPHY_MII_BMCR, 28412997Swpaul XMPHY_BMCR_AUTOEN | XMPHY_BMCR_STARTNEG); 28512997Swpaul 28612997Swpaul return (EJUSTRETURN); 28712997Swpaul} 28813375Swpaul