1179098Syongari/*- 2179098Syongari * Copyright (c) 2008, Pyun YongHyeon <yongari@FreeBSD.org> 3179098Syongari * All rights reserved. 4179098Syongari * 5179098Syongari * Redistribution and use in source and binary forms, with or without 6179098Syongari * modification, are permitted provided that the following conditions 7179098Syongari * are met: 8179098Syongari * 1. Redistributions of source code must retain the above copyright 9179098Syongari * notice unmodified, this list of conditions, and the following 10179098Syongari * disclaimer. 11179098Syongari * 2. Redistributions in binary form must reproduce the above copyright 12179098Syongari * notice, this list of conditions and the following disclaimer in the 13179098Syongari * documentation and/or other materials provided with the distribution. 14179098Syongari * 15179098Syongari * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16179098Syongari * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17179098Syongari * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18179098Syongari * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19179098Syongari * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20179098Syongari * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21179098Syongari * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22179098Syongari * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23179098Syongari * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24179098Syongari * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25179098Syongari * SUCH DAMAGE. 26179098Syongari */ 27179098Syongari 28179098Syongari#include <sys/cdefs.h> 29179098Syongari__FBSDID("$FreeBSD$"); 30179098Syongari 31179098Syongari/* 32179098Syongari * Driver for the Attansic/Atheros F1 10/100/1000 PHY. 33179098Syongari */ 34179098Syongari 35179098Syongari#include <sys/param.h> 36179098Syongari#include <sys/systm.h> 37179098Syongari#include <sys/kernel.h> 38179098Syongari#include <sys/module.h> 39179098Syongari#include <sys/socket.h> 40179098Syongari#include <sys/bus.h> 41179098Syongari 42179098Syongari#include <net/if.h> 43179098Syongari#include <net/if_media.h> 44179098Syongari 45179098Syongari#include <dev/mii/mii.h> 46179098Syongari#include <dev/mii/miivar.h> 47179098Syongari#include "miidevs.h" 48179098Syongari 49179098Syongari#include <dev/mii/atphyreg.h> 50179098Syongari 51179098Syongari#include "miibus_if.h" 52179098Syongari 53179098Syongaristatic int atphy_probe(device_t); 54179098Syongaristatic int atphy_attach(device_t); 55179098Syongari 56179098Syongaristatic device_method_t atphy_methods[] = { 57179098Syongari /* Device interface. */ 58179098Syongari DEVMETHOD(device_probe, atphy_probe), 59179098Syongari DEVMETHOD(device_attach, atphy_attach), 60179098Syongari DEVMETHOD(device_detach, mii_phy_detach), 61179098Syongari DEVMETHOD(device_shutdown, bus_generic_shutdown), 62227908Smarius DEVMETHOD_END 63179098Syongari}; 64179098Syongari 65179098Syongaristatic devclass_t atphy_devclass; 66179098Syongaristatic driver_t atphy_driver = { 67179098Syongari "atphy", 68179098Syongari atphy_methods, 69221407Smarius sizeof(struct mii_softc) 70179098Syongari}; 71179098Syongari 72179098SyongariDRIVER_MODULE(atphy, miibus, atphy_driver, atphy_devclass, 0, 0); 73179098Syongari 74179098Syongaristatic int atphy_service(struct mii_softc *, struct mii_data *, int); 75179098Syongaristatic void atphy_status(struct mii_softc *); 76179098Syongaristatic void atphy_reset(struct mii_softc *); 77179098Syongaristatic uint16_t atphy_anar(struct ifmedia_entry *); 78215298Smariusstatic int atphy_setmedia(struct mii_softc *, int); 79179098Syongari 80179098Syongaristatic const struct mii_phydesc atphys[] = { 81221407Smarius MII_PHY_DESC(xxATHEROS, F1), 82221407Smarius MII_PHY_DESC(xxATHEROS, F1_7), 83257751Snwhitehorn MII_PHY_DESC(xxATHEROS, AR8021), 84221407Smarius MII_PHY_DESC(xxATHEROS, F2), 85179098Syongari MII_PHY_END 86179098Syongari}; 87179098Syongari 88221407Smariusstatic const struct mii_phy_funcs atphy_funcs = { 89221407Smarius atphy_service, 90221407Smarius atphy_status, 91221407Smarius atphy_reset 92221407Smarius}; 93221407Smarius 94179098Syongaristatic int 95179098Syongariatphy_probe(device_t dev) 96179098Syongari{ 97179098Syongari 98179098Syongari return (mii_phy_dev_probe(dev, atphys, BUS_PROBE_DEFAULT)); 99179098Syongari} 100179098Syongari 101179098Syongaristatic int 102179098Syongariatphy_attach(device_t dev) 103179098Syongari{ 104179098Syongari 105221407Smarius mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &atphy_funcs, 1); 106213364Smarius return (0); 107179098Syongari} 108179098Syongari 109179098Syongaristatic int 110179098Syongariatphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 111179098Syongari{ 112179098Syongari struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 113179098Syongari uint16_t anar, bmcr, bmsr; 114179098Syongari 115179098Syongari switch (cmd) { 116179098Syongari case MII_POLLSTAT: 117179098Syongari break; 118179098Syongari 119179098Syongari case MII_MEDIACHG: 120179098Syongari if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO || 121179098Syongari IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { 122215298Smarius atphy_setmedia(sc, ife->ifm_media); 123179098Syongari break; 124179098Syongari } 125179098Syongari 126179098Syongari bmcr = 0; 127179098Syongari switch (IFM_SUBTYPE(ife->ifm_media)) { 128179098Syongari case IFM_100_TX: 129179098Syongari bmcr = BMCR_S100; 130179098Syongari break; 131179098Syongari case IFM_10_T: 132179098Syongari bmcr = BMCR_S10; 133179098Syongari break; 134179098Syongari case IFM_NONE: 135179098Syongari bmcr = PHY_READ(sc, MII_BMCR); 136179098Syongari /* 137179098Syongari * XXX 138179098Syongari * Due to an unknown reason powering down PHY resulted 139215298Smarius * in unexpected results such as inaccessibility of 140179098Syongari * hardware of freshly rebooted system. Disable 141179098Syongari * powering down PHY until I got more information for 142179098Syongari * Attansic/Atheros PHY hardwares. 143179098Syongari */ 144179098Syongari PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO); 145179098Syongari goto done; 146179098Syongari default: 147179098Syongari return (EINVAL); 148179098Syongari } 149179098Syongari 150179098Syongari anar = atphy_anar(ife); 151217412Smarius if ((ife->ifm_media & IFM_FDX) != 0) { 152179098Syongari bmcr |= BMCR_FDX; 153217412Smarius if ((ife->ifm_media & IFM_FLOW) != 0 || 154215298Smarius (sc->mii_flags & MIIF_FORCEPAUSE) != 0) 155215298Smarius anar |= ANAR_PAUSE_TOWARDS; 156179098Syongari } 157179098Syongari 158179098Syongari if ((sc->mii_extcapabilities & (EXTSR_1000TFDX | 159179098Syongari EXTSR_1000THDX)) != 0) 160179098Syongari PHY_WRITE(sc, MII_100T2CR, 0); 161179098Syongari PHY_WRITE(sc, MII_ANAR, anar | ANAR_CSMA); 162179098Syongari 163179098Syongari /* 164179098Syongari * Reset the PHY so all changes take effect. 165179098Syongari */ 166184253Syongari PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_RESET | BMCR_AUTOEN | 167184253Syongari BMCR_STARTNEG); 168179098Syongaridone: 169179098Syongari break; 170179098Syongari 171179098Syongari case MII_TICK: 172179098Syongari /* 173179098Syongari * Only used for autonegotiation. 174179098Syongari */ 175179098Syongari if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { 176179098Syongari sc->mii_ticks = 0; 177179098Syongari break; 178179098Syongari } 179179098Syongari 180179098Syongari /* 181215298Smarius * Check for link. 182179098Syongari * Read the status register twice; BMSR_LINK is latch-low. 183179098Syongari */ 184179098Syongari bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 185179098Syongari if (bmsr & BMSR_LINK) { 186179098Syongari sc->mii_ticks = 0; 187179098Syongari break; 188179098Syongari } 189179098Syongari 190179098Syongari /* Announce link loss right after it happens. */ 191179098Syongari if (sc->mii_ticks++ == 0) 192179098Syongari break; 193179098Syongari if (sc->mii_ticks <= sc->mii_anegticks) 194179098Syongari return (0); 195179098Syongari 196179098Syongari sc->mii_ticks = 0; 197215298Smarius atphy_setmedia(sc, ife->ifm_media); 198179098Syongari break; 199179098Syongari } 200179098Syongari 201179098Syongari /* Update the media status. */ 202221407Smarius PHY_STATUS(sc); 203179098Syongari 204179098Syongari /* Callback if something changed. */ 205179098Syongari mii_phy_update(sc, cmd); 206179098Syongari return (0); 207179098Syongari} 208179098Syongari 209179098Syongaristatic void 210179098Syongariatphy_status(struct mii_softc *sc) 211179098Syongari{ 212179098Syongari struct mii_data *mii = sc->mii_pdata; 213179098Syongari uint32_t bmsr, bmcr, ssr; 214179098Syongari 215179098Syongari mii->mii_media_status = IFM_AVALID; 216179098Syongari mii->mii_media_active = IFM_ETHER; 217179098Syongari 218179098Syongari bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 219179098Syongari if ((bmsr & BMSR_LINK) != 0) 220179098Syongari mii->mii_media_status |= IFM_ACTIVE; 221179098Syongari 222179098Syongari bmcr = PHY_READ(sc, MII_BMCR); 223179098Syongari if ((bmcr & BMCR_ISO) != 0) { 224179098Syongari mii->mii_media_active |= IFM_NONE; 225179098Syongari mii->mii_media_status = 0; 226179098Syongari return; 227179098Syongari } 228179098Syongari 229179098Syongari if ((bmcr & BMCR_LOOP) != 0) 230179098Syongari mii->mii_media_active |= IFM_LOOP; 231179098Syongari 232179098Syongari ssr = PHY_READ(sc, ATPHY_SSR); 233179098Syongari if ((ssr & ATPHY_SSR_SPD_DPLX_RESOLVED) == 0) { 234179098Syongari /* Erg, still trying, I guess... */ 235179098Syongari mii->mii_media_active |= IFM_NONE; 236179098Syongari return; 237179098Syongari } 238179098Syongari 239179098Syongari switch (ssr & ATPHY_SSR_SPEED_MASK) { 240179098Syongari case ATPHY_SSR_1000MBS: 241179098Syongari mii->mii_media_active |= IFM_1000_T; 242179098Syongari /* 243215298Smarius * atphy(4) has a valid link so reset mii_ticks. 244179098Syongari * Resetting mii_ticks is needed in order to 245179098Syongari * detect link loss after auto-negotiation. 246179098Syongari */ 247179098Syongari sc->mii_ticks = 0; 248179098Syongari break; 249179098Syongari case ATPHY_SSR_100MBS: 250179098Syongari mii->mii_media_active |= IFM_100_TX; 251179098Syongari sc->mii_ticks = 0; 252179098Syongari break; 253179098Syongari case ATPHY_SSR_10MBS: 254179098Syongari mii->mii_media_active |= IFM_10_T; 255179098Syongari sc->mii_ticks = 0; 256179098Syongari break; 257179098Syongari default: 258179098Syongari mii->mii_media_active |= IFM_NONE; 259179098Syongari return; 260179098Syongari } 261179098Syongari 262179098Syongari if ((ssr & ATPHY_SSR_DUPLEX) != 0) 263215298Smarius mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc); 264179098Syongari else 265179098Syongari mii->mii_media_active |= IFM_HDX; 266179098Syongari 267215298Smarius if ((IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) && 268215298Smarius (PHY_READ(sc, MII_100T2SR) & GTSR_MS_RES) != 0) 269215298Smarius mii->mii_media_active |= IFM_ETH_MASTER; 270179098Syongari} 271179098Syongari 272179098Syongaristatic void 273179098Syongariatphy_reset(struct mii_softc *sc) 274179098Syongari{ 275215459Smarius struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur; 276179098Syongari uint32_t reg; 277179098Syongari int i; 278179098Syongari 279179098Syongari /* Take PHY out of power down mode. */ 280179098Syongari PHY_WRITE(sc, 29, 0x29); 281179098Syongari PHY_WRITE(sc, 30, 0); 282179098Syongari 283179098Syongari reg = PHY_READ(sc, ATPHY_SCR); 284179098Syongari /* Enable automatic crossover. */ 285179098Syongari reg |= ATPHY_SCR_AUTO_X_MODE; 286179098Syongari /* Disable power down. */ 287179098Syongari reg &= ~ATPHY_SCR_MAC_PDOWN; 288179098Syongari /* Enable CRS on Tx. */ 289179098Syongari reg |= ATPHY_SCR_ASSERT_CRS_ON_TX; 290179098Syongari /* Auto correction for reversed cable polarity. */ 291179098Syongari reg |= ATPHY_SCR_POLARITY_REVERSAL; 292179098Syongari PHY_WRITE(sc, ATPHY_SCR, reg); 293179098Syongari 294179098Syongari /* Workaround F1 bug to reset phy. */ 295215459Smarius atphy_setmedia(sc, ife == NULL ? IFM_AUTO : ife->ifm_media); 296179098Syongari 297179098Syongari for (i = 0; i < 1000; i++) { 298179098Syongari DELAY(1); 299179098Syongari if ((PHY_READ(sc, MII_BMCR) & BMCR_RESET) == 0) 300179098Syongari break; 301179098Syongari } 302179098Syongari} 303179098Syongari 304179098Syongaristatic uint16_t 305179098Syongariatphy_anar(struct ifmedia_entry *ife) 306179098Syongari{ 307179098Syongari uint16_t anar; 308179098Syongari 309179098Syongari anar = 0; 310179098Syongari switch (IFM_SUBTYPE(ife->ifm_media)) { 311179098Syongari case IFM_AUTO: 312179098Syongari anar |= ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10; 313179098Syongari return (anar); 314179098Syongari case IFM_1000_T: 315179098Syongari return (anar); 316179098Syongari case IFM_100_TX: 317179098Syongari anar |= ANAR_TX; 318179098Syongari break; 319179098Syongari case IFM_10_T: 320179098Syongari anar |= ANAR_10; 321179098Syongari break; 322179098Syongari default: 323179098Syongari return (0); 324179098Syongari } 325179098Syongari 326217412Smarius if ((ife->ifm_media & IFM_FDX) != 0) { 327179098Syongari if (IFM_SUBTYPE(ife->ifm_media) == IFM_100_TX) 328179098Syongari anar |= ANAR_TX_FD; 329179098Syongari else 330179098Syongari anar |= ANAR_10_FD; 331179098Syongari } 332179098Syongari 333179098Syongari return (anar); 334179098Syongari} 335179098Syongari 336179098Syongaristatic int 337215298Smariusatphy_setmedia(struct mii_softc *sc, int media) 338179098Syongari{ 339179098Syongari uint16_t anar; 340179098Syongari 341215298Smarius anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; 342217412Smarius if ((IFM_SUBTYPE(media) == IFM_AUTO || (media & IFM_FDX) != 0) && 343217412Smarius ((media & IFM_FLOW) != 0 || 344217412Smarius (sc->mii_flags & MIIF_FORCEPAUSE) != 0)) 345215298Smarius anar |= ANAR_PAUSE_TOWARDS; 346215298Smarius PHY_WRITE(sc, MII_ANAR, anar); 347217412Smarius if ((sc->mii_extcapabilities & 348217412Smarius (EXTSR_1000TFDX | EXTSR_1000THDX)) != 0) 349179098Syongari PHY_WRITE(sc, MII_100T2CR, GTCR_ADV_1000TFDX | 350179098Syongari GTCR_ADV_1000THDX); 351221817Syongari else if (sc->mii_mpd_model == MII_MODEL_xxATHEROS_F1) { 352221817Syongari /* 353221817Syongari * AR8132 has 10/100 PHY and the PHY uses the same 354221817Syongari * model number of F1 gigabit PHY. The PHY has no 355221817Syongari * ability to establish gigabit link so explicitly 356221817Syongari * disable 1000baseT configuration for the PHY. 357221817Syongari * Otherwise, there is a case that atphy(4) could 358221817Syongari * not establish a link against gigabit link partner 359221817Syongari * unless the link partner supports down-shifting. 360221817Syongari */ 361221817Syongari PHY_WRITE(sc, MII_100T2CR, 0); 362221817Syongari } 363179098Syongari PHY_WRITE(sc, MII_BMCR, BMCR_RESET | BMCR_AUTOEN | BMCR_STARTNEG); 364179098Syongari 365179098Syongari return (EJUSTRETURN); 366179098Syongari} 367