1d1307e81SPyun YongHyeon /*- 2d1307e81SPyun YongHyeon * Copyright (c) 2008, Pyun YongHyeon <yongari@FreeBSD.org> 3d1307e81SPyun YongHyeon * All rights reserved. 4d1307e81SPyun YongHyeon * 5d1307e81SPyun YongHyeon * Redistribution and use in source and binary forms, with or without 6d1307e81SPyun YongHyeon * modification, are permitted provided that the following conditions 7d1307e81SPyun YongHyeon * are met: 8d1307e81SPyun YongHyeon * 1. Redistributions of source code must retain the above copyright 9d1307e81SPyun YongHyeon * notice unmodified, this list of conditions, and the following 10d1307e81SPyun YongHyeon * disclaimer. 11d1307e81SPyun YongHyeon * 2. Redistributions in binary form must reproduce the above copyright 12d1307e81SPyun YongHyeon * notice, this list of conditions and the following disclaimer in the 13d1307e81SPyun YongHyeon * documentation and/or other materials provided with the distribution. 14d1307e81SPyun YongHyeon * 15d1307e81SPyun YongHyeon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16d1307e81SPyun YongHyeon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17d1307e81SPyun YongHyeon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18d1307e81SPyun YongHyeon * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19d1307e81SPyun YongHyeon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20d1307e81SPyun YongHyeon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21d1307e81SPyun YongHyeon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22d1307e81SPyun YongHyeon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23d1307e81SPyun YongHyeon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24d1307e81SPyun YongHyeon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25d1307e81SPyun YongHyeon * SUCH DAMAGE. 26d1307e81SPyun YongHyeon */ 27d1307e81SPyun YongHyeon 28d1307e81SPyun YongHyeon #include <sys/cdefs.h> 29d1307e81SPyun YongHyeon __FBSDID("$FreeBSD$"); 30d1307e81SPyun YongHyeon 31d1307e81SPyun YongHyeon /* 32d1307e81SPyun YongHyeon * Driver for the Attansic/Atheros F1 10/100/1000 PHY. 33d1307e81SPyun YongHyeon */ 34d1307e81SPyun YongHyeon 35d1307e81SPyun YongHyeon #include <sys/param.h> 36d1307e81SPyun YongHyeon #include <sys/systm.h> 37d1307e81SPyun YongHyeon #include <sys/kernel.h> 38d1307e81SPyun YongHyeon #include <sys/module.h> 39d1307e81SPyun YongHyeon #include <sys/socket.h> 40d1307e81SPyun YongHyeon #include <sys/bus.h> 41d1307e81SPyun YongHyeon 42d1307e81SPyun YongHyeon #include <net/if.h> 43d1307e81SPyun YongHyeon #include <net/if_media.h> 44d1307e81SPyun YongHyeon 45d1307e81SPyun YongHyeon #include <dev/mii/mii.h> 46d1307e81SPyun YongHyeon #include <dev/mii/miivar.h> 47d1307e81SPyun YongHyeon #include "miidevs.h" 48d1307e81SPyun YongHyeon 49d1307e81SPyun YongHyeon #include <dev/mii/atphyreg.h> 50d1307e81SPyun YongHyeon 51d1307e81SPyun YongHyeon #include "miibus_if.h" 52d1307e81SPyun YongHyeon 53d1307e81SPyun YongHyeon static int atphy_probe(device_t); 54d1307e81SPyun YongHyeon static int atphy_attach(device_t); 55d1307e81SPyun YongHyeon 56d1307e81SPyun YongHyeon struct atphy_softc { 57d1307e81SPyun YongHyeon struct mii_softc mii_sc; 58d1307e81SPyun YongHyeon int mii_oui; 59d1307e81SPyun YongHyeon int mii_model; 60d1307e81SPyun YongHyeon int mii_rev; 61d1307e81SPyun YongHyeon }; 62d1307e81SPyun YongHyeon 63d1307e81SPyun YongHyeon static device_method_t atphy_methods[] = { 64d1307e81SPyun YongHyeon /* Device interface. */ 65d1307e81SPyun YongHyeon DEVMETHOD(device_probe, atphy_probe), 66d1307e81SPyun YongHyeon DEVMETHOD(device_attach, atphy_attach), 67d1307e81SPyun YongHyeon DEVMETHOD(device_detach, mii_phy_detach), 68d1307e81SPyun YongHyeon DEVMETHOD(device_shutdown, bus_generic_shutdown), 69d1307e81SPyun YongHyeon { NULL, NULL } 70d1307e81SPyun YongHyeon }; 71d1307e81SPyun YongHyeon 72d1307e81SPyun YongHyeon static devclass_t atphy_devclass; 73d1307e81SPyun YongHyeon static driver_t atphy_driver = { 74d1307e81SPyun YongHyeon "atphy", 75d1307e81SPyun YongHyeon atphy_methods, 76d1307e81SPyun YongHyeon sizeof(struct atphy_softc) 77d1307e81SPyun YongHyeon }; 78d1307e81SPyun YongHyeon 79d1307e81SPyun YongHyeon DRIVER_MODULE(atphy, miibus, atphy_driver, atphy_devclass, 0, 0); 80d1307e81SPyun YongHyeon 81d1307e81SPyun YongHyeon static int atphy_service(struct mii_softc *, struct mii_data *, int); 82d1307e81SPyun YongHyeon static void atphy_status(struct mii_softc *); 83d1307e81SPyun YongHyeon static void atphy_reset(struct mii_softc *); 84d1307e81SPyun YongHyeon static uint16_t atphy_anar(struct ifmedia_entry *); 85*991ab941SMarius Strobl static int atphy_setmedia(struct mii_softc *, int); 86d1307e81SPyun YongHyeon 87d1307e81SPyun YongHyeon static const struct mii_phydesc atphys[] = { 88d1307e81SPyun YongHyeon MII_PHY_DESC(ATHEROS, F1), 89af1f79ceSPyun YongHyeon MII_PHY_DESC(ATHEROS, F1_7), 90ba26d470SStanislav Sedov MII_PHY_DESC(ATHEROS, F2), 91d1307e81SPyun YongHyeon MII_PHY_END 92d1307e81SPyun YongHyeon }; 93d1307e81SPyun YongHyeon 94d1307e81SPyun YongHyeon static int 95d1307e81SPyun YongHyeon atphy_probe(device_t dev) 96d1307e81SPyun YongHyeon { 97d1307e81SPyun YongHyeon 98d1307e81SPyun YongHyeon return (mii_phy_dev_probe(dev, atphys, BUS_PROBE_DEFAULT)); 99d1307e81SPyun YongHyeon } 100d1307e81SPyun YongHyeon 101d1307e81SPyun YongHyeon static int 102d1307e81SPyun YongHyeon atphy_attach(device_t dev) 103d1307e81SPyun YongHyeon { 104d1307e81SPyun YongHyeon struct atphy_softc *asc; 105d1307e81SPyun YongHyeon struct mii_softc *sc; 106d1307e81SPyun YongHyeon struct mii_attach_args *ma; 107d1307e81SPyun YongHyeon struct mii_data *mii; 108d1307e81SPyun YongHyeon 109d1307e81SPyun YongHyeon asc = device_get_softc(dev); 110d1307e81SPyun YongHyeon sc = &asc->mii_sc; 111d1307e81SPyun YongHyeon ma = device_get_ivars(dev); 112d1307e81SPyun YongHyeon sc->mii_dev = device_get_parent(dev); 1137b9a15f7SMarius Strobl mii = ma->mii_data; 114d1307e81SPyun YongHyeon LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 115d1307e81SPyun YongHyeon 1168e5d93dbSMarius Strobl sc->mii_flags = miibus_get_flags(dev); 117de1add1eSMarius Strobl sc->mii_inst = mii->mii_instance++; 118d1307e81SPyun YongHyeon sc->mii_phy = ma->mii_phyno; 119d1307e81SPyun YongHyeon sc->mii_service = atphy_service; 120d1307e81SPyun YongHyeon sc->mii_pdata = mii; 121d1307e81SPyun YongHyeon 122d1307e81SPyun YongHyeon asc->mii_oui = MII_OUI(ma->mii_id1, ma->mii_id2); 123d1307e81SPyun YongHyeon asc->mii_model = MII_MODEL(ma->mii_id2); 124d1307e81SPyun YongHyeon asc->mii_rev = MII_REV(ma->mii_id2); 125d1307e81SPyun YongHyeon if (bootverbose) 126d1307e81SPyun YongHyeon device_printf(dev, "OUI 0x%06x, model 0x%04x, rev. %d\n", 127d1307e81SPyun YongHyeon asc->mii_oui, asc->mii_model, asc->mii_rev); 128d1307e81SPyun YongHyeon 129d1307e81SPyun YongHyeon atphy_reset(sc); 130d1307e81SPyun YongHyeon 131d1307e81SPyun YongHyeon sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 132d1307e81SPyun YongHyeon if (sc->mii_capabilities & BMSR_EXTSTAT) 133d1307e81SPyun YongHyeon sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); 134d1307e81SPyun YongHyeon device_printf(dev, " "); 135d1307e81SPyun YongHyeon mii_phy_add_media(sc); 136d1307e81SPyun YongHyeon printf("\n"); 137d1307e81SPyun YongHyeon 138d1307e81SPyun YongHyeon MIIBUS_MEDIAINIT(sc->mii_dev); 139d1307e81SPyun YongHyeon return (0); 140d1307e81SPyun YongHyeon } 141d1307e81SPyun YongHyeon 142d1307e81SPyun YongHyeon static int 143d1307e81SPyun YongHyeon atphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 144d1307e81SPyun YongHyeon { 145d1307e81SPyun YongHyeon struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 146d1307e81SPyun YongHyeon uint16_t anar, bmcr, bmsr; 147d1307e81SPyun YongHyeon 148d1307e81SPyun YongHyeon switch (cmd) { 149d1307e81SPyun YongHyeon case MII_POLLSTAT: 150d1307e81SPyun YongHyeon break; 151d1307e81SPyun YongHyeon 152d1307e81SPyun YongHyeon case MII_MEDIACHG: 153d1307e81SPyun YongHyeon /* 154d1307e81SPyun YongHyeon * If the interface is not up, don't do anything. 155d1307e81SPyun YongHyeon */ 156d1307e81SPyun YongHyeon if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 157d1307e81SPyun YongHyeon break; 158d1307e81SPyun YongHyeon 159d1307e81SPyun YongHyeon if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO || 160d1307e81SPyun YongHyeon IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { 161*991ab941SMarius Strobl atphy_setmedia(sc, ife->ifm_media); 162d1307e81SPyun YongHyeon break; 163d1307e81SPyun YongHyeon } 164d1307e81SPyun YongHyeon 165d1307e81SPyun YongHyeon bmcr = 0; 166d1307e81SPyun YongHyeon switch (IFM_SUBTYPE(ife->ifm_media)) { 167d1307e81SPyun YongHyeon case IFM_100_TX: 168d1307e81SPyun YongHyeon bmcr = BMCR_S100; 169d1307e81SPyun YongHyeon break; 170d1307e81SPyun YongHyeon case IFM_10_T: 171d1307e81SPyun YongHyeon bmcr = BMCR_S10; 172d1307e81SPyun YongHyeon break; 173d1307e81SPyun YongHyeon case IFM_NONE: 174d1307e81SPyun YongHyeon bmcr = PHY_READ(sc, MII_BMCR); 175d1307e81SPyun YongHyeon /* 176d1307e81SPyun YongHyeon * XXX 177d1307e81SPyun YongHyeon * Due to an unknown reason powering down PHY resulted 178*991ab941SMarius Strobl * in unexpected results such as inaccessibility of 179d1307e81SPyun YongHyeon * hardware of freshly rebooted system. Disable 180d1307e81SPyun YongHyeon * powering down PHY until I got more information for 181d1307e81SPyun YongHyeon * Attansic/Atheros PHY hardwares. 182d1307e81SPyun YongHyeon */ 183d1307e81SPyun YongHyeon PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO); 184d1307e81SPyun YongHyeon goto done; 185d1307e81SPyun YongHyeon default: 186d1307e81SPyun YongHyeon return (EINVAL); 187d1307e81SPyun YongHyeon } 188d1307e81SPyun YongHyeon 189d1307e81SPyun YongHyeon anar = atphy_anar(ife); 190d1307e81SPyun YongHyeon if (((ife->ifm_media & IFM_GMASK) & IFM_FDX) != 0) { 191d1307e81SPyun YongHyeon bmcr |= BMCR_FDX; 192*991ab941SMarius Strobl if (((ife->ifm_media & IFM_GMASK) & IFM_FLOW) != 0 || 193*991ab941SMarius Strobl (sc->mii_flags & MIIF_FORCEPAUSE) != 0) 194*991ab941SMarius Strobl anar |= ANAR_PAUSE_TOWARDS; 195d1307e81SPyun YongHyeon } 196d1307e81SPyun YongHyeon 197d1307e81SPyun YongHyeon if ((sc->mii_extcapabilities & (EXTSR_1000TFDX | 198d1307e81SPyun YongHyeon EXTSR_1000THDX)) != 0) 199d1307e81SPyun YongHyeon PHY_WRITE(sc, MII_100T2CR, 0); 200d1307e81SPyun YongHyeon PHY_WRITE(sc, MII_ANAR, anar | ANAR_CSMA); 201d1307e81SPyun YongHyeon 202d1307e81SPyun YongHyeon /* 203d1307e81SPyun YongHyeon * Reset the PHY so all changes take effect. 204d1307e81SPyun YongHyeon */ 205d2cd2263SPyun YongHyeon PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_RESET | BMCR_AUTOEN | 206d2cd2263SPyun YongHyeon BMCR_STARTNEG); 207d1307e81SPyun YongHyeon done: 208d1307e81SPyun YongHyeon break; 209d1307e81SPyun YongHyeon 210d1307e81SPyun YongHyeon case MII_TICK: 211d1307e81SPyun YongHyeon /* 212d1307e81SPyun YongHyeon * Is the interface even up? 213d1307e81SPyun YongHyeon */ 214d1307e81SPyun YongHyeon if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 215d1307e81SPyun YongHyeon return (0); 216d1307e81SPyun YongHyeon 217d1307e81SPyun YongHyeon /* 218d1307e81SPyun YongHyeon * Only used for autonegotiation. 219d1307e81SPyun YongHyeon */ 220d1307e81SPyun YongHyeon if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { 221d1307e81SPyun YongHyeon sc->mii_ticks = 0; 222d1307e81SPyun YongHyeon break; 223d1307e81SPyun YongHyeon } 224d1307e81SPyun YongHyeon 225d1307e81SPyun YongHyeon /* 226*991ab941SMarius Strobl * Check for link. 227d1307e81SPyun YongHyeon * Read the status register twice; BMSR_LINK is latch-low. 228d1307e81SPyun YongHyeon */ 229d1307e81SPyun YongHyeon bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 230d1307e81SPyun YongHyeon if (bmsr & BMSR_LINK) { 231d1307e81SPyun YongHyeon sc->mii_ticks = 0; 232d1307e81SPyun YongHyeon break; 233d1307e81SPyun YongHyeon } 234d1307e81SPyun YongHyeon 235d1307e81SPyun YongHyeon /* Announce link loss right after it happens. */ 236d1307e81SPyun YongHyeon if (sc->mii_ticks++ == 0) 237d1307e81SPyun YongHyeon break; 238d1307e81SPyun YongHyeon if (sc->mii_ticks <= sc->mii_anegticks) 239d1307e81SPyun YongHyeon return (0); 240d1307e81SPyun YongHyeon 241d1307e81SPyun YongHyeon sc->mii_ticks = 0; 242*991ab941SMarius Strobl atphy_setmedia(sc, ife->ifm_media); 243d1307e81SPyun YongHyeon break; 244d1307e81SPyun YongHyeon } 245d1307e81SPyun YongHyeon 246d1307e81SPyun YongHyeon /* Update the media status. */ 247d1307e81SPyun YongHyeon atphy_status(sc); 248d1307e81SPyun YongHyeon 249d1307e81SPyun YongHyeon /* Callback if something changed. */ 250d1307e81SPyun YongHyeon mii_phy_update(sc, cmd); 251d1307e81SPyun YongHyeon return (0); 252d1307e81SPyun YongHyeon } 253d1307e81SPyun YongHyeon 254d1307e81SPyun YongHyeon static void 255d1307e81SPyun YongHyeon atphy_status(struct mii_softc *sc) 256d1307e81SPyun YongHyeon { 257d1307e81SPyun YongHyeon struct mii_data *mii = sc->mii_pdata; 258d1307e81SPyun YongHyeon uint32_t bmsr, bmcr, ssr; 259d1307e81SPyun YongHyeon 260d1307e81SPyun YongHyeon mii->mii_media_status = IFM_AVALID; 261d1307e81SPyun YongHyeon mii->mii_media_active = IFM_ETHER; 262d1307e81SPyun YongHyeon 263d1307e81SPyun YongHyeon bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 264d1307e81SPyun YongHyeon if ((bmsr & BMSR_LINK) != 0) 265d1307e81SPyun YongHyeon mii->mii_media_status |= IFM_ACTIVE; 266d1307e81SPyun YongHyeon 267d1307e81SPyun YongHyeon bmcr = PHY_READ(sc, MII_BMCR); 268d1307e81SPyun YongHyeon if ((bmcr & BMCR_ISO) != 0) { 269d1307e81SPyun YongHyeon mii->mii_media_active |= IFM_NONE; 270d1307e81SPyun YongHyeon mii->mii_media_status = 0; 271d1307e81SPyun YongHyeon return; 272d1307e81SPyun YongHyeon } 273d1307e81SPyun YongHyeon 274d1307e81SPyun YongHyeon if ((bmcr & BMCR_LOOP) != 0) 275d1307e81SPyun YongHyeon mii->mii_media_active |= IFM_LOOP; 276d1307e81SPyun YongHyeon 277d1307e81SPyun YongHyeon ssr = PHY_READ(sc, ATPHY_SSR); 278d1307e81SPyun YongHyeon if ((ssr & ATPHY_SSR_SPD_DPLX_RESOLVED) == 0) { 279d1307e81SPyun YongHyeon /* Erg, still trying, I guess... */ 280d1307e81SPyun YongHyeon mii->mii_media_active |= IFM_NONE; 281d1307e81SPyun YongHyeon return; 282d1307e81SPyun YongHyeon } 283d1307e81SPyun YongHyeon 284d1307e81SPyun YongHyeon switch (ssr & ATPHY_SSR_SPEED_MASK) { 285d1307e81SPyun YongHyeon case ATPHY_SSR_1000MBS: 286d1307e81SPyun YongHyeon mii->mii_media_active |= IFM_1000_T; 287d1307e81SPyun YongHyeon /* 288*991ab941SMarius Strobl * atphy(4) has a valid link so reset mii_ticks. 289d1307e81SPyun YongHyeon * Resetting mii_ticks is needed in order to 290d1307e81SPyun YongHyeon * detect link loss after auto-negotiation. 291d1307e81SPyun YongHyeon */ 292d1307e81SPyun YongHyeon sc->mii_ticks = 0; 293d1307e81SPyun YongHyeon break; 294d1307e81SPyun YongHyeon case ATPHY_SSR_100MBS: 295d1307e81SPyun YongHyeon mii->mii_media_active |= IFM_100_TX; 296d1307e81SPyun YongHyeon sc->mii_ticks = 0; 297d1307e81SPyun YongHyeon break; 298d1307e81SPyun YongHyeon case ATPHY_SSR_10MBS: 299d1307e81SPyun YongHyeon mii->mii_media_active |= IFM_10_T; 300d1307e81SPyun YongHyeon sc->mii_ticks = 0; 301d1307e81SPyun YongHyeon break; 302d1307e81SPyun YongHyeon default: 303d1307e81SPyun YongHyeon mii->mii_media_active |= IFM_NONE; 304d1307e81SPyun YongHyeon return; 305d1307e81SPyun YongHyeon } 306d1307e81SPyun YongHyeon 307d1307e81SPyun YongHyeon if ((ssr & ATPHY_SSR_DUPLEX) != 0) 308*991ab941SMarius Strobl mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc); 309d1307e81SPyun YongHyeon else 310d1307e81SPyun YongHyeon mii->mii_media_active |= IFM_HDX; 311d1307e81SPyun YongHyeon 312*991ab941SMarius Strobl if ((IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) && 313*991ab941SMarius Strobl (PHY_READ(sc, MII_100T2SR) & GTSR_MS_RES) != 0) 314*991ab941SMarius Strobl mii->mii_media_active |= IFM_ETH_MASTER; 315d1307e81SPyun YongHyeon } 316d1307e81SPyun YongHyeon 317d1307e81SPyun YongHyeon static void 318d1307e81SPyun YongHyeon atphy_reset(struct mii_softc *sc) 319d1307e81SPyun YongHyeon { 320d1307e81SPyun YongHyeon struct atphy_softc *asc; 321d1307e81SPyun YongHyeon uint32_t reg; 322d1307e81SPyun YongHyeon int i; 323d1307e81SPyun YongHyeon 324d1307e81SPyun YongHyeon asc = (struct atphy_softc *)sc; 325d1307e81SPyun YongHyeon 326d1307e81SPyun YongHyeon /* Take PHY out of power down mode. */ 327d1307e81SPyun YongHyeon PHY_WRITE(sc, 29, 0x29); 328d1307e81SPyun YongHyeon PHY_WRITE(sc, 30, 0); 329d1307e81SPyun YongHyeon 330d1307e81SPyun YongHyeon reg = PHY_READ(sc, ATPHY_SCR); 331d1307e81SPyun YongHyeon /* Enable automatic crossover. */ 332d1307e81SPyun YongHyeon reg |= ATPHY_SCR_AUTO_X_MODE; 333d1307e81SPyun YongHyeon /* Disable power down. */ 334d1307e81SPyun YongHyeon reg &= ~ATPHY_SCR_MAC_PDOWN; 335d1307e81SPyun YongHyeon /* Enable CRS on Tx. */ 336d1307e81SPyun YongHyeon reg |= ATPHY_SCR_ASSERT_CRS_ON_TX; 337d1307e81SPyun YongHyeon /* Auto correction for reversed cable polarity. */ 338d1307e81SPyun YongHyeon reg |= ATPHY_SCR_POLARITY_REVERSAL; 339d1307e81SPyun YongHyeon PHY_WRITE(sc, ATPHY_SCR, reg); 340d1307e81SPyun YongHyeon 341d1307e81SPyun YongHyeon /* Workaround F1 bug to reset phy. */ 342*991ab941SMarius Strobl atphy_setmedia(sc, sc->mii_pdata->mii_media.ifm_cur->ifm_media); 343d1307e81SPyun YongHyeon 344d1307e81SPyun YongHyeon for (i = 0; i < 1000; i++) { 345d1307e81SPyun YongHyeon DELAY(1); 346d1307e81SPyun YongHyeon if ((PHY_READ(sc, MII_BMCR) & BMCR_RESET) == 0) 347d1307e81SPyun YongHyeon break; 348d1307e81SPyun YongHyeon } 349d1307e81SPyun YongHyeon } 350d1307e81SPyun YongHyeon 351d1307e81SPyun YongHyeon static uint16_t 352d1307e81SPyun YongHyeon atphy_anar(struct ifmedia_entry *ife) 353d1307e81SPyun YongHyeon { 354d1307e81SPyun YongHyeon uint16_t anar; 355d1307e81SPyun YongHyeon 356d1307e81SPyun YongHyeon anar = 0; 357d1307e81SPyun YongHyeon switch (IFM_SUBTYPE(ife->ifm_media)) { 358d1307e81SPyun YongHyeon case IFM_AUTO: 359d1307e81SPyun YongHyeon anar |= ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10; 360d1307e81SPyun YongHyeon return (anar); 361d1307e81SPyun YongHyeon case IFM_1000_T: 362d1307e81SPyun YongHyeon return (anar); 363d1307e81SPyun YongHyeon case IFM_100_TX: 364d1307e81SPyun YongHyeon anar |= ANAR_TX; 365d1307e81SPyun YongHyeon break; 366d1307e81SPyun YongHyeon case IFM_10_T: 367d1307e81SPyun YongHyeon anar |= ANAR_10; 368d1307e81SPyun YongHyeon break; 369d1307e81SPyun YongHyeon default: 370d1307e81SPyun YongHyeon return (0); 371d1307e81SPyun YongHyeon } 372d1307e81SPyun YongHyeon 373d1307e81SPyun YongHyeon if (((ife->ifm_media & IFM_GMASK) & IFM_FDX) != 0) { 374d1307e81SPyun YongHyeon if (IFM_SUBTYPE(ife->ifm_media) == IFM_100_TX) 375d1307e81SPyun YongHyeon anar |= ANAR_TX_FD; 376d1307e81SPyun YongHyeon else 377d1307e81SPyun YongHyeon anar |= ANAR_10_FD; 378d1307e81SPyun YongHyeon } 379d1307e81SPyun YongHyeon 380d1307e81SPyun YongHyeon return (anar); 381d1307e81SPyun YongHyeon } 382d1307e81SPyun YongHyeon 383d1307e81SPyun YongHyeon static int 384*991ab941SMarius Strobl atphy_setmedia(struct mii_softc *sc, int media) 385d1307e81SPyun YongHyeon { 386d1307e81SPyun YongHyeon uint16_t anar; 387d1307e81SPyun YongHyeon 388*991ab941SMarius Strobl anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; 389*991ab941SMarius Strobl if (((IFM_SUBTYPE(media) == IFM_AUTO || 390*991ab941SMarius Strobl ((media & IFM_GMASK) & IFM_FDX) != 0) && 391*991ab941SMarius Strobl ((media & IFM_GMASK) & IFM_FLOW) != 0) || 392*991ab941SMarius Strobl (sc->mii_flags & MIIF_FORCEPAUSE) != 0) 393*991ab941SMarius Strobl anar |= ANAR_PAUSE_TOWARDS; 394*991ab941SMarius Strobl PHY_WRITE(sc, MII_ANAR, anar); 395d1307e81SPyun YongHyeon if ((sc->mii_extcapabilities & (EXTSR_1000TFDX | EXTSR_1000THDX)) != 0) 396d1307e81SPyun YongHyeon PHY_WRITE(sc, MII_100T2CR, GTCR_ADV_1000TFDX | 397d1307e81SPyun YongHyeon GTCR_ADV_1000THDX); 398d1307e81SPyun YongHyeon PHY_WRITE(sc, MII_BMCR, BMCR_RESET | BMCR_AUTOEN | BMCR_STARTNEG); 399d1307e81SPyun YongHyeon 400d1307e81SPyun YongHyeon return (EJUSTRETURN); 401d1307e81SPyun YongHyeon } 402