1 1.5 msaitoh /* $NetBSD: jmphy.c,v 1.5 2023/02/22 08:09:09 msaitoh Exp $ */ 2 1.1 msaitoh /* $OpenBSD: jmphy.c,v 1.6 2015/03/14 03:38:48 jsg Exp $ */ 3 1.1 msaitoh /*- 4 1.1 msaitoh * Copyright (c) 2008, Pyun YongHyeon <yongari (at) FreeBSD.org> 5 1.1 msaitoh * All rights reserved. 6 1.1 msaitoh * 7 1.1 msaitoh * Redistribution and use in source and binary forms, with or without 8 1.1 msaitoh * modification, are permitted provided that the following conditions 9 1.1 msaitoh * are met: 10 1.1 msaitoh * 1. Redistributions of source code must retain the above copyright 11 1.1 msaitoh * notice unmodified, this list of conditions, and the following 12 1.1 msaitoh * disclaimer. 13 1.1 msaitoh * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 msaitoh * notice, this list of conditions and the following disclaimer in the 15 1.1 msaitoh * documentation and/or other materials provided with the distribution. 16 1.1 msaitoh * 17 1.1 msaitoh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 1.1 msaitoh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 1.1 msaitoh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 1.1 msaitoh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 1.1 msaitoh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 1.1 msaitoh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 1.1 msaitoh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 1.1 msaitoh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 1.1 msaitoh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 1.1 msaitoh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 1.1 msaitoh * SUCH DAMAGE. 28 1.1 msaitoh * 29 1.1 msaitoh * $FreeBSD: src/sys/dev/mii/jmphy.c,v 1.1 2008/05/27 01:16:40 yongari Exp $ 30 1.1 msaitoh * $DragonFly: src/sys/dev/netif/mii_layer/jmphy.c,v 1.1 2008/07/22 11:28:49 sephe Exp $ 31 1.1 msaitoh */ 32 1.1 msaitoh 33 1.1 msaitoh /* 34 1.1 msaitoh * Driver for the JMicron JMP211 10/100/1000, JMP202 10/100 PHY. 35 1.1 msaitoh */ 36 1.1 msaitoh 37 1.1 msaitoh #include <sys/param.h> 38 1.1 msaitoh #include <sys/systm.h> 39 1.1 msaitoh #include <sys/device.h> 40 1.1 msaitoh #include <sys/socket.h> 41 1.1 msaitoh 42 1.1 msaitoh #include <net/if.h> 43 1.1 msaitoh #include <net/if_media.h> 44 1.1 msaitoh 45 1.1 msaitoh #include <dev/mii/mii.h> 46 1.1 msaitoh #include <dev/mii/miivar.h> 47 1.1 msaitoh #include <dev/mii/miidevs.h> 48 1.1 msaitoh #include <dev/mii/jmphyreg.h> 49 1.1 msaitoh 50 1.1 msaitoh static int jmphy_service(struct mii_softc *, struct mii_data *, int); 51 1.1 msaitoh static void jmphy_status(struct mii_softc *); 52 1.1 msaitoh static int jmphy_match(device_t, cfdata_t, void *); 53 1.1 msaitoh static void jmphy_attach(device_t, device_t, void *); 54 1.1 msaitoh static void jmphy_reset(struct mii_softc *); 55 1.1 msaitoh static uint16_t jmphy_anar(struct ifmedia_entry *); 56 1.1 msaitoh static int jmphy_auto(struct mii_softc *, struct ifmedia_entry *); 57 1.1 msaitoh 58 1.1 msaitoh static const struct mii_phy_funcs jmphy_funcs = { 59 1.1 msaitoh jmphy_service, jmphy_status, jmphy_reset, 60 1.1 msaitoh }; 61 1.1 msaitoh 62 1.1 msaitoh CFATTACH_DECL_NEW(jmphy, sizeof (struct mii_softc), 63 1.1 msaitoh jmphy_match, jmphy_attach, mii_phy_detach, mii_phy_activate); 64 1.1 msaitoh 65 1.1 msaitoh static const struct mii_phydesc jmphys[] = { 66 1.1 msaitoh MII_PHY_DESC(JMICRON, JMP202), 67 1.1 msaitoh MII_PHY_DESC(JMICRON, JMP211), 68 1.1 msaitoh MII_PHY_END, 69 1.1 msaitoh }; 70 1.1 msaitoh 71 1.1 msaitoh static int 72 1.1 msaitoh jmphy_match(device_t parent, cfdata_t match, void *aux) 73 1.1 msaitoh { 74 1.1 msaitoh struct mii_attach_args *ma = aux; 75 1.1 msaitoh 76 1.1 msaitoh if (mii_phy_match(ma, jmphys) != NULL) 77 1.1 msaitoh return 10; 78 1.1 msaitoh 79 1.1 msaitoh return 0; 80 1.1 msaitoh } 81 1.1 msaitoh 82 1.1 msaitoh static void 83 1.1 msaitoh jmphy_attach(device_t parent, device_t self, void *aux) 84 1.1 msaitoh { 85 1.1 msaitoh struct mii_softc *sc = device_private(self); 86 1.1 msaitoh struct mii_attach_args *ma = aux; 87 1.1 msaitoh struct mii_data *mii = ma->mii_data; 88 1.1 msaitoh const struct mii_phydesc *mpd; 89 1.1 msaitoh 90 1.1 msaitoh mpd = mii_phy_match(ma, jmphys); 91 1.1 msaitoh aprint_naive(": Media interface\n"); 92 1.1 msaitoh aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2)); 93 1.1 msaitoh 94 1.1 msaitoh sc->mii_dev = self; 95 1.1 msaitoh sc->mii_inst = mii->mii_instance; 96 1.1 msaitoh sc->mii_phy = ma->mii_phyno; 97 1.1 msaitoh sc->mii_funcs = &jmphy_funcs; 98 1.1 msaitoh sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2); 99 1.1 msaitoh sc->mii_mpd_model = MII_MODEL(ma->mii_id2); 100 1.1 msaitoh sc->mii_mpd_rev = MII_REV(ma->mii_id2); 101 1.1 msaitoh sc->mii_pdata = mii; 102 1.1 msaitoh sc->mii_flags = ma->mii_flags; 103 1.1 msaitoh 104 1.1 msaitoh sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP; 105 1.1 msaitoh 106 1.4 thorpej mii_lock(mii); 107 1.4 thorpej 108 1.1 msaitoh PHY_RESET(sc); 109 1.1 msaitoh 110 1.1 msaitoh PHY_READ(sc, MII_BMSR, &sc->mii_capabilities); 111 1.1 msaitoh sc->mii_capabilities &= ma->mii_capmask; 112 1.1 msaitoh if (sc->mii_capabilities & BMSR_EXTSTAT) 113 1.1 msaitoh PHY_READ(sc, MII_EXTSR, &sc->mii_extcapabilities); 114 1.1 msaitoh 115 1.4 thorpej mii_unlock(mii); 116 1.4 thorpej 117 1.3 msaitoh mii_phy_add_media(sc); 118 1.1 msaitoh } 119 1.1 msaitoh 120 1.1 msaitoh static int 121 1.1 msaitoh jmphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 122 1.1 msaitoh { 123 1.1 msaitoh struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 124 1.1 msaitoh uint16_t bmcr, ssr; 125 1.1 msaitoh 126 1.4 thorpej KASSERT(mii_locked(mii)); 127 1.4 thorpej 128 1.1 msaitoh switch (cmd) { 129 1.1 msaitoh case MII_POLLSTAT: 130 1.2 msaitoh /* If we're not polling our PHY instance, just return. */ 131 1.1 msaitoh if (IFM_INST(ife->ifm_media) != sc->mii_inst) 132 1.1 msaitoh return 0; 133 1.1 msaitoh break; 134 1.1 msaitoh 135 1.1 msaitoh case MII_MEDIACHG: 136 1.1 msaitoh /* 137 1.1 msaitoh * If the media indicates a different PHY instance, 138 1.1 msaitoh * isolate ourselves. 139 1.1 msaitoh */ 140 1.1 msaitoh if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 141 1.1 msaitoh PHY_READ(sc, MII_BMCR, &bmcr); 142 1.1 msaitoh PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO); 143 1.1 msaitoh return 0; 144 1.1 msaitoh } 145 1.1 msaitoh 146 1.2 msaitoh /* If the interface is not up, don't do anything. */ 147 1.1 msaitoh if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 148 1.1 msaitoh break; 149 1.1 msaitoh 150 1.1 msaitoh if (jmphy_auto(sc, ife) != EJUSTRETURN) 151 1.1 msaitoh return EINVAL; 152 1.1 msaitoh break; 153 1.1 msaitoh 154 1.1 msaitoh case MII_TICK: 155 1.2 msaitoh /* If we're not currently selected, just return. */ 156 1.1 msaitoh if (IFM_INST(ife->ifm_media) != sc->mii_inst) 157 1.1 msaitoh return 0; 158 1.1 msaitoh 159 1.2 msaitoh /* Is the interface even up? */ 160 1.1 msaitoh if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 161 1.1 msaitoh return 0; 162 1.1 msaitoh 163 1.2 msaitoh /* Only used for autonegotiation. */ 164 1.1 msaitoh if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 165 1.1 msaitoh break; 166 1.1 msaitoh 167 1.1 msaitoh /* Check for link. */ 168 1.1 msaitoh PHY_READ(sc, JMPHY_SSR, &ssr); 169 1.1 msaitoh if (ssr & JMPHY_SSR_LINK_UP) { 170 1.1 msaitoh sc->mii_ticks = 0; 171 1.1 msaitoh break; 172 1.1 msaitoh } 173 1.1 msaitoh 174 1.1 msaitoh /* Announce link loss right after it happens. */ 175 1.1 msaitoh if (sc->mii_ticks++ == 0) 176 1.1 msaitoh break; 177 1.5 msaitoh if (sc->mii_ticks < sc->mii_anegticks) 178 1.1 msaitoh return 0; 179 1.1 msaitoh 180 1.1 msaitoh sc->mii_ticks = 0; 181 1.1 msaitoh jmphy_auto(sc, ife); 182 1.1 msaitoh break; 183 1.1 msaitoh } 184 1.1 msaitoh 185 1.1 msaitoh /* Update the media status. */ 186 1.1 msaitoh jmphy_status(sc); 187 1.1 msaitoh 188 1.1 msaitoh /* Callback if something changed. */ 189 1.1 msaitoh mii_phy_update(sc, cmd); 190 1.1 msaitoh return 0; 191 1.1 msaitoh } 192 1.1 msaitoh 193 1.1 msaitoh static void 194 1.1 msaitoh jmphy_status(struct mii_softc *sc) 195 1.1 msaitoh { 196 1.1 msaitoh struct mii_data *mii = sc->mii_pdata; 197 1.1 msaitoh uint16_t bmcr, ssr, gtsr; 198 1.1 msaitoh 199 1.4 thorpej KASSERT(mii_locked(mii)); 200 1.4 thorpej 201 1.1 msaitoh mii->mii_media_status = IFM_AVALID; 202 1.1 msaitoh mii->mii_media_active = IFM_ETHER; 203 1.1 msaitoh 204 1.1 msaitoh PHY_READ(sc, JMPHY_SSR, &ssr); 205 1.1 msaitoh if ((ssr & JMPHY_SSR_LINK_UP) != 0) 206 1.1 msaitoh mii->mii_media_status |= IFM_ACTIVE; 207 1.1 msaitoh 208 1.1 msaitoh PHY_READ(sc, MII_BMCR, &bmcr); 209 1.1 msaitoh if ((bmcr & BMCR_ISO) != 0) { 210 1.1 msaitoh mii->mii_media_active |= IFM_NONE; 211 1.1 msaitoh mii->mii_media_status = 0; 212 1.1 msaitoh return; 213 1.1 msaitoh } 214 1.1 msaitoh 215 1.1 msaitoh if ((bmcr & BMCR_LOOP) != 0) 216 1.1 msaitoh mii->mii_media_active |= IFM_LOOP; 217 1.1 msaitoh 218 1.1 msaitoh if ((ssr & JMPHY_SSR_SPD_DPLX_RESOLVED) == 0) { 219 1.1 msaitoh /* Erg, still trying, I guess... */ 220 1.1 msaitoh mii->mii_media_active |= IFM_NONE; 221 1.1 msaitoh return; 222 1.1 msaitoh } 223 1.1 msaitoh 224 1.1 msaitoh switch ((ssr & JMPHY_SSR_SPEED_MASK)) { 225 1.1 msaitoh case JMPHY_SSR_SPEED_1000: 226 1.1 msaitoh mii->mii_media_active |= IFM_1000_T; 227 1.1 msaitoh /* 228 1.1 msaitoh * jmphy(4) got a valid link so reset mii_ticks. 229 1.1 msaitoh * Resetting mii_ticks is needed in order to 230 1.1 msaitoh * detect link loss after auto-negotiation. 231 1.1 msaitoh */ 232 1.1 msaitoh sc->mii_ticks = 0; 233 1.1 msaitoh break; 234 1.1 msaitoh case JMPHY_SSR_SPEED_100: 235 1.1 msaitoh mii->mii_media_active |= IFM_100_TX; 236 1.1 msaitoh sc->mii_ticks = 0; 237 1.1 msaitoh break; 238 1.1 msaitoh case JMPHY_SSR_SPEED_10: 239 1.1 msaitoh mii->mii_media_active |= IFM_10_T; 240 1.1 msaitoh sc->mii_ticks = 0; 241 1.1 msaitoh break; 242 1.1 msaitoh default: 243 1.1 msaitoh mii->mii_media_active |= IFM_NONE; 244 1.1 msaitoh return; 245 1.1 msaitoh } 246 1.1 msaitoh 247 1.1 msaitoh if ((ssr & JMPHY_SSR_DUPLEX) != 0) 248 1.1 msaitoh mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc); 249 1.1 msaitoh else 250 1.1 msaitoh mii->mii_media_active |= IFM_HDX; 251 1.1 msaitoh 252 1.1 msaitoh if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { 253 1.1 msaitoh PHY_READ(sc, MII_GTSR, >sr); 254 1.1 msaitoh if ((gtsr & GTSR_MS_RES) != 0) 255 1.1 msaitoh mii->mii_media_active |= IFM_ETH_MASTER; 256 1.1 msaitoh } 257 1.1 msaitoh } 258 1.1 msaitoh 259 1.1 msaitoh static void 260 1.1 msaitoh jmphy_reset(struct mii_softc *sc) 261 1.1 msaitoh { 262 1.1 msaitoh int i; 263 1.1 msaitoh uint16_t val; 264 1.1 msaitoh 265 1.4 thorpej KASSERT(mii_locked(sc->mii_pdata)); 266 1.4 thorpej 267 1.1 msaitoh /* Disable sleep mode. */ 268 1.1 msaitoh PHY_READ(sc, JMPHY_TMCTL, &val); 269 1.1 msaitoh PHY_WRITE(sc, JMPHY_TMCTL, val & ~JMPHY_TMCTL_SLEEP_ENB); 270 1.1 msaitoh 271 1.1 msaitoh PHY_READ(sc, MII_BMCR, &val); 272 1.1 msaitoh PHY_WRITE(sc, MII_BMCR, val | BMCR_RESET); 273 1.1 msaitoh 274 1.1 msaitoh for (i = 0; i < 1000; i++) { 275 1.1 msaitoh DELAY(1); 276 1.1 msaitoh PHY_READ(sc, MII_BMCR, &val); 277 1.1 msaitoh if ((val & BMCR_RESET) == 0) 278 1.1 msaitoh break; 279 1.1 msaitoh } 280 1.1 msaitoh } 281 1.1 msaitoh 282 1.1 msaitoh static uint16_t 283 1.1 msaitoh jmphy_anar(struct ifmedia_entry *ife) 284 1.1 msaitoh { 285 1.1 msaitoh uint16_t anar; 286 1.1 msaitoh 287 1.1 msaitoh anar = 0; 288 1.1 msaitoh switch (IFM_SUBTYPE(ife->ifm_media)) { 289 1.1 msaitoh case IFM_AUTO: 290 1.1 msaitoh anar |= ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10; 291 1.1 msaitoh break; 292 1.1 msaitoh case IFM_1000_T: 293 1.1 msaitoh break; 294 1.1 msaitoh case IFM_100_TX: 295 1.1 msaitoh anar |= ANAR_TX | ANAR_TX_FD; 296 1.1 msaitoh break; 297 1.1 msaitoh case IFM_10_T: 298 1.1 msaitoh anar |= ANAR_10 | ANAR_10_FD; 299 1.1 msaitoh break; 300 1.1 msaitoh default: 301 1.1 msaitoh break; 302 1.1 msaitoh } 303 1.1 msaitoh 304 1.1 msaitoh return anar; 305 1.1 msaitoh } 306 1.1 msaitoh 307 1.1 msaitoh static int 308 1.1 msaitoh jmphy_auto(struct mii_softc *sc, struct ifmedia_entry *ife) 309 1.1 msaitoh { 310 1.1 msaitoh uint16_t anar, bmcr, gig; 311 1.1 msaitoh 312 1.4 thorpej KASSERT(mii_locked(sc->mii_pdata)); 313 1.4 thorpej 314 1.1 msaitoh gig = 0; 315 1.1 msaitoh PHY_READ(sc, MII_BMCR, &bmcr); 316 1.1 msaitoh switch (IFM_SUBTYPE(ife->ifm_media)) { 317 1.1 msaitoh case IFM_AUTO: 318 1.1 msaitoh gig |= GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX; 319 1.1 msaitoh break; 320 1.1 msaitoh case IFM_1000_T: 321 1.1 msaitoh gig |= GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX; 322 1.1 msaitoh break; 323 1.1 msaitoh case IFM_100_TX: 324 1.1 msaitoh case IFM_10_T: 325 1.1 msaitoh break; 326 1.1 msaitoh case IFM_NONE: 327 1.1 msaitoh PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO | BMCR_PDOWN); 328 1.1 msaitoh return EJUSTRETURN; 329 1.1 msaitoh default: 330 1.1 msaitoh return EINVAL; 331 1.1 msaitoh } 332 1.1 msaitoh 333 1.1 msaitoh if ((ife->ifm_media & IFM_LOOP) != 0) 334 1.1 msaitoh bmcr |= BMCR_LOOP; 335 1.1 msaitoh 336 1.1 msaitoh anar = jmphy_anar(ife); 337 1.1 msaitoh if (sc->mii_flags & MIIF_DOPAUSE) 338 1.1 msaitoh anar |= ANAR_PAUSE_TOWARDS; 339 1.1 msaitoh 340 1.1 msaitoh if ((sc->mii_flags & MIIF_HAVE_GTCR) != 0) { 341 1.1 msaitoh #ifdef notyet 342 1.1 msaitoh struct mii_data *mii; 343 1.1 msaitoh 344 1.1 msaitoh mii = sc->mii_pdata; 345 1.1 msaitoh if ((mii->mii_media.ifm_media & IFM_ETH_MASTER) != 0) 346 1.1 msaitoh gig |= GTCR_MAN_MS | GTCR_MAN_ADV; 347 1.1 msaitoh #endif 348 1.1 msaitoh PHY_WRITE(sc, MII_100T2CR, gig); 349 1.1 msaitoh } 350 1.1 msaitoh PHY_WRITE(sc, MII_ANAR, anar | ANAR_CSMA); 351 1.1 msaitoh PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_AUTOEN | BMCR_STARTNEG); 352 1.1 msaitoh 353 1.1 msaitoh return EJUSTRETURN; 354 1.1 msaitoh } 355