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