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