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 *); 85d1307e81SPyun YongHyeon static int atphy_auto(struct mii_softc *); 86d1307e81SPyun YongHyeon 87d1307e81SPyun YongHyeon static const struct mii_phydesc atphys[] = { 88d1307e81SPyun YongHyeon MII_PHY_DESC(ATHEROS, F1), 89ba26d470SStanislav Sedov MII_PHY_DESC(ATHEROS, F2), 90d1307e81SPyun YongHyeon MII_PHY_END 91d1307e81SPyun YongHyeon }; 92d1307e81SPyun YongHyeon 93d1307e81SPyun YongHyeon static int 94d1307e81SPyun YongHyeon atphy_probe(device_t dev) 95d1307e81SPyun YongHyeon { 96d1307e81SPyun YongHyeon 97d1307e81SPyun YongHyeon return (mii_phy_dev_probe(dev, atphys, BUS_PROBE_DEFAULT)); 98d1307e81SPyun YongHyeon } 99d1307e81SPyun YongHyeon 100d1307e81SPyun YongHyeon static int 101d1307e81SPyun YongHyeon atphy_attach(device_t dev) 102d1307e81SPyun YongHyeon { 103d1307e81SPyun YongHyeon struct atphy_softc *asc; 104d1307e81SPyun YongHyeon struct mii_softc *sc; 105d1307e81SPyun YongHyeon struct mii_attach_args *ma; 106d1307e81SPyun YongHyeon struct mii_data *mii; 107d1307e81SPyun YongHyeon 108d1307e81SPyun YongHyeon asc = device_get_softc(dev); 109d1307e81SPyun YongHyeon sc = &asc->mii_sc; 110d1307e81SPyun YongHyeon ma = device_get_ivars(dev); 111d1307e81SPyun YongHyeon sc->mii_dev = device_get_parent(dev); 112d1307e81SPyun YongHyeon mii = device_get_softc(sc->mii_dev); 113d1307e81SPyun YongHyeon LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 114d1307e81SPyun YongHyeon 115d1307e81SPyun YongHyeon sc->mii_inst = mii->mii_instance; 116d1307e81SPyun YongHyeon sc->mii_phy = ma->mii_phyno; 117d1307e81SPyun YongHyeon sc->mii_service = atphy_service; 118d1307e81SPyun YongHyeon sc->mii_pdata = mii; 119d1307e81SPyun YongHyeon sc->mii_anegticks = MII_ANEGTICKS_GIGE; 120d1307e81SPyun YongHyeon 121d1307e81SPyun YongHyeon mii->mii_instance++; 122d1307e81SPyun YongHyeon 123d1307e81SPyun YongHyeon asc->mii_oui = MII_OUI(ma->mii_id1, ma->mii_id2); 124d1307e81SPyun YongHyeon asc->mii_model = MII_MODEL(ma->mii_id2); 125d1307e81SPyun YongHyeon asc->mii_rev = MII_REV(ma->mii_id2); 126d1307e81SPyun YongHyeon if (bootverbose) 127d1307e81SPyun YongHyeon device_printf(dev, "OUI 0x%06x, model 0x%04x, rev. %d\n", 128d1307e81SPyun YongHyeon asc->mii_oui, asc->mii_model, asc->mii_rev); 129d1307e81SPyun YongHyeon 130d1307e81SPyun YongHyeon atphy_reset(sc); 131d1307e81SPyun YongHyeon 132d1307e81SPyun YongHyeon sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 133d1307e81SPyun YongHyeon if (sc->mii_capabilities & BMSR_EXTSTAT) 134d1307e81SPyun YongHyeon sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); 135d1307e81SPyun YongHyeon device_printf(dev, " "); 136d1307e81SPyun YongHyeon mii_phy_add_media(sc); 137d1307e81SPyun YongHyeon printf("\n"); 138d1307e81SPyun YongHyeon 139d1307e81SPyun YongHyeon MIIBUS_MEDIAINIT(sc->mii_dev); 140d1307e81SPyun YongHyeon return(0); 141d1307e81SPyun YongHyeon } 142d1307e81SPyun YongHyeon 143d1307e81SPyun YongHyeon static int 144d1307e81SPyun YongHyeon atphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 145d1307e81SPyun YongHyeon { 146d1307e81SPyun YongHyeon struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 147d1307e81SPyun YongHyeon uint16_t anar, bmcr, bmsr; 148d1307e81SPyun YongHyeon 149d1307e81SPyun YongHyeon switch (cmd) { 150d1307e81SPyun YongHyeon case MII_POLLSTAT: 151d1307e81SPyun YongHyeon /* 152d1307e81SPyun YongHyeon * If we're not polling our PHY instance, just return. 153d1307e81SPyun YongHyeon */ 154d1307e81SPyun YongHyeon if (IFM_INST(ife->ifm_media) != sc->mii_inst) 155d1307e81SPyun YongHyeon return (0); 156d1307e81SPyun YongHyeon break; 157d1307e81SPyun YongHyeon 158d1307e81SPyun YongHyeon case MII_MEDIACHG: 159d1307e81SPyun YongHyeon /* 160d1307e81SPyun YongHyeon * If the media indicates a different PHY instance, 161d1307e81SPyun YongHyeon * isolate ourselves. 162d1307e81SPyun YongHyeon */ 163d1307e81SPyun YongHyeon if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 164d1307e81SPyun YongHyeon bmcr = PHY_READ(sc, MII_BMCR); 165d1307e81SPyun YongHyeon PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO); 166d1307e81SPyun YongHyeon return (0); 167d1307e81SPyun YongHyeon } 168d1307e81SPyun YongHyeon 169d1307e81SPyun YongHyeon /* 170d1307e81SPyun YongHyeon * If the interface is not up, don't do anything. 171d1307e81SPyun YongHyeon */ 172d1307e81SPyun YongHyeon if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 173d1307e81SPyun YongHyeon break; 174d1307e81SPyun YongHyeon 175d1307e81SPyun YongHyeon if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO || 176d1307e81SPyun YongHyeon IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { 177d1307e81SPyun YongHyeon atphy_auto(sc); 178d1307e81SPyun YongHyeon break; 179d1307e81SPyun YongHyeon } 180d1307e81SPyun YongHyeon 181d1307e81SPyun YongHyeon bmcr = 0; 182d1307e81SPyun YongHyeon switch (IFM_SUBTYPE(ife->ifm_media)) { 183d1307e81SPyun YongHyeon case IFM_100_TX: 184d1307e81SPyun YongHyeon bmcr = BMCR_S100; 185d1307e81SPyun YongHyeon break; 186d1307e81SPyun YongHyeon case IFM_10_T: 187d1307e81SPyun YongHyeon bmcr = BMCR_S10; 188d1307e81SPyun YongHyeon break; 189d1307e81SPyun YongHyeon case IFM_NONE: 190d1307e81SPyun YongHyeon bmcr = PHY_READ(sc, MII_BMCR); 191d1307e81SPyun YongHyeon /* 192d1307e81SPyun YongHyeon * XXX 193d1307e81SPyun YongHyeon * Due to an unknown reason powering down PHY resulted 194d1307e81SPyun YongHyeon * in unexpected results such as inaccessbility of 195d1307e81SPyun YongHyeon * hardware of freshly rebooted system. Disable 196d1307e81SPyun YongHyeon * powering down PHY until I got more information for 197d1307e81SPyun YongHyeon * Attansic/Atheros PHY hardwares. 198d1307e81SPyun YongHyeon */ 199d1307e81SPyun YongHyeon PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO); 200d1307e81SPyun YongHyeon goto done; 201d1307e81SPyun YongHyeon default: 202d1307e81SPyun YongHyeon return (EINVAL); 203d1307e81SPyun YongHyeon } 204d1307e81SPyun YongHyeon 205d1307e81SPyun YongHyeon anar = atphy_anar(ife); 206d1307e81SPyun YongHyeon if (((ife->ifm_media & IFM_GMASK) & IFM_FDX) != 0) { 207d1307e81SPyun YongHyeon bmcr |= BMCR_FDX; 208d1307e81SPyun YongHyeon /* Enable pause. */ 209d1307e81SPyun YongHyeon anar |= (3 << 10); 210d1307e81SPyun YongHyeon } 211d1307e81SPyun YongHyeon 212d1307e81SPyun YongHyeon if ((sc->mii_extcapabilities & (EXTSR_1000TFDX | 213d1307e81SPyun YongHyeon EXTSR_1000THDX)) != 0) 214d1307e81SPyun YongHyeon PHY_WRITE(sc, MII_100T2CR, 0); 215d1307e81SPyun YongHyeon PHY_WRITE(sc, MII_ANAR, anar | ANAR_CSMA); 216d1307e81SPyun YongHyeon 217d1307e81SPyun YongHyeon /* 218d1307e81SPyun YongHyeon * Reset the PHY so all changes take effect. 219d1307e81SPyun YongHyeon */ 220d2cd2263SPyun YongHyeon PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_RESET | BMCR_AUTOEN | 221d2cd2263SPyun YongHyeon BMCR_STARTNEG); 222d1307e81SPyun YongHyeon done: 223d1307e81SPyun YongHyeon break; 224d1307e81SPyun YongHyeon 225d1307e81SPyun YongHyeon case MII_TICK: 226d1307e81SPyun YongHyeon /* 227d1307e81SPyun YongHyeon * If we're not currently selected, just return. 228d1307e81SPyun YongHyeon */ 229d1307e81SPyun YongHyeon if (IFM_INST(ife->ifm_media) != sc->mii_inst) 230d1307e81SPyun YongHyeon return (0); 231d1307e81SPyun YongHyeon 232d1307e81SPyun YongHyeon /* 233d1307e81SPyun YongHyeon * Is the interface even up? 234d1307e81SPyun YongHyeon */ 235d1307e81SPyun YongHyeon if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 236d1307e81SPyun YongHyeon return (0); 237d1307e81SPyun YongHyeon 238d1307e81SPyun YongHyeon /* 239d1307e81SPyun YongHyeon * Only used for autonegotiation. 240d1307e81SPyun YongHyeon */ 241d1307e81SPyun YongHyeon if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { 242d1307e81SPyun YongHyeon sc->mii_ticks = 0; 243d1307e81SPyun YongHyeon break; 244d1307e81SPyun YongHyeon } 245d1307e81SPyun YongHyeon 246d1307e81SPyun YongHyeon /* 247d1307e81SPyun YongHyeon * check for link. 248d1307e81SPyun YongHyeon * Read the status register twice; BMSR_LINK is latch-low. 249d1307e81SPyun YongHyeon */ 250d1307e81SPyun YongHyeon bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 251d1307e81SPyun YongHyeon if (bmsr & BMSR_LINK) { 252d1307e81SPyun YongHyeon sc->mii_ticks = 0; 253d1307e81SPyun YongHyeon break; 254d1307e81SPyun YongHyeon } 255d1307e81SPyun YongHyeon 256d1307e81SPyun YongHyeon /* Announce link loss right after it happens. */ 257d1307e81SPyun YongHyeon if (sc->mii_ticks++ == 0) 258d1307e81SPyun YongHyeon break; 259d1307e81SPyun YongHyeon if (sc->mii_ticks <= sc->mii_anegticks) 260d1307e81SPyun YongHyeon return (0); 261d1307e81SPyun YongHyeon 262d1307e81SPyun YongHyeon sc->mii_ticks = 0; 263d1307e81SPyun YongHyeon atphy_auto(sc); 264d1307e81SPyun YongHyeon break; 265d1307e81SPyun YongHyeon } 266d1307e81SPyun YongHyeon 267d1307e81SPyun YongHyeon /* Update the media status. */ 268d1307e81SPyun YongHyeon atphy_status(sc); 269d1307e81SPyun YongHyeon 270d1307e81SPyun YongHyeon /* Callback if something changed. */ 271d1307e81SPyun YongHyeon mii_phy_update(sc, cmd); 272d1307e81SPyun YongHyeon return (0); 273d1307e81SPyun YongHyeon } 274d1307e81SPyun YongHyeon 275d1307e81SPyun YongHyeon static void 276d1307e81SPyun YongHyeon atphy_status(struct mii_softc *sc) 277d1307e81SPyun YongHyeon { 278d1307e81SPyun YongHyeon struct mii_data *mii = sc->mii_pdata; 279d1307e81SPyun YongHyeon uint32_t bmsr, bmcr, ssr; 280d1307e81SPyun YongHyeon 281d1307e81SPyun YongHyeon mii->mii_media_status = IFM_AVALID; 282d1307e81SPyun YongHyeon mii->mii_media_active = IFM_ETHER; 283d1307e81SPyun YongHyeon 284d1307e81SPyun YongHyeon bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 285d1307e81SPyun YongHyeon if ((bmsr & BMSR_LINK) != 0) 286d1307e81SPyun YongHyeon mii->mii_media_status |= IFM_ACTIVE; 287d1307e81SPyun YongHyeon 288d1307e81SPyun YongHyeon bmcr = PHY_READ(sc, MII_BMCR); 289d1307e81SPyun YongHyeon if ((bmcr & BMCR_ISO) != 0) { 290d1307e81SPyun YongHyeon mii->mii_media_active |= IFM_NONE; 291d1307e81SPyun YongHyeon mii->mii_media_status = 0; 292d1307e81SPyun YongHyeon return; 293d1307e81SPyun YongHyeon } 294d1307e81SPyun YongHyeon 295d1307e81SPyun YongHyeon if ((bmcr & BMCR_LOOP) != 0) 296d1307e81SPyun YongHyeon mii->mii_media_active |= IFM_LOOP; 297d1307e81SPyun YongHyeon 298d1307e81SPyun YongHyeon ssr = PHY_READ(sc, ATPHY_SSR); 299d1307e81SPyun YongHyeon if ((ssr & ATPHY_SSR_SPD_DPLX_RESOLVED) == 0) { 300d1307e81SPyun YongHyeon /* Erg, still trying, I guess... */ 301d1307e81SPyun YongHyeon mii->mii_media_active |= IFM_NONE; 302d1307e81SPyun YongHyeon return; 303d1307e81SPyun YongHyeon } 304d1307e81SPyun YongHyeon 305d1307e81SPyun YongHyeon switch (ssr & ATPHY_SSR_SPEED_MASK) { 306d1307e81SPyun YongHyeon case ATPHY_SSR_1000MBS: 307d1307e81SPyun YongHyeon mii->mii_media_active |= IFM_1000_T; 308d1307e81SPyun YongHyeon /* 309d1307e81SPyun YongHyeon * atphy(4) got a valid link so reset mii_ticks. 310d1307e81SPyun YongHyeon * Resetting mii_ticks is needed in order to 311d1307e81SPyun YongHyeon * detect link loss after auto-negotiation. 312d1307e81SPyun YongHyeon */ 313d1307e81SPyun YongHyeon sc->mii_ticks = 0; 314d1307e81SPyun YongHyeon break; 315d1307e81SPyun YongHyeon case ATPHY_SSR_100MBS: 316d1307e81SPyun YongHyeon mii->mii_media_active |= IFM_100_TX; 317d1307e81SPyun YongHyeon sc->mii_ticks = 0; 318d1307e81SPyun YongHyeon break; 319d1307e81SPyun YongHyeon case ATPHY_SSR_10MBS: 320d1307e81SPyun YongHyeon mii->mii_media_active |= IFM_10_T; 321d1307e81SPyun YongHyeon sc->mii_ticks = 0; 322d1307e81SPyun YongHyeon break; 323d1307e81SPyun YongHyeon default: 324d1307e81SPyun YongHyeon mii->mii_media_active |= IFM_NONE; 325d1307e81SPyun YongHyeon return; 326d1307e81SPyun YongHyeon } 327d1307e81SPyun YongHyeon 328d1307e81SPyun YongHyeon if ((ssr & ATPHY_SSR_DUPLEX) != 0) 329d1307e81SPyun YongHyeon mii->mii_media_active |= IFM_FDX; 330d1307e81SPyun YongHyeon else 331d1307e81SPyun YongHyeon mii->mii_media_active |= IFM_HDX; 332d1307e81SPyun YongHyeon 333d1307e81SPyun YongHyeon /* XXX Master/Slave, Flow-control */ 334d1307e81SPyun YongHyeon } 335d1307e81SPyun YongHyeon 336d1307e81SPyun YongHyeon static void 337d1307e81SPyun YongHyeon atphy_reset(struct mii_softc *sc) 338d1307e81SPyun YongHyeon { 339d1307e81SPyun YongHyeon struct atphy_softc *asc; 340d1307e81SPyun YongHyeon uint32_t reg; 341d1307e81SPyun YongHyeon int i; 342d1307e81SPyun YongHyeon 343d1307e81SPyun YongHyeon asc = (struct atphy_softc *)sc; 344d1307e81SPyun YongHyeon 345d1307e81SPyun YongHyeon /* Take PHY out of power down mode. */ 346d1307e81SPyun YongHyeon PHY_WRITE(sc, 29, 0x29); 347d1307e81SPyun YongHyeon PHY_WRITE(sc, 30, 0); 348d1307e81SPyun YongHyeon 349d1307e81SPyun YongHyeon reg = PHY_READ(sc, ATPHY_SCR); 350d1307e81SPyun YongHyeon /* Enable automatic crossover. */ 351d1307e81SPyun YongHyeon reg |= ATPHY_SCR_AUTO_X_MODE; 352d1307e81SPyun YongHyeon /* Disable power down. */ 353d1307e81SPyun YongHyeon reg &= ~ATPHY_SCR_MAC_PDOWN; 354d1307e81SPyun YongHyeon /* Enable CRS on Tx. */ 355d1307e81SPyun YongHyeon reg |= ATPHY_SCR_ASSERT_CRS_ON_TX; 356d1307e81SPyun YongHyeon /* Auto correction for reversed cable polarity. */ 357d1307e81SPyun YongHyeon reg |= ATPHY_SCR_POLARITY_REVERSAL; 358d1307e81SPyun YongHyeon PHY_WRITE(sc, ATPHY_SCR, reg); 359d1307e81SPyun YongHyeon 360d1307e81SPyun YongHyeon /* Workaround F1 bug to reset phy. */ 361d1307e81SPyun YongHyeon atphy_auto(sc); 362d1307e81SPyun YongHyeon 363d1307e81SPyun YongHyeon for (i = 0; i < 1000; i++) { 364d1307e81SPyun YongHyeon DELAY(1); 365d1307e81SPyun YongHyeon if ((PHY_READ(sc, MII_BMCR) & BMCR_RESET) == 0) 366d1307e81SPyun YongHyeon break; 367d1307e81SPyun YongHyeon } 368d1307e81SPyun YongHyeon } 369d1307e81SPyun YongHyeon 370d1307e81SPyun YongHyeon static uint16_t 371d1307e81SPyun YongHyeon atphy_anar(struct ifmedia_entry *ife) 372d1307e81SPyun YongHyeon { 373d1307e81SPyun YongHyeon uint16_t anar; 374d1307e81SPyun YongHyeon 375d1307e81SPyun YongHyeon anar = 0; 376d1307e81SPyun YongHyeon switch (IFM_SUBTYPE(ife->ifm_media)) { 377d1307e81SPyun YongHyeon case IFM_AUTO: 378d1307e81SPyun YongHyeon anar |= ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10; 379d1307e81SPyun YongHyeon return (anar); 380d1307e81SPyun YongHyeon case IFM_1000_T: 381d1307e81SPyun YongHyeon return (anar); 382d1307e81SPyun YongHyeon case IFM_100_TX: 383d1307e81SPyun YongHyeon anar |= ANAR_TX; 384d1307e81SPyun YongHyeon break; 385d1307e81SPyun YongHyeon case IFM_10_T: 386d1307e81SPyun YongHyeon anar |= ANAR_10; 387d1307e81SPyun YongHyeon break; 388d1307e81SPyun YongHyeon default: 389d1307e81SPyun YongHyeon return (0); 390d1307e81SPyun YongHyeon } 391d1307e81SPyun YongHyeon 392d1307e81SPyun YongHyeon if (((ife->ifm_media & IFM_GMASK) & IFM_FDX) != 0) { 393d1307e81SPyun YongHyeon if (IFM_SUBTYPE(ife->ifm_media) == IFM_100_TX) 394d1307e81SPyun YongHyeon anar |= ANAR_TX_FD; 395d1307e81SPyun YongHyeon else 396d1307e81SPyun YongHyeon anar |= ANAR_10_FD; 397d1307e81SPyun YongHyeon } 398d1307e81SPyun YongHyeon 399d1307e81SPyun YongHyeon return (anar); 400d1307e81SPyun YongHyeon } 401d1307e81SPyun YongHyeon 402d1307e81SPyun YongHyeon static int 403d1307e81SPyun YongHyeon atphy_auto(struct mii_softc *sc) 404d1307e81SPyun YongHyeon { 405d1307e81SPyun YongHyeon uint16_t anar; 406d1307e81SPyun YongHyeon 407d1307e81SPyun YongHyeon anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities); 408d1307e81SPyun YongHyeon PHY_WRITE(sc, MII_ANAR, anar | (3 << 10) | ANAR_CSMA); 409d1307e81SPyun YongHyeon if ((sc->mii_extcapabilities & (EXTSR_1000TFDX | EXTSR_1000THDX)) != 0) 410d1307e81SPyun YongHyeon PHY_WRITE(sc, MII_100T2CR, GTCR_ADV_1000TFDX | 411d1307e81SPyun YongHyeon GTCR_ADV_1000THDX); 412d1307e81SPyun YongHyeon PHY_WRITE(sc, MII_BMCR, BMCR_RESET | BMCR_AUTOEN | BMCR_STARTNEG); 413d1307e81SPyun YongHyeon 414d1307e81SPyun YongHyeon return (EJUSTRETURN); 415d1307e81SPyun YongHyeon } 416