brgphy.c revision 160078
1139749Simp/*- 259477Swpaul * Copyright (c) 2000 359477Swpaul * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. 459477Swpaul * 559477Swpaul * Redistribution and use in source and binary forms, with or without 659477Swpaul * modification, are permitted provided that the following conditions 759477Swpaul * are met: 859477Swpaul * 1. Redistributions of source code must retain the above copyright 959477Swpaul * notice, this list of conditions and the following disclaimer. 1059477Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1159477Swpaul * notice, this list of conditions and the following disclaimer in the 1259477Swpaul * documentation and/or other materials provided with the distribution. 1359477Swpaul * 3. All advertising materials mentioning features or use of this software 1459477Swpaul * must display the following acknowledgement: 1559477Swpaul * This product includes software developed by Bill Paul. 1659477Swpaul * 4. Neither the name of the author nor the names of any co-contributors 1759477Swpaul * may be used to endorse or promote products derived from this software 1859477Swpaul * without specific prior written permission. 1959477Swpaul * 2059477Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 2159477Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2259477Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2359477Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 2459477Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2559477Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2659477Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2759477Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2859477Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2959477Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3059477Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 3159477Swpaul */ 3259477Swpaul 33119418Sobrien#include <sys/cdefs.h> 34119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/mii/brgphy.c 160078 2006-07-03 08:01:27Z yongari $"); 35119418Sobrien 3659477Swpaul/* 3759477Swpaul * Driver for the Broadcom BCR5400 1000baseTX PHY. Speed is always 3859477Swpaul * 1000mbps; all we need to negotiate here is full or half duplex. 3959477Swpaul */ 4059477Swpaul 4159477Swpaul#include <sys/param.h> 4259477Swpaul#include <sys/systm.h> 4359477Swpaul#include <sys/kernel.h> 44129876Sphk#include <sys/module.h> 4559477Swpaul#include <sys/socket.h> 4659477Swpaul#include <sys/bus.h> 4759477Swpaul 4859477Swpaul 4959477Swpaul#include <net/if.h> 50157642Sps#include <net/ethernet.h> 5159477Swpaul#include <net/if_media.h> 5259477Swpaul 5359477Swpaul#include <dev/mii/mii.h> 5459477Swpaul#include <dev/mii/miivar.h> 55109514Sobrien#include "miidevs.h" 5659477Swpaul 5759477Swpaul#include <dev/mii/brgphyreg.h> 58117659Swpaul#include <net/if_arp.h> 59117659Swpaul#include <machine/bus.h> 60117659Swpaul#include <dev/bge/if_bgereg.h> 61157642Sps#include <dev/bce/if_bcereg.h> 6259477Swpaul 63119285Simp#include <dev/pci/pcireg.h> 64119285Simp#include <dev/pci/pcivar.h> 65118814Swpaul 6659477Swpaul#include "miibus_if.h" 6759477Swpaul 68105135Salfredstatic int brgphy_probe(device_t); 69105135Salfredstatic int brgphy_attach(device_t); 7059477Swpaul 7159477Swpaulstatic device_method_t brgphy_methods[] = { 7259477Swpaul /* device interface */ 7359477Swpaul DEVMETHOD(device_probe, brgphy_probe), 7459477Swpaul DEVMETHOD(device_attach, brgphy_attach), 7595722Sphk DEVMETHOD(device_detach, mii_phy_detach), 7659477Swpaul DEVMETHOD(device_shutdown, bus_generic_shutdown), 7759477Swpaul { 0, 0 } 7859477Swpaul}; 7959477Swpaul 8059477Swpaulstatic devclass_t brgphy_devclass; 8159477Swpaul 8259477Swpaulstatic driver_t brgphy_driver = { 8359477Swpaul "brgphy", 8459477Swpaul brgphy_methods, 8559477Swpaul sizeof(struct mii_softc) 8659477Swpaul}; 8759477Swpaul 8859477SwpaulDRIVER_MODULE(brgphy, miibus, brgphy_driver, brgphy_devclass, 0, 0); 8959477Swpaul 9084145Sjlemonstatic int brgphy_service(struct mii_softc *, struct mii_data *, int); 9184145Sjlemonstatic void brgphy_status(struct mii_softc *); 9296026Sphkstatic int brgphy_mii_phy_auto(struct mii_softc *); 93114590Spsstatic void brgphy_reset(struct mii_softc *); 94114590Spsstatic void brgphy_loop(struct mii_softc *); 95114590Spsstatic void bcm5401_load_dspcode(struct mii_softc *); 96114590Spsstatic void bcm5411_load_dspcode(struct mii_softc *); 97114590Spsstatic void bcm5703_load_dspcode(struct mii_softc *); 98135772Spsstatic void bcm5750_load_dspcode(struct mii_softc *); 99114590Spsstatic int brgphy_mii_model; 10059477Swpaul 101160078Syongaristatic const struct mii_phydesc brgphys[] = { 102160078Syongari MII_PHY_DESC(xxBROADCOM, BCM5400), 103160078Syongari MII_PHY_DESC(xxBROADCOM, BCM5401), 104160078Syongari MII_PHY_DESC(xxBROADCOM, BCM5411), 105160078Syongari MII_PHY_DESC(xxBROADCOM, BCM5701), 106160078Syongari MII_PHY_DESC(xxBROADCOM, BCM5703), 107160078Syongari MII_PHY_DESC(xxBROADCOM, BCM5704), 108160078Syongari MII_PHY_DESC(xxBROADCOM, BCM5705), 109160078Syongari MII_PHY_DESC(xxBROADCOM, BCM5750), 110160078Syongari MII_PHY_DESC(xxBROADCOM, BCM5714), 111160078Syongari MII_PHY_DESC(xxBROADCOM, BCM5780), 112160078Syongari MII_PHY_DESC(xxBROADCOM, BCM5706C), 113160078Syongari MII_PHY_DESC(xxBROADCOM, BCM5708C), 114160078Syongari MII_PHY_END 115160078Syongari}; 116160078Syongari 117105135Salfredstatic int 118150763Simpbrgphy_probe(device_t dev) 11959477Swpaul{ 12059477Swpaul struct mii_attach_args *ma; 121160078Syongari const struct mii_phydesc *mpd; 12259477Swpaul 12359477Swpaul ma = device_get_ivars(dev); 124160078Syongari mpd = mii_phy_match(ma, brgphys); 125160078Syongari if (mpd != NULL) { 126160078Syongari device_set_desc(dev, mpd->mpd_name); 127160076Syongari return (BUS_PROBE_DEFAULT); 128157642Sps } 129157642Sps 130160078Syongari return (ENXIO); 13159477Swpaul} 13259477Swpaul 133105135Salfredstatic int 134150763Simpbrgphy_attach(device_t dev) 13559477Swpaul{ 13659477Swpaul struct mii_softc *sc; 13759477Swpaul struct mii_attach_args *ma; 13859477Swpaul struct mii_data *mii; 13959477Swpaul const char *sep = ""; 140157642Sps struct bge_softc *bge_sc = NULL; 141157642Sps struct bce_softc *bce_sc = NULL; 142118814Swpaul int fast_ether_only = FALSE; 14359477Swpaul 14459477Swpaul sc = device_get_softc(dev); 14559477Swpaul ma = device_get_ivars(dev); 14659477Swpaul sc->mii_dev = device_get_parent(dev); 14759477Swpaul mii = device_get_softc(sc->mii_dev); 14859477Swpaul LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 14959477Swpaul 15059477Swpaul sc->mii_inst = mii->mii_instance; 15159477Swpaul sc->mii_phy = ma->mii_phyno; 15259477Swpaul sc->mii_service = brgphy_service; 15359477Swpaul sc->mii_pdata = mii; 15459477Swpaul 15559477Swpaul sc->mii_flags |= MIIF_NOISOLATE; 15659477Swpaul mii->mii_instance++; 15759477Swpaul 15859477Swpaul#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) 15959477Swpaul#define PRINT(s) printf("%s%s", sep, s); sep = ", " 16059477Swpaul 16159477Swpaul ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), 16259477Swpaul BMCR_ISO); 16359477Swpaul#if 0 16459477Swpaul ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), 16559477Swpaul BMCR_LOOP|BMCR_S100); 16659477Swpaul#endif 16759477Swpaul 168114590Sps brgphy_mii_model = MII_MODEL(ma->mii_id2); 169114590Sps brgphy_reset(sc); 17059477Swpaul 17183029Swpaul 17295667Sphk sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 17395667Sphk sc->mii_capabilities &= ~BMSR_ANEG; 17459477Swpaul device_printf(dev, " "); 17595667Sphk mii_add_media(sc); 176118814Swpaul 177157642Sps /* Find the driver associated with this PHY. */ 178157642Sps if (strcmp(mii->mii_ifp->if_dname, "bge") == 0) { 179157642Sps bge_sc = mii->mii_ifp->if_softc; 180157642Sps } else if (strcmp(mii->mii_ifp->if_dname, "bce") == 0) { 181157642Sps bce_sc = mii->mii_ifp->if_softc; 182157642Sps } 183157642Sps 184118814Swpaul /* The 590x chips are 10/100 only. */ 185121816Sbrooks if (strcmp(mii->mii_ifp->if_dname, "bge") == 0 && 186118814Swpaul pci_get_vendor(bge_sc->bge_dev) == BCOM_VENDORID && 187118814Swpaul (pci_get_device(bge_sc->bge_dev) == BCOM_DEVICEID_BCM5901 || 188118814Swpaul pci_get_device(bge_sc->bge_dev) == BCOM_DEVICEID_BCM5901A2)) 189118814Swpaul fast_ether_only = TRUE; 190118814Swpaul 191118814Swpaul if (fast_ether_only == FALSE) { 192118814Swpaul ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, 193118814Swpaul sc->mii_inst), BRGPHY_BMCR_FDX); 194118814Swpaul PRINT(", 1000baseTX"); 195118814Swpaul ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 196118814Swpaul IFM_FDX, sc->mii_inst), 0); 197118814Swpaul PRINT("1000baseTX-FDX"); 198118814Swpaul } 199118814Swpaul 20059477Swpaul ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0); 20159477Swpaul PRINT("auto"); 20259477Swpaul 20359477Swpaul printf("\n"); 20459477Swpaul#undef ADD 20559477Swpaul#undef PRINT 20659477Swpaul 20759477Swpaul MIIBUS_MEDIAINIT(sc->mii_dev); 20859477Swpaul return(0); 20959477Swpaul} 21059477Swpaul 21184145Sjlemonstatic int 212150763Simpbrgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 21359477Swpaul{ 21459477Swpaul struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 215114590Sps int reg, speed, gig; 21659477Swpaul 21759477Swpaul switch (cmd) { 21859477Swpaul case MII_POLLSTAT: 21959477Swpaul /* 22059477Swpaul * If we're not polling our PHY instance, just return. 22159477Swpaul */ 22259477Swpaul if (IFM_INST(ife->ifm_media) != sc->mii_inst) 22359477Swpaul return (0); 22459477Swpaul break; 22559477Swpaul 22659477Swpaul case MII_MEDIACHG: 22759477Swpaul /* 22859477Swpaul * If the media indicates a different PHY instance, 22959477Swpaul * isolate ourselves. 23059477Swpaul */ 23159477Swpaul if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 23259477Swpaul reg = PHY_READ(sc, MII_BMCR); 23359477Swpaul PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 23459477Swpaul return (0); 23559477Swpaul } 23659477Swpaul 23759477Swpaul /* 23859477Swpaul * If the interface is not up, don't do anything. 23959477Swpaul */ 24059477Swpaul if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 24159477Swpaul break; 24259477Swpaul 243114590Sps brgphy_reset(sc); /* XXX hardware bug work-around */ 24459477Swpaul 24559477Swpaul switch (IFM_SUBTYPE(ife->ifm_media)) { 24659477Swpaul case IFM_AUTO: 24759477Swpaul#ifdef foo 24859477Swpaul /* 24959477Swpaul * If we're already in auto mode, just return. 25059477Swpaul */ 25159477Swpaul if (PHY_READ(sc, BRGPHY_MII_BMCR) & BRGPHY_BMCR_AUTOEN) 25259477Swpaul return (0); 25359477Swpaul#endif 25496026Sphk (void) brgphy_mii_phy_auto(sc); 25559477Swpaul break; 25695673Sphk case IFM_1000_T: 25783029Swpaul speed = BRGPHY_S1000; 25883029Swpaul goto setit; 25983029Swpaul case IFM_100_TX: 26083029Swpaul speed = BRGPHY_S100; 26183029Swpaul goto setit; 26283029Swpaul case IFM_10_T: 26383029Swpaul speed = BRGPHY_S10; 26483029Swpaulsetit: 265114590Sps brgphy_loop(sc); 26659477Swpaul if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { 267114590Sps speed |= BRGPHY_BMCR_FDX; 268114590Sps gig = BRGPHY_1000CTL_AFD; 26959477Swpaul } else { 270114590Sps gig = BRGPHY_1000CTL_AHD; 27159477Swpaul } 272114590Sps 273114590Sps PHY_WRITE(sc, BRGPHY_MII_1000CTL, 0); 274114590Sps PHY_WRITE(sc, BRGPHY_MII_BMCR, speed); 27559477Swpaul PHY_WRITE(sc, BRGPHY_MII_ANAR, BRGPHY_SEL_TYPE); 27659477Swpaul 277114590Sps if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) 27883029Swpaul break; 27983029Swpaul 280114590Sps PHY_WRITE(sc, BRGPHY_MII_1000CTL, gig); 281114590Sps PHY_WRITE(sc, BRGPHY_MII_BMCR, 282114590Sps speed|BRGPHY_BMCR_AUTOEN|BRGPHY_BMCR_STARTNEG); 283114590Sps 284114590Sps if (brgphy_mii_model != MII_MODEL_xxBROADCOM_BCM5701) 285114590Sps break; 286114590Sps 28759477Swpaul /* 28859477Swpaul * When settning the link manually, one side must 28959477Swpaul * be the master and the other the slave. However 29059477Swpaul * ifmedia doesn't give us a good way to specify 29159477Swpaul * this, so we fake it by using one of the LINK 29259477Swpaul * flags. If LINK0 is set, we program the PHY to 29359477Swpaul * be a master, otherwise it's a slave. 29459477Swpaul */ 29559477Swpaul if ((mii->mii_ifp->if_flags & IFF_LINK0)) { 29659477Swpaul PHY_WRITE(sc, BRGPHY_MII_1000CTL, 297114590Sps gig|BRGPHY_1000CTL_MSE|BRGPHY_1000CTL_MSC); 29859477Swpaul } else { 29959477Swpaul PHY_WRITE(sc, BRGPHY_MII_1000CTL, 300114590Sps gig|BRGPHY_1000CTL_MSE); 30159477Swpaul } 30259477Swpaul break; 30383597Swpaul#ifdef foo 30483597Swpaul case IFM_NONE: 30583597Swpaul PHY_WRITE(sc, MII_BMCR, BMCR_ISO|BMCR_PDOWN); 30683597Swpaul break; 30783597Swpaul#endif 30859477Swpaul case IFM_100_T4: 30959477Swpaul default: 31059477Swpaul return (EINVAL); 31159477Swpaul } 31259477Swpaul break; 31359477Swpaul 31459477Swpaul case MII_TICK: 31559477Swpaul /* 31659477Swpaul * If we're not currently selected, just return. 31759477Swpaul */ 31859477Swpaul if (IFM_INST(ife->ifm_media) != sc->mii_inst) 31959477Swpaul return (0); 32059477Swpaul 32159477Swpaul /* 32259477Swpaul * Is the interface even up? 32359477Swpaul */ 32459477Swpaul if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 32559477Swpaul return (0); 32659477Swpaul 32759477Swpaul /* 32884145Sjlemon * Only used for autonegotiation. 32959477Swpaul */ 33084145Sjlemon if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 33184145Sjlemon break; 33259477Swpaul 33359477Swpaul /* 33459477Swpaul * Check to see if we have link. If we do, we don't 33559477Swpaul * need to restart the autonegotiation process. Read 33659477Swpaul * the BMSR twice in case it's latched. 33759477Swpaul */ 33859477Swpaul reg = PHY_READ(sc, BRGPHY_MII_AUXSTS); 33959477Swpaul if (reg & BRGPHY_AUXSTS_LINK) 34059477Swpaul break; 34159477Swpaul 34284145Sjlemon /* 34384145Sjlemon * Only retry autonegotiation every 5 seconds. 34484145Sjlemon */ 345128870Sandre if (++sc->mii_ticks <= 5) 346128870Sandre break; 34784145Sjlemon 34884145Sjlemon sc->mii_ticks = 0; 34996026Sphk brgphy_mii_phy_auto(sc); 350153234Soleg break; 35159477Swpaul } 35259477Swpaul 35359477Swpaul /* Update the media status. */ 35459477Swpaul brgphy_status(sc); 35559477Swpaul 356114628Sps /* 357114628Sps * Callback if something changed. Note that we need to poke 358114628Sps * the DSP on the Broadcom PHYs if the media changes. 359114628Sps * 360114628Sps */ 361114628Sps if (sc->mii_media_active != mii->mii_media_active || 362114628Sps sc->mii_media_status != mii->mii_media_status || 363114628Sps cmd == MII_MEDIACHG) { 364114628Sps switch (brgphy_mii_model) { 365151370Sgrehan case MII_MODEL_xxBROADCOM_BCM5400: 366114628Sps case MII_MODEL_xxBROADCOM_BCM5401: 367114628Sps bcm5401_load_dspcode(sc); 368114628Sps break; 369114628Sps case MII_MODEL_xxBROADCOM_BCM5411: 370114628Sps bcm5411_load_dspcode(sc); 371114628Sps break; 372114628Sps } 373114628Sps } 374128870Sandre mii_phy_update(sc, cmd); 37559477Swpaul return (0); 37659477Swpaul} 37759477Swpaul 37884145Sjlemonstatic void 379150763Simpbrgphy_status(struct mii_softc *sc) 38059477Swpaul{ 38159477Swpaul struct mii_data *mii = sc->mii_pdata; 38283029Swpaul struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 38383029Swpaul int bmsr, bmcr; 38459477Swpaul 38559477Swpaul mii->mii_media_status = IFM_AVALID; 38659477Swpaul mii->mii_media_active = IFM_ETHER; 38759477Swpaul 38859477Swpaul bmsr = PHY_READ(sc, BRGPHY_MII_BMSR); 38959477Swpaul if (PHY_READ(sc, BRGPHY_MII_AUXSTS) & BRGPHY_AUXSTS_LINK) 39059477Swpaul mii->mii_media_status |= IFM_ACTIVE; 39159477Swpaul 39259477Swpaul bmcr = PHY_READ(sc, BRGPHY_MII_BMCR); 39359477Swpaul 39459477Swpaul if (bmcr & BRGPHY_BMCR_LOOP) 39559477Swpaul mii->mii_media_active |= IFM_LOOP; 39659477Swpaul 39759477Swpaul if (bmcr & BRGPHY_BMCR_AUTOEN) { 39859477Swpaul if ((bmsr & BRGPHY_BMSR_ACOMP) == 0) { 39959477Swpaul /* Erg, still trying, I guess... */ 40059477Swpaul mii->mii_media_active |= IFM_NONE; 40159477Swpaul return; 40259477Swpaul } 40359477Swpaul 40483029Swpaul switch (PHY_READ(sc, BRGPHY_MII_AUXSTS) & 40583029Swpaul BRGPHY_AUXSTS_AN_RES) { 40683029Swpaul case BRGPHY_RES_1000FD: 40795673Sphk mii->mii_media_active |= IFM_1000_T | IFM_FDX; 40883029Swpaul break; 40983029Swpaul case BRGPHY_RES_1000HD: 41095673Sphk mii->mii_media_active |= IFM_1000_T | IFM_HDX; 41183029Swpaul break; 41283029Swpaul case BRGPHY_RES_100FD: 41383029Swpaul mii->mii_media_active |= IFM_100_TX | IFM_FDX; 41483029Swpaul break; 41583029Swpaul case BRGPHY_RES_100T4: 41683029Swpaul mii->mii_media_active |= IFM_100_T4; 41783029Swpaul break; 41883029Swpaul case BRGPHY_RES_100HD: 41983029Swpaul mii->mii_media_active |= IFM_100_TX | IFM_HDX; 42083029Swpaul break; 42183029Swpaul case BRGPHY_RES_10FD: 42283029Swpaul mii->mii_media_active |= IFM_10_T | IFM_FDX; 42383029Swpaul break; 42483029Swpaul case BRGPHY_RES_10HD: 42583029Swpaul mii->mii_media_active |= IFM_10_T | IFM_HDX; 42683029Swpaul break; 42783029Swpaul default: 42883029Swpaul mii->mii_media_active |= IFM_NONE; 42983029Swpaul break; 43083029Swpaul } 43159477Swpaul return; 43259477Swpaul } 43359477Swpaul 43483029Swpaul mii->mii_media_active = ife->ifm_media; 43559477Swpaul 43659477Swpaul return; 43759477Swpaul} 43859477Swpaul 43959477Swpaul 44059477Swpaulstatic int 441150763Simpbrgphy_mii_phy_auto(struct mii_softc *mii) 44259477Swpaul{ 44396026Sphk int ktcr = 0; 44459477Swpaul 445114590Sps brgphy_loop(mii); 446114590Sps brgphy_reset(mii); 447114590Sps ktcr = BRGPHY_1000CTL_AFD|BRGPHY_1000CTL_AHD; 448114590Sps if (brgphy_mii_model == MII_MODEL_xxBROADCOM_BCM5701) 449114590Sps ktcr |= BRGPHY_1000CTL_MSE|BRGPHY_1000CTL_MSC; 450114590Sps PHY_WRITE(mii, BRGPHY_MII_1000CTL, ktcr); 45196026Sphk ktcr = PHY_READ(mii, BRGPHY_MII_1000CTL); 45296026Sphk DELAY(1000); 45396026Sphk PHY_WRITE(mii, BRGPHY_MII_ANAR, 45496026Sphk BMSR_MEDIA_TO_ANAR(mii->mii_capabilities) | ANAR_CSMA); 45596026Sphk DELAY(1000); 45696026Sphk PHY_WRITE(mii, BRGPHY_MII_BMCR, 45796026Sphk BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG); 45896026Sphk PHY_WRITE(mii, BRGPHY_MII_IMR, 0xFF00); 45959477Swpaul return (EJUSTRETURN); 46059477Swpaul} 461114590Sps 462114590Spsstatic void 463114590Spsbrgphy_loop(struct mii_softc *sc) 464114590Sps{ 465114590Sps u_int32_t bmsr; 466114590Sps int i; 467114590Sps 468114590Sps PHY_WRITE(sc, BRGPHY_MII_BMCR, BRGPHY_BMCR_LOOP); 469114590Sps for (i = 0; i < 15000; i++) { 470114590Sps bmsr = PHY_READ(sc, BRGPHY_MII_BMSR); 471114590Sps if (!(bmsr & BRGPHY_BMSR_LINK)) { 472114590Sps#if 0 473114590Sps device_printf(sc->mii_dev, "looped %d\n", i); 474114590Sps#endif 475114590Sps break; 476114590Sps } 477114590Sps DELAY(10); 478114590Sps } 479114590Sps} 480114590Sps 481114590Sps/* Turn off tap power management on 5401. */ 482114590Spsstatic void 483114590Spsbcm5401_load_dspcode(struct mii_softc *sc) 484114590Sps{ 485114590Sps static const struct { 486114590Sps int reg; 487114590Sps uint16_t val; 488114590Sps } dspcode[] = { 489114590Sps { BRGPHY_MII_AUXCTL, 0x0c20 }, 490114590Sps { BRGPHY_MII_DSP_ADDR_REG, 0x0012 }, 491114590Sps { BRGPHY_MII_DSP_RW_PORT, 0x1804 }, 492114590Sps { BRGPHY_MII_DSP_ADDR_REG, 0x0013 }, 493114590Sps { BRGPHY_MII_DSP_RW_PORT, 0x1204 }, 494114590Sps { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, 495114590Sps { BRGPHY_MII_DSP_RW_PORT, 0x0132 }, 496114590Sps { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, 497114590Sps { BRGPHY_MII_DSP_RW_PORT, 0x0232 }, 498114590Sps { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 499114590Sps { BRGPHY_MII_DSP_RW_PORT, 0x0a20 }, 500114590Sps { 0, 0 }, 501114590Sps }; 502114590Sps int i; 503114590Sps 504114590Sps for (i = 0; dspcode[i].reg != 0; i++) 505114590Sps PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 506114590Sps DELAY(40); 507114590Sps} 508114590Sps 509114590Spsstatic void 510114590Spsbcm5411_load_dspcode(struct mii_softc *sc) 511114590Sps{ 512114590Sps static const struct { 513114590Sps int reg; 514114590Sps uint16_t val; 515114590Sps } dspcode[] = { 516114590Sps { 0x1c, 0x8c23 }, 517114590Sps { 0x1c, 0x8ca3 }, 518114590Sps { 0x1c, 0x8c23 }, 519114590Sps { 0, 0 }, 520114590Sps }; 521114590Sps int i; 522114590Sps 523114590Sps for (i = 0; dspcode[i].reg != 0; i++) 524114590Sps PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 525114590Sps} 526114590Sps 527114590Spsstatic void 528114590Spsbcm5703_load_dspcode(struct mii_softc *sc) 529114590Sps{ 530114590Sps static const struct { 531114590Sps int reg; 532114590Sps uint16_t val; 533114590Sps } dspcode[] = { 534114590Sps { BRGPHY_MII_AUXCTL, 0x0c00 }, 535114590Sps { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 536114590Sps { BRGPHY_MII_DSP_RW_PORT, 0x2aaa }, 537114590Sps { 0, 0 }, 538114590Sps }; 539114590Sps int i; 540114590Sps 541114590Sps for (i = 0; dspcode[i].reg != 0; i++) 542114590Sps PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 543114590Sps} 544114590Sps 545114590Spsstatic void 546114590Spsbcm5704_load_dspcode(struct mii_softc *sc) 547114590Sps{ 548114590Sps static const struct { 549114590Sps int reg; 550114590Sps u_int16_t val; 551114590Sps } dspcode[] = { 552114590Sps { 0x1c, 0x8d68 }, 553114590Sps { 0x1c, 0x8d68 }, 554114590Sps { 0, 0 }, 555114590Sps }; 556114590Sps int i; 557114590Sps 558114590Sps for (i = 0; dspcode[i].reg != 0; i++) 559114590Sps PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 560114590Sps} 561114590Sps 562114590Spsstatic void 563135772Spsbcm5750_load_dspcode(struct mii_softc *sc) 564135772Sps{ 565135772Sps static const struct { 566135772Sps int reg; 567135772Sps u_int16_t val; 568135772Sps } dspcode[] = { 569135772Sps { 0x18, 0x0c00 }, 570135772Sps { 0x17, 0x000a }, 571135772Sps { 0x15, 0x310b }, 572135772Sps { 0x17, 0x201f }, 573135772Sps { 0x15, 0x9506 }, 574135772Sps { 0x17, 0x401f }, 575135772Sps { 0x15, 0x14e2 }, 576135772Sps { 0x18, 0x0400 }, 577135772Sps { 0, 0 }, 578135772Sps }; 579135772Sps int i; 580135772Sps 581135772Sps for (i = 0; dspcode[i].reg != 0; i++) 582135772Sps PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 583135772Sps} 584135772Sps 585135772Spsstatic void 586114590Spsbrgphy_reset(struct mii_softc *sc) 587114590Sps{ 588114590Sps u_int32_t val; 589117659Swpaul struct ifnet *ifp; 590157642Sps struct bge_softc *bge_sc = NULL; 591157642Sps struct bce_softc *bce_sc = NULL; 592114590Sps 593114590Sps mii_phy_reset(sc); 594114590Sps 595114590Sps switch (brgphy_mii_model) { 596151370Sgrehan case MII_MODEL_xxBROADCOM_BCM5400: 597114590Sps case MII_MODEL_xxBROADCOM_BCM5401: 598114590Sps bcm5401_load_dspcode(sc); 599114590Sps break; 600114590Sps case MII_MODEL_xxBROADCOM_BCM5411: 601114590Sps bcm5411_load_dspcode(sc); 602114590Sps break; 603114590Sps case MII_MODEL_xxBROADCOM_BCM5703: 604114590Sps bcm5703_load_dspcode(sc); 605114590Sps break; 606114590Sps case MII_MODEL_xxBROADCOM_BCM5704: 607114590Sps bcm5704_load_dspcode(sc); 608114590Sps break; 609135772Sps case MII_MODEL_xxBROADCOM_BCM5750: 610146413Sps case MII_MODEL_xxBROADCOM_BCM5714: 611157041Soleg case MII_MODEL_xxBROADCOM_BCM5780: 612157642Sps case MII_MODEL_xxBROADCOM_BCM5706C: 613157642Sps case MII_MODEL_xxBROADCOM_BCM5708C: 614135772Sps bcm5750_load_dspcode(sc); 615135772Sps break; 616114590Sps } 617114590Sps 618117659Swpaul ifp = sc->mii_pdata->mii_ifp; 619117659Swpaul 620157642Sps /* Find the driver associated with this PHY. */ 621157642Sps if (strcmp(ifp->if_dname, "bge") == 0) { 622157642Sps bge_sc = ifp->if_softc; 623157642Sps } else if (strcmp(ifp->if_dname, "bce") == 0) { 624157642Sps bce_sc = ifp->if_softc; 625157642Sps } 626117659Swpaul 627157642Sps /* Handle any NetXtreme/bge workarounds. */ 628157642Sps if (bge_sc) { 629157642Sps /* 630157642Sps * Don't enable Ethernet@WireSpeed for the 5700 or the 631157642Sps * 5705 A1 and A2 chips. Make sure we only do this test 632157642Sps * on "bge" NICs, since other drivers may use this same 633157642Sps * PHY subdriver. 634157642Sps */ 635157642Sps if (bge_sc->bge_asicrev == BGE_ASICREV_BCM5700 || 636157642Sps bge_sc->bge_chipid == BGE_CHIPID_BCM5705_A1 || 637157642Sps bge_sc->bge_chipid == BGE_CHIPID_BCM5705_A2) 638157642Sps return; 639119157Sambrisko 640157642Sps /* Enable Ethernet@WireSpeed. */ 641157642Sps PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007); 642157642Sps val = PHY_READ(sc, BRGPHY_MII_AUXCTL); 643157642Sps PHY_WRITE(sc, BRGPHY_MII_AUXCTL, val | (1 << 15) | (1 << 4)); 644157642Sps 645157642Sps /* Enable Link LED on Dell boxes */ 646157642Sps if (bge_sc->bge_no_3_led) { 647157642Sps PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 648157642Sps PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL) 649157642Sps & ~BRGPHY_PHY_EXTCTL_3_LED); 650157642Sps } 651157642Sps } else if (bce_sc) { 652157642Sps 653157642Sps /* Set or clear jumbo frame settings in the PHY. */ 654157642Sps if (ifp->if_mtu > ETHER_MAX_LEN) { 655157642Sps PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7); 656157642Sps val = PHY_READ(sc, BRGPHY_MII_AUXCTL); 657157642Sps PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 658157642Sps val | BRGPHY_AUXCTL_LONG_PKT); 659157642Sps 660157642Sps val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL); 661157642Sps PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 662157642Sps val | BRGPHY_PHY_EXTCTL_HIGH_LA); 663157642Sps } else { 664157642Sps PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7); 665157642Sps val = PHY_READ(sc, BRGPHY_MII_AUXCTL); 666157642Sps PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 667157642Sps val & ~(BRGPHY_AUXCTL_LONG_PKT | 0x7)); 668157642Sps 669157642Sps val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL); 670157642Sps PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 671157642Sps val & ~BRGPHY_PHY_EXTCTL_HIGH_LA); 672157642Sps } 673157642Sps 674157642Sps /* Enable Ethernet@Wirespeed */ 675157642Sps PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007); 676157642Sps val = PHY_READ(sc, BRGPHY_MII_AUXCTL); 677157642Sps PHY_WRITE(sc, BRGPHY_MII_AUXCTL, (val | (1 << 15) | (1 << 4))); 678119157Sambrisko } 679114590Sps} 680