1 /*- 2 * SPDX-License-Identifier: BSD-4-Clause 3 * 4 * Copyright (c) 2004 5 * Bill Paul <wpaul@windriver.com>. 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 #include <sys/cdefs.h> 36 __FBSDID("$FreeBSD$"); 37 38 /* 39 * Driver for the Cicada/Vitesse CS/VSC8xxx 10/100/1000 copper PHY. 40 */ 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/kernel.h> 45 #include <sys/module.h> 46 #include <sys/socket.h> 47 #include <sys/bus.h> 48 49 #include <net/if.h> 50 #include <net/if_arp.h> 51 #include <net/if_media.h> 52 53 #include <dev/mii/mii.h> 54 #include <dev/mii/miivar.h> 55 #include "miidevs.h" 56 57 #include <dev/mii/ciphyreg.h> 58 59 #include "miibus_if.h" 60 61 #include <machine/bus.h> 62 63 static int ciphy_probe(device_t); 64 static int ciphy_attach(device_t); 65 66 static device_method_t ciphy_methods[] = { 67 /* device interface */ 68 DEVMETHOD(device_probe, ciphy_probe), 69 DEVMETHOD(device_attach, ciphy_attach), 70 DEVMETHOD(device_detach, mii_phy_detach), 71 DEVMETHOD(device_shutdown, bus_generic_shutdown), 72 DEVMETHOD_END 73 }; 74 75 static devclass_t ciphy_devclass; 76 77 static driver_t ciphy_driver = { 78 "ciphy", 79 ciphy_methods, 80 sizeof(struct mii_softc) 81 }; 82 83 DRIVER_MODULE(ciphy, miibus, ciphy_driver, ciphy_devclass, 0, 0); 84 85 static int ciphy_service(struct mii_softc *, struct mii_data *, int); 86 static void ciphy_status(struct mii_softc *); 87 static void ciphy_reset(struct mii_softc *); 88 static void ciphy_fixup(struct mii_softc *); 89 90 static const struct mii_phydesc ciphys[] = { 91 MII_PHY_DESC(xxCICADA, CS8201), 92 MII_PHY_DESC(xxCICADA, CS8201A), 93 MII_PHY_DESC(xxCICADA, CS8201B), 94 MII_PHY_DESC(xxCICADA, CS8204), 95 MII_PHY_DESC(xxCICADA, VSC8211), 96 MII_PHY_DESC(xxCICADA, VSC8221), 97 MII_PHY_DESC(xxCICADA, CS8244), 98 MII_PHY_DESC(xxVITESSE, VSC8601), 99 MII_PHY_DESC(xxVITESSE, VSC8641), 100 MII_PHY_END 101 }; 102 103 static const struct mii_phy_funcs ciphy_funcs = { 104 ciphy_service, 105 ciphy_status, 106 ciphy_reset 107 }; 108 109 static int 110 ciphy_probe(device_t dev) 111 { 112 113 return (mii_phy_dev_probe(dev, ciphys, BUS_PROBE_DEFAULT)); 114 } 115 116 static int 117 ciphy_attach(device_t dev) 118 { 119 120 mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, 121 &ciphy_funcs, 1); 122 return (0); 123 } 124 125 static int 126 ciphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 127 { 128 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 129 int reg, speed, gig; 130 131 switch (cmd) { 132 case MII_POLLSTAT: 133 break; 134 135 case MII_MEDIACHG: 136 ciphy_fixup(sc); /* XXX hardware bug work-around */ 137 138 switch (IFM_SUBTYPE(ife->ifm_media)) { 139 case IFM_AUTO: 140 #ifdef foo 141 /* 142 * If we're already in auto mode, just return. 143 */ 144 if (PHY_READ(sc, CIPHY_MII_BMCR) & CIPHY_BMCR_AUTOEN) 145 return (0); 146 #endif 147 (void)mii_phy_auto(sc); 148 break; 149 case IFM_1000_T: 150 speed = CIPHY_S1000; 151 goto setit; 152 case IFM_100_TX: 153 speed = CIPHY_S100; 154 goto setit; 155 case IFM_10_T: 156 speed = CIPHY_S10; 157 setit: 158 if ((ife->ifm_media & IFM_FDX) != 0) { 159 speed |= CIPHY_BMCR_FDX; 160 gig = CIPHY_1000CTL_AFD; 161 } else 162 gig = CIPHY_1000CTL_AHD; 163 164 if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { 165 gig |= CIPHY_1000CTL_MSE; 166 if ((ife->ifm_media & IFM_ETH_MASTER) != 0) 167 gig |= CIPHY_1000CTL_MSC; 168 speed |= 169 CIPHY_BMCR_AUTOEN | CIPHY_BMCR_STARTNEG; 170 } else 171 gig = 0; 172 PHY_WRITE(sc, CIPHY_MII_1000CTL, gig); 173 PHY_WRITE(sc, CIPHY_MII_BMCR, speed); 174 PHY_WRITE(sc, CIPHY_MII_ANAR, CIPHY_SEL_TYPE); 175 break; 176 case IFM_NONE: 177 PHY_WRITE(sc, MII_BMCR, BMCR_ISO | BMCR_PDOWN); 178 break; 179 default: 180 return (EINVAL); 181 } 182 break; 183 184 case MII_TICK: 185 /* 186 * Only used for autonegotiation. 187 */ 188 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 189 break; 190 191 /* 192 * Check to see if we have link. If we do, we don't 193 * need to restart the autonegotiation process. Read 194 * the BMSR twice in case it's latched. 195 */ 196 reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 197 if (reg & BMSR_LINK) 198 break; 199 200 /* Announce link loss right after it happens. */ 201 if (++sc->mii_ticks == 0) 202 break; 203 /* 204 * Only retry autonegotiation every mii_anegticks seconds. 205 */ 206 if (sc->mii_ticks <= sc->mii_anegticks) 207 break; 208 209 sc->mii_ticks = 0; 210 mii_phy_auto(sc); 211 break; 212 } 213 214 /* Update the media status. */ 215 PHY_STATUS(sc); 216 217 /* 218 * Callback if something changed. Note that we need to poke 219 * apply fixups for certain PHY revs. 220 */ 221 if (sc->mii_media_active != mii->mii_media_active || 222 sc->mii_media_status != mii->mii_media_status || 223 cmd == MII_MEDIACHG) { 224 ciphy_fixup(sc); 225 } 226 mii_phy_update(sc, cmd); 227 return (0); 228 } 229 230 static void 231 ciphy_status(struct mii_softc *sc) 232 { 233 struct mii_data *mii = sc->mii_pdata; 234 int bmsr, bmcr; 235 236 mii->mii_media_status = IFM_AVALID; 237 mii->mii_media_active = IFM_ETHER; 238 239 bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 240 241 if (bmsr & BMSR_LINK) 242 mii->mii_media_status |= IFM_ACTIVE; 243 244 bmcr = PHY_READ(sc, CIPHY_MII_BMCR); 245 246 if (bmcr & CIPHY_BMCR_LOOP) 247 mii->mii_media_active |= IFM_LOOP; 248 249 if (bmcr & CIPHY_BMCR_AUTOEN) { 250 if ((bmsr & CIPHY_BMSR_ACOMP) == 0) { 251 /* Erg, still trying, I guess... */ 252 mii->mii_media_active |= IFM_NONE; 253 return; 254 } 255 } 256 257 bmsr = PHY_READ(sc, CIPHY_MII_AUXCSR); 258 switch (bmsr & CIPHY_AUXCSR_SPEED) { 259 case CIPHY_SPEED10: 260 mii->mii_media_active |= IFM_10_T; 261 break; 262 case CIPHY_SPEED100: 263 mii->mii_media_active |= IFM_100_TX; 264 break; 265 case CIPHY_SPEED1000: 266 mii->mii_media_active |= IFM_1000_T; 267 break; 268 default: 269 device_printf(sc->mii_dev, "unknown PHY speed %x\n", 270 bmsr & CIPHY_AUXCSR_SPEED); 271 break; 272 } 273 274 if (bmsr & CIPHY_AUXCSR_FDX) 275 mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc); 276 else 277 mii->mii_media_active |= IFM_HDX; 278 279 if ((IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) && 280 (PHY_READ(sc, CIPHY_MII_1000STS) & CIPHY_1000STS_MSR) != 0) 281 mii->mii_media_active |= IFM_ETH_MASTER; 282 } 283 284 static void 285 ciphy_reset(struct mii_softc *sc) 286 { 287 288 mii_phy_reset(sc); 289 DELAY(1000); 290 } 291 292 #define PHY_SETBIT(x, y, z) \ 293 PHY_WRITE(x, y, (PHY_READ(x, y) | (z))) 294 #define PHY_CLRBIT(x, y, z) \ 295 PHY_WRITE(x, y, (PHY_READ(x, y) & ~(z))) 296 297 static void 298 ciphy_fixup(struct mii_softc *sc) 299 { 300 uint16_t model; 301 uint16_t status, speed; 302 uint16_t val; 303 304 model = MII_MODEL(PHY_READ(sc, CIPHY_MII_PHYIDR2)); 305 status = PHY_READ(sc, CIPHY_MII_AUXCSR); 306 speed = status & CIPHY_AUXCSR_SPEED; 307 308 if (mii_phy_mac_match(sc, "nfe")) { 309 /* need to set for 2.5V RGMII for NVIDIA adapters */ 310 val = PHY_READ(sc, CIPHY_MII_ECTL1); 311 val &= ~(CIPHY_ECTL1_IOVOL | CIPHY_ECTL1_INTSEL); 312 val |= (CIPHY_IOVOL_2500MV | CIPHY_INTSEL_RGMII); 313 PHY_WRITE(sc, CIPHY_MII_ECTL1, val); 314 /* From Linux. */ 315 val = PHY_READ(sc, CIPHY_MII_AUXCSR); 316 val |= CIPHY_AUXCSR_MDPPS; 317 PHY_WRITE(sc, CIPHY_MII_AUXCSR, val); 318 val = PHY_READ(sc, CIPHY_MII_10BTCSR); 319 val |= CIPHY_10BTCSR_ECHO; 320 PHY_WRITE(sc, CIPHY_MII_10BTCSR, val); 321 } 322 323 switch (model) { 324 case MII_MODEL_xxCICADA_CS8204: 325 case MII_MODEL_xxCICADA_CS8201: 326 327 /* Turn off "aux mode" (whatever that means) */ 328 PHY_SETBIT(sc, CIPHY_MII_AUXCSR, CIPHY_AUXCSR_MDPPS); 329 330 /* 331 * Work around speed polling bug in VT3119/VT3216 332 * when using MII in full duplex mode. 333 */ 334 if ((speed == CIPHY_SPEED10 || speed == CIPHY_SPEED100) && 335 (status & CIPHY_AUXCSR_FDX)) { 336 PHY_SETBIT(sc, CIPHY_MII_10BTCSR, CIPHY_10BTCSR_ECHO); 337 } else { 338 PHY_CLRBIT(sc, CIPHY_MII_10BTCSR, CIPHY_10BTCSR_ECHO); 339 } 340 341 /* Enable link/activity LED blink. */ 342 PHY_SETBIT(sc, CIPHY_MII_LED, CIPHY_LED_LINKACTBLINK); 343 344 break; 345 346 case MII_MODEL_xxCICADA_CS8201A: 347 case MII_MODEL_xxCICADA_CS8201B: 348 349 /* 350 * Work around speed polling bug in VT3119/VT3216 351 * when using MII in full duplex mode. 352 */ 353 if ((speed == CIPHY_SPEED10 || speed == CIPHY_SPEED100) && 354 (status & CIPHY_AUXCSR_FDX)) { 355 PHY_SETBIT(sc, CIPHY_MII_10BTCSR, CIPHY_10BTCSR_ECHO); 356 } else { 357 PHY_CLRBIT(sc, CIPHY_MII_10BTCSR, CIPHY_10BTCSR_ECHO); 358 } 359 360 break; 361 case MII_MODEL_xxCICADA_VSC8211: 362 case MII_MODEL_xxCICADA_VSC8221: 363 case MII_MODEL_xxCICADA_CS8244: 364 case MII_MODEL_xxVITESSE_VSC8601: 365 case MII_MODEL_xxVITESSE_VSC8641: 366 break; 367 default: 368 device_printf(sc->mii_dev, "unknown CICADA PHY model %x\n", 369 model); 370 break; 371 } 372 } 373