1 /* $OpenBSD: mlphy.c,v 1.4 2013/12/28 03:30:41 deraadt Exp $ */ 2 3 /*- 4 * Copyright (c) 1997, 1998, 1999 5 * Bill Paul <wpaul <at> ctr.columbia.edu>. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Bill Paul. 18 * 4. Neither the name of the author nor the names of any co-contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 32 * THE POSSIBILITY OF SUCH DAMAGE. 33 * 34 */ 35 36 /*- 37 * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. 38 * All rights reserved. 39 * 40 * This code is derived from software contributed to The NetBSD Foundation 41 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 42 * NASA Ames Research Center, and by Frank van der Linden. 43 * 44 * Redistribution and use in source and binary forms, with or without 45 * modification, are permitted provided that the following conditions 46 * are met: 47 * 1. Redistributions of source code must retain the above copyright 48 * notice, this list of conditions and the following disclaimer. 49 * 2. Redistributions in binary form must reproduce the above copyright 50 * notice, this list of conditions and the following disclaimer in the 51 * documentation and/or other materials provided with the distribution. 52 * 53 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 54 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 55 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 56 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 57 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 58 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 59 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 60 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 61 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 62 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 63 * POSSIBILITY OF SUCH DAMAGE. 64 */ 65 66 /* 67 * Copyright (c) 1997 Manuel Bouyer. All rights reserved. 68 * 69 * Redistribution and use in source and binary forms, with or without 70 * modification, are permitted provided that the following conditions 71 * are met: 72 * 1. Redistributions of source code must retain the above copyright 73 * notice, this list of conditions and the following disclaimer. 74 * 2. Redistributions in binary form must reproduce the above copyright 75 * notice, this list of conditions and the following disclaimer in the 76 * documentation and/or other materials provided with the distribution. 77 * 78 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 79 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 80 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 81 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 82 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 83 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 84 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 85 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 86 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 87 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 88 */ 89 90 /* 91 * Micro Linear 6692 PHY 92 * 93 * The Micro Linear 6692 is a strange beast, and dealing with it using 94 * this code framework is tricky. The 6692 is actually a 100Mbps-only 95 * device, which means that a second PHY is required to support 10Mbps 96 * modes. However, even though the 6692 does not support 10Mbps modes, 97 * it can still advertise them when performing autonegotiation. If a 98 * 10Mbps mode is negotiated, we must program the registers of the 99 * companion PHY accordingly in addition to programming the registers 100 * of the 6692. 101 * 102 * This device also does not have vendor/device ID registers. 103 * 104 */ 105 106 #include <sys/param.h> 107 #include <sys/systm.h> 108 #include <sys/kernel.h> 109 #include <sys/device.h> 110 #include <sys/socket.h> 111 #include <sys/errno.h> 112 113 #include <net/if.h> 114 #include <net/if_media.h> 115 116 #include <dev/mii/mii.h> 117 #include <dev/mii/miivar.h> 118 119 #define ML_STATE_AUTO_SELF 1 120 #define ML_STATE_AUTO_OTHER 2 121 122 struct mlphy_softc { 123 struct mii_softc ml_mii; 124 struct device *ml_dev; 125 int ml_state; 126 int ml_linked; 127 }; 128 129 int mlphy_probe(struct device *, void *, void *); 130 void mlphy_attach(struct device *, struct device *, void *); 131 132 struct cfattach mlphy_ca = { 133 sizeof(struct mii_softc), mlphy_probe, mlphy_attach, mii_phy_detach 134 }; 135 136 struct cfdriver mlphy_cd = { 137 NULL, "mlphy", DV_DULL 138 }; 139 140 void mlphy_reset(struct mii_softc *); 141 int mlphy_service(struct mii_softc *, struct mii_data *, int); 142 void mlphy_status(struct mii_softc *); 143 144 const struct mii_phy_funcs mlphy_funcs = { 145 mlphy_service, mlphy_status, mlphy_reset, 146 }; 147 148 int 149 mlphy_probe(struct device *parent, void *match, void *aux) 150 { 151 struct mii_attach_args *ma = aux; 152 153 /* 154 * Micro Linear PHY reports oui == 0 model == 0 155 */ 156 if (MII_OUI(ma->mii_id1, ma->mii_id2) != 0 || 157 MII_MODEL(ma->mii_id2) != 0) 158 return (0); 159 /* 160 * Make sure the parent is a `tl'. So far, I have only 161 * encountered the 6692 on an Olicom card with a ThunderLAN 162 * controller chip. 163 */ 164 if (strcmp(parent->dv_cfdata->cf_driver->cd_name, "tl") != 0) 165 return (0); 166 167 return (10); 168 } 169 170 void 171 mlphy_attach(struct device *parent, struct device *self, void *aux) 172 { 173 struct mlphy_softc *msc = (struct mlphy_softc *)self; 174 struct mii_softc *sc = (struct mii_softc *)self; 175 struct mii_attach_args *ma = aux; 176 struct mii_data *mii = ma->mii_data; 177 178 printf(": ML6692 100baseTX PHY\n"); 179 180 sc->mii_inst = mii->mii_instance; 181 sc->mii_phy = ma->mii_phyno; 182 sc->mii_funcs = &mlphy_funcs; 183 sc->mii_pdata = mii; 184 sc->mii_flags = ma->mii_flags; 185 msc->ml_dev = parent; 186 187 PHY_RESET(sc); 188 189 sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 190 #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) 191 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), 192 MII_MEDIA_100_TX); 193 ma->mii_capmask = ~sc->mii_capabilities; 194 #undef ADD 195 if(sc->mii_capabilities & BMSR_MEDIAMASK) 196 mii_phy_add_media(sc); 197 } 198 199 int 200 mlphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 201 { 202 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 203 struct mii_softc *other = NULL; 204 struct mlphy_softc *msc = (struct mlphy_softc *)sc; 205 int other_inst, reg; 206 207 LIST_FOREACH(other, &mii->mii_phys, mii_list) 208 if (other != sc) 209 break; 210 211 if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0) 212 return (ENXIO); 213 214 switch (cmd) { 215 case MII_POLLSTAT: 216 /* 217 * If we're not polling our PHY instance, just return. 218 */ 219 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 220 return (0); 221 break; 222 223 case MII_MEDIACHG: 224 /* 225 * If the interface is not up, don't do anything. 226 */ 227 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 228 break; 229 230 switch (IFM_SUBTYPE(ife->ifm_media)) { 231 case IFM_AUTO: 232 msc->ml_state = ML_STATE_AUTO_SELF; 233 if (other != NULL) { 234 mii_phy_reset(other); 235 PHY_WRITE(other, MII_BMCR, BMCR_ISO); 236 } 237 (void)mii_phy_auto(sc, 0); 238 msc->ml_linked = 0; 239 break; 240 case IFM_10_T: 241 /* 242 * For 10baseT modes, reset and program the 243 * companion PHY (of any), then setup ourselves 244 * to match. This will put us in pass-through 245 * mode and let the companion PHY do all the 246 * work. 247 * BMCR data is stored in the ifmedia entry. 248 */ 249 if (other != NULL) { 250 mii_phy_reset(other); 251 PHY_WRITE(other, MII_BMCR, ife->ifm_data); 252 } 253 mii_phy_setmedia(sc); 254 msc->ml_state = 0; 255 break; 256 case IFM_100_TX: 257 /* 258 * For 100baseTX modes, reset and isolate the 259 * companion PHY (if any), then setup ourselves 260 * accordingly. 261 * 262 * BMCR data is stored in the ifmedia entry. 263 */ 264 if (other != NULL) { 265 mii_phy_reset(other); 266 PHY_WRITE(other, MII_BMCR, BMCR_ISO); 267 } 268 mii_phy_setmedia(sc); 269 msc->ml_state = 0; 270 break; 271 default: 272 return (EINVAL); 273 } 274 break; 275 case MII_TICK: 276 /* 277 * If interface is not up, don't do anything 278 */ 279 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 280 return (0); 281 /* 282 * Only used for autonegotiation. 283 */ 284 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 285 break; 286 /* 287 * Check to see if we have link. If we do, we don't 288 * need to restart the autonegotiation process. Read 289 * the BMSR twice in case it's latched. 290 * If we're in a 10Mbps mode, check the link of the 291 * 10Mbps PHY. Sometimes the Micro Linear PHY's 292 * linkstat bit will clear while the linkstat bit of 293 * the companion PHY will remain set. 294 */ 295 if (msc->ml_state == ML_STATE_AUTO_OTHER) { 296 reg = PHY_READ(other, MII_BMSR) | 297 PHY_READ(other, MII_BMSR); 298 } else { 299 reg = PHY_READ(sc, MII_BMSR) | 300 PHY_READ(sc, MII_BMSR); 301 } 302 303 if (reg & BMSR_LINK) { 304 if (!msc->ml_linked) { 305 msc->ml_linked = 1; 306 mlphy_status(sc); 307 } 308 sc->mii_ticks = 0; 309 break; 310 } 311 /* 312 * Only retry autonegotiation every 5 seconds. 313 */ 314 if (++sc->mii_ticks <= MII_ANEGTICKS) 315 break; 316 317 sc->mii_ticks = 0; 318 msc->ml_linked = 0; 319 mii->mii_media_active = IFM_NONE; 320 mii_phy_reset(sc); 321 msc->ml_state = ML_STATE_AUTO_SELF; 322 if (other != NULL) { 323 mii_phy_reset(other); 324 PHY_WRITE(other, MII_BMCR, BMCR_ISO); 325 } 326 mii_phy_auto(sc, 0); 327 break; 328 329 case MII_DOWN: 330 mii_phy_down(sc); 331 return (0); 332 } 333 334 /* Update the media status. */ 335 if (msc->ml_state == ML_STATE_AUTO_OTHER && other != NULL) { 336 other_inst = other->mii_inst; 337 other->mii_inst = sc->mii_inst; 338 if (IFM_INST(ife->ifm_media) == other->mii_inst) 339 (void) PHY_SERVICE(other, mii, MII_POLLSTAT); 340 other->mii_inst = other_inst; 341 sc->mii_media_active = other->mii_media_active; 342 sc->mii_media_status = other->mii_media_status; 343 } else 344 ukphy_status(sc); 345 346 /* Callback if something changed. */ 347 mii_phy_update(sc, cmd); 348 return (0); 349 } 350 351 void 352 mlphy_reset(struct mii_softc *sc) 353 { 354 int reg; 355 356 mii_phy_reset(sc); 357 reg = PHY_READ(sc, MII_BMCR); 358 reg &= ~BMCR_AUTOEN; 359 PHY_WRITE(sc, MII_BMCR, reg); 360 } 361 362 /* 363 * If we negotiate a 10Mbps mode, we need to check for an alternate 364 * PHY and make sure it's enabled and set correctly. 365 */ 366 void 367 mlphy_status(struct mii_softc *sc) 368 { 369 struct mlphy_softc *msc = (struct mlphy_softc *)sc; 370 struct mii_data *mii = sc->mii_pdata; 371 struct mii_softc *other = NULL; 372 373 /* See if there's another PHY on the bus with us. */ 374 LIST_FOREACH(other, &mii->mii_phys, mii_list) 375 if (other != sc) 376 break; 377 378 ukphy_status(sc); 379 380 if (IFM_SUBTYPE(mii->mii_media_active) != IFM_10_T) { 381 msc->ml_state = ML_STATE_AUTO_SELF; 382 if (other != NULL) { 383 mii_phy_reset(other); 384 PHY_WRITE(other, MII_BMCR, BMCR_ISO); 385 } 386 } 387 388 if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T) { 389 msc->ml_state = ML_STATE_AUTO_OTHER; 390 mlphy_reset(&msc->ml_mii); 391 PHY_WRITE(&msc->ml_mii, MII_BMCR, BMCR_ISO); 392 if (other != NULL) { 393 mii_phy_reset(other); 394 mii_phy_auto(other, 1); 395 } 396 } 397 } 398