1 /* $OpenBSD: mlphy.c,v 1.3 2013/05/28 09:46:06 mikeb 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 mii_phy_activate 135 }; 136 137 struct cfdriver mlphy_cd = { 138 NULL, "mlphy", DV_DULL 139 }; 140 141 void mlphy_reset(struct mii_softc *); 142 int mlphy_service(struct mii_softc *, struct mii_data *, int); 143 void mlphy_status(struct mii_softc *); 144 145 const struct mii_phy_funcs mlphy_funcs = { 146 mlphy_service, mlphy_status, mlphy_reset, 147 }; 148 149 int 150 mlphy_probe(struct device *parent, void *match, void *aux) 151 { 152 struct mii_attach_args *ma = aux; 153 154 /* 155 * Micro Linear PHY reports oui == 0 model == 0 156 */ 157 if (MII_OUI(ma->mii_id1, ma->mii_id2) != 0 || 158 MII_MODEL(ma->mii_id2) != 0) 159 return (0); 160 /* 161 * Make sure the parent is a `tl'. So far, I have only 162 * encountered the 6692 on an Olicom card with a ThunderLAN 163 * controller chip. 164 */ 165 if (strcmp(parent->dv_cfdata->cf_driver->cd_name, "tl") != 0) 166 return (0); 167 168 return (10); 169 } 170 171 void 172 mlphy_attach(struct device *parent, struct device *self, void *aux) 173 { 174 struct mlphy_softc *msc = (struct mlphy_softc *)self; 175 struct mii_softc *sc = (struct mii_softc *)self; 176 struct mii_attach_args *ma = aux; 177 struct mii_data *mii = ma->mii_data; 178 179 printf(": ML6692 100baseTX PHY\n"); 180 181 sc->mii_inst = mii->mii_instance; 182 sc->mii_phy = ma->mii_phyno; 183 sc->mii_funcs = &mlphy_funcs; 184 sc->mii_pdata = mii; 185 sc->mii_flags = ma->mii_flags; 186 msc->ml_dev = parent; 187 188 mii_phy_reset(sc); 189 190 sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 191 #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) 192 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), 193 MII_MEDIA_100_TX); 194 ma->mii_capmask = ~sc->mii_capabilities; 195 #undef ADD 196 if(sc->mii_capabilities & BMSR_MEDIAMASK) 197 mii_phy_add_media(sc); 198 } 199 200 int 201 mlphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 202 { 203 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 204 struct mii_softc *other = NULL; 205 struct mlphy_softc *msc = (struct mlphy_softc *)sc; 206 int other_inst, reg; 207 208 LIST_FOREACH(other, &mii->mii_phys, mii_list) 209 if (other != sc) 210 break; 211 212 if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0) 213 return (ENXIO); 214 215 switch (cmd) { 216 case MII_POLLSTAT: 217 /* 218 * If we're not polling our PHY instance, just return. 219 */ 220 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 221 return (0); 222 break; 223 224 case MII_MEDIACHG: 225 /* 226 * If the interface is not up, don't do anything. 227 */ 228 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 229 break; 230 231 switch (IFM_SUBTYPE(ife->ifm_media)) { 232 case IFM_AUTO: 233 msc->ml_state = ML_STATE_AUTO_SELF; 234 if (other != NULL) { 235 mii_phy_reset(other); 236 PHY_WRITE(other, MII_BMCR, BMCR_ISO); 237 } 238 (void)mii_phy_auto(sc, 0); 239 msc->ml_linked = 0; 240 break; 241 case IFM_10_T: 242 /* 243 * For 10baseT modes, reset and program the 244 * companion PHY (of any), then setup ourselves 245 * to match. This will put us in pass-through 246 * mode and let the companion PHY do all the 247 * work. 248 * BMCR data is stored in the ifmedia entry. 249 */ 250 if (other != NULL) { 251 mii_phy_reset(other); 252 PHY_WRITE(other, MII_BMCR, ife->ifm_data); 253 } 254 mii_phy_setmedia(sc); 255 msc->ml_state = 0; 256 break; 257 case IFM_100_TX: 258 /* 259 * For 100baseTX modes, reset and isolate the 260 * companion PHY (if any), then setup ourselves 261 * accordingly. 262 * 263 * BMCR data is stored in the ifmedia entry. 264 */ 265 if (other != NULL) { 266 mii_phy_reset(other); 267 PHY_WRITE(other, MII_BMCR, BMCR_ISO); 268 } 269 mii_phy_setmedia(sc); 270 msc->ml_state = 0; 271 break; 272 default: 273 return (EINVAL); 274 } 275 break; 276 case MII_TICK: 277 /* 278 * If interface is not up, don't do anything 279 */ 280 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 281 return (0); 282 /* 283 * Only used for autonegotiation. 284 */ 285 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 286 break; 287 /* 288 * Check to see if we have link. If we do, we don't 289 * need to restart the autonegotiation process. Read 290 * the BMSR twice in case it's latched. 291 * If we're in a 10Mbps mode, check the link of the 292 * 10Mbps PHY. Sometimes the Micro Linear PHY's 293 * linkstat bit will clear while the linkstat bit of 294 * the companion PHY will remain set. 295 */ 296 if (msc->ml_state == ML_STATE_AUTO_OTHER) { 297 reg = PHY_READ(other, MII_BMSR) | 298 PHY_READ(other, MII_BMSR); 299 } else { 300 reg = PHY_READ(sc, MII_BMSR) | 301 PHY_READ(sc, MII_BMSR); 302 } 303 304 if (reg & BMSR_LINK) { 305 if (!msc->ml_linked) { 306 msc->ml_linked = 1; 307 mlphy_status(sc); 308 } 309 sc->mii_ticks = 0; 310 break; 311 } 312 /* 313 * Only retry autonegotiation every 5 seconds. 314 */ 315 if (++sc->mii_ticks <= MII_ANEGTICKS) 316 break; 317 318 sc->mii_ticks = 0; 319 msc->ml_linked = 0; 320 mii->mii_media_active = IFM_NONE; 321 mii_phy_reset(sc); 322 msc->ml_state = ML_STATE_AUTO_SELF; 323 if (other != NULL) { 324 mii_phy_reset(other); 325 PHY_WRITE(other, MII_BMCR, BMCR_ISO); 326 } 327 mii_phy_auto(sc, 0); 328 break; 329 330 case MII_DOWN: 331 mii_phy_down(sc); 332 return (0); 333 } 334 335 /* Update the media status. */ 336 if (msc->ml_state == ML_STATE_AUTO_OTHER && other != NULL) { 337 other_inst = other->mii_inst; 338 other->mii_inst = sc->mii_inst; 339 if (IFM_INST(ife->ifm_media) == other->mii_inst) 340 (void) PHY_SERVICE(other, mii, MII_POLLSTAT); 341 other->mii_inst = other_inst; 342 sc->mii_media_active = other->mii_media_active; 343 sc->mii_media_status = other->mii_media_status; 344 } else 345 ukphy_status(sc); 346 347 /* Callback if something changed. */ 348 mii_phy_update(sc, cmd); 349 return (0); 350 } 351 352 void 353 mlphy_reset(struct mii_softc *sc) 354 { 355 int reg; 356 357 mii_phy_reset(sc); 358 reg = PHY_READ(sc, MII_BMCR); 359 reg &= ~BMCR_AUTOEN; 360 PHY_WRITE(sc, MII_BMCR, reg); 361 } 362 363 /* 364 * If we negotiate a 10Mbps mode, we need to check for an alternate 365 * PHY and make sure it's enabled and set correctly. 366 */ 367 void 368 mlphy_status(struct mii_softc *sc) 369 { 370 struct mlphy_softc *msc = (struct mlphy_softc *)sc; 371 struct mii_data *mii = sc->mii_pdata; 372 struct mii_softc *other = NULL; 373 374 /* See if there's another PHY on the bus with us. */ 375 LIST_FOREACH(other, &mii->mii_phys, mii_list) 376 if (other != sc) 377 break; 378 379 ukphy_status(sc); 380 381 if (IFM_SUBTYPE(mii->mii_media_active) != IFM_10_T) { 382 msc->ml_state = ML_STATE_AUTO_SELF; 383 if (other != NULL) { 384 mii_phy_reset(other); 385 PHY_WRITE(other, MII_BMCR, BMCR_ISO); 386 } 387 } 388 389 if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T) { 390 msc->ml_state = ML_STATE_AUTO_OTHER; 391 mlphy_reset(&msc->ml_mii); 392 PHY_WRITE(&msc->ml_mii, MII_BMCR, BMCR_ISO); 393 if (other != NULL) { 394 mii_phy_reset(other); 395 mii_phy_auto(other, 1); 396 } 397 } 398 } 399