1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2001-2003, Shunsuke Akiyama <akiyama@FreeBSD.org>. 5 * 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 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 */ 29 30 /* 31 * driver for RealTek RTL8150 internal PHY 32 */ 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kernel.h> 37 #include <sys/malloc.h> 38 #include <sys/module.h> 39 #include <sys/socket.h> 40 #include <sys/bus.h> 41 42 #include <net/if.h> 43 #include <net/if_arp.h> 44 #include <net/if_media.h> 45 46 #include <dev/mii/mii.h> 47 #include <dev/mii/miivar.h> 48 #include "miidevs.h" 49 50 #include <dev/usb/net/ruephyreg.h> 51 52 #include "miibus_if.h" 53 54 static int ruephy_probe(device_t); 55 static int ruephy_attach(device_t); 56 57 static device_method_t ruephy_methods[] = { 58 /* device interface */ 59 DEVMETHOD(device_probe, ruephy_probe), 60 DEVMETHOD(device_attach, ruephy_attach), 61 DEVMETHOD(device_detach, mii_phy_detach), 62 DEVMETHOD(device_shutdown, bus_generic_shutdown), 63 DEVMETHOD_END 64 }; 65 66 static driver_t ruephy_driver = { 67 .name = "ruephy", 68 .methods = ruephy_methods, 69 .size = sizeof(struct mii_softc) 70 }; 71 72 DRIVER_MODULE(ruephy, miibus, ruephy_driver, 0, 0); 73 74 static int ruephy_service(struct mii_softc *, struct mii_data *, int); 75 static void ruephy_reset(struct mii_softc *); 76 static void ruephy_status(struct mii_softc *); 77 78 /* 79 * The RealTek RTL8150 internal PHY doesn't have vendor/device ID 80 * registers; rue(4) fakes up a return value of all zeros. 81 */ 82 static const struct mii_phydesc ruephys[] = { 83 { 0, 0, "RealTek RTL8150 internal media interface" }, 84 MII_PHY_END 85 }; 86 87 static const struct mii_phy_funcs ruephy_funcs = { 88 ruephy_service, 89 ruephy_status, 90 ruephy_reset 91 }; 92 93 static int 94 ruephy_probe(device_t dev) 95 { 96 97 if (strcmp(device_get_name(device_get_parent(device_get_parent(dev))), 98 "rue") == 0) 99 return (mii_phy_dev_probe(dev, ruephys, BUS_PROBE_DEFAULT)); 100 return (ENXIO); 101 } 102 103 static int 104 ruephy_attach(device_t dev) 105 { 106 107 mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, 108 &ruephy_funcs, 1); 109 return (0); 110 } 111 112 static int 113 ruephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 114 { 115 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 116 int reg; 117 118 switch (cmd) { 119 case MII_POLLSTAT: 120 break; 121 122 case MII_MEDIACHG: 123 mii_phy_setmedia(sc); 124 break; 125 126 case MII_TICK: 127 /* 128 * Only used for autonegotiation. 129 */ 130 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 131 break; 132 133 /* 134 * Check to see if we have link. If we do, we don't 135 * need to restart the autonegotiation process. Read 136 * the MSR twice in case it's latched. 137 */ 138 reg = PHY_READ(sc, RUEPHY_MII_MSR) | 139 PHY_READ(sc, RUEPHY_MII_MSR); 140 if (reg & RUEPHY_MSR_LINK) 141 break; 142 143 /* Only retry autonegotiation every mii_anegticks seconds. */ 144 if (sc->mii_ticks <= sc->mii_anegticks) 145 break; 146 147 sc->mii_ticks = 0; 148 PHY_RESET(sc); 149 if (mii_phy_auto(sc) == EJUSTRETURN) 150 return (0); 151 break; 152 } 153 154 /* Update the media status. */ 155 PHY_STATUS(sc); 156 157 /* Callback if something changed. */ 158 mii_phy_update(sc, cmd); 159 160 return (0); 161 } 162 163 static void 164 ruephy_reset(struct mii_softc *sc) 165 { 166 167 mii_phy_reset(sc); 168 169 /* 170 * XXX RealTek RTL8150 PHY doesn't set the BMCR properly after 171 * XXX reset, which breaks autonegotiation. 172 */ 173 PHY_WRITE(sc, MII_BMCR, (BMCR_S100 | BMCR_AUTOEN | BMCR_FDX)); 174 } 175 176 static void 177 ruephy_status(struct mii_softc *phy) 178 { 179 struct mii_data *mii = phy->mii_pdata; 180 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 181 int bmsr, bmcr, msr; 182 183 mii->mii_media_status = IFM_AVALID; 184 mii->mii_media_active = IFM_ETHER; 185 186 msr = PHY_READ(phy, RUEPHY_MII_MSR) | PHY_READ(phy, RUEPHY_MII_MSR); 187 if (msr & RUEPHY_MSR_LINK) 188 mii->mii_media_status |= IFM_ACTIVE; 189 190 bmcr = PHY_READ(phy, MII_BMCR); 191 if (bmcr & BMCR_ISO) { 192 mii->mii_media_active |= IFM_NONE; 193 mii->mii_media_status = 0; 194 return; 195 } 196 197 bmsr = PHY_READ(phy, MII_BMSR) | PHY_READ(phy, MII_BMSR); 198 if (bmcr & BMCR_AUTOEN) { 199 if ((bmsr & BMSR_ACOMP) == 0) { 200 /* Erg, still trying, I guess... */ 201 mii->mii_media_active |= IFM_NONE; 202 return; 203 } 204 205 if (msr & RUEPHY_MSR_SPEED100) 206 mii->mii_media_active |= IFM_100_TX; 207 else 208 mii->mii_media_active |= IFM_10_T; 209 210 if (msr & RUEPHY_MSR_DUPLEX) 211 mii->mii_media_active |= 212 IFM_FDX | mii_phy_flowstatus(phy); 213 else 214 mii->mii_media_active |= IFM_HDX; 215 } else 216 mii->mii_media_active = ife->ifm_media; 217 } 218