1 1.73 andvar /* $NetBSD: makphy.c,v 1.73 2024/02/09 22:08:35 andvar Exp $ */ 2 1.1 thorpej 3 1.1 thorpej /*- 4 1.1 thorpej * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc. 5 1.1 thorpej * All rights reserved. 6 1.1 thorpej * 7 1.1 thorpej * This code is derived from software contributed to The NetBSD Foundation 8 1.1 thorpej * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 1.1 thorpej * NASA Ames Research Center. 10 1.1 thorpej * 11 1.1 thorpej * Redistribution and use in source and binary forms, with or without 12 1.1 thorpej * modification, are permitted provided that the following conditions 13 1.1 thorpej * are met: 14 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 15 1.1 thorpej * notice, this list of conditions and the following disclaimer. 16 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 18 1.1 thorpej * documentation and/or other materials provided with the distribution. 19 1.1 thorpej * 20 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 1.1 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 1.1 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 1.1 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 1.1 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 1.1 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 1.1 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 1.1 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 1.1 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 1.1 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 1.1 thorpej * POSSIBILITY OF SUCH DAMAGE. 31 1.1 thorpej */ 32 1.1 thorpej 33 1.1 thorpej /* 34 1.1 thorpej * Copyright (c) 1997 Manuel Bouyer. All rights reserved. 35 1.1 thorpej * 36 1.1 thorpej * Redistribution and use in source and binary forms, with or without 37 1.1 thorpej * modification, are permitted provided that the following conditions 38 1.1 thorpej * are met: 39 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 40 1.1 thorpej * notice, this list of conditions and the following disclaimer. 41 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 42 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 43 1.1 thorpej * documentation and/or other materials provided with the distribution. 44 1.1 thorpej * 45 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 46 1.1 thorpej * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 47 1.1 thorpej * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 48 1.1 thorpej * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 49 1.1 thorpej * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 50 1.1 thorpej * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 51 1.1 thorpej * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 52 1.1 thorpej * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 53 1.1 thorpej * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 54 1.1 thorpej * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 55 1.1 thorpej */ 56 1.1 thorpej 57 1.50 msaitoh /* 58 1.50 msaitoh * Driver for the Marvell 88E1000 ``Alaska'' 10/100/1000 PHY. 59 1.50 msaitoh */ 60 1.50 msaitoh 61 1.4 lukem #include <sys/cdefs.h> 62 1.73 andvar __KERNEL_RCSID(0, "$NetBSD: makphy.c,v 1.73 2024/02/09 22:08:35 andvar Exp $"); 63 1.1 thorpej 64 1.1 thorpej #include <sys/param.h> 65 1.1 thorpej #include <sys/systm.h> 66 1.1 thorpej #include <sys/kernel.h> 67 1.1 thorpej #include <sys/device.h> 68 1.1 thorpej #include <sys/socket.h> 69 1.1 thorpej #include <sys/errno.h> 70 1.1 thorpej 71 1.1 thorpej #include <net/if.h> 72 1.1 thorpej #include <net/if_media.h> 73 1.1 thorpej 74 1.1 thorpej #include <dev/mii/mii.h> 75 1.1 thorpej #include <dev/mii/miivar.h> 76 1.1 thorpej #include <dev/mii/miidevs.h> 77 1.1 thorpej 78 1.46 msaitoh #include <dev/mii/makphyreg.h> 79 1.58 msaitoh #include <dev/mii/makphyvar.h> 80 1.1 thorpej 81 1.28 xtraeme static int makphymatch(device_t, cfdata_t, void *); 82 1.28 xtraeme static void makphyattach(device_t, device_t, void *); 83 1.1 thorpej 84 1.58 msaitoh CFATTACH_DECL_NEW(makphy, sizeof(struct makphy_softc), 85 1.11 thorpej makphymatch, makphyattach, mii_phy_detach, mii_phy_activate); 86 1.1 thorpej 87 1.15 thorpej static int makphy_service(struct mii_softc *, struct mii_data *, int); 88 1.15 thorpej static void makphy_status(struct mii_softc *); 89 1.23 msaitoh static void makphy_reset(struct mii_softc *); 90 1.1 thorpej 91 1.46 msaitoh static const struct mii_phy_funcs makphy_funcs = { 92 1.23 msaitoh makphy_service, makphy_status, makphy_reset, 93 1.1 thorpej }; 94 1.1 thorpej 95 1.46 msaitoh static const struct mii_phydesc makphys[] = { 96 1.55 christos MII_PHY_DESC(MARVELL, E1000_0), 97 1.55 christos MII_PHY_DESC(MARVELL, E1000_3), 98 1.55 christos MII_PHY_DESC(MARVELL, E1000_5), 99 1.55 christos MII_PHY_DESC(MARVELL, E1000_6), 100 1.55 christos MII_PHY_DESC(xxMARVELL, E1000_3), 101 1.55 christos MII_PHY_DESC(xxMARVELL, E1000_5), 102 1.55 christos MII_PHY_DESC(xxMARVELL, E1000S), 103 1.55 christos MII_PHY_DESC(xxMARVELL, E1011), 104 1.55 christos MII_PHY_DESC(xxMARVELL, E1101), 105 1.55 christos MII_PHY_DESC(xxMARVELL, E1111), 106 1.55 christos MII_PHY_DESC(xxMARVELL, E1112), 107 1.55 christos MII_PHY_DESC(xxMARVELL, E1116), 108 1.55 christos MII_PHY_DESC(xxMARVELL, E1116R), 109 1.55 christos MII_PHY_DESC(xxMARVELL, E1118), 110 1.55 christos MII_PHY_DESC(xxMARVELL, E1145), 111 1.55 christos MII_PHY_DESC(xxMARVELL, E1149), 112 1.55 christos MII_PHY_DESC(xxMARVELL, E1149R), 113 1.55 christos MII_PHY_DESC(xxMARVELL, E1240), 114 1.55 christos MII_PHY_DESC(xxMARVELL, E1318S), 115 1.55 christos MII_PHY_DESC(xxMARVELL, E1512), 116 1.55 christos MII_PHY_DESC(xxMARVELL, E1543), 117 1.55 christos MII_PHY_DESC(xxMARVELL, E3016), 118 1.55 christos MII_PHY_DESC(xxMARVELL, E3082), 119 1.55 christos MII_PHY_DESC(xxMARVELL, PHYG65G), 120 1.67 msaitoh MII_PHY_DESC(xxMARVELL, I347), 121 1.55 christos MII_PHY_END, 122 1.1 thorpej }; 123 1.1 thorpej 124 1.47 msaitoh #define MAKARG_PDOWN true /* Power DOWN */ 125 1.47 msaitoh #define MAKARG_PUP false /* Power UP */ 126 1.47 msaitoh 127 1.54 msaitoh static bool 128 1.54 msaitoh makphy_isi210(device_t parent, struct mii_attach_args *ma) 129 1.54 msaitoh { 130 1.54 msaitoh 131 1.54 msaitoh /* I21[01]'s model number is 0 */ 132 1.54 msaitoh if ((MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxMARVELL) 133 1.57 jakllsch && (MII_MODEL(ma->mii_id2) == MII_MODEL_xxMARVELL_I210) 134 1.54 msaitoh && (device_is_a(parent, "wm"))) 135 1.54 msaitoh return true; 136 1.54 msaitoh return false; 137 1.54 msaitoh } 138 1.54 msaitoh 139 1.15 thorpej static int 140 1.28 xtraeme makphymatch(device_t parent, cfdata_t match, void *aux) 141 1.1 thorpej { 142 1.1 thorpej struct mii_attach_args *ma = aux; 143 1.1 thorpej 144 1.46 msaitoh if (mii_phy_match(ma, makphys) != NULL) 145 1.54 msaitoh return 10; 146 1.1 thorpej 147 1.54 msaitoh if (makphy_isi210(parent, ma)) 148 1.54 msaitoh return 10; 149 1.59 msaitoh 150 1.54 msaitoh return 0; 151 1.1 thorpej } 152 1.1 thorpej 153 1.15 thorpej static void 154 1.28 xtraeme makphyattach(device_t parent, device_t self, void *aux) 155 1.1 thorpej { 156 1.18 thorpej struct mii_softc *sc = device_private(self); 157 1.1 thorpej struct mii_attach_args *ma = aux; 158 1.1 thorpej struct mii_data *mii = ma->mii_data; 159 1.1 thorpej const struct mii_phydesc *mpd; 160 1.58 msaitoh struct makphy_softc *maksc = (struct makphy_softc *)sc; 161 1.54 msaitoh const char *name; 162 1.58 msaitoh uint16_t reg, model; 163 1.69 msaitoh int rv; 164 1.1 thorpej 165 1.46 msaitoh mpd = mii_phy_match(ma, makphys); 166 1.12 thorpej aprint_naive(": Media interface\n"); 167 1.54 msaitoh if (mpd) 168 1.54 msaitoh name = mpd->mpd_name; 169 1.58 msaitoh else if (makphy_isi210(parent, ma)) { 170 1.54 msaitoh name = MII_STR_xxMARVELL_I210; 171 1.58 msaitoh maksc->sc_flags |= MAKPHY_F_I210; 172 1.58 msaitoh } else 173 1.54 msaitoh panic("Unknown PHY"); 174 1.54 msaitoh aprint_normal(": %s, rev. %d\n", name, MII_REV(ma->mii_id2)); 175 1.1 thorpej 176 1.28 xtraeme sc->mii_dev = self; 177 1.42 msaitoh sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2); 178 1.58 msaitoh sc->mii_mpd_model = model = MII_MODEL(ma->mii_id2); 179 1.42 msaitoh sc->mii_mpd_rev = MII_REV(ma->mii_id2); 180 1.1 thorpej sc->mii_inst = mii->mii_instance; 181 1.1 thorpej sc->mii_phy = ma->mii_phyno; 182 1.46 msaitoh sc->mii_funcs = &makphy_funcs; 183 1.1 thorpej sc->mii_pdata = mii; 184 1.6 thorpej sc->mii_flags = ma->mii_flags; 185 1.1 thorpej 186 1.65 thorpej mii_lock(mii); 187 1.65 thorpej 188 1.58 msaitoh switch (model) { 189 1.58 msaitoh case MII_MODEL_xxMARVELL_E1000: 190 1.58 msaitoh if ((maksc->sc_flags & MAKPHY_F_I210) != 0) 191 1.58 msaitoh goto page0; 192 1.58 msaitoh /* FALLTHROUGH */ 193 1.58 msaitoh case MII_MODEL_xxMARVELL_E1000_3: 194 1.58 msaitoh case MII_MODEL_xxMARVELL_E1000S: 195 1.58 msaitoh case MII_MODEL_xxMARVELL_E1000_5: 196 1.58 msaitoh /* 88E1000 series has no EADR */ 197 1.58 msaitoh break; 198 1.58 msaitoh default: 199 1.58 msaitoh page0: 200 1.58 msaitoh /* Make sure page 0 is selected. */ 201 1.58 msaitoh if (PHY_WRITE(sc, MAKPHY_EADR, 0) != 0) 202 1.58 msaitoh aprint_verbose_dev(self, 203 1.58 msaitoh "Failed to access EADR. Are you an emulator?\n"); 204 1.58 msaitoh break; 205 1.58 msaitoh } 206 1.44 jdolecek 207 1.1 thorpej PHY_RESET(sc); 208 1.1 thorpej 209 1.52 msaitoh PHY_READ(sc, MII_BMSR, &sc->mii_capabilities); 210 1.52 msaitoh sc->mii_capabilities &= ma->mii_capmask; 211 1.69 msaitoh if (sc->mii_capabilities & BMSR_EXTSTAT) { 212 1.69 msaitoh rv = PHY_READ(sc, MII_EXTSR, &sc->mii_extcapabilities); 213 1.69 msaitoh if (rv != 0) { 214 1.69 msaitoh aprint_verbose_dev(self, "Failed to read EXTSR. " 215 1.69 msaitoh "Are you an emulator?. " 216 1.69 msaitoh "Regard as 1000BASE-T.\n"); 217 1.69 msaitoh sc->mii_extcapabilities 218 1.69 msaitoh |= EXTSR_1000TFDX | EXTSR_1000THDX; 219 1.72 msaitoh 220 1.72 msaitoh /* 221 1.72 msaitoh * Also assume it doesn't support PSSR_LINK bit. 222 1.72 msaitoh * It's for QEMU. 223 1.72 msaitoh */ 224 1.72 msaitoh maksc->sc_flags |= MAKPHY_QUIRK_PSSR_LINK; 225 1.69 msaitoh } 226 1.69 msaitoh } 227 1.1 thorpej 228 1.63 msaitoh if (((sc->mii_extcapabilities & (EXTSR_1000TFDX | EXTSR_1000THDX)) 229 1.63 msaitoh != 0) 230 1.63 msaitoh && ((sc->mii_extcapabilities & (EXTSR_1000XFDX | EXTSR_1000XHDX)) 231 1.63 msaitoh != 0)) { 232 1.63 msaitoh bool fiberonly = false, copperonly = false; 233 1.63 msaitoh 234 1.64 msaitoh /* Both copper and fiber are set. check MODE[] */ 235 1.63 msaitoh switch (sc->mii_mpd_model) { 236 1.63 msaitoh case MII_MODEL_xxMARVELL_E1011: 237 1.63 msaitoh case MII_MODEL_xxMARVELL_E1111: 238 1.63 msaitoh /* These devices have ESSR register */ 239 1.70 msaitoh rv = PHY_READ(sc, MAKPHY_ESSR, ®); 240 1.70 msaitoh if (rv != 0) { 241 1.70 msaitoh /* 242 1.70 msaitoh * XXX Emulator (e.g qemu) may not implement 243 1.70 msaitoh * the ESSR register. If so, regard as copper 244 1.70 msaitoh * media. 245 1.70 msaitoh */ 246 1.70 msaitoh copperonly = true; 247 1.70 msaitoh aprint_verbose_dev(self, "Failed to access " 248 1.70 msaitoh "ESSR. Are you an emulator? Regard as " 249 1.70 msaitoh "copper only media.\n"); 250 1.70 msaitoh } else if ((reg & ESSR_AUTOSEL_DISABLE) != 0) { 251 1.63 msaitoh switch (reg & ESSR_HWCFG_MODE) { 252 1.63 msaitoh case ESSR_RTBI_FIBER: 253 1.63 msaitoh case ESSR_RGMII_FIBER: 254 1.63 msaitoh case ESSR_RGMII_SGMII: /* right? */ 255 1.63 msaitoh case ESSR_TBI_FIBER: 256 1.63 msaitoh case ESSR_GMII_FIBER: 257 1.63 msaitoh fiberonly = true; 258 1.63 msaitoh break; 259 1.63 msaitoh case ESSR_SGMII_WC_COPPER: 260 1.63 msaitoh case ESSR_SGMII_WOC_COPPER: 261 1.63 msaitoh case ESSR_RTBI_COPPER: 262 1.63 msaitoh case ESSR_RGMII_COPPER: 263 1.63 msaitoh case ESSR_GMII_COPPER: 264 1.63 msaitoh copperonly = true; 265 1.63 msaitoh default: 266 1.63 msaitoh break; 267 1.63 msaitoh } 268 1.71 msaitoh } else 269 1.71 msaitoh maksc->sc_flags |= MAKPHY_F_FICO_AUTOSEL; 270 1.63 msaitoh break; 271 1.63 msaitoh default: 272 1.63 msaitoh break; 273 1.63 msaitoh } 274 1.63 msaitoh if (fiberonly || copperonly) 275 1.63 msaitoh aprint_debug_dev(self, "both copper and fiber are set " 276 1.63 msaitoh "but MODE[] is %s only.\n", 277 1.63 msaitoh fiberonly ? "fiber" : "copper"); 278 1.63 msaitoh if (fiberonly) 279 1.63 msaitoh sc->mii_extcapabilities 280 1.63 msaitoh &= ~(EXTSR_1000TFDX | EXTSR_1000THDX); 281 1.63 msaitoh else if (copperonly) { 282 1.63 msaitoh sc->mii_extcapabilities 283 1.63 msaitoh &= ~(EXTSR_1000XFDX | EXTSR_1000XHDX); 284 1.63 msaitoh sc->mii_flags &= ~MIIF_IS_1000X; 285 1.63 msaitoh } 286 1.63 msaitoh } 287 1.65 thorpej mii_unlock(mii); 288 1.62 msaitoh mii_phy_add_media(sc); 289 1.1 thorpej } 290 1.1 thorpej 291 1.23 msaitoh static void 292 1.23 msaitoh makphy_reset(struct mii_softc *sc) 293 1.23 msaitoh { 294 1.58 msaitoh struct makphy_softc *maksc = (struct makphy_softc *)sc; 295 1.51 msaitoh uint16_t reg; 296 1.44 jdolecek 297 1.65 thorpej KASSERT(mii_locked(sc->mii_pdata)); 298 1.65 thorpej 299 1.46 msaitoh mii_phy_reset(sc); 300 1.44 jdolecek 301 1.61 msaitoh /* Initialize PHY Specific Control Register. */ 302 1.52 msaitoh PHY_READ(sc, MAKPHY_PSCR, ®); 303 1.44 jdolecek 304 1.44 jdolecek /* Assert CRS on transmit. */ 305 1.44 jdolecek switch (sc->mii_mpd_model) { 306 1.46 msaitoh case MII_MODEL_MARVELL_E1000_0: 307 1.58 msaitoh if ((maksc->sc_flags & MAKPHY_F_I210) != 0) 308 1.58 msaitoh break; 309 1.58 msaitoh /* FALLTHROUGH */ 310 1.46 msaitoh case MII_MODEL_MARVELL_E1000_3: 311 1.46 msaitoh case MII_MODEL_MARVELL_E1000_5: 312 1.46 msaitoh case MII_MODEL_MARVELL_E1000_6: 313 1.46 msaitoh case MII_MODEL_xxMARVELL_E1000S: 314 1.46 msaitoh case MII_MODEL_xxMARVELL_E1011: 315 1.46 msaitoh case MII_MODEL_xxMARVELL_E1111: 316 1.46 msaitoh reg |= PSCR_CRS_ON_TX; 317 1.44 jdolecek break; 318 1.46 msaitoh default: /* No PSCR_CRS_ON_TX bit */ 319 1.44 jdolecek break; 320 1.44 jdolecek } 321 1.44 jdolecek 322 1.44 jdolecek /* Enable scrambler if necessary. */ 323 1.44 jdolecek if (sc->mii_mpd_model == MII_MODEL_xxMARVELL_E3016) 324 1.46 msaitoh reg &= ~E3016_PSCR_SCRAMBLE_DIS; 325 1.44 jdolecek 326 1.44 jdolecek /* 327 1.44 jdolecek * Store next page in the Link Partner Next Page register for 328 1.44 jdolecek * compatibility with 802.3ab. 329 1.44 jdolecek */ 330 1.44 jdolecek if (sc->mii_mpd_model == MII_MODEL_xxMARVELL_E3016) 331 1.46 msaitoh reg |= E3016_PSCR_REG8NXTPG; 332 1.44 jdolecek 333 1.46 msaitoh PHY_WRITE(sc, MAKPHY_PSCR, reg); 334 1.44 jdolecek 335 1.44 jdolecek /* Configure LEDs if they were left unconfigured. */ 336 1.52 msaitoh if (sc->mii_mpd_model == MII_MODEL_xxMARVELL_E3016) { 337 1.52 msaitoh PHY_READ(sc, 0x16, ®); 338 1.52 msaitoh if (reg == 0) { 339 1.52 msaitoh reg = (0x0b << 8) | (0x05 << 4) | 0x04; /* XXX */ 340 1.52 msaitoh PHY_WRITE(sc, 0x16, reg); 341 1.52 msaitoh } 342 1.44 jdolecek } 343 1.23 msaitoh 344 1.46 msaitoh mii_phy_reset(sc); 345 1.23 msaitoh } 346 1.23 msaitoh 347 1.47 msaitoh static void 348 1.47 msaitoh makphy_pdown(struct mii_softc *sc, bool pdown) 349 1.47 msaitoh { 350 1.52 msaitoh uint16_t bmcr, new; 351 1.47 msaitoh bool need_reset = false; 352 1.47 msaitoh 353 1.47 msaitoh /* 354 1.47 msaitoh * XXX 355 1.47 msaitoh * PSCR (register 16) should be modified on some chips. 356 1.47 msaitoh */ 357 1.47 msaitoh 358 1.52 msaitoh PHY_READ(sc, MII_BMCR, &bmcr); 359 1.47 msaitoh if (pdown) 360 1.47 msaitoh new = bmcr | BMCR_PDOWN; 361 1.47 msaitoh else 362 1.47 msaitoh new = bmcr & ~BMCR_PDOWN; 363 1.47 msaitoh if (bmcr != new) 364 1.47 msaitoh need_reset = true; 365 1.47 msaitoh 366 1.47 msaitoh if (need_reset) 367 1.47 msaitoh new |= BMCR_RESET; 368 1.47 msaitoh PHY_WRITE(sc, MII_BMCR, new); 369 1.47 msaitoh } 370 1.47 msaitoh 371 1.15 thorpej static int 372 1.3 thorpej makphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 373 1.1 thorpej { 374 1.1 thorpej struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 375 1.52 msaitoh uint16_t bmcr; 376 1.44 jdolecek 377 1.44 jdolecek if (!device_is_active(sc->mii_dev)) 378 1.54 msaitoh return ENXIO; 379 1.1 thorpej 380 1.65 thorpej KASSERT(mii_locked(mii)); 381 1.65 thorpej 382 1.1 thorpej switch (cmd) { 383 1.1 thorpej case MII_POLLSTAT: 384 1.59 msaitoh /* If we're not polling our PHY instance, just return. */ 385 1.1 thorpej if (IFM_INST(ife->ifm_media) != sc->mii_inst) 386 1.54 msaitoh return 0; 387 1.1 thorpej break; 388 1.1 thorpej 389 1.1 thorpej case MII_MEDIACHG: 390 1.1 thorpej /* 391 1.1 thorpej * If the media indicates a different PHY instance, 392 1.1 thorpej * isolate ourselves. 393 1.1 thorpej */ 394 1.1 thorpej if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 395 1.52 msaitoh PHY_READ(sc, MII_BMCR, &bmcr); 396 1.45 msaitoh PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO); 397 1.54 msaitoh return 0; 398 1.1 thorpej } 399 1.1 thorpej 400 1.59 msaitoh /* If the interface is not up, don't do anything. */ 401 1.1 thorpej if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 402 1.1 thorpej break; 403 1.1 thorpej 404 1.47 msaitoh /* Try to power up the PHY in case it's down */ 405 1.47 msaitoh if (IFM_SUBTYPE(ife->ifm_media) != IFM_NONE) 406 1.47 msaitoh makphy_pdown(sc, MAKARG_PUP); 407 1.47 msaitoh 408 1.1 thorpej mii_phy_setmedia(sc); 409 1.44 jdolecek 410 1.44 jdolecek /* 411 1.73 andvar * If autonegotiation is not enabled, we need a 412 1.44 jdolecek * software reset for the settings to take effect. 413 1.44 jdolecek */ 414 1.47 msaitoh if (IFM_SUBTYPE(ife->ifm_media) == IFM_NONE) 415 1.47 msaitoh makphy_pdown(sc, MAKARG_PDOWN); 416 1.47 msaitoh else if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { 417 1.52 msaitoh PHY_READ(sc, MII_BMCR, &bmcr); 418 1.45 msaitoh PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_RESET); 419 1.20 bouyer } 420 1.1 thorpej break; 421 1.1 thorpej 422 1.1 thorpej case MII_TICK: 423 1.59 msaitoh /* If we're not currently selected, just return. */ 424 1.1 thorpej if (IFM_INST(ife->ifm_media) != sc->mii_inst) 425 1.54 msaitoh return 0; 426 1.1 thorpej 427 1.1 thorpej if (mii_phy_tick(sc) == EJUSTRETURN) 428 1.54 msaitoh return 0; 429 1.1 thorpej break; 430 1.1 thorpej 431 1.1 thorpej case MII_DOWN: 432 1.1 thorpej mii_phy_down(sc); 433 1.54 msaitoh return 0; 434 1.1 thorpej } 435 1.1 thorpej 436 1.1 thorpej /* Update the media status. */ 437 1.1 thorpej mii_phy_status(sc); 438 1.1 thorpej 439 1.1 thorpej /* Callback if something changed. */ 440 1.1 thorpej mii_phy_update(sc, cmd); 441 1.54 msaitoh return 0; 442 1.1 thorpej } 443 1.1 thorpej 444 1.15 thorpej static void 445 1.3 thorpej makphy_status(struct mii_softc *sc) 446 1.1 thorpej { 447 1.72 msaitoh struct makphy_softc *maksc = (struct makphy_softc *)sc; 448 1.1 thorpej struct mii_data *mii = sc->mii_pdata; 449 1.63 msaitoh uint16_t bmcr, gsr, pssr, essr; 450 1.1 thorpej 451 1.65 thorpej KASSERT(mii_locked(mii)); 452 1.65 thorpej 453 1.1 thorpej mii->mii_media_status = IFM_AVALID; 454 1.1 thorpej mii->mii_media_active = IFM_ETHER; 455 1.1 thorpej 456 1.52 msaitoh PHY_READ(sc, MII_BMCR, &bmcr); 457 1.46 msaitoh /* XXX FIXME: Use different page for Fiber on newer chips */ 458 1.52 msaitoh PHY_READ(sc, MAKPHY_PSSR, &pssr); 459 1.1 thorpej 460 1.72 msaitoh if ((maksc->sc_flags & MAKPHY_QUIRK_PSSR_LINK) != 0) { 461 1.72 msaitoh uint16_t bmsr; 462 1.72 msaitoh 463 1.72 msaitoh /* 464 1.72 msaitoh * QEMU e1000 driver has the PSSR register but it doesn't 465 1.72 msaitoh * support the PSSR_LINK bit well. It always returns 1. 466 1.72 msaitoh * To avoid this problem, use the BMSR_LINK bit. It's not 467 1.72 msaitoh * required to read it twice as real device because it's not 468 1.72 msaitoh * latched. 469 1.72 msaitoh */ 470 1.72 msaitoh PHY_READ(sc, MII_BMSR, &bmsr); 471 1.72 msaitoh if (bmsr & BMSR_LINK) 472 1.72 msaitoh pssr |= MAKPHY_PSSR_LINK; 473 1.72 msaitoh else 474 1.72 msaitoh pssr &= ~MAKPHY_PSSR_LINK; 475 1.72 msaitoh } 476 1.72 msaitoh 477 1.66 msaitoh if (pssr & MAKPHY_PSSR_LINK) 478 1.1 thorpej mii->mii_media_status |= IFM_ACTIVE; 479 1.1 thorpej 480 1.47 msaitoh if (bmcr & BMCR_LOOP) 481 1.47 msaitoh mii->mii_media_active |= IFM_LOOP; 482 1.47 msaitoh 483 1.68 msaitoh if (bmcr & (BMCR_ISO | BMCR_PDOWN)) { 484 1.45 msaitoh mii->mii_media_active |= IFM_NONE; 485 1.45 msaitoh return; 486 1.45 msaitoh } 487 1.45 msaitoh 488 1.47 msaitoh if ((bmcr & BMCR_AUTOEN) != 0) { 489 1.47 msaitoh /* 490 1.47 msaitoh * Check Speed and Duplex Resolved bit. 491 1.47 msaitoh * Note that this bit is always 1 when autonego is not enabled. 492 1.47 msaitoh */ 493 1.66 msaitoh if (!(pssr & MAKPHY_PSSR_RESOLVED)) { 494 1.47 msaitoh /* Erg, still trying, I guess... */ 495 1.47 msaitoh mii->mii_media_active |= IFM_NONE; 496 1.47 msaitoh return; 497 1.47 msaitoh } 498 1.47 msaitoh } else { 499 1.66 msaitoh if ((pssr & MAKPHY_PSSR_LINK) == 0) { 500 1.47 msaitoh mii->mii_media_active |= IFM_NONE; 501 1.47 msaitoh return; 502 1.47 msaitoh } 503 1.1 thorpej } 504 1.1 thorpej 505 1.63 msaitoh /* 506 1.63 msaitoh * XXX The following code support Fiber/Copper auto select mode 507 1.63 msaitoh * only for 88E1011, 88E1111 and 88E1112. For other chips, the document 508 1.63 msaitoh * is required. 509 1.63 msaitoh */ 510 1.44 jdolecek if (sc->mii_flags & MIIF_IS_1000X) { 511 1.63 msaitoh /* Not in Fiber/Copper auto select mode */ 512 1.63 msaitoh mii->mii_media_active |= IFM_1000_SX; 513 1.63 msaitoh } else if ((sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1011) || 514 1.63 msaitoh (sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1111)) { 515 1.71 msaitoh if ((maksc->sc_flags & MAKPHY_F_FICO_AUTOSEL) != 0) { 516 1.71 msaitoh /* Fiber/Copper auto select mode */ 517 1.71 msaitoh PHY_READ(sc, MAKPHY_ESSR, &essr); 518 1.71 msaitoh if ((essr & ESSR_FIBER_LINK) == 0) 519 1.71 msaitoh goto copper; 520 1.71 msaitoh else { 521 1.71 msaitoh /* Regard as 1000BASE-SX */ 522 1.71 msaitoh mii->mii_media_active |= IFM_1000_SX; 523 1.71 msaitoh } 524 1.71 msaitoh } else 525 1.63 msaitoh goto copper; 526 1.63 msaitoh } else if (sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1112) { 527 1.63 msaitoh /* Fiber/Copper auto select mode */ 528 1.63 msaitoh 529 1.63 msaitoh PHY_READ(sc, MAKPHY_PSSR, &pssr); 530 1.66 msaitoh if ((pssr & MAKPHY_PSSR_RESOLUTION_FIBER) == 0) 531 1.63 msaitoh goto copper; 532 1.63 msaitoh 533 1.66 msaitoh switch (MAKPHY_PSSR_SPEED_get(pssr)) { 534 1.63 msaitoh case SPEED_1000: 535 1.63 msaitoh mii->mii_media_active |= IFM_1000_SX; 536 1.63 msaitoh break; 537 1.63 msaitoh case SPEED_100: 538 1.63 msaitoh mii->mii_media_active |= IFM_100_FX; 539 1.63 msaitoh break; 540 1.63 msaitoh default: /* Undefined (reserved) value */ 541 1.63 msaitoh mii->mii_media_active |= IFM_NONE; 542 1.63 msaitoh mii->mii_media_status = 0; 543 1.63 msaitoh return; 544 1.63 msaitoh } 545 1.44 jdolecek } else { 546 1.63 msaitoh copper: 547 1.66 msaitoh switch (MAKPHY_PSSR_SPEED_get(pssr)) { 548 1.46 msaitoh case SPEED_1000: 549 1.1 thorpej mii->mii_media_active |= IFM_1000_T; 550 1.46 msaitoh break; 551 1.46 msaitoh case SPEED_100: 552 1.1 thorpej mii->mii_media_active |= IFM_100_TX; 553 1.46 msaitoh break; 554 1.46 msaitoh case SPEED_10: 555 1.1 thorpej mii->mii_media_active |= IFM_10_T; 556 1.46 msaitoh break; 557 1.47 msaitoh default: /* Undefined (reserved) value */ 558 1.46 msaitoh mii->mii_media_active |= IFM_NONE; 559 1.46 msaitoh mii->mii_media_status = 0; 560 1.46 msaitoh return; 561 1.46 msaitoh } 562 1.44 jdolecek } 563 1.1 thorpej 564 1.66 msaitoh if (pssr & MAKPHY_PSSR_DUPLEX) 565 1.44 jdolecek mii->mii_media_active |= mii_phy_flowstatus(sc) | IFM_FDX; 566 1.44 jdolecek else 567 1.44 jdolecek mii->mii_media_active |= IFM_HDX; 568 1.1 thorpej 569 1.44 jdolecek if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { 570 1.52 msaitoh PHY_READ(sc, MII_100T2SR, &gsr); 571 1.45 msaitoh if (gsr & GTSR_MS_RES) 572 1.44 jdolecek mii->mii_media_active |= IFM_ETH_MASTER; 573 1.44 jdolecek } 574 1.1 thorpej } 575