1 /* $OpenBSD: rgephy.c,v 1.29 2008/09/17 07:19:19 brad Exp $ */ 2 /* 3 * Copyright (c) 2003 4 * Bill Paul <wpaul@windriver.com>. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Bill Paul. 17 * 4. Neither the name of the author nor the names of any co-contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31 * THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 * $FreeBSD: rgephy.c,v 1.5 2004/05/30 17:57:40 phk Exp $ 34 */ 35 36 /* 37 * Driver for the RealTek 8169S/8110S internal 10/100/1000 PHY. 38 */ 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/kernel.h> 43 #include <sys/device.h> 44 #include <sys/socket.h> 45 #include <sys/errno.h> 46 47 #include <machine/bus.h> 48 49 #include <net/if.h> 50 #include <net/if_media.h> 51 52 #include <netinet/in.h> 53 #include <netinet/if_ether.h> 54 55 #include <dev/mii/mii.h> 56 #include <dev/mii/miivar.h> 57 #include <dev/mii/miidevs.h> 58 59 #include <dev/mii/rgephyreg.h> 60 61 #include <dev/ic/rtl81x9reg.h> 62 63 int rgephymatch(struct device *, void *, void *); 64 void rgephyattach(struct device *, struct device *, void *); 65 66 struct cfattach rgephy_ca = { 67 sizeof(struct mii_softc), 68 rgephymatch, 69 rgephyattach, 70 mii_phy_detach, 71 mii_phy_activate 72 }; 73 74 struct cfdriver rgephy_cd = { 75 NULL, "rgephy", DV_DULL 76 }; 77 78 int rgephy_service(struct mii_softc *, struct mii_data *, int); 79 void rgephy_status(struct mii_softc *); 80 int rgephy_mii_phy_auto(struct mii_softc *); 81 void rgephy_reset(struct mii_softc *); 82 void rgephy_loop(struct mii_softc *); 83 void rgephy_load_dspcode(struct mii_softc *); 84 85 const struct mii_phy_funcs rgephy_funcs = { 86 rgephy_service, rgephy_status, rgephy_reset, 87 }; 88 89 static const struct mii_phydesc rgephys[] = { 90 { MII_OUI_REALTEK2, MII_MODEL_xxREALTEK_RTL8169S, 91 MII_STR_xxREALTEK_RTL8169S }, 92 { MII_OUI_xxREALTEK, MII_MODEL_xxREALTEK_RTL8169S, 93 MII_STR_xxREALTEK_RTL8169S }, 94 95 { 0, 0, 96 NULL }, 97 }; 98 99 int 100 rgephymatch(struct device *parent, void *match, void *aux) 101 { 102 struct mii_attach_args *ma = aux; 103 104 if (mii_phy_match(ma, rgephys) != NULL) 105 return (10); 106 107 return (0); 108 } 109 110 void 111 rgephyattach(struct device *parent, struct device *self, void *aux) 112 { 113 struct mii_softc *sc = (struct mii_softc *)self; 114 struct mii_attach_args *ma = aux; 115 struct mii_data *mii = ma->mii_data; 116 const struct mii_phydesc *mpd; 117 118 mpd = mii_phy_match(ma, rgephys); 119 printf(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2)); 120 121 sc->mii_inst = mii->mii_instance; 122 sc->mii_phy = ma->mii_phyno; 123 sc->mii_funcs = &rgephy_funcs; 124 sc->mii_model = MII_MODEL(ma->mii_id2); 125 sc->mii_rev = MII_REV(ma->mii_id2); 126 sc->mii_pdata = mii; 127 sc->mii_flags = ma->mii_flags; 128 sc->mii_anegticks = MII_ANEGTICKS_GIGE; 129 130 sc->mii_flags |= MIIF_NOISOLATE; 131 132 sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 133 134 if (sc->mii_capabilities & BMSR_EXTSTAT) 135 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); 136 if ((sc->mii_capabilities & BMSR_MEDIAMASK) || 137 (sc->mii_extcapabilities & EXTSR_MEDIAMASK)) 138 mii_phy_add_media(sc); 139 140 PHY_RESET(sc); 141 } 142 143 int 144 rgephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 145 { 146 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 147 int anar, reg, speed, gig = 0; 148 149 switch (cmd) { 150 case MII_POLLSTAT: 151 /* 152 * If we're not polling our PHY instance, just return. 153 */ 154 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 155 return (0); 156 break; 157 158 case MII_MEDIACHG: 159 /* 160 * If the media indicates a different PHY instance, 161 * isolate ourselves. 162 */ 163 if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 164 reg = PHY_READ(sc, MII_BMCR); 165 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 166 return (0); 167 } 168 169 /* 170 * If the interface is not up, don't do anything. 171 */ 172 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 173 break; 174 175 PHY_RESET(sc); /* XXX hardware bug work-around */ 176 177 anar = PHY_READ(sc, RGEPHY_MII_ANAR); 178 anar &= ~(RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_TX | 179 RGEPHY_ANAR_10_FD | RGEPHY_ANAR_10); 180 181 switch (IFM_SUBTYPE(ife->ifm_media)) { 182 case IFM_AUTO: 183 (void) rgephy_mii_phy_auto(sc); 184 break; 185 case IFM_1000_T: 186 speed = RGEPHY_S1000; 187 goto setit; 188 case IFM_100_TX: 189 speed = RGEPHY_S100; 190 anar |= RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_TX; 191 goto setit; 192 case IFM_10_T: 193 speed = RGEPHY_S10; 194 anar |= RGEPHY_ANAR_10_FD | RGEPHY_ANAR_10; 195 setit: 196 rgephy_loop(sc); 197 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { 198 speed |= RGEPHY_BMCR_FDX; 199 if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) 200 gig = RGEPHY_1000CTL_AFD; 201 anar &= ~(RGEPHY_ANAR_TX | RGEPHY_ANAR_10); 202 } else { 203 if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) 204 gig = RGEPHY_1000CTL_AHD; 205 anar &= 206 ~(RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_10_FD); 207 } 208 209 if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T && 210 mii->mii_media.ifm_media & IFM_ETH_MASTER) 211 gig |= RGEPHY_1000CTL_MSE|RGEPHY_1000CTL_MSC; 212 213 PHY_WRITE(sc, RGEPHY_MII_1000CTL, gig); 214 PHY_WRITE(sc, RGEPHY_MII_BMCR, speed | 215 RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG); 216 PHY_WRITE(sc, RGEPHY_MII_ANAR, anar); 217 break; 218 #if 0 219 case IFM_NONE: 220 PHY_WRITE(sc, MII_BMCR, BMCR_ISO|BMCR_PDOWN); 221 break; 222 #endif 223 default: 224 return (EINVAL); 225 } 226 break; 227 228 case MII_TICK: 229 /* 230 * If we're not currently selected, just return. 231 */ 232 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 233 return (0); 234 235 /* 236 * Is the interface even up? 237 */ 238 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 239 return (0); 240 241 /* 242 * Only used for autonegotiation. 243 */ 244 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 245 break; 246 247 /* 248 * Check to see if we have link. If we do, we don't 249 * need to restart the autonegotiation process. Read 250 * the BMSR twice in case it's latched. 251 */ 252 if (sc->mii_rev < 2) { 253 reg = PHY_READ(sc, RL_GMEDIASTAT); 254 if (reg & RL_GMEDIASTAT_LINK) 255 break; 256 } else { 257 reg = PHY_READ(sc, RGEPHY_SR); 258 if (reg & RGEPHY_SR_LINK) 259 break; 260 } 261 262 /* 263 * Only retry autonegotiation every mii_anegticks seconds. 264 */ 265 if (++sc->mii_ticks <= sc->mii_anegticks) 266 break; 267 268 sc->mii_ticks = 0; 269 rgephy_mii_phy_auto(sc); 270 return (0); 271 } 272 273 /* Update the media status. */ 274 mii_phy_status(sc); 275 276 /* 277 * Callback if something changed. Note that we need to poke 278 * the DSP on the RealTek PHYs if the media changes. 279 * 280 */ 281 if (sc->mii_media_active != mii->mii_media_active || 282 sc->mii_media_status != mii->mii_media_status || 283 cmd == MII_MEDIACHG) 284 rgephy_load_dspcode(sc); 285 286 /* Callback if something changed. */ 287 mii_phy_update(sc, cmd); 288 289 return (0); 290 } 291 292 void 293 rgephy_status(struct mii_softc *sc) 294 { 295 struct mii_data *mii = sc->mii_pdata; 296 int bmsr, bmcr, gtsr; 297 298 mii->mii_media_status = IFM_AVALID; 299 mii->mii_media_active = IFM_ETHER; 300 301 if (sc->mii_rev < 2) { 302 bmsr = PHY_READ(sc, RL_GMEDIASTAT); 303 304 if (bmsr & RL_GMEDIASTAT_LINK) 305 mii->mii_media_status |= IFM_ACTIVE; 306 } else { 307 bmsr = PHY_READ(sc, RGEPHY_SR); 308 if (bmsr & RGEPHY_SR_LINK) 309 mii->mii_media_status |= IFM_ACTIVE; 310 } 311 312 bmsr = PHY_READ(sc, RGEPHY_MII_BMSR); 313 314 bmcr = PHY_READ(sc, RGEPHY_MII_BMCR); 315 316 if (bmcr & RGEPHY_BMCR_LOOP) 317 mii->mii_media_active |= IFM_LOOP; 318 319 if (bmcr & RGEPHY_BMCR_AUTOEN) { 320 if ((bmsr & RGEPHY_BMSR_ACOMP) == 0) { 321 /* Erg, still trying, I guess... */ 322 mii->mii_media_active |= IFM_NONE; 323 return; 324 } 325 } 326 327 if (sc->mii_rev < 2) { 328 bmsr = PHY_READ(sc, RL_GMEDIASTAT); 329 if (bmsr & RL_GMEDIASTAT_1000MBPS) 330 mii->mii_media_active |= IFM_1000_T; 331 else if (bmsr & RL_GMEDIASTAT_100MBPS) 332 mii->mii_media_active |= IFM_100_TX; 333 else if (bmsr & RL_GMEDIASTAT_10MBPS) 334 mii->mii_media_active |= IFM_10_T; 335 336 if (bmsr & RL_GMEDIASTAT_FDX) 337 mii->mii_media_active |= mii_phy_flowstatus(sc) | 338 IFM_FDX; 339 else 340 mii->mii_media_active |= IFM_HDX; 341 } else { 342 bmsr = PHY_READ(sc, RGEPHY_SR); 343 if (RGEPHY_SR_SPEED(bmsr) == RGEPHY_SR_SPEED_1000MBPS) 344 mii->mii_media_active |= IFM_1000_T; 345 else if (RGEPHY_SR_SPEED(bmsr) == RGEPHY_SR_SPEED_100MBPS) 346 mii->mii_media_active |= IFM_100_TX; 347 else if (RGEPHY_SR_SPEED(bmsr) == RGEPHY_SR_SPEED_10MBPS) 348 mii->mii_media_active |= IFM_10_T; 349 350 if (bmsr & RGEPHY_SR_FDX) 351 mii->mii_media_active |= mii_phy_flowstatus(sc) | 352 IFM_FDX; 353 else 354 mii->mii_media_active |= IFM_HDX; 355 } 356 357 gtsr = PHY_READ(sc, RGEPHY_MII_1000STS); 358 if ((IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) && 359 gtsr & RGEPHY_1000STS_MSR) 360 mii->mii_media_active |= IFM_ETH_MASTER; 361 } 362 363 364 int 365 rgephy_mii_phy_auto(struct mii_softc *sc) 366 { 367 int anar; 368 369 rgephy_loop(sc); 370 PHY_RESET(sc); 371 372 anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; 373 if (sc->mii_flags & MIIF_DOPAUSE) 374 anar |= RGEPHY_ANAR_PC | RGEPHY_ANAR_ASP; 375 376 PHY_WRITE(sc, RGEPHY_MII_ANAR, anar); 377 DELAY(1000); 378 PHY_WRITE(sc, RGEPHY_MII_1000CTL, 379 RGEPHY_1000CTL_AHD | RGEPHY_1000CTL_AFD); 380 DELAY(1000); 381 PHY_WRITE(sc, RGEPHY_MII_BMCR, 382 RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG); 383 DELAY(100); 384 385 return (EJUSTRETURN); 386 } 387 388 void 389 rgephy_loop(struct mii_softc *sc) 390 { 391 u_int32_t bmsr; 392 int i; 393 394 if (sc->mii_rev < 2) { 395 PHY_WRITE(sc, RGEPHY_MII_BMCR, RGEPHY_BMCR_PDOWN); 396 DELAY(1000); 397 } 398 399 for (i = 0; i < 15000; i++) { 400 bmsr = PHY_READ(sc, RGEPHY_MII_BMSR); 401 if (!(bmsr & RGEPHY_BMSR_LINK)) 402 break; 403 DELAY(10); 404 } 405 } 406 407 #define PHY_SETBIT(x, y, z) \ 408 PHY_WRITE(x, y, (PHY_READ(x, y) | (z))) 409 #define PHY_CLRBIT(x, y, z) \ 410 PHY_WRITE(x, y, (PHY_READ(x, y) & ~(z))) 411 412 /* 413 * Initialize RealTek PHY per the datasheet. The DSP in the PHYs of 414 * existing revisions of the 8169S/8110S chips need to be tuned in 415 * order to reliably negotiate a 1000Mbps link. This is only needed 416 * for rev 0 and rev 1 of the PHY. Later versions work without 417 * any fixups. 418 */ 419 void 420 rgephy_load_dspcode(struct mii_softc *sc) 421 { 422 int val; 423 424 if (sc->mii_rev > 1) 425 return; 426 427 PHY_WRITE(sc, 31, 0x0001); 428 PHY_WRITE(sc, 21, 0x1000); 429 PHY_WRITE(sc, 24, 0x65C7); 430 PHY_CLRBIT(sc, 4, 0x0800); 431 val = PHY_READ(sc, 4) & 0xFFF; 432 PHY_WRITE(sc, 4, val); 433 PHY_WRITE(sc, 3, 0x00A1); 434 PHY_WRITE(sc, 2, 0x0008); 435 PHY_WRITE(sc, 1, 0x1020); 436 PHY_WRITE(sc, 0, 0x1000); 437 PHY_SETBIT(sc, 4, 0x0800); 438 PHY_CLRBIT(sc, 4, 0x0800); 439 val = (PHY_READ(sc, 4) & 0xFFF) | 0x7000; 440 PHY_WRITE(sc, 4, val); 441 PHY_WRITE(sc, 3, 0xFF41); 442 PHY_WRITE(sc, 2, 0xDE60); 443 PHY_WRITE(sc, 1, 0x0140); 444 PHY_WRITE(sc, 0, 0x0077); 445 val = (PHY_READ(sc, 4) & 0xFFF) | 0xA000; 446 PHY_WRITE(sc, 4, val); 447 PHY_WRITE(sc, 3, 0xDF01); 448 PHY_WRITE(sc, 2, 0xDF20); 449 PHY_WRITE(sc, 1, 0xFF95); 450 PHY_WRITE(sc, 0, 0xFA00); 451 val = (PHY_READ(sc, 4) & 0xFFF) | 0xB000; 452 PHY_WRITE(sc, 4, val); 453 PHY_WRITE(sc, 3, 0xFF41); 454 PHY_WRITE(sc, 2, 0xDE20); 455 PHY_WRITE(sc, 1, 0x0140); 456 PHY_WRITE(sc, 0, 0x00BB); 457 val = (PHY_READ(sc, 4) & 0xFFF) | 0xF000; 458 PHY_WRITE(sc, 4, val); 459 PHY_WRITE(sc, 3, 0xDF01); 460 PHY_WRITE(sc, 2, 0xDF20); 461 PHY_WRITE(sc, 1, 0xFF95); 462 PHY_WRITE(sc, 0, 0xBF00); 463 PHY_SETBIT(sc, 4, 0x0800); 464 PHY_CLRBIT(sc, 4, 0x0800); 465 PHY_WRITE(sc, 31, 0x0000); 466 467 DELAY(40); 468 } 469 470 void 471 rgephy_reset(struct mii_softc *sc) 472 { 473 mii_phy_reset(sc); 474 DELAY(1000); 475 rgephy_load_dspcode(sc); 476 } 477