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 #include <sys/cdefs.h> 31 /* 32 * driver for RealTek RTL8150 internal PHY 33 */ 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 #include <sys/malloc.h> 39 #include <sys/module.h> 40 #include <sys/socket.h> 41 #include <sys/bus.h> 42 43 #include <net/if.h> 44 #include <net/if_arp.h> 45 #include <net/if_media.h> 46 47 #include <dev/mii/mii.h> 48 #include <dev/mii/miivar.h> 49 #include "miidevs.h" 50 51 #include <dev/usb/net/ruephyreg.h> 52 53 #include "miibus_if.h" 54 55 static int ruephy_probe(device_t); 56 static int ruephy_attach(device_t); 57 58 static device_method_t ruephy_methods[] = { 59 /* device interface */ 60 DEVMETHOD(device_probe, ruephy_probe), 61 DEVMETHOD(device_attach, ruephy_attach), 62 DEVMETHOD(device_detach, mii_phy_detach), 63 DEVMETHOD(device_shutdown, bus_generic_shutdown), 64 DEVMETHOD_END 65 }; 66 67 static driver_t ruephy_driver = { 68 .name = "ruephy", 69 .methods = ruephy_methods, 70 .size = sizeof(struct mii_softc) 71 }; 72 73 DRIVER_MODULE(ruephy, miibus, ruephy_driver, 0, 0); 74 75 static int ruephy_service(struct mii_softc *, struct mii_data *, int); 76 static void ruephy_reset(struct mii_softc *); 77 static void ruephy_status(struct mii_softc *); 78 79 /* 80 * The RealTek RTL8150 internal PHY doesn't have vendor/device ID 81 * registers; rue(4) fakes up a return value of all zeros. 82 */ 83 static const struct mii_phydesc ruephys[] = { 84 { 0, 0, "RealTek RTL8150 internal media interface" }, 85 MII_PHY_END 86 }; 87 88 static const struct mii_phy_funcs ruephy_funcs = { 89 ruephy_service, 90 ruephy_status, 91 ruephy_reset 92 }; 93 94 static int 95 ruephy_probe(device_t dev) 96 { 97 98 if (strcmp(device_get_name(device_get_parent(device_get_parent(dev))), 99 "rue") == 0) 100 return (mii_phy_dev_probe(dev, ruephys, BUS_PROBE_DEFAULT)); 101 return (ENXIO); 102 } 103 104 static int 105 ruephy_attach(device_t dev) 106 { 107 108 mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, 109 &ruephy_funcs, 1); 110 return (0); 111 } 112 113 static int 114 ruephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 115 { 116 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 117 int reg; 118 119 switch (cmd) { 120 case MII_POLLSTAT: 121 break; 122 123 case MII_MEDIACHG: 124 mii_phy_setmedia(sc); 125 break; 126 127 case MII_TICK: 128 /* 129 * Only used for autonegotiation. 130 */ 131 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 132 break; 133 134 /* 135 * Check to see if we have link. If we do, we don't 136 * need to restart the autonegotiation process. Read 137 * the MSR twice in case it's latched. 138 */ 139 reg = PHY_READ(sc, RUEPHY_MII_MSR) | 140 PHY_READ(sc, RUEPHY_MII_MSR); 141 if (reg & RUEPHY_MSR_LINK) 142 break; 143 144 /* Only retry autonegotiation every mii_anegticks seconds. */ 145 if (sc->mii_ticks <= sc->mii_anegticks) 146 break; 147 148 sc->mii_ticks = 0; 149 PHY_RESET(sc); 150 if (mii_phy_auto(sc) == EJUSTRETURN) 151 return (0); 152 break; 153 } 154 155 /* Update the media status. */ 156 PHY_STATUS(sc); 157 158 /* Callback if something changed. */ 159 mii_phy_update(sc, cmd); 160 161 return (0); 162 } 163 164 static void 165 ruephy_reset(struct mii_softc *sc) 166 { 167 168 mii_phy_reset(sc); 169 170 /* 171 * XXX RealTek RTL8150 PHY doesn't set the BMCR properly after 172 * XXX reset, which breaks autonegotiation. 173 */ 174 PHY_WRITE(sc, MII_BMCR, (BMCR_S100 | BMCR_AUTOEN | BMCR_FDX)); 175 } 176 177 static void 178 ruephy_status(struct mii_softc *phy) 179 { 180 struct mii_data *mii = phy->mii_pdata; 181 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 182 int bmsr, bmcr, msr; 183 184 mii->mii_media_status = IFM_AVALID; 185 mii->mii_media_active = IFM_ETHER; 186 187 msr = PHY_READ(phy, RUEPHY_MII_MSR) | PHY_READ(phy, RUEPHY_MII_MSR); 188 if (msr & RUEPHY_MSR_LINK) 189 mii->mii_media_status |= IFM_ACTIVE; 190 191 bmcr = PHY_READ(phy, MII_BMCR); 192 if (bmcr & BMCR_ISO) { 193 mii->mii_media_active |= IFM_NONE; 194 mii->mii_media_status = 0; 195 return; 196 } 197 198 bmsr = PHY_READ(phy, MII_BMSR) | PHY_READ(phy, MII_BMSR); 199 if (bmcr & BMCR_AUTOEN) { 200 if ((bmsr & BMSR_ACOMP) == 0) { 201 /* Erg, still trying, I guess... */ 202 mii->mii_media_active |= IFM_NONE; 203 return; 204 } 205 206 if (msr & RUEPHY_MSR_SPEED100) 207 mii->mii_media_active |= IFM_100_TX; 208 else 209 mii->mii_media_active |= IFM_10_T; 210 211 if (msr & RUEPHY_MSR_DUPLEX) 212 mii->mii_media_active |= 213 IFM_FDX | mii_phy_flowstatus(phy); 214 else 215 mii->mii_media_active |= IFM_HDX; 216 } else 217 mii->mii_media_active = ife->ifm_media; 218 } 219