1 1.40 msaitoh /* $NetBSD: urlphy.c,v 1.40 2023/02/22 08:09:09 msaitoh Exp $ */ 2 1.1 ichiro /* 3 1.1 ichiro * Copyright (c) 2001, 2002 4 1.1 ichiro * Shingo WATANABE <nabe (at) nabechan.org>. All rights reserved. 5 1.1 ichiro * 6 1.1 ichiro * Redistribution and use in source and binary forms, with or without 7 1.1 ichiro * modification, are permitted provided that the following conditions 8 1.1 ichiro * are met: 9 1.1 ichiro * 1. Redistributions of source code must retain the above copyright 10 1.1 ichiro * notice, this list of conditions and the following disclaimer. 11 1.1 ichiro * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 ichiro * notice, this list of conditions and the following disclaimer in the 13 1.1 ichiro * documentation and/or other materials provided with the distribution. 14 1.9 tsutsui * 3. Neither the name of the author nor the names of any co-contributors 15 1.1 ichiro * may be used to endorse or promote products derived from this software 16 1.1 ichiro * without specific prior written permission. 17 1.1 ichiro * 18 1.1 ichiro * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 1.1 ichiro * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 1.1 ichiro * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 1.1 ichiro * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 1.1 ichiro * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 1.1 ichiro * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 1.1 ichiro * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 1.1 ichiro * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 1.1 ichiro * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 1.1 ichiro * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 1.1 ichiro * SUCH DAMAGE. 29 1.1 ichiro * 30 1.1 ichiro */ 31 1.1 ichiro 32 1.1 ichiro /* 33 1.1 ichiro * driver for Realtek RL8150L internal phy 34 1.1 ichiro */ 35 1.1 ichiro 36 1.1 ichiro #include <sys/cdefs.h> 37 1.40 msaitoh __KERNEL_RCSID(0, "$NetBSD: urlphy.c,v 1.40 2023/02/22 08:09:09 msaitoh Exp $"); 38 1.1 ichiro 39 1.1 ichiro #include <sys/param.h> 40 1.1 ichiro #include <sys/systm.h> 41 1.1 ichiro #include <sys/kernel.h> 42 1.1 ichiro #include <sys/device.h> 43 1.1 ichiro #include <sys/socket.h> 44 1.1 ichiro 45 1.1 ichiro #include <net/if.h> 46 1.1 ichiro #include <net/if_media.h> 47 1.1 ichiro 48 1.1 ichiro #include <dev/mii/mii.h> 49 1.1 ichiro #include <dev/mii/miivar.h> 50 1.1 ichiro #include <dev/mii/miidevs.h> 51 1.1 ichiro #include <dev/mii/urlphyreg.h> 52 1.1 ichiro 53 1.1 ichiro #ifdef URLPHY_DEBUG 54 1.1 ichiro #define DPRINTF(x) if (urlphydebug) printf x 55 1.1 ichiro #define DPRINTFN(n,x) if (urlphydebug>(n)) printf x 56 1.1 ichiro int urlphydebug = URLPHY_DEBUG; 57 1.1 ichiro #else 58 1.1 ichiro #define DPRINTF(x) 59 1.1 ichiro #define DPRINTFN(n,x) 60 1.1 ichiro #endif 61 1.1 ichiro 62 1.23 xtraeme static int urlphy_match(device_t, cfdata_t, void *); 63 1.23 xtraeme static void urlphy_attach(device_t, device_t, void *); 64 1.1 ichiro 65 1.23 xtraeme CFATTACH_DECL_NEW(urlphy, sizeof(struct mii_softc), 66 1.6 thorpej urlphy_match, urlphy_attach, mii_phy_detach, mii_phy_activate); 67 1.1 ichiro 68 1.10 thorpej static int urlphy_service(struct mii_softc *, struct mii_data *, int); 69 1.10 thorpej static void urlphy_status(struct mii_softc *); 70 1.1 ichiro 71 1.10 thorpej static const struct mii_phy_funcs urlphy_funcs = { 72 1.1 ichiro urlphy_service, urlphy_status, mii_phy_reset, 73 1.1 ichiro }; 74 1.1 ichiro 75 1.10 thorpej static int 76 1.23 xtraeme urlphy_match(device_t parent, cfdata_t match, void *aux) 77 1.1 ichiro { 78 1.1 ichiro struct mii_attach_args *ma = aux; 79 1.1 ichiro 80 1.34 msaitoh /* RTL8150 reports OUI == 0, MODEL == 0 */ 81 1.1 ichiro if (MII_OUI(ma->mii_id1, ma->mii_id2) != 0 && 82 1.1 ichiro MII_MODEL(ma->mii_id2) != 0) 83 1.34 msaitoh return 0; 84 1.1 ichiro 85 1.34 msaitoh /* Make sure the parent is an 'url' device. */ 86 1.14 kleink if (!device_is_a(parent, "url")) 87 1.34 msaitoh return 0; 88 1.1 ichiro 89 1.34 msaitoh return 10; 90 1.1 ichiro } 91 1.1 ichiro 92 1.10 thorpej static void 93 1.23 xtraeme urlphy_attach(device_t parent, device_t self, void *aux) 94 1.1 ichiro { 95 1.15 thorpej struct mii_softc *sc = device_private(self); 96 1.1 ichiro struct mii_attach_args *ma = aux; 97 1.1 ichiro struct mii_data *mii = ma->mii_data; 98 1.1 ichiro 99 1.8 thorpej aprint_naive(": Media interface\n"); 100 1.8 thorpej aprint_normal(": Realtek RTL8150L internal media interface\n"); 101 1.1 ichiro 102 1.23 xtraeme DPRINTF(("%s: %s: enter\n", device_xname(self), __func__)); 103 1.1 ichiro 104 1.23 xtraeme sc->mii_dev = self; 105 1.1 ichiro sc->mii_inst = mii->mii_instance; 106 1.1 ichiro sc->mii_phy = ma->mii_phyno; 107 1.1 ichiro sc->mii_funcs = &urlphy_funcs; 108 1.1 ichiro sc->mii_pdata = mii; 109 1.32 msaitoh sc->mii_flags = ma->mii_flags; 110 1.1 ichiro 111 1.1 ichiro /* Don't do loopback on this PHY. */ 112 1.1 ichiro sc->mii_flags |= MIIF_NOLOOP; 113 1.1 ichiro /* Don't do isolate on this PHY. */ 114 1.1 ichiro sc->mii_flags |= MIIF_NOISOLATE; 115 1.1 ichiro 116 1.1 ichiro if (mii->mii_instance != 0) { 117 1.31 msaitoh aprint_error_dev(self, 118 1.31 msaitoh "ignoring this PHY, non-zero instance\n"); 119 1.1 ichiro return; 120 1.1 ichiro } 121 1.39 riastrad 122 1.39 riastrad mii_lock(mii); 123 1.39 riastrad 124 1.1 ichiro PHY_RESET(sc); 125 1.1 ichiro 126 1.33 msaitoh PHY_READ(sc, MII_BMSR, &sc->mii_capabilities); 127 1.33 msaitoh sc->mii_capabilities &= ma->mii_capmask; 128 1.35 msaitoh 129 1.39 riastrad mii_unlock(mii); 130 1.39 riastrad 131 1.35 msaitoh mii_phy_add_media(sc); 132 1.1 ichiro } 133 1.1 ichiro 134 1.10 thorpej static int 135 1.1 ichiro urlphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 136 1.1 ichiro { 137 1.1 ichiro struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 138 1.33 msaitoh uint16_t reg; 139 1.1 ichiro 140 1.23 xtraeme DPRINTF(("%s: %s: enter\n", device_xname(sc->mii_dev), __func__)); 141 1.1 ichiro 142 1.1 ichiro switch (cmd) { 143 1.1 ichiro case MII_POLLSTAT: 144 1.34 msaitoh /* If we're not polling our PHY instance, just return. */ 145 1.1 ichiro if (IFM_INST(ife->ifm_media) != sc->mii_inst) 146 1.34 msaitoh return 0; 147 1.1 ichiro break; 148 1.1 ichiro 149 1.1 ichiro case MII_MEDIACHG: 150 1.34 msaitoh /* If we're not currently selected, just return. */ 151 1.1 ichiro if (IFM_INST(ife->ifm_media) != sc->mii_inst) 152 1.34 msaitoh return 0; 153 1.1 ichiro 154 1.1 ichiro /* If the interface is not up, don't do anything. */ 155 1.1 ichiro if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 156 1.1 ichiro break; 157 1.1 ichiro 158 1.1 ichiro mii_phy_setmedia(sc); 159 1.1 ichiro break; 160 1.1 ichiro 161 1.1 ichiro case MII_TICK: 162 1.34 msaitoh /* If we're not currently selected, just return. */ 163 1.1 ichiro if (IFM_INST(ife->ifm_media) != sc->mii_inst) 164 1.34 msaitoh return 0; 165 1.1 ichiro 166 1.1 ichiro /* Just bail now if the interface is down. */ 167 1.1 ichiro if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 168 1.34 msaitoh return 0; 169 1.1 ichiro 170 1.1 ichiro /* 171 1.1 ichiro * If we're not doing autonegotiation, we don't need to do 172 1.1 ichiro * any extra work here. However, we need to check the link 173 1.1 ichiro * status so we can generate an announcement if the status 174 1.1 ichiro * changes. 175 1.1 ichiro */ 176 1.1 ichiro if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 177 1.27 msaitoh break; 178 1.1 ichiro 179 1.1 ichiro /* Read the status register twice; MSR_LINK is latch-low. */ 180 1.33 msaitoh PHY_READ(sc, URLPHY_MSR, ®); 181 1.33 msaitoh PHY_READ(sc, URLPHY_MSR, ®); 182 1.28 msaitoh if (reg & URLPHY_MSR_LINK) { 183 1.28 msaitoh /* 184 1.28 msaitoh * Reset autonegotiation timer to 0 in case the link 185 1.28 msaitoh * goes down in the next tick. 186 1.28 msaitoh */ 187 1.28 msaitoh sc->mii_ticks = 0; 188 1.28 msaitoh /* See above. */ 189 1.27 msaitoh break; 190 1.28 msaitoh } 191 1.28 msaitoh 192 1.28 msaitoh /* 193 1.29 msaitoh * mii_ticks == 0 means it's the first tick after changing the 194 1.28 msaitoh * media or the link became down since the last tick (see 195 1.28 msaitoh * above), so break to update the status. 196 1.28 msaitoh */ 197 1.29 msaitoh if (sc->mii_ticks++ == 0) 198 1.28 msaitoh break; 199 1.28 msaitoh 200 1.34 msaitoh /* Only retry autonegotiation every N seconds. */ 201 1.1 ichiro KASSERT(sc->mii_anegticks != 0); 202 1.40 msaitoh if (sc->mii_ticks < sc->mii_anegticks) 203 1.34 msaitoh return 0; 204 1.1 ichiro 205 1.37 msaitoh if (mii_phy_auto_restart(sc) == EJUSTRETURN) 206 1.34 msaitoh return 0; 207 1.1 ichiro 208 1.1 ichiro break; 209 1.1 ichiro 210 1.1 ichiro case MII_DOWN: 211 1.1 ichiro mii_phy_down(sc); 212 1.34 msaitoh return 0; 213 1.1 ichiro } 214 1.1 ichiro 215 1.1 ichiro /* Update the media status. */ 216 1.1 ichiro mii_phy_status(sc); 217 1.1 ichiro 218 1.1 ichiro /* Callback if something changed. */ 219 1.1 ichiro mii_phy_update(sc, cmd); 220 1.1 ichiro 221 1.34 msaitoh return 0; 222 1.1 ichiro } 223 1.1 ichiro 224 1.10 thorpej static void 225 1.1 ichiro urlphy_status(struct mii_softc *sc) 226 1.1 ichiro { 227 1.1 ichiro struct mii_data *mii = sc->mii_pdata; 228 1.1 ichiro struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 229 1.33 msaitoh uint16_t msr, bmsr, bmcr; 230 1.1 ichiro 231 1.23 xtraeme DPRINTF(("%s: %s: enter\n", device_xname(sc->mii_dev), __func__)); 232 1.1 ichiro 233 1.1 ichiro mii->mii_media_status = IFM_AVALID; 234 1.1 ichiro mii->mii_media_active = IFM_ETHER; 235 1.1 ichiro 236 1.1 ichiro /* 237 1.1 ichiro * The link status bit is not exist in the BMSR register, 238 1.1 ichiro * so we need to read the MSR register to get link status. 239 1.1 ichiro */ 240 1.33 msaitoh PHY_READ(sc, URLPHY_MSR, &msr); 241 1.33 msaitoh PHY_READ(sc, URLPHY_MSR, &msr); 242 1.1 ichiro if (msr & URLPHY_MSR_LINK) 243 1.1 ichiro mii->mii_media_status |= IFM_ACTIVE; 244 1.1 ichiro 245 1.23 xtraeme DPRINTF(("%s: %s: link %s\n", device_xname(sc->mii_dev), __func__, 246 1.1 ichiro mii->mii_media_status & IFM_ACTIVE ? "up" : "down")); 247 1.1 ichiro 248 1.33 msaitoh PHY_READ(sc, MII_BMCR, &bmcr); 249 1.1 ichiro if (bmcr & BMCR_AUTOEN) { 250 1.33 msaitoh PHY_READ(sc, MII_BMSR, &bmsr); 251 1.33 msaitoh PHY_READ(sc, MII_BMSR, &bmsr); 252 1.1 ichiro if ((bmsr & BMSR_ACOMP) == 0) { 253 1.1 ichiro /* Erg, still trying, I guess... */ 254 1.1 ichiro mii->mii_media_active |= IFM_NONE; 255 1.1 ichiro return; 256 1.1 ichiro } 257 1.1 ichiro 258 1.1 ichiro if (msr & URLPHY_MSR_SPEED_100) 259 1.1 ichiro mii->mii_media_active |= IFM_100_TX; 260 1.1 ichiro else 261 1.1 ichiro mii->mii_media_active |= IFM_10_T; 262 1.30 msaitoh 263 1.1 ichiro if (msr & URLPHY_MSR_DUPLEX) 264 1.1 ichiro mii->mii_media_active |= IFM_FDX; 265 1.30 msaitoh else 266 1.30 msaitoh mii->mii_media_active |= IFM_HDX; 267 1.1 ichiro } else 268 1.1 ichiro mii->mii_media_active = ife->ifm_media; 269 1.1 ichiro } 270