dcphy.c revision 74914
154134Swpaul/* 254134Swpaul * Copyright (c) 1997, 1998, 1999 354134Swpaul * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. 454134Swpaul * 554134Swpaul * Redistribution and use in source and binary forms, with or without 654134Swpaul * modification, are permitted provided that the following conditions 754134Swpaul * are met: 854134Swpaul * 1. Redistributions of source code must retain the above copyright 954134Swpaul * notice, this list of conditions and the following disclaimer. 1054134Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1154134Swpaul * notice, this list of conditions and the following disclaimer in the 1254134Swpaul * documentation and/or other materials provided with the distribution. 1354134Swpaul * 3. All advertising materials mentioning features or use of this software 1454134Swpaul * must display the following acknowledgement: 1554134Swpaul * This product includes software developed by Bill Paul. 1654134Swpaul * 4. Neither the name of the author nor the names of any co-contributors 1754134Swpaul * may be used to endorse or promote products derived from this software 1854134Swpaul * without specific prior written permission. 1954134Swpaul * 2054134Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 2154134Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2254134Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2354134Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 2454134Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2554134Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2654134Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2754134Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2854134Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2954134Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3054134Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 3154134Swpaul * 3254134Swpaul * $FreeBSD: head/sys/dev/dc/dcphy.c 74914 2001-03-28 09:17:56Z jhb $ 3354134Swpaul */ 3454134Swpaul 3554134Swpaul/* 3654134Swpaul * Pseudo-driver for internal NWAY support on DEC 21143 and workalike 3754134Swpaul * controllers. Technically we're abusing the miibus code to handle 3854134Swpaul * media selection and NWAY support here since there is no MII 3954134Swpaul * interface. However the logical operations are roughly the same, 4054134Swpaul * and the alternative is to create a fake MII interface in the driver, 4154134Swpaul * which is harder to do. 4254134Swpaul */ 4354134Swpaul 4454134Swpaul#include <sys/param.h> 4554134Swpaul#include <sys/systm.h> 4654134Swpaul#include <sys/kernel.h> 4754134Swpaul#include <sys/socket.h> 4854134Swpaul#include <sys/errno.h> 4974914Sjhb#include <sys/lock.h> 5054134Swpaul#include <sys/module.h> 5167365Sjhb#include <sys/mutex.h> 5254134Swpaul#include <sys/bus.h> 5354134Swpaul 5454134Swpaul#include <net/if.h> 5554134Swpaul#include <net/if_arp.h> 5654134Swpaul#include <net/if_media.h> 5754134Swpaul 5854134Swpaul#include <dev/mii/mii.h> 5954134Swpaul#include <dev/mii/miivar.h> 6054134Swpaul#include <dev/mii/miidevs.h> 6154134Swpaul 6254134Swpaul#include <machine/bus_pio.h> 6354134Swpaul#include <machine/bus_memio.h> 6454134Swpaul#include <machine/bus.h> 6554134Swpaul#include <machine/resource.h> 6654134Swpaul#include <sys/bus.h> 6754134Swpaul 6854134Swpaul#include <pci/pcivar.h> 6954134Swpaul 7054134Swpaul#include <pci/if_dcreg.h> 7154134Swpaul 7254134Swpaul#include "miibus_if.h" 7354134Swpaul 7454134Swpaul#if !defined(lint) 7554134Swpaulstatic const char rcsid[] = 7654134Swpaul "$FreeBSD: head/sys/dev/dc/dcphy.c 74914 2001-03-28 09:17:56Z jhb $"; 7754134Swpaul#endif 7854134Swpaul 7954134Swpaul#define DC_SETBIT(sc, reg, x) \ 8054134Swpaul CSR_WRITE_4(sc, reg, \ 8154134Swpaul CSR_READ_4(sc, reg) | x) 8254134Swpaul 8354134Swpaul#define DC_CLRBIT(sc, reg, x) \ 8454134Swpaul CSR_WRITE_4(sc, reg, \ 8554134Swpaul CSR_READ_4(sc, reg) & ~x) 8654134Swpaul 8754134Swpaul#define MIIF_AUTOTIMEOUT 0x0004 8854134Swpaul 8954577Swpaul/* 9054577Swpaul * This is the subsystem ID for the built-in 21143 ethernet 9154577Swpaul * in several Compaq Presario systems. Apparently these are 9254577Swpaul * 10Mbps only, so we need to treat them specially. 9354577Swpaul */ 9454577Swpaul#define COMPAQ_PRESARIO_ID 0xb0bb0e11 9554577Swpaul 9654134Swpaulstatic int dcphy_probe __P((device_t)); 9754134Swpaulstatic int dcphy_attach __P((device_t)); 9854134Swpaulstatic int dcphy_detach __P((device_t)); 9954134Swpaul 10054134Swpaulstatic device_method_t dcphy_methods[] = { 10154134Swpaul /* device interface */ 10254134Swpaul DEVMETHOD(device_probe, dcphy_probe), 10354134Swpaul DEVMETHOD(device_attach, dcphy_attach), 10454134Swpaul DEVMETHOD(device_detach, dcphy_detach), 10554134Swpaul DEVMETHOD(device_shutdown, bus_generic_shutdown), 10654134Swpaul { 0, 0 } 10754134Swpaul}; 10854134Swpaul 10954134Swpaulstatic devclass_t dcphy_devclass; 11054134Swpaul 11154134Swpaulstatic driver_t dcphy_driver = { 11254134Swpaul "dcphy", 11354134Swpaul dcphy_methods, 11454134Swpaul sizeof(struct mii_softc) 11554134Swpaul}; 11654134Swpaul 11754134SwpaulDRIVER_MODULE(dcphy, miibus, dcphy_driver, dcphy_devclass, 0, 0); 11854134Swpaul 11954134Swpaulint dcphy_service __P((struct mii_softc *, struct mii_data *, int)); 12054134Swpaulvoid dcphy_status __P((struct mii_softc *)); 12154134Swpaulstatic int dcphy_auto __P((struct mii_softc *, int)); 12254134Swpaulstatic void dcphy_reset __P((struct mii_softc *)); 12354134Swpaul 12454134Swpaulstatic int dcphy_probe(dev) 12554134Swpaul device_t dev; 12654134Swpaul{ 12754134Swpaul struct mii_attach_args *ma; 12854134Swpaul 12954134Swpaul ma = device_get_ivars(dev); 13054134Swpaul 13154134Swpaul /* 13254134Swpaul * The dc driver will report the 21143 vendor and device 13354134Swpaul * ID to let us know that it wants us to attach. 13454134Swpaul */ 13554134Swpaul if (ma->mii_id1 != DC_VENDORID_DEC || 13654134Swpaul ma->mii_id2 != DC_DEVICEID_21143) 13754134Swpaul return(ENXIO); 13854134Swpaul 13954134Swpaul device_set_desc(dev, "Intel 21143 NWAY media interface"); 14054134Swpaul 14154134Swpaul return (0); 14254134Swpaul} 14354134Swpaul 14454134Swpaulstatic int dcphy_attach(dev) 14554134Swpaul device_t dev; 14654134Swpaul{ 14754134Swpaul struct mii_softc *sc; 14854134Swpaul struct mii_attach_args *ma; 14954134Swpaul struct mii_data *mii; 15054134Swpaul struct dc_softc *dc_sc; 15154134Swpaul 15254134Swpaul sc = device_get_softc(dev); 15354134Swpaul ma = device_get_ivars(dev); 15454134Swpaul sc->mii_dev = device_get_parent(dev); 15554134Swpaul mii = device_get_softc(sc->mii_dev); 15654134Swpaul LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 15754134Swpaul 15854134Swpaul sc->mii_inst = mii->mii_instance; 15954134Swpaul sc->mii_phy = ma->mii_phyno; 16054134Swpaul sc->mii_service = dcphy_service; 16154134Swpaul sc->mii_pdata = mii; 16254134Swpaul 16354134Swpaul sc->mii_flags |= MIIF_NOISOLATE; 16454134Swpaul mii->mii_instance++; 16554134Swpaul 16654134Swpaul#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) 16754134Swpaul 16854134Swpaul ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), 16954134Swpaul BMCR_ISO); 17054134Swpaul 17154134Swpaul /*dcphy_reset(sc);*/ 17254134Swpaul dc_sc = mii->mii_ifp->if_softc; 17354134Swpaul CSR_WRITE_4(dc_sc, DC_10BTSTAT, 0); 17454134Swpaul CSR_WRITE_4(dc_sc, DC_10BTCTRL, 0); 17554134Swpaul 17654134Swpaul switch(pci_read_config(device_get_parent(sc->mii_dev), 17754134Swpaul DC_PCI_CSID, 4)) { 17854577Swpaul case COMPAQ_PRESARIO_ID: 17954134Swpaul /* Example of how to only allow 10Mbps modes. */ 18054577Swpaul sc->mii_capabilities = BMSR_ANEG|BMSR_10TFDX|BMSR_10THDX; 18154134Swpaul break; 18254134Swpaul default: 18366681Swpaul if (dc_sc->dc_pmode == DC_PMODE_SIA) { 18466681Swpaul sc->mii_capabilities = 18566681Swpaul BMSR_ANEG|BMSR_10TFDX|BMSR_10THDX; 18666681Swpaul } else { 18766681Swpaul ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, 18866681Swpaul sc->mii_inst), BMCR_LOOP|BMCR_S100); 18954577Swpaul 19066681Swpaul sc->mii_capabilities = 19166681Swpaul BMSR_ANEG|BMSR_100TXFDX|BMSR_100TXHDX| 19266681Swpaul BMSR_10TFDX|BMSR_10THDX; 19366681Swpaul } 19454134Swpaul break; 19554134Swpaul } 19654134Swpaul 19754134Swpaul sc->mii_capabilities &= ma->mii_capmask; 19854134Swpaul device_printf(dev, " "); 19954134Swpaul if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0) 20054134Swpaul printf("no media present"); 20154134Swpaul else 20254134Swpaul mii_add_media(mii, sc->mii_capabilities, sc->mii_inst); 20354134Swpaul printf("\n"); 20454134Swpaul#undef ADD 20554134Swpaul 20654134Swpaul MIIBUS_MEDIAINIT(sc->mii_dev); 20754134Swpaul return(0); 20854134Swpaul} 20954134Swpaul 21054134Swpaulstatic int dcphy_detach(dev) 21154134Swpaul device_t dev; 21254134Swpaul{ 21354134Swpaul struct mii_softc *sc; 21454134Swpaul struct mii_data *mii; 21554134Swpaul 21654134Swpaul sc = device_get_softc(dev); 21754134Swpaul mii = device_get_softc(device_get_parent(dev)); 21854134Swpaul sc->mii_dev = NULL; 21954134Swpaul LIST_REMOVE(sc, mii_list); 22054134Swpaul 22154134Swpaul return(0); 22254134Swpaul} 22354134Swpaul 22454134Swpaulint 22554134Swpauldcphy_service(sc, mii, cmd) 22654134Swpaul struct mii_softc *sc; 22754134Swpaul struct mii_data *mii; 22854134Swpaul int cmd; 22954134Swpaul{ 23054134Swpaul struct dc_softc *dc_sc; 23154134Swpaul struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 23254134Swpaul int reg; 23354134Swpaul u_int32_t mode; 23454134Swpaul 23554134Swpaul dc_sc = mii->mii_ifp->if_softc; 23654134Swpaul 23754134Swpaul switch (cmd) { 23854134Swpaul case MII_POLLSTAT: 23954134Swpaul /* 24054134Swpaul * If we're not polling our PHY instance, just return. 24154134Swpaul */ 24254134Swpaul if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 24354134Swpaul return (0); 24454134Swpaul } 24554134Swpaul break; 24654134Swpaul 24754134Swpaul case MII_MEDIACHG: 24854134Swpaul /* 24954134Swpaul * If the media indicates a different PHY instance, 25054134Swpaul * isolate ourselves. 25154134Swpaul */ 25254134Swpaul if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 25354134Swpaul return (0); 25454134Swpaul } 25554134Swpaul 25654134Swpaul /* 25754134Swpaul * If the interface is not up, don't do anything. 25854134Swpaul */ 25954134Swpaul if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 26054134Swpaul break; 26154134Swpaul 26254134Swpaul sc->mii_flags = 0; 26354134Swpaul mii->mii_media_active = IFM_NONE; 26454134Swpaul mode = CSR_READ_4(dc_sc, DC_NETCFG); 26554134Swpaul mode &= ~(DC_NETCFG_FULLDUPLEX|DC_NETCFG_PORTSEL| 26654134Swpaul DC_NETCFG_PCS|DC_NETCFG_SCRAMBLER|DC_NETCFG_SPEEDSEL); 26754134Swpaul 26854134Swpaul switch (IFM_SUBTYPE(ife->ifm_media)) { 26954134Swpaul case IFM_AUTO: 27054134Swpaul /*dcphy_reset(sc);*/ 27161110Swpaul sc->mii_flags &= ~MIIF_DOINGAUTO; 27254134Swpaul (void) dcphy_auto(sc, 0); 27354134Swpaul break; 27454134Swpaul case IFM_100_T4: 27554134Swpaul /* 27654134Swpaul * XXX Not supported as a manual setting right now. 27754134Swpaul */ 27854134Swpaul return (EINVAL); 27954134Swpaul case IFM_100_TX: 28054134Swpaul dcphy_reset(sc); 28154134Swpaul DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL); 28254134Swpaul mode |= DC_NETCFG_PORTSEL|DC_NETCFG_PCS| 28354134Swpaul DC_NETCFG_SCRAMBLER; 28454134Swpaul if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) 28554134Swpaul mode |= DC_NETCFG_FULLDUPLEX; 28654134Swpaul else 28754134Swpaul mode &= ~DC_NETCFG_FULLDUPLEX; 28854134Swpaul CSR_WRITE_4(dc_sc, DC_NETCFG, mode); 28954134Swpaul break; 29054134Swpaul case IFM_10_T: 29154134Swpaul DC_CLRBIT(dc_sc, DC_SIARESET, DC_SIA_RESET); 29254134Swpaul DC_CLRBIT(dc_sc, DC_10BTCTRL, 0xFFFF); 29354134Swpaul if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) 29454134Swpaul DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3D); 29554134Swpaul else 29654134Swpaul DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3F); 29754134Swpaul DC_SETBIT(dc_sc, DC_SIARESET, DC_SIA_RESET); 29854134Swpaul DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL); 29954134Swpaul mode &= ~DC_NETCFG_PORTSEL; 30054134Swpaul mode |= DC_NETCFG_SPEEDSEL; 30154134Swpaul if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) 30254134Swpaul mode |= DC_NETCFG_FULLDUPLEX; 30354134Swpaul else 30454134Swpaul mode &= ~DC_NETCFG_FULLDUPLEX; 30554134Swpaul CSR_WRITE_4(dc_sc, DC_NETCFG, mode); 30654134Swpaul break; 30754134Swpaul default: 30854134Swpaul return(EINVAL); 30954134Swpaul break; 31054134Swpaul } 31154134Swpaul break; 31254134Swpaul 31354134Swpaul case MII_TICK: 31454134Swpaul /* 31554134Swpaul * If we're not currently selected, just return. 31654134Swpaul */ 31754134Swpaul if (IFM_INST(ife->ifm_media) != sc->mii_inst) 31854134Swpaul return (0); 31954134Swpaul 32054134Swpaul /* 32154134Swpaul * Only used for autonegotiation. 32254134Swpaul */ 32354134Swpaul if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 32454134Swpaul return (0); 32554134Swpaul 32654134Swpaul /* 32754134Swpaul * Is the interface even up? 32854134Swpaul */ 32954134Swpaul if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 33054134Swpaul return (0); 33154134Swpaul 33254134Swpaul reg = CSR_READ_4(dc_sc, DC_10BTSTAT) & 33354134Swpaul (DC_TSTAT_LS10|DC_TSTAT_LS100); 33454134Swpaul 33561110Swpaul if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100)) 33661110Swpaul return(0); 33754134Swpaul 33861110Swpaul /* 33961110Swpaul * Only retry autonegotiation every 5 seconds. 34061110Swpaul */ 34161110Swpaul if (++sc->mii_ticks != 50) 34261110Swpaul return (0); 34361110Swpaul 34454134Swpaul sc->mii_ticks = 0; 34561110Swpaul /*if (DC_IS_INTEL(dc_sc))*/ 34661110Swpaul sc->mii_flags &= ~MIIF_DOINGAUTO; 34754134Swpaul dcphy_auto(sc, 0); 34854134Swpaul 34954134Swpaul break; 35054134Swpaul } 35154134Swpaul 35254134Swpaul /* Update the media status. */ 35354134Swpaul dcphy_status(sc); 35454134Swpaul 35554134Swpaul /* Callback if something changed. */ 35654134Swpaul if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) { 35754134Swpaul MIIBUS_STATCHG(sc->mii_dev); 35854134Swpaul sc->mii_active = mii->mii_media_active; 35954134Swpaul } 36054134Swpaul return (0); 36154134Swpaul} 36254134Swpaul 36354134Swpaulvoid 36454134Swpauldcphy_status(sc) 36554134Swpaul struct mii_softc *sc; 36654134Swpaul{ 36754134Swpaul struct mii_data *mii = sc->mii_pdata; 36861110Swpaul int reg, anlpar, tstat = 0; 36954134Swpaul struct dc_softc *dc_sc; 37054134Swpaul 37154134Swpaul dc_sc = mii->mii_ifp->if_softc; 37254134Swpaul 37354134Swpaul mii->mii_media_status = IFM_AVALID; 37454134Swpaul mii->mii_media_active = IFM_ETHER; 37554134Swpaul 37661290Swpaul if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 37761290Swpaul return; 37861290Swpaul 37954134Swpaul reg = CSR_READ_4(dc_sc, DC_10BTSTAT) & 38061110Swpaul (DC_TSTAT_LS10|DC_TSTAT_LS100); 38154134Swpaul 38254134Swpaul if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100)) 38354134Swpaul mii->mii_media_status |= IFM_ACTIVE; 38454134Swpaul 38561110Swpaul if (CSR_READ_4(dc_sc, DC_10BTCTRL) & DC_TCTL_AUTONEGENBL) { 38654134Swpaul /* Erg, still trying, I guess... */ 38761110Swpaul tstat = CSR_READ_4(dc_sc, DC_10BTSTAT); 38861110Swpaul if ((tstat & DC_TSTAT_ANEGSTAT) != DC_ASTAT_AUTONEGCMP) { 38961110Swpaul if ((DC_IS_MACRONIX(dc_sc) || DC_IS_PNICII(dc_sc)) && 39061110Swpaul (tstat & DC_TSTAT_ANEGSTAT) == DC_ASTAT_DISABLE) 39161110Swpaul goto skip; 39254134Swpaul mii->mii_media_active |= IFM_NONE; 39354134Swpaul return; 39454134Swpaul } 39554134Swpaul 39661110Swpaul if (tstat & DC_TSTAT_LP_CAN_NWAY) { 39761110Swpaul anlpar = tstat >> 16; 39854577Swpaul if (anlpar & ANLPAR_T4 && 39954577Swpaul sc->mii_capabilities & BMSR_100TXHDX) 40054134Swpaul mii->mii_media_active |= IFM_100_T4; 40154577Swpaul else if (anlpar & ANLPAR_TX_FD && 40261110Swpaul sc->mii_capabilities & BMSR_100TXFDX) 40354134Swpaul mii->mii_media_active |= IFM_100_TX|IFM_FDX; 40454577Swpaul else if (anlpar & ANLPAR_TX && 40554577Swpaul sc->mii_capabilities & BMSR_100TXHDX) 40654134Swpaul mii->mii_media_active |= IFM_100_TX; 40754134Swpaul else if (anlpar & ANLPAR_10_FD) 40854134Swpaul mii->mii_media_active |= IFM_10_T|IFM_FDX; 40954134Swpaul else if (anlpar & ANLPAR_10) 41054134Swpaul mii->mii_media_active |= IFM_10_T; 41154134Swpaul else 41254134Swpaul mii->mii_media_active |= IFM_NONE; 41354134Swpaul if (DC_IS_INTEL(dc_sc)) 41454134Swpaul DC_CLRBIT(dc_sc, DC_10BTCTRL, 41554134Swpaul DC_TCTL_AUTONEGENBL); 41654134Swpaul return; 41754134Swpaul } 41854134Swpaul /* 41954134Swpaul * If the other side doesn't support NWAY, then the 42054134Swpaul * best we can do is determine if we have a 10Mbps or 42154134Swpaul * 100Mbps link. There's no way to know if the link 42254134Swpaul * is full or half duplex, so we default to half duplex 42354134Swpaul * and hope that the user is clever enough to manually 42454134Swpaul * change the media settings if we're wrong. 42554134Swpaul */ 42654134Swpaul if (!(reg & DC_TSTAT_LS100)) 42754134Swpaul mii->mii_media_active |= IFM_100_TX; 42854134Swpaul else if (!(reg & DC_TSTAT_LS10)) 42954134Swpaul mii->mii_media_active |= IFM_10_T; 43054134Swpaul else 43154134Swpaul mii->mii_media_active |= IFM_NONE; 43254134Swpaul if (DC_IS_INTEL(dc_sc)) 43354134Swpaul DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL); 43454134Swpaul return; 43554134Swpaul } 43654134Swpaul 43761110Swpaulskip: 43866681Swpaul 43966681Swpaul if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_SPEEDSEL) 44066681Swpaul mii->mii_media_active |= IFM_10_T; 44166681Swpaul else 44254134Swpaul mii->mii_media_active |= IFM_100_TX; 44354134Swpaul if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_FULLDUPLEX) 44454134Swpaul mii->mii_media_active |= IFM_FDX; 44554134Swpaul 44654134Swpaul return; 44754134Swpaul} 44854134Swpaul 44954134Swpaulstatic int 45054134Swpauldcphy_auto(mii, waitfor) 45154134Swpaul struct mii_softc *mii; 45254134Swpaul int waitfor; 45354134Swpaul{ 45454134Swpaul int i; 45554134Swpaul struct dc_softc *sc; 45654134Swpaul 45754134Swpaul sc = mii->mii_pdata->mii_ifp->if_softc; 45854134Swpaul 45954134Swpaul if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) { 46054134Swpaul DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL); 46154134Swpaul DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_FULLDUPLEX); 46254134Swpaul DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET); 46354577Swpaul if (mii->mii_capabilities & BMSR_100TXHDX) 46454577Swpaul CSR_WRITE_4(sc, DC_10BTCTRL, 0x3FFFF); 46554577Swpaul else 46654577Swpaul CSR_WRITE_4(sc, DC_10BTCTRL, 0xFFFF); 46754134Swpaul DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET); 46854134Swpaul DC_SETBIT(sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL); 46954134Swpaul DC_SETBIT(sc, DC_10BTSTAT, DC_ASTAT_TXDISABLE); 47054134Swpaul } 47154134Swpaul 47254134Swpaul if (waitfor) { 47354134Swpaul /* Wait 500ms for it to complete. */ 47454134Swpaul for (i = 0; i < 500; i++) { 47554134Swpaul if ((CSR_READ_4(sc, DC_10BTSTAT) & DC_TSTAT_ANEGSTAT) 47654134Swpaul == DC_ASTAT_AUTONEGCMP) 47754134Swpaul return(0); 47854134Swpaul DELAY(1000); 47954134Swpaul } 48054134Swpaul /* 48154134Swpaul * Don't need to worry about clearing MIIF_DOINGAUTO. 48254134Swpaul * If that's set, a timeout is pending, and it will 48354134Swpaul * clear the flag. 48454134Swpaul */ 48554134Swpaul return(EIO); 48654134Swpaul } 48754134Swpaul 48854134Swpaul /* 48954134Swpaul * Just let it finish asynchronously. This is for the benefit of 49054134Swpaul * the tick handler driving autonegotiation. Don't want 500ms 49154134Swpaul * delays all the time while the system is running! 49254134Swpaul */ 49354134Swpaul if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) 49454134Swpaul mii->mii_flags |= MIIF_DOINGAUTO; 49554134Swpaul 49654134Swpaul return(EJUSTRETURN); 49754134Swpaul} 49854134Swpaul 49954134Swpaulstatic void 50054134Swpauldcphy_reset(mii) 50154134Swpaul struct mii_softc *mii; 50254134Swpaul{ 50354134Swpaul struct dc_softc *sc; 50454134Swpaul 50554134Swpaul sc = mii->mii_pdata->mii_ifp->if_softc; 50654134Swpaul 50754134Swpaul DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET); 50854134Swpaul DELAY(1000); 50954134Swpaul DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET); 51054134Swpaul 51154134Swpaul return; 51254134Swpaul} 51354134Swpaul 514